privoxy-3.0.21-stable/./cgi.c000640 001751 001751 00000223323 12060362340 014671 0ustar00fkfk000000 000000 const char cgi_rcs[] = "$Id: cgi.c,v 1.158 2012/12/07 12:45:20 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgi.c,v $ * * Purpose : Declares functions to intercept request, generate * html or gif answers, and to compose HTTP resonses. * This only contains the framework functions, the * actual handler functions are declared elsewhere. * * Copyright : Written by and Copyright (C) 2001-2004, 2006-2008 * the SourceForge Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "config.h" #include #include #include #include #include #include #include #ifdef FEATURE_COMPRESSION #include #endif #include "project.h" #include "cgi.h" #include "list.h" #include "encode.h" #include "ssplit.h" #include "errlog.h" #include "filters.h" #include "miscutil.h" #include "cgisimple.h" #include "jbsockets.h" #if defined(FEATURE_CGI_EDIT_ACTIONS) || defined(FEATURE_TOGGLE) #include "cgiedit.h" #endif /* defined(FEATURE_CGI_EDIT_ACTIONS) || defined (FEATURE_TOGGLE) */ /* loadcfg.h is for global_toggle_state only */ #include "loadcfg.h" /* jcc.h is for mutex semaphore globals only */ #include "jcc.h" const char cgi_h_rcs[] = CGI_H_VERSION; /* * List of CGI functions: name, handler, description * Note: Do NOT use single quotes in the description; * this will break the dynamic "blocked" template! */ static const struct cgi_dispatcher cgi_dispatchers[] = { { "", cgi_default, "Privoxy main page", TRUE }, #ifdef FEATURE_GRACEFUL_TERMINATION { "die", cgi_die, "Shut down - Do not deploy this build in a production environment, " "this is a one click Denial Of Service attack!!!", FALSE }, #endif { "show-status", cgi_show_status, #ifdef FEATURE_CGI_EDIT_ACTIONS "View & change the current configuration", #else "View the current configuration", #endif TRUE }, { "show-version", cgi_show_version, "View the source code version numbers", TRUE }, { "show-request", cgi_show_request, "View the request headers", TRUE }, { "show-url-info", cgi_show_url_info, "Look up which actions apply to a URL and why", TRUE }, #ifdef FEATURE_TOGGLE { "toggle", cgi_toggle, "Toggle Privoxy on or off", FALSE }, #endif /* def FEATURE_TOGGLE */ #ifdef FEATURE_CGI_EDIT_ACTIONS { "edit-actions", /* Edit the actions list */ cgi_edit_actions, NULL, FALSE }, { "eaa", /* Shortcut for edit-actions-add-url-form */ cgi_edit_actions_add_url_form, NULL, FALSE }, { "eau", /* Shortcut for edit-actions-url-form */ cgi_edit_actions_url_form, NULL, FALSE }, { "ear", /* Shortcut for edit-actions-remove-url-form */ cgi_edit_actions_remove_url_form, NULL, FALSE }, { "eal", /* Shortcut for edit-actions-list */ cgi_edit_actions_list, NULL, FALSE }, { "eafu", /* Shortcut for edit-actions-for-url */ cgi_edit_actions_for_url, NULL, FALSE }, { "eas", /* Shortcut for edit-actions-submit */ cgi_edit_actions_submit, NULL, FALSE }, { "easa", /* Shortcut for edit-actions-section-add */ cgi_edit_actions_section_add, NULL, FALSE }, { "easr", /* Shortcut for edit-actions-section-remove */ cgi_edit_actions_section_remove, NULL, FALSE }, { "eass", /* Shortcut for edit-actions-section-swap */ cgi_edit_actions_section_swap, NULL, FALSE }, { "edit-actions-for-url", cgi_edit_actions_for_url, NULL, FALSE /* Edit the actions for (a) specified URL(s) */ }, { "edit-actions-list", cgi_edit_actions_list, NULL, TRUE /* Edit the actions list */ }, { "edit-actions-submit", cgi_edit_actions_submit, NULL, FALSE /* Change the actions for (a) specified URL(s) */ }, { "edit-actions-url", cgi_edit_actions_url, NULL, FALSE /* Change a URL pattern in the actionsfile */ }, { "edit-actions-url-form", cgi_edit_actions_url_form, NULL, FALSE /* Form to change a URL pattern in the actionsfile */ }, { "edit-actions-add-url", cgi_edit_actions_add_url, NULL, FALSE /* Add a URL pattern to the actionsfile */ }, { "edit-actions-add-url-form", cgi_edit_actions_add_url_form, NULL, FALSE /* Form to add a URL pattern to the actionsfile */ }, { "edit-actions-remove-url", cgi_edit_actions_remove_url, NULL, FALSE /* Remove a URL pattern from the actionsfile */ }, { "edit-actions-remove-url-form", cgi_edit_actions_remove_url_form, NULL, FALSE /* Form to remove a URL pattern from the actionsfile */ }, { "edit-actions-section-add", cgi_edit_actions_section_add, NULL, FALSE /* Remove a section from the actionsfile */ }, { "edit-actions-section-remove", cgi_edit_actions_section_remove, NULL, FALSE /* Remove a section from the actionsfile */ }, { "edit-actions-section-swap", cgi_edit_actions_section_swap, NULL, FALSE /* Swap two sections in the actionsfile */ }, #endif /* def FEATURE_CGI_EDIT_ACTIONS */ { "error-favicon.ico", cgi_send_error_favicon, NULL, TRUE /* Sends the favicon image for error pages. */ }, { "favicon.ico", cgi_send_default_favicon, NULL, TRUE /* Sends the default favicon image. */ }, { "robots.txt", cgi_robots_txt, NULL, TRUE /* Sends a robots.txt file to tell robots to go away. */ }, { "send-banner", cgi_send_banner, NULL, TRUE /* Send a built-in image */ }, { "send-stylesheet", cgi_send_stylesheet, NULL, FALSE /* Send templates/cgi-style.css */ }, { "t", cgi_transparent_image, NULL, TRUE /* Send a transparent image (short name) */ }, { "url-info-osd.xml", cgi_send_url_info_osd, NULL, TRUE /* Send templates/url-info-osd.xml */ }, { "user-manual", cgi_send_user_manual, NULL, TRUE /* Send user-manual */ }, { NULL, /* NULL Indicates end of list and default page */ cgi_error_404, NULL, TRUE /* Unknown CGI page */ } }; /* * Built-in images for ad replacement * * Hint: You can encode your own images like this: * cat your-image | perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o", unpack("C", $c)); }' */ #ifdef FEATURE_NO_GIFS /* * Checkerboard pattern, as a PNG. */ const char image_pattern_data[] = "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104" "\122\000\000\000\004\000\000\000\004\010\006\000\000\000\251" "\361\236\176\000\000\000\006\142\113\107\104\000\000\000\000" "\000\000\371\103\273\177\000\000\000\033\111\104\101\124\010" "\327\143\140\140\140\060\377\377\377\077\003\234\106\341\060" "\060\230\063\020\124\001\000\161\021\031\241\034\364\030\143" "\000\000\000\000\111\105\116\104\256\102\140\202"; /* * 1x1 transparant PNG. */ const char image_blank_data[] = "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122" "\000\000\000\001\000\000\000\001\001\003\000\000\000\045\333\126" "\312\000\000\000\003\120\114\124\105\377\377\377\247\304\033\310" "\000\000\000\001\164\122\116\123\000\100\346\330\146\000\000\000" "\001\142\113\107\104\000\210\005\035\110\000\000\000\012\111\104" "\101\124\170\001\143\140\000\000\000\002\000\001\163\165\001\030" "\000\000\000\000\111\105\116\104\256\102\140\202"; #else /* * Checkerboard pattern, as a GIF. */ const char image_pattern_data[] = "\107\111\106\070\071\141\004\000\004\000\200\000\000\310\310" "\310\377\377\377\041\376\016\111\040\167\141\163\040\141\040" "\142\141\156\156\145\162\000\041\371\004\001\012\000\001\000" "\054\000\000\000\000\004\000\004\000\000\002\005\104\174\147" "\270\005\000\073"; /* * 1x1 transparant GIF. */ const char image_blank_data[] = "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000" "\000!\371\004\001\000\000\000\000,\000\000\000\000\001" "\000\001\000\000\002\002D\001\000;"; #endif const size_t image_pattern_length = sizeof(image_pattern_data) - 1; const size_t image_blank_length = sizeof(image_blank_data) - 1; #ifdef FEATURE_COMPRESSION /* * Minimum length which a buffer has to reach before * we bother to (re-)compress it. Completely arbitrary. */ const size_t LOWER_LENGTH_LIMIT_FOR_COMPRESSION = 1024U; #endif static struct http_response cgi_error_memory_response[1]; static struct http_response *dispatch_known_cgi(struct client_state * csp, const char * path); static struct map *parse_cgi_parameters(char *argstring); /********************************************************************* * * Function : dispatch_cgi * * Description : Checks if a request URL has either the magical * hostname CGI_SITE_1_HOST (usually http://p.p/) or * matches CGI_SITE_2_HOST CGI_SITE_2_PATH (usually * http://config.privoxy.org/). If so, it passes * the (rest of the) path onto dispatch_known_cgi, which * calls the relevant CGI handler function. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : http_response if match, NULL if nonmatch or handler fail * *********************************************************************/ struct http_response *dispatch_cgi(struct client_state *csp) { const char *host = csp->http->host; const char *path = csp->http->path; /* * Should we intercept ? */ /* Note: "example.com" and "example.com." are equivalent hostnames. */ /* Either the host matches CGI_SITE_1_HOST ..*/ if ( ( (0 == strcmpic(host, CGI_SITE_1_HOST)) || (0 == strcmpic(host, CGI_SITE_1_HOST "."))) && (path[0] == '/')) { /* ..then the path will all be for us. Remove leading '/' */ path++; } /* Or it's the host part CGI_SITE_2_HOST, and the path CGI_SITE_2_PATH */ else if (( (0 == strcmpic(host, CGI_SITE_2_HOST)) || (0 == strcmpic(host, CGI_SITE_2_HOST "."))) && (0 == strncmpic(path, CGI_SITE_2_PATH, strlen(CGI_SITE_2_PATH)))) { /* take everything following CGI_SITE_2_PATH */ path += strlen(CGI_SITE_2_PATH); if (*path == '/') { /* skip the forward slash after CGI_SITE_2_PATH */ path++; } else if (*path != '\0') { /* * weirdness: URL is /configXXX, where XXX is some string * Do *NOT* intercept. */ return NULL; } } else { /* Not a CGI */ return NULL; } if (strcmpic(csp->http->gpc, "GET") && strcmpic(csp->http->gpc, "HEAD")) { log_error(LOG_LEVEL_ERROR, "CGI request with unsupported method received: %s", csp->http->gpc); /* * The CGI pages currently only support GET and HEAD requests. * * If the client used a different method, ditch any data following * the current headers to reduce the likelihood of parse errors * with the following request. */ csp->client_iob->eod = csp->client_iob->cur; } /* * This is a CGI call. */ return dispatch_known_cgi(csp, path); } /********************************************************************* * * Function : grep_cgi_referrer * * Description : Ugly provisorical fix that greps the value of the * referer HTTP header field out of a linked list of * strings like found at csp->headers. Will disappear * in Privoxy 3.1. * * FIXME: csp->headers ought to be csp->http->headers * FIXME: Parsing all client header lines should * happen right after the request is received! * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : pointer to value (no copy!), or NULL if none found. * *********************************************************************/ static char *grep_cgi_referrer(const struct client_state *csp) { struct list_entry *p; for (p = csp->headers->first; p != NULL; p = p->next) { if (p->str == NULL) continue; if (strncmpic(p->str, "Referer: ", 9) == 0) { return ((p->str) + 9); } } return NULL; } /********************************************************************* * * Function : referrer_is_safe * * Description : Decides whether we trust the Referer for * CGI pages which are only meant to be reachable * through Privoxy's web interface directly. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : TRUE if the referrer is safe, or * FALSE if the referrer is unsafe or not set. * *********************************************************************/ static int referrer_is_safe(const struct client_state *csp) { char *referrer; static const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/"; referrer = grep_cgi_referrer(csp); if (NULL == referrer) { /* No referrer, no access */ log_error(LOG_LEVEL_ERROR, "Denying access to %s. No referrer found.", csp->http->url); } else if ((0 == strncmp(referrer, CGI_PREFIX, sizeof(CGI_PREFIX)-1) || (0 == strncmp(referrer, alternative_prefix, strlen(alternative_prefix))))) { /* Trustworthy referrer */ log_error(LOG_LEVEL_CGI, "Granting access to %s, referrer %s is trustworthy.", csp->http->url, referrer); return TRUE; } else { /* Untrustworthy referrer */ log_error(LOG_LEVEL_ERROR, "Denying access to %s, referrer %s isn't trustworthy.", csp->http->url, referrer); } return FALSE; } /********************************************************************* * * Function : dispatch_known_cgi * * Description : Processes a CGI once dispatch_cgi has determined that * it matches one of the magic prefixes. Parses the path * as a cgi name plus query string, prepares a map that * maps CGI parameter names to their values, initializes * the http_response struct, and calls the relevant CGI * handler function. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : path = Path of CGI, with the CGI prefix removed. * Should not have a leading "/". * * Returns : http_response, or NULL on handler failure or out of * memory. * *********************************************************************/ static struct http_response *dispatch_known_cgi(struct client_state * csp, const char * path) { const struct cgi_dispatcher *d; struct map *param_list; struct http_response *rsp; char *query_args_start; char *path_copy; jb_err err; if (NULL == (path_copy = strdup(path))) { return cgi_error_memory(); } query_args_start = path_copy; while (*query_args_start && *query_args_start != '?' && *query_args_start != '/') { query_args_start++; } if (*query_args_start == '/') { *query_args_start++ = '\0'; if ((param_list = new_map())) { map(param_list, "file", 1, url_decode(query_args_start), 0); } } else { if (*query_args_start == '?') { *query_args_start++ = '\0'; } if (NULL == (param_list = parse_cgi_parameters(query_args_start))) { free(path_copy); return cgi_error_memory(); } } /* * At this point: * path_copy = CGI call name * param_list = CGI params, as map */ /* Get mem for response or fail*/ if (NULL == (rsp = alloc_http_response())) { free(path_copy); free_map(param_list); return cgi_error_memory(); } /* * Find and start the right CGI function */ d = cgi_dispatchers; for (;;) { if ((d->name == NULL) || (strcmp(path_copy, d->name) == 0)) { /* * If the called CGI is either harmless, or referred * from a trusted source, start it. */ if (d->harmless || referrer_is_safe(csp)) { err = (d->handler)(csp, rsp, param_list); } else { /* * Else, modify toggle calls so that they only display * the status, and deny all other calls. */ if (0 == strcmp(path_copy, "toggle")) { unmap(param_list, "set"); err = (d->handler)(csp, rsp, param_list); } else { err = cgi_error_disabled(csp, rsp); } } free(path_copy); free_map(param_list); if (err == JB_ERR_CGI_PARAMS) { err = cgi_error_bad_param(csp, rsp); } if (err && (err != JB_ERR_MEMORY)) { /* Unexpected error! Shouldn't get here */ log_error(LOG_LEVEL_ERROR, "Unexpected CGI error %d in top-level handler. " "Please file a bug report!", err); err = cgi_error_unknown(csp, rsp, err); } if (!err) { /* It worked */ rsp->crunch_reason = CGI_CALL; return finish_http_response(csp, rsp); } else { /* Error in handler, probably out-of-memory */ free_http_response(rsp); return cgi_error_memory(); } } d++; } } /********************************************************************* * * Function : parse_cgi_parameters * * Description : Parse a URL-encoded argument string into name/value * pairs and store them in a struct map list. * * Parameters : * 1 : argstring = string to be parsed. Will be trashed. * * Returns : pointer to param list, or NULL if out of memory. * *********************************************************************/ static struct map *parse_cgi_parameters(char *argstring) { char *p; char **vector; int pairs, i; struct map *cgi_params; /* * XXX: This estimate is guaranteed to be high enough as we * let ssplit() ignore empty fields, but also a bit wasteful. * The same hack is used in get_last_url() so it looks like * a real solution is needed. */ size_t max_segments = strlen(argstring) / 2; if (max_segments == 0) { /* * XXX: If the argstring is empty, there's really * no point in creating a param list, but currently * other parts of Privoxy depend on the list's existence. */ max_segments = 1; } vector = malloc_or_die(max_segments * sizeof(char *)); if (NULL == (cgi_params = new_map())) { freez(vector); return NULL; } /* * IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends * the fragment identifier along with the request, so we must * cut it off here, so it won't pollute the CGI params: */ if (NULL != (p = strchr(argstring, '#'))) { *p = '\0'; } pairs = ssplit(argstring, "&", vector, max_segments); assert(pairs != -1); if (pairs == -1) { freez(vector); free_map(cgi_params); return NULL; } for (i = 0; i < pairs; i++) { if ((NULL != (p = strchr(vector[i], '='))) && (*(p+1) != '\0')) { *p = '\0'; if (map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0)) { freez(vector); free_map(cgi_params); return NULL; } } } freez(vector); return cgi_params; } /********************************************************************* * * Function : get_char_param * * Description : Get a single-character parameter passed to a CGI * function. * * Parameters : * 1 : parameters = map of cgi parameters * 2 : param_name = The name of the parameter to read * * Returns : Uppercase character on success, '\0' on error. * *********************************************************************/ char get_char_param(const struct map *parameters, const char *param_name) { char ch; assert(parameters); assert(param_name); ch = *(lookup(parameters, param_name)); if ((ch >= 'a') && (ch <= 'z')) { ch = (char)(ch - 'a' + 'A'); } return ch; } /********************************************************************* * * Function : get_string_param * * Description : Get a string paramater, to be used as an * ACTION_STRING or ACTION_MULTI paramater. * Validates the input to prevent stupid/malicious * users from corrupting their action file. * * Parameters : * 1 : parameters = map of cgi parameters * 2 : param_name = The name of the parameter to read * 3 : pparam = destination for paramater. Allocated as * part of the map "parameters", so don't free it. * Set to NULL if not specified. * * Returns : JB_ERR_OK on success, or if the paramater * was not specified. * JB_ERR_MEMORY on out-of-memory. * JB_ERR_CGI_PARAMS if the paramater is not valid. * *********************************************************************/ jb_err get_string_param(const struct map *parameters, const char *param_name, const char **pparam) { const char *param; const char *s; char ch; assert(parameters); assert(param_name); assert(pparam); *pparam = NULL; param = lookup(parameters, param_name); if (!*param) { return JB_ERR_OK; } if (strlen(param) >= CGI_PARAM_LEN_MAX) { /* * Too long. * * Note that the length limit is arbitrary, it just seems * sensible to limit it to *something*. There's no * technical reason for any limit at all. */ return JB_ERR_CGI_PARAMS; } /* Check every character to see if it's legal */ s = param; while ((ch = *s++) != '\0') { if (((unsigned char)ch < (unsigned char)' ') || (ch == '}')) { /* Probable hack attempt, or user accidentally used '}'. */ return JB_ERR_CGI_PARAMS; } } /* Success */ *pparam = param; return JB_ERR_OK; } /********************************************************************* * * Function : get_number_param * * Description : Get a non-negative integer from the parameters * passed to a CGI function. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters * 3 : name = Name of CGI parameter to read * 4 : pvalue = destination for value. * Set to -1 on error. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the parameter was not specified * or is not valid. * *********************************************************************/ jb_err get_number_param(struct client_state *csp, const struct map *parameters, char *name, unsigned *pvalue) { const char *param; char ch; unsigned value; assert(csp); assert(parameters); assert(name); assert(pvalue); *pvalue = 0; param = lookup(parameters, name); if (!*param) { return JB_ERR_CGI_PARAMS; } /* We don't use atoi because I want to check this carefully... */ value = 0; while ((ch = *param++) != '\0') { if ((ch < '0') || (ch > '9')) { return JB_ERR_CGI_PARAMS; } ch = (char)(ch - '0'); /* Note: * * defines UINT_MAX * * (UINT_MAX - ch) / 10 is the largest number that * can be safely multiplied by 10 then have ch added. */ if (value > ((UINT_MAX - (unsigned)ch) / 10U)) { return JB_ERR_CGI_PARAMS; } value = value * 10 + (unsigned)ch; } /* Success */ *pvalue = value; return JB_ERR_OK; } /********************************************************************* * * Function : error_response * * Description : returns an http_response that explains the reason * why a request failed. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : templatename = Which template should be used for the answer * * Returns : A http_response. If we run out of memory, this * will be cgi_error_memory(). * *********************************************************************/ struct http_response *error_response(struct client_state *csp, const char *templatename) { jb_err err; struct http_response *rsp; struct map *exports = default_exports(csp, NULL); char *path = NULL; if (exports == NULL) { return cgi_error_memory(); } if (NULL == (rsp = alloc_http_response())) { free_map(exports); return cgi_error_memory(); } #ifdef FEATURE_FORCE_LOAD if (csp->flags & CSP_FLAG_FORCED) { path = strdup(FORCE_PREFIX); } else #endif /* def FEATURE_FORCE_LOAD */ { path = strdup(""); } err = string_append(&path, csp->http->path); if (!err) err = map(exports, "host", 1, html_encode(csp->http->host), 0); if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0); if (!err) err = map(exports, "path", 1, html_encode_and_free_original(path), 0); if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) { err = map(exports, "host-ip", 1, html_encode(csp->http->host_ip_addr_str), 0); if (err) { /* Some failures, like "404 no such domain", don't have an IP address. */ err = map(exports, "host-ip", 1, html_encode(csp->http->host), 0); } } if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } if (!strcmp(templatename, "no-such-domain")) { rsp->status = strdup("404 No such domain"); rsp->crunch_reason = NO_SUCH_DOMAIN; } else if (!strcmp(templatename, "forwarding-failed")) { const struct forward_spec *fwd = forward_url(csp, csp->http); char *socks_type = NULL; if (fwd == NULL) { log_error(LOG_LEVEL_FATAL, "gateway spec is NULL. This shouldn't happen!"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } /* * XXX: While the template is called forwarding-failed, * it currently only handles socks forwarding failures. */ assert(fwd != NULL); assert(fwd->type != SOCKS_NONE); /* * Map failure reason, forwarding type and forwarder. */ if (NULL == csp->error_message) { /* * Either we forgot to record the failure reason, * or the memory allocation failed. */ log_error(LOG_LEVEL_ERROR, "Socks failure reason missing."); csp->error_message = strdup("Failure reason missing. Check the log file for details."); } if (!err) err = map(exports, "gateway", 1, fwd->gateway_host, 1); /* * XXX: this is almost the same code as in cgi_show_url_info() * and thus should be factored out and shared. */ switch (fwd->type) { case SOCKS_4: socks_type = "socks4-"; break; case SOCKS_4A: socks_type = "socks4a-"; break; case SOCKS_5: socks_type = "socks5-"; break; case SOCKS_5T: socks_type = "socks5t-"; break; default: log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type); } if (!err) err = map(exports, "forwarding-type", 1, socks_type, 1); if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0); if ((NULL == csp->error_message) || err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } rsp->status = strdup("503 Forwarding failure"); rsp->crunch_reason = FORWARDING_FAILED; } else if (!strcmp(templatename, "connect-failed")) { rsp->status = strdup("503 Connect failed"); rsp->crunch_reason = CONNECT_FAILED; } else if (!strcmp(templatename, "connection-timeout")) { rsp->status = strdup("504 Connection timeout"); rsp->crunch_reason = CONNECTION_TIMEOUT; } else if (!strcmp(templatename, "no-server-data")) { rsp->status = strdup("502 No data received from server or forwarder"); rsp->crunch_reason = NO_SERVER_DATA; } if (rsp->status == NULL) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } err = template_fill_for_cgi(csp, templatename, exports, rsp); if (err) { free_http_response(rsp); return cgi_error_memory(); } return finish_http_response(csp, rsp); } /********************************************************************* * * Function : cgi_error_disabled * * Description : CGI function that is called to generate an error * response if the actions editor or toggle CGI are * accessed despite having being disabled at compile- * or run-time, or if the user followed an untrusted link * to access a unsafe CGI feature that is only reachable * through Privoxy directly. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_error_disabled(const struct client_state *csp, struct http_response *rsp) { struct map *exports; assert(csp); assert(rsp); if (NULL == (exports = default_exports(csp, "cgi-error-disabled"))) { return JB_ERR_MEMORY; } if (map(exports, "url", 1, html_encode(csp->http->url), 0)) { /* Not important enough to do anything */ log_error(LOG_LEVEL_ERROR, "Failed to fill in url."); } return template_fill_for_cgi(csp, "cgi-error-disabled", exports, rsp); } /********************************************************************* * * Function : cgi_init_error_messages * * Description : Call at the start of the program to initialize * the error message used by cgi_error_memory(). * * Parameters : N/A * * Returns : N/A * *********************************************************************/ void cgi_init_error_messages(void) { memset(cgi_error_memory_response, '\0', sizeof(*cgi_error_memory_response)); cgi_error_memory_response->head = "HTTP/1.0 500 Internal Privoxy Error\r\n" "Content-Type: text/html\r\n" "\r\n"; cgi_error_memory_response->body = "\n" "\n" " 500 Internal Privoxy Error\n" " " "\n" "\n" "

500 Internal Privoxy Error

\n" "

Privoxy ran out of memory while processing your request.

\n" "

Please contact your proxy administrator, or try again later

\n" "\n" "\n"; cgi_error_memory_response->head_length = strlen(cgi_error_memory_response->head); cgi_error_memory_response->content_length = strlen(cgi_error_memory_response->body); cgi_error_memory_response->crunch_reason = OUT_OF_MEMORY; } /********************************************************************* * * Function : cgi_error_memory * * Description : Called if a CGI function runs out of memory. * Returns a statically-allocated error response. * * Parameters : N/A * * Returns : http_response data structure for output. This is * statically allocated, for obvious reasons. * *********************************************************************/ struct http_response *cgi_error_memory(void) { /* assert that it's been initialized. */ assert(cgi_error_memory_response->head); return cgi_error_memory_response; } /********************************************************************* * * Function : cgi_error_no_template * * Description : Almost-CGI function that is called if a template * cannot be loaded. Note this is not a true CGI, * it takes a template name rather than a map of * parameters. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : template_name = Name of template that could not * be loaded. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_error_no_template(const struct client_state *csp, struct http_response *rsp, const char *template_name) { static const char status[] = "500 Internal Privoxy Error"; static const char body_prefix[] = "\n" "\n" " 500 Internal Privoxy Error\n" " " "\n" "\n" "

500 Internal Privoxy Error

\n" "

Privoxy encountered an error while processing your request:

\n" "

Could not load template file "; static const char body_suffix[] = " or one of its included components.

\n" "

Please contact your proxy administrator.

\n" "

If you are the proxy administrator, please put the required file(s)" "in the (confdir)/templates directory. The " "location of the (confdir) directory " "is specified in the main Privoxy config " "file. (It's typically the Privoxy install directory" #ifndef _WIN32 ", or /etc/privoxy/" #endif /* ndef _WIN32 */ ").

\n" "\n" "\n"; const size_t body_size = strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1; assert(csp); assert(rsp); assert(template_name); /* Reset rsp, if needed */ freez(rsp->status); freez(rsp->head); freez(rsp->body); rsp->content_length = 0; rsp->head_length = 0; rsp->is_static = 0; rsp->body = malloc_or_die(body_size); strlcpy(rsp->body, body_prefix, body_size); strlcat(rsp->body, template_name, body_size); strlcat(rsp->body, body_suffix, body_size); rsp->status = strdup(status); if (rsp->status == NULL) { return JB_ERR_MEMORY; } return JB_ERR_OK; } /********************************************************************* * * Function : cgi_error_unknown * * Description : Almost-CGI function that is called if an unexpected * error occurs in the top-level CGI dispatcher. * In this context, "unexpected" means "anything other * than JB_ERR_MEMORY or JB_ERR_CGI_PARAMS" - CGIs are * expected to handle all other errors internally, * since they can give more relavent error messages * that way. * * Note this is not a true CGI, it takes an error * code rather than a map of parameters. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : error_to_report = Error code to report. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_error_unknown(const struct client_state *csp, struct http_response *rsp, jb_err error_to_report) { static const char status[] = "500 Internal Privoxy Error"; static const char body_prefix[] = "\n" "\n" " 500 Internal Privoxy Error\n" " " "\n" "\n" "

500 Internal Privoxy Error

\n" "

Privoxy encountered an error while processing your request:

\n" "

Unexpected internal error: "; static const char body_suffix[] = "

\n" "

Please " "" "file a bug report.

\n" "\n" "\n"; /* Includes room for larger error numbers in the future. */ const size_t body_size = sizeof(body_prefix) + sizeof(body_suffix) + 5; assert(csp); assert(rsp); /* Reset rsp, if needed */ freez(rsp->status); freez(rsp->head); freez(rsp->body); rsp->content_length = 0; rsp->head_length = 0; rsp->is_static = 0; rsp->crunch_reason = INTERNAL_ERROR; rsp->body = malloc_or_die(body_size); snprintf(rsp->body, body_size, "%s%d%s", body_prefix, error_to_report, body_suffix); rsp->status = strdup(status); if (rsp->status == NULL) { return JB_ERR_MEMORY; } return JB_ERR_OK; } /********************************************************************* * * Function : cgi_error_bad_param * * Description : CGI function that is called if the parameters * (query string) for a CGI were wrong. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_error_bad_param(const struct client_state *csp, struct http_response *rsp) { struct map *exports; assert(csp); assert(rsp); if (NULL == (exports = default_exports(csp, NULL))) { return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "cgi-error-bad-param", exports, rsp); } /********************************************************************* * * Function : cgi_redirect * * Description : CGI support function to generate a HTTP redirect * message * * Parameters : * 1 : rsp = http_response data structure for output * 2 : target = string with the target URL * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_redirect (struct http_response * rsp, const char *target) { jb_err err; assert(rsp); assert(target); err = enlist_unique_header(rsp->headers, "Location", target); rsp->status = strdup("302 Local Redirect from Privoxy"); if (rsp->status == NULL) { return JB_ERR_MEMORY; } return err; } /********************************************************************* * * Function : add_help_link * * Description : Produce a copy of the string given as item, * embedded in an HTML link to its corresponding * section (item name in uppercase) in the actions * chapter of the user manual, (whose URL is given in * the config and defaults to our web site). * * FIXME: I currently only work for actions, and would * like to be generalized for other topics. * * Parameters : * 1 : item = item (will NOT be free()d.) * It is assumed to be HTML-safe. * 2 : config = The current configuration. * * Returns : String with item embedded in link, or NULL on * out-of-memory * *********************************************************************/ char *add_help_link(const char *item, struct configuration_spec *config) { char *result; if (!item) return NULL; result = strdup("usermanual, "file://", 7) || !strncmpic(config->usermanual, "http", 4)) { string_append(&result, config->usermanual); } else { string_append(&result, "http://"); string_append(&result, CGI_SITE_2_HOST); string_append(&result, "/user-manual/"); } string_append(&result, ACTIONS_HELP_PREFIX); string_join (&result, string_toupper(item)); string_append(&result, "\">"); string_append(&result, item); string_append(&result, ""); return result; } /********************************************************************* * * Function : get_http_time * * Description : Get the time in a format suitable for use in a * HTTP header - e.g.: * "Sun, 06 Nov 1994 08:49:37 GMT" * * Parameters : * 1 : time_offset = Time returned will be current time * plus this number of seconds. * 2 : buf = Destination for result. * 3 : buffer_size = Size of the buffer above. Must be big * enough to hold 29 characters plus a * trailing zero. * * Returns : N/A * *********************************************************************/ void get_http_time(int time_offset, char *buf, size_t buffer_size) { struct tm *t; time_t current_time; #if defined(HAVE_GMTIME_R) struct tm dummy; #endif assert(buf); assert(buffer_size > (size_t)29); time(¤t_time); current_time += time_offset; /* get and save the gmt */ #if HAVE_GMTIME_R t = gmtime_r(¤t_time, &dummy); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); t = gmtime(¤t_time); privoxy_mutex_unlock(&gmtime_mutex); #else t = gmtime(¤t_time); #endif strftime(buf, buffer_size, "%a, %d %b %Y %H:%M:%S GMT", t); } /********************************************************************* * * Function : get_locale_time * * Description : Get the time in a date(1)-like format * according to the current locale - e.g.: * "Fri Aug 29 19:37:12 CEST 2008" * * XXX: Should we allow the user to change the format? * * Parameters : * 1 : buf = Destination for result. * 2 : buffer_size = Size of the buffer above. Must be big * enough to hold 29 characters plus a * trailing zero. * * Returns : N/A * *********************************************************************/ static void get_locale_time(char *buf, size_t buffer_size) { struct tm *timeptr; time_t current_time; #if defined(HAVE_LOCALTIME_R) struct tm dummy; #endif assert(buf); assert(buffer_size > (size_t)29); time(¤t_time); #if HAVE_LOCALTIME_R timeptr = localtime_r(¤t_time, &dummy); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&localtime_mutex); timeptr = localtime(¤t_time); privoxy_mutex_unlock(&localtime_mutex); #else timeptr = localtime(¤t_time); #endif strftime(buf, buffer_size, "%a %b %d %X %Z %Y", timeptr); } #ifdef FEATURE_COMPRESSION /********************************************************************* * * Function : compress_buffer * * Description : Compresses the content of a buffer with zlib's deflate * Allocates a new buffer for the result, free'ing it is * up to the caller. * * Parameters : * 1 : buffer = buffer whose content should be compressed * 2 : buffer_length = length of the buffer * 3 : compression_level = compression level for compress2() * * Returns : NULL on error, otherwise a pointer to the compressed * content of the input buffer. * *********************************************************************/ char *compress_buffer(char *buffer, size_t *buffer_length, int compression_level) { char *compressed_buffer; uLongf new_length; assert(-1 <= compression_level && compression_level <= 9); /* Let zlib figure out the maximum length of the compressed data */ new_length = compressBound((uLongf)*buffer_length); compressed_buffer = malloc_or_die(new_length); if (Z_OK != compress2((Bytef *)compressed_buffer, &new_length, (Bytef *)buffer, *buffer_length, compression_level)) { log_error(LOG_LEVEL_ERROR, "compress2() failed. Buffer size: %d, compression level: %d.", new_length, compression_level); freez(compressed_buffer); return NULL; } log_error(LOG_LEVEL_RE_FILTER, "Compressed content from %d to %d bytes. Compression level: %d", *buffer_length, new_length, compression_level); *buffer_length = (size_t)new_length; return compressed_buffer; } #endif /********************************************************************* * * Function : finish_http_response * * Description : Fill in the missing headers in an http response, * and flatten the headers to an http head. * For HEAD requests the body is freed once * the Content-Length header is set. * * Parameters : * 1 : rsp = pointer to http_response to be processed * * Returns : A http_response, usually the rsp parameter. * On error, free()s rsp and returns cgi_error_memory() * *********************************************************************/ struct http_response *finish_http_response(struct client_state *csp, struct http_response *rsp) { char buf[BUFFER_SIZE]; jb_err err; /* Special case - do NOT change this statically allocated response, * which is ready for output anyway. */ if (rsp == cgi_error_memory_response) { return rsp; } /* * Fill in the HTTP Status, using HTTP/1.1 * unless the client asked for HTTP/1.0. */ snprintf(buf, sizeof(buf), "%s %s", strcmpic(csp->http->ver, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0", rsp->status ? rsp->status : "200 OK"); err = enlist_first(rsp->headers, buf); /* * Set the Content-Length */ if (rsp->content_length == 0) { rsp->content_length = rsp->body ? strlen(rsp->body) : 0; } #ifdef FEATURE_COMPRESSION if (!err && (csp->flags & CSP_FLAG_CLIENT_SUPPORTS_DEFLATE) && (rsp->content_length > LOWER_LENGTH_LIMIT_FOR_COMPRESSION)) { char *compressed_content; compressed_content = compress_buffer(rsp->body, &rsp->content_length, csp->config->compression_level); if (NULL != compressed_content) { freez(rsp->body); rsp->body = compressed_content; err = enlist_unique_header(rsp->headers, "Content-Encoding", "deflate"); } } #endif if (!err) { snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length); /* * Signal serve() that the client will be able to figure out * the end of the response without having to close the connection. */ csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; err = enlist(rsp->headers, buf); } if (0 == strcmpic(csp->http->gpc, "head")) { /* * The client only asked for the head. Dispose * the body and log an offensive message. * * While it may seem to be a bit inefficient to * prepare the body if it isn't needed, it's the * only way to get the Content-Length right for * dynamic pages. We could have disposed the body * earlier, but not without duplicating the * Content-Length setting code above. */ log_error(LOG_LEVEL_CGI, "Preparing to give head to %s.", csp->ip_addr_str); freez(rsp->body); rsp->content_length = 0; } if (strncmpic(rsp->status, "302", 3)) { /* * If it's not a redirect without any content, * set the Content-Type to text/html if it's * not already specified. */ if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13); } /* * Fill in the rest of the default headers: * * Date: set to current date/time. * Last-Modified: set to date/time the page was last changed. * Expires: set to date/time page next needs reloading. * Cache-Control: set to "no-cache" if applicable. * * See http://www.w3.org/Protocols/rfc2068/rfc2068 */ if (rsp->is_static) { /* * Set Expires to about 10 min into the future so it'll get reloaded * occasionally, e.g. if Privoxy gets upgraded. */ if (!err) { get_http_time(0, buf, sizeof(buf)); err = enlist_unique_header(rsp->headers, "Date", buf); } /* Some date in the past. */ if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Sat, 17 Jun 2000 12:00:00 GMT"); if (!err) { get_http_time(10 * 60, buf, sizeof(buf)); /* 10 * 60sec = 10 minutes */ err = enlist_unique_header(rsp->headers, "Expires", buf); } } else if (!strncmpic(rsp->status, "302", 3)) { get_http_time(0, buf, sizeof(buf)); if (!err) err = enlist_unique_header(rsp->headers, "Date", buf); } else { /* * Setting "Cache-Control" to "no-cache" and "Expires" to * the current time doesn't exactly forbid caching, it just * requires the client to revalidate the cached copy. * * If a temporary problem occurs and the user tries again after * getting Privoxy's error message, a compliant browser may set the * If-Modified-Since header with the content of the error page's * Last-Modified header. More often than not, the document on the server * is older than Privoxy's error message, the server would send status code * 304 and the browser would display the outdated error message again and again. * * For documents delivered with status code 403, 404 and 503 we set "Last-Modified" * to Tim Berners-Lee's birthday, which predates the age of any page on the web * and can be safely used to "revalidate" without getting a status code 304. * * There is no need to let the useless If-Modified-Since header reach the * server, it is therefore stripped by client_if_modified_since in parsers.c. */ if (!err) err = enlist_unique_header(rsp->headers, "Cache-Control", "no-cache"); get_http_time(0, buf, sizeof(buf)); if (!err) err = enlist_unique_header(rsp->headers, "Date", buf); if (!strncmpic(rsp->status, "403", 3) || !strncmpic(rsp->status, "404", 3) || !strncmpic(rsp->status, "502", 3) || !strncmpic(rsp->status, "503", 3) || !strncmpic(rsp->status, "504", 3)) { if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Wed, 08 Jun 1955 12:00:00 GMT"); } else { if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", buf); } if (!err) err = enlist_unique_header(rsp->headers, "Expires", "Sat, 17 Jun 2000 12:00:00 GMT"); if (!err) err = enlist_unique_header(rsp->headers, "Pragma", "no-cache"); } if (!err && (!(csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) || (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))) { err = enlist_unique_header(rsp->headers, "Connection", "close"); } /* * Write the head */ if (err || (NULL == (rsp->head = list_to_text(rsp->headers)))) { free_http_response(rsp); return cgi_error_memory(); } rsp->head_length = strlen(rsp->head); return rsp; } /********************************************************************* * * Function : alloc_http_response * * Description : Allocates a new http_response structure. * * Parameters : N/A * * Returns : pointer to a new http_response, or NULL. * *********************************************************************/ struct http_response *alloc_http_response(void) { return (struct http_response *) zalloc(sizeof(struct http_response)); } /********************************************************************* * * Function : free_http_response * * Description : Free the memory occupied by an http_response * and its depandant structures. * * Parameters : * 1 : rsp = pointer to http_response to be freed * * Returns : N/A * *********************************************************************/ void free_http_response(struct http_response *rsp) { /* * Must special case cgi_error_memory_response, which is never freed. */ if (rsp && (rsp != cgi_error_memory_response)) { freez(rsp->status); freez(rsp->head); freez(rsp->body); destroy_list(rsp->headers); free(rsp); } } /********************************************************************* * * Function : template_load * * Description : CGI support function that loads a given HTML * template, ignoring comment lines and following * #include statements up to a depth of 1. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : template_ptr = Destination for pointer to loaded * template text. * 3 : templatename = name of the HTML template to be used * 4 : recursive = Flag set if this function calls itself * following an #include statament * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * JB_ERR_FILE if the template file cannot be read * *********************************************************************/ jb_err template_load(const struct client_state *csp, char **template_ptr, const char *templatename, int recursive) { jb_err err; char *templates_dir_path; char *full_path; char *file_buffer; char *included_module; const char *p; FILE *fp; char buf[BUFFER_SIZE]; assert(csp); assert(template_ptr); assert(templatename); *template_ptr = NULL; /* Validate template name. Paranoia. */ for (p = templatename; *p != 0; p++) { if ( ((*p < 'a') || (*p > 'z')) && ((*p < 'A') || (*p > 'Z')) && ((*p < '0') || (*p > '9')) && (*p != '-') && (*p != '.')) { /* Illegal character */ return JB_ERR_FILE; } } /* * Generate full path using either templdir * or confdir/templates as base directory. */ if (NULL != csp->config->templdir) { templates_dir_path = strdup(csp->config->templdir); } else { templates_dir_path = make_path(csp->config->confdir, "templates"); } if (templates_dir_path == NULL) { log_error(LOG_LEVEL_ERROR, "Out of memory while generating template path for %s.", templatename); return JB_ERR_MEMORY; } full_path = make_path(templates_dir_path, templatename); free(templates_dir_path); if (full_path == NULL) { log_error(LOG_LEVEL_ERROR, "Out of memory while generating full template path for %s.", templatename); return JB_ERR_MEMORY; } /* Allocate buffer */ file_buffer = strdup(""); if (file_buffer == NULL) { log_error(LOG_LEVEL_ERROR, "Not enough free memory to buffer %s.", full_path); free(full_path); return JB_ERR_MEMORY; } /* Open template file */ if (NULL == (fp = fopen(full_path, "r"))) { log_error(LOG_LEVEL_ERROR, "Cannot open template file %s: %E", full_path); free(full_path); free(file_buffer); return JB_ERR_FILE; } free(full_path); /* * Read the file, ignoring comments, and honoring #include * statements, unless we're already called recursively. * * XXX: The comment handling could break with lines lengths > sizeof(buf). * This is unlikely in practise. */ while (fgets(buf, sizeof(buf), fp)) { if (!recursive && !strncmp(buf, "#include ", 9)) { if (JB_ERR_OK != (err = template_load(csp, &included_module, chomp(buf + 9), 1))) { free(file_buffer); fclose(fp); return err; } if (string_join(&file_buffer, included_module)) { fclose(fp); return JB_ERR_MEMORY; } continue; } /* skip lines starting with '#' */ if (*buf == '#') { continue; } if (string_append(&file_buffer, buf)) { fclose(fp); return JB_ERR_MEMORY; } } fclose(fp); *template_ptr = file_buffer; return JB_ERR_OK; } /********************************************************************* * * Function : template_fill * * Description : CGI support function that fills in a pre-loaded * HTML template by replacing @name@ with value using * pcrs, for each item in the output map. * * Note that a leading '$' character in the export map's * values will be stripped and toggle on backreference * interpretation. * * Parameters : * 1 : template_ptr = IN: Template to be filled out. * Will be free()d. * OUT: Filled out template. * Caller must free(). * 2 : exports = map with fill in symbol -> name pairs * * Returns : JB_ERR_OK on success (and for uncritical errors) * JB_ERR_MEMORY on out-of-memory error * *********************************************************************/ jb_err template_fill(char **template_ptr, const struct map *exports) { struct map_entry *m; pcrs_job *job; char buf[BUFFER_SIZE]; char *tmp_out_buffer; char *file_buffer; size_t size; int error; const char *flags; assert(template_ptr); assert(*template_ptr); assert(exports); file_buffer = *template_ptr; size = strlen(file_buffer) + 1; /* * Assemble pcrs joblist from exports map */ for (m = exports->first; m != NULL; m = m->next) { if (*m->name == '$') { /* * First character of name is '$', so remove this flag * character and allow backreferences ($1 etc) in the * "replace with" text. */ snprintf(buf, sizeof(buf), "%s", m->name + 1); flags = "sigU"; } else { /* * Treat the "replace with" text as a literal string - * no quoting needed, no backreferences allowed. * ("Trivial" ['T'] flag). */ flags = "sigTU"; /* Enclose name in @@ */ snprintf(buf, sizeof(buf), "@%s@", m->name); } log_error(LOG_LEVEL_CGI, "Substituting: s/%s/%s/%s", buf, m->value, flags); /* Make and run job. */ job = pcrs_compile(buf, m->value, flags, &error); if (job == NULL) { if (error == PCRS_ERR_NOMEM) { free(file_buffer); *template_ptr = NULL; return JB_ERR_MEMORY; } else { log_error(LOG_LEVEL_ERROR, "Error compiling template fill job %s: %d", m->name, error); /* Hope it wasn't important and silently ignore the invalid job */ } } else { error = pcrs_execute(job, file_buffer, size, &tmp_out_buffer, &size); pcrs_free_job(job); if (NULL == tmp_out_buffer) { *template_ptr = NULL; return JB_ERR_MEMORY; } if (error < 0) { /* * Substitution failed, keep the original buffer, * log the problem and ignore it. * * The user might see some unresolved @CGI_VARIABLES@, * but returning a special CGI error page seems unreasonable * and could mask more important error messages. */ free(tmp_out_buffer); log_error(LOG_LEVEL_ERROR, "Failed to execute s/%s/%s/%s. %s", buf, m->value, flags, pcrs_strerror(error)); } else { /* Substitution succeeded, use modified buffer. */ free(file_buffer); file_buffer = tmp_out_buffer; } } } /* * Return */ *template_ptr = file_buffer; return JB_ERR_OK; } /********************************************************************* * * Function : template_fill_for_cgi * * Description : CGI support function that loads a HTML template * and fills it in. Handles file-not-found errors * by sending a HTML error message. For convenience, * this function also frees the passed "exports" map. * * Parameters : * 1 : csp = Client state * 2 : templatename = name of the HTML template to be used * 3 : exports = map with fill in symbol -> name pairs. * Will be freed by this function. * 4 : rsp = Response structure to fill in. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error * *********************************************************************/ jb_err template_fill_for_cgi(const struct client_state *csp, const char *templatename, struct map *exports, struct http_response *rsp) { jb_err err; assert(csp); assert(templatename); assert(exports); assert(rsp); err = template_load(csp, &rsp->body, templatename, 0); if (err == JB_ERR_FILE) { free_map(exports); return cgi_error_no_template(csp, rsp, templatename); } else if (err) { free_map(exports); return err; /* JB_ERR_MEMORY */ } err = template_fill(&rsp->body, exports); free_map(exports); return err; } /********************************************************************* * * Function : default_exports * * Description : returns a struct map list that contains exports * which are common to all CGI functions. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : caller = name of CGI who calls us and which should * be excluded from the generated menu. May be * NULL. * Returns : NULL if no memory, else a new map. Caller frees. * *********************************************************************/ struct map *default_exports(const struct client_state *csp, const char *caller) { char buf[30]; jb_err err; struct map * exports; int local_help_exists = 0; char *ip_address = NULL; char *port = NULL; char *hostname = NULL; assert(csp); exports = new_map(); if (exports == NULL) { return NULL; } if (csp->config->hostname) { get_host_information(csp->cfd, &ip_address, &port, NULL); hostname = strdup(csp->config->hostname); } else { get_host_information(csp->cfd, &ip_address, &port, &hostname); } err = map(exports, "version", 1, html_encode(VERSION), 0); get_locale_time(buf, sizeof(buf)); if (!err) err = map(exports, "time", 1, html_encode(buf), 0); if (!err) err = map(exports, "my-ip-address", 1, html_encode(ip_address ? ip_address : "unknown"), 0); freez(ip_address); if (!err) err = map(exports, "my-port", 1, html_encode(port ? port : "unknown"), 0); freez(port); if (!err) err = map(exports, "my-hostname", 1, html_encode(hostname ? hostname : "unknown"), 0); freez(hostname); if (!err) err = map(exports, "homepage", 1, html_encode(HOME_PAGE_URL), 0); if (!err) err = map(exports, "default-cgi", 1, html_encode(CGI_PREFIX), 0); if (!err) err = map(exports, "menu", 1, make_menu(caller, csp->config->feature_flags), 0); if (!err) err = map(exports, "code-status", 1, CODE_STATUS, 1); if (!strncmpic(csp->config->usermanual, "file://", 7) || !strncmpic(csp->config->usermanual, "http", 4)) { /* Manual is located somewhere else, just link to it. */ if (!err) err = map(exports, "user-manual", 1, html_encode(csp->config->usermanual), 0); } else { /* Manual is delivered by Privoxy. */ if (!err) err = map(exports, "user-manual", 1, html_encode(CGI_PREFIX"user-manual/"), 0); } if (!err) err = map(exports, "actions-help-prefix", 1, ACTIONS_HELP_PREFIX ,1); #ifdef FEATURE_TOGGLE if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state); #else if (!err) err = map_block_killer(exports, "can-toggle"); #endif if (!strcmp(CODE_STATUS, "stable")) { if (!err) err = map_block_killer(exports, "unstable"); } if (csp->config->admin_address != NULL) { if (!err) err = map(exports, "admin-address", 1, html_encode(csp->config->admin_address), 0); local_help_exists = 1; } else { if (!err) err = map_block_killer(exports, "have-adminaddr-info"); } if (csp->config->proxy_info_url != NULL) { if (!err) err = map(exports, "proxy-info-url", 1, html_encode(csp->config->proxy_info_url), 0); local_help_exists = 1; } else { if (!err) err = map_block_killer(exports, "have-proxy-info"); } if (local_help_exists == 0) { if (!err) err = map_block_killer(exports, "have-help-info"); } if (err) { free_map(exports); return NULL; } return exports; } /********************************************************************* * * Function : map_block_killer * * Description : Convenience function. * Adds a "killer" for the conditional HTML-template * block , i.e. a substitution of the regex * "if--start.*if--end" to the given * export list. * * Parameters : * 1 : exports = map to extend * 2 : name = name of conditional block * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err map_block_killer(struct map *exports, const char *name) { char buf[1000]; /* Will do, since the names are hardwired */ assert(exports); assert(name); assert(strlen(name) < (size_t)490); snprintf(buf, sizeof(buf), "if-%s-start.*if-%s-end", name, name); return map(exports, buf, 1, "", 1); } /********************************************************************* * * Function : map_block_keep * * Description : Convenience function. Removes the markers used * by map-block-killer, to save a few bytes. * i.e. removes "@if--start@" and "@if--end@" * * Parameters : * 1 : exports = map to extend * 2 : name = name of conditional block * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err map_block_keep(struct map *exports, const char *name) { jb_err err; char buf[500]; /* Will do, since the names are hardwired */ assert(exports); assert(name); assert(strlen(name) < (size_t)490); snprintf(buf, sizeof(buf), "if-%s-start", name); err = map(exports, buf, 1, "", 1); if (err) { return err; } snprintf(buf, sizeof(buf), "if-%s-end", name); return map(exports, buf, 1, "", 1); } /********************************************************************* * * Function : map_conditional * * Description : Convenience function. * Adds an "if-then-else" for the conditional HTML-template * block , i.e. a substitution of the form: * @if--then@ * True text * @else-not-@ * False text * @endif-@ * * The control structure and one of the alternatives * will be hidden. * * Parameters : * 1 : exports = map to extend * 2 : name = name of conditional block * 3 : choose_first = nonzero for first, zero for second. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err map_conditional(struct map *exports, const char *name, int choose_first) { char buf[1000]; /* Will do, since the names are hardwired */ jb_err err; assert(exports); assert(name); assert(strlen(name) < (size_t)480); snprintf(buf, sizeof(buf), (choose_first ? "else-not-%s@.*@endif-%s" : "if-%s-then@.*@else-not-%s"), name, name); err = map(exports, buf, 1, "", 1); if (err) { return err; } snprintf(buf, sizeof(buf), (choose_first ? "if-%s-then" : "endif-%s"), name); return map(exports, buf, 1, "", 1); } /********************************************************************* * * Function : make_menu * * Description : Returns an HTML-formatted menu of the available * unhidden CGIs, excluding the one given in * and the toggle CGI if toggling is disabled. * * Parameters : * 1 : self = name of CGI to leave out, can be NULL for * complete listing. * 2 : feature_flags = feature bitmap from csp->config * * * Returns : menu string, or NULL on out-of-memory error. * *********************************************************************/ char *make_menu(const char *self, const unsigned feature_flags) { const struct cgi_dispatcher *d; char *result = strdup(""); if (self == NULL) { self = "NO-SUCH-CGI!"; } /* List available unhidden CGI's and export as "other-cgis" */ for (d = cgi_dispatchers; d->name; d++) { #ifdef FEATURE_TOGGLE if (!(feature_flags & RUNTIME_FEATURE_CGI_TOGGLE) && !strcmp(d->name, "toggle")) { /* * Suppress the toggle link if remote toggling is disabled. */ continue; } #endif /* def FEATURE_TOGGLE */ if (d->description && strcmp(d->name, self)) { char *html_encoded_prefix; /* * Line breaks would be great, but break * the "blocked" template's JavaScript. */ string_append(&result, "
  • name); string_append(&result, "\">"); string_append(&result, d->description); string_append(&result, "
  • "); } } return result; } /********************************************************************* * * Function : dump_map * * Description : HTML-dump a map for debugging (as table) * * Parameters : * 1 : the_map = map to dump * * Returns : string with HTML * *********************************************************************/ char *dump_map(const struct map *the_map) { struct map_entry *cur_entry; char *ret = strdup(""); string_append(&ret, "\n"); for (cur_entry = the_map->first; (cur_entry != NULL) && (ret != NULL); cur_entry = cur_entry->next) { string_append(&ret, "\n"); } string_append(&ret, "
    "); string_join (&ret, html_encode(cur_entry->name)); string_append(&ret, ""); string_join (&ret, html_encode(cur_entry->value)); string_append(&ret, "
    \n"); return ret; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./configure.in000640 001751 001751 00000077001 12114164002 016267 0ustar00fkfk000000 000000 dnl Process this file with autoconf to produce a configure script. dnl dnl $Id: configure.in,v 1.179 2013/03/01 17:40:18 fabiankeil Exp $ dnl dnl Written by and Copyright (C) 2001-2010 the dnl Privoxy team. http://www.privoxy.org/ dnl dnl Based on the Internet Junkbuster originally written dnl by and Copyright (C) 1997 Anonymous Coders and dnl Junkbusters Corporation. http://www.junkbusters.com dnl dnl This program is free software; you can redistribute it dnl and/or modify it under the terms of the GNU General dnl Public License as published by the Free Software dnl Foundation; either version 2 of the License, or (at dnl your option) any later version. dnl dnl This program is distributed in the hope that it will dnl be useful, but WITHOUT ANY WARRANTY; without even the dnl implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. See the GNU General Public dnl License for more details. dnl dnl The GNU General Public License should be included with dnl this file. If not, you can view it at dnl http://www.gnu.org/copyleft/gpl.html dnl or write to the Free Software Foundation, Inc., 59 dnl Temple Place - Suite 330, Boston, MA 02111-1307, USA. dnl dnl ================================================================= dnl AutoConf Initialization dnl ================================================================= AC_REVISION($Revision: 1.179 $) AC_INIT(jcc.c) if test ! -f config.h.in; then echo "You need to run autoheader first. " echo -n "Shall I do this for you now? (y/n) " read answer if test "$answer" != "y"; then exit 1 else autoheader fi fi AC_CONFIG_HEADER([config.h]) AC_CANONICAL_HOST dodk=auto DKPREFIX=none AC_ARG_WITH(docbook, dnl --with-docbook=[[yes|no|directory]] Enable docbook documentation creation (default = yes, for gnu and linux),[dnl case "$with_docbook" in yes) dodk=yes;; no) dodk=no;; *) dodk=yes DKPREFIX=$withval ;; esac ]) DB2HTML=false AC_ARG_WITH(db2html, dnl --with-db2html= Set the location of the docbook to html converter (default = search),[dnl DB2HTML=$withval ]) dnl ================================================================= dnl Application version number dnl ================================================================= VERSION_MAJOR=3 VERSION_MINOR=0 VERSION_POINT=21 CODE_STATUS="stable" dnl CODE_STATUS can be "alpha", "beta", "stable" or "UNRELEASED", dnl and will be used for CGI output. Increment version number and dnl set status to "UNRELEASED" whenever CVS differs from the last dnl release and no new release is near. dnl ================================================================= dnl Substitute the version numbers dnl ================================================================= AC_SUBST(VERSION_MAJOR) AC_SUBST(VERSION_MINOR) AC_SUBST(VERSION_POINT) AC_SUBST(CODE_STATUS) dnl AC_DEFINE_UNQUOTED(VERSION_MAJOR,${VERSION_MAJOR}) AC_DEFINE_UNQUOTED(VERSION_MINOR,${VERSION_MINOR}) AC_DEFINE_UNQUOTED(VERSION_POINT,${VERSION_POINT}) AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}") AC_DEFINE_UNQUOTED(CODE_STATUS,"${CODE_STATUS}") dnl ================================================================= dnl Checks for programs needed to build. dnl ================================================================= dnl Keep AC_PROG_CC from setting its own defaults: if test "X$CFLAGS" = "X"; then CFLAGS=" " fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_AWK AC_CHECK_PROG(GDB,gdb,yes,no) AC_PATH_PROG(BGROUPS,groups,no,$PATH:/bin:/usr/bin:/usr/local/bin) AC_PATH_PROG(ID,id,no,$PATH:/bin:/usr/bin:/usr/local/bin) AC_SUBST(ID) AC_SUBST(BGROUPS) dnl ================================================================= dnl debug, gcc and gdb support dnl ================================================================= AC_ARG_WITH(debug, [ --with-debug Enable debug mode], [ if test "x$withval" != "xno" ; then if test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then if test "$GDB"; then CFLAGS="$CFLAGS -ggdb" else CFLAGS="$CFLAGS -g" fi CFLAGS="$CFLAGS -Wshadow -Wconversion" else CFLAGS="$CFLAGS -g" fi fi fi ], [ if test "X$CFLAGS" = "X "; then # if CFLAGS were unset (see above) if test "$GCC" = yes; then CFLAGS="-O2" fi fi ] ) dnl ================================================================= dnl Check for user and group validity dnl ================================================================= if test "$EMXOS2" = yes || test "$host_os" = haiku; then echo "Skipping user and group validity stuff."; else $ID privoxy >/dev/null 2>/dev/null if test $? -ne 0 ; then AC_MSG_WARN(There is no user 'privoxy' on this system) fi AC_MSG_CHECKING([for user]) AC_ARG_WITH(user, [ --with-user=privoxy Set user under which privoxy will run], [ if test "x$withval" != "xyes"; then if test $ID = no ; then AC_MSG_ERROR(There is no 'id' program on this system) else AC_MSG_RESULT($with_user) $ID $with_user 2>/dev/null >/dev/null if test $? -eq 0 ; then USER=$with_user; else AC_MSG_ERROR(There is no user '$with_user' on this system) fi fi else AC_MSG_ERROR(We need a user if you give me this parameter) fi ], [ if test $ID = no ; then AC_MSG_ERROR(There is no 'id' programm on this system) else AC_MSG_RESULT(none specified) USER=$with_user fi ] ) AC_SUBST(USER) AC_MSG_CHECKING([for group]) AC_ARG_WITH(group, [ --with-group=privoxy Set group for privoxy], [ if test "x$withval" != "xyes"; then if test $BGROUPS = no ; then AC_MSG_ERROR(There is no 'groups' program on this system) else AC_MSG_RESULT($with_group) $BGROUPS $USER >/dev/null if test $? -eq 0 ; then # FIXME: this fails if valid group, but not first group # listed. if test "$with_group" != "`$BGROUPS $USER | sed 's/.*: //' 2>/dev/null |$AWK '{print $1}'`" ; then AC_MSG_ERROR(The given value '$withval' does not match group entry) else GROUP=$with_group; fi else AC_MSG_ERROR(There is no group entry for user '$USER') fi fi else AC_MSG_ERROR(We need a group if you give me this parameter) fi ], [ if test $BGROUPS = no ; then AC_MSG_ERROR(There is no 'groups' programm on this system) else AC_MSG_RESULT(none specified) GROUP=$with_group; fi ] ) AC_SUBST(GROUP) fi dnl ================================================================= dnl additional gcc flags dnl ================================================================= dnl if test "$GCC"; then if test "$host" != "powerpc-unknown-amigaos"; then CFLAGS="-pipe $CFLAGS" fi fi dnl ================================================================= dnl Build type dnl ================================================================= dnl dnl Must do this first. dnl dnl Reason: This sets CFLAGS in order to switch the Cygwin compiler dnl into Cygwin or MinGW32 modes. Depending on the mode selected, dnl the compiler will use completely different sets of library dnl and include files. dnl dnl ================================================================= AC_MINGW32 AC_CYGWIN if test "$MINGW32" = "yes"; then target_type=mingw else if test "$CYGWIN" = "yes"; then target_type=cygwin else target_type=unix fi fi if test $dodk = auto; then dodk=no if test $target_type = unix; then case "$host_os" in linux* | gnu*) dodk=yes ;; esac fi fi dnl Decide what to do based on target_type dnl Note: PTHREAD_LIB is always set, even if pthread is disabled. dnl This is because we don't know yet whether pthread is enabled. AC_ARG_ENABLE(mingw32, [ --enable-mingw32 Use mingw32 for a Windows GUI], [if test $enableval = yes; then target_type=mingw fi]) if test $target_type = mingw; then WIN_ONLY= CFLAGS="$CFLAGS -DWINVER=0x501" SPECIAL_CFLAGS="-mwindows -mno-cygwin" PTHREAD_LIB=-lpthreadGC echo "Using mingw32 (Win32 GUI)" else WIN_ONLY=# if test $target_type = cygwin; then SPECIAL_CFLAGS="-mno-win32" PTHREAD_LIB= echo "Using Cygnus (Win32 command line)" else SPECIAL_CFLAGS= PTHREAD_LIB=-lpthread fi fi AC_SUBST(WIN_ONLY) if test $dodk != no; then AC_CHECK_PROGS(W3M, w3m, false) if test "$W3M" = false; then AC_MSG_WARN(You need w3m to build text documentation.) fi if test $DB2HTML = false; then dnl We need to clean the variable, otherwise AC_CHECK_PROGS dnl will fail DB2HTML="" AC_CHECK_PROGS(DB2HTML,db2html docbook2html,false) fi fi AC_SUBST(W3M) AC_SUBST(DB2HTML) dnl If we use rpm, we need to check where %_topdir is AC_CHECK_PROGS(RPMBIN,rpm,false) if test $RPMBIN != false; then RPM_BASE=`rpm --eval "%{_topdir}"` if test "$RPM_BASE" = ""; then RPM_BASE=/usr/src/redhat fi fi AC_SUBST(RPM_BASE) dnl Check for jade, so we can build the documentation AC_CHECK_PROGS(JADEBIN,jade openjade,false) AC_SUBST(JADEBIN) dnl Check for man2html for docs. AC_CHECK_PROGS(MAN2HTML,man2html,false) AC_SUBST(MAN2HTML) dnl Set doc status flag for conditional content inclusions DOC_STATUS=p-not-stable if test $CODE_STATUS = stable; then DOC_STATUS="p-stable" fi AC_SUBST(DOC_STATUS) dnl Checking for the docbook.dsl stylesheet file dnl It is still not portable (directory slash) JADECAT="" if test $dodk = yes; then if test $DKPREFIX = none; then for i in /usr/share/sgml/docbook/dsssl-stylesheets \ /usr/share/sgml/docbkdsl /usr/share/sgml/docbook-dsssl \ /usr/local/share/sgml/docbook/dsssl/modular \ /usr/share/sgml/docbook/stylesheet/dsssl/modular/ \ ; do dnl echo -n does not fly with /bin/sh. dnl echo -n "checking for $i/html/docbook.dsl..." AC_MSG_CHECKING([for $i]) if test -f $i/html/docbook.dsl; then echo "yes" DKPREFIX=$i break else echo "no" fi done # where are the catalogs? for i in /usr/share/sgml/CATALOG.docbk30 \ /usr/share/sgml/CATALOG.docbk31 \ /usr/share/sgml/CATALOG.docbk31 \ /usr/local/share/sgml/docbook/3.0/docbook.cat \ /usr/local/share/sgml/docbook/3.1/docbook.cat \ /usr/share/sgml/docbook/dtd/3.1/docbook.cat \ ; do dnl echo -n "checking for $i..." AC_MSG_CHECKING([for $i]) if test -f $i; then echo "yes" JADECAT="$JADECAT -c $i" else echo "no" fi done fi fi AC_SUBST(JADECAT) AC_SUBST(DKPREFIX) AC_ARG_ENABLE(large-file-support, [ --enable-large-file-support Define _LARGE_FILES and friends. Required by some systems to support files larger then 2GB.], [if test $enableval = yes; then CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE_SOURCE=1" fi]) dnl Save old CFLAGS so we can restore them later, then add SPECIAL_CFLAGS old_CFLAGS_nospecial=$CFLAGS CFLAGS="$CFLAGS $SPECIAL_CFLAGS" # Hack to force AutoConf to use the CFLAGS we just set dnl Warning: This may break with a future version of Autoconf dnl Tested with autoconf 2.13 ac_cpp='$CPP $CPPFLAGS $SPECIAL_CFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' dnl ================================================================= dnl Thread support dnl ================================================================= AC_CHECK_HEADER(pthread.h, [have_pthread=yes], [have_pthread=no]) AC_ARG_ENABLE(pthread, [ --disable-pthread Don't use POSIX threads (pthreads)], [if test $enableval = no; then # Disable pthreads if test $have_pthread = yes; then AC_MSG_WARN([pthreads seem to be available but you are using --disable-pthread.]) AC_MSG_WARN([This is almost always a mistake and can render Privoxy unacceptable slow.]) fi have_pthread=no fi]) if test $have_pthread = yes; then PTHREAD_ONLY= AC_DEFINE(FEATURE_PTHREAD) echo Using POSIX threads if test "$GCC" = "yes"; then # Set a GCC specific switch: if test "$target_type" = "unix"; then ac_jgf_save_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -pthread" AC_TRY_LINK([#include ], [void *p = pthread_create;], [ # This compiler switch makes GCC on Linux thread-safe # However, it's not supported on most other OS. PTHREAD_LIB= SPECIAL_CFLAGS="-pthread" ]) CFLAGS=$ac_jgf_save_CFLAGS fi fi else PTHREAD_ONLY=# echo Using native threads fi AC_SUBST(PTHREAD_ONLY) dnl ================================================================= dnl Support for thread-safe versions of gethostbyaddr, gethostbyname, dnl gmtime and localtime dnl ================================================================= dnl Next line needed to find the gethost*_r functions on Solaris AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_FUNC(gethostbyaddr_r, [ AC_MSG_CHECKING([signature of gethostbyaddr_r]) AC_TRY_COMPILE([ # include ], [ struct hostent *h, *hp; char *a, *b; int l, bl, t, e; (void) gethostbyaddr_r(a, l, t, h, b, bl, &hp, &e) ], [ AC_DEFINE(HAVE_GETHOSTBYADDR_R_8_ARGS) AC_MSG_RESULT([8 args]) ], [ AC_TRY_COMPILE([ # include ], [ struct hostent *h; char *a, *b; int l, bl, t, e; (void) gethostbyaddr_r(a, l, t, h, b, bl, &e) ], [ AC_DEFINE(HAVE_GETHOSTBYADDR_R_7_ARGS) AC_MSG_RESULT([7 args]) ], [ AC_TRY_COMPILE([ # include ], [ struct hostent_data *d; struct hostent *h; char a, int l, t; (void) gethostbyaddr_r(a, l, t, h, d) ], [ AC_DEFINE(HAVE_GETHOSTBYADDR_R_5_ARGS) AC_MSG_RESULT([5 args]) ], [ AC_MSG_RESULT(unrecognised) ]) ]) ]) ], [ AC_MSG_RESULT(no) ]) AC_CHECK_FUNC(gethostbyname_r, [ AC_MSG_CHECKING([signature of gethostbyname_r]) AC_TRY_COMPILE([ # include ], [ struct hostent *h, *r; char *n, *b; int bl, e; (void) gethostbyname_r(n, h, b, bl, &r, &e) ], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARGS) AC_MSG_RESULT([6 args]) ], [ AC_TRY_COMPILE([ # include ], [ struct hostent *h; char *n, *b; int bl, e; (void) gethostbyname_r(n, h, b, bl, &e) ], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARGS) AC_MSG_RESULT([5 args]) ], [ AC_TRY_COMPILE([ # include ], [ struct hostent_data *d; struct hostent *h; char *n, (void) gethostbyname_r(n, h, d) ], [ AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARGS) AC_MSG_RESULT([3 args]) ], [ AC_MSG_RESULT(unrecognised) ]) ]) ]) ], [ AC_MSG_RESULT(no) ]) AC_CHECK_FUNC(gmtime_r, [ AC_MSG_CHECKING([signature of gmtime_r]) AC_TRY_COMPILE([ # include ], [ struct time *t; struct tm *tm; (void) gmtime_r(t, tm) ], [ AC_MSG_RESULT(ok) AC_DEFINE(HAVE_GMTIME_R) ], [ AC_MSG_RESULT(unrecognised) ]) ], [ AC_MSG_RESULT(no) ]) AC_CHECK_FUNC(localtime_r, [ AC_MSG_CHECKING([signature of localtime_r]) AC_TRY_COMPILE([ # include ], [ struct time *t; struct tm *tm; (void) localtime_r(t, tm) ], [ AC_MSG_RESULT(ok) AC_DEFINE(HAVE_LOCALTIME_R) ], [ AC_MSG_RESULT(unrecognised) ]) ], [ AC_MSG_RESULT(no) ]) dnl ================================================================= dnl Solaris specific dnl FIXME: Not tested on Solaris yet... dnl ISFIXED: Have tested it on Solaris, but there are other ways to dnl make these checks generic, e.g.: dnl AC_CHECK_FUNC(getsockopt, , AC_CHECK_LIB(socket, getsockopt)) dnl (Moritz Barsnick ) dnl ================================================================= SOCKET_LIB= case "$host" in *-solaris*) SOCKET_LIB="-lsocket -lnsl" AC_DEFINE(__EXTENSIONS__) if test "$GCC" = "yes"; then # Set a GCC specific switch: # This compiler switch makes Solaris thread-safe PTHREAD_LIB= SPECIAL_CFLAGS="-pthreads" else # What do we do without GCC? Guess this: SPECIAL_CFLAGS="-D_REENTRANT" fi ;; esac AC_SUBST(SOCKET_LIB) dnl ================================================================= dnl Solaris problem, and others perhaps (socklen_t is undefined) dnl ================================================================= AC_MSG_CHECKING([for socklen_t]) AC_EGREP_HEADER(socklen_t, sys/socket.h, AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) AC_DEFINE(socklen_t,int, [ Define to 'int' if doesn't have it. ])) dnl ================================================================= dnl OS/2 specific dnl ================================================================= case "$host" in *-os2-emx*) SOCKET_LIB=-lsocket ;; esac AC_SUBST(SOCKET_LIB) dnl ================================================================= dnl Mac OSX specific dnl ================================================================= case "$host" in *-apple-darwin*) SPECIAL_CFLAGS="-Dunix" ;; esac dnl ================================================================= dnl OpenBSD specific dnl ================================================================= case "$host" in *-openbsd*) SPECIAL_CFLAGS="$SPECIAL_CFLAGS -Dunix" ;; esac dnl ================================================================= dnl AmigaOS specific dnl ================================================================= AMIGAOS_ONLY=# case "$host" in *-amigaos) AMIGAOS_ONLY= ;; esac AC_SUBST(AMIGAOS_ONLY) dnl ================================================================= dnl Haiku specific dnl ================================================================= if test "$host_os" = haiku; then # Omit the "-pthread" flag to gcc, even when building with gcc 2.95 SPECIAL_CFLAGS= # Haiku's pthreads implementation exists in its system library, # libroot, not in a separate pthreads library PTHREAD_LIB= # Networking code exists in libnetwork SOCKET_LIB=-lnetwork # Search Haiku's common-library folder to find its pcre and # pcreposix libraries LIBS="-L/boot/common/lib $LIBS" fi dnl ================================================================= dnl Check for standard compiler stuff dnl ================================================================= AC_EXEEXT AC_OBJEXT AC_HEADER_STDC AC_HEADER_DIRENT AC_C_CONST AC_TYPE_SIZE_T AC_TYPE_PID_T AC_HEADER_TIME AC_STRUCT_TM AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(char *, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(long long, 8) AC_CHECK_SIZEOF(size_t, 4) dnl Checks for header files. AC_CHECK_HEADERS([ \ OS.h \ arpa/inet.h \ errno.h \ fcntl.h \ limits.h \ locale.h \ netdb.h \ netinet/in.h \ stddef.h \ stdlib.h \ string.h \ sys/ioctl.h \ sys/socket.h \ sys/time.h \ sys/timeb.h \ sys/wait.h \ unistd.h \ ]) dnl Checks for library functions. dnl bcopy is for PCRE AC_CHECK_FUNCS([bcopy]) AC_PROG_GCC_TRADITIONAL AC_TYPE_SIGNAL AC_CHECK_FUNCS([ \ access \ atexit \ getcwd \ gethostbyaddr \ gethostbyaddr_r \ gethostbyname \ gethostbyname_r \ gettimeofday \ inet_ntoa \ localtime_r \ memchr \ memmove \ memset \ poll \ putenv \ random \ regcomp \ select \ setlocale \ shutdown \ snprintf \ socket \ strchr \ strdup \ strerror \ strftime \ strlcat \ strlcpy \ strptime \ strtoul \ timegm \ tzset \ ]) dnl Checks for RFC 2553 resolver and socket functions AC_ARG_ENABLE(ipv6-support, [ --disable-ipv6-support Disable IPv6 support and other RFC-2554-related improvements], [if test $enableval = yes; then enable_ipv6_support=yes fi], enable_ipv6_support=yes) if test $enable_ipv6_support != yes; then AC_MSG_WARN([Skipping checks for IPv6 support and other RFC-2554-related improvements. Due to lock contention, this may result in slower DNS resolution for IPv4 setups, too.]) elif test $target_type = mingw; then AC_CHECK_LIB(ws2_32, main) AC_MSG_CHECKING(getaddrinfo in ws2_32) AC_TRY_LINK( [ #include #include ], [getaddrinfo(0,0,0,0)], have_ws2_32_getaddrinfo=yes ) AC_MSG_RESULT($have_ws2_32_getaddrinfo) AC_MSG_CHECKING(getnameinfo in ws2_32) AC_TRY_LINK( [ #include #include ], [getnameinfo(0,0,0,0,0,0,0)], have_ws2_32_getnameinfo=yes ) AC_MSG_RESULT($have_ws2_32_getnameinfo) if test $have_ws2_32_getaddrinfo ; then if test $have_ws2_32_getnameinfo ; then AC_DEFINE([HAVE_RFC2553], [1], [Define if RFC 2553 resolver functions like getaddrinfo(3) and getnameinfo(3) present]) fi fi else AC_CHECK_FUNC([getaddrinfo], [AC_CHECK_FUNC([getnameinfo], [AC_DEFINE([HAVE_RFC2553], [1], [Define if RFC 2553 resolver functions like getaddrinfo(3) and getnameinfo(3) present]) ]) ]) fi dnl ================================================================= dnl Checks for libraries. dnl ================================================================= dnl Note: Some systems may have the library but not the system header dnl file, so we must check for both. dnl Also check for correct version AC_CHECK_LIB(pcre, pcre_compile, [ AC_CHECK_HEADER(pcre.h, [ AC_EGREP_HEADER(pcre_fullinfo, pcre.h, [have_pcre=yes], [AC_MSG_WARN([[pcre old version installed]]); have_pcre=no]) ], [ AC_CHECK_HEADER(pcre/pcre.h, [ AC_EGREP_HEADER(pcre_fullinfo, pcre/pcre.h, [have_pcre=yes]; [AC_DEFINE(PCRE_H_IN_SUBDIR)], [AC_MSG_WARN([[pcre old version installed]]); have_pcre=no]) ], [have_pcre=no]) ]) ], [have_pcre=no]) AC_CHECK_LIB(pcreposix, regcomp, [ AC_CHECK_HEADER(pcreposix.h, [ AC_EGREP_HEADER(pcreposix_regerror, pcreposix.h, [AC_MSG_WARN([[pcreposix old version installed]]); have_pcreposix=no], [have_pcreposix=yes]) ], [ AC_CHECK_HEADER(pcre/pcreposix.h, [ AC_EGREP_HEADER(pcreposix_regerror, pcre/pcreposix.h, [AC_MSG_WARN([[pcreposix old version installed]]); have_pcreposix=no], [have_pcreposix=yes]; [AC_DEFINE(PCREPOSIX_H_IN_SUBDIR)]) ], [have_pcreposix=no]) ]) ], [have_pcreposix=no], -lpcre) dnl ================================================================ dnl libpcrs is temporarily disabled. dnl dnl Privoxy's own pcrs version fixes some problems that dnl are present in libpcrs 0.3, the last pcrs release we dnl know of, and as libpcrs seems to be currently unmaintained dnl we can't send these fixes upstream. dnl ================================================================ dnl dnl AC_CHECK_LIB(pcrs, pcrs_compile, [AC_CHECK_HEADER(pcrs.h, [have_pcrs=yes], [have_pcrs=no])], [have_pcrs=no], -lpcre) dnl ================================================================= dnl Always defined dnl ================================================================= AC_DEFINE(__MT__) dnl ================================================================= dnl Features dnl ================================================================= AC_ARG_ENABLE(toggle, [ --disable-toggle Don't support temporary disable], [if test $enableval = yes; then AC_DEFINE(FEATURE_TOGGLE) fi],AC_DEFINE(FEATURE_TOGGLE)) AC_ARG_ENABLE(force, [ --disable-force Don't allow single-page disable], [if test $enableval = yes; then AC_DEFINE(FEATURE_FORCE_LOAD) fi],AC_DEFINE(FEATURE_FORCE_LOAD)) AC_ARG_ENABLE(fast-redirects, [ --disable-fast-redirects Don't support fast redirects], [if test $enableval = yes; then AC_DEFINE(FEATURE_FAST_REDIRECTS) fi], AC_DEFINE(FEATURE_FAST_REDIRECTS)) AC_ARG_ENABLE(stats, [ --disable-stats Don't keep statistics], [if test $enableval = yes; then AC_DEFINE(FEATURE_STATISTICS) fi],AC_DEFINE(FEATURE_STATISTICS)) AC_ARG_ENABLE(ie-images, [ --enable-ie-images Enable a quick but not always reliable auto-detect whether requests from MS Internet Explorer are for an image or not.], [if test $enableval = yes; then AC_DEFINE(FEATURE_IMAGE_DETECT_MSIE) fi],) AC_ARG_ENABLE(image-blocking, [ --disable-image-blocking Don't try to figure out whether a request is for an image or HTML - assume HTML.], [if test $enableval = yes; then AC_DEFINE(FEATURE_IMAGE_BLOCKING) fi], AC_DEFINE(FEATURE_IMAGE_BLOCKING)) AC_ARG_ENABLE(acl-support, [ --disable-acl-support Prevents the use of ACLs to control access to Privoxy by IP address.], [if test $enableval = yes; then AC_DEFINE(FEATURE_ACL) fi], AC_DEFINE(FEATURE_ACL)) AC_ARG_ENABLE(trust-files, [ --disable-trust-files Prevents the use of trust files.], [if test $enableval = yes; then AC_DEFINE(FEATURE_TRUST) fi], AC_DEFINE(FEATURE_TRUST)) AC_ARG_ENABLE(editor, [ --disable-editor Prevents the use of the web-based actions file editor and web-based temporary disable setting.], [if test $enableval = yes; then AC_DEFINE(FEATURE_CGI_EDIT_ACTIONS) fi], AC_DEFINE(FEATURE_CGI_EDIT_ACTIONS)) AC_ARG_ENABLE(no-gifs, [ --enable-no-gifs Use politically correct PNG format instead of GIF for built-in images. May not work with all browsers.], [if test $enableval = yes; then AC_DEFINE(FEATURE_NO_GIFS) fi]) AC_ARG_ENABLE(graceful-termination, [ --enable-graceful-termination Allow to shutdown Privoxy through the webinterface.], [if test $enableval = yes; then AC_DEFINE(FEATURE_GRACEFUL_TERMINATION) fi]) AC_ARG_ENABLE(extended-host-patterns, [ --enable-extended-host-patterns Enable and require PCRE syntax in host patterns. This feature hasn't been announced yet and it's not clear if it's a good idea. It's expected to work, but undocumented. You should only enable it if you know what PCRE is and are sure that you need it for your host patterns. You can use tools/url-pattern-translator.pl to convert existing action files to use PCRE host patterns. Please don't enable this option when creating packages for others that may not be expecting it.], [if test $enableval = yes; then AC_DEFINE(FEATURE_EXTENDED_HOST_PATTERNS) fi]) AC_ARG_ENABLE(accept-filter, [ --enable-accept-filter Try to use accf_http(9) if supported.], [if test $enableval = yes; then AC_DEFINE(FEATURE_ACCEPT_FILTER) fi]) AC_ARG_ENABLE(strptime-sanity-checks, [ --enable-strptime-sanity-checks Only trust strptime() results if an additional strftime()/strptime() conversion doesn't change the result. Can be useful if strptime() is known or suspected to be broken.], [if test $enableval = yes; then AC_DEFINE(FEATURE_STRPTIME_SANITY_CHECKS) fi]) dnl pcre/pcrs is needed for CGI anyway, so dnl the choice is only between static and dnl dynamic: AC_ARG_ENABLE(dynamic-pcre, [ --disable-dynamic-pcre Use the built-in, static pcre, even if libpcre is available], [ if test $enableval = "no"; then have_pcre=no; fi ]) dnl ================================================= dnl libpcrs is temporarily disabled, dnl see comment above for the reason. dnl ================================================= dnl AC_ARG_ENABLE(dynamic-pcrs, dnl [ --disable-dynamic-pcrs Use the built-in, static pcrs, even if libpcrs is available], dnl [ if test $enableval = "no"; then have_pcrs=no; fi ]) dnl ==================================================== dnl This check is incomplete. For mingw32 zlib is found dnl by configure, but not necessarily by the compiler. dnl ==================================================== AC_ARG_ENABLE(zlib, [ --disable-zlib Don't use zlib to decompress data before filtering.], [enableval2=$enableval], [enableval2=yes]) if test $enableval2 = yes; then AC_CHECK_LIB(z, zlibVersion, [have_zlib="yes"], [have_zlib="no"]) if test $have_zlib = "yes"; then LIBS="$LIBS -lz" AC_DEFINE(FEATURE_ZLIB,1,[Define to 1 to use zlib to decompress data before filtering.]) else AC_MSG_WARN([No zlib found. Privoxy will not be able to filter compressed content. This may become a fatal error in the future.]) fi fi AC_ARG_ENABLE(compression, [ --enable-compression Allow Privoxy to compress buffered content if the client supports it. Requires zlib support.], [enableval2=$enableval], [enableval2=no]) if test $enableval2 = yes; then if test $have_zlib = "yes"; then echo Enabling compression support. AC_DEFINE(FEATURE_COMPRESSION,1,[Define to 1 to use compression through the zlib library.]) else AC_MSG_WARN([No zlib found. Privoxy will not be able to (re-)compressed buffered content.]) fi fi # If we have libpcre and either we also have pcreposix or # we don't need pcreposix, then link pcre dynamically; else # build it and link statically # if test $have_pcre = "yes"; then echo "using libpcre" pcre_dyn=yes STATIC_PCRE_ONLY=# LIBS="$LIBS -lpcre -lpcreposix" else AC_MSG_WARN([You are using the static PCRE code which is out of date and scheduled for removal, for details see: http://sourceforge.net/mailarchive/forum.php?thread_name=20080511195555.2dc6cfdc%40fabiankeil.de&forum_name=ijbswa-developers]) pcre_dyn=no AC_DEFINE(STATIC_PCRE) STATIC_PCRE_ONLY= fi AC_DEFINE(FEATURE_CONNECTION_KEEP_ALIVE) if test $have_pthread = "yes" -o $target_type = "mingw"; then echo Enabling connection-sharing support. AC_DEFINE(FEATURE_CONNECTION_SHARING) fi dnl ================================================= dnl libpcrs is temporarily disabled, dnl see comment above for the reason. dnl ================================================= dnl # If we have libpcrs and pcre is linked dynamically dnl # then also link pcrs dynamically, else build and link dnl # pcrs statically dnl dnl if test $have_pcrs = "yes" -a $pcre_dyn = "yes"; then dnl echo "using libpcrs" dnl STATIC_PCRS_ONLY=# dnl LIBS="$LIBS -lpcrs" dnl else dnl echo "using built-in static pcrs" AC_DEFINE(STATIC_PCRS) STATIC_PCRS_ONLY= dnl fi AC_SUBST(STATIC_PCRE_ONLY) AC_SUBST(STATIC_PCRS_ONLY) dnl ================================================================= dnl Final cleanup and output dnl ================================================================= dnl Remove the SPECIAL_CFLAGS stuff from CFLAGS, and add it separately dnl in the Makefile CFLAGS=$old_CFLAGS_nospecial AC_SUBST(SPECIAL_CFLAGS) AC_SUBST(PTHREAD_LIB) AC_OUTPUT(GNUmakefile doc/source/ldp.dsl) privoxy-3.0.21-stable/./config000640 001751 001751 00000170545 12116120047 015160 0ustar00fkfk000000 000000 # Sample Configuration File for Privoxy 3.0.21 # # $Id: config,v 1.104 2013/03/07 14:11:51 fabiankeil Exp $ # # Copyright (C) 2001-2013 Privoxy Developers http://www.privoxy.org/ # #################################################################### # # # Table of Contents # # # # I. INTRODUCTION # # II. FORMAT OF THE CONFIGURATION FILE # # # # 1. LOCAL SET-UP DOCUMENTATION # # 2. CONFIGURATION AND LOG FILE LOCATIONS # # 3. DEBUGGING # # 4. ACCESS CONTROL AND SECURITY # # 5. FORWARDING # # 6. MISCELLANEOUS # # 7. WINDOWS GUI OPTIONS # # # #################################################################### # # # I. INTRODUCTION # =============== # # This file holds Privoxy's main configuration. Privoxy detects # configuration changes automatically, so you don't have to restart # it unless you want to load a different configuration file. # # The configuration will be reloaded with the first request after # the change was done, this request itself will still use the old # configuration, though. In other words: it takes two requests # before you see the result of your changes. Requests that are # dropped due to ACL don't trigger reloads. # # When starting Privoxy on Unix systems, give the location of this # file as last argument. On Windows systems, Privoxy will look for # this file with the name 'config.txt' in the current working # directory of the Privoxy process. # # # II. FORMAT OF THE CONFIGURATION FILE # ==================================== # # Configuration lines consist of an initial keyword followed by a # list of values, all separated by whitespace (any number of spaces # or tabs). For example, # # actionsfile default.action # # Indicates that the actionsfile is named 'default.action'. # # The '#' indicates a comment. Any part of a line following a '#' is # ignored, except if the '#' is preceded by a '\'. # # Thus, by placing a # at the start of an existing configuration # line, you can make it a comment and it will be treated as if it # weren't there. This is called "commenting out" an option and can # be useful. Removing the # again is called "uncommenting". # # Note that commenting out an option and leaving it at its default # are two completely different things! Most options behave very # differently when unset. See the "Effect if unset" explanation in # each option's description for details. # # Long lines can be continued on the next line by using a `\' as the # last character. # # # 1. LOCAL SET-UP DOCUMENTATION # ============================== # # If you intend to operate Privoxy for more users than just # yourself, it might be a good idea to let them know how to reach # you, what you block and why you do that, your policies, etc. # # # 1.1. user-manual # ================= # # Specifies: # # Location of the Privoxy User Manual. # # Type of value: # # A fully qualified URI # # Default value: # # Unset # # Effect if unset: # # http://www.privoxy.org/version/user-manual/ will be used, # where version is the Privoxy version. # # Notes: # # The User Manual URI is the single best source of information # on Privoxy, and is used for help links from some of the # internal CGI pages. The manual itself is normally packaged # with the binary distributions, so you probably want to set # this to a locally installed copy. # # Examples: # # The best all purpose solution is simply to put the full local # PATH to where the User Manual is located: # # user-manual /usr/share/doc/privoxy/user-manual # # The User Manual is then available to anyone with access to # Privoxy, by following the built-in URL: http:// # config.privoxy.org/user-manual/ (or the shortcut: http://p.p/ # user-manual/). # # If the documentation is not on the local system, it can be # accessed from a remote server, as: # # user-manual http://example.com/privoxy/user-manual/ # # WARNING!!! # # If set, this option should be the first option in the # config file, because it is used while the config file is # being read. # #user-manual http://www.privoxy.org/user-manual/ # # 1.2. trust-info-url # ==================== # # Specifies: # # A URL to be displayed in the error page that users will see if # access to an untrusted page is denied. # # Type of value: # # URL # # Default value: # # Unset # # Effect if unset: # # No links are displayed on the "untrusted" error page. # # Notes: # # The value of this option only matters if the experimental # trust mechanism has been activated. (See trustfile below.) # # If you use the trust mechanism, it is a good idea to write up # some on-line documentation about your trust policy and to # specify the URL(s) here. Use multiple times for multiple URLs. # # The URL(s) should be added to the trustfile as well, so users # don't end up locked out from the information on why they were # locked out in the first place! # #trust-info-url http://www.example.com/why_we_block.html #trust-info-url http://www.example.com/what_we_allow.html # # 1.3. admin-address # =================== # # Specifies: # # An email address to reach the Privoxy administrator. # # Type of value: # # Email address # # Default value: # # Unset # # Effect if unset: # # No email address is displayed on error pages and the CGI user # interface. # # Notes: # # If both admin-address and proxy-info-url are unset, the whole # "Local Privoxy Support" box on all generated pages will not be # shown. # #admin-address privoxy-admin@example.com # # 1.4. proxy-info-url # ==================== # # Specifies: # # A URL to documentation about the local Privoxy setup, # configuration or policies. # # Type of value: # # URL # # Default value: # # Unset # # Effect if unset: # # No link to local documentation is displayed on error pages and # the CGI user interface. # # Notes: # # If both admin-address and proxy-info-url are unset, the whole # "Local Privoxy Support" box on all generated pages will not be # shown. # # This URL shouldn't be blocked ;-) # #proxy-info-url http://www.example.com/proxy-service.html # # 2. CONFIGURATION AND LOG FILE LOCATIONS # ======================================== # # Privoxy can (and normally does) use a number of other files for # additional configuration, help and logging. This section of the # configuration file tells Privoxy where to find those other files. # # The user running Privoxy, must have read permission for all # configuration files, and write permission to any files that would # be modified, such as log files and actions files. # # # 2.1. confdir # ============= # # Specifies: # # The directory where the other configuration files are located. # # Type of value: # # Path name # # Default value: # # /etc/privoxy (Unix) or Privoxy installation dir (Windows) # # Effect if unset: # # Mandatory # # Notes: # # No trailing "/", please. # confdir . # # 2.2. templdir # ============== # # Specifies: # # An alternative directory where the templates are loaded from. # # Type of value: # # Path name # # Default value: # # unset # # Effect if unset: # # The templates are assumed to be located in confdir/template. # # Notes: # # Privoxy's original templates are usually overwritten with each # update. Use this option to relocate customized templates that # should be kept. As template variables might change between # updates, you shouldn't expect templates to work with Privoxy # releases other than the one they were part of, though. # #templdir . # # 2.3. logdir # ============ # # Specifies: # # The directory where all logging takes place (i.e. where the # logfile is located). # # Type of value: # # Path name # # Default value: # # /var/log/privoxy (Unix) or Privoxy installation dir (Windows) # # Effect if unset: # # Mandatory # # Notes: # # No trailing "/", please. # logdir . # # 2.4. actionsfile # ================= # # Specifies: # # The actions file(s) to use # # Type of value: # # Complete file name, relative to confdir # # Default values: # # match-all.action # Actions that are applied to all sites and maybe overruled later on. # # default.action # Main actions file # # user.action # User customizations # # Effect if unset: # # No actions are taken at all. More or less neutral proxying. # # Notes: # # Multiple actionsfile lines are permitted, and are in fact # recommended! # # The default values are default.action, which is the "main" # actions file maintained by the developers, and user.action, # where you can make your personal additions. # # Actions files contain all the per site and per URL # configuration for ad blocking, cookie management, privacy # considerations, etc. There is no point in using Privoxy # without at least one actions file. # # Note that since Privoxy 3.0.7, the complete filename, # including the ".action" extension has to be specified. The # syntax change was necessary to be consistent with the other # file options and to allow previously forbidden characters. # actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on. actionsfile default.action # Main actions file actionsfile user.action # User customizations # # 2.5. filterfile # ================ # # Specifies: # # The filter file(s) to use # # Type of value: # # File name, relative to confdir # # Default value: # # default.filter (Unix) or default.filter.txt (Windows) # # Effect if unset: # # No textual content filtering takes place, i.e. all +filter{name} # actions in the actions files are turned neutral. # # Notes: # # Multiple filterfile lines are permitted. # # The filter files contain content modification rules that use # regular expressions. These rules permit powerful changes on # the content of Web pages, and optionally the headers as well, # e.g., you could try to disable your favorite JavaScript # annoyances, re-write the actual displayed text, or just have # some fun playing buzzword bingo with web pages. # # The +filter{name} actions rely on the relevant filter (name) # to be defined in a filter file! # # A pre-defined filter file called default.filter that contains # a number of useful filters for common problems is included in # the distribution. See the section on the filter action for a # list. # # It is recommended to place any locally adapted filters into a # separate file, such as user.filter. # filterfile default.filter filterfile user.filter # User customizations # # 2.6. logfile # ============= # # Specifies: # # The log file to use # # Type of value: # # File name, relative to logdir # # Default value: # # Unset (commented out). When activated: logfile (Unix) or # privoxy.log (Windows). # # Effect if unset: # # No logfile is written. # # Notes: # # The logfile is where all logging and error messages are # written. The level of detail and number of messages are set # with the debug option (see below). The logfile can be useful # for tracking down a problem with Privoxy (e.g., it's not # blocking an ad you think it should block) and it can help you # to monitor what your browser is doing. # # Depending on the debug options below, the logfile may be a # privacy risk if third parties can get access to it. As most # users will never look at it, Privoxy 3.0.7 and later only log # fatal errors by default. # # For most troubleshooting purposes, you will have to change # that, please refer to the debugging section for details. # # Your logfile will grow indefinitely, and you will probably # want to periodically remove it. On Unix systems, you can do # this with a cron job (see "man cron"). # # Any log files must be writable by whatever user Privoxy is # being run as (on Unix, default user id is "privoxy"). # logfile logfile # # 2.7. trustfile # =============== # # Specifies: # # The name of the trust file to use # # Type of value: # # File name, relative to confdir # # Default value: # # Unset (commented out). When activated: trust (Unix) or # trust.txt (Windows) # # Effect if unset: # # The entire trust mechanism is disabled. # # Notes: # # The trust mechanism is an experimental feature for building # white-lists and should be used with care. It is NOT # recommended for the casual user. # # If you specify a trust file, Privoxy will only allow access to # sites that are specified in the trustfile. Sites can be listed # in one of two ways: # # Prepending a ~ character limits access to this site only (and # any sub-paths within this site), e.g. ~www.example.com allows # access to ~www.example.com/features/news.html, etc. # # Or, you can designate sites as trusted referrers, by # prepending the name with a + character. The effect is that # access to untrusted sites will be granted -- but only if a # link from this trusted referrer was used to get there. The # link target will then be added to the "trustfile" so that # future, direct accesses will be granted. Sites added via this # mechanism do not become trusted referrers themselves (i.e. # they are added with a ~ designation). There is a limit of 512 # such entries, after which new entries will not be made. # # If you use the + operator in the trust file, it may grow # considerably over time. # # It is recommended that Privoxy be compiled with the # --disable-force, --disable-toggle and --disable-editor # options, if this feature is to be used. # # Possible applications include limiting Internet access for # children. # #trustfile trust # # 3. DEBUGGING # ============= # # These options are mainly useful when tracing a problem. Note that # you might also want to invoke Privoxy with the --no-daemon command # line option when debugging. # # # 3.1. debug # =========== # # Specifies: # # Key values that determine what information gets logged. # # Type of value: # # Integer values # # Default value: # # 0 (i.e.: only fatal errors (that cause Privoxy to exit) are # logged) # # Effect if unset: # # Default value is used (see above). # # Notes: # # The available debug levels are: # # debug 1 # Log the destination for each request Privoxy let through. See also debug 1024. # debug 2 # show each connection status # debug 4 # show I/O status # debug 8 # show header parsing # debug 16 # log all data written to the network # debug 32 # debug force feature # debug 64 # debug regular expression filters # debug 128 # debug redirects # debug 256 # debug GIF de-animation # debug 512 # Common Log Format # debug 1024 # Log the destination for requests Privoxy didn't let through, and the reason why. # debug 2048 # CGI user interface # debug 4096 # Startup banner and warnings. # debug 8192 # Non-fatal errors # debug 32768 # log all data read from the network # debug 65536 # Log the applying actions # # To select multiple debug levels, you can either add them or # use multiple debug lines. # # A debug level of 1 is informative because it will show you # each request as it happens. 1, 1024, 4096 and 8192 are # recommended so that you will notice when things go wrong. The # other levels are probably only of interest if you are hunting # down a specific problem. They can produce a hell of an output # (especially 16). # # Privoxy used to ship with the debug levels recommended above # enabled by default, but due to privacy concerns 3.0.7 and # later are configured to only log fatal errors. # # If you are used to the more verbose settings, simply enable # the debug lines below again. # # If you want to use pure CLF (Common Log Format), you should # set "debug 512" ONLY and not enable anything else. # # Privoxy has a hard-coded limit for the length of log messages. # If it's reached, messages are logged truncated and marked with # "... [too long, truncated]". # # Please don't file any support requests without trying to # reproduce the problem with increased debug level first. Once # you read the log messages, you may even be able to solve the # problem on your own. # #debug 1 # Log the destination for each request Privoxy let through. See also debug 1024. #debug 1024 # Actions that are applied to all sites and maybe overruled later on. #debug 4096 # Startup banner and warnings #debug 8192 # Non-fatal errors # # 3.2. single-threaded # ===================== # # Specifies: # # Whether to run only one server thread. # # Type of value: # # None # # Default value: # # Unset # # Effect if unset: # # Multi-threaded (or, where unavailable: forked) operation, i.e. # the ability to serve multiple requests simultaneously. # # Notes: # # This option is only there for debugging purposes. It will # drastically reduce performance. # #single-threaded # # 3.3. hostname # ============== # # Specifies: # # The hostname shown on the CGI pages. # # Type of value: # # Text # # Default value: # # Unset # # Effect if unset: # # The hostname provided by the operating system is used. # # Notes: # # On some misconfigured systems resolving the hostname fails or # takes too much time and slows Privoxy down. Setting a fixed # hostname works around the problem. # # In other circumstances it might be desirable to show a # hostname other than the one returned by the operating system. # For example if the system has several different hostnames and # you don't want to use the first one. # # Note that Privoxy does not validate the specified hostname # value. # #hostname hostname.example.org # # 4. ACCESS CONTROL AND SECURITY # =============================== # # This section of the config file controls the security-relevant # aspects of Privoxy's configuration. # # # 4.1. listen-address # ==================== # # Specifies: # # The address and TCP port on which Privoxy will listen for # client requests. # # Type of value: # # [IP-Address]:Port # # [Hostname]:Port # # Default value: # # 127.0.0.1:8118 # # Effect if unset: # # Bind to 127.0.0.1 (IPv4 localhost), port 8118. This is # suitable and recommended for home users who run Privoxy on the # same machine as their browser. # # Notes: # # You will need to configure your browser(s) to this proxy # address and port. # # If you already have another service running on port 8118, or # if you want to serve requests from other machines (e.g. on # your local network) as well, you will need to override the # default. # # You can use this statement multiple times to make Privoxy # listen on more ports or more IP addresses. Suitable if your # operating system does not support sharing IPv6 and IPv4 # protocols on the same socket. # # If a hostname is used instead of an IP address, Privoxy will # try to resolve it to an IP address and if there are multiple, # use the first one returned. # # If the address for the hostname isn't already known on the # system (for example because it's in /etc/hostname), this may # result in DNS traffic. # # If the specified address isn't available on the system, or if # the hostname can't be resolved, Privoxy will fail to start. # # IPv6 addresses containing colons have to be quoted by # brackets. They can only be used if Privoxy has been compiled # with IPv6 support. If you aren't sure if your version supports # it, have a look at http://config.privoxy.org/show-status. # # Some operating systems will prefer IPv6 to IPv4 addresses even # if the system has no IPv6 connectivity which is usually not # expected by the user. Some even rely on DNS to resolve # localhost which mean the "localhost" address used may not # actually be local. # # It is therefore recommended to explicitly configure the # intended IP address instead of relying on the operating # system, unless there's a strong reason not to. # # If you leave out the address, Privoxy will bind to all IPv4 # interfaces (addresses) on your machine and may become # reachable from the Internet and/or the local network. Be aware # that some GNU/Linux distributions modify that behaviour # without updating the documentation. Check for non-standard # patches if your Privoxy version behaves differently. # # If you configure Privoxy to be reachable from the network, # consider using access control lists (ACL's, see below), and/or # a firewall. # # If you open Privoxy to untrusted users, you will also want to # make sure that the following actions are disabled: # enable-edit-actions and enable-remote-toggle # # Example: # # Suppose you are running Privoxy on a machine which has the # address 192.168.0.1 on your local private network # (192.168.0.0) and has another outside connection with a # different address. You want it to serve requests from inside # only: # # listen-address 192.168.0.1:8118 # # Suppose you are running Privoxy on an IPv6-capable machine and # you want it to listen on the IPv6 address of the loopback # device: # # listen-address [::1]:8118 # listen-address 127.0.0.1:8118 # # 4.2. toggle # ============ # # Specifies: # # Initial state of "toggle" status # # Type of value: # # 1 or 0 # # Default value: # # 1 # # Effect if unset: # # Act as if toggled on # # Notes: # # If set to 0, Privoxy will start in "toggled off" mode, i.e. # mostly behave like a normal, content-neutral proxy with both # ad blocking and content filtering disabled. See # enable-remote-toggle below. # toggle 1 # # 4.3. enable-remote-toggle # ========================== # # Specifies: # # Whether or not the web-based toggle feature may be used # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # The web-based toggle feature is disabled. # # Notes: # # When toggled off, Privoxy mostly acts like a normal, # content-neutral proxy, i.e. doesn't block ads or filter # content. # # Access to the toggle feature can not be controlled separately # by "ACLs" or HTTP authentication, so that everybody who can # access Privoxy (see "ACLs" and listen-address above) can # toggle it for all users. So this option is not recommended for # multi-user environments with untrusted users. # # Note that malicious client side code (e.g Java) is also # capable of using this option. # # As a lot of Privoxy users don't read documentation, this # feature is disabled by default. # # Note that you must have compiled Privoxy with support for this # feature, otherwise this option has no effect. # enable-remote-toggle 0 # # 4.4. enable-remote-http-toggle # =============================== # # Specifies: # # Whether or not Privoxy recognizes special HTTP headers to # change its behaviour. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Privoxy ignores special HTTP headers. # # Notes: # # When toggled on, the client can change Privoxy's behaviour by # setting special HTTP headers. Currently the only supported # special header is "X-Filter: No", to disable filtering for the # ongoing request, even if it is enabled in one of the action # files. # # This feature is disabled by default. If you are using Privoxy # in a environment with trusted clients, you may enable this # feature at your discretion. Note that malicious client side # code (e.g Java) is also capable of using this feature. # # This option will be removed in future releases as it has been # obsoleted by the more general header taggers. # enable-remote-http-toggle 0 # # 4.5. enable-edit-actions # ========================= # # Specifies: # # Whether or not the web-based actions file editor may be used # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # The web-based actions file editor is disabled. # # Notes: # # Access to the editor can not be controlled separately by # "ACLs" or HTTP authentication, so that everybody who can # access Privoxy (see "ACLs" and listen-address above) can # modify its configuration for all users. # # This option is not recommended for environments with untrusted # users and as a lot of Privoxy users don't read documentation, # this feature is disabled by default. # # Note that malicious client side code (e.g Java) is also # capable of using the actions editor and you shouldn't enable # this options unless you understand the consequences and are # sure your browser is configured correctly. # # Note that you must have compiled Privoxy with support for this # feature, otherwise this option has no effect. # enable-edit-actions 0 # # 4.6. enforce-blocks # ==================== # # Specifies: # # Whether the user is allowed to ignore blocks and can "go there # anyway". # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Blocks are not enforced. # # Notes: # # Privoxy is mainly used to block and filter requests as a # service to the user, for example to block ads and other junk # that clogs the pipes. Privoxy's configuration isn't perfect # and sometimes innocent pages are blocked. In this situation it # makes sense to allow the user to enforce the request and have # Privoxy ignore the block. # # In the default configuration Privoxy's "Blocked" page contains # a "go there anyway" link to adds a special string (the force # prefix) to the request URL. If that link is used, Privoxy will # detect the force prefix, remove it again and let the request # pass. # # Of course Privoxy can also be used to enforce a network # policy. In that case the user obviously should not be able to # bypass any blocks, and that's what the "enforce-blocks" option # is for. If it's enabled, Privoxy hides the "go there anyway" # link. If the user adds the force prefix by hand, it will not # be accepted and the circumvention attempt is logged. # # Examples: # # enforce-blocks 1 # enforce-blocks 0 # # 4.7. ACLs: permit-access and deny-access # ========================================= # # Specifies: # # Who can access what. # # Type of value: # # src_addr[:port][/src_masklen] [dst_addr[:port][/dst_masklen]] # # Where src_addr and dst_addr are IPv4 addresses in dotted # decimal notation or valid DNS names, port is a port number, # and src_masklen and dst_masklen are subnet masks in CIDR # notation, i.e. integer values from 2 to 30 representing the # length (in bits) of the network address. The masks and the # whole destination part are optional. # # If your system implements RFC 3493, then src_addr and dst_addr # can be IPv6 addresses delimeted by brackets, port can be a # number or a service name, and src_masklen and dst_masklen can # be a number from 0 to 128. # # Default value: # # Unset # # If no port is specified, any port will match. If no # src_masklen or src_masklen is given, the complete IP address # has to match (i.e. 32 bits for IPv4 and 128 bits for IPv6). # # Effect if unset: # # Don't restrict access further than implied by listen-address # # Notes: # # Access controls are included at the request of ISPs and # systems administrators, and are not usually needed by # individual users. For a typical home user, it will normally # suffice to ensure that Privoxy only listens on the localhost # (127.0.0.1) or internal (home) network address by means of the # listen-address option. # # Please see the warnings in the FAQ that Privoxy is not # intended to be a substitute for a firewall or to encourage # anyone to defer addressing basic security weaknesses. # # Multiple ACL lines are OK. If any ACLs are specified, Privoxy # only talks to IP addresses that match at least one # permit-access line and don't match any subsequent deny-access # line. In other words, the last match wins, with the default # being deny-access. # # If Privoxy is using a forwarder (see forward below) for a # particular destination URL, the dst_addr that is examined is # the address of the forwarder and NOT the address of the # ultimate target. This is necessary because it may be # impossible for the local Privoxy to determine the IP address # of the ultimate target (that's often what gateways are used # for). # # You should prefer using IP addresses over DNS names, because # the address lookups take time. All DNS names must resolve! You # can not use domain patterns like "*.org" or partial domain # names. If a DNS name resolves to multiple IP addresses, only # the first one is used. # # Some systems allow IPv4 clients to connect to IPv6 server # sockets. Then the client's IPv4 address will be translated by # the system into IPv6 address space with special prefix # ::ffff:0:0/96 (so called IPv4 mapped IPv6 address). Privoxy # can handle it and maps such ACL addresses automatically. # # Denying access to particular sites by ACL may have undesired # side effects if the site in question is hosted on a machine # which also hosts other sites (most sites are). # # Examples: # # Explicitly define the default behavior if no ACL and # listen-address are set: "localhost" is OK. The absence of a # dst_addr implies that all destination addresses are OK: # # permit-access localhost # # Allow any host on the same class C subnet as www.privoxy.org # access to nothing but www.example.com (or other domains hosted # on the same system): # # permit-access www.privoxy.org/24 www.example.com/32 # # Allow access from any host on the 26-bit subnet 192.168.45.64 # to anywhere, with the exception that 192.168.45.73 may not # access the IP address behind www.dirty-stuff.example.com: # # permit-access 192.168.45.64/26 # deny-access 192.168.45.73 www.dirty-stuff.example.com # # Allow access from the IPv4 network 192.0.2.0/24 even if # listening on an IPv6 wild card address (not supported on all # platforms): # # permit-access 192.0.2.0/24 # # This is equivalent to the following line even if listening on # an IPv4 address (not supported on all platforms): # # permit-access [::ffff:192.0.2.0]/120 # # # 4.8. buffer-limit # ================== # # Specifies: # # Maximum size of the buffer for content filtering. # # Type of value: # # Size in Kbytes # # Default value: # # 4096 # # Effect if unset: # # Use a 4MB (4096 KB) limit. # # Notes: # # For content filtering, i.e. the +filter and +deanimate-gif # actions, it is necessary that Privoxy buffers the entire # document body. This can be potentially dangerous, since a # server could just keep sending data indefinitely and wait for # your RAM to exhaust -- with nasty consequences. Hence this # option. # # When a document buffer size reaches the buffer-limit, it is # flushed to the client unfiltered and no further attempt to # filter the rest of the document is made. Remember that there # may be multiple threads running, which might require up to # buffer-limit Kbytes each, unless you have enabled # "single-threaded" above. # buffer-limit 4096 # # 4.9. enable-proxy-authentication-forwarding # ============================================ # # Specifies: # # Whether or not proxy authentication through Privoxy should # work. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Proxy authentication headers are removed. # # Notes: # # Privoxy itself does not support proxy authentication, but can # allow clients to authenticate against Privoxy's parent proxy. # # By default Privoxy (3.0.21 and later) don't do that and remove # Proxy-Authorization headers in requests and Proxy-Authenticate # headers in responses to make it harder for malicious sites to # trick inexperienced users into providing login information. # # If this option is enabled the headers are forwarded. # # Enabling this option is not recommended if there is no parent # proxy that requires authentication or if the local network # between Privoxy and the parent proxy isn't trustworthy. If # proxy authentication is only required for some requests, it is # recommended to use a client header filter to remove the # authentication headers for requests where they aren't needed. # enable-proxy-authentication-forwarding 0 # # 5. FORWARDING # ============== # # This feature allows routing of HTTP requests through a chain of # multiple proxies. # # Forwarding can be used to chain Privoxy with a caching proxy to # speed up browsing. Using a parent proxy may also be necessary if # the machine that Privoxy runs on has no direct Internet access. # # Note that parent proxies can severely decrease your privacy level. # For example a parent proxy could add your IP address to the # request headers and if it's a caching proxy it may add the "Etag" # header to revalidation requests again, even though you configured # Privoxy to remove it. It may also ignore Privoxy's header time # randomization and use the original values which could be used by # the server as cookie replacement to track your steps between # visits. # # Also specified here are SOCKS proxies. Privoxy supports the SOCKS # 4 and SOCKS 4A protocols. # # # 5.1. forward # ============= # # Specifies: # # To which parent HTTP proxy specific requests should be routed. # # Type of value: # # target_pattern http_parent[:port] # # where target_pattern is a URL pattern that specifies to which # requests (i.e. URLs) this forward rule shall apply. Use / to # denote "all URLs". http_parent[:port] is the DNS name or IP # address of the parent HTTP proxy through which the requests # should be forwarded, optionally followed by its listening port # (default: 8000). Use a single dot (.) to denote "no # forwarding". # # Default value: # # Unset # # Effect if unset: # # Don't use parent HTTP proxies. # # Notes: # # If http_parent is ".", then requests are not forwarded to # another HTTP proxy but are made directly to the web servers. # # http_parent can be a numerical IPv6 address (if RFC 3493 is # implemented). To prevent clashes with the port delimiter, the # whole IP address has to be put into brackets. On the other # hand a target_pattern containing an IPv6 address has to be put # into angle brackets (normal brackets are reserved for regular # expressions already). # # Multiple lines are OK, they are checked in sequence, and the # last match wins. # # Examples: # # Everything goes to an example parent proxy, except SSL on port # 443 (which it doesn't handle): # # forward / parent-proxy.example.org:8080 # forward :443 . # # Everything goes to our example ISP's caching proxy, except for # requests to that ISP's sites: # # forward / caching-proxy.isp.example.net:8000 # forward .isp.example.net . # # Parent proxy specified by an IPv6 address: # # forward / [2001:DB8::1]:8000 # # Suppose your parent proxy doesn't support IPv6: # # forward / parent-proxy.example.org:8000 # forward ipv6-server.example.org . # forward <[2-3][0-9a-f][0-9a-f][0-9a-f]:*> . # # # 5.2. forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t # ========================================================================= # # Specifies: # # Through which SOCKS proxy (and optionally to which parent HTTP # proxy) specific requests should be routed. # # Type of value: # # target_pattern socks_proxy[:port] http_parent[:port] # # where target_pattern is a URL pattern that specifies to which # requests (i.e. URLs) this forward rule shall apply. Use / to # denote "all URLs". http_parent and socks_proxy are IP # addresses in dotted decimal notation or valid DNS names ( # http_parent may be "." to denote "no HTTP forwarding"), and # the optional port parameters are TCP ports, i.e. integer # values from 1 to 65535 # # Default value: # # Unset # # Effect if unset: # # Don't use SOCKS proxies. # # Notes: # # Multiple lines are OK, they are checked in sequence, and the # last match wins. # # The difference between forward-socks4 and forward-socks4a is # that in the SOCKS 4A protocol, the DNS resolution of the # target hostname happens on the SOCKS server, while in SOCKS 4 # it happens locally. # # With forward-socks5 the DNS resolution will happen on the # remote server as well. # # forward-socks5t works like vanilla forward-socks5 but lets # Privoxy additionally use Tor-specific SOCKS extensions. # Currently the only supported SOCKS extension is optimistic # data which can reduce the latency for the first request made # on a newly created connection. # # socks_proxy and http_parent can be a numerical IPv6 address # (if RFC 3493 is implemented). To prevent clashes with the port # delimiter, the whole IP address has to be put into brackets. # On the other hand a target_pattern containing an IPv6 address # has to be put into angle brackets (normal brackets are # reserved for regular expressions already). # # If http_parent is ".", then requests are not forwarded to # another HTTP proxy but are made (HTTP-wise) directly to the # web servers, albeit through a SOCKS proxy. # # Examples: # # From the company example.com, direct connections are made to # all "internal" domains, but everything outbound goes through # their ISP's proxy by way of example.com's corporate SOCKS 4A # gateway to the Internet. # # forward-socks4a / socks-gw.example.com:1080 www-cache.isp.example.net:8080 # forward .example.com . # # A rule that uses a SOCKS 4 gateway for all destinations but no # HTTP parent looks like this: # # forward-socks4 / socks-gw.example.com:1080 . # # To chain Privoxy and Tor, both running on the same system, you # would use something like: # # forward-socks5 / 127.0.0.1:9050 . # # The public Tor network can't be used to reach your local # network, if you need to access local servers you therefore # might want to make some exceptions: # # forward 192.168.*.*/ . # forward 10.*.*.*/ . # forward 127.*.*.*/ . # # Unencrypted connections to systems in these address ranges # will be as (un)secure as the local network is, but the # alternative is that you can't reach the local network through # Privoxy at all. Of course this may actually be desired and # there is no reason to make these exceptions if you aren't sure # you need them. # # If you also want to be able to reach servers in your local # network by using their names, you will need additional # exceptions that look like this: # # forward localhost/ . # # # 5.3. forwarded-connect-retries # =============================== # # Specifies: # # How often Privoxy retries if a forwarded connection request # fails. # # Type of value: # # Number of retries. # # Default value: # # 0 # # Effect if unset: # # Connections forwarded through other proxies are treated like # direct connections and no retry attempts are made. # # Notes: # # forwarded-connect-retries is mainly interesting for socks4a # connections, where Privoxy can't detect why the connections # failed. The connection might have failed because of a DNS # timeout in which case a retry makes sense, but it might also # have failed because the server doesn't exist or isn't # reachable. In this case the retry will just delay the # appearance of Privoxy's error message. # # Note that in the context of this option, "forwarded # connections" includes all connections that Privoxy forwards # through other proxies. This option is not limited to the HTTP # CONNECT method. # # Only use this option, if you are getting lots of # forwarding-related error messages that go away when you try # again manually. Start with a small value and check Privoxy's # logfile from time to time, to see how many retries are usually # needed. # # Examples: # # forwarded-connect-retries 1 # forwarded-connect-retries 0 # # 6. MISCELLANEOUS # ================= # # 6.1. accept-intercepted-requests # ================================= # # Specifies: # # Whether intercepted requests should be treated as valid. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Only proxy requests are accepted, intercepted requests are # treated as invalid. # # Notes: # # If you don't trust your clients and want to force them to use # Privoxy, enable this option and configure your packet filter # to redirect outgoing HTTP connections into Privoxy. # # Make sure that Privoxy's own requests aren't redirected as # well. Additionally take care that Privoxy can't intentionally # connect to itself, otherwise you could run into redirection # loops if Privoxy's listening port is reachable by the outside # or an attacker has access to the pages you visit. # # Examples: # # accept-intercepted-requests 1 # accept-intercepted-requests 0 # # 6.2. allow-cgi-request-crunching # ================================= # # Specifies: # # Whether requests to Privoxy's CGI pages can be blocked or # redirected. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Privoxy ignores block and redirect actions for its CGI pages. # # Notes: # # By default Privoxy ignores block or redirect actions for its # CGI pages. Intercepting these requests can be useful in # multi-user setups to implement fine-grained access control, # but it can also render the complete web interface useless and # make debugging problems painful if done without care. # # Don't enable this option unless you're sure that you really # need it. # # Examples: # # allow-cgi-request-crunching 1 # allow-cgi-request-crunching 0 # # 6.3. split-large-forms # ======================= # # Specifies: # # Whether the CGI interface should stay compatible with broken # HTTP clients. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # The CGI form generate long GET URLs. # # Notes: # # Privoxy's CGI forms can lead to rather long URLs. This isn't a # problem as far as the HTTP standard is concerned, but it can # confuse clients with arbitrary URL length limitations. # # Enabling split-large-forms causes Privoxy to divide big forms # into smaller ones to keep the URL length down. It makes # editing a lot less convenient and you can no longer submit all # changes at once, but at least it works around this browser # bug. # # If you don't notice any editing problems, there is no reason # to enable this option, but if one of the submit buttons # appears to be broken, you should give it a try. # # Examples: # # split-large-forms 1 # split-large-forms 0 # # 6.4. keep-alive-timeout # ======================== # # Specifies: # # Number of seconds after which an open connection will no # longer be reused. # # Type of value: # # Time in seconds. # # Default value: # # None # # Effect if unset: # # Connections are not kept alive. # # Notes: # # This option allows clients to keep the connection to Privoxy # alive. If the server supports it, Privoxy will keep the # connection to the server alive as well. Under certain # circumstances this may result in speed-ups. # # By default, Privoxy will close the connection to the server if # the client connection gets closed, or if the specified timeout # has been reached without a new request coming in. This # behaviour can be changed with the connection-sharing option. # # This option has no effect if Privoxy has been compiled without # keep-alive support. # # Note that a timeout of five seconds as used in the default # configuration file significantly decreases the number of # connections that will be reused. The value is used because # some browsers limit the number of connections they open to a # single host and apply the same limit to proxies. This can # result in a single website "grabbing" all the connections the # browser allows, which means connections to other websites # can't be opened until the connections currently in use time # out. # # Several users have reported this as a Privoxy bug, so the # default value has been reduced. Consider increasing it to 300 # seconds or even more if you think your browser can handle it. # If your browser appears to be hanging, it probably can't. # # Examples: # # keep-alive-timeout 300 # keep-alive-timeout 5 # # 6.5. tolerate-pipelining # ========================= # # Specifies: # # Whether or not pipelined requests should be served. # # Type of value: # # 0 or 1. # # Default value: # # None # # Effect if unset: # # If Privoxy receives more than one request at once, it # terminates the client connection after serving the first one. # # Notes: # # Privoxy currently doesn't pipeline outgoing requests, thus # allowing pipelining on the client connection is not guaranteed # to improve the performance. # # By default Privoxy tries to discourage clients from pipelining # by discarding aggressively pipelined requests, which forces # the client to resend them through a new connection. # # This option lets Privoxy tolerate pipelining. Whether or not # that improves performance mainly depends on the client # configuration. # # If you are seeing problems with pages not properly loading, # disabling this option could work around the problem. # # Examples: # # tolerate-pipelining 1 # tolerate-pipelining 1 # # 6.6. default-server-timeout # ============================ # # Specifies: # # Assumed server-side keep-alive timeout if not specified by the # server. # # Type of value: # # Time in seconds. # # Default value: # # None # # Effect if unset: # # Connections for which the server didn't specify the keep-alive # timeout are not reused. # # Notes: # # Enabling this option significantly increases the number of # connections that are reused, provided the keep-alive-timeout # option is also enabled. # # While it also increases the number of connections problems # when Privoxy tries to reuse a connection that already has been # closed on the server side, or is closed while Privoxy is # trying to reuse it, this should only be a problem if it # happens for the first request sent by the client. If it # happens for requests on reused client connections, Privoxy # will simply close the connection and the client is supposed to # retry the request without bothering the user. # # Enabling this option is therefore only recommended if the # connection-sharing option is disabled. # # It is an error to specify a value larger than the # keep-alive-timeout value. # # This option has no effect if Privoxy has been compiled without # keep-alive support. # # Examples: # # default-server-timeout 60 # #default-server-timeout 60 # # 6.7. connection-sharing # ======================== # # Specifies: # # Whether or not outgoing connections that have been kept alive # should be shared between different incoming connections. # # Type of value: # # 0 or 1 # # Default value: # # None # # Effect if unset: # # Connections are not shared. # # Notes: # # This option has no effect if Privoxy has been compiled without # keep-alive support, or if it's disabled. # # Notes: # # Note that reusing connections doesn't necessary cause # speedups. There are also a few privacy implications you should # be aware of. # # If this option is effective, outgoing connections are shared # between clients (if there are more than one) and closing the # browser that initiated the outgoing connection does no longer # affect the connection between Privoxy and the server unless # the client's request hasn't been completed yet. # # If the outgoing connection is idle, it will not be closed # until either Privoxy's or the server's timeout is reached. # While it's open, the server knows that the system running # Privoxy is still there. # # If there are more than one client (maybe even belonging to # multiple users), they will be able to reuse each others # connections. This is potentially dangerous in case of # authentication schemes like NTLM where only the connection is # authenticated, instead of requiring authentication for each # request. # # If there is only a single client, and if said client can keep # connections alive on its own, enabling this option has next to # no effect. If the client doesn't support connection # keep-alive, enabling this option may make sense as it allows # Privoxy to keep outgoing connections alive even if the client # itself doesn't support it. # # You should also be aware that enabling this option increases # the likelihood of getting the "No server or forwarder data" # error message, especially if you are using a slow connection # to the Internet. # # This option should only be used by experienced users who # understand the risks and can weight them against the benefits. # # Examples: # # connection-sharing 1 # #connection-sharing 1 # # 6.8. socket-timeout # ==================== # # Specifies: # # Number of seconds after which a socket times out if no data is # received. # # Type of value: # # Time in seconds. # # Default value: # # None # # Effect if unset: # # A default value of 300 seconds is used. # # Notes: # # The default is quite high and you probably want to reduce it. # If you aren't using an occasionally slow proxy like Tor, # reducing it to a few seconds should be fine. # # Examples: # # socket-timeout 300 # socket-timeout 300 # # 6.9. max-client-connections # ============================ # # Specifies: # # Maximum number of client connections that will be served. # # Type of value: # # Positive number. # # Default value: # # 128 # # Effect if unset: # # Connections are served until a resource limit is reached. # # Notes: # # Privoxy creates one thread (or process) for every incoming # client connection that isn't rejected based on the access # control settings. # # If the system is powerful enough, Privoxy can theoretically # deal with several hundred (or thousand) connections at the # same time, but some operating systems enforce resource limits # by shutting down offending processes and their default limits # may be below the ones Privoxy would require under heavy load. # # Configuring Privoxy to enforce a connection limit below the # thread or process limit used by the operating system makes # sure this doesn't happen. Simply increasing the operating # system's limit would work too, but if Privoxy isn't the only # application running on the system, you may actually want to # limit the resources used by Privoxy. # # If Privoxy is only used by a single trusted user, limiting the # number of client connections is probably unnecessary. If there # are multiple possibly untrusted users you probably still want # to additionally use a packet filter to limit the maximal # number of incoming connections per client. Otherwise a # malicious user could intentionally create a high number of # connections to prevent other users from using Privoxy. # # Obviously using this option only makes sense if you choose a # limit below the one enforced by the operating system. # # One most POSIX-compliant systems Privoxy can't properly deal # with more than FD_SETSIZE file descriptors at the same time # and has to reject connections if the limit is reached. This # will likely change in a future version, but currently this # limit can't be increased without recompiling Privoxy with a # different FD_SETSIZE limit. # # Examples: # # max-client-connections 256 # #max-client-connections 256 # # 6.10. handle-as-empty-doc-returns-ok # ===================================== # # Specifies: # # The status code Privoxy returns for pages blocked with # +handle-as-empty-document. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Privoxy returns a status 403(forbidden) for all blocked pages. # # Effect if set: # # Privoxy returns a status 200(OK) for pages blocked with # +handle-as-empty-document and a status 403(Forbidden) for all # other blocked pages. # # Notes: # # This is a work-around for Firefox bug 492459: " Websites are # no longer rendered if SSL requests for JavaScripts are blocked # by a proxy. " (https://bugzilla.mozilla.org/show_bug.cgi?id= # 492459) As the bug has been fixed for quite some time this # option should no longer be needed and will be removed in a # future release. Please speak up if you have a reason why the # option should be kept around. # #handle-as-empty-doc-returns-ok 1 # # 6.11. enable-compression # ========================= # # Specifies: # # Whether or not buffered content is compressed before delivery. # # Type of value: # # 0 or 1 # # Default value: # # 0 # # Effect if unset: # # Privoxy does not compress buffered content. # # Effect if set: # # Privoxy compresses buffered content before delivering it to # the client, provided the client supports it. # # Notes: # # This directive is only supported if Privoxy has been compiled # with FEATURE_COMPRESSION, which should not to be confused with # FEATURE_ZLIB. # # Compressing buffered content is mainly useful if Privoxy and # the client are running on different systems. If they are # running on the same system, enabling compression is likely to # slow things down. If you didn't measure otherwise, you should # assume that it does and keep this option disabled. # # Privoxy will not compress buffered content below a certain # length. # #enable-compression 1 # # 6.12. compression-level # ======================== # # Specifies: # # The compression level that is passed to the zlib library when # compressing buffered content. # # Type of value: # # Positive number ranging from 0 to 9. # # Default value: # # 1 # # Notes: # # Compressing the data more takes usually longer than # compressing it less or not compressing it at all. Which level # is best depends on the connection between Privoxy and the # client. If you can't be bothered to benchmark it for yourself, # you should stick with the default and keep compression # disabled. # # If compression is disabled, the compression level is # irrelevant. # # Examples: # # # Best speed (compared to the other levels) # compression-level 1 # # # Best compression # compression-level 9 # # # No compression. Only useful for testing as the added header # # slightly increases the amount of data that has to be sent. # # If your benchmark shows that using this compression level # # is superior to using no compression at all, the benchmark # # is likely to be flawed. # compression-level 0 # # #compression-level 1 # # 6.13. client-header-order # ========================== # # Specifies: # # The order in which client headers are sorted before forwarding # them. # # Type of value: # # Client header names delimited by spaces or tabs # # Default value: # # None # # Notes: # # By default Privoxy leaves the client headers in the order they # were sent by the client. Headers are modified in-place, new # headers are added at the end of the already existing headers. # # The header order can be used to fingerprint client requests # independently of other headers like the User-Agent. # # This directive allows to sort the headers differently to # better mimic a different User-Agent. Client headers will be # emitted in the order given, headers whose name isn't # explicitly specified are added at the end. # # Note that sorting headers in an uncommon way will make # fingerprinting actually easier. Encrypted headers are not # affected by this directive. # #client-header-order Host \ # Accept \ # Accept-Language \ # Accept-Encoding \ # Proxy-Connection \ # Referer \ # Cookie \ # DNT \ # If-Modified-Since \ # Cache-Control \ # Content-Length \ # Content-Type # # # 7. WINDOWS GUI OPTIONS # ======================= # # Privoxy has a number of options specific to the Windows GUI # interface: # # # # If "activity-animation" is set to 1, the Privoxy icon will animate # when "Privoxy" is active. To turn off, set to 0. # #activity-animation 1 # # # # If "log-messages" is set to 1, Privoxy copies log messages to the # console window. The log detail depends on the debug directive. # #log-messages 1 # # # # If "log-buffer-size" is set to 1, the size of the log buffer, i.e. # the amount of memory used for the log messages displayed in the # console window, will be limited to "log-max-lines" (see below). # # Warning: Setting this to 0 will result in the buffer to grow # infinitely and eat up all your memory! # #log-buffer-size 1 # # # # log-max-lines is the maximum number of lines held in the log # buffer. See above. # #log-max-lines 200 # # # # If "log-highlight-messages" is set to 1, Privoxy will highlight # portions of the log messages with a bold-faced font: # #log-highlight-messages 1 # # # # The font used in the console window: # #log-font-name Comic Sans MS # # # # Font size used in the console window: # #log-font-size 8 # # # # "show-on-task-bar" controls whether or not Privoxy will appear as # a button on the Task bar when minimized: # #show-on-task-bar 0 # # # # If "close-button-minimizes" is set to 1, the Windows close button # will minimize Privoxy instead of closing the program (close with # the exit option on the File menu). # #close-button-minimizes 1 # # # # The "hide-console" option is specific to the MS-Win console # version of Privoxy. If this option is used, Privoxy will # disconnect from and hide the command console. # #hide-console # # # privoxy-3.0.21-stable/./encode.h000640 001751 001751 00000004501 11655471470 015402 0ustar00fkfk000000 000000 #ifndef ENCODE_H_INCLUDED #define ENCODE_H_INCLUDED #define ENCODE_H_VERSION "$Id: encode.h,v 1.12 2011/11/06 11:44:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/encode.h,v $ * * Purpose : Functions to encode and decode URLs, and also to * encode cookies and HTML text. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif extern char * html_encode(const char *s); extern char * url_encode(const char *s); extern char * url_decode(const char *str); extern int xtoi(const char *s); extern char * html_encode_and_free_original(char *s); extern char * percent_encode_url(const char *s); /* Revision control strings from this header and associated .c file */ extern const char encode_rcs[]; extern const char encode_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef ENCODE_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32taskbar.h000640 001751 001751 00000004331 11630656300 016117 0ustar00fkfk000000 000000 #ifndef W32TASKBAR_H_INCLUDED #define W32TASKBAR_H_INCLUDED #define W32TASKBAR_H_VERSION "$Id: w32taskbar.h,v 1.8 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32taskbar.h,v $ * * Purpose : Functions for creating, setting and destroying the * workspace tray icon * * Copyright : Written by and Copyright (C) 2001-2002 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 1999 Adam Lock * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif extern HWND CreateTrayWindow(HINSTANCE hInstance); extern BOOL TrayAddIcon(HWND hwnd, UINT uID, HICON hicon, const char *pszToolTip); extern BOOL TraySetIcon(HWND hwnd, UINT uID, HICON hicon); extern BOOL TrayDeleteIcon(HWND hwnd, UINT uID); /* Revision control strings from this header and associated .c file */ extern const char w32taskbar_rcs[]; extern const char w32taskbar_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef W32TASKBAR_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./deanimate.c000640 001751 001751 00000030554 11726427304 016072 0ustar00fkfk000000 000000 const char deanimate_rcs[] = "$Id: deanimate.c,v 1.23 2012/03/09 16:24:36 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/deanimate.c,v $ * * Purpose : Declares functions to manipulate binary images on the * fly. High-level functions include: * - Deanimation of GIF images * * Copyright : Written by and Copyright (C) 2001 - 2004, 2006 by the * SourceForge Privoxy team. http://www.privoxy.org/ * * Based on the GIF file format specification (see * http://tronche.com/computer-graphics/gif/gif89a.html) * and ideas from the Image::DeAnim Perl module by * Ken MacFarlane, * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "config.h" #include #include #include "errlog.h" #include "project.h" #include "deanimate.h" #include "miscutil.h" const char deanimate_h_rcs[] = DEANIMATE_H_VERSION; /********************************************************************* * * Function : buf_free * * Description : Safely frees a struct binbuffer * * Parameters : * 1 : buf = Pointer to the binbuffer to be freed * * Returns : N/A * *********************************************************************/ void buf_free(struct binbuffer *buf) { if (buf == NULL) return; if (buf->buffer != NULL) { free(buf->buffer); } free(buf); } /********************************************************************* * * Function : buf_extend * * Description : Ensure that a given binbuffer can hold a given amount * of bytes, by reallocating its buffer if necessary. * Allocate new mem in chunks of 1024 bytes, so we don't * have to realloc() too often. * * Parameters : * 1 : buf = Pointer to the binbuffer * 2 : length = Desired minimum size * * * Returns : 0 on success, 1 on failure. * *********************************************************************/ static int buf_extend(struct binbuffer *buf, size_t length) { char *newbuf; if (buf->offset + length > buf->size) { buf->size = ((buf->size + length + (size_t)1023) & ~(size_t)1023); newbuf = (char *)realloc(buf->buffer, buf->size); if (newbuf == NULL) { freez(buf->buffer); return 1; } else { buf->buffer = newbuf; return 0; } } return 0; } /********************************************************************* * * Function : buf_copy * * Description : Safely copies a given amount of bytes from one * struct binbuffer to another, advancing the * offsets appropriately. * * Parameters : * 1 : src = Pointer to the source binbuffer * 2 : dst = Pointer to the destination binbuffer * 3 : length = Number of bytes to be copied * * Returns : 0 on success, 1 on failure. * *********************************************************************/ static int buf_copy(struct binbuffer *src, struct binbuffer *dst, size_t length) { /* * Sanity check: Can't copy more data than we have */ if (src->offset + length > src->size) { return 1; } /* * Ensure that dst can hold the new data */ if (buf_extend(dst, length)) { return 1; } /* * Now that it's safe, memcpy() the desired amount of * data from src to dst and adjust the offsets */ memcpy(dst->buffer + dst->offset, src->buffer + src->offset, length); src->offset += length; dst->offset += length; return 0; } /********************************************************************* * * Function : buf_getbyte * * Description : Safely gets a byte from a given binbuffer at a * given offset * * Parameters : * 1 : src = Pointer to the source binbuffer * 2 : offset = Offset to the desired byte * * Returns : The byte on success, or 0 on failure * *********************************************************************/ static unsigned char buf_getbyte(const struct binbuffer *src, size_t offset) { if (src->offset + offset < src->size) { return (unsigned char)*(src->buffer + src->offset + offset); } else { return '\0'; } } /********************************************************************* * * Function : gif_skip_data_block * * Description : Safely advances the offset of a given struct binbuffer * that contains a GIF image and whose offset is * positioned at the start of a data block, behind * that block. * * Parameters : * 1 : buf = Pointer to the binbuffer * * Returns : 0 on success, or 1 on failure * *********************************************************************/ static int gif_skip_data_block(struct binbuffer *buf) { unsigned char c; /* * Data blocks are sequences of chunks, which are headed * by a one-byte length field, with the last chunk having * zero length. */ while((c = buf_getbyte(buf, 0)) != '\0') { buf->offset += (size_t)c + 1; if (buf->offset >= buf->size - 1) { return 1; } } buf->offset++; return 0; } /********************************************************************* * * Function : gif_extract_image * * Description : Safely extracts an image data block from a given * struct binbuffer that contains a GIF image and whose * offset is positioned at the start of a data block * into a given destination binbuffer. * * Parameters : * 1 : src = Pointer to the source binbuffer * 2 : dst = Pointer to the destination binbuffer * * Returns : 0 on success, or 1 on failure * *********************************************************************/ static int gif_extract_image(struct binbuffer *src, struct binbuffer *dst) { unsigned char c; /* * Remember the colormap flag and copy the image head */ c = buf_getbyte(src, 9); if (buf_copy(src, dst, 10)) { return 1; } /* * If the image has a local colormap, copy it. */ if (c & 0x80) { int map_length = 3 * (1 << ((c & 0x07) + 1)); if (map_length <= 0) { log_error(LOG_LEVEL_DEANIMATE, "colormap length = %d (%c)?", map_length, c); return 1; } if (buf_copy(src, dst, (size_t)map_length)) { return 1; } } if (buf_copy(src, dst, 1)) return 1; /* * Copy the image chunk by chunk. */ while((c = buf_getbyte(src, 0)) != '\0') { if (buf_copy(src, dst, 1 + (size_t) c)) return 1; } if (buf_copy(src, dst, 1)) return 1; /* * Trim and rewind the dst buffer */ if (NULL == (dst->buffer = (char *)realloc(dst->buffer, dst->offset))) return 1; dst->size = dst->offset; dst->offset = 0; return(0); } /********************************************************************* * * Function : gif_deanimate * * Description : Deanimate a given GIF image, i.e. given a GIF with * an (optional) image block and an arbitrary number * of image extension blocks, produce an output GIF with * only one image block that contains the last image * (extenstion) block of the original. * Also strip Comments, Application extenstions, etc. * * Parameters : * 1 : src = Pointer to the source binbuffer * 2 : dst = Pointer to the destination binbuffer * 3 : get_first_image = Flag: If set, get the first image * If unset (default), get the last * * Returns : 0 on success, or 1 on failure * *********************************************************************/ int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image) { unsigned char c; struct binbuffer *image; if (NULL == src || NULL == dst) { return 1; } c = buf_getbyte(src, 10); /* * Check & copy GIF header */ if (strncmp(src->buffer, "GIF89a", 6) && strncmp(src->buffer, "GIF87a", 6)) { return 1; } else { if (buf_copy(src, dst, 13)) { return 1; } } /* * Look for global colormap and copy if found. */ if (c & 0x80) { int map_length = 3 * (1 << ((c & 0x07) + 1)); if (map_length <= 0) { log_error(LOG_LEVEL_DEANIMATE, "colormap length = %d (%c)?", map_length, c); return 1; } if (buf_copy(src, dst, (size_t)map_length)) { return 1; } } /* * Reserve a buffer for the current image block */ if (NULL == (image = (struct binbuffer *)zalloc(sizeof(*image)))) { return 1; } /* * Parse the GIF block by block and copy the relevant * parts to dst */ while(src->offset < src->size) { switch(buf_getbyte(src, 0)) { /* * End-of-GIF Marker: Append current image and return */ case 0x3b: goto write; /* * Image block: Extract to current image buffer. */ case 0x2c: image->offset = 0; if (gif_extract_image(src, image)) goto failed; if (get_first_image) goto write; continue; /* * Extension block: Look at next byte and decide */ case 0x21: switch (buf_getbyte(src, 1)) { /* * Image extension: Copy extension header and image * to the current image buffer */ case 0xf9: image->offset = 0; if (buf_copy(src, image, 8) || buf_getbyte(src, 0) != 0x2c) goto failed; if (gif_extract_image(src, image)) goto failed; if (get_first_image) goto write; continue; /* * Application extension: Skip */ case 0xff: if ((src->offset += 14) >= src->size || gif_skip_data_block(src)) goto failed; continue; /* * Comment extension: Skip */ case 0xfe: if ((src->offset += 2) >= src->size || gif_skip_data_block(src)) goto failed; continue; /* * Plain text extension: Skip */ case 0x01: if ((src->offset += 15) >= src->size || gif_skip_data_block(src)) goto failed; continue; /* * Ooops, what type of extension is that? */ default: goto failed; } /* * Ooops, what type of block is that? */ default: goto failed; } } /* -END- while src */ /* * Either we got here by goto, or because the GIF is * bogus and EOF was reached before an end-of-gif marker * was found. */ failed: buf_free(image); return 1; /* * Append the current image to dst and return */ write: if (buf_copy(image, dst, image->size)) goto failed; if (buf_extend(dst, 1)) goto failed; *(dst->buffer + dst->offset++) = 0x3b; buf_free(image); return 0; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./ssplit.h000640 001751 001751 00000004135 11764413377 015471 0ustar00fkfk000000 000000 #ifndef SSPLIT_H_INCLUDED #define SSPLIT_H_INCLUDED #define SSPLIT_H_VERSION "$Id: ssplit.h,v 1.11 2012/06/08 15:15:11 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/ssplit.h,v $ * * Purpose : A function to split a string at specified deliminters. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif extern int ssplit(char *str, const char *delim, char *vec[], size_t vec_len); /* Revision control strings from this header and associated .c file */ extern const char ssplit_rcs[]; extern const char ssplit_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef SSPLIT_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./user.action000640 001751 001751 00000021132 11655470441 016145 0ustar00fkfk000000 000000 ###################################################################### # # File : $Source: /cvsroot/ijbswa/current/user.action,v $ # # $Id: user.action,v 1.13 2011/11/06 11:36:01 fabiankeil Exp $ # # Purpose : User-maintained actions file, see # http://www.privoxy.org/user-manual/actions-file.html # ###################################################################### # This is the place to add your personal exceptions and additions to # the general policies as defined in default.action. (Here they will be # safe from updates to default.action.) Later defined actions always # take precedence, so anything defined here should have the last word. # See http://www.privoxy.org/user-manual/actions-file.html, or the # comments in default.action, for an explanation of what an "action" is # and what each action does. # The examples included here either use bogus sites, or have the actual # rules commented out (with the '#' character). Useful aliases are # included in the top section as a convenience. ############################################################################# # Aliases ############################################################################# {{alias}} ############################################################################# # # You can define a short form for a list of permissions - e.g., instead # of "-crunch-incoming-cookies -crunch-outgoing-cookies -filter -fast-redirects", # you can just write "shop". This is called an alias. # # Currently, an alias can contain any character except space, tab, '=', '{' # or '}'. # But please use only 'a'-'z', '0'-'9', '+', and '-'. # # Alias names are not case sensitive. # # Aliases beginning with '+' or '-' may be used for system action names # in future releases - so try to avoid alias names like this. (e.g. # "+crunch-all-cookies" below is not a good name) # # Aliases must be defined before they are used. # # These aliases just save typing later: # +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies allow-all-cookies = -crunch-all-cookies -session-cookies-only -filter{content-cookies} allow-popups = -filter{all-popups} -filter{unsolicited-popups} +block-as-image = +block{Blocked image request.} +handle-as-image -block-as-image = -block # These aliases define combinations of actions # that are useful for certain types of sites: # fragile = -block -crunch-all-cookies -filter -fast-redirects -hide-referer -prevent-compression shop = -crunch-all-cookies allow-popups # Your favourite blend of filters: # myfilters = +filter{html-annoyances} +filter{js-annoyances} +filter{all-popups}\ +filter{webbugs} +filter{banners-by-size} # Allow ads for selected useful free sites: # allow-ads = -block -filter{banners-by-size} -filter{banners-by-link} #... etc. Customize to your heart's content. ## end aliases ######################################################## ####################################################################### # Begin examples: ##################################################### # Say you have accounts on some sites that you visit regularly, and you # don't want to have to log in manually each time. So you'd like to allow # persistent cookies for these sites. The allow-all-cookies alias defined # above does exactly that, i.e. it disables crunching of cookies in any # direction, and the processing of cookies to make them only temporary. # { allow-all-cookies } #.sourceforge.net #sunsolve.sun.com #slashdot.org #.yahoo.com #.msdn.microsoft.com #.redhat.com # Say the site where you do your homebanking needs to open popup # windows, but you have chosen to kill popups uncoditionally by default. # This will allow it for your-example-bank.com: # { -filter{all-popups} } .banking.example.com # Some hosts and some file types you may not want to filter for # various reasons: # { -filter } # Technical documentation is likely to contain strings that might # erroneously get altered by the JavaScript-oriented filters: # #.tldp.org #/(.*/)?selfhtml/ # And this stupid host sends streaming video with a wrong MIME type, # so that Privoxy thinks it is getting HTML and starts filtering: # stupid-server.example.com/ # Example of a simple "block" action. Say you've seen an ad on your # favourite page on example.com that you want to get rid of. You have # right-clicked the image, selected "copy image location" and pasted # the URL below while removing the leading http://, into a { +block{reason} } # section. Note that { +handle-as-image } need not be specified, since # all URLs ending in .gif will be tagged as images by the general rules # as set in default.action anyway: # { +block{Nasty ads.} } www.example.com/nasty-ads/sponsor.gif # The URLs of dynamically generated banners, especially from large banner # farms, often don't use the well-known image file name extensions, which # makes it impossible for Privoxy to guess the file type just by looking # at the URL. # You can use the +block-as-image alias defined above for these cases. # Note that objects which match this rule but then turn out NOT to be an # image are typically rendered as a "broken image" icon by the browser. # Use cautiously. # { +block-as-image } #.doubleclick.net #/Realmedia/ads/ #ar.atwola.com/ # Now you noticed that the default configuration breaks Forbes # Magazine, but you were too lazy to find out which action is the # culprit, and you were again too lazy to give feedback, so you just # used the fragile alias on the site, and -- whoa! -- it worked. The # 'fragile' aliases disables those actions that are most likely to break # a site. Also, good for testing purposes to see if it is Privoxy that # is causing the problem or not. # { fragile } #.forbes.com # Here are some sites we wish to support, and we will allow their ads # through. # { allow-ads } #.sourceforge.net #.slashdot.org #.osdn.net # user.action is generally the best place to define exceptions and # additions to the default policies of default.action. Some actions are # safe to have their default policies set here though. So let's set a # default policy to have a 'blank' image as opposed to the checkerboard # pattern for ALL sites. '/' of course matches all URLs. # patterns: # { +set-image-blocker{blank} } #/ # Enable the following section (not the regression-test directives) # to rewrite and redirect click-tracking URLs on news.google.com. # Disabling JavaScript should work as well and probably works more reliably. # # Redirected URL = http://news.google.com/news/url?ct2=us%2F0_0_s_1_1_a&sa=t&usg=AFQjCNHJWPc7ffoSXPSqBRz55jDA0KgxOQ&cid=8797762374160&url=http%3A%2F%2Fonline.wsj.com%2Farticle%2FSB10001424052970204485304576640791304008536.html&ei=YcqeTsymCIjxggf8uQE&rt=HOMEPAGE&vm=STANDARD&bvm=section&did=-6537064229385238098 # Redirect Destination = http://online.wsj.com/article/SB10001424052970204485304576640791304008536.html # Ignore = Yes # #{+fast-redirects{check-decoded-url}} #news.google.com/news/url.*&url=http.*& # Enable the following section (not the regression-test directives) # to block various Facebook "like" and similar tracking URLs. At the # time this section was added it was reported to not break Facebook # itself but this may have changed by the time you read this. This URL # list is probably incomplete and if you don't have an account anyway, # you may prefer to block the whole domain. # # Blocked URL = http://www.facebook.com/plugins/likebox.php?href=http%3A%2F%2Ffacebook.com%2Farstechnica&width=300&colorscheme=light&show_faces=false&stream=false&header=false&height=62&border_color=%23FFFFFF # Ignore = Yes # Blocked URL = http://www.facebook.com/plugins/activity.php?site=arstechnica.com&width=300&height=370&header=false&colorscheme=light&recommendations=false&border_color=%23FFFFFF # Ignore = Yes # Blocked URL = http://www.facebook.com/plugins/fan.php?api_key=368513495882&connections=10&height=250&id=8304333127&locale=en_US&sdk=joey&stream=false&width=377 # Ignore = Yes # Blocked URL = http://www.facebook.com/plugins/like.php?api_key=368513495882&channel_url=http%3A%2F%2Fstatic.ak.fbcdn.net%2Fconnect%2Fxd_proxy.php%3Fversion%3D3%23cb%3Df13997452c%26origin%3Dhttp%253A%252F%252Fonline.wsj.com%252Ff1b037e354%26relation%3Dparent.parent%26transport%3Dpostmessage&extended_social_context=false&href=http%3A%2F%2Fonline.wsj.com%2Farticle%2FSB10001424052970204485304576640791304008536.html&layout=button_count&locale=en_US&node_type=link&ref=wsj_share_FB&sdk=joey&send=false&show_faces=false&width=90 # Ignore = Yes # #{+block{Facebook "like" and similar tracking URLs.}} #www.facebook.com/(extern|plugins)/(login_status|like(box)?|activity|fan)\.php privoxy-3.0.21-stable/./actionlist.h000640 001751 001751 00000025511 12047716035 016315 0ustar00fkfk000000 000000 /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actionlist.h,v $ * * Purpose : Master list of supported actions. * Not really a header, since it generates code. * This is included (3 times!) from actions.c * Each time, the following macros are defined to * suitable values beforehand: * DEFINE_ACTION_MULTI() * DEFINE_ACTION_STRING() * DEFINE_ACTION_BOOL() * DEFINE_ACTION_ALIAS * * Copyright : Written by and Copyright (C) 2001-2008 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #if !(defined(DEFINE_ACTION_BOOL) && defined(DEFINE_ACTION_MULTI) && defined(DEFINE_ACTION_STRING)) #error Please define lots of macros before including "actionlist.h". #endif /* !defined(all the DEFINE_ACTION_xxx macros) */ #ifndef DEFINE_CGI_PARAM_RADIO #define DEFINE_CGI_PARAM_RADIO(name, bit, index, value, is_default) #define DEFINE_CGI_PARAM_CUSTOM(name, bit, index, default_val) #define DEFINE_CGI_PARAM_NO_RADIO(name, bit, index, default_val) #endif /* ndef DEFINE_CGI_PARAM_RADIO */ DEFINE_ACTION_MULTI ("add-header", ACTION_MULTI_ADD_HEADER) DEFINE_ACTION_STRING ("block", ACTION_BLOCK, ACTION_STRING_BLOCK) DEFINE_CGI_PARAM_NO_RADIO("block", ACTION_BLOCK, ACTION_STRING_BLOCK, "No reason specified.") DEFINE_ACTION_STRING ("change-x-forwarded-for", ACTION_CHANGE_X_FORWARDED_FOR, ACTION_STRING_CHANGE_X_FORWARDED_FOR) DEFINE_CGI_PARAM_RADIO ("change-x-forwarded-for", ACTION_CHANGE_X_FORWARDED_FOR, ACTION_STRING_CHANGE_X_FORWARDED_FOR, "block", 0) DEFINE_CGI_PARAM_RADIO ("change-x-forwarded-for", ACTION_CHANGE_X_FORWARDED_FOR, ACTION_STRING_CHANGE_X_FORWARDED_FOR, "add", 1) DEFINE_ACTION_MULTI ("client-header-filter", ACTION_MULTI_CLIENT_HEADER_FILTER) DEFINE_ACTION_MULTI ("client-header-tagger", ACTION_MULTI_CLIENT_HEADER_TAGGER) DEFINE_ACTION_STRING ("content-type-overwrite", ACTION_CONTENT_TYPE_OVERWRITE, ACTION_STRING_CONTENT_TYPE) DEFINE_CGI_PARAM_NO_RADIO("content-type-overwrite", ACTION_CONTENT_TYPE_OVERWRITE, ACTION_STRING_CONTENT_TYPE, "text/html") DEFINE_ACTION_STRING ("crunch-client-header", ACTION_CRUNCH_CLIENT_HEADER, ACTION_STRING_CLIENT_HEADER) DEFINE_CGI_PARAM_NO_RADIO("crunch-client-header", ACTION_CRUNCH_CLIENT_HEADER, ACTION_STRING_CLIENT_HEADER, "X-Whatever:") DEFINE_ACTION_BOOL ("crunch-if-none-match", ACTION_CRUNCH_IF_NONE_MATCH) DEFINE_ACTION_BOOL ("crunch-incoming-cookies", ACTION_CRUNCH_INCOMING_COOKIES) DEFINE_ACTION_BOOL ("crunch-outgoing-cookies", ACTION_CRUNCH_OUTGOING_COOKIES) DEFINE_ACTION_STRING ("crunch-server-header", ACTION_CRUNCH_SERVER_HEADER, ACTION_STRING_SERVER_HEADER) DEFINE_CGI_PARAM_NO_RADIO("crunch-server-header", ACTION_CRUNCH_SERVER_HEADER, ACTION_STRING_SERVER_HEADER, "X-Whatever:") DEFINE_ACTION_STRING ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE) DEFINE_CGI_PARAM_RADIO ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE, "first", 0) DEFINE_CGI_PARAM_RADIO ("deanimate-gifs", ACTION_DEANIMATE, ACTION_STRING_DEANIMATE, "last", 1) DEFINE_ACTION_BOOL ("downgrade-http-version", ACTION_DOWNGRADE) #ifdef FEATURE_FAST_REDIRECTS DEFINE_ACTION_STRING ("fast-redirects", ACTION_FAST_REDIRECTS, ACTION_STRING_FAST_REDIRECTS) DEFINE_CGI_PARAM_RADIO ("fast-redirects", ACTION_FAST_REDIRECTS, ACTION_STRING_FAST_REDIRECTS, "simple-check", 0) DEFINE_CGI_PARAM_RADIO ("fast-redirects", ACTION_FAST_REDIRECTS, ACTION_STRING_FAST_REDIRECTS, "check-decoded-url", 1) #endif /* def FEATURE_FAST_REDIRECTS */ DEFINE_ACTION_MULTI ("filter", ACTION_MULTI_FILTER) DEFINE_ACTION_BOOL ("force-text-mode", ACTION_FORCE_TEXT_MODE) DEFINE_ACTION_STRING ("forward-override", ACTION_FORWARD_OVERRIDE, ACTION_STRING_FORWARD_OVERRIDE) DEFINE_CGI_PARAM_CUSTOM ("forward-override", ACTION_FORWARD_OVERRIDE, ACTION_STRING_FORWARD_OVERRIDE, "forward .") DEFINE_ACTION_BOOL ("handle-as-empty-document", ACTION_HANDLE_AS_EMPTY_DOCUMENT) DEFINE_ACTION_BOOL ("handle-as-image", ACTION_IMAGE) DEFINE_ACTION_STRING ("hide-accept-language", ACTION_HIDE_ACCEPT_LANGUAGE, ACTION_STRING_LANGUAGE) DEFINE_CGI_PARAM_RADIO ("hide-accept-language", ACTION_HIDE_ACCEPT_LANGUAGE, ACTION_STRING_LANGUAGE, "block", 0) DEFINE_CGI_PARAM_CUSTOM ("hide-accept-language", ACTION_HIDE_ACCEPT_LANGUAGE, ACTION_STRING_LANGUAGE, "de-de") DEFINE_ACTION_STRING ("hide-content-disposition", ACTION_HIDE_CONTENT_DISPOSITION, ACTION_STRING_CONTENT_DISPOSITION) DEFINE_CGI_PARAM_RADIO ("hide-content-disposition", ACTION_HIDE_CONTENT_DISPOSITION, ACTION_STRING_CONTENT_DISPOSITION, "block", 0) DEFINE_CGI_PARAM_CUSTOM ("hide-content-disposition", ACTION_HIDE_CONTENT_DISPOSITION, ACTION_STRING_CONTENT_DISPOSITION, "attachment; filename=WHATEVER.txt") DEFINE_ACTION_STRING ("hide-from-header", ACTION_HIDE_FROM, ACTION_STRING_FROM) DEFINE_CGI_PARAM_RADIO ("hide-from-header", ACTION_HIDE_FROM, ACTION_STRING_FROM, "block", 1) DEFINE_CGI_PARAM_CUSTOM ("hide-from-header", ACTION_HIDE_FROM, ACTION_STRING_FROM, "spam_me_senseless@sittingduck.xyz") DEFINE_ACTION_STRING ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE) DEFINE_CGI_PARAM_RADIO ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "block", 0) DEFINE_CGI_PARAM_CUSTOM ("hide-if-modified-since", ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "-1") DEFINE_ACTION_STRING ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "conditional-forge", 3) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "conditional-block", 2) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "forge", 1) DEFINE_CGI_PARAM_RADIO ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "block", 0) DEFINE_CGI_PARAM_CUSTOM ("hide-referrer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER, "http://www.privoxy.org/") DEFINE_ACTION_STRING ("hide-user-agent", ACTION_HIDE_USER_AGENT, ACTION_STRING_USER_AGENT) DEFINE_CGI_PARAM_NO_RADIO("hide-user-agent", ACTION_HIDE_USER_AGENT, ACTION_STRING_USER_AGENT, "Privoxy " VERSION) DEFINE_ACTION_STRING ("limit-connect", ACTION_LIMIT_CONNECT, ACTION_STRING_LIMIT_CONNECT) DEFINE_CGI_PARAM_NO_RADIO("limit-connect", ACTION_LIMIT_CONNECT, ACTION_STRING_LIMIT_CONNECT, "443") DEFINE_ACTION_STRING ("limit-cookie-lifetime", ACTION_LIMIT_COOKIE_LIFETIME, ACTION_STRING_LIMIT_COOKIE_LIFETIME) DEFINE_CGI_PARAM_CUSTOM ("limit-cookie-lifetime", ACTION_LIMIT_COOKIE_LIFETIME, ACTION_STRING_LIMIT_COOKIE_LIFETIME, "60") DEFINE_ACTION_STRING ("overwrite-last-modified", ACTION_OVERWRITE_LAST_MODIFIED, ACTION_STRING_LAST_MODIFIED) DEFINE_CGI_PARAM_RADIO ("overwrite-last-modified", ACTION_OVERWRITE_LAST_MODIFIED, ACTION_STRING_LAST_MODIFIED, "block", 0) DEFINE_CGI_PARAM_RADIO ("overwrite-last-modified", ACTION_OVERWRITE_LAST_MODIFIED, ACTION_STRING_LAST_MODIFIED, "reset-to-request-time", 1) DEFINE_CGI_PARAM_RADIO ("overwrite-last-modified", ACTION_OVERWRITE_LAST_MODIFIED, ACTION_STRING_LAST_MODIFIED, "randomize", 2) DEFINE_ACTION_BOOL ("prevent-compression", ACTION_NO_COMPRESSION) DEFINE_ACTION_STRING ("redirect", ACTION_REDIRECT, ACTION_STRING_REDIRECT) DEFINE_CGI_PARAM_NO_RADIO("redirect", ACTION_REDIRECT, ACTION_STRING_REDIRECT, "http://localhost/") DEFINE_ACTION_MULTI ("server-header-filter", ACTION_MULTI_SERVER_HEADER_FILTER) DEFINE_ACTION_MULTI ("server-header-tagger", ACTION_MULTI_SERVER_HEADER_TAGGER) DEFINE_ACTION_BOOL ("session-cookies-only", ACTION_SESSION_COOKIES_ONLY) DEFINE_ACTION_STRING ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER) DEFINE_CGI_PARAM_RADIO ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, "pattern", 1) DEFINE_CGI_PARAM_RADIO ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, "blank", 0) DEFINE_CGI_PARAM_CUSTOM ("set-image-blocker", ACTION_IMAGE_BLOCKER, ACTION_STRING_IMAGE_BLOCKER, CGI_PREFIX "send-banner?type=pattern") #if DEFINE_ACTION_ALIAS /* * Alternative spellings */ DEFINE_ACTION_STRING ("hide-referer", ACTION_HIDE_REFERER, ACTION_STRING_REFERER) DEFINE_ACTION_BOOL ("prevent-keeping-cookies", ACTION_SESSION_COOKIES_ONLY) /* * Pre-3.0.7 (pseudo) compatibility */ DEFINE_ACTION_MULTI ("filter-client-headers", ACTION_MULTI_CLIENT_HEADER_FILTER) DEFINE_ACTION_MULTI ("filter-server-headers", ACTION_MULTI_SERVER_HEADER_FILTER) #endif /* if DEFINE_ACTION_ALIAS */ #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS #undef DEFINE_CGI_PARAM_CUSTOM #undef DEFINE_CGI_PARAM_RADIO #undef DEFINE_CGI_PARAM_NO_RADIO privoxy-3.0.21-stable/./w32res.h000640 001751 001751 00000007050 11630656300 015262 0ustar00fkfk000000 000000 #ifndef W32RES_H_INCLUDED #define W32RES_H_INCLUDED #define W32RES_H_VERSION "$Id: w32res.h,v 1.20 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32res.h,v $ * * Purpose : Identifiers for Windows GUI resources. * * Copyright : Written by and Copyright (C) 2001-2002 members of * the Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #define IDR_TRAYMENU 101 #define IDI_IDLE 102 #define IDR_LOGVIEW 103 #define IDR_ACCELERATOR 104 #define IDR_POPUP_SELECTION 105 #define IDI_MAINICON 200 #define IDI_ANIMATED1 201 #define IDI_ANIMATED2 202 #define IDI_ANIMATED3 203 #define IDI_ANIMATED4 204 #define IDI_ANIMATED5 205 #define IDI_ANIMATED6 206 #define IDI_ANIMATED7 207 #define IDI_ANIMATED8 208 #define IDI_OFF 209 #define ID_TOGGLE_SHOWWINDOW 4000 #define ID_HELP_ABOUT 4001 #define ID_FILE_EXIT 4002 #define ID_VIEW_CLEARLOG 4003 #define ID_VIEW_LOGMESSAGES 4004 #define ID_VIEW_MESSAGEHIGHLIGHTING 4005 #define ID_VIEW_LIMITBUFFERSIZE 4006 #define ID_VIEW_ACTIVITYANIMATION 4007 #define ID_HELP_FAQ 4008 #define ID_HELP_MANUAL 4009 #define ID_HELP_GPL 4010 #define ID_HELP_STATUS 4011 #ifdef FEATURE_TOGGLE #define ID_TOGGLE_ENABLED 4012 #endif /* def FEATURE_TOGGLE */ /* Break these out so they are easier to extend, but keep consecutive */ #define ID_TOOLS_EDITCONFIG 5000 #define ID_TOOLS_EDITDEFAULTACTIONS 5001 #define ID_TOOLS_EDITUSERACTIONS 5002 #define ID_TOOLS_EDITDEFAULTFILTERS 5003 #define ID_TOOLS_EDITUSERFILTERS 5004 #ifdef FEATURE_TRUST #define ID_TOOLS_EDITTRUST 5005 #endif /* def FEATURE_TRUST */ #define ID_EDIT_COPY 30000 #endif /* ndef W32RES_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./miscutil.h000640 001751 001751 00000007350 12054151171 015766 0ustar00fkfk000000 000000 #ifndef MISCUTIL_H_INCLUDED #define MISCUTIL_H_INCLUDED #define MISCUTIL_H_VERSION "$Id: miscutil.h,v 1.37 2012/11/24 13:58:17 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/miscutil.h,v $ * * Purpose : zalloc, hash_string, strcmpic, strncmpic, and * MinGW32 strdup functions. These are each too small * to deserve their own file but don't really fit in * any other file. * * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "project.h" #if defined(__cplusplus) extern "C" { #endif extern const char *basedir; extern void *zalloc(size_t size); extern char *strdup_or_die(const char *str); extern void *malloc_or_die(size_t buffer_size); #if defined(unix) extern void write_pid_file(void); #endif /* unix */ extern unsigned int hash_string(const char* s); extern int strcmpic(const char *s1, const char *s2); extern int strncmpic(const char *s1, const char *s2, size_t n); extern jb_err string_append(char **target_string, const char *text_to_append); extern jb_err string_join (char **target_string, char *text_to_append); extern char *string_toupper(const char *string); extern void string_move(char *dst, char *src); extern char *chomp(char *string); extern char *bindup(const char *string, size_t len); extern char *make_path(const char * dir, const char * file); long int pick_from_range(long int range); #ifndef HAVE_SNPRINTF extern int snprintf(char *, size_t, const char *, /*args*/ ...); #endif /* ndef HAVE_SNPRINTF */ #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) time_t timegm(struct tm *tm); #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */ /* Here's looking at you, Ulrich. */ #if !defined(HAVE_STRLCPY) size_t privoxy_strlcpy(char *destination, const char *source, size_t size); #define strlcpy privoxy_strlcpy #define USE_PRIVOXY_STRLCPY 1 #define HAVE_STRLCPY 1 #endif /* ndef HAVE_STRLCPY*/ #ifndef HAVE_STRLCAT size_t privoxy_strlcat(char *destination, const char *source, size_t size); #define strlcat privoxy_strlcat #endif /* ndef HAVE_STRLCAT */ /* Revision control strings from this header and associated .c file */ extern const char miscutil_rcs[]; extern const char miscutil_h_rcs[]; #if defined(__cplusplus) } #endif #endif /* ndef MISCUTIL_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./pcre/configure.in000640 001751 001751 00000004124 10546014100 017214 0ustar00fkfk000000 000000 dnl Process this file with autoconf to produce a configure script. dnl This is required at the start; the name is the name of a file dnl it should be seeing, to verify it is in the same directory. AC_INIT(dftables.c) dnl Arrange to build config.h from config.in. Note that pcre.h is dnl built differently, as it is just a "substitution" file. dnl Manual says this macro should come right after AC_INIT. AC_CONFIG_HEADER(config.h:config.in) dnl Provide the current PCRE version information. Do not use numbers dnl with leading zeros for the minor version, as they end up in a C dnl macro, and may be treated as octal constants. Stick to single dnl digits for minor numbers less than 10. There are unlikely to be dnl that many releases anyway. PCRE_MAJOR=3 PCRE_MINOR=4 PCRE_DATE=22-Aug-2000 PCRE_VERSION=${PCRE_MAJOR}.${PCRE_MINOR} dnl Provide versioning information for libtool shared libraries that dnl are built by default on Unix systems. PCRE_LIB_VERSION=0:1:0 PCRE_POSIXLIB_VERSION=0:0:0 dnl Checks for programs. AC_PROG_CC AC_PROG_RANLIB dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(limits.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T dnl Checks for library functions. AC_CHECK_FUNCS(bcopy memmove strerror) dnl Handle --enable-shared-libraries LIBTOOL=./libtool LIBSUFFIX=la AC_ARG_ENABLE(shared, [ --disable-shared build PCRE as a static library], if test "$enableval" = "no"; then LIBTOOL= LIBSUFFIX=a fi ) dnl Handle --enable-utf8 AC_ARG_ENABLE(utf8, [ --enable-utf8 enable UTF8 support (incomplete)], if test "$enableval" = "yes"; then UTF8=-DSUPPORT_UTF8 fi ) dnl "Export" these variables AC_SUBST(HAVE_MEMMOVE) AC_SUBST(HAVE_STRERROR) AC_SUBST(LIBTOOL) AC_SUBST(LIBSUFFIX) AC_SUBST(UTF8) AC_SUBST(PCRE_MAJOR) AC_SUBST(PCRE_MINOR) AC_SUBST(PCRE_DATE) AC_SUBST(PCRE_VERSION) AC_SUBST(PCRE_LIB_VERSION) AC_SUBST(PCRE_POSIXLIB_VERSION) dnl This must be last; it determines what files are written AC_OUTPUT(Makefile pcre.h:pcre.in pcre-config:pcre-config.in RunTest:RunTest.in,[chmod a+x RunTest pcre-config]) privoxy-3.0.21-stable/./pcre/pcre.c000640 001751 001751 00000451021 10546014100 016002 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* Define DEBUG to get debugging output on stdout. */ /* #define DEBUG */ /* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef inline, and there are *still* stupid compilers about that don't like indented pre-processor statements. I suppose it's only been 10 years... */ #ifdef DEBUG #define DPRINTF(p) printf p #else #define DPRINTF(p) /*nothing*/ #endif /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /* Allow compilation as C++ source code, should anybody want to do that. */ #ifdef __cplusplus #define class pcre_class #endif /* Number of items on the nested bracket stacks at compile time. This should not be set greater than 200. */ #define BRASTACK_SIZE 200 /* The number of bytes in a literal character string above which we can't add any more is different when UTF-8 characters may be encountered. */ #ifdef SUPPORT_UTF8 #define MAXLIT 250 #else #define MAXLIT 255 #endif /* Min and max values for the common repeats; for the maxima, 0 => infinity */ static const char rep_min[] = { 0, 0, 1, 1, 0, 0 }; static const char rep_max[] = { 0, 0, 0, 0, 1, 1 }; /* Text forms of OP_ values and things, for debugging (not all used) */ #ifdef DEBUG static const char *OP_names[] = { "End", "\\A", "\\B", "\\b", "\\D", "\\d", "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z", "Opt", "^", "$", "Any", "chars", "not", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "class", "Ref", "Recurse", "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref", "Brazero", "Braminzero", "Bra" }; #endif /* Table for handling escaped characters in the range '0'-'z'. Positive returns are simple data values; negative values are for special things like \d and so on. Zero means further processing is needed (for things like \x), or the escape is invalid. */ static const short int escapes[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ '@', -ESC_A, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ 0, 0, -ESC_Z, '[', '\\', ']', '^', '_', /* X - _ */ '`', 7, -ESC_b, 0, -ESC_d, 27, '\f', 0, /* ` - g */ 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ 0, 0, '\r', -ESC_s, '\t', 0, 0, -ESC_w, /* p - w */ 0, 0, -ESC_z /* x - z */ }; /* Tables of names of POSIX character classes and their lengths. The list is terminated by a zero length entry. The first three must be alpha, upper, lower, as this is assumed for handling case independence. */ static const char *posix_names[] = { "alpha", "lower", "upper", "alnum", "ascii", "cntrl", "digit", "graph", "print", "punct", "space", "word", "xdigit" }; static const uschar posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; /* Table of class bit maps for each POSIX class; up to three may be combined to form the class. */ static const int posix_class_maps[] = { cbit_lower, cbit_upper, -1, /* alpha */ cbit_lower, -1, -1, /* lower */ cbit_upper, -1, -1, /* upper */ cbit_digit, cbit_lower, cbit_upper, /* alnum */ cbit_print, cbit_cntrl, -1, /* ascii */ cbit_cntrl, -1, -1, /* cntrl */ cbit_digit, -1, -1, /* digit */ cbit_graph, -1, -1, /* graph */ cbit_print, -1, -1, /* print */ cbit_punct, -1, -1, /* punct */ cbit_space, -1, -1, /* space */ cbit_word, -1, -1, /* word */ cbit_xdigit,-1, -1 /* xdigit */ }; /* Definition to allow mutual recursion */ static BOOL compile_regex(int, int, int *, uschar **, const uschar **, const char **, BOOL, int, int *, int *, compile_data *); /* Structure for building a chain of data that actually lives on the stack, for holding the values of the subject pointer at the start of each subpattern, so as to detect when an empty string has been matched by a subpattern - to break infinite loops. */ typedef struct eptrblock { struct eptrblock *prev; const uschar *saved_eptr; } eptrblock; /* Flag bits for the match() function */ #define match_condassert 0x01 /* Called to check a condition assertion */ #define match_isgroup 0x02 /* Set if start of bracketed group */ /************************************************* * Global variables * *************************************************/ /* PCRE is thread-clean and doesn't use any global variables in the normal sense. However, it calls memory allocation and free functions via the two indirections below, which are can be changed by the caller, but are shared between all threads. */ void *(*pcre_malloc)(size_t) = malloc; void (*pcre_free)(void *) = free; /************************************************* * Macros and tables for character handling * *************************************************/ /* When UTF-8 encoding is being used, a character is no longer just a single byte. The macros for character handling generate simple sequences when used in byte-mode, and more complicated ones for UTF-8 characters. */ #ifndef SUPPORT_UTF8 #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; #define BACKCHAR(eptr) #else /* SUPPORT_UTF8 */ /* Get the next UTF-8 character, advancing the pointer */ #define GETCHARINC(c, eptr) \ c = *eptr++; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ int s = 6 - a; /* Amount to shift next byte */ \ c &= utf8_table3[a]; /* Low order bits from first byte */ \ while (a-- > 0) \ { \ c |= (*eptr++ & 0x3f) << s; \ s += 6; \ } \ } /* Get the next UTF-8 character, not advancing the pointer, setting length */ #define GETCHARLEN(c, eptr, len) \ c = *eptr; \ len = 1; \ if (md->utf8 && (c & 0xc0) == 0xc0) \ { \ int i; \ int a = utf8_table4[c & 0x3f]; /* Number of additional bytes */ \ int s = 6 - a; /* Amount to shift next byte */ \ c &= utf8_table3[a]; /* Low order bits from first byte */ \ for (i = 1; i <= a; i++) \ { \ c |= (eptr[i] & 0x3f) << s; \ s += 6; \ } \ len += a; \ } /* If the pointer is not at the start of a character, move it back until it is. */ #define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--; #endif /************************************************* * Default character tables * *************************************************/ /* A default set of character tables is included in the PCRE binary. Its source is built by the maketables auxiliary program, which uses the default C ctypes functions, and put in the file chartables.c. These tables are used by PCRE whenever the caller of pcre_compile() does not provide an alternate set of tables. */ #include "chartables.c" #ifdef SUPPORT_UTF8 /************************************************* * Tables for UTF-8 support * *************************************************/ /* These are the breakpoints for different numbers of bytes in a UTF-8 character. */ static int utf8_table1[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; /* These are the indicator bits and the mask for the data bits to set in the first byte of a character, indexed by the number of additional bytes. */ static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; /* Table of the number of extra characters, indexed by the first character masked with 0x3f. The highest number for a valid UTF-8 character is in fact 0x3d. */ static uschar utf8_table4[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /************************************************* * Convert character value to UTF-8 * *************************************************/ /* This function takes an integer value in the range 0 - 0x7fffffff and encodes it as a UTF-8 character in 0 to 6 bytes. Arguments: cvalue the character value buffer pointer to buffer for result - at least 6 bytes long Returns: number of characters placed in the buffer */ static int ord2utf8(int cvalue, uschar *buffer) { register int i, j; for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) if (cvalue <= utf8_table1[i]) break; *buffer++ = utf8_table2[i] | (cvalue & utf8_table3[i]); cvalue >>= 6 - i; for (j = 0; j < i; j++) { *buffer++ = 0x80 | (cvalue & 0x3f); cvalue >>= 6; } return i + 1; } #endif /************************************************* * Return version string * *************************************************/ #define STRING(a) # a #define XSTRING(s) STRING(s) const char * pcre_version(void) { return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE); } /************************************************* * (Obsolete) Return info about compiled pattern * *************************************************/ /* This is the original "info" function. It picks potentially useful data out of the private structure, but its interface was too rigid. It remains for backwards compatibility. The public options are passed back in an int - though the re->options field has been expanded to a long int, all the public options at the low end of it, and so even on 16-bit systems this will still be OK. Therefore, I haven't changed the API for pcre_info(). Arguments: external_re points to compiled code optptr where to pass back the options first_char where to pass back the first character, or -1 if multiline and all branches start ^, or -2 otherwise Returns: number of capturing subpatterns or negative values on error */ int pcre_info(const pcre *external_re, int *optptr, int *first_char) { const real_pcre *re = (const real_pcre *)external_re; if (re == NULL) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS); if (first_char != NULL) *first_char = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; return re->top_bracket; } /************************************************* * Return info about compiled pattern * *************************************************/ /* This is a newer "info" function which has an extensible interface so that additional items can be added compatibly. Arguments: external_re points to compiled code external_study points to study data, or NULL what what information is required where where to put the information Returns: 0 if data returned, negative on error */ int pcre_fullinfo(const pcre *external_re, const pcre_extra *study_data, int what, void *where) { const real_pcre *re = (const real_pcre *)external_re; const real_pcre_extra *study = (const real_pcre_extra *)study_data; if (re == NULL || where == NULL) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; switch (what) { case PCRE_INFO_OPTIONS: *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS; break; case PCRE_INFO_SIZE: *((size_t *)where) = re->size; break; case PCRE_INFO_CAPTURECOUNT: *((int *)where) = re->top_bracket; break; case PCRE_INFO_BACKREFMAX: *((int *)where) = re->top_backref; break; case PCRE_INFO_FIRSTCHAR: *((int *)where) = ((re->options & PCRE_FIRSTSET) != 0)? re->first_char : ((re->options & PCRE_STARTLINE) != 0)? -1 : -2; break; case PCRE_INFO_FIRSTTABLE: *((const uschar **)where) = (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)? study->start_bits : NULL; break; case PCRE_INFO_LASTLITERAL: *((int *)where) = ((re->options & PCRE_REQCHSET) != 0)? re->req_char : -1; break; default: return PCRE_ERROR_BADOPTION; } return 0; } #ifdef DEBUG /************************************************* * Debugging function to print chars * *************************************************/ /* Print a sequence of chars in printable format, stopping at the end of the subject if the requested. Arguments: p points to characters length number to print is_subject TRUE if printing from within md->start_subject md pointer to matching data block, if is_subject is TRUE Returns: nothing */ static void pchars(const uschar *p, int length, BOOL is_subject, match_data *md) { int c; if (is_subject && length > md->end_subject - p) length = md->end_subject - p; while (length-- > 0) if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c); } #endif /************************************************* * Handle escapes * *************************************************/ /* This function is called when a \ has been encountered. It either returns a positive value for a simple escape such as \n, or a negative value which encodes one of the more complicated things such as \d. When UTF-8 is enabled, a positive value greater than 255 may be returned. On entry, ptr is pointing at the \. On exit, it is on the final character of the escape sequence. Arguments: ptrptr points to the pattern position pointer errorptr points to the pointer to the error message bracount number of previous extracting brackets options the options bits isclass TRUE if inside a character class cd pointer to char tables block Returns: zero or positive => a data character negative => a special escape sequence on error, errorptr is set */ static int check_escape(const uschar **ptrptr, const char **errorptr, int bracount, int options, BOOL isclass, compile_data *cd) { const uschar *ptr = *ptrptr; int c, i; /* If backslash is at the end of the pattern, it's an error. */ c = *(++ptr); if (c == 0) *errorptr = ERR1; /* Digits or letters may have special meaning; all others are literals. */ else if (c < '0' || c > 'z') {} /* Do an initial lookup in a table. A non-zero result is something that can be returned immediately. Otherwise further processing may be required. */ else if ((i = escapes[c - '0']) != 0) c = i; /* Escapes that need further processing, or are illegal. */ else { const uschar *oldptr; switch (c) { /* The handling of escape sequences consisting of a string of digits starting with one that is not zero is not straightforward. By experiment, the way Perl works seems to be as follows: Outside a character class, the digits are read as a decimal number. If the number is less than 10, or if there are that many previous extracting left brackets, then it is a back reference. Otherwise, up to three octal digits are read to form an escaped byte. Thus \123 is likely to be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal value is greater than 377, the least significant 8 bits are taken. Inside a character class, \ followed by a digit is always an octal number. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!isclass) { oldptr = ptr; c -= '0'; while ((cd->ctypes[ptr[1]] & ctype_digit) != 0) c = c * 10 + *(++ptr) - '0'; if (c < 10 || c <= bracount) { c = -(ESC_REF + c); break; } ptr = oldptr; /* Put the pointer back and fall through */ } /* Handle an octal number following \. If the first digit is 8 or 9, Perl generates a binary zero byte and treats the digit as a following literal. Thus we have to pull back the pointer by one. */ if ((c = *ptr) >= '8') { ptr--; c = 0; break; } /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. */ case '0': c -= '0'; while(i++ < 2 && (cd->ctypes[ptr[1]] & ctype_digit) != 0 && ptr[1] != '8' && ptr[1] != '9') c = c * 8 + *(++ptr) - '0'; c &= 255; /* Take least significant 8 bits */ break; /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number which can be greater than 0xff, but only if the ddd are hex digits. */ case 'x': #ifdef SUPPORT_UTF8 if (ptr[1] == '{' && (options & PCRE_UTF8) != 0) { const uschar *pt = ptr + 2; register int count = 0; c = 0; while ((cd->ctypes[*pt] & ctype_xdigit) != 0) { count++; c = c * 16 + cd->lcc[*pt] - (((cd->ctypes[*pt] & ctype_digit) != 0)? '0' : 'W'); pt++; } if (*pt == '}') { if (c < 0 || count > 8) *errorptr = ERR34; ptr = pt; break; } /* If the sequence of hex digits does not end with '}', then we don't recognize this construct; fall through to the normal \x handling. */ } #endif /* Read just a single hex char */ c = 0; while (i++ < 2 && (cd->ctypes[ptr[1]] & ctype_xdigit) != 0) { ptr++; c = c * 16 + cd->lcc[*ptr] - (((cd->ctypes[*ptr] & ctype_digit) != 0)? '0' : 'W'); } break; /* Other special escapes not starting with a digit are straightforward */ case 'c': c = *(++ptr); if (c == 0) { *errorptr = ERR2; return 0; } /* A letter is upper-cased; then the 0x40 bit is flipped */ if (c >= 'a' && c <= 'z') c = cd->fcc[c]; c ^= 0x40; break; /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any other alphameric following \ is an error if PCRE_EXTRA was set; otherwise, for Perl compatibility, it is a literal. This code looks a bit odd, but there used to be some cases other than the default, and there may be again in future, so I haven't "optimized" it. */ default: if ((options & PCRE_EXTRA) != 0) switch(c) { default: *errorptr = ERR3; break; } break; } } *ptrptr = ptr; return c; } /************************************************* * Check for counted repeat * *************************************************/ /* This function is called when a '{' is encountered in a place where it might start a quantifier. It looks ahead to see if it really is a quantifier or not. It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. Arguments: p pointer to the first char after '{' cd pointer to char tables block Returns: TRUE or FALSE */ static BOOL is_counted_repeat(const uschar *p, compile_data *cd) { if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; while ((cd->ctypes[*p] & ctype_digit) != 0) p++; if (*p == '}') return TRUE; if (*p++ != ',') return FALSE; if (*p == '}') return TRUE; if ((cd->ctypes[*p++] & ctype_digit) == 0) return FALSE; while ((cd->ctypes[*p] & ctype_digit) != 0) p++; return (*p == '}'); } /************************************************* * Read repeat counts * *************************************************/ /* Read an item of the form {n,m} and return the values. This is called only after is_counted_repeat() has confirmed that a repeat-count quantifier exists, so the syntax is guaranteed to be correct, but we need to check the values. Arguments: p pointer to first char after '{' minp pointer to int for min maxp pointer to int for max returned as -1 if no max errorptr points to pointer to error message cd pointer to character tables clock Returns: pointer to '}' on success; current ptr on error, with errorptr set */ static const uschar * read_repeat_counts(const uschar *p, int *minp, int *maxp, const char **errorptr, compile_data *cd) { int min = 0; int max = -1; while ((cd->ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; if (*p == '}') max = min; else { if (*(++p) != '}') { max = 0; while((cd->ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; if (max < min) { *errorptr = ERR4; return p; } } } /* Do paranoid checks, then fill in the required variables, and pass back the pointer to the terminating '}'. */ if (min > 65535 || max > 65535) *errorptr = ERR5; else { *minp = min; *maxp = max; } return p; } /************************************************* * Find the fixed length of a pattern * *************************************************/ /* Scan a pattern and compute the fixed length of subject that will match it, if the length is fixed. This is needed for dealing with backward assertions. Arguments: code points to the start of the pattern (the bracket) options the compiling options Returns: the fixed length, or -1 if there is no fixed length */ static int find_fixedlength(uschar *code, int options) { int length = -1; register int branchlength = 0; register uschar *cc = code + 3; /* Scan along the opcodes for this branch. If we get to the end of the branch, check the length against that of the other branches. */ for (;;) { int d; register int op = *cc; if (op >= OP_BRA) op = OP_BRA; switch (op) { case OP_BRA: case OP_ONCE: case OP_COND: d = find_fixedlength(cc, options); if (d < 0) return -1; branchlength += d; do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); cc += 3; break; /* Reached end of a branch; if it's a ket it is the end of a nested call. If it's ALT it is an alternation in a nested call. If it is END it's the end of the outer call. All can be handled by the same code. */ case OP_ALT: case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_END: if (length < 0) length = branchlength; else if (length != branchlength) return -1; if (*cc != OP_ALT) return length; cc += 3; branchlength = 0; break; /* Skip over assertive subpatterns */ case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do cc += (cc[1] << 8) + cc[2]; while (*cc == OP_ALT); cc += 3; break; /* Skip over things that don't match chars */ case OP_REVERSE: cc++; /* Fall through */ case OP_CREF: case OP_OPT: cc++; /* Fall through */ case OP_SOD: case OP_EOD: case OP_EODN: case OP_CIRC: case OP_DOLL: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: cc++; break; /* Handle char strings. In UTF-8 mode we must count characters, not bytes. This requires a scan of the string, unfortunately. We assume valid UTF-8 strings, so all we do is reduce the length by one for byte whose bits are 10xxxxxx. */ case OP_CHARS: branchlength += *(++cc); #ifdef SUPPORT_UTF8 for (d = 1; d <= *cc; d++) if ((cc[d] & 0xc0) == 0x80) branchlength--; #endif cc += *cc + 1; break; /* Handle exact repetitions */ case OP_EXACT: case OP_TYPEEXACT: branchlength += (cc[1] << 8) + cc[2]; cc += 4; break; /* Handle single-char matchers */ case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: branchlength++; cc++; break; /* Check a class for variable quantification */ case OP_CLASS: cc += (*cc == OP_REF)? 2 : 33; switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: return -1; case OP_CRRANGE: case OP_CRMINRANGE: if ((cc[1] << 8) + cc[2] != (cc[3] << 8) + cc[4]) return -1; branchlength += (cc[1] << 8) + cc[2]; cc += 5; break; default: branchlength++; } break; /* Anything else is variable length */ default: return -1; } } /* Control never gets here */ } /************************************************* * Check for POSIX class syntax * *************************************************/ /* This function is called when the sequence "[:" or "[." or "[=" is encountered in a character class. It checks whether this is followed by an optional ^ and then a sequence of letters, terminated by a matching ":]" or ".]" or "=]". Argument: ptr pointer to the initial [ endptr where to return the end pointer cd pointer to compile data Returns: TRUE or FALSE */ static BOOL check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) { int terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ if (*(++ptr) == '^') ptr++; while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; if (*ptr == terminator && ptr[1] == ']') { *endptr = ptr; return TRUE; } return FALSE; } /************************************************* * Check POSIX class name * *************************************************/ /* This function is called to check the name given in a POSIX-style class entry such as [:alnum:]. Arguments: ptr points to the first letter len the length of the name Returns: a value representing the name, or -1 if unknown */ static int check_posix_name(const uschar *ptr, int len) { register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield; yield++; } return -1; } /************************************************* * Compile one branch * *************************************************/ /* Scan the pattern, compiling it into the code vector. Arguments: options the option bits brackets points to number of brackets used code points to the pointer to the current code point ptrptr points to the current pattern pointer errorptr points to pointer to error message optchanged set to the value of the last OP_OPT item compiled reqchar set to the last literal character required, else -1 countlits set to count of mandatory literal characters cd contains pointers to tables Returns: TRUE on success FALSE, with *errorptr set on error */ static BOOL compile_branch(int options, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, int *optchanged, int *reqchar, int *countlits, compile_data *cd) { int repeat_type, op_type; int repeat_min, repeat_max; int bravalue, length; int greedy_default, greedy_non_default; int prevreqchar; int condcount = 0; int subcountlits = 0; register int c; register uschar *code = *codeptr; uschar *tempcode; const uschar *ptr = *ptrptr; const uschar *tempptr; uschar *previous = NULL; uschar class[32]; /* Set up the default and non-default settings for greediness */ greedy_default = ((options & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; /* Initialize no required char, and count of literals */ *reqchar = prevreqchar = -1; *countlits = 0; /* Switch on next character until the end of the branch */ for (;; ptr++) { BOOL negate_class; int class_charcount; int class_lastchar; int newoptions; int condref; int subreqchar; c = *ptr; if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != '\n') ; continue; } } switch(c) { /* The branch terminates at end of string, |, or ). */ case 0: case '|': case ')': *codeptr = code; *ptrptr = ptr; return TRUE; /* Handle single-character metacharacters */ case '^': previous = NULL; *code++ = OP_CIRC; break; case '$': previous = NULL; *code++ = OP_DOLL; break; case '.': previous = code; *code++ = OP_ANY; break; /* Character classes. These always build a 32-byte bitmap of the permitted characters, except in the special case where there is only one character. For negated classes, we build the map as usual, then invert it at the end. */ case '[': previous = code; *code++ = OP_CLASS; /* If the first character is '^', set the negation flag and skip it. */ if ((c = *(++ptr)) == '^') { negate_class = TRUE; c = *(++ptr); } else negate_class = FALSE; /* Keep a count of chars so that we can optimize the case of just a single character. */ class_charcount = 0; class_lastchar = -1; /* Initialize the 32-char bit map to all zeros. We have to build the map in a temporary bit of store, in case the class contains only 1 character, because in that case the compiled code doesn't use the bit map. */ memset(class, 0, 32 * sizeof(uschar)); /* Process characters until ] is reached. By writing this as a "do" it means that an initial ] is taken as a data character. */ do { if (c == 0) { *errorptr = ERR6; goto FAILED; } /* Handle POSIX class names. Perl allows a negation extension of the form [:^name]. A square bracket that doesn't match the syntax is treated as a literal. We also recognize the POSIX constructions [.ch.] and [=ch=] ("collating elements") and fault them, as Perl 5.6 does. */ if (c == '[' && (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') && check_posix_syntax(ptr, &tempptr, cd)) { BOOL local_negate = FALSE; int posix_class, i; register const uschar *cbits = cd->cbits; if (ptr[1] != ':') { *errorptr = ERR31; goto FAILED; } ptr += 2; if (*ptr == '^') { local_negate = TRUE; ptr++; } posix_class = check_posix_name(ptr, tempptr - ptr); if (posix_class < 0) { *errorptr = ERR30; goto FAILED; } /* If matching is caseless, upper and lower are converted to alpha. This relies on the fact that the class table starts with alpha, lower, upper as the first 3 entries. */ if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) posix_class = 0; /* Or into the map we are building up to 3 of the static class tables, or their negations. */ posix_class *= 3; for (i = 0; i < 3; i++) { int taboffset = posix_class_maps[posix_class + i]; if (taboffset < 0) break; if (local_negate) for (c = 0; c < 32; c++) class[c] |= ~cbits[c+taboffset]; else for (c = 0; c < 32; c++) class[c] |= cbits[c+taboffset]; } ptr = tempptr + 1; class_charcount = 10; /* Set > 1; assumes more than 1 per class */ continue; } /* Backslash may introduce a single character, or it may introduce one of the specials, which just set a flag. Escaped items are checked for validity in the pre-compiling pass. The sequence \b is a special case. Inside a class (and only there) it is treated as backspace. Elsewhere it marks a word boundary. Other escapes have preset maps ready to or into the one we are building. We assume they have more than one character in them, so set class_count bigger than one. */ if (c == '\\') { c = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); if (-c == ESC_b) c = '\b'; else if (c < 0) { register const uschar *cbits = cd->cbits; class_charcount = 10; switch (-c) { case ESC_d: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_digit]; continue; case ESC_D: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_digit]; continue; case ESC_w: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_word]; continue; case ESC_W: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_word]; continue; case ESC_s: for (c = 0; c < 32; c++) class[c] |= cbits[c+cbit_space]; continue; case ESC_S: for (c = 0; c < 32; c++) class[c] |= ~cbits[c+cbit_space]; continue; default: *errorptr = ERR7; goto FAILED; } } /* Fall through if single character, but don't at present allow chars > 255 in UTF-8 mode. */ #ifdef SUPPORT_UTF8 if (c > 255) { *errorptr = ERR33; goto FAILED; } #endif } /* A single character may be followed by '-' to form a range. However, Perl does not permit ']' to be the end of the range. A '-' character here is treated as a literal. */ if (ptr[1] == '-' && ptr[2] != ']') { int d; ptr += 2; d = *ptr; if (d == 0) { *errorptr = ERR6; goto FAILED; } /* The second part of a range can be a single-character escape, but not any of the other escapes. Perl 5.6 treats a hyphen as a literal in such circumstances. */ if (d == '\\') { const uschar *oldptr = ptr; d = check_escape(&ptr, errorptr, *brackets, options, TRUE, cd); #ifdef SUPPORT_UTF8 if (d > 255) { *errorptr = ERR33; goto FAILED; } #endif /* \b is backslash; any other special means the '-' was literal */ if (d < 0) { if (d == -ESC_b) d = '\b'; else { ptr = oldptr - 2; goto SINGLE_CHARACTER; /* A few lines below */ } } } if (d < c) { *errorptr = ERR8; goto FAILED; } for (; c <= d; c++) { class[c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { int uc = cd->fcc[c]; /* flip case */ class[uc/8] |= (1 << (uc&7)); } class_charcount++; /* in case a one-char range */ class_lastchar = c; } continue; /* Go get the next char in the class */ } /* Handle a lone single character - we can get here for a normal non-escape char, or after \ that introduces a single character. */ SINGLE_CHARACTER: class [c/8] |= (1 << (c&7)); if ((options & PCRE_CASELESS) != 0) { c = cd->fcc[c]; /* flip case */ class[c/8] |= (1 << (c&7)); } class_charcount++; class_lastchar = c; } /* Loop until ']' reached; the check for end of string happens inside the loop. This "while" is the end of the "do" above. */ while ((c = *(++ptr)) != ']'); /* If class_charcount is 1 and class_lastchar is not negative, we saw precisely one character. This doesn't need the whole 32-byte bit map. We turn it into a 1-character OP_CHAR if it's positive, or OP_NOT if it's negative. */ if (class_charcount == 1 && class_lastchar >= 0) { if (negate_class) { code[-1] = OP_NOT; } else { code[-1] = OP_CHARS; *code++ = 1; } *code++ = class_lastchar; } /* Otherwise, negate the 32-byte map if necessary, and copy it into the code vector. */ else { if (negate_class) for (c = 0; c < 32; c++) code[c] = ~class[c]; else memcpy(code, class, 32); code += 32; } break; /* Various kinds of repeat */ case '{': if (!is_counted_repeat(ptr+1, cd)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr, cd); if (*errorptr != NULL) goto FAILED; goto REPEAT; case '*': repeat_min = 0; repeat_max = -1; goto REPEAT; case '+': repeat_min = 1; repeat_max = -1; goto REPEAT; case '?': repeat_min = 0; repeat_max = 1; REPEAT: if (previous == NULL) { *errorptr = ERR9; goto FAILED; } /* If the next character is '?' this is a minimizing repeat, by default, but if PCRE_UNGREEDY is set, it works the other way round. Advance to the next character. */ if (ptr[1] == '?') { repeat_type = greedy_non_default; ptr++; } else repeat_type = greedy_default; /* If previous was a string of characters, chop off the last one and use it as the subject of the repeat. If there was only one character, we can abolish the previous item altogether. A repeat with a zero minimum wipes out any reqchar setting, backing up to the previous value. We must also adjust the countlits value. */ if (*previous == OP_CHARS) { int len = previous[1]; if (repeat_min == 0) *reqchar = prevreqchar; *countlits += repeat_min - 1; if (len == 1) { c = previous[2]; code = previous; } else { c = previous[len+1]; previous[1]--; code--; } op_type = 0; /* Use single-char op codes */ goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ } /* If previous was a single negated character ([^a] or similar), we use one of the special opcodes, replacing it. The code is shared with single- character repeats by adding a suitable offset into repeat_type. */ else if ((int)*previous == OP_NOT) { op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ c = previous[1]; code = previous; goto OUTPUT_SINGLE_REPEAT; } /* If previous was a character type match (\d or similar), abolish it and create a suitable repeat item. The code is shared with single-character repeats by adding a suitable offset into repeat_type. */ else if ((int)*previous < OP_EODN || *previous == OP_ANY) { op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ c = *previous; code = previous; OUTPUT_SINGLE_REPEAT: /* If the maximum is zero then the minimum must also be zero; Perl allows this case, so we do too - by simply omitting the item altogether. */ if (repeat_max == 0) goto END_REPEAT; /* Combine the op_type with the repeat_type */ repeat_type += op_type; /* A minimum of zero is handled either as the special case * or ?, or as an UPTO, with the maximum given. */ if (repeat_min == 0) { if (repeat_max == -1) *code++ = OP_STAR + repeat_type; else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; else { *code++ = OP_UPTO + repeat_type; *code++ = repeat_max >> 8; *code++ = (repeat_max & 255); } } /* The case {1,} is handled as the special case + */ else if (repeat_min == 1 && repeat_max == -1) *code++ = OP_PLUS + repeat_type; /* The case {n,n} is just an EXACT, while the general case {n,m} is handled as an EXACT followed by an UPTO. An EXACT of 1 is optimized. */ else { if (repeat_min != 1) { *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ *code++ = repeat_min >> 8; *code++ = (repeat_min & 255); } /* If the mininum is 1 and the previous item was a character string, we either have to put back the item that got cancelled if the string length was 1, or add the character back onto the end of a longer string. For a character type nothing need be done; it will just get put back naturally. Note that the final character is always going to get added below. */ else if (*previous == OP_CHARS) { if (code == previous) code += 2; else previous[1]++; } /* For a single negated character we also have to put back the item that got cancelled. */ else if (*previous == OP_NOT) code++; /* If the maximum is unlimited, insert an OP_STAR. */ if (repeat_max < 0) { *code++ = c; *code++ = OP_STAR + repeat_type; } /* Else insert an UPTO if the max is greater than the min. */ else if (repeat_max != repeat_min) { *code++ = c; repeat_max -= repeat_min; *code++ = OP_UPTO + repeat_type; *code++ = repeat_max >> 8; *code++ = (repeat_max & 255); } } /* The character or character type itself comes last in all cases. */ *code++ = c; } /* If previous was a character class or a back reference, we put the repeat stuff after it, but just skip the item if the repeat was {0,0}. */ else if (*previous == OP_CLASS || *previous == OP_REF) { if (repeat_max == 0) { code = previous; goto END_REPEAT; } if (repeat_min == 0 && repeat_max == -1) *code++ = OP_CRSTAR + repeat_type; else if (repeat_min == 1 && repeat_max == -1) *code++ = OP_CRPLUS + repeat_type; else if (repeat_min == 0 && repeat_max == 1) *code++ = OP_CRQUERY + repeat_type; else { *code++ = OP_CRRANGE + repeat_type; *code++ = repeat_min >> 8; *code++ = repeat_min & 255; if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ *code++ = repeat_max >> 8; *code++ = repeat_max & 255; } } /* If previous was a bracket group, we may have to replicate it in certain cases. */ else if ((int)*previous >= OP_BRA || (int)*previous == OP_ONCE || (int)*previous == OP_COND) { register int i; int ketoffset = 0; int len = code - previous; uschar *bralink = NULL; /* If the maximum repeat count is unlimited, find the end of the bracket by scanning through from the start, and compute the offset back to it from the current code pointer. There may be an OP_OPT setting following the final KET, so we can't find the end just by going back from the code pointer. */ if (repeat_max == -1) { register uschar *ket = previous; do ket += (ket[1] << 8) + ket[2]; while (*ket != OP_KET); ketoffset = code - ket; } /* The case of a zero minimum is special because of the need to stick OP_BRAZERO in front of it, and because the group appears once in the data, whereas in other cases it appears the minimum number of times. For this reason, it is simplest to treat this case separately, as otherwise the code gets far too mess. There are several special subcases when the minimum is zero. */ if (repeat_min == 0) { /* If we set up a required char from the bracket, we must back off to the previous value and reset the countlits value too. */ if (subcountlits > 0) { *reqchar = prevreqchar; *countlits -= subcountlits; } /* If the maximum is also zero, we just omit the group from the output altogether. */ if (repeat_max == 0) { code = previous; goto END_REPEAT; } /* If the maximum is 1 or unlimited, we just have to stick in the BRAZERO and do no more at this point. */ if (repeat_max <= 1) { memmove(previous+1, previous, len); code++; *previous++ = OP_BRAZERO + repeat_type; } /* If the maximum is greater than 1 and limited, we have to replicate in a nested fashion, sticking OP_BRAZERO before each set of brackets. The first one has to be handled carefully because it's the original copy, which has to be moved up. The remainder can be handled by code that is common with the non-zero minimum case below. We just have to adjust the value or repeat_max, since one less copy is required. */ else { int offset; memmove(previous+4, previous, len); code += 4; *previous++ = OP_BRAZERO + repeat_type; *previous++ = OP_BRA; /* We chain together the bracket offset fields that have to be filled in later when the ends of the brackets are reached. */ offset = (bralink == NULL)? 0 : previous - bralink; bralink = previous; *previous++ = offset >> 8; *previous++ = offset & 255; } repeat_max--; } /* If the minimum is greater than zero, replicate the group as many times as necessary, and adjust the maximum to the number of subsequent copies that we need. */ else { for (i = 1; i < repeat_min; i++) { memcpy(code, previous, len); code += len; } if (repeat_max > 0) repeat_max -= repeat_min; } /* This code is common to both the zero and non-zero minimum cases. If the maximum is limited, it replicates the group in a nested fashion, remembering the bracket starts on a stack. In the case of a zero minimum, the first one was set up above. In all cases the repeat_max now specifies the number of additional copies needed. */ if (repeat_max >= 0) { for (i = repeat_max - 1; i >= 0; i--) { *code++ = OP_BRAZERO + repeat_type; /* All but the final copy start a new nesting, maintaining the chain of brackets outstanding. */ if (i != 0) { int offset; *code++ = OP_BRA; offset = (bralink == NULL)? 0 : code - bralink; bralink = code; *code++ = offset >> 8; *code++ = offset & 255; } memcpy(code, previous, len); code += len; } /* Now chain through the pending brackets, and fill in their length fields (which are holding the chain links pro tem). */ while (bralink != NULL) { int oldlinkoffset; int offset = code - bralink + 1; uschar *bra = code - offset; oldlinkoffset = (bra[1] << 8) + bra[2]; bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; *code++ = OP_KET; *code++ = bra[1] = offset >> 8; *code++ = bra[2] = (offset & 255); } } /* If the maximum is unlimited, set a repeater in the final copy. We can't just offset backwards from the current code point, because we don't know if there's been an options resetting after the ket. The correct offset was computed above. */ else code[-ketoffset] = OP_KETRMAX + repeat_type; } /* Else there's some kind of shambles */ else { *errorptr = ERR11; goto FAILED; } /* In all case we no longer have a previous item. */ END_REPEAT: previous = NULL; break; /* Start of nested bracket sub-expression, or comment or lookahead or lookbehind or option setting or condition. First deal with special things that can come after a bracket; all are introduced by ?, and the appearance of any of them means that this is not a referencing group. They were checked for validity in the first pass over the string, so we don't have to check for syntax errors here. */ case '(': newoptions = options; condref = -1; if (*(++ptr) == '?') { int set, unset; int *optset; switch (*(++ptr)) { case '#': /* Comment; skip to ket */ ptr++; while (*ptr != ')') ptr++; continue; case ':': /* Non-extracting bracket */ bravalue = OP_BRA; ptr++; break; case '(': bravalue = OP_COND; /* Conditional group */ if ((cd->ctypes[*(++ptr)] & ctype_digit) != 0) { condref = *ptr - '0'; while (*(++ptr) != ')') condref = condref*10 + *ptr - '0'; if (condref == 0) { *errorptr = ERR35; goto FAILED; } ptr++; } else ptr--; break; case '=': /* Positive lookahead */ bravalue = OP_ASSERT; ptr++; break; case '!': /* Negative lookahead */ bravalue = OP_ASSERT_NOT; ptr++; break; case '<': /* Lookbehinds */ switch (*(++ptr)) { case '=': /* Positive lookbehind */ bravalue = OP_ASSERTBACK; ptr++; break; case '!': /* Negative lookbehind */ bravalue = OP_ASSERTBACK_NOT; ptr++; break; default: /* Syntax error */ *errorptr = ERR24; goto FAILED; } break; case '>': /* One-time brackets */ bravalue = OP_ONCE; ptr++; break; case 'R': /* Pattern recursion */ *code++ = OP_RECURSE; ptr++; continue; default: /* Option setting */ set = unset = 0; optset = &set; while (*ptr != ')' && *ptr != ':') { switch (*ptr++) { case '-': optset = &unset; break; case 'i': *optset |= PCRE_CASELESS; break; case 'm': *optset |= PCRE_MULTILINE; break; case 's': *optset |= PCRE_DOTALL; break; case 'x': *optset |= PCRE_EXTENDED; break; case 'U': *optset |= PCRE_UNGREEDY; break; case 'X': *optset |= PCRE_EXTRA; break; default: *errorptr = ERR12; goto FAILED; } } /* Set up the changed option bits, but don't change anything yet. */ newoptions = (options | set) & (~unset); /* If the options ended with ')' this is not the start of a nested group with option changes, so the options change at this level. At top level there is nothing else to be done (the options will in fact have been set from the start of compiling as a result of the first pass) but at an inner level we must compile code to change the ims options if necessary, and pass the new setting back so that it can be put at the start of any following branches, and when this group ends, a resetting item can be compiled. */ if (*ptr == ')') { if ((options & PCRE_INGROUP) != 0 && (options & PCRE_IMS) != (newoptions & PCRE_IMS)) { *code++ = OP_OPT; *code++ = *optchanged = newoptions & PCRE_IMS; } options = newoptions; /* Change options at this level */ previous = NULL; /* This item can't be repeated */ continue; /* It is complete */ } /* If the options ended with ':' we are heading into a nested group with possible change of options. Such groups are non-capturing and are not assertions of any kind. All we need to do is skip over the ':'; the newoptions value is handled below. */ bravalue = OP_BRA; ptr++; } } /* Else we have a referencing group; adjust the opcode. */ else { if (++(*brackets) > EXTRACT_MAX) { *errorptr = ERR13; goto FAILED; } bravalue = OP_BRA + *brackets; } /* Process nested bracketed re. Assertions may not be repeated, but other kinds can be. We copy code into a non-register variable in order to be able to pass its address because some compilers complain otherwise. Pass in a new setting for the ims options if they have changed. */ previous = (bravalue >= OP_ONCE)? code : NULL; *code = bravalue; tempcode = code; if (!compile_regex( options | PCRE_INGROUP, /* Set for all nested groups */ ((options & PCRE_IMS) != (newoptions & PCRE_IMS))? newoptions & PCRE_IMS : -1, /* Pass ims options if changed */ brackets, /* Bracket level */ &tempcode, /* Where to put code (updated) */ &ptr, /* Input pointer (updated) */ errorptr, /* Where to put an error message */ (bravalue == OP_ASSERTBACK || bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ condref, /* Condition reference number */ &subreqchar, /* For possible last char */ &subcountlits, /* For literal count */ cd)) /* Tables block */ goto FAILED; /* At the end of compiling, code is still pointing to the start of the group, while tempcode has been updated to point past the end of the group and any option resetting that may follow it. The pattern pointer (ptr) is on the bracket. */ /* If this is a conditional bracket, check that there are no more than two branches in the group. */ if (bravalue == OP_COND) { uschar *tc = code; condcount = 0; do { condcount++; tc += (tc[1] << 8) | tc[2]; } while (*tc != OP_KET); if (condcount > 2) { *errorptr = ERR27; goto FAILED; } } /* Handle updating of the required character. If the subpattern didn't set one, leave it as it was. Otherwise, update it for normal brackets of all kinds, forward assertions, and conditions with two branches. Don't update the literal count for forward assertions, however. If the bracket is followed by a quantifier with zero repeat, we have to back off. Hence the definition of prevreqchar and subcountlits outside the main loop so that they can be accessed for the back off. */ if (subreqchar > 0 && (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_ASSERT || (bravalue == OP_COND && condcount == 2))) { prevreqchar = *reqchar; *reqchar = subreqchar; if (bravalue != OP_ASSERT) *countlits += subcountlits; } /* Now update the main code pointer to the end of the group. */ code = tempcode; /* Error if hit end of pattern */ if (*ptr != ')') { *errorptr = ERR14; goto FAILED; } break; /* Check \ for being a real metacharacter; if not, fall through and handle it as a data character at the start of a string. Escape items are checked for validity in the pre-compiling pass. */ case '\\': tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values are arranged to be the negation of the corresponding OP_values. For the back references, the values are ESC_REF plus the reference number. Only back references and those types that consume a character may be repeated. We can test for values between ESC_b and ESC_Z for the latter; this may have to change if any new ones are ever created. */ if (c < 0) { if (-c >= ESC_REF) { previous = code; *code++ = OP_REF; *code++ = -c - ESC_REF; } else { previous = (-c > ESC_b && -c < ESC_Z)? code : NULL; *code++ = -c; } continue; } /* Data character: reset and fall through */ ptr = tempptr; c = '\\'; /* Handle a run of data characters until a metacharacter is encountered. The first character is guaranteed not to be whitespace or # when the extended flag is set. */ NORMAL_CHAR: default: previous = code; *code = OP_CHARS; code += 2; length = 0; do { if ((options & PCRE_EXTENDED) != 0) { if ((cd->ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != '\n') ; if (c == 0) break; continue; } } /* Backslash may introduce a data char or a metacharacter. Escaped items are checked for validity in the pre-compiling pass. Stop the string before a metaitem. */ if (c == '\\') { tempptr = ptr; c = check_escape(&ptr, errorptr, *brackets, options, FALSE, cd); if (c < 0) { ptr = tempptr; break; } /* If a character is > 127 in UTF-8 mode, we have to turn it into two or more characters in the UTF-8 encoding. */ #ifdef SUPPORT_UTF8 if (c > 127 && (options & PCRE_UTF8) != 0) { uschar buffer[8]; int len = ord2utf8(c, buffer); for (c = 0; c < len; c++) *code++ = buffer[c]; length += len; continue; } #endif } /* Ordinary character or single-char escape */ *code++ = c; length++; } /* This "while" is the end of the "do" above. */ while (length < MAXLIT && (cd->ctypes[c = *(++ptr)] & ctype_meta) == 0); /* Update the last character and the count of literals */ prevreqchar = (length > 1)? code[-2] : *reqchar; *reqchar = code[-1]; *countlits += length; /* Compute the length and set it in the data vector, and advance to the next state. */ previous[1] = length; if (length < MAXLIT) ptr--; break; } } /* end of big loop */ /* Control never reaches here by falling through, only by a goto for all the error states. Pass back the position in the pattern so that it can be displayed to the user for diagnosing the error. */ FAILED: *ptrptr = ptr; return FALSE; } /************************************************* * Compile sequence of alternatives * *************************************************/ /* On entry, ptr is pointing past the bracket character, but on return it points to the closing bracket, or vertical bar, or end of string. The code variable is pointing at the byte into which the BRA operator has been stored. If the ims options are changed at the start (for a (?ims: group) or during any branch, we need to insert an OP_OPT item at the start of every following branch to ensure they get set correctly at run time, and also pass the new options into every subsequent branch compile. Argument: options the option bits optchanged new ims options to set as if (?ims) were at the start, or -1 for no change brackets -> int containing the number of extracting brackets used codeptr -> the address of the current code pointer ptrptr -> the address of the current pattern pointer errorptr -> pointer to error message lookbehind TRUE if this is a lookbehind assertion condref >= 0 for OPT_CREF setting at start of conditional group reqchar -> place to put the last required character, or a negative number countlits -> place to put the shortest literal count of any branch cd points to the data block with tables pointers Returns: TRUE on success */ static BOOL compile_regex(int options, int optchanged, int *brackets, uschar **codeptr, const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int condref, int *reqchar, int *countlits, compile_data *cd) { const uschar *ptr = *ptrptr; uschar *code = *codeptr; uschar *last_branch = code; uschar *start_bracket = code; uschar *reverse_count = NULL; int oldoptions = options & PCRE_IMS; int branchreqchar, branchcountlits; *reqchar = -1; *countlits = INT_MAX; code += 3; /* At the start of a reference-based conditional group, insert the reference number as an OP_CREF item. */ if (condref >= 0) { *code++ = OP_CREF; *code++ = condref; } /* Loop for each alternative branch */ for (;;) { int length; /* Handle change of options */ if (optchanged >= 0) { *code++ = OP_OPT; *code++ = optchanged; options = (options & ~PCRE_IMS) | optchanged; } /* Set up dummy OP_REVERSE if lookbehind assertion */ if (lookbehind) { *code++ = OP_REVERSE; reverse_count = code; *code++ = 0; *code++ = 0; } /* Now compile the branch */ if (!compile_branch(options, brackets, &code, &ptr, errorptr, &optchanged, &branchreqchar, &branchcountlits, cd)) { *ptrptr = ptr; return FALSE; } /* Fill in the length of the last branch */ length = code - last_branch; last_branch[1] = length >> 8; last_branch[2] = length & 255; /* Save the last required character if all branches have the same; a current value of -1 means unset, while -2 means "previous branch had no last required char". */ if (*reqchar != -2) { if (branchreqchar >= 0) { if (*reqchar == -1) *reqchar = branchreqchar; else if (*reqchar != branchreqchar) *reqchar = -2; } else *reqchar = -2; } /* Keep the shortest literal count */ if (branchcountlits < *countlits) *countlits = branchcountlits; DPRINTF(("literal count = %d min=%d\n", branchcountlits, *countlits)); /* If lookbehind, check that this branch matches a fixed-length string, and put the length into the OP_REVERSE item. Temporarily mark the end of the branch with OP_END. */ if (lookbehind) { *code = OP_END; length = find_fixedlength(last_branch, options); DPRINTF(("fixed length = %d\n", length)); if (length < 0) { *errorptr = ERR25; *ptrptr = ptr; return FALSE; } reverse_count[0] = (length >> 8); reverse_count[1] = length & 255; } /* Reached end of expression, either ')' or end of pattern. Insert a terminating ket and the length of the whole bracketed item, and return, leaving the pointer at the terminating char. If any of the ims options were changed inside the group, compile a resetting op-code following. */ if (*ptr != '|') { length = code - start_bracket; *code++ = OP_KET; *code++ = length >> 8; *code++ = length & 255; if (optchanged >= 0) { *code++ = OP_OPT; *code++ = oldoptions; } *codeptr = code; *ptrptr = ptr; return TRUE; } /* Another branch follows; insert an "or" node and advance the pointer. */ *code = OP_ALT; last_branch = code; code += 3; ptr++; } /* Control never reaches here */ } /************************************************* * Find first significant op code * *************************************************/ /* This is called by several functions that scan a compiled expression looking for a fixed first character, or an anchoring op code etc. It skips over things that do not influence this. For one application, a change of caseless option is important. Arguments: code pointer to the start of the group options pointer to external options optbit the option bit whose changing is significant, or zero if none are optstop TRUE to return on option change, otherwise change the options value and continue Returns: pointer to the first significant opcode */ static const uschar* first_significant_code(const uschar *code, int *options, int optbit, BOOL optstop) { for (;;) { switch ((int)*code) { case OP_OPT: if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit)) { if (optstop) return code; *options = (int)code[1]; } code += 2; break; case OP_CREF: code += 2; break; case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: code++; break; case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do code += (code[1] << 8) + code[2]; while (*code == OP_ALT); code += 3; break; default: return code; } } /* Control never reaches here */ } /************************************************* * Check for anchored expression * *************************************************/ /* Try to find out if this is an anchored regular expression. Consider each alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then it's anchored. However, if this is a multiline pattern, then only OP_SOD counts, since OP_CIRC can match in the middle. A branch is also implicitly anchored if it starts with .* and DOTALL is set, because that will try the rest of the pattern at all possible matching points, so there is no point trying them again. Arguments: code points to start of expression (the bracket) options points to the options setting Returns: TRUE or FALSE */ static BOOL is_anchored(register const uschar *code, int *options) { do { const uschar *scode = first_significant_code(code + 3, options, PCRE_MULTILINE, FALSE); register int op = *scode; if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_anchored(scode, options)) return FALSE; } else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) && (*options & PCRE_DOTALL) != 0) { if (scode[1] != OP_ANY) return FALSE; } else if (op != OP_SOD && ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC)) return FALSE; code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return TRUE; } /************************************************* * Check for starting with ^ or .* * *************************************************/ /* This is called to find out if every branch starts with ^ or .* so that "first char" processing can be done to speed things up in multiline matching and for non-DOTALL patterns that start with .* (which must start at the beginning or after \n). Argument: points to start of expression (the bracket) Returns: TRUE or FALSE */ static BOOL is_startline(const uschar *code) { do { const uschar *scode = first_significant_code(code + 3, NULL, 0, FALSE); register int op = *scode; if (op >= OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND) { if (!is_startline(scode)) return FALSE; } else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) { if (scode[1] != OP_ANY) return FALSE; } else if (op != OP_CIRC) return FALSE; code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return TRUE; } /************************************************* * Check for fixed first char * *************************************************/ /* Try to find out if there is a fixed first character. This is called for unanchored expressions, as it speeds up their processing quite considerably. Consider each alternative branch. If they all start with the same char, or with a bracket all of whose alternatives start with the same char (recurse ad lib), then we return that char, otherwise -1. Arguments: code points to start of expression (the bracket) options pointer to the options (used to check casing changes) Returns: -1 or the fixed first char */ static int find_firstchar(const uschar *code, int *options) { register int c = -1; do { int d; const uschar *scode = first_significant_code(code + 3, options, PCRE_CASELESS, TRUE); register int op = *scode; if (op >= OP_BRA) op = OP_BRA; switch(op) { default: return -1; case OP_BRA: case OP_ASSERT: case OP_ONCE: case OP_COND: if ((d = find_firstchar(scode, options)) < 0) return -1; if (c < 0) c = d; else if (c != d) return -1; break; case OP_EXACT: /* Fall through */ scode++; case OP_CHARS: /* Fall through */ scode++; case OP_PLUS: case OP_MINPLUS: if (c < 0) c = scode[1]; else if (c != scode[1]) return -1; break; } code += (code[1] << 8) + code[2]; } while (*code == OP_ALT); return c; } /************************************************* * Compile a Regular Expression * *************************************************/ /* This function takes a string and returns a pointer to a block of store holding a compiled version of the expression. Arguments: pattern the regular expression options various option bits errorptr pointer to pointer to error text erroroffset ptr offset in pattern where error was detected tables pointer to character tables or NULL Returns: pointer to compiled data block, or NULL on error, with errorptr and erroroffset set */ pcre * pcre_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) { real_pcre *re; int length = 3; /* For initial BRA plus length */ int runlength; int c, reqchar, countlits; int bracount = 0; int top_backref = 0; int branch_extra = 0; int branch_newextra; unsigned int brastackptr = 0; size_t size; uschar *code; const uschar *ptr; compile_data compile_block; int brastack[BRASTACK_SIZE]; uschar bralenstack[BRASTACK_SIZE]; #ifdef DEBUG uschar *code_base, *code_end; #endif /* Can't support UTF8 unless PCRE has been compiled to include the code. */ #ifndef SUPPORT_UTF8 if ((options & PCRE_UTF8) != 0) { *errorptr = ERR32; return NULL; } #endif /* We can't pass back an error message if errorptr is NULL; I guess the best we can do is just return NULL. */ if (errorptr == NULL) return NULL; *errorptr = NULL; /* However, we can give a message for this error */ if (erroroffset == NULL) { *errorptr = ERR16; return NULL; } *erroroffset = 0; if ((options & ~PUBLIC_OPTIONS) != 0) { *errorptr = ERR17; return NULL; } /* Set up pointers to the individual character tables */ if (tables == NULL) tables = pcre_default_tables; compile_block.lcc = tables + lcc_offset; compile_block.fcc = tables + fcc_offset; compile_block.cbits = tables + cbits_offset; compile_block.ctypes = tables + ctypes_offset; /* Reflect pattern for debugging output */ DPRINTF(("------------------------------------------------------------------\n")); DPRINTF(("%s\n", pattern)); /* The first thing to do is to make a pass over the pattern to compute the amount of store required to hold the compiled code. This does not have to be perfect as long as errors are overestimates. At the same time we can detect any internal flag settings. Make an attempt to correct for any counted white space if an "extended" flag setting appears late in the pattern. We can't be so clever for #-comments. */ ptr = (const uschar *)(pattern - 1); while ((c = *(++ptr)) != 0) { int min, max; int class_charcount; if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != '\n') ; continue; } } switch(c) { /* A backslashed item may be an escaped "normal" character or a character type. For a "normal" character, put the pointers and character back so that tests for whitespace etc. in the input are done correctly. */ case '\\': { const uschar *save_ptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c >= 0) { ptr = save_ptr; c = '\\'; goto NORMAL_CHAR; } } length++; /* A back reference needs an additional char, plus either one or 5 bytes for a repeat. We also need to keep the value of the highest back reference. */ if (c <= -ESC_REF) { int refnum = -c - ESC_REF; if (refnum > top_backref) top_backref = refnum; length++; /* For single back reference */ if (ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '?') ptr++; } } continue; case '^': case '.': case '$': case '*': /* These repeats won't be after brackets; */ case '+': /* those are handled separately */ case '?': length++; continue; /* This covers the cases of repeats after a single char, metachar, class, or back reference. */ case '{': if (!is_counted_repeat(ptr+1, &compile_block)) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else { length--; /* Uncount the original char or metachar */ if (min == 1) length++; else if (min > 0) length += 4; if (max > 0) length += 4; else length += 2; } if (ptr[1] == '?') ptr++; continue; /* An alternation contains an offset to the next branch or ket. If any ims options changed in the previous branch(es), and/or if we are in a lookbehind assertion, extra space will be needed at the start of the branch. This is handled by branch_extra. */ case '|': length += 3 + branch_extra; continue; /* A character class uses 33 characters. Don't worry about character types that aren't allowed in classes - they'll get picked up during the compile. A character class that contains only one character uses 2 or 3 bytes, depending on whether it is negated or not. Notice this where we can. */ case '[': class_charcount = 0; if (*(++ptr) == '^') ptr++; do { if (*ptr == '\\') { int ch = check_escape(&ptr, errorptr, bracount, options, TRUE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (-ch == ESC_b) class_charcount++; else class_charcount = 10; } else class_charcount++; ptr++; } while (*ptr != 0 && *ptr != ']'); /* Repeats for negated single chars are handled by the general code */ if (class_charcount == 1) length += 3; else { length += 33; /* A repeat needs either 1 or 5 bytes. */ if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &min, &max, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if ((min == 0 && (max == 1 || max == -1)) || (min == 1 && max == -1)) length++; else length += 5; if (ptr[1] == '?') ptr++; } } continue; /* Brackets may be genuine groups or special things */ case '(': branch_newextra = 0; /* Handle special forms of bracket, which all start (? */ if (ptr[1] == '?') { int set, unset; int *optset; switch (c = ptr[2]) { /* Skip over comments entirely */ case '#': ptr += 3; while (*ptr != 0 && *ptr != ')') ptr++; if (*ptr == 0) { *errorptr = ERR18; goto PCRE_ERROR_RETURN; } continue; /* Non-referencing groups and lookaheads just move the pointer on, and then behave like a non-special bracket, except that they don't increment the count of extracting brackets. Ditto for the "once only" bracket, which is in Perl from version 5.005. */ case ':': case '=': case '!': case '>': ptr += 2; break; /* A recursive call to the regex is an extension, to provide the facility which can be obtained by $(?p{perl-code}) in Perl 5.6. */ case 'R': if (ptr[3] != ')') { *errorptr = ERR29; goto PCRE_ERROR_RETURN; } ptr += 3; length += 1; break; /* Lookbehinds are in Perl from version 5.005 */ case '<': if (ptr[3] == '=' || ptr[3] == '!') { ptr += 3; branch_newextra = 3; length += 3; /* For the first branch */ break; } *errorptr = ERR24; goto PCRE_ERROR_RETURN; /* Conditionals are in Perl from version 5.005. The bracket must either be followed by a number (for bracket reference) or by an assertion group. */ case '(': if ((compile_block.ctypes[ptr[3]] & ctype_digit) != 0) { ptr += 4; length += 2; while ((compile_block.ctypes[*ptr] & ctype_digit) != 0) ptr++; if (*ptr != ')') { *errorptr = ERR26; goto PCRE_ERROR_RETURN; } } else /* An assertion must follow */ { ptr++; /* Can treat like ':' as far as spacing is concerned */ if (ptr[2] != '?' || (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') ) { ptr += 2; /* To get right offset in message */ *errorptr = ERR28; goto PCRE_ERROR_RETURN; } } break; /* Else loop checking valid options until ) is met. Anything else is an error. If we are without any brackets, i.e. at top level, the settings act as if specified in the options, so massage the options immediately. This is for backward compatibility with Perl 5.004. */ default: set = unset = 0; optset = &set; ptr += 2; for (;; ptr++) { c = *ptr; switch (c) { case 'i': *optset |= PCRE_CASELESS; continue; case 'm': *optset |= PCRE_MULTILINE; continue; case 's': *optset |= PCRE_DOTALL; continue; case 'x': *optset |= PCRE_EXTENDED; continue; case 'X': *optset |= PCRE_EXTRA; continue; case 'U': *optset |= PCRE_UNGREEDY; continue; case '-': optset = &unset; continue; /* A termination by ')' indicates an options-setting-only item; this is global at top level; otherwise nothing is done here and it is handled during the compiling process on a per-bracket-group basis. */ case ')': if (brastackptr == 0) { options = (options | set) & (~unset); set = unset = 0; /* To save length */ } /* Fall through */ /* A termination by ':' indicates the start of a nested group with the given options set. This is again handled at compile time, but we must allow for compiled space if any of the ims options are set. We also have to allow for resetting space at the end of the group, which is why 4 is added to the length and not just 2. If there are several changes of options within the same group, this will lead to an over-estimate on the length, but this shouldn't matter very much. We also have to allow for resetting options at the start of any alternations, which we do by setting branch_newextra to 2. Finally, we record whether the case-dependent flag ever changes within the regex. This is used by the "required character" code. */ case ':': if (((set|unset) & PCRE_IMS) != 0) { length += 4; branch_newextra = 2; if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED; } goto END_OPTIONS; /* Unrecognized option character */ default: *errorptr = ERR12; goto PCRE_ERROR_RETURN; } } /* If we hit a closing bracket, that's it - this is a freestanding option-setting. We need to ensure that branch_extra is updated if necessary. The only values branch_newextra can have here are 0 or 2. If the value is 2, then branch_extra must either be 2 or 5, depending on whether this is a lookbehind group or not. */ END_OPTIONS: if (c == ')') { if (branch_newextra == 2 && (branch_extra == 0 || branch_extra == 3)) branch_extra += branch_newextra; continue; } /* If options were terminated by ':' control comes here. Fall through to handle the group below. */ } } /* Extracting brackets must be counted so we can process escapes in a Perlish way. */ else bracount++; /* Non-special forms of bracket. Save length for computing whole length at end if there's a repeat that requires duplication of the group. Also save the current value of branch_extra, and start the new group with the new value. If non-zero, this will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ if (brastackptr >= sizeof(brastack)/sizeof(int)) { *errorptr = ERR19; goto PCRE_ERROR_RETURN; } bralenstack[brastackptr] = branch_extra; branch_extra = branch_newextra; brastack[brastackptr++] = length; length += 3; continue; /* Handle ket. Look for subsequent max/min; for certain sets of values we have to replicate this bracket up to that many times. If brastackptr is 0 this is an unmatched bracket which will generate an error, but take care not to try to access brastack[-1] when computing the length and restoring the branch_extra value. */ case ')': length += 3; { int minval = 1; int maxval = 1; int duplength; if (brastackptr > 0) { duplength = length - brastack[--brastackptr]; branch_extra = bralenstack[brastackptr]; } else duplength = 0; /* Leave ptr at the final char; for read_repeat_counts this happens automatically; for the others we need an increment. */ if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2, &compile_block)) { ptr = read_repeat_counts(ptr+2, &minval, &maxval, errorptr, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; } else if (c == '*') { minval = 0; maxval = -1; ptr++; } else if (c == '+') { maxval = -1; ptr++; } else if (c == '?') { minval = 0; ptr++; } /* If the minimum is zero, we have to allow for an OP_BRAZERO before the group, and if the maximum is greater than zero, we have to replicate maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting bracket set - hence the 7. */ if (minval == 0) { length++; if (maxval > 0) length += (maxval - 1) * (duplength + 7); } /* When the minimum is greater than zero, 1 we have to replicate up to minval-1 times, with no additions required in the copies. Then, if there is a limited maximum we have to replicate up to maxval-1 times allowing for a BRAZERO item before each optional copy and nesting brackets for all but one of the optional copies. */ else { length += (minval - 1) * duplength; if (maxval > minval) /* Need this test as maxval=-1 means no limit */ length += (maxval - minval) * (duplength + 7) - 6; } } continue; /* Non-special character. For a run of such characters the length required is the number of characters + 2, except that the maximum run length is 255. We won't get a skipped space or a non-data escape or the start of a # comment as the first character, so the length can't be zero. */ NORMAL_CHAR: default: length += 2; runlength = 0; do { if ((options & PCRE_EXTENDED) != 0) { if ((compile_block.ctypes[c] & ctype_space) != 0) continue; if (c == '#') { /* The space before the ; is to avoid a warning on a silly compiler on the Macintosh. */ while ((c = *(++ptr)) != 0 && c != '\n') ; continue; } } /* Backslash may introduce a data char or a metacharacter; stop the string before the latter. */ if (c == '\\') { const uschar *saveptr = ptr; c = check_escape(&ptr, errorptr, bracount, options, FALSE, &compile_block); if (*errorptr != NULL) goto PCRE_ERROR_RETURN; if (c < 0) { ptr = saveptr; break; } #ifdef SUPPORT_UTF8 if (c > 127 && (options & PCRE_UTF8) != 0) { int i; for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) if (c <= utf8_table1[i]) break; runlength += i; } #endif } /* Ordinary character or single-char escape */ runlength++; } /* This "while" is the end of the "do" above. */ while (runlength < MAXLIT && (compile_block.ctypes[c = *(++ptr)] & ctype_meta) == 0); ptr--; length += runlength; continue; } } length += 4; /* For final KET and END */ if (length > 65539) { *errorptr = ERR20; return NULL; } /* Compute the size of data block needed and get it, either from malloc or externally provided function. We specify "code[0]" in the offsetof() expression rather than just "code", because it has been reported that one broken compiler fails on "code" because it is also an independent variable. It should make no difference to the value of the offsetof(). */ size = length + offsetof(real_pcre, code[0]); re = (real_pcre *)(pcre_malloc)(size); if (re == NULL) { *errorptr = ERR21; return NULL; } /* Put in the magic number, and save the size, options, and table pointer */ re->magic_number = MAGIC_NUMBER; re->size = size; re->options = options; re->tables = tables; /* Set up a starting, non-extracting bracket, then compile the expression. On error, *errorptr will be set non-NULL, so we don't need to look at the result of the function here. */ ptr = (const uschar *)pattern; code = re->code; *code = OP_BRA; bracount = 0; (void)compile_regex(options, -1, &bracount, &code, &ptr, errorptr, FALSE, -1, &reqchar, &countlits, &compile_block); re->top_bracket = bracount; re->top_backref = top_backref; /* If not reached end of pattern on success, there's an excess bracket. */ if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22; /* Fill in the terminating state and check for disastrous overflow, but if debugging, leave the test till after things are printed out. */ *code++ = OP_END; #ifndef DEBUG if (code - re->code > length) *errorptr = ERR23; #endif /* Give an error if there's back reference to a non-existent capturing subpattern. */ if (top_backref > re->top_bracket) *errorptr = ERR15; /* Failed to compile */ if (*errorptr != NULL) { (pcre_free)(re); PCRE_ERROR_RETURN: *erroroffset = ptr - (const uschar *)pattern; return NULL; } /* If the anchored option was not passed, set flag if we can determine that the pattern is anchored by virtue of ^ characters or \A or anything else (such as starting with .* when DOTALL is set). Otherwise, see if we can determine what the first character has to be, because that speeds up unanchored matches no end. If not, see if we can set the PCRE_STARTLINE flag. This is helpful for multiline matches when all branches start with ^. and also when all branches start with .* for non-DOTALL matches. */ if ((options & PCRE_ANCHORED) == 0) { int temp_options = options; if (is_anchored(re->code, &temp_options)) re->options |= PCRE_ANCHORED; else { int ch = find_firstchar(re->code, &temp_options); if (ch >= 0) { re->first_char = ch; re->options |= PCRE_FIRSTSET; } else if (is_startline(re->code)) re->options |= PCRE_STARTLINE; } } /* Save the last required character if there are at least two literal characters on all paths, or if there is no first character setting. */ if (reqchar >= 0 && (countlits > 1 || (re->options & PCRE_FIRSTSET) == 0)) { re->req_char = reqchar; re->options |= PCRE_REQCHSET; } /* Print out the compiled data for debugging */ #ifdef DEBUG printf("Length = %d top_bracket = %d top_backref = %d\n", length, re->top_bracket, re->top_backref); if (re->options != 0) { printf("%s%s%s%s%s%s%s%s%s\n", ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "", ((re->options & PCRE_CASELESS) != 0)? "caseless " : "", ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "", ((re->options & PCRE_EXTENDED) != 0)? "extended " : "", ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "", ((re->options & PCRE_DOTALL) != 0)? "dotall " : "", ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "", ((re->options & PCRE_EXTRA) != 0)? "extra " : "", ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : ""); } if ((re->options & PCRE_FIRSTSET) != 0) { if (isprint(re->first_char)) printf("First char = %c\n", re->first_char); else printf("First char = \\x%02x\n", re->first_char); } if ((re->options & PCRE_REQCHSET) != 0) { if (isprint(re->req_char)) printf("Req char = %c\n", re->req_char); else printf("Req char = \\x%02x\n", re->req_char); } code_end = code; code_base = code = re->code; while (code < code_end) { int charlength; printf("%3d ", code - code_base); if (*code >= OP_BRA) { printf("%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA); code += 2; } else switch(*code) { case OP_OPT: printf(" %.2x %s", code[1], OP_names[*code]); code++; break; case OP_COND: printf("%3d Cond", (code[1] << 8) + code[2]); code += 2; break; case OP_CREF: printf(" %.2d %s", code[1], OP_names[*code]); code++; break; case OP_CHARS: charlength = *(++code); printf("%3d ", charlength); while (charlength-- > 0) if (isprint(c = *(++code))) printf("%c", c); else printf("\\x%02x", c); break; case OP_KETRMAX: case OP_KETRMIN: case OP_ALT: case OP_KET: case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]); code += 2; break; case OP_REVERSE: printf("%3d %s", (code[1] << 8) + code[2], OP_names[*code]); code += 2; break; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: if (*code >= OP_TYPESTAR) printf(" %s", OP_names[code[1]]); else if (isprint(c = code[1])) printf(" %c", c); else printf(" \\x%02x", c); printf("%s", OP_names[*code++]); break; case OP_EXACT: case OP_UPTO: case OP_MINUPTO: if (isprint(c = code[3])) printf(" %c{", c); else printf(" \\x%02x{", c); if (*code != OP_EXACT) printf("0,"); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_MINUPTO) printf("?"); code += 3; break; case OP_TYPEEXACT: case OP_TYPEUPTO: case OP_TYPEMINUPTO: printf(" %s{", OP_names[code[3]]); if (*code != OP_TYPEEXACT) printf(","); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_TYPEMINUPTO) printf("?"); code += 3; break; case OP_NOT: if (isprint(c = *(++code))) printf(" [^%c]", c); else printf(" [^\\x%02x]", c); break; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: if (isprint(c = code[1])) printf(" [^%c]", c); else printf(" [^\\x%02x]", c); printf("%s", OP_names[*code++]); break; case OP_NOTEXACT: case OP_NOTUPTO: case OP_NOTMINUPTO: if (isprint(c = code[3])) printf(" [^%c]{", c); else printf(" [^\\x%02x]{", c); if (*code != OP_NOTEXACT) printf(","); printf("%d}", (code[1] << 8) + code[2]); if (*code == OP_NOTMINUPTO) printf("?"); code += 3; break; case OP_REF: printf(" \\%d", *(++code)); code ++; goto CLASS_REF_REPEAT; case OP_CLASS: { int i, min, max; code++; printf(" ["); for (i = 0; i < 256; i++) { if ((code[i/8] & (1 << (i&7))) != 0) { int j; for (j = i+1; j < 256; j++) if ((code[j/8] & (1 << (j&7))) == 0) break; if (i == '-' || i == ']') printf("\\"); if (isprint(i)) printf("%c", i); else printf("\\x%02x", i); if (--j > i) { printf("-"); if (j == '-' || j == ']') printf("\\"); if (isprint(j)) printf("%c", j); else printf("\\x%02x", j); } i = j; } } printf("]"); code += 32; CLASS_REF_REPEAT: switch(*code) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: printf("%s", OP_names[*code]); break; case OP_CRRANGE: case OP_CRMINRANGE: min = (code[1] << 8) + code[2]; max = (code[3] << 8) + code[4]; if (max == 0) printf("{%d,}", min); else printf("{%d,%d}", min, max); if (*code == OP_CRMINRANGE) printf("?"); code += 4; break; default: code--; } } break; /* Anything else is just a one-node item */ default: printf(" %s", OP_names[*code]); break; } code++; printf("\n"); } printf("------------------------------------------------------------------\n"); /* This check is done here in the debugging case so that the code that was compiled can be seen. */ if (code - re->code > length) { *errorptr = ERR23; (pcre_free)(re); *erroroffset = ptr - (uschar *)pattern; return NULL; } #endif return (pcre *)re; } /************************************************* * Match a back-reference * *************************************************/ /* If a back reference hasn't been set, the length that is passed is greater than the number of characters left in the string, so the match fails. Arguments: offset index into the offset vector eptr points into the subject length length to be matched md points to match data block ims the ims flags Returns: TRUE if matched */ static BOOL match_ref(int offset, register const uschar *eptr, int length, match_data *md, unsigned long int ims) { const uschar *p = md->start_subject + md->offset_vector[offset]; #ifdef DEBUG if (eptr >= md->end_subject) printf("matching subject "); else { printf("matching subject "); pchars(eptr, length, TRUE, md); } printf(" against backref "); pchars(p, length, FALSE, md); printf("\n"); #endif /* Always fail if not enough characters left */ if (length > md->end_subject - eptr) return FALSE; /* Separate the caselesss case for speed */ if ((ims & PCRE_CASELESS) != 0) { while (length-- > 0) if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE; } else { while (length-- > 0) if (*p++ != *eptr++) return FALSE; } return TRUE; } /************************************************* * Match from current position * *************************************************/ /* On entry ecode points to the first opcode, and eptr to the first character in the subject string, while eptrb holds the value of eptr at the start of the last bracketed group - used for breaking infinite loops matching zero-length strings. Arguments: eptr pointer in subject ecode position in code offset_top current top pointer md pointer to "static" info for the match ims current /i, /m, and /s options eptrb pointer to chain of blocks containing eptr at start of brackets - for testing for empty matches flags can contain match_condassert - this is an assertion condition match_isgroup - this is the start of a bracketed group Returns: TRUE if matched */ static BOOL match(register const uschar *eptr, register const uschar *ecode, int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, int flags) { unsigned long int original_ims = ims; /* Save for resetting on ')' */ eptrblock newptrb; /* At the start of a bracketed group, add the current subject pointer to the stack of such pointers, to be re-instated at the end of the group when we hit the closing ket. When match() is called in other circumstances, we don't add to the stack. */ if ((flags & match_isgroup) != 0) { newptrb.prev = eptrb; newptrb.saved_eptr = eptr; eptrb = &newptrb; } /* Now start processing the operations. */ for (;;) { int op = (int)*ecode; int min, max, ctype; register int i; register int c; BOOL minimize = FALSE; /* Opening capturing bracket. If there is space in the offset vector, save the current subject position in the working slot at the top of the vector. We mustn't change the current values of the data slot, because they may be set from a previous iteration of this group, and be referred to by a reference inside the group. If the bracket fails to match, we need to restore this value and also the values of the final offsets, in case they were set by a previous iteration of the same bracket. If there isn't enough space in the offset vector, treat this as if it were a non-capturing bracket. Don't worry about setting the flag for the error case here; that is handled in the code for KET. */ if (op > OP_BRA) { int number = op - OP_BRA; int offset = number << 1; #ifdef DEBUG printf("start bracket %d subject=", number); pchars(eptr, 16, TRUE, md); printf("\n"); #endif if (offset < md->offset_max) { int save_offset1 = md->offset_vector[offset]; int save_offset2 = md->offset_vector[offset+1]; int save_offset3 = md->offset_vector[md->offset_end - number]; DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); md->offset_vector[md->offset_end - number] = eptr - md->start_subject; do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); DPRINTF(("bracket %d failed\n", number)); md->offset_vector[offset] = save_offset1; md->offset_vector[offset+1] = save_offset2; md->offset_vector[md->offset_end - number] = save_offset3; return FALSE; } /* Insufficient room for saving captured contents */ else op = OP_BRA; } /* Other types of node can be handled by a switch */ switch(op) { case OP_BRA: /* Non-capturing bracket: optimized */ DPRINTF(("start bracket 0\n")); do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); DPRINTF(("bracket 0 failed\n")); return FALSE; /* Conditional group: compilation checked that there are no more than two branches. If the condition is false, skipping the first branch takes us past the end if there is only one branch, but that's OK because that is exactly what going to the ket would do. */ case OP_COND: if (ecode[3] == OP_CREF) /* Condition is extraction test */ { int offset = ecode[4] << 1; /* Doubled reference number */ return match(eptr, ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)? 5 : 3 + (ecode[1] << 8) + ecode[2]), offset_top, md, ims, eptrb, match_isgroup); } /* The condition is an assertion. Call match() to evaluate it - setting the final argument TRUE causes it to stop at the end of an assertion. */ else { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_condassert | match_isgroup)) { ecode += 3 + (ecode[4] << 8) + ecode[5]; while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2]; } else ecode += (ecode[1] << 8) + ecode[2]; return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup); } /* Control never reaches here */ /* Skip over conditional reference data if encountered (should not be) */ case OP_CREF: ecode += 2; break; /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched an empty string - recursion will then try other alternatives, if any. */ case OP_END: if (md->notempty && eptr == md->start_match) return FALSE; md->end_match_ptr = eptr; /* Record where we ended */ md->end_offset_top = offset_top; /* and how many extracts were taken */ return TRUE; /* Change option settings */ case OP_OPT: ims = ecode[1]; ecode += 2; DPRINTF(("ims set to %02lx\n", ims)); break; /* Assertion brackets. Check the alternative branches in turn - the matching won't pass the KET for an assertion. If any one branch matches, the assertion is true. Lookbehind assertions have an OP_REVERSE item at the start of each branch to move the current point backwards, so the code at this level is identical to the lookahead case. */ case OP_ASSERT: case OP_ASSERTBACK: do { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); if (*ecode == OP_KET) return FALSE; /* If checking an assertion for a condition, return TRUE. */ if ((flags & match_condassert) != 0) return TRUE; /* Continue from after the assertion, updating the offsets high water mark, since extracts may have been taken during the assertion. */ do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); ecode += 3; offset_top = md->end_offset_top; continue; /* Negative assertion: all branches must fail to match */ case OP_ASSERT_NOT: case OP_ASSERTBACK_NOT: do { if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) return FALSE; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); if ((flags & match_condassert) != 0) return TRUE; ecode += 3; continue; /* Move the subject pointer back. This occurs only at the start of each branch of a lookbehind assertion. If we are too close to the start to move back, this match function fails. When working with UTF-8 we move back a number of characters, not bytes. */ case OP_REVERSE: #ifdef SUPPORT_UTF8 c = (ecode[1] << 8) + ecode[2]; for (i = 0; i < c; i++) { eptr--; BACKCHAR(eptr) } #else eptr -= (ecode[1] << 8) + ecode[2]; #endif if (eptr < md->start_subject) return FALSE; ecode += 3; break; /* Recursion matches the current regex, nested. If there are any capturing brackets started but not finished, we have to save their starting points and reinstate them after the recursion. However, we don't know how many such there are (offset_top records the completed total) so we just have to save all the potential data. There may be up to 99 such values, which is a bit large to put on the stack, but using malloc for small numbers seems expensive. As a compromise, the stack is used when there are fewer than 16 values to store; otherwise malloc is used. A problem is what to do if the malloc fails ... there is no way of returning to the top level with an error. Save the top 15 values on the stack, and accept that the rest may be wrong. */ case OP_RECURSE: { BOOL rc; int *save; int stacksave[15]; c = md->offset_max; if (c < 16) save = stacksave; else { save = (int *)(pcre_malloc)((c+1) * sizeof(int)); if (save == NULL) { save = stacksave; c = 15; } } for (i = 1; i <= c; i++) save[i] = md->offset_vector[md->offset_end - i]; rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb, match_isgroup); for (i = 1; i <= c; i++) md->offset_vector[md->offset_end - i] = save[i]; if (save != stacksave) (pcre_free)(save); if (!rc) return FALSE; /* In case the recursion has set more capturing values, save the final number, then move along the subject till after the recursive match, and advance one byte in the pattern code. */ offset_top = md->end_offset_top; eptr = md->end_match_ptr; ecode++; } break; /* "Once" brackets are like assertion brackets except that after a match, the point in the subject string is not moved back. Thus there can never be a move back into the brackets. Check the alternative branches in turn - the matching won't pass the KET for this kind of subpattern. If any one branch matches, we carry on as at the end of a normal bracket, leaving the subject pointer. */ case OP_ONCE: { const uschar *prev = ecode; const uschar *saved_eptr = eptr; do { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup)) break; ecode += (ecode[1] << 8) + ecode[2]; } while (*ecode == OP_ALT); /* If hit the end of the group (which could be repeated), fail */ if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE; /* Continue as from after the assertion, updating the offsets high water mark, since extracts may have been taken. */ do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); offset_top = md->end_offset_top; eptr = md->end_match_ptr; /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 3; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. We need to reset any options that changed within the bracket before re-running it, so check the next opcode. */ if (ecode[3] == OP_OPT) { ims = (ims & ~PCRE_IMS) | ecode[4]; DPRINTF(("ims set to %02lx at group repeat\n", ims)); } if (*ecode == OP_KETRMIN) { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; } else /* OP_KETRMAX */ { if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; } } return FALSE; /* An alternation is the end of a branch; scan along to find the end of the bracketed group and go to there. */ case OP_ALT: do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT); break; /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating that it may occur zero times. It may repeat infinitely, or not at all - i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper repeat limits are compiled as a number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. */ case OP_BRAZERO: { const uschar *next = ecode+1; if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); ecode = next + 3; } break; case OP_BRAMINZERO: { const uschar *next = ecode+1; do next += (next[1] << 8) + next[2]; while (*next == OP_ALT); if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; ecode++; } break; /* End of a group, repeated or non-repeating. If we are at the end of an assertion "group", stop matching and return TRUE, but record the current high water mark for use by positive assertions. Do this also for the "once" (not-backup up) groups. */ case OP_KET: case OP_KETRMIN: case OP_KETRMAX: { const uschar *prev = ecode - (ecode[1] << 8) - ecode[2]; const uschar *saved_eptr = eptrb->saved_eptr; eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */ if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT || *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT || *prev == OP_ONCE) { md->end_match_ptr = eptr; /* For ONCE */ md->end_offset_top = offset_top; return TRUE; } /* In all other cases except a conditional group we have to check the group number back at the start and if necessary complete handling an extraction by setting the offsets and bumping the high water mark. */ if (*prev != OP_COND) { int number = *prev - OP_BRA; int offset = number << 1; #ifdef DEBUG printf("end bracket %d", number); printf("\n"); #endif if (number > 0) { if (offset >= md->offset_max) md->offset_overflow = TRUE; else { md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; md->offset_vector[offset+1] = eptr - md->start_subject; if (offset_top <= offset) offset_top = offset + 2; } } } /* Reset the value of the ims flags, in case they got changed during the group. */ ims = original_ims; DPRINTF(("ims reset to %02lx\n", ims)); /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. If there is an options reset, it will get obeyed in the normal course of events. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 3; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. */ if (*ecode == OP_KETRMIN) { if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) || match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup)) return TRUE; } else /* OP_KETRMAX */ { if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) || match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE; } } return FALSE; /* Start of subject unless notbol, or after internal newline if multiline */ case OP_CIRC: if (md->notbol && eptr == md->start_subject) return FALSE; if ((ims & PCRE_MULTILINE) != 0) { if (eptr != md->start_subject && eptr[-1] != '\n') return FALSE; ecode++; break; } /* ... else fall through */ /* Start of subject assertion */ case OP_SOD: if (eptr != md->start_subject) return FALSE; ecode++; break; /* Assert before internal newline if multiline, or before a terminating newline unless endonly is set, else end of subject unless noteol is set. */ case OP_DOLL: if ((ims & PCRE_MULTILINE) != 0) { if (eptr < md->end_subject) { if (*eptr != '\n') return FALSE; } else { if (md->noteol) return FALSE; } ecode++; break; } else { if (md->noteol) return FALSE; if (!md->endonly) { if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE; ecode++; break; } } /* ... else fall through */ /* End of subject assertion (\z) */ case OP_EOD: if (eptr < md->end_subject) return FALSE; ecode++; break; /* End of subject or ending \n assertion (\Z) */ case OP_EODN: if (eptr < md->end_subject - 1 || (eptr == md->end_subject - 1 && *eptr != '\n')) return FALSE; ecode++; break; /* Word boundary assertions */ case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: { BOOL prev_is_word = (eptr != md->start_subject) && ((md->ctypes[eptr[-1]] & ctype_word) != 0); BOOL cur_is_word = (eptr < md->end_subject) && ((md->ctypes[*eptr] & ctype_word) != 0); if ((*ecode++ == OP_WORD_BOUNDARY)? cur_is_word == prev_is_word : cur_is_word != prev_is_word) return FALSE; } break; /* Match a single character type; inline for speed */ case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == '\n') return FALSE; if (eptr++ >= md->end_subject) return FALSE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; #endif ecode++; break; case OP_NOT_DIGIT: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE; ecode++; break; case OP_DIGIT: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE; ecode++; break; case OP_NOT_WHITESPACE: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_space) != 0) return FALSE; ecode++; break; case OP_WHITESPACE: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_space) == 0) return FALSE; ecode++; break; case OP_NOT_WORDCHAR: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_word) != 0) return FALSE; ecode++; break; case OP_WORDCHAR: if (eptr >= md->end_subject || (md->ctypes[*eptr++] & ctype_word) == 0) return FALSE; ecode++; break; /* Match a back reference, possibly repeatedly. Look past the end of the item to see if there is repeat information following. The code is similar to that for character classes, but repeated for efficiency. Then obey similar code to character type repeats - written out again for speed. However, if the referenced string is the empty string, always treat it as matched, any number of times (otherwise there could be infinite loops). */ case OP_REF: { int length; int offset = ecode[1] << 1; /* Doubled reference number */ ecode += 2; /* Advance past the item */ /* If the reference is unset, set the length to be longer than the amount of subject left; this ensures that every attempt at a match fails. We can't just fail here, because of the possibility of quantifiers with zero minima. */ length = (offset >= offset_top || md->offset_vector[offset] < 0)? md->end_subject - eptr + 1 : md->offset_vector[offset+1] - md->offset_vector[offset]; /* Set up for repetition, or handle the non-repeated case */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = (ecode[1] << 8) + ecode[2]; max = (ecode[3] << 8) + ecode[4]; if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ if (!match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; continue; /* With the main loop */ } /* If the length of the reference is zero, just continue with the main loop. */ if (length == 0) continue; /* First, ensure the minimum number of matches are present. We get back the length of the reference string explicitly rather than passing the address of eptr, so that eptr can be a register variable. */ for (i = 1; i <= min; i++) { if (!match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; } /* If min = max, continue at the same level without recursion. They are not both allowed to be zero. */ if (min == max) continue; /* If minimizing, keep trying and advancing the pointer */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || !match_ref(offset, eptr, length, md, ims)) return FALSE; eptr += length; } /* Control never gets here */ } /* If maximizing, find the longest string and work backwards */ else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (!match_ref(offset, eptr, length, md, ims)) break; eptr += length; } while (eptr >= pp) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; eptr -= length; } return FALSE; } } /* Control never gets here */ /* Match a character class, possibly repeatedly. Look past the end of the item to see if there is repeat information following. Then obey similar code to character type repeats - written out again for speed. */ case OP_CLASS: { const uschar *data = ecode + 1; /* Save for matching */ ecode += 33; /* Advance past the item */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = (ecode[1] << 8) + ecode[2]; max = (ecode[3] << 8) + ecode[4]; if (max == 0) max = INT_MAX; ecode += 5; break; default: /* No repeat follows */ min = max = 1; break; } /* First, ensure the minimum number of matches are present. */ for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) return FALSE; GETCHARINC(c, eptr) /* Get character; increment eptr */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) return FALSE; #endif if ((data[c/8] & (1 << (c&7))) != 0) continue; return FALSE; } /* If max == min we can continue with the main loop without the need to recurse. */ if (min == max) continue; /* If minimizing, keep testing the rest of the expression and advancing the pointer while it matches the class. */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject) return FALSE; GETCHARINC(c, eptr) /* Get character; increment eptr */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) return FALSE; #endif if ((data[c/8] & (1 << (c&7))) != 0) continue; return FALSE; } /* Control never gets here */ } /* If maximizing, find the longest possible run, then work backwards. */ else { const uschar *pp = eptr; int len = 1; for (i = min; i < max; i++) { if (eptr >= md->end_subject) break; GETCHARLEN(c, eptr, len) /* Get character, set length if UTF-8 */ #ifdef SUPPORT_UTF8 /* We do not yet support class members > 255 */ if (c > 255) break; #endif if ((data[c/8] & (1 << (c&7))) == 0) break; eptr += len; } while (eptr >= pp) { if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; #ifdef SUPPORT_UTF8 BACKCHAR(eptr) #endif } return FALSE; } } /* Control never gets here */ /* Match a run of characters */ case OP_CHARS: { register int length = ecode[1]; ecode += 2; #ifdef DEBUG /* Sigh. Some compilers never learn. */ if (eptr >= md->end_subject) printf("matching subject against pattern "); else { printf("matching subject "); pchars(eptr, length, TRUE, md); printf(" against pattern "); } pchars(ecode, length, FALSE, md); printf("\n"); #endif if (length > md->end_subject - eptr) return FALSE; if ((ims & PCRE_CASELESS) != 0) { while (length-- > 0) if (md->lcc[*ecode++] != md->lcc[*eptr++]) return FALSE; } else { while (length-- > 0) if (*ecode++ != *eptr++) return FALSE; } } break; /* Match a single character repeatedly; different opcodes share code. */ case OP_EXACT: min = max = (ecode[1] << 8) + ecode[2]; ecode += 3; goto REPEATCHAR; case OP_UPTO: case OP_MINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_MINUPTO; ecode += 3; goto REPEATCHAR; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: c = *ecode++ - OP_STAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATCHAR: if (min > md->end_subject - eptr) return FALSE; c = *ecode++; /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { c = md->lcc[c]; for (i = 1; i <= min; i++) if (c != md->lcc[*eptr++]) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c != md->lcc[*eptr++]) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c != md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } /* Control never gets here */ } /* Caseful comparisons */ else { for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c != *eptr) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } } /* Control never gets here */ /* Match a negated single character */ case OP_NOT: if (eptr >= md->end_subject) return FALSE; ecode++; if ((ims & PCRE_CASELESS) != 0) { if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE; } else { if (*ecode++ == *eptr++) return FALSE; } break; /* Match a negated single character repeatedly. This is almost a repeat of the code for a repeated single character, but I haven't found a nice way of commoning these up that doesn't require a test of the positive/negative option for each character match. Maybe that wouldn't add very much to the time taken, but character matching *is* what this is all about... */ case OP_NOTEXACT: min = max = (ecode[1] << 8) + ecode[2]; ecode += 3; goto REPEATNOTCHAR; case OP_NOTUPTO: case OP_NOTMINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_NOTMINUPTO; ecode += 3; goto REPEATNOTCHAR; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: c = *ecode++ - OP_NOTSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We can give up quickly if there are fewer than the minimum number of characters left in the subject. */ REPEATNOTCHAR: if (min > md->end_subject - eptr) return FALSE; c = *ecode++; /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max, max, eptr)); if ((ims & PCRE_CASELESS) != 0) { c = md->lcc[c]; for (i = 1; i <= min; i++) if (c == md->lcc[*eptr++]) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c == md->lcc[*eptr++]) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c == md->lcc[*eptr]) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } /* Control never gets here */ } /* Caseful comparisons */ else { for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE; if (min == max) continue; if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE; } /* Control never gets here */ } else { const uschar *pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject || c == *eptr) break; eptr++; } while (eptr >= pp) if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; return FALSE; } } /* Control never gets here */ /* Match a single character type repeatedly; several different opcodes share code. This is very similar to the code for single characters, but we repeat it in the interests of efficiency. */ case OP_TYPEEXACT: min = max = (ecode[1] << 8) + ecode[2]; minimize = TRUE; ecode += 3; goto REPEATTYPE; case OP_TYPEUPTO: case OP_TYPEMINUPTO: min = 0; max = (ecode[1] << 8) + ecode[2]; minimize = *ecode == OP_TYPEMINUPTO; ecode += 3; goto REPEATTYPE; case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: c = *ecode++ - OP_TYPESTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single character type matches */ REPEATTYPE: ctype = *ecode++; /* Code for the character type */ /* First, ensure the minimum number of matches are present. Use inline code for maximizing the speed, and do the type test once at the start (i.e. keep it out of the loop). Also we can test that there are at least the minimum number of bytes before we start, except when doing '.' in UTF8 mode. Leave the test in in all cases; in the special case we have to test after each character. */ if (min > md->end_subject - eptr) return FALSE; if (min > 0) switch(ctype) { case OP_ANY: #ifdef SUPPORT_UTF8 if (md->utf8) { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject || (*eptr++ == '\n' && (ims & PCRE_DOTALL) == 0)) return FALSE; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } break; } #endif /* Non-UTF8 can be faster */ if ((ims & PCRE_DOTALL) == 0) { for (i = 1; i <= min; i++) if (*eptr++ == '\n') return FALSE; } else eptr += min; break; case OP_NOT_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE; break; case OP_DIGIT: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE; break; case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE; break; case OP_WHITESPACE: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE; break; case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) != 0) return FALSE; break; case OP_WORDCHAR: for (i = 1; i <= min; i++) if ((md->ctypes[*eptr++] & ctype_word) == 0) return FALSE; break; } /* If min = max, continue at the same level without recursing */ if (min == max) continue; /* If minimizing, we have to test the rest of the pattern before each subsequent match. */ if (minimize) { for (i = min;; i++) { if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; if (i >= max || eptr >= md->end_subject) return FALSE; c = *eptr++; switch(ctype) { case OP_ANY: if ((ims & PCRE_DOTALL) == 0 && c == '\n') return FALSE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; #endif break; case OP_NOT_DIGIT: if ((md->ctypes[c] & ctype_digit) != 0) return FALSE; break; case OP_DIGIT: if ((md->ctypes[c] & ctype_digit) == 0) return FALSE; break; case OP_NOT_WHITESPACE: if ((md->ctypes[c] & ctype_space) != 0) return FALSE; break; case OP_WHITESPACE: if ((md->ctypes[c] & ctype_space) == 0) return FALSE; break; case OP_NOT_WORDCHAR: if ((md->ctypes[c] & ctype_word) != 0) return FALSE; break; case OP_WORDCHAR: if ((md->ctypes[c] & ctype_word) == 0) return FALSE; break; } } /* Control never gets here */ } /* If maximizing it is worth using inline code for speed, doing the type test once at the start (i.e. keep it out of the loop). */ else { const uschar *pp = eptr; switch(ctype) { case OP_ANY: /* Special code is required for UTF8, but when the maximum is unlimited we don't need it. */ #ifdef SUPPORT_UTF8 if (md->utf8 && max < INT_MAX) { if ((ims & PCRE_DOTALL) == 0) { for (i = min; i < max; i++) { if (eptr >= md->end_subject || *eptr++ == '\n') break; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } } else { for (i = min; i < max; i++) { eptr++; while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++; } } break; } #endif /* Non-UTF8 can be faster */ if ((ims & PCRE_DOTALL) == 0) { for (i = min; i < max; i++) { if (eptr >= md->end_subject || *eptr == '\n') break; eptr++; } } else { c = max - min; if (c > md->end_subject - eptr) c = md->end_subject - eptr; eptr += c; } break; case OP_NOT_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0) break; eptr++; } break; case OP_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0) break; eptr++; } break; case OP_NOT_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0) break; eptr++; } break; case OP_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0) break; eptr++; } break; case OP_NOT_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0) break; eptr++; } break; case OP_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0) break; eptr++; } break; } while (eptr >= pp) { if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0)) return TRUE; #ifdef SUPPORT_UTF8 if (md->utf8) while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--; #endif } return FALSE; } /* Control never gets here */ /* There's been some horrible disaster. */ default: DPRINTF(("Unknown opcode %d\n", *ecode)); md->errorcode = PCRE_ERROR_UNKNOWN_NODE; return FALSE; } /* Do not stick any code in here without much thought; it is assumed that "continue" in the code above comes out to here to repeat the main loop. */ } /* End of main loop */ /* Control never reaches here */ } /************************************************* * Execute a Regular Expression * *************************************************/ /* This function applies a compiled re to a subject string and picks out portions of the string if it matches. Two elements in the vector are set for each substring: the offsets to the start and end of the substring. Arguments: external_re points to the compiled expression external_extra points to "hints" from pcre_study() or is NULL subject points to the subject string length length of subject string (may contain binary zeros) start_offset where to start in the subject string options option bits offsets points to a vector of ints to be filled in with offsets offsetcount the number of elements in the vector Returns: > 0 => success; value is the number of elements filled in = 0 => success, but offsets is not big enough -1 => failed to match < -1 => some kind of unexpected problem */ int pcre_exec(const pcre *external_re, const pcre_extra *external_extra, const char *subject, int length, int start_offset, int options, int *offsets, int offsetcount) { int resetcount, ocount; int first_char = -1; int req_char = -1; int req_char2 = -1; unsigned long int ims = 0; match_data match_block; const uschar *start_bits = NULL; const uschar *start_match = (const uschar *)subject + start_offset; const uschar *end_subject; const uschar *req_char_ptr = start_match - 1; const real_pcre *re = (const real_pcre *)external_re; const real_pcre_extra *extra = (const real_pcre_extra *)external_extra; BOOL using_temporary_offsets = FALSE; BOOL anchored = ((re->options | options) & PCRE_ANCHORED) != 0; BOOL startline = (re->options & PCRE_STARTLINE) != 0; if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; match_block.start_pattern = re->code; match_block.start_subject = (const uschar *)subject; match_block.end_subject = match_block.start_subject + length; end_subject = match_block.end_subject; match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; match_block.utf8 = (re->options & PCRE_UTF8) != 0; match_block.notbol = (options & PCRE_NOTBOL) != 0; match_block.noteol = (options & PCRE_NOTEOL) != 0; match_block.notempty = (options & PCRE_NOTEMPTY) != 0; match_block.errorcode = PCRE_ERROR_NOMATCH; /* Default error */ match_block.lcc = re->tables + lcc_offset; match_block.ctypes = re->tables + ctypes_offset; /* The ims options can vary during the matching as a result of the presence of (?ims) items in the pattern. They are kept in a local variable so that restoring at the exit of a group is easy. */ ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL); /* If the expression has got more back references than the offsets supplied can hold, we get a temporary bit of working store to use during the matching. Otherwise, we can use the vector supplied, rounding down its size to a multiple of 3. */ ocount = offsetcount - (offsetcount % 3); if (re->top_backref > 0 && re->top_backref >= ocount/3) { ocount = re->top_backref * 3 + 3; match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int)); if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY; using_temporary_offsets = TRUE; DPRINTF(("Got memory to hold back references\n")); } else match_block.offset_vector = offsets; match_block.offset_end = ocount; match_block.offset_max = (2*ocount)/3; match_block.offset_overflow = FALSE; /* Compute the minimum number of offsets that we need to reset each time. Doing this makes a huge difference to execution time when there aren't many brackets in the pattern. */ resetcount = 2 + re->top_bracket * 2; if (resetcount > offsetcount) resetcount = ocount; /* Reset the working variable associated with each extraction. These should never be used unless previously set, but they get saved and restored, and so we initialize them to avoid reading uninitialized locations. */ if (match_block.offset_vector != NULL) { register int *iptr = match_block.offset_vector + ocount; register int *iend = iptr - resetcount/2 + 1; while (--iptr >= iend) *iptr = -1; } /* Set up the first character to match, if available. The first_char value is never set for an anchored regular expression, but the anchoring may be forced at run time, so we have to test for anchoring. The first char may be unset for an unanchored pattern, of course. If there's no first char and the pattern was studied, there may be a bitmap of possible first characters. */ if (!anchored) { if ((re->options & PCRE_FIRSTSET) != 0) { first_char = re->first_char; if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char]; } else if (!startline && extra != NULL && (extra->options & PCRE_STUDY_MAPPED) != 0) start_bits = extra->start_bits; } /* For anchored or unanchored matches, there may be a "last known required character" set. If the PCRE_CASELESS is set, implying that the match starts caselessly, or if there are any changes of this flag within the regex, set up both cases of the character. Otherwise set the two values the same, which will avoid duplicate testing (which takes significant time). This covers the vast majority of cases. It will be suboptimal when the case flag changes in a regex and the required character in fact is caseful. */ if ((re->options & PCRE_REQCHSET) != 0) { req_char = re->req_char; req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)? (re->tables + fcc_offset)[req_char] : req_char; } /* Loop for handling unanchored repeated matching attempts; for anchored regexs the loop runs just once. */ do { int rc; register int *iptr = match_block.offset_vector; register int *iend = iptr + resetcount; /* Reset the maximum number of extractions we might see. */ while (iptr < iend) *iptr++ = -1; /* Advance to a unique first char if possible */ if (first_char >= 0) { if ((ims & PCRE_CASELESS) != 0) while (start_match < end_subject && match_block.lcc[*start_match] != first_char) start_match++; else while (start_match < end_subject && *start_match != first_char) start_match++; } /* Or to just after \n for a multiline match if possible */ else if (startline) { if (start_match > match_block.start_subject + start_offset) { while (start_match < end_subject && start_match[-1] != '\n') start_match++; } } /* Or to a non-unique first char after study */ else if (start_bits != NULL) { while (start_match < end_subject) { register int c = *start_match; if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break; } } #ifdef DEBUG /* Sigh. Some compilers never learn. */ printf(">>>> Match against: "); pchars(start_match, end_subject - start_match, TRUE, &match_block); printf("\n"); #endif /* If req_char is set, we know that that character must appear in the subject for the match to succeed. If the first character is set, req_char must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of backtracking in patterns with nested unlimited repeats that aren't going to match. We don't know what the state of case matching may be when this character is hit, so test for it in both its cases if necessary. However, the different cased versions will not be set up unless PCRE_CASELESS was given or the casing state changes within the regex. Writing separate code makes it go faster, as does using an autoincrement and backing off on a match. */ if (req_char >= 0) { register const uschar *p = start_match + ((first_char >= 0)? 1 : 0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ if (p > req_char_ptr) { /* Do a single test if no case difference is set up */ if (req_char == req_char2) { while (p < end_subject) { if (*p++ == req_char) { p--; break; } } } /* Otherwise test for either case */ else { while (p < end_subject) { register int pp = *p++; if (pp == req_char || pp == req_char2) { p--; break; } } } /* If we can't find the required character, break the matching loop */ if (p >= end_subject) break; /* If we have found the required character, save the point where we found it, so that we don't search again next time round the loop if the start hasn't passed this character yet. */ req_char_ptr = p; } } /* When a match occurs, substrings will be set for all internal extractions; we just need to set up the whole thing as substring 0 before returning. If there were too many extractions, set the return code to zero. In the case where we had to get some local store to hold offsets for backreferences, copy those back references that we can. In this case there need not be overflow if certain parts of the pattern were not used. */ match_block.start_match = start_match; if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup)) continue; /* Copy the offset information from temporary store if necessary */ if (using_temporary_offsets) { if (offsetcount >= 4) { memcpy(offsets + 2, match_block.offset_vector + 2, (offsetcount - 2) * sizeof(int)); DPRINTF(("Copied offsets from temporary memory\n")); } if (match_block.end_offset_top > offsetcount) match_block.offset_overflow = TRUE; DPRINTF(("Freeing temporary memory\n")); (pcre_free)(match_block.offset_vector); } rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2; if (match_block.offset_end < 2) rc = 0; else { offsets[0] = start_match - match_block.start_subject; offsets[1] = match_block.end_match_ptr - match_block.start_subject; } DPRINTF((">>>> returning %d\n", rc)); return rc; } /* This "while" is the end of the "do" above */ while (!anchored && match_block.errorcode == PCRE_ERROR_NOMATCH && start_match++ < end_subject); if (using_temporary_offsets) { DPRINTF(("Freeing temporary memory\n")); (pcre_free)(match_block.offset_vector); } DPRINTF((">>>> returning %d\n", match_block.errorcode)); return match_block.errorcode; } /* End of pcre.c */ privoxy-3.0.21-stable/./pcre/pcreposix.h000640 001751 001751 00000004445 10546014100 017076 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2000 University of Cambridge */ #ifndef _PCREPOSIX_H #define _PCREPOSIX_H /* This is the header for the POSIX wrapper interface to the PCRE Perl- Compatible Regular Expression library. It defines the things POSIX says should be there. I hope. */ /* Have to include stdlib.h in order to ensure that size_t is defined. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options defined by POSIX. */ #define REG_ICASE 0x01 #define REG_NEWLINE 0x02 #define REG_NOTBOL 0x04 #define REG_NOTEOL 0x08 /* These are not used by PCRE, but by defining them we make it easier to slot PCRE into existing programs that make POSIX calls. */ #define REG_EXTENDED 0 #define REG_NOSUB 0 /* Error values. Not all these are relevant or used by the wrapper. */ enum { REG_ASSERT = 1, /* internal error ? */ REG_BADBR, /* invalid repeat counts in {} */ REG_BADPAT, /* pattern error */ REG_BADRPT, /* ? * + invalid */ REG_EBRACE, /* unbalanced {} */ REG_EBRACK, /* unbalanced [] */ REG_ECOLLATE, /* collation error - not relevant */ REG_ECTYPE, /* bad class */ REG_EESCAPE, /* bad escape sequence */ REG_EMPTY, /* empty expression */ REG_EPAREN, /* unbalanced () */ REG_ERANGE, /* bad range inside [] */ REG_ESIZE, /* expression too big */ REG_ESPACE, /* failed to get memory */ REG_ESUBREG, /* bad back reference */ REG_INVARG, /* bad argument */ REG_NOMATCH /* match failed */ }; /* The structure representing a compiled regular expression. */ typedef struct { void *re_pcre; size_t re_nsub; size_t re_erroffset; } regex_t; /* The structure in which a captured offset is returned. */ typedef int regoff_t; typedef struct { regoff_t rm_so; regoff_t rm_eo; } regmatch_t; /* The functions */ extern int regcomp(regex_t *, const char *, int); extern int regexec(regex_t *, const char *, size_t, regmatch_t *, int); extern size_t regerror(int, const regex_t *, char *, size_t); extern void regfree(regex_t *); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcreposix.h */ privoxy-3.0.21-stable/./pcre/get.c000640 001751 001751 00000016401 10546014100 015627 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* This module contains some convenience functions for extracting substrings from the subject string after a regex match has succeeded. The original idea for these functions came from Scott Wimer . */ /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /************************************************* * Copy captured string to given buffer * *************************************************/ /* This function copies a single captured substring into a given buffer. Note that we use memcpy() rather than strncpy() in case there are binary zeros in the string. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring buffer where to put the substring size the size of the buffer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) buffer too small PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) { int yield; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; if (size < yield + 1) return PCRE_ERROR_NOMEMORY; memcpy(buffer, subject + ovector[stringnumber], yield); buffer[yield] = 0; return yield; } /************************************************* * Copy all captured strings to new store * *************************************************/ /* This function gets one chunk of store and builds a list of pointers and all of the captured substrings in it. A NULL pointer is put on the end of the list. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) listptr set to point to the list of pointers Returns: if successful: 0 if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store */ int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr) { int i; int size = sizeof(char *); int double_count = stringcount * 2; char **stringlist; char *p; for (i = 0; i < double_count; i += 2) size += sizeof(char *) + ovector[i+1] - ovector[i] + 1; stringlist = (char **)(pcre_malloc)(size); if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; *listptr = (const char **)stringlist; p = (char *)(stringlist + stringcount + 1); for (i = 0; i < double_count; i += 2) { int len = ovector[i+1] - ovector[i]; memcpy(p, subject + ovector[i], len); *stringlist++ = p; p += len; *p++ = 0; } *stringlist = NULL; return 0; } /************************************************* * Free store obtained by get_substring_list * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (pcre_free)() directly. Argument: the result of a previous pcre_get_substring_list() Returns: nothing */ void pcre_free_substring_list(const char **pointer) { (pcre_free)((void *)pointer); } /************************************************* * Copy captured string to new store * *************************************************/ /* This function copies a single captured substring into a piece of new store Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring stringptr where to put a pointer to the substring Returns: if successful: the length of the string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store PCRE_ERROR_NOSUBSTRING (-7) substring not present */ int pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr) { int yield; char *substring; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; substring = (char *)(pcre_malloc)(yield + 1); if (substring == NULL) return PCRE_ERROR_NOMEMORY; memcpy(substring, subject + ovector[stringnumber], yield); substring[yield] = 0; *stringptr = substring; return yield; } /************************************************* * Free store obtained by get_substring * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (pcre_free)() directly. Argument: the result of a previous pcre_get_substring() Returns: nothing */ void pcre_free_substring(const char *pointer) { (pcre_free)((void *)pointer); } /* End of get.c */ privoxy-3.0.21-stable/./pcre/dll.mk000640 001751 001751 00000003667 10546014100 016022 0ustar00fkfk000000 000000 # dll.mk - auxilary Makefile to easy build dll's for mingw32 target # ver. 0.6 of 1999-03-25 # # Homepage of this makefile - http://www.is.lg.ua/~paul/devel/ # Homepage of original mingw32 project - # http://www.fu.is.saga-u.ac.jp/~colin/gcc.html # # How to use: # This makefile can: # 1. Create automatical .def file from list of objects # 2. Create .dll from objects and .def file, either automatical, or your # hand-written (maybe) file, which must have same basename as dll # WARNING! There MUST be object, which name match dll's name. Make sux. # 3. Create import library from .def (as for .dll, only its name required, # not dll itself) # By convention implibs for dll have .dll.a suffix, e.g. libstuff.dll.a # Why not just libstuff.a? 'Cos that's name for static lib, ok? # Process divided into 3 phases because: # 1. Pre-existent .def possible # 2. Generating implib is enough time-consuming # # Variables: # DLL_LDLIBS - libs for linking dll # DLL_LDFLAGS - flags for linking dll # # By using $(DLL_SUFFIX) instead of 'dll', e.g. stuff.$(DLL_SUFFIX) # you may help porting makefiles to other platforms # # Put this file in your make's include path (e.g. main include dir, for # more information see include section in make doc). Put in the beginning # of your own Makefile line "include dll.mk". Specify dependences, e.g.: # # Do all stuff in one step # libstuff.dll.a: $(OBJECTS) stuff.def # stuff.def: $(OBJECTS) # # Steps separated, pre-provided .def, link with user32 # # DLL_LDLIBS=-luser32 # stuff.dll: $(OBJECTS) # libstuff.dll.a: $(OBJECTS) DLLWRAP=dllwrap DLLTOOL=dlltool DLL_SUFFIX=dll .SUFFIXES: .o .$(DLL_SUFFIX) _%.def: %.o $(DLLTOOL) --export-all --output-def $@ $^ %.$(DLL_SUFFIX): %.o $(DLLWRAP) --dllname $(notdir $@) --driver-name $(CC) --def $*.def -o $@ $(filter %.o,$^) $(DLL_LDFLAGS) $(DLL_LDLIBS) lib%.$(DLL_SUFFIX).a:%.def $(DLLTOOL) --dllname $(notdir $*.dll) --def $< --output-lib $@ # End privoxy-3.0.21-stable/./pcre/configure000640 001751 001751 00000134707 10546014100 016622 0ustar00fkfk000000 000000 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --disable-shared build PCRE as a static library" ac_help="$ac_help --enable-utf8 enable UTF8 support (incomplete)" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # The list generated by autoconf has been trimmed to remove many # options that are totally irrelevant to PCRE (e.g. relating to X), # or are not supported by its Makefile. # The list generated by autoconf has been trimmed to remove many # options that are totally irrelevant to PCRE (e.g. relating to X), # or are not supported by its Makefile. # The list generated by autoconf has been trimmed to remove many # options that are totally irrelevant to PCRE (e.g. relating to X), # or are not supported by its Makefile. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: ./configure [options] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --mandir=DIR man documentation in DIR [PREFIX/man] EOF cat << EOF EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=dftables.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi PCRE_MAJOR=3 PCRE_MINOR=4 PCRE_DATE=22-Aug-2000 PCRE_VERSION=${PCRE_MAJOR}.${PCRE_MINOR} PCRE_LIB_VERSION=0:1:0 PCRE_POSIXLIB_VERSION=0:0:0 # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:546: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:576: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_save_ifs" if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:627: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:659: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 670 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:701: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:706: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:734: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 if test "$ac_test_CFLAGS" = set; then CFLAGS="$ac_save_CFLAGS" elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:768: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:798: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:819: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:836: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:853: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo "configure:878: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:891: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF if { (eval echo configure:958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_header_stdc=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi for ac_hdr in limits.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:985: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:995: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for working const""... $ac_c" 1>&6 echo "configure:1024: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if { (eval echo configure:1078: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 echo "configure:1099: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&6 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi for ac_func in bcopy memmove strerror do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1136: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1164: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done LIBTOOL=./libtool LIBSUFFIX=la # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" if test "$enableval" = "no"; then LIBTOOL= LIBSUFFIX=a fi fi # Check whether --enable-utf8 or --disable-utf8 was given. if test "${enable_utf8+set}" = set; then enableval="$enable_utf8" if test "$enableval" = "yes"; then UTF8=-DSUPPORT_UTF8 fi fi trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 DEFS=-DHAVE_CONFIG_H # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "Makefile pcre.h:pcre.in pcre-config:pcre-config.in RunTest:RunTest.in config.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@CC@%$CC%g s%@RANLIB@%$RANLIB%g s%@CPP@%$CPP%g s%@HAVE_MEMMOVE@%$HAVE_MEMMOVE%g s%@HAVE_STRERROR@%$HAVE_STRERROR%g s%@LIBTOOL@%$LIBTOOL%g s%@LIBSUFFIX@%$LIBSUFFIX%g s%@UTF8@%$UTF8%g s%@PCRE_MAJOR@%$PCRE_MAJOR%g s%@PCRE_MINOR@%$PCRE_MINOR%g s%@PCRE_DATE@%$PCRE_DATE%g s%@PCRE_VERSION@%$PCRE_VERSION%g s%@PCRE_LIB_VERSION@%$PCRE_LIB_VERSION%g s%@PCRE_POSIXLIB_VERSION@%$PCRE_POSIXLIB_VERSION%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' ac_dC='\3' ac_dD='%g' # ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='\([ ]\)%\1#\2define\3' ac_uC=' ' ac_uD='\4%g' # ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_eB='$%\1#\2define\3' ac_eC=' ' ac_eD='%g' if test "${CONFIG_HEADERS+set}" != set; then EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF fi for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac echo creating $ac_file rm -f conftest.frag conftest.in conftest.out ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` cat $ac_file_inputs > conftest.in EOF # Transform confdefs.h into a sed script conftest.vals that substitutes # the proper values into config.h.in to produce config.h. And first: # Protect against being on the right side of a sed subst in config.status. # Protect against being in an unquoted here document in config.status. rm -f conftest.vals cat > conftest.hdr <<\EOF s/[\\&%]/\\&/g s%[\\$`]%\\&%g s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp s%ac_d%ac_u%gp s%ac_u%ac_e%gp EOF sed -n -f conftest.hdr confdefs.h > conftest.vals rm -f conftest.hdr # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >> conftest.vals <<\EOF s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% EOF # Break up conftest.vals because some shells have a limit on # the size of here documents, and old seds have small limits too. rm -f conftest.tail while : do ac_lines=`grep -c . conftest.vals` # grep -c gives empty output for an empty file on some AIX systems. if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi # Write a limited-size here document to conftest.frag. echo ' cat > conftest.frag <> $CONFIG_STATUS sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS echo 'CEOF sed -f conftest.frag conftest.in > conftest.out rm -f conftest.in mv conftest.out conftest.in ' >> $CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail rm -f conftest.vals mv conftest.tail conftest.vals done rm -f conftest.vals cat >> $CONFIG_STATUS <<\EOF rm -f conftest.frag conftest.h echo "/* $ac_file. Generated automatically by configure. */" > conftest.h cat conftest.in >> conftest.h rm -f conftest.in if cmp -s $ac_file conftest.h 2>/dev/null; then echo "$ac_file is unchanged" rm -f conftest.h else # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" fi rm -f $ac_file mv conftest.h $ac_file fi fi; done EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF chmod a+x RunTest pcre-config exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 privoxy-3.0.21-stable/./pcre/pcre-config000750 001751 001751 00000002126 10546014100 017024 0ustar00fkfk000000 000000 #!/bin/sh prefix=/usr/local exec_prefix=${prefix} exec_prefix_set=no usage="\ Usage: pcre-config [--prefix] [--exec-prefix] [--version] [--libs] [--libs-posix] [--cflags] [--cflags-posix]" if test $# -eq 0; then echo "${usage}" 1>&2 exit 1 fi while test $# -gt 0; do case "$1" in -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac case $1 in --prefix=*) prefix=$optarg if test $exec_prefix_set = no ; then exec_prefix=$optarg fi ;; --prefix) echo $prefix ;; --exec-prefix=*) exec_prefix=$optarg exec_prefix_set=yes ;; --exec-prefix) echo $exec_prefix ;; --version) echo 3.4 ;; --cflags | --cflags-posix) if test ${prefix}/include != /usr/include ; then includes=-I${prefix}/include fi echo $includes ;; --libs-posix) echo -L${exec_prefix}/lib -lpcreposix -lpcre ;; --libs) echo -L${exec_prefix}/lib -lpcre ;; *) echo "${usage}" 1>&2 exit 1 ;; esac shift done privoxy-3.0.21-stable/./pcre/pcregrep.c000640 001751 001751 00000011572 10546014100 016663 0ustar00fkfk000000 000000 /************************************************* * pcregrep program * *************************************************/ /* This is a grep program that uses the PCRE regular expression library to do its pattern matching. */ #include #include #include #include #include "config.h" #include "pcre.h" #define FALSE 0 #define TRUE 1 typedef int BOOL; /************************************************* * Global variables * *************************************************/ static pcre *pattern; static pcre_extra *hints; static BOOL count_only = FALSE; static BOOL filenames_only = FALSE; static BOOL invert = FALSE; static BOOL number = FALSE; static BOOL silent = FALSE; static BOOL whole_lines = FALSE; #if ! HAVE_STRERROR /************************************************* * Provide strerror() for non-ANSI libraries * *************************************************/ /* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror() in their libraries, but can provide the same facility by this simple alternative function. */ extern int sys_nerr; extern char *sys_errlist[]; char * strerror(int n) { if (n < 0 || n >= sys_nerr) return "unknown error number"; return sys_errlist[n]; } #endif /* HAVE_STRERROR */ /************************************************* * Grep an individual file * *************************************************/ static int pcregrep(FILE *in, char *name) { int rc = 1; int linenumber = 0; int count = 0; int offsets[99]; char buffer[BUFSIZ]; while (fgets(buffer, sizeof(buffer), in) != NULL) { BOOL match; int length = (int)strlen(buffer); if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0; linenumber++; match = pcre_exec(pattern, hints, buffer, length, 0, 0, offsets, 99) >= 0; if (match && whole_lines && offsets[1] != length) match = FALSE; if (match != invert) { if (count_only) count++; else if (filenames_only) { fprintf(stdout, "%s\n", (name == NULL)? "" : name); return 0; } else if (silent) return 0; else { if (name != NULL) fprintf(stdout, "%s:", name); if (number) fprintf(stdout, "%d:", linenumber); fprintf(stdout, "%s\n", buffer); } rc = 0; } } if (count_only) { if (name != NULL) fprintf(stdout, "%s:", name); fprintf(stdout, "%d\n", count); } return rc; } /************************************************* * Usage function * *************************************************/ static int usage(int rc) { fprintf(stderr, "Usage: pcregrep [-Vchilnsvx] pattern [file] ...\n"); return rc; } /************************************************* * Main program * *************************************************/ int main(int argc, char **argv) { int i; int rc = 1; int options = 0; int errptr; const char *error; BOOL filenames = TRUE; /* Process the options */ for (i = 1; i < argc; i++) { char *s; if (argv[i][0] != '-') break; s = argv[i] + 1; while (*s != 0) { switch (*s++) { case 'c': count_only = TRUE; break; case 'h': filenames = FALSE; break; case 'i': options |= PCRE_CASELESS; break; case 'l': filenames_only = TRUE; case 'n': number = TRUE; break; case 's': silent = TRUE; break; case 'v': invert = TRUE; break; case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break; case 'V': fprintf(stderr, "PCRE version %s\n", pcre_version()); break; default: fprintf(stderr, "pcregrep: unknown option %c\n", s[-1]); return usage(2); } } } /* There must be at least a regexp argument */ if (i >= argc) return usage(0); /* Compile the regular expression. */ pattern = pcre_compile(argv[i++], options, &error, &errptr, NULL); if (pattern == NULL) { fprintf(stderr, "pcregrep: error in regex at offset %d: %s\n", errptr, error); return 2; } /* Study the regular expression, as we will be running it may times */ hints = pcre_study(pattern, 0, &error); if (error != NULL) { fprintf(stderr, "pcregrep: error while studing regex: %s\n", error); return 2; } /* If there are no further arguments, do the business on stdin and exit */ if (i >= argc) return pcregrep(stdin, NULL); /* Otherwise, work through the remaining arguments as files. If there is only one, don't give its name on the output. */ if (i == argc - 1) filenames = FALSE; if (filenames_only) filenames = TRUE; for (; i < argc; i++) { FILE *in = fopen(argv[i], "r"); if (in == NULL) { fprintf(stderr, "%s: failed to open: %s\n", argv[i], strerror(errno)); rc = 2; } else { int frc = pcregrep(in, filenames? argv[i] : NULL); if (frc == 0 && rc == 1) rc = 0; fclose(in); } } return rc; } /* End */ privoxy-3.0.21-stable/./pcre/vc_dftables.dsp000750 001751 001751 00000022574 10546014100 017702 0ustar00fkfk000000 000000 # Microsoft Developer Studio Project File - Name="vc_dftables" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 5.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=vc_dftables - Win32 Debug with Win32 threads !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "vc_dftables.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "vc_dftables.mak"\ CFG="vc_dftables - Win32 Debug with Win32 threads" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "vc_dftables - Win32 Release" (based on\ "Win32 (x86) Console Application") !MESSAGE "vc_dftables - Win32 Debug" (based on\ "Win32 (x86) Console Application") !MESSAGE "vc_dftables - Win32 Debug with Win32 threads" (based on\ "Win32 (x86) Console Application") !MESSAGE "vc_dftables - Win32 Release with Win32 threads" (based on\ "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "vc_dftables - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "vc_dftables" # PROP Intermediate_Dir "vc_dftables" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x809 /d "NDEBUG" # ADD RSC /l 0x809 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # Begin Special Build Tool OutDir=.\vc_dftables SOURCE=$(InputPath) PostBuild_Desc=Running program to generate chartables.c PostBuild_Cmds=$(OutDir)\vc_dftables.exe >$(OutDir)\..\chartables.c # End Special Build Tool !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "vc_dftables_dbg" # PROP Intermediate_Dir "vc_dftables_dbg" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x809 /d "_DEBUG" # ADD RSC /l 0x809 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool OutDir=.\vc_dftables_dbg SOURCE=$(InputPath) PostBuild_Desc=Running program to generate chartables.c PostBuild_Cmds=$(OutDir)\vc_dftables.exe >$(OutDir)\..\chartables.c # End Special Build Tool !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug with Win32 threads" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "vc_dftab" # PROP BASE Intermediate_Dir "vc_dftab" # PROP BASE Ignore_Export_Lib 0 # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "vc_dftables_dbg" # PROP Intermediate_Dir "vc_dftables_dbg" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x809 /d "_DEBUG" # ADD RSC /l 0x809 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool OutDir=.\vc_dftables_dbg SOURCE=$(InputPath) PostBuild_Desc=Running program to generate chartables.c PostBuild_Cmds=$(OutDir)\vc_dftables.exe >$(OutDir)\..\chartables.c # End Special Build Tool !ELSEIF "$(CFG)" == "vc_dftables - Win32 Release with Win32 threads" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "vc_dfta0" # PROP BASE Intermediate_Dir "vc_dfta0" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "vc_dftables" # PROP Intermediate_Dir "vc_dftables" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x809 /d "NDEBUG" # ADD RSC /l 0x809 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # Begin Special Build Tool OutDir=.\vc_dftables SOURCE=$(InputPath) PostBuild_Desc=Running program to generate chartables.c PostBuild_Cmds=$(OutDir)\vc_dftables.exe >$(OutDir)\..\chartables.c # End Special Build Tool !ENDIF # Begin Target # Name "vc_dftables - Win32 Release" # Name "vc_dftables - Win32 Debug" # Name "vc_dftables - Win32 Debug with Win32 threads" # Name "vc_dftables - Win32 Release with Win32 threads" # Begin Group "File Copy" # PROP Default_Filter "" # Begin Source File SOURCE=..\vc_config_pthreads.h !IF "$(CFG)" == "vc_dftables - Win32 Release" # PROP Ignore_Default_Tool 1 # Begin Custom Build - Copying vc_config_pthreads.h WkspDir=. InputPath=..\vc_config_pthreads.h "$(WkspDir)\..\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy "$(InputPath)" "$(WkspDir)\..\config.h" # End Custom Build !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug" # PROP Ignore_Default_Tool 1 # Begin Custom Build - Copying vc_config_pthreads.h WkspDir=. InputPath=..\vc_config_pthreads.h "$(WkspDir)\..\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy "$(InputPath)" "$(WkspDir)\..\config.h" # End Custom Build !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug with Win32 threads" # PROP Exclude_From_Build 1 # PROP Ignore_Default_Tool 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Release with Win32 threads" # PROP Exclude_From_Build 1 # PROP Ignore_Default_Tool 1 !ENDIF # End Source File # Begin Source File SOURCE=..\vc_config_winthreads.h !IF "$(CFG)" == "vc_dftables - Win32 Release" # PROP Exclude_From_Build 1 # PROP Ignore_Default_Tool 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug" # PROP Exclude_From_Build 1 # PROP Ignore_Default_Tool 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug with Win32 threads" # PROP Ignore_Default_Tool 1 # Begin Custom Build - Copying vc_config_winthreads.h WkspDir=. InputPath=..\vc_config_winthreads.h "$(WkspDir)\..\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy "$(InputPath)" "$(WkspDir)\..\config.h" # End Custom Build !ELSEIF "$(CFG)" == "vc_dftables - Win32 Release with Win32 threads" # PROP Ignore_Default_Tool 1 # Begin Custom Build - Copying vc_config_winthreads.h WkspDir=. InputPath=..\vc_config_winthreads.h "$(WkspDir)\..\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" copy "$(InputPath)" "$(WkspDir)\..\config.h" # End Custom Build !ENDIF # End Source File # End Group # Begin Source File SOURCE=..\config.h # End Source File # Begin Source File SOURCE=.\config.h # End Source File # Begin Source File SOURCE=.\dftables.c # End Source File # Begin Source File SOURCE=.\internal.h # End Source File # Begin Source File SOURCE=.\maketables.c !IF "$(CFG)" == "vc_dftables - Win32 Release" # PROP Exclude_From_Build 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug" # PROP Exclude_From_Build 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Debug with Win32 threads" # PROP BASE Exclude_From_Build 1 # PROP Exclude_From_Build 1 !ELSEIF "$(CFG)" == "vc_dftables - Win32 Release with Win32 threads" # PROP BASE Exclude_From_Build 1 # PROP Exclude_From_Build 1 !ENDIF # End Source File # Begin Source File SOURCE=.\pcre.h # End Source File # End Target # End Project privoxy-3.0.21-stable/./pcre/doc/pcreposix.3000640 001751 001751 00000013625 10546014100 017556 0ustar00fkfk000000 000000 .TH PCRE 3 .SH NAME pcreposix - POSIX API for Perl-compatible regular expressions. .SH SYNOPSIS .B #include .PP .SM .br .B int regcomp(regex_t *\fIpreg\fR, const char *\fIpattern\fR, .ti +5n .B int \fIcflags\fR); .PP .br .B int regexec(regex_t *\fIpreg\fR, const char *\fIstring\fR, .ti +5n .B size_t \fInmatch\fR, regmatch_t \fIpmatch\fR[], int \fIeflags\fR); .PP .br .B size_t regerror(int \fIerrcode\fR, const regex_t *\fIpreg\fR, .ti +5n .B char *\fIerrbuf\fR, size_t \fIerrbuf_size\fR); .PP .br .B void regfree(regex_t *\fIpreg\fR); .SH DESCRIPTION This set of functions provides a POSIX-style API to the PCRE regular expression package. See the \fBpcre\fR documentation for a description of the native API, which contains additional functionality. The functions described here are just wrapper functions that ultimately call the native API. Their prototypes are defined in the \fBpcreposix.h\fR header file, and on Unix systems the library itself is called \fBpcreposix.a\fR, so can be accessed by adding \fB-lpcreposix\fR to the command for linking an application which uses them. Because the POSIX functions call the native ones, it is also necessary to add \fR-lpcre\fR. I have implemented only those option bits that can be reasonably mapped to PCRE native options. In addition, the options REG_EXTENDED and REG_NOSUB are defined with the value zero. They have no effect, but since programs that are written to the POSIX interface often use them, this makes it easier to slot in PCRE as a replacement library. Other POSIX options are not even defined. When PCRE is called via these functions, it is only the API that is POSIX-like in style. The syntax and semantics of the regular expressions themselves are still those of Perl, subject to the setting of various PCRE options, as described below. The header for these functions is supplied as \fBpcreposix.h\fR to avoid any potential clash with other POSIX libraries. It can, of course, be renamed or aliased as \fBregex.h\fR, which is the "correct" name. It provides two structure types, \fIregex_t\fR for compiled internal forms, and \fIregmatch_t\fR for returning captured substrings. It also defines some constants whose names start with "REG_"; these are used for setting options and identifying error codes. .SH COMPILING A PATTERN The function \fBregcomp()\fR is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument \fIpattern\fR. The \fIpreg\fR argument is a pointer to a regex_t structure which is used as a base for storing information about the compiled expression. The argument \fIcflags\fR is either zero, or contains one or more of the bits defined by the following macros: REG_ICASE The PCRE_CASELESS option is set when the expression is passed for compilation to the native function. REG_NEWLINE The PCRE_MULTILINE option is set when the expression is passed for compilation to the native function. In the absence of these flags, no options are passed to the native function. This means the the regex is compiled with PCRE default semantics. In particular, the way it handles newline characters in the subject string is the Perl way, not the POSIX way. Note that setting PCRE_MULTILINE has only \fIsome\fR of the effects specified for REG_NEWLINE. It does not affect the way newlines are matched by . (they aren't) or a negative class such as [^a] (they are). The yield of \fBregcomp()\fR is zero on success, and non-zero otherwise. The \fIpreg\fR structure is filled in on success, and one member of the structure is publicized: \fIre_nsub\fR contains the number of capturing subpatterns in the regular expression. Various error codes are defined in the header file. .SH MATCHING A PATTERN The function \fBregexec()\fR is called to match a pre-compiled pattern \fIpreg\fR against a given \fIstring\fR, which is terminated by a zero byte, subject to the options in \fIeflags\fR. These can be: REG_NOTBOL The PCRE_NOTBOL option is set when calling the underlying PCRE matching function. REG_NOTEOL The PCRE_NOTEOL option is set when calling the underlying PCRE matching function. The portion of the string that was matched, and also any captured substrings, are returned via the \fIpmatch\fR argument, which points to an array of \fInmatch\fR structures of type \fIregmatch_t\fR, containing the members \fIrm_so\fR and \fIrm_eo\fR. These contain the offset to the first character of each substring and the offset to the first character after the end of each substring, respectively. The 0th element of the vector relates to the entire portion of \fIstring\fR that was matched; subsequent elements relate to the capturing subpatterns of the regular expression. Unused entries in the array have both structure members set to -1. A successful match yields a zero return; various error codes are defined in the header file, of which REG_NOMATCH is the "expected" failure code. .SH ERROR MESSAGES The \fBregerror()\fR function maps a non-zero errorcode from either \fBregcomp\fR or \fBregexec\fR to a printable message. If \fIpreg\fR is not NULL, the error should have arisen from the use of that structure. A message terminated by a binary zero is placed in \fIerrbuf\fR. The length of the message, including the zero, is limited to \fIerrbuf_size\fR. The yield of the function is the size of buffer needed to hold the whole message. .SH STORAGE Compiling a regular expression causes memory to be allocated and associated with the \fIpreg\fR structure. The function \fBregfree()\fR frees all such memory, after which \fIpreg\fR may no longer be used as a compiled expression. .SH AUTHOR Philip Hazel .br University Computing Service, .br New Museums Site, .br Cambridge CB2 3QG, England. .br Phone: +44 1223 334714 Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/pcregrep.html000640 001751 001751 00000006776 10546014100 020164 0ustar00fkfk000000 000000 pcregrep specification

    pcregrep specification

    This HTML document has been generated automatically from the original man page. If there is any nonsense in it, please consult the man page in case the conversion went wrong.
  • NAME

    pcregrep - a grep with Perl-compatible regular expressions.

  • SYNOPSIS

    pcregrep [-Vchilnsvx] pattern [file] ...

  • DESCRIPTION

    pcregrep searches files for character patterns, in the same way as other grep commands do, but it uses the PCRE regular expression library to support patterns that are compatible with the regular expressions of Perl 5. See pcre(3) for a full description of syntax and semantics.

    If no files are specified, pcregrep reads the standard input. By default, each line that matches the pattern is copied to the standard output, and if there is more than one file, the file name is printed before each line of output. However, there are options that can change how pcregrep behaves.

    Lines are limited to BUFSIZ characters. BUFSIZ is defined in <stdio.h>. The newline character is removed from the end of each line before it is matched against the pattern.

  • OPTIONS

    -V Write the version number of the PCRE library being used to the standard error stream.

    -c Do not print individual lines; instead just print a count of the number of lines that would otherwise have been printed. If several files are given, a count is printed for each of them.

    -h Suppress printing of filenames when searching multiple files.

    -i Ignore upper/lower case distinctions during comparisons.

    -l Instead of printing lines from the files, just print the names of the files containing lines that would have been printed. Each file name is printed once, on a separate line.

    -n Precede each line by its line number in the file.

    -s Work silently, that is, display nothing except error messages. The exit status indicates whether any matches were found.

    -v Invert the sense of the match, so that lines which do not match the pattern are now the ones that are found.

    -x Force the pattern to be anchored (it must start matching at the beginning of the line) and in addition, require it to match the entire line. This is equivalent to having ^ and $ characters at the start and end of each alternative branch in the regular expression.

  • SEE ALSO

    pcre(3), Perl 5 documentation

  • DIAGNOSTICS

    Exit status is 0 if any matches were found, 1 if no matches were found, and 2 for syntax errors or inacessible files (even if matches were found).

  • AUTHOR

    Philip Hazel <ph10@cam.ac.uk>
    Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/news000640 001751 001751 00000004116 10546014077 016365 0ustar00fkfk000000 000000 News about PCRE releases ------------------------ Release 3.3 01-Aug-00 --------------------- There is some support for UTF-8 character strings. This is incomplete and experimental. The documentation describes what is and what is not implemented. Otherwise, this is just a bug-fixing release. Release 3.0 01-Feb-00 --------------------- 1. A "configure" script is now used to configure PCRE for Unix systems. It builds a Makefile, a config.h file, and the pcre-config script. 2. PCRE is built as a shared library by default. 3. There is support for POSIX classes such as [:alpha:]. 5. There is an experimental recursion feature. ---------------------------------------------------------------------------- IMPORTANT FOR THOSE UPGRADING FROM VERSIONS BEFORE 2.00 Please note that there has been a change in the API such that a larger ovector is required at matching time, to provide some additional workspace. The new man page has details. This change was necessary in order to support some of the new functionality in Perl 5.005. IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.00 Another (I hope this is the last!) change has been made to the API for the pcre_compile() function. An additional argument has been added to make it possible to pass over a pointer to character tables built in the current locale by pcre_maketables(). To use the default tables, this new arguement should be passed as NULL. IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.05 Yet another (and again I hope this really is the last) change has been made to the API for the pcre_exec() function. An additional argument has been added to make it possible to start the match other than at the start of the subject string. This is important if there are lookbehinds. The new man page has the details, but you just want to convert existing programs, all you need to do is to stick in a new fifth argument to pcre_exec(), with a value of zero. For example, change pcre_exec(pattern, extra, subject, length, options, ovec, ovecsize) to pcre_exec(pattern, extra, subject, length, 0, options, ovec, ovecsize) **** privoxy-3.0.21-stable/./pcre/doc/perltest.txt000640 001751 001751 00000002745 10546014100 020062 0ustar00fkfk000000 000000 The perltest program -------------------- The perltest program tests Perl's regular expressions; it has the same specification as pcretest, and so can be given identical input, except that input patterns can be followed only by Perl's lower case modifiers and /+ (as used by pcretest), which is recognized and handled by the program. The data lines are processed as Perl double-quoted strings, so if they contain " \ $ or @ characters, these have to be escaped. For this reason, all such characters in testinput1 and testinput3 are escaped so that they can be used for perltest as well as for pcretest, and the special upper case modifiers such as /A that pcretest recognizes are not used in these files. The output should be identical, apart from the initial identifying banner. For testing UTF-8 features, an alternative form of perltest, called perltest8, is supplied. This requires Perl 5.6 or higher. It recognizes the special modifier /8 that pcretest uses to invoke UTF-8 functionality. The testinput5 file can be fed to perltest8. The testinput2 and testinput4 files are not suitable for feeding to perltest, since they do make use of the special upper case modifiers and escapes that pcretest uses to test some features of PCRE. The first of these files also contains malformed regular expressions, in order to check that PCRE diagnoses them correctly. Similarly, testinput6 tests UTF-8 features that do not relate to Perl. Philip Hazel August 2000 privoxy-3.0.21-stable/./pcre/doc/pcregrep.txt000640 001751 001751 00000005646 10546014100 020032 0ustar00fkfk000000 000000 NAME pcregrep - a grep with Perl-compatible regular expressions. SYNOPSIS pcregrep [-Vchilnsvx] pattern [file] ... DESCRIPTION pcregrep searches files for character patterns, in the same way as other grep commands do, but it uses the PCRE regular expression library to support patterns that are compatible with the regular expressions of Perl 5. See pcre(3) for a full description of syntax and semantics. If no files are specified, pcregrep reads the standard input. By default, each line that matches the pattern is copied to the standard output, and if there is more than one file, the file name is printed before each line of output. However, there are options that can change how pcregrep behaves. Lines are limited to BUFSIZ characters. BUFSIZ is defined in . The newline character is removed from the end of each line before it is matched against the pattern. OPTIONS -V Write the version number of the PCRE library being used to the standard error stream. -c Do not print individual lines; instead just print a count of the number of lines that would other- wise have been printed. If several files are given, a count is printed for each of them. -h Suppress printing of filenames when searching mul- tiple files. -i Ignore upper/lower case distinctions during com- parisons. -l Instead of printing lines from the files, just print the names of the files containing lines that would have been printed. Each file name is printed once, on a separate line. -n Precede each line by its line number in the file. -s Work silently, that is, display nothing except error messages. The exit status indicates whether any matches were found. -v Invert the sense of the match, so that lines which do not match the pattern are now the ones that are found. -x Force the pattern to be anchored (it must start matching at the beginning of the line) and in addition, require it to match the entire line. This is equivalent to having ^ and $ characters at the start and end of each alternative branch in the regular expression. SEE ALSO pcre(3), Perl 5 documentation DIAGNOSTICS Exit status is 0 if any matches were found, 1 if no matches were found, and 2 for syntax errors or inacessible files (even if matches were found). AUTHOR Philip Hazel Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/pcre.3000640 001751 001751 00000247276 10546014100 016506 0ustar00fkfk000000 000000 .TH PCRE 3 .SH NAME pcre - Perl-compatible regular expressions. .SH SYNOPSIS .B #include .PP .SM .br .B pcre *pcre_compile(const char *\fIpattern\fR, int \fIoptions\fR, .ti +5n .B const char **\fIerrptr\fR, int *\fIerroffset\fR, .ti +5n .B const unsigned char *\fItableptr\fR); .PP .br .B pcre_extra *pcre_study(const pcre *\fIcode\fR, int \fIoptions\fR, .ti +5n .B const char **\fIerrptr\fR); .PP .br .B int pcre_exec(const pcre *\fIcode\fR, "const pcre_extra *\fIextra\fR," .ti +5n .B "const char *\fIsubject\fR," int \fIlength\fR, int \fIstartoffset\fR, .ti +5n .B int \fIoptions\fR, int *\fIovector\fR, int \fIovecsize\fR); .PP .br .B int pcre_copy_substring(const char *\fIsubject\fR, int *\fIovector\fR, .ti +5n .B int \fIstringcount\fR, int \fIstringnumber\fR, char *\fIbuffer\fR, .ti +5n .B int \fIbuffersize\fR); .PP .br .B int pcre_get_substring(const char *\fIsubject\fR, int *\fIovector\fR, .ti +5n .B int \fIstringcount\fR, int \fIstringnumber\fR, .ti +5n .B const char **\fIstringptr\fR); .PP .br .B int pcre_get_substring_list(const char *\fIsubject\fR, .ti +5n .B int *\fIovector\fR, int \fIstringcount\fR, "const char ***\fIlistptr\fR);" .PP .br .B void pcre_free_substring(const char *\fIstringptr\fR); .PP .br .B void pcre_free_substring_list(const char **\fIstringptr\fR); .PP .br .B const unsigned char *pcre_maketables(void); .PP .br .B int pcre_fullinfo(const pcre *\fIcode\fR, "const pcre_extra *\fIextra\fR," .ti +5n .B int \fIwhat\fR, void *\fIwhere\fR); .PP .br .B int pcre_info(const pcre *\fIcode\fR, int *\fIoptptr\fR, int .B *\fIfirstcharptr\fR); .PP .br .B char *pcre_version(void); .PP .br .B void *(*pcre_malloc)(size_t); .PP .br .B void (*pcre_free)(void *); .SH DESCRIPTION The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5, with just a few differences (see below). The current implementation corresponds to Perl 5.005, with some additional features from later versions. This includes some experimental, incomplete support for UTF-8 encoded strings. Details of exactly what is and what is not supported are given below. PCRE has its own native API, which is described in this document. There is also a set of wrapper functions that correspond to the POSIX regular expression API. These are described in the \fBpcreposix\fR documentation. The native API function prototypes are defined in the header file \fBpcre.h\fR, and on Unix systems the library itself is called \fBlibpcre.a\fR, so can be accessed by adding \fB-lpcre\fR to the command for linking an application which calls it. The header file defines the macros PCRE_MAJOR and PCRE_MINOR to contain the major and minor release numbers for the library. Applications can use these to include support for different releases. The functions \fBpcre_compile()\fR, \fBpcre_study()\fR, and \fBpcre_exec()\fR are used for compiling and matching regular expressions. The functions \fBpcre_copy_substring()\fR, \fBpcre_get_substring()\fR, and \fBpcre_get_substring_list()\fR are convenience functions for extracting captured substrings from a matched subject string; \fBpcre_free_substring()\fR and \fBpcre_free_substring_list()\fR are also provided, to free the memory used for extracted strings. The function \fBpcre_maketables()\fR is used (optionally) to build a set of character tables in the current locale for passing to \fBpcre_compile()\fR. The function \fBpcre_fullinfo()\fR is used to find out information about a compiled pattern; \fBpcre_info()\fR is an obsolete version which returns only some of the available information, but is retained for backwards compatibility. The function \fBpcre_version()\fR returns a pointer to a string containing the version of PCRE and its date of release. The global variables \fBpcre_malloc\fR and \fBpcre_free\fR initially contain the entry points of the standard \fBmalloc()\fR and \fBfree()\fR functions respectively. PCRE calls the memory management functions via these variables, so a calling program can replace them if it wishes to intercept the calls. This should be done before calling any PCRE functions. .SH MULTI-THREADING The PCRE functions can be used in multi-threading applications, with the proviso that the memory management functions pointed to by \fBpcre_malloc\fR and \fBpcre_free\fR are shared by all threads. The compiled form of a regular expression is not altered during matching, so the same compiled pattern can safely be used by several threads at once. .SH COMPILING A PATTERN The function \fBpcre_compile()\fR is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument \fIpattern\fR. A pointer to a single block of memory that is obtained via \fBpcre_malloc\fR is returned. This contains the compiled code and related data. The \fBpcre\fR type is defined for this for convenience, but in fact \fBpcre\fR is just a typedef for \fBvoid\fR, since the contents of the block are not externally defined. It is up to the caller to free the memory when it is no longer required. .PP The size of a compiled pattern is roughly proportional to the length of the pattern string, except that each character class (other than those containing just a single character, negated or not) requires 33 bytes, and repeat quantifiers with a minimum greater than one or a bounded maximum cause the relevant portions of the compiled pattern to be replicated. .PP The \fIoptions\fR argument contains independent bits that affect the compilation. It should be zero if no options are required. Some of the options, in particular, those that are compatible with Perl, can also be set and unset from within the pattern (see the detailed description of regular expressions below). For these options, the contents of the \fIoptions\fR argument specifies their initial settings at the start of compilation and execution. The PCRE_ANCHORED option can be set at the time of matching as well as at compile time. .PP If \fIerrptr\fR is NULL, \fBpcre_compile()\fR returns NULL immediately. Otherwise, if compilation of a pattern fails, \fBpcre_compile()\fR returns NULL, and sets the variable pointed to by \fIerrptr\fR to point to a textual error message. The offset from the start of the pattern to the character where the error was discovered is placed in the variable pointed to by \fIerroffset\fR, which must not be NULL. If it is, an immediate error is given. .PP If the final argument, \fItableptr\fR, is NULL, PCRE uses a default set of character tables which are built when it is compiled, using the default C locale. Otherwise, \fItableptr\fR must be the result of a call to \fBpcre_maketables()\fR. See the section on locale support below. .PP The following option bits are defined in the header file: PCRE_ANCHORED If this bit is set, the pattern is forced to be "anchored", that is, it is constrained to match only at the start of the string which is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself, which is the only way to do it in Perl. PCRE_CASELESS If this bit is set, letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option. PCRE_DOLLAR_ENDONLY If this bit is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before the final character if it is a newline (but not before any other newlines). The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. There is no equivalent to this option in Perl. PCRE_DOTALL If this bit is set, a dot metacharater in the pattern matches all characters, including newlines. Without it, newlines are excluded. This option is equivalent to Perl's /s option. A negative class such as [^a] always matches a newline character, independent of the setting of this option. PCRE_EXTENDED If this bit is set, whitespace data characters in the pattern are totally ignored except when escaped or inside a character class, and characters between an unescaped # outside a character class and the next newline character, inclusive, are also ignored. This is equivalent to Perl's /x option, and makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence (?( which introduces a conditional subpattern. PCRE_EXTRA This option was invented in order to turn on additional functionality of PCRE that is incompatible with Perl, but it is currently of very little use. When set, any backslash in a pattern that is followed by a letter that has no special meaning causes an error, thus reserving these combinations for future expansion. By default, as in Perl, a backslash followed by a letter with no special meaning is treated as a literal. There are at present no other features controlled by this option. It can also be set by a (?X) option setting within a pattern. PCRE_MULTILINE By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY is set). This is the same as Perl. When PCRE_MULTILINE it is set, the "start of line" and "end of line" constructs match immediately following or immediately before any newline in the subject string, respectively, as well as at the very start and end. This is equivalent to Perl's /m option. If there are no "\\n" characters in a subject string, or no occurrences of ^ or $ in a pattern, setting PCRE_MULTILINE has no effect. PCRE_UNGREEDY This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern. PCRE_UTF8 This option causes PCRE to regard both the pattern and the subject as strings of UTF-8 characters instead of just byte strings. However, it is available only if PCRE has been built to include UTF-8 support. If not, the use of this option provokes an error. Support for UTF-8 is new, experimental, and incomplete. Details of exactly what it entails are given below. .SH STUDYING A PATTERN When a pattern is going to be used several times, it is worth spending more time analyzing it in order to speed up the time taken for matching. The function \fBpcre_study()\fR takes a pointer to a compiled pattern as its first argument, and returns a pointer to a \fBpcre_extra\fR block (another \fBvoid\fR typedef) containing additional information about the pattern; this can be passed to \fBpcre_exec()\fR. If no additional information is available, NULL is returned. The second argument contains option bits. At present, no options are defined for \fBpcre_study()\fR, and this argument should always be zero. The third argument for \fBpcre_study()\fR is a pointer to an error message. If studying succeeds (even if no data is returned), the variable it points to is set to NULL. Otherwise it points to a textual error message. At present, studying a pattern is useful only for non-anchored patterns that do not have a single fixed starting character. A bitmap of possible starting characters is created. .SH LOCALE SUPPORT PCRE handles caseless matching, and determines whether characters are letters, digits, or whatever, by reference to a set of tables. The library contains a default set of tables which is created in the default C locale when PCRE is compiled. This is used when the final argument of \fBpcre_compile()\fR is NULL, and is sufficient for many applications. An alternative set of tables can, however, be supplied. Such tables are built by calling the \fBpcre_maketables()\fR function, which has no arguments, in the relevant locale. The result can then be passed to \fBpcre_compile()\fR as often as necessary. For example, to build and use tables that are appropriate for the French locale (where accented characters with codes greater than 128 are treated as letters), the following code could be used: setlocale(LC_CTYPE, "fr"); tables = pcre_maketables(); re = pcre_compile(..., tables); The tables are built in memory that is obtained via \fBpcre_malloc\fR. The pointer that is passed to \fBpcre_compile\fR is saved with the compiled pattern, and the same tables are used via this pointer by \fBpcre_study()\fR and \fBpcre_exec()\fR. Thus for any single pattern, compilation, studying and matching all happen in the same locale, but different patterns can be compiled in different locales. It is the caller's responsibility to ensure that the memory containing the tables remains available for as long as it is needed. .SH INFORMATION ABOUT A PATTERN The \fBpcre_fullinfo()\fR function returns information about a compiled pattern. It replaces the obsolete \fBpcre_info()\fR function, which is nevertheless retained for backwards compability (and is documented below). The first argument for \fBpcre_fullinfo()\fR is a pointer to the compiled pattern. The second argument is the result of \fBpcre_study()\fR, or NULL if the pattern was not studied. The third argument specifies which piece of information is required, while the fourth argument is a pointer to a variable to receive the data. The yield of the function is zero for success, or one of the following negative numbers: PCRE_ERROR_NULL the argument \fIcode\fR was NULL the argument \fIwhere\fR was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found PCRE_ERROR_BADOPTION the value of \fIwhat\fR was invalid The possible values for the third argument are defined in \fBpcre.h\fR, and are as follows: PCRE_INFO_OPTIONS Return a copy of the options with which the pattern was compiled. The fourth argument should point to au \fBunsigned long int\fR variable. These option bits are those specified in the call to \fBpcre_compile()\fR, modified by any top-level option settings within the pattern itself, and with the PCRE_ANCHORED bit forcibly set if the form of the pattern implies that it can match only at the start of a subject string. PCRE_INFO_SIZE Return the size of the compiled pattern, that is, the value that was passed as the argument to \fBpcre_malloc()\fR when PCRE was getting memory in which to place the compiled data. The fourth argument should point to a \fBsize_t\fR variable. PCRE_INFO_CAPTURECOUNT Return the number of capturing subpatterns in the pattern. The fourth argument should point to an \fbint\fR variable. PCRE_INFO_BACKREFMAX Return the number of the highest back reference in the pattern. The fourth argument should point to an \fBint\fR variable. Zero is returned if there are no back references. PCRE_INFO_FIRSTCHAR Return information about the first character of any matched string, for a non-anchored pattern. If there is a fixed first character, e.g. from a pattern such as (cat|cow|coyote), it is returned in the integer pointed to by \fIwhere\fR. Otherwise, if either (a) the pattern was compiled with the PCRE_MULTILINE option, and every branch starts with "^", or (b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not set (if it were set, the pattern would be anchored), -1 is returned, indicating that the pattern matches only at the start of a subject string or after any "\\n" within the string. Otherwise -2 is returned. For anchored patterns, -2 is returned. PCRE_INFO_FIRSTTABLE If the pattern was studied, and this resulted in the construction of a 256-bit table indicating a fixed set of characters for the first character in any matching string, a pointer to the table is returned. Otherwise NULL is returned. The fourth argument should point to an \fBunsigned char *\fR variable. PCRE_INFO_LASTLITERAL For a non-anchored pattern, return the value of the rightmost literal character which must exist in any matched string, other than at its start. The fourth argument should point to an \fBint\fR variable. If there is no such character, or if the pattern is anchored, -1 is returned. For example, for the pattern /a\\d+z\\d+/ the returned value is 'z'. The \fBpcre_info()\fR function is now obsolete because its interface is too restrictive to return all the available data about a compiled pattern. New programs should use \fBpcre_fullinfo()\fR instead. The yield of \fBpcre_info()\fR is the number of capturing subpatterns, or one of the following negative numbers: PCRE_ERROR_NULL the argument \fIcode\fR was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found If the \fIoptptr\fR argument is not NULL, a copy of the options with which the pattern was compiled is placed in the integer it points to (see PCRE_INFO_OPTIONS above). If the pattern is not anchored and the \fIfirstcharptr\fR argument is not NULL, it is used to pass back information about the first character of any matched string (see PCRE_INFO_FIRSTCHAR above). .SH MATCHING A PATTERN The function \fBpcre_exec()\fR is called to match a subject string against a pre-compiled pattern, which is passed in the \fIcode\fR argument. If the pattern has been studied, the result of the study should be passed in the \fIextra\fR argument. Otherwise this must be NULL. The PCRE_ANCHORED option can be passed in the \fIoptions\fR argument, whose unused bits must be zero. However, if a pattern was compiled with PCRE_ANCHORED, or turned out to be anchored by virtue of its contents, it cannot be made unachored at matching time. There are also three further options that can be set only at matching time: PCRE_NOTBOL The first character of the string is not the beginning of a line, so the circumflex metacharacter should not match before it. Setting this without PCRE_MULTILINE (at compile time) causes circumflex never to match. PCRE_NOTEOL The end of the string is not the end of a line, so the dollar metacharacter should not match it nor (except in multiline mode) a newline immediately before it. Setting this without PCRE_MULTILINE (at compile time) causes dollar never to match. PCRE_NOTEMPTY An empty string is not considered to be a valid match if this option is set. If there are alternatives in the pattern, they are tried. If all the alternatives match the empty string, the entire match fails. For example, if the pattern a?b? is applied to a string not beginning with "a" or "b", it matches the empty string at the start of the subject. With PCRE_NOTEMPTY set, this match is not valid, so PCRE searches further into the string for occurrences of "a" or "b". Perl has no direct equivalent of PCRE_NOTEMPTY, but it does make a special case of a pattern match of the empty string within its \fBsplit()\fR function, and when using the /g modifier. It is possible to emulate Perl's behaviour after matching a null string by first trying the match again at the same offset with PCRE_NOTEMPTY set, and then if that fails by advancing the starting offset (see below) and trying an ordinary match again. The subject string is passed as a pointer in \fIsubject\fR, a length in \fIlength\fR, and a starting offset in \fIstartoffset\fR. Unlike the pattern string, it may contain binary zero characters. When the starting offset is zero, the search for a match starts at the beginning of the subject, and this is by far the most common case. A non-zero starting offset is useful when searching for another match in the same subject by calling \fBpcre_exec()\fR again after a previous success. Setting \fIstartoffset\fR differs from just passing over a shortened string and setting PCRE_NOTBOL in the case of a pattern that begins with any kind of lookbehind. For example, consider the pattern \\Biss\\B which finds occurrences of "iss" in the middle of words. (\\B matches only if the current position in the subject is not a word boundary.) When applied to the string "Mississipi" the first call to \fBpcre_exec()\fR finds the first occurrence. If \fBpcre_exec()\fR is called again with just the remainder of the subject, namely "issipi", it does not match, because \\B is always false at the start of the subject, which is deemed to be a word boundary. However, if \fBpcre_exec()\fR is passed the entire string again, but with \fIstartoffset\fR set to 4, it finds the second occurrence of "iss" because it is able to look behind the starting point to discover that it is preceded by a letter. If a non-zero starting offset is passed when the pattern is anchored, one attempt to match at the given offset is tried. This can only succeed if the pattern does not require the match to be at the start of the subject. In general, a pattern matches a certain portion of the subject, and in addition, further substrings from the subject may be picked out by parts of the pattern. Following the usage in Jeffrey Friedl's book, this is called "capturing" in what follows, and the phrase "capturing subpattern" is used for a fragment of a pattern that picks out a substring. PCRE supports several other kinds of parenthesized subpattern that do not cause substrings to be captured. Captured substrings are returned to the caller via a vector of integer offsets whose address is passed in \fIovector\fR. The number of elements in the vector is passed in \fIovecsize\fR. The first two-thirds of the vector is used to pass back captured substrings, each substring using a pair of integers. The remaining third of the vector is used as workspace by \fBpcre_exec()\fR while matching capturing subpatterns, and is not available for passing back information. The length passed in \fIovecsize\fR should always be a multiple of three. If it is not, it is rounded down. When a match has been successful, information about captured substrings is returned in pairs of integers, starting at the beginning of \fIovector\fR, and continuing up to two-thirds of its length at the most. The first element of a pair is set to the offset of the first character in a substring, and the second is set to the offset of the first character after the end of a substring. The first pair, \fIovector[0]\fR and \fIovector[1]\fR, identify the portion of the subject string matched by the entire pattern. The next pair is used for the first capturing subpattern, and so on. The value returned by \fBpcre_exec()\fR is the number of pairs that have been set. If there are no capturing subpatterns, the return value from a successful match is 1, indicating that just the first pair of offsets has been set. Some convenience functions are provided for extracting the captured substrings as separate strings. These are described in the following section. It is possible for an capturing subpattern number \fIn+1\fR to match some part of the subject when subpattern \fIn\fR has not been used at all. For example, if the string "abc" is matched against the pattern (a|(z))(bc) subpatterns 1 and 3 are matched, but 2 is not. When this happens, both offset values corresponding to the unused subpattern are set to -1. If a capturing subpattern is matched repeatedly, it is the last portion of the string that it matched that gets returned. If the vector is too small to hold all the captured substrings, it is used as far as possible (up to two-thirds of its length), and the function returns a value of zero. In particular, if the substring offsets are not of interest, \fBpcre_exec()\fR may be called with \fIovector\fR passed as NULL and \fIovecsize\fR as zero. However, if the pattern contains back references and the \fIovector\fR isn't big enough to remember the related substrings, PCRE has to get additional memory for use during matching. Thus it is usually advisable to supply an \fIovector\fR. Note that \fBpcre_info()\fR can be used to find out how many capturing subpatterns there are in a compiled pattern. The smallest size for \fIovector\fR that will allow for \fIn\fR captured substrings in addition to the offsets of the substring matched by the whole pattern is (\fIn\fR+1)*3. If \fBpcre_exec()\fR fails, it returns a negative number. The following are defined in the header file: PCRE_ERROR_NOMATCH (-1) The subject string did not match the pattern. PCRE_ERROR_NULL (-2) Either \fIcode\fR or \fIsubject\fR was passed as NULL, or \fIovector\fR was NULL and \fIovecsize\fR was not zero. PCRE_ERROR_BADOPTION (-3) An unrecognized bit was set in the \fIoptions\fR argument. PCRE_ERROR_BADMAGIC (-4) PCRE stores a 4-byte "magic number" at the start of the compiled code, to catch the case when it is passed a junk pointer. This is the error it gives when the magic number isn't present. PCRE_ERROR_UNKNOWN_NODE (-5) While running the pattern match, an unknown item was encountered in the compiled pattern. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern. PCRE_ERROR_NOMEMORY (-6) If a pattern contains back references, but the \fIovector\fR that is passed to \fBpcre_exec()\fR is not big enough to remember the referenced substrings, PCRE gets a block of memory at the start of matching to use for this purpose. If the call via \fBpcre_malloc()\fR fails, this error is given. The memory is freed at the end of matching. .SH EXTRACTING CAPTURED SUBSTRINGS Captured substrings can be accessed directly by using the offsets returned by \fBpcre_exec()\fR in \fIovector\fR. For convenience, the functions \fBpcre_copy_substring()\fR, \fBpcre_get_substring()\fR, and \fBpcre_get_substring_list()\fR are provided for extracting captured substrings as new, separate, zero-terminated strings. A substring that contains a binary zero is correctly extracted and has a further zero added on the end, but the result does not, of course, function as a C string. The first three arguments are the same for all three functions: \fIsubject\fR is the subject string which has just been successfully matched, \fIovector\fR is a pointer to the vector of integer offsets that was passed to \fBpcre_exec()\fR, and \fIstringcount\fR is the number of substrings that were captured by the match, including the substring that matched the entire regular expression. This is the value returned by \fBpcre_exec\fR if it is greater than zero. If \fBpcre_exec()\fR returned zero, indicating that it ran out of space in \fIovector\fR, the value passed as \fIstringcount\fR should be the size of the vector divided by three. The functions \fBpcre_copy_substring()\fR and \fBpcre_get_substring()\fR extract a single substring, whose number is given as \fIstringnumber\fR. A value of zero extracts the substring that matched the entire pattern, while higher values extract the captured substrings. For \fBpcre_copy_substring()\fR, the string is placed in \fIbuffer\fR, whose length is given by \fIbuffersize\fR, while for \fBpcre_get_substring()\fR a new block of memory is obtained via \fBpcre_malloc\fR, and its address is returned via \fIstringptr\fR. The yield of the function is the length of the string, not including the terminating zero, or one of PCRE_ERROR_NOMEMORY (-6) The buffer was too small for \fBpcre_copy_substring()\fR, or the attempt to get memory failed for \fBpcre_get_substring()\fR. PCRE_ERROR_NOSUBSTRING (-7) There is no substring whose number is \fIstringnumber\fR. The \fBpcre_get_substring_list()\fR function extracts all available substrings and builds a list of pointers to them. All this is done in a single block of memory which is obtained via \fBpcre_malloc\fR. The address of the memory block is returned via \fIlistptr\fR, which is also the start of the list of string pointers. The end of the list is marked by a NULL pointer. The yield of the function is zero if all went well, or PCRE_ERROR_NOMEMORY (-6) if the attempt to get the memory block failed. When any of these functions encounter a substring that is unset, which can happen when capturing subpattern number \fIn+1\fR matches some part of the subject, but subpattern \fIn\fR has not been used at all, they return an empty string. This can be distinguished from a genuine zero-length substring by inspecting the appropriate offset in \fIovector\fR, which is negative for unset substrings. The two convenience functions \fBpcre_free_substring()\fR and \fBpcre_free_substring_list()\fR can be used to free the memory returned by a previous call of \fBpcre_get_substring()\fR or \fBpcre_get_substring_list()\fR, respectively. They do nothing more than call the function pointed to by \fBpcre_free\fR, which of course could be called directly from a C program. However, PCRE is used in some situations where it is linked via a special interface to another programming language which cannot use \fBpcre_free\fR directly; it is for these cases that the functions are provided. .SH LIMITATIONS There are some size limitations in PCRE but it is hoped that they will never in practice be relevant. The maximum length of a compiled pattern is 65539 (sic) bytes. All values in repeating quantifiers must be less than 65536. The maximum number of capturing subpatterns is 99. The maximum number of all parenthesized subpatterns, including capturing subpatterns, assertions, and other types of subpattern, is 200. The maximum length of a subject string is the largest positive number that an integer variable can hold. However, PCRE uses recursion to handle subpatterns and indefinite repetition. This means that the available stack space may limit the size of a subject string that can be processed by certain patterns. .SH DIFFERENCES FROM PERL The differences described here are with respect to Perl 5.005. 1. By default, a whitespace character is any character that the C library function \fBisspace()\fR recognizes, though it is possible to compile PCRE with alternative character type tables. Normally \fBisspace()\fR matches space, formfeed, newline, carriage return, horizontal tab, and vertical tab. Perl 5 no longer includes vertical tab in its set of whitespace characters. The \\v escape that was in the Perl documentation for a long time was never in fact recognized. However, the character itself was treated as whitespace at least up to 5.002. In 5.004 and 5.005 it does not match \\s. 2. PCRE does not allow repeat quantifiers on lookahead assertions. Perl permits them, but they do not mean what you might think. For example, (?!a){3} does not assert that the next three characters are not "a". It just asserts that the next character is not "a" three times. 3. Capturing subpatterns that occur inside negative lookahead assertions are counted, but their entries in the offsets vector are never set. Perl sets its numerical variables from any such patterns that are matched before the assertion fails to match something (thereby succeeding), but only if the negative lookahead assertion contains just one branch. 4. Though binary zero characters are supported in the subject string, they are not allowed in a pattern string because it is passed as a normal C string, terminated by zero. The escape sequence "\\0" can be used in the pattern to represent a binary zero. 5. The following Perl escape sequences are not supported: \\l, \\u, \\L, \\U, \\E, \\Q. In fact these are implemented by Perl's general string-handling and are not part of its pattern matching engine. 6. The Perl \\G assertion is not supported as it is not relevant to single pattern matches. 7. Fairly obviously, PCRE does not support the (?{code}) and (?p{code}) constructions. However, there is some experimental support for recursive patterns using the non-Perl item (?R). 8. There are at the time of writing some oddities in Perl 5.005_02 concerned with the settings of captured strings when part of a pattern is repeated. For example, matching "aba" against the pattern /^(a(b)?)+$/ sets $2 to the value "b", but matching "aabbaa" against /^(aa(bb)?)+$/ leaves $2 unset. However, if the pattern is changed to /^(aa(b(b))?)+$/ then $2 (and $3) are set. In Perl 5.004 $2 is set in both cases, and that is also true of PCRE. If in the future Perl changes to a consistent state that is different, PCRE may change to follow. 9. Another as yet unresolved discrepancy is that in Perl 5.005_02 the pattern /^(a)?(?(1)a|b)+$/ matches the string "a", whereas in PCRE it does not. However, in both Perl and PCRE /^(a)?a/ matched against "a" leaves $1 unset. 10. PCRE provides some extensions to the Perl regular expression facilities: (a) Although lookbehind assertions must match fixed length strings, each alternative branch of a lookbehind assertion can match a different length of string. Perl 5.005 requires them all to have the same length. (b) If PCRE_DOLLAR_ENDONLY is set and PCRE_MULTILINE is not set, the $ meta- character matches only at the very end of the string. (c) If PCRE_EXTRA is set, a backslash followed by a letter with no special meaning is faulted. (d) If PCRE_UNGREEDY is set, the greediness of the repetition quantifiers is inverted, that is, by default they are not greedy, but if followed by a question mark they are. (e) PCRE_ANCHORED can be used to force a pattern to be tried only at the start of the subject. (f) The PCRE_NOTBOL, PCRE_NOTEOL, and PCRE_NOTEMPTY options for \fBpcre_exec()\fR have no Perl equivalents. (g) The (?R) construct allows for recursive pattern matching (Perl 5.6 can do this using the (?p{code}) construct, which PCRE cannot of course support.) .SH REGULAR EXPRESSION DETAILS The syntax and semantics of the regular expressions supported by PCRE are described below. Regular expressions are also described in the Perl documentation and in a number of other books, some of which have copious examples. Jeffrey Friedl's "Mastering Regular Expressions", published by O'Reilly (ISBN 1-56592-257), covers them in great detail. The description here is intended as reference documentation. The basic operation of PCRE is on strings of bytes. However, there is the beginnings of some support for UTF-8 character strings. To use this support you must configure PCRE to include it, and then call \fBpcre_compile()\fR with the PCRE_UTF8 option. How this affects the pattern matching is described in the final section of this document. A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and match the corresponding characters in the subject. As a trivial example, the pattern The quick brown fox matches a portion of a subject string that is identical to itself. The power of regular expressions comes from the ability to include alternatives and repetitions in the pattern. These are encoded in the pattern by the use of \fImeta-characters\fR, which do not stand for themselves but instead are interpreted in some special way. There are two different sets of meta-characters: those that are recognized anywhere in the pattern except within square brackets, and those that are recognized in square brackets. Outside square brackets, the meta-characters are as follows: \\ general escape character with several uses ^ assert start of subject (or line, in multiline mode) $ assert end of subject (or line, in multiline mode) . match any character except newline (by default) [ start character class definition | start of alternative branch ( start subpattern ) end subpattern ? extends the meaning of ( also 0 or 1 quantifier also quantifier minimizer * 0 or more quantifier + 1 or more quantifier { start min/max quantifier Part of a pattern that is in square brackets is called a "character class". In a character class the only meta-characters are: \\ general escape character ^ negate the class, but only if the first character - indicates character range ] terminates the character class The following sections describe the use of each of the meta-characters. .SH BACKSLASH The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes. For example, if you want to match a "*" character, you write "\\*" in the pattern. This applies whether or not the following character would otherwise be interpreted as a meta-character, so it is always safe to precede a non-alphameric with "\\" to specify that it stands for itself. In particular, if you want to match a backslash, you write "\\\\". If a pattern is compiled with the PCRE_EXTENDED option, whitespace in the pattern (other than in a character class) and characters between a "#" outside a character class and the next newline character are ignored. An escaping backslash can be used to include a whitespace or "#" character as part of the pattern. A second use of backslash provides a way of encoding non-printing characters in patterns in a visible manner. There is no restriction on the appearance of non-printing characters, apart from the binary zero that terminates a pattern, but when a pattern is being prepared by text editing, it is usually easier to use one of the following escape sequences than the binary character it represents: \\a alarm, that is, the BEL character (hex 07) \\cx "control-x", where x is any character \\e escape (hex 1B) \\f formfeed (hex 0C) \\n newline (hex 0A) \\r carriage return (hex 0D) \\t tab (hex 09) \\xhh character with hex code hh \\ddd character with octal code ddd, or backreference The precise effect of "\\cx" is as follows: if "x" is a lower case letter, it is converted to upper case. Then bit 6 of the character (hex 40) is inverted. Thus "\\cz" becomes hex 1A, but "\\c{" becomes hex 3B, while "\\c;" becomes hex 7B. After "\\x", up to two hexadecimal digits are read (letters can be in upper or lower case). After "\\0" up to two further octal digits are read. In both cases, if there are fewer than two digits, just those that are present are used. Thus the sequence "\\0\\x\\07" specifies two binary zeros followed by a BEL character. Make sure you supply two digits after the initial zero if the character that follows is itself an octal digit. The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a \fIback reference\fR. A description of how this works is given later, following the discussion of parenthesized subpatterns. Inside a character class, or if the decimal number is greater than 9 and there have not been that many capturing subpatterns, PCRE re-reads up to three octal digits following the backslash, and generates a single byte from the least significant 8 bits of the value. Any subsequent digits stand for themselves. For example: \\040 is another way of writing a space \\40 is the same, provided there are fewer than 40 previous capturing subpatterns \\7 is always a back reference \\11 might be a back reference, or another way of writing a tab \\011 is always a tab \\0113 is a tab followed by the character "3" \\113 is the character with octal code 113 (since there can be no more than 99 back references) \\377 is a byte consisting entirely of 1 bits \\81 is either a back reference, or a binary zero followed by the two characters "8" and "1" Note that octal values of 100 or greater must not be introduced by a leading zero, because no more than three octal digits are ever read. All the sequences that define a single byte value can be used both inside and outside character classes. In addition, inside a character class, the sequence "\\b" is interpreted as the backspace character (hex 08). Outside a character class it has a different meaning (see below). The third use of backslash is for specifying generic character types: \\d any decimal digit \\D any character that is not a decimal digit \\s any whitespace character \\S any character that is not a whitespace character \\w any "word" character \\W any "non-word" character Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair. A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is controlled by PCRE's character tables, and may vary if locale- specific matching is taking place (see "Locale support" above). For example, in the "fr" (French) locale, some character codes greater than 128 are used for accented letters, and these are matched by \\w. These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match. The fourth use of backslash is for certain simple assertions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are \\b word boundary \\B not a word boundary \\A start of subject (independent of multiline mode) \\Z end of subject or newline at end (independent of multiline mode) \\z end of subject (independent of multiline mode) These assertions may not appear in character classes (but note that "\\b" has a different meaning, namely the backspace character, inside a character class). A word boundary is a position in the subject string where the current character and the previous character do not both match \\w or \\W (i.e. one matches \\w and the other matches \\W), or the start or end of the string if the first or last character matches \\w, respectively. The \\A, \\Z, and \\z assertions differ from the traditional circumflex and dollar (described below) in that they only ever match at the very start and end of the subject string, whatever options are set. They are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options. If the \fIstartoffset\fR argument of \fBpcre_exec()\fR is non-zero, \\A can never match. The difference between \\Z and \\z is that \\Z matches before a newline that is the last character of the string as well as at the end of the string, whereas \\z matches only at the end. .SH CIRCUMFLEX AND DOLLAR Outside a character class, in the default matching mode, the circumflex character is an assertion which is true only if the current matching point is at the start of the subject string. If the \fIstartoffset\fR argument of \fBpcre_exec()\fR is non-zero, circumflex can never match. Inside a character class, circumflex has an entirely different meaning (see below). Circumflex need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alternatives start with a circumflex, that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other constructs that can cause a pattern to be anchored.) A dollar character is an assertion which is true only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class. The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at compile or matching time. This does not affect the \\Z assertion. The meanings of the circumflex and dollar characters are changed if the PCRE_MULTILINE option is set. When this is the case, they match immediately after and immediately before an internal "\\n" character, respectively, in addition to matching at the start and end of the subject string. For example, the pattern /^abc$/ matches the subject string "def\\nabc" in multiline mode, but not otherwise. Consequently, patterns that are anchored in single line mode because all branches start with "^" are not anchored in multiline mode, and a match for circumflex is possible when the \fIstartoffset\fR argument of \fBpcre_exec()\fR is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. Note that the sequences \\A, \\Z, and \\z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with \\A is it always anchored, whether PCRE_MULTILINE is set or not. .SH FULL STOP (PERIOD, DOT) Outside a character class, a dot in the pattern matches any one character in the subject, including a non-printing character, but not (by default) newline. If the PCRE_DOTALL option is set, dots match newlines as well. The handling of dot is entirely independent of the handling of circumflex and dollar, the only relationship being that they both involve newline characters. Dot has no special meaning in a character class. .SH SQUARE BRACKETS An opening square bracket introduces a character class, terminated by a closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, it should be the first data character in the class (after an initial circumflex, if present) or escaped with a backslash. A character class matches a single character in the subject; the character must be in the set of characters defined by the class, unless the first character in the class is a circumflex, in which case the subject character must not be in the set defined by the class. If a circumflex is actually required as a member of the class, ensure it is not the first character, or escape it with a backslash. For example, the character class [aeiou] matches any lower case vowel, while [^aeiou] matches any character that is not a lower case vowel. Note that a circumflex is just a convenient notation for specifying the characters which are in the class by enumerating those that are not. It is not an assertion: it still consumes a character from the subject string, and fails if the current pointer is at the end of the string. When caseless matching is set, any letters in a class represent both their upper case and lower case versions, so for example, a caseless [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a caseful version would. The newline character is never treated in any special way in character classes, whatever the setting of the PCRE_DOTALL or PCRE_MULTILINE options is. A class such as [^a] will always match a newline. The minus (hyphen) character can be used to specify a range of characters in a character class. For example, [d-m] matches any letter between d and m, inclusive. If a minus character is required in a class, it must be escaped with a backslash or appear in a position where it cannot be interpreted as indicating a range, typically as the first or last character in the class. It is not possible to have the literal character "]" as the end character of a range. A pattern such as [W-]46] is interpreted as a class of two characters ("W" and "-") followed by a literal string "46]", so it would match "W46]" or "-46]". However, if the "]" is escaped with a backslash it is interpreted as the end of range, so [W-\\]46] is interpreted as a single class containing a range followed by two separate characters. The octal or hexadecimal representation of "]" can also be used to end a range. Ranges operate in ASCII collating sequence. They can also be used for characters specified numerically, for example [\\000-\\037]. If a range that includes letters is used when caseless matching is set, it matches the letters in either case. For example, [W-c] is equivalent to [][\\^_`wxyzabc], matched caselessly, and if character tables for the "fr" locale are in use, [\\xc8-\\xcb] matches accented E characters in both cases. The character types \\d, \\D, \\s, \\S, \\w, and \\W may also appear in a character class, and add the characters that they match to the class. For example, [\\dABCDEF] matches any hexadecimal digit. A circumflex can conveniently be used with the upper case character types to specify a more restricted set of characters than the matching lower case type. For example, the class [^\\W_] matches any letter or digit, but not underscore. All non-alphameric characters other than \\, -, ^ (at the start) and the terminating ] are non-special in character classes, but it does no harm if they are escaped. .SH POSIX CHARACTER CLASSES Perl 5.6 (not yet released at the time of writing) is going to support the POSIX notation for character classes, which uses names enclosed by [: and :] within the enclosing square brackets. PCRE supports this notation. For example, [01[:alpha:]%] matches "0", "1", any alphabetic character, or "%". The supported class names are alnum letters and digits alpha letters ascii character codes 0 - 127 cntrl control characters digit decimal digits (same as \\d) graph printing characters, excluding space lower lower case letters print printing characters, including space punct printing characters, excluding letters and digits space white space (same as \\s) upper upper case letters word "word" characters (same as \\w) xdigit hexadecimal digits The names "ascii" and "word" are Perl extensions. Another Perl extension is negation, which is indicated by a ^ character after the colon. For example, [12[:^digit:]] matches "1", "2", or any non-digit. PCRE (and Perl) also recogize the POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not supported, and an error is given if they are encountered. .SH VERTICAL BAR Vertical bar characters are used to separate alternative patterns. For example, the pattern gilbert|sullivan matches either "gilbert" or "sullivan". Any number of alternatives may appear, and an empty alternative is permitted (matching the empty string). The matching process tries each alternative in turn, from left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern. .SH INTERNAL OPTION SETTING The settings of PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and PCRE_EXTENDED can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")". The option letters are i for PCRE_CASELESS m for PCRE_MULTILINE s for PCRE_DOTALL x for PCRE_EXTENDED For example, (?im) sets caseless, multiline matching. It is also possible to unset these options by preceding the letter with a hyphen, and a combined setting and unsetting such as (?im-sx), which sets PCRE_CASELESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, is also permitted. If a letter appears both before and after the hyphen, the option is unset. The scope of these option changes depends on where in the pattern the setting occurs. For settings that are outside any subpattern (defined below), the effect is the same as if the options were set or unset at the start of matching. The following patterns all behave in exactly the same way: (?i)abc a(?i)bc ab(?i)c abc(?i) which in turn is the same as compiling the pattern abc with PCRE_CASELESS set. In other words, such "top level" settings apply to the whole pattern (unless there are other changes inside subpatterns). If there is more than one setting of the same option at top level, the rightmost setting is used. If an option change occurs inside a subpattern, the effect is different. This is a change of behaviour in Perl 5.005. An option change inside a subpattern affects only that part of the subpattern that follows it, so (a(?i)b)c matches abc and aBc and no other strings (assuming PCRE_CASELESS is not used). By this means, options can be made to have different settings in different parts of the pattern. Any changes made in one alternative do carry on into subsequent branches within the same subpattern. For example, (a(?i)b|c) matches "ab", "aB", "c", and "C", even though when matching "C" the first branch is abandoned before the option setting. This is because the effects of option settings happen at compile time. There would be some very weird behaviour otherwise. The PCRE-specific options PCRE_UNGREEDY and PCRE_EXTRA can be changed in the same way as the Perl-compatible options by using the characters U and X respectively. The (?X) flag setting is special in that it must always occur earlier in the pattern than any of the additional features it turns on, even when it is at top level. It is best put at the start. .SH SUBPATTERNS Subpatterns are delimited by parentheses (round brackets), which can be nested. Marking part of a pattern as a subpattern does two things: 1. It localizes a set of alternatives. For example, the pattern cat(aract|erpillar|) matches one of the words "cat", "cataract", or "caterpillar". Without the parentheses, it would match "cataract", "erpillar" or the empty string. 2. It sets up the subpattern as a capturing subpattern (as defined above). When the whole pattern matches, that portion of the subject string that matched the subpattern is passed back to the caller via the \fIovector\fR argument of \fBpcre_exec()\fR. Opening parentheses are counted from left to right (starting from 1) to obtain the numbers of the capturing subpatterns. For example, if the string "the red king" is matched against the pattern the ((red|white) (king|queen)) the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3. The fact that plain parentheses fulfil two functions is not always helpful. There are often times when a grouping subpattern is required without a capturing requirement. If an opening parenthesis is followed by "?:", the subpattern does not do any capturing, and is not counted when computing the number of any subsequent capturing subpatterns. For example, if the string "the white queen" is matched against the pattern the ((?:red|white) (king|queen)) the captured substrings are "white queen" and "queen", and are numbered 1 and 2. The maximum number of captured substrings is 99, and the maximum number of all subpatterns, both capturing and non-capturing, is 200. As a convenient shorthand, if any option settings are required at the start of a non-capturing subpattern, the option letters may appear between the "?" and the ":". Thus the two patterns (?i:saturday|sunday) (?:(?i)saturday|sunday) match exactly the same set of strings. Because alternative branches are tried from left to right, and options are not reset until the end of the subpattern is reached, an option setting in one branch does affect subsequent branches, so the above patterns match "SUNDAY" as well as "Saturday". .SH REPETITION Repetition is specified by quantifiers, which can follow any of the following items: a single character, possibly escaped the . metacharacter a character class a back reference (see next section) a parenthesized subpattern (unless it is an assertion - see below) The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example: z{2,4} matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special character. If the second number is omitted, but the comma is present, there is no upper limit; if the second number and the comma are both omitted, the quantifier specifies an exact number of required matches. Thus [aeiou]{3,} matches at least 3 successive vowels, but may match many more, while \\d{8} matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantifier, but a literal string of four characters. The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present. For convenience (and historical compatibility) the three most common quantifiers have single-character abbreviations: * is equivalent to {0,} + is equivalent to {1,} ? is equivalent to {0,1} It is possible to construct infinite loops by following a subpattern that can match no characters with a quantifier that has no upper limit, for example: (a?)* Earlier versions of Perl and PCRE used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but if any repetition of the subpattern does in fact match no characters, the loop is forcibly broken. By default, the quantifiers are "greedy", that is, they match as much as possible (up to the maximum number of permitted times), without causing the rest of the pattern to fail. The classic example of where this gives problems is in trying to match comments in C programs. These appear between the sequences /* and */ and within the sequence, individual * and / characters may appear. An attempt to match C comments by applying the pattern /\\*.*\\*/ to the string /* first command */ not comment /* second comment */ fails, because it matches the entire string owing to the greediness of the .* item. However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern /\\*.*?\\*/ does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the preferred number of matches. Do not confuse this use of question mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in \\d??\\d which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches. If the PCRE_UNGREEDY option is set (an option which is not available in Perl), the quantifiers are not greedy by default, but individual ones can be made greedy by following them with a question mark. In other words, it inverts the default behaviour. When a parenthesized subpattern is quantified with a minimum repeat count that is greater than 1 or with a limited maximum, more store is required for the compiled pattern, in proportion to the size of the minimum or maximum. If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equivalent to Perl's /s) is set, thus allowing the . to match newlines, the pattern is implicitly anchored, because whatever follows will be tried against every character position in the subject string, so there is no point in retrying the overall match at any position after the first. PCRE treats such a pattern as though it were preceded by \\A. In cases where it is known that the subject string contains no newlines, it is worth setting PCRE_DOTALL when the pattern begins with .* in order to obtain this optimization, or alternatively using ^ to indicate anchoring explicitly. When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For example, after (tweedle[dume]{3}\\s*)+ has matched "tweedledum tweedledee" the value of the captured substring is "tweedledee". However, if there are nested capturing subpatterns, the corresponding captured values may have been set in previous iterations. For example, after /(a|(b))+/ matches "aba" the value of the second captured substring is "b". .SH BACK REFERENCES Outside a character class, a backslash followed by a digit greater than 0 (and possibly further digits) is a back reference to a capturing subpattern earlier (i.e. to its left) in the pattern, provided there have been that many previous capturing left parentheses. However, if the decimal number following the backslash is less than 10, it is always taken as a back reference, and causes an error only if there are not that many capturing left parentheses in the entire pattern. In other words, the parentheses that are referenced need not be to the left of the reference for numbers less than 10. See the section entitled "Backslash" above for further details of the handling of digits following a backslash. A back reference matches whatever actually matched the capturing subpattern in the current subject string, rather than anything matching the subpattern itself. So the pattern (sens|respons)e and \\1ibility matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example, ((?i)rah)\\s+\\1 matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched caselessly. There may be more than one back reference to the same subpattern. If a subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern (a|(bc))\\2 always fails if it starts to match "a" rather than "bc". Because there may be up to 99 back references, all digits following the backslash are taken as part of a potential back reference number. If the pattern continues with a digit character, some delimiter must be used to terminate the back reference. If the PCRE_EXTENDED option is set, this can be whitespace. Otherwise an empty comment can be used. A back reference that occurs inside the parentheses to which it refers fails when the subpattern is first used, so, for example, (a\\1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pattern (a|b\\1)+ matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding to the previous iteration. In order for this to work, the pattern must be such that the first iteration does not need to match the back reference. This can be done using alternation, as in the example above, or by a quantifier with a minimum of zero. .SH ASSERTIONS An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters. The simple assertions coded as \\b, \\B, \\A, \\Z, \\z, ^ and $ are described above. More complicated assertions are coded as subpatterns. There are two kinds: those that look ahead of the current position in the subject string, and those that look behind it. An assertion subpattern is matched in the normal way, except that it does not cause the current matching position to be changed. Lookahead assertions start with (?= for positive assertions and (?! for negative assertions. For example, \\w+(?=;) matches a word followed by a semicolon, but does not include the semicolon in the match, and foo(?!bar) matches any occurrence of "foo" that is not followed by "bar". Note that the apparently similar pattern (?!foo)bar does not find an occurrence of "bar" that is preceded by something other than "foo"; it finds any occurrence of "bar" whatsoever, because the assertion (?!foo) is always true when the next three characters are "bar". A lookbehind assertion is needed to achieve this effect. Lookbehind assertions start with (?<= for positive assertions and (? as in this example: (?>\\d+)bar This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from backtracking into it. Backtracking past it to previous items, however, works as normal. An alternative description is that a subpattern of this type matches the string of characters that an identical standalone pattern would match, if anchored at the current point in the subject string. Once-only subpatterns are not capturing subpatterns. Simple cases such as the above example can be thought of as a maximizing repeat that must swallow everything it can. So, while both \\d+ and \\d+? are prepared to adjust the number of digits they match in order to make the rest of the pattern match, (?>\\d+) can only match an entire sequence of digits. This construction can of course contain arbitrarily complicated subpatterns, and it can be nested. Once-only subpatterns can be used in conjunction with lookbehind assertions to specify efficient matching at the end of the subject string. Consider a simple pattern such as abcd$ when applied to a long string which does not match. Because matching proceeds from left to right, PCRE will look for each "a" in the subject and then see if what follows matches the rest of the pattern. If the pattern is specified as ^.*abcd$ the initial .* matches the entire string at first, but when this fails (because there is no following "a"), it backtracks to match all but the last character, then all but the last two characters, and so on. Once again the search for "a" covers the entire string, from right to left, so we are no better off. However, if the pattern is written as ^(?>.*)(?<=abcd) there can be no backtracking for the .* item; it can match only the entire string. The subsequent lookbehind assertion does a single test on the last four characters. If it fails, the match fails immediately. For long strings, this approach makes a significant difference to the processing time. When a pattern contains an unlimited repeat inside a subpattern that can itself be repeated an unlimited number of times, the use of a once-only subpattern is the only way to avoid some failing matches taking a very long time indeed. The pattern (\\D+|<\\d+>)*[!?] matches an unlimited number of substrings that either consist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa it takes a long time before reporting failure. This is because the string can be divided between the two repeats in a large number of ways, and all have to be tried. (The example used [!?] rather than a single character at the end, because both PCRE and Perl have an optimization that allows for fast failure when a single character is used. They remember the last single character that is required for a match, and fail early if it is not present in the string.) If the pattern is changed to ((?>\\D+)|<\\d+>)*[!?] sequences of non-digits cannot be broken, and failure happens quickly. .SH CONDITIONAL SUBPATTERNS It is possible to cause the matching process to obey a subpattern conditionally or to choose between two alternative subpatterns, depending on the result of an assertion, or whether a previous capturing subpattern matched or not. The two possible forms of conditional subpattern are (?(condition)yes-pattern) (?(condition)yes-pattern|no-pattern) If the condition is satisfied, the yes-pattern is used; otherwise the no-pattern (if present) is used. If there are more than two alternatives in the subpattern, a compile-time error occurs. There are two kinds of condition. If the text between the parentheses consists of a sequence of digits, the condition is satisfied if the capturing subpattern of that number has previously matched. The number must be greater than zero. Consider the following pattern, which contains non-significant white space to make it more readable (assume the PCRE_EXTENDED option) and to divide it into three parts for ease of discussion: ( \\( )? [^()]+ (?(1) \\) ) The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part matches one or more characters that are not parentheses. The third part is a conditional subpattern that tests whether the first set of parentheses matched or not. If they did, that is, if subject started with an opening parenthesis, the condition is true, and so the yes-pattern is executed and a closing parenthesis is required. Otherwise, since no-pattern is not present, the subpattern matches nothing. In other words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses. If the condition is not a sequence of digits, it must be an assertion. This may be a positive or negative lookahead or lookbehind assertion. Consider this pattern, again containing non-significant white space, and with the two alternatives on the second line: (?(?=[^a-z]*[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a letter is found, the subject is matched against the first alternative; otherwise it is matched against the second. This pattern matches strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits. .SH COMMENTS The sequence (?# marks the start of a comment which continues up to the next closing parenthesis. Nested parentheses are not permitted. The characters that make up a comment play no part in the pattern matching at all. If the PCRE_EXTENDED option is set, an unescaped # character outside a character class introduces a comment that continues up to the next newline character in the pattern. .SH RECURSIVE PATTERNS Consider the problem of matching a string in parentheses, allowing for unlimited nested parentheses. Without the use of recursion, the best that can be done is to use a pattern that matches up to some fixed depth of nesting. It is not possible to handle an arbitrary nesting depth. Perl 5.6 has provided an experimental facility that allows regular expressions to recurse (amongst other things). It does this by interpolating Perl code in the expression at run time, and the code can refer to the expression itself. A Perl pattern to solve the parentheses problem can be created like this: $re = qr{\\( (?: (?>[^()]+) | (?p{$re}) )* \\)}x; The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears. Obviously, PCRE cannot support the interpolation of Perl code. Instead, the special item (?R) is provided for the specific case of recursion. This PCRE pattern solves the parentheses problem (assume the PCRE_EXTENDED option is set so that white space is ignored): \\( ( (?>[^()]+) | (?R) )* \\) First it matches an opening parenthesis. Then it matches any number of substrings which can either be a sequence of non-parentheses, or a recursive match of the pattern itself (i.e. a correctly parenthesized substring). Finally there is a closing parenthesis. This particular example pattern contains nested unlimited repeats, and so the use of a once-only subpattern for matching strings of non-parentheses is important when applying the pattern to strings that do not match. For example, when it is applied to (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() it yields "no match" quickly. However, if a once-only subpattern is not used, the match runs for a very long time indeed because there are so many different ways the + and * repeats can carve up the subject, and all have to be tested before failure can be reported. The values set for any capturing subpatterns are those from the outermost level of the recursion at which the subpattern value is set. If the pattern above is matched against (ab(cd)ef) the value for the capturing parentheses is "ef", which is the last value taken on at the top level. If additional parentheses are added, giving \\( ( ( (?>[^()]+) | (?R) )* ) \\) ^ ^ ^ ^ the string they capture is "ab(cd)ef", the contents of the top level parentheses. If there are more than 15 capturing parentheses in a pattern, PCRE has to obtain extra memory to store data during a recursion, which it does by using \fBpcre_malloc\fR, freeing it via \fBpcre_free\fR afterwards. If no memory can be obtained, it saves data for the first 15 capturing parentheses only, as there is no way to give an out-of-memory error from within a recursion. .SH PERFORMANCE Certain items that may appear in patterns are more efficient than others. It is more efficient to use a character class like [aeiou] than a set of alternatives such as (a|e|i|o|u). In general, the simplest construction that provides the required behaviour is usually the most efficient. Jeffrey Friedl's book contains a lot of discussion about optimizing regular expressions for efficient performance. When a pattern begins with .* and the PCRE_DOTALL option is set, the pattern is implicitly anchored by PCRE, since it can match only at the start of a subject string. However, if PCRE_DOTALL is not set, PCRE cannot make this optimization, because the . metacharacter does not then match a newline, and if the subject string contains newlines, the pattern may match from the character immediately following one of them instead of from the very start. For example, the pattern (.*) second matches the subject "first\\nand second" (where \\n stands for a newline character) with the first captured substring being "and". In order to do this, PCRE has to retry the match starting after every newline in the subject. If you are using such a pattern with subject strings that do not contain newlines, the best performance is obtained by setting PCRE_DOTALL, or starting the pattern with ^.* to indicate explicit anchoring. That saves PCRE from having to scan along the subject looking for a newline to restart at. Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match. Consider the pattern fragment (a+)* This can match "aaaa" in 33 different ways, and this number increases very rapidly as the string gets longer. (The * repeat can match 0, 1, 2, 3, or 4 times, and for each of those cases other than 0, the + repeats can match different numbers of times.) When the remainder of the pattern is such that the entire match is going to fail, PCRE has in principle to try every possible variation, and this can take an extremely long time. An optimization catches some of the more simple cases such as (a+)*b where a literal character follows. Before embarking on the standard matching procedure, PCRE checks that there is a "b" later in the subject string, and if there is not, it fails the match immediately. However, when there is no following literal this optimization cannot be used. You can see the difference by comparing the behaviour of (a+)*\\d with the pattern above. The former gives a failure almost instantly when applied to a whole line of "a" characters, whereas the latter takes an appreciable time with strings longer than about 20 characters. .SH UTF-8 SUPPORT Starting at release 3.3, PCRE has some support for character strings encoded in the UTF-8 format. This is incomplete, and is regarded as experimental. In order to use it, you must configure PCRE to include UTF-8 support in the code, and, in addition, you must call \fBpcre_compile()\fR with the PCRE_UTF8 option flag. When you do this, both the pattern and any subject strings that are matched against it are treated as UTF-8 strings instead of just strings of bytes, but only in the cases that are mentioned below. If you compile PCRE with UTF-8 support, but do not use it at run time, the library will be a bit bigger, but the additional run time overhead is limited to testing the PCRE_UTF8 flag in several places, so should not be very large. PCRE assumes that the strings it is given contain valid UTF-8 codes. It does not diagnose invalid UTF-8 strings. If you pass invalid UTF-8 strings to PCRE, the results are undefined. Running with PCRE_UTF8 set causes these changes in the way PCRE works: 1. In a pattern, the escape sequence \\x{...}, where the contents of the braces is a string of hexadecimal digits, is interpreted as a UTF-8 character whose code number is the given hexadecimal number, for example: \\x{1234}. This inserts from one to six literal bytes into the pattern, using the UTF-8 encoding. If a non-hexadecimal digit appears between the braces, the item is not recognized. 2. The original hexadecimal escape sequence, \\xhh, generates a two-byte UTF-8 character if its value is greater than 127. 3. Repeat quantifiers are NOT correctly handled if they follow a multibyte character. For example, \\x{100}* and \\xc3+ do not work. If you want to repeat such characters, you must enclose them in non-capturing parentheses, for example (?:\\x{100}), at present. 4. The dot metacharacter matches one UTF-8 character instead of a single byte. 5. Unlike literal UTF-8 characters, the dot metacharacter followed by a repeat quantifier does operate correctly on UTF-8 characters instead of single bytes. 4. Although the \\x{...} escape is permitted in a character class, characters whose values are greater than 255 cannot be included in a class. 5. A class is matched against a UTF-8 character instead of just a single byte, but it can match only characters whose values are less than 256. Characters with greater values always fail to match a class. 6. Repeated classes work correctly on multiple characters. 7. Classes containing just a single character whose value is greater than 127 (but less than 256), for example, [\\x80] or [^\\x{93}], do not work because these are optimized into single byte matches. In the first case, of course, the class brackets are just redundant. 8. Lookbehind assertions move backwards in the subject by a fixed number of characters instead of a fixed number of bytes. Simple cases have been tested to work correctly, but there may be hidden gotchas herein. 9. The character types such as \\d and \\w do not work correctly with UTF-8 characters. They continue to test a single byte. 10. Anything not explicitly mentioned here continues to work in bytes rather than in characters. The following UTF-8 features of Perl 5.6 are not implemented: 1. The escape sequence \\C to match a single byte. 2. The use of Unicode tables and properties and escapes \\p, \\P, and \\X. .SH AUTHOR Philip Hazel .br University Computing Service, .br New Museums Site, .br Cambridge CB2 3QG, England. .br Phone: +44 1223 334714 Last updated: 28 August 2000, .br the 250th anniversary of the death of J.S. Bach. .br Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/pcreposix.html000640 001751 001751 00000016271 10546014100 020360 0ustar00fkfk000000 000000 pcreposix specification

    pcreposix specification

    This HTML document has been generated automatically from the original man page. If there is any nonsense in it, please consult the man page in case the conversion went wrong.
  • NAME

    pcreposix - POSIX API for Perl-compatible regular expressions.

  • SYNOPSIS

    #include <pcreposix.h>

    int regcomp(regex_t *preg, const char *pattern, int cflags);

    int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);

    size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);

    void regfree(regex_t *preg);

  • DESCRIPTION

    This set of functions provides a POSIX-style API to the PCRE regular expression package. See the pcre documentation for a description of the native API, which contains additional functionality.

    The functions described here are just wrapper functions that ultimately call the native API. Their prototypes are defined in the pcreposix.h header file, and on Unix systems the library itself is called pcreposix.a, so can be accessed by adding -lpcreposix to the command for linking an application which uses them. Because the POSIX functions call the native ones, it is also necessary to add \fR-lpcre\fR.

    I have implemented only those option bits that can be reasonably mapped to PCRE native options. In addition, the options REG_EXTENDED and REG_NOSUB are defined with the value zero. They have no effect, but since programs that are written to the POSIX interface often use them, this makes it easier to slot in PCRE as a replacement library. Other POSIX options are not even defined.

    When PCRE is called via these functions, it is only the API that is POSIX-like in style. The syntax and semantics of the regular expressions themselves are still those of Perl, subject to the setting of various PCRE options, as described below.

    The header for these functions is supplied as pcreposix.h to avoid any potential clash with other POSIX libraries. It can, of course, be renamed or aliased as regex.h, which is the "correct" name. It provides two structure types, regex_t for compiled internal forms, and regmatch_t for returning captured substrings. It also defines some constants whose names start with "REG_"; these are used for setting options and identifying error codes.

  • COMPILING A PATTERN

    The function regcomp() is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument pattern. The preg argument is a pointer to a regex_t structure which is used as a base for storing information about the compiled expression.

    The argument cflags is either zero, or contains one or more of the bits defined by the following macros:

      REG_ICASE
    

    The PCRE_CASELESS option is set when the expression is passed for compilation to the native function.

      REG_NEWLINE
    

    The PCRE_MULTILINE option is set when the expression is passed for compilation to the native function.

    In the absence of these flags, no options are passed to the native function. This means the the regex is compiled with PCRE default semantics. In particular, the way it handles newline characters in the subject string is the Perl way, not the POSIX way. Note that setting PCRE_MULTILINE has only some of the effects specified for REG_NEWLINE. It does not affect the way newlines are matched by . (they aren't) or a negative class such as [^a] (they are).

    The yield of regcomp() is zero on success, and non-zero otherwise. The preg structure is filled in on success, and one member of the structure is publicized: re_nsub contains the number of capturing subpatterns in the regular expression. Various error codes are defined in the header file.

  • MATCHING A PATTERN

    The function regexec() is called to match a pre-compiled pattern preg against a given string, which is terminated by a zero byte, subject to the options in eflags. These can be:

      REG_NOTBOL
    

    The PCRE_NOTBOL option is set when calling the underlying PCRE matching function.

      REG_NOTEOL
    

    The PCRE_NOTEOL option is set when calling the underlying PCRE matching function.

    The portion of the string that was matched, and also any captured substrings, are returned via the pmatch argument, which points to an array of nmatch structures of type regmatch_t, containing the members rm_so and rm_eo. These contain the offset to the first character of each substring and the offset to the first character after the end of each substring, respectively. The 0th element of the vector relates to the entire portion of string that was matched; subsequent elements relate to the capturing subpatterns of the regular expression. Unused entries in the array have both structure members set to -1.

    A successful match yields a zero return; various error codes are defined in the header file, of which REG_NOMATCH is the "expected" failure code.

  • ERROR MESSAGES

    The regerror() function maps a non-zero errorcode from either regcomp or regexec to a printable message. If preg is not NULL, the error should have arisen from the use of that structure. A message terminated by a binary zero is placed in errbuf. The length of the message, including the zero, is limited to errbuf_size. The yield of the function is the size of buffer needed to hold the whole message.

  • STORAGE

    Compiling a regular expression causes memory to be allocated and associated with the preg structure. The function regfree() frees all such memory, after which preg may no longer be used as a compiled expression.

  • AUTHOR

    Philip Hazel <ph10@cam.ac.uk>
    University Computing Service,
    New Museums Site,
    Cambridge CB2 3QG, England.
    Phone: +44 1223 334714

    Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/pcre.html000640 001751 001751 00000267174 10546014100 017307 0ustar00fkfk000000 000000 pcre specification

    pcre specification

    This HTML document has been generated automatically from the original man page. If there is any nonsense in it, please consult the man page in case the conversion went wrong.
  • NAME

    pcre - Perl-compatible regular expressions.

  • SYNOPSIS

    #include <pcre.h>

    pcre *pcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr);

    pcre_extra *pcre_study(const pcre *code, int options, const char **errptr);

    int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject, int length, int startoffset, int options, int *ovector, int ovecsize);

    int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int buffersize);

    int pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr);

    int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr);

    void pcre_free_substring(const char *stringptr);

    void pcre_free_substring_list(const char **stringptr);

    const unsigned char *pcre_maketables(void);

    int pcre_fullinfo(const pcre *code, const pcre_extra *extra, int what, void *where);

    int pcre_info(const pcre *code, int *optptr, int *firstcharptr);

    char *pcre_version(void);

    void *(*pcre_malloc)(size_t);

    void (*pcre_free)(void *);

  • DESCRIPTION

    The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5, with just a few differences (see below). The current implementation corresponds to Perl 5.005, with some additional features from later versions. This includes some experimental, incomplete support for UTF-8 encoded strings. Details of exactly what is and what is not supported are given below.

    PCRE has its own native API, which is described in this document. There is also a set of wrapper functions that correspond to the POSIX regular expression API. These are described in the pcreposix documentation.

    The native API function prototypes are defined in the header file pcre.h, and on Unix systems the library itself is called libpcre.a, so can be accessed by adding -lpcre to the command for linking an application which calls it. The header file defines the macros PCRE_MAJOR and PCRE_MINOR to contain the major and minor release numbers for the library. Applications can use these to include support for different releases.

    The functions pcre_compile(), pcre_study(), and pcre_exec() are used for compiling and matching regular expressions.

    The functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are convenience functions for extracting captured substrings from a matched subject string; pcre_free_substring() and pcre_free_substring_list() are also provided, to free the memory used for extracted strings.

    The function pcre_maketables() is used (optionally) to build a set of character tables in the current locale for passing to pcre_compile().

    The function pcre_fullinfo() is used to find out information about a compiled pattern; pcre_info() is an obsolete version which returns only some of the available information, but is retained for backwards compatibility. The function pcre_version() returns a pointer to a string containing the version of PCRE and its date of release.

    The global variables pcre_malloc and pcre_free initially contain the entry points of the standard malloc() and free() functions respectively. PCRE calls the memory management functions via these variables, so a calling program can replace them if it wishes to intercept the calls. This should be done before calling any PCRE functions.

  • MULTI-THREADING

    The PCRE functions can be used in multi-threading applications, with the proviso that the memory management functions pointed to by pcre_malloc and pcre_free are shared by all threads.

    The compiled form of a regular expression is not altered during matching, so the same compiled pattern can safely be used by several threads at once.

  • COMPILING A PATTERN

    The function pcre_compile() is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument pattern. A pointer to a single block of memory that is obtained via pcre_malloc is returned. This contains the compiled code and related data. The pcre type is defined for this for convenience, but in fact pcre is just a typedef for void, since the contents of the block are not externally defined. It is up to the caller to free the memory when it is no longer required.

    The size of a compiled pattern is roughly proportional to the length of the pattern string, except that each character class (other than those containing just a single character, negated or not) requires 33 bytes, and repeat quantifiers with a minimum greater than one or a bounded maximum cause the relevant portions of the compiled pattern to be replicated.

    The options argument contains independent bits that affect the compilation. It should be zero if no options are required. Some of the options, in particular, those that are compatible with Perl, can also be set and unset from within the pattern (see the detailed description of regular expressions below). For these options, the contents of the options argument specifies their initial settings at the start of compilation and execution. The PCRE_ANCHORED option can be set at the time of matching as well as at compile time.

    If errptr is NULL, pcre_compile() returns NULL immediately. Otherwise, if compilation of a pattern fails, pcre_compile() returns NULL, and sets the variable pointed to by errptr to point to a textual error message. The offset from the start of the pattern to the character where the error was discovered is placed in the variable pointed to by erroffset, which must not be NULL. If it is, an immediate error is given.

    If the final argument, tableptr, is NULL, PCRE uses a default set of character tables which are built when it is compiled, using the default C locale. Otherwise, tableptr must be the result of a call to pcre_maketables(). See the section on locale support below.

    The following option bits are defined in the header file:

      PCRE_ANCHORED
    

    If this bit is set, the pattern is forced to be "anchored", that is, it is constrained to match only at the start of the string which is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself, which is the only way to do it in Perl.

      PCRE_CASELESS
    

    If this bit is set, letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option.

      PCRE_DOLLAR_ENDONLY
    

    If this bit is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before the final character if it is a newline (but not before any other newlines). The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. There is no equivalent to this option in Perl.

      PCRE_DOTALL
    

    If this bit is set, a dot metacharater in the pattern matches all characters, including newlines. Without it, newlines are excluded. This option is equivalent to Perl's /s option. A negative class such as [^a] always matches a newline character, independent of the setting of this option.

      PCRE_EXTENDED
    

    If this bit is set, whitespace data characters in the pattern are totally ignored except when escaped or inside a character class, and characters between an unescaped # outside a character class and the next newline character, inclusive, are also ignored. This is equivalent to Perl's /x option, and makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence (?( which introduces a conditional subpattern.

      PCRE_EXTRA
    

    This option was invented in order to turn on additional functionality of PCRE that is incompatible with Perl, but it is currently of very little use. When set, any backslash in a pattern that is followed by a letter that has no special meaning causes an error, thus reserving these combinations for future expansion. By default, as in Perl, a backslash followed by a letter with no special meaning is treated as a literal. There are at present no other features controlled by this option. It can also be set by a (?X) option setting within a pattern.

      PCRE_MULTILINE
    

    By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY is set). This is the same as Perl.

    When PCRE_MULTILINE it is set, the "start of line" and "end of line" constructs match immediately following or immediately before any newline in the subject string, respectively, as well as at the very start and end. This is equivalent to Perl's /m option. If there are no "\n" characters in a subject string, or no occurrences of ^ or $ in a pattern, setting PCRE_MULTILINE has no effect.

      PCRE_UNGREEDY
    

    This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern.

      PCRE_UTF8
    

    This option causes PCRE to regard both the pattern and the subject as strings of UTF-8 characters instead of just byte strings. However, it is available only if PCRE has been built to include UTF-8 support. If not, the use of this option provokes an error. Support for UTF-8 is new, experimental, and incomplete. Details of exactly what it entails are given below.

  • STUDYING A PATTERN

    When a pattern is going to be used several times, it is worth spending more time analyzing it in order to speed up the time taken for matching. The function pcre_study() takes a pointer to a compiled pattern as its first argument, and returns a pointer to a pcre_extra block (another void typedef) containing additional information about the pattern; this can be passed to pcre_exec(). If no additional information is available, NULL is returned.

    The second argument contains option bits. At present, no options are defined for pcre_study(), and this argument should always be zero.

    The third argument for pcre_study() is a pointer to an error message. If studying succeeds (even if no data is returned), the variable it points to is set to NULL. Otherwise it points to a textual error message.

    At present, studying a pattern is useful only for non-anchored patterns that do not have a single fixed starting character. A bitmap of possible starting characters is created.

  • LOCALE SUPPORT

    PCRE handles caseless matching, and determines whether characters are letters, digits, or whatever, by reference to a set of tables. The library contains a default set of tables which is created in the default C locale when PCRE is compiled. This is used when the final argument of pcre_compile() is NULL, and is sufficient for many applications.

    An alternative set of tables can, however, be supplied. Such tables are built by calling the pcre_maketables() function, which has no arguments, in the relevant locale. The result can then be passed to pcre_compile() as often as necessary. For example, to build and use tables that are appropriate for the French locale (where accented characters with codes greater than 128 are treated as letters), the following code could be used:

      setlocale(LC_CTYPE, "fr");
      tables = pcre_maketables();
      re = pcre_compile(..., tables);
    

    The tables are built in memory that is obtained via pcre_malloc. The pointer that is passed to pcre_compile is saved with the compiled pattern, and the same tables are used via this pointer by pcre_study() and pcre_exec(). Thus for any single pattern, compilation, studying and matching all happen in the same locale, but different patterns can be compiled in different locales. It is the caller's responsibility to ensure that the memory containing the tables remains available for as long as it is needed.

  • INFORMATION ABOUT A PATTERN

    The pcre_fullinfo() function returns information about a compiled pattern. It replaces the obsolete pcre_info() function, which is nevertheless retained for backwards compability (and is documented below).

    The first argument for pcre_fullinfo() is a pointer to the compiled pattern. The second argument is the result of pcre_study(), or NULL if the pattern was not studied. The third argument specifies which piece of information is required, while the fourth argument is a pointer to a variable to receive the data. The yield of the function is zero for success, or one of the following negative numbers:

      PCRE_ERROR_NULL       the argument code was NULL
                            the argument where was NULL
      PCRE_ERROR_BADMAGIC   the "magic number" was not found
      PCRE_ERROR_BADOPTION  the value of what was invalid
    

    The possible values for the third argument are defined in pcre.h, and are as follows:

      PCRE_INFO_OPTIONS
    

    Return a copy of the options with which the pattern was compiled. The fourth argument should point to au unsigned long int variable. These option bits are those specified in the call to pcre_compile(), modified by any top-level option settings within the pattern itself, and with the PCRE_ANCHORED bit forcibly set if the form of the pattern implies that it can match only at the start of a subject string.

      PCRE_INFO_SIZE
    

    Return the size of the compiled pattern, that is, the value that was passed as the argument to pcre_malloc() when PCRE was getting memory in which to place the compiled data. The fourth argument should point to a size_t variable.

      PCRE_INFO_CAPTURECOUNT
    

    Return the number of capturing subpatterns in the pattern. The fourth argument should point to an \fbint\fR variable.

      PCRE_INFO_BACKREFMAX
    

    Return the number of the highest back reference in the pattern. The fourth argument should point to an int variable. Zero is returned if there are no back references.

      PCRE_INFO_FIRSTCHAR
    

    Return information about the first character of any matched string, for a non-anchored pattern. If there is a fixed first character, e.g. from a pattern such as (cat|cow|coyote), it is returned in the integer pointed to by where. Otherwise, if either

    (a) the pattern was compiled with the PCRE_MULTILINE option, and every branch starts with "^", or

    (b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not set (if it were set, the pattern would be anchored),

    -1 is returned, indicating that the pattern matches only at the start of a subject string or after any "\n" within the string. Otherwise -2 is returned. For anchored patterns, -2 is returned.

      PCRE_INFO_FIRSTTABLE
    

    If the pattern was studied, and this resulted in the construction of a 256-bit table indicating a fixed set of characters for the first character in any matching string, a pointer to the table is returned. Otherwise NULL is returned. The fourth argument should point to an unsigned char * variable.

      PCRE_INFO_LASTLITERAL
    

    For a non-anchored pattern, return the value of the rightmost literal character which must exist in any matched string, other than at its start. The fourth argument should point to an int variable. If there is no such character, or if the pattern is anchored, -1 is returned. For example, for the pattern /a\d+z\d+/ the returned value is 'z'.

    The pcre_info() function is now obsolete because its interface is too restrictive to return all the available data about a compiled pattern. New programs should use pcre_fullinfo() instead. The yield of pcre_info() is the number of capturing subpatterns, or one of the following negative numbers:

      PCRE_ERROR_NULL       the argument code was NULL
      PCRE_ERROR_BADMAGIC   the "magic number" was not found
    

    If the optptr argument is not NULL, a copy of the options with which the pattern was compiled is placed in the integer it points to (see PCRE_INFO_OPTIONS above).

    If the pattern is not anchored and the firstcharptr argument is not NULL, it is used to pass back information about the first character of any matched string (see PCRE_INFO_FIRSTCHAR above).

  • MATCHING A PATTERN

    The function pcre_exec() is called to match a subject string against a pre-compiled pattern, which is passed in the code argument. If the pattern has been studied, the result of the study should be passed in the extra argument. Otherwise this must be NULL.

    The PCRE_ANCHORED option can be passed in the options argument, whose unused bits must be zero. However, if a pattern was compiled with PCRE_ANCHORED, or turned out to be anchored by virtue of its contents, it cannot be made unachored at matching time.

    There are also three further options that can be set only at matching time:

      PCRE_NOTBOL
    

    The first character of the string is not the beginning of a line, so the circumflex metacharacter should not match before it. Setting this without PCRE_MULTILINE (at compile time) causes circumflex never to match.

      PCRE_NOTEOL
    

    The end of the string is not the end of a line, so the dollar metacharacter should not match it nor (except in multiline mode) a newline immediately before it. Setting this without PCRE_MULTILINE (at compile time) causes dollar never to match.

      PCRE_NOTEMPTY
    

    An empty string is not considered to be a valid match if this option is set. If there are alternatives in the pattern, they are tried. If all the alternatives match the empty string, the entire match fails. For example, if the pattern

      a?b?
    

    is applied to a string not beginning with "a" or "b", it matches the empty string at the start of the subject. With PCRE_NOTEMPTY set, this match is not valid, so PCRE searches further into the string for occurrences of "a" or "b".

    Perl has no direct equivalent of PCRE_NOTEMPTY, but it does make a special case of a pattern match of the empty string within its split() function, and when using the /g modifier. It is possible to emulate Perl's behaviour after matching a null string by first trying the match again at the same offset with PCRE_NOTEMPTY set, and then if that fails by advancing the starting offset (see below) and trying an ordinary match again.

    The subject string is passed as a pointer in subject, a length in length, and a starting offset in startoffset. Unlike the pattern string, it may contain binary zero characters. When the starting offset is zero, the search for a match starts at the beginning of the subject, and this is by far the most common case.

    A non-zero starting offset is useful when searching for another match in the same subject by calling pcre_exec() again after a previous success. Setting startoffset differs from just passing over a shortened string and setting PCRE_NOTBOL in the case of a pattern that begins with any kind of lookbehind. For example, consider the pattern

      \Biss\B
    

    which finds occurrences of "iss" in the middle of words. (\B matches only if the current position in the subject is not a word boundary.) When applied to the string "Mississipi" the first call to pcre_exec() finds the first occurrence. If pcre_exec() is called again with just the remainder of the subject, namely "issipi", it does not match, because \B is always false at the start of the subject, which is deemed to be a word boundary. However, if pcre_exec() is passed the entire string again, but with startoffset set to 4, it finds the second occurrence of "iss" because it is able to look behind the starting point to discover that it is preceded by a letter.

    If a non-zero starting offset is passed when the pattern is anchored, one attempt to match at the given offset is tried. This can only succeed if the pattern does not require the match to be at the start of the subject.

    In general, a pattern matches a certain portion of the subject, and in addition, further substrings from the subject may be picked out by parts of the pattern. Following the usage in Jeffrey Friedl's book, this is called "capturing" in what follows, and the phrase "capturing subpattern" is used for a fragment of a pattern that picks out a substring. PCRE supports several other kinds of parenthesized subpattern that do not cause substrings to be captured.

    Captured substrings are returned to the caller via a vector of integer offsets whose address is passed in ovector. The number of elements in the vector is passed in ovecsize. The first two-thirds of the vector is used to pass back captured substrings, each substring using a pair of integers. The remaining third of the vector is used as workspace by pcre_exec() while matching capturing subpatterns, and is not available for passing back information. The length passed in ovecsize should always be a multiple of three. If it is not, it is rounded down.

    When a match has been successful, information about captured substrings is returned in pairs of integers, starting at the beginning of ovector, and continuing up to two-thirds of its length at the most. The first element of a pair is set to the offset of the first character in a substring, and the second is set to the offset of the first character after the end of a substring. The first pair, ovector[0] and ovector[1], identify the portion of the subject string matched by the entire pattern. The next pair is used for the first capturing subpattern, and so on. The value returned by pcre_exec() is the number of pairs that have been set. If there are no capturing subpatterns, the return value from a successful match is 1, indicating that just the first pair of offsets has been set.

    Some convenience functions are provided for extracting the captured substrings as separate strings. These are described in the following section.

    It is possible for an capturing subpattern number n+1 to match some part of the subject when subpattern n has not been used at all. For example, if the string "abc" is matched against the pattern (a|(z))(bc) subpatterns 1 and 3 are matched, but 2 is not. When this happens, both offset values corresponding to the unused subpattern are set to -1.

    If a capturing subpattern is matched repeatedly, it is the last portion of the string that it matched that gets returned.

    If the vector is too small to hold all the captured substrings, it is used as far as possible (up to two-thirds of its length), and the function returns a value of zero. In particular, if the substring offsets are not of interest, pcre_exec() may be called with ovector passed as NULL and ovecsize as zero. However, if the pattern contains back references and the ovector isn't big enough to remember the related substrings, PCRE has to get additional memory for use during matching. Thus it is usually advisable to supply an ovector.

    Note that pcre_info() can be used to find out how many capturing subpatterns there are in a compiled pattern. The smallest size for ovector that will allow for n captured substrings in addition to the offsets of the substring matched by the whole pattern is (n+1)*3.

    If pcre_exec() fails, it returns a negative number. The following are defined in the header file:

      PCRE_ERROR_NOMATCH        (-1)
    

    The subject string did not match the pattern.

      PCRE_ERROR_NULL           (-2)
    

    Either code or subject was passed as NULL, or ovector was NULL and ovecsize was not zero.

      PCRE_ERROR_BADOPTION      (-3)
    

    An unrecognized bit was set in the options argument.

      PCRE_ERROR_BADMAGIC       (-4)
    

    PCRE stores a 4-byte "magic number" at the start of the compiled code, to catch the case when it is passed a junk pointer. This is the error it gives when the magic number isn't present.

      PCRE_ERROR_UNKNOWN_NODE   (-5)
    

    While running the pattern match, an unknown item was encountered in the compiled pattern. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern.

      PCRE_ERROR_NOMEMORY       (-6)
    

    If a pattern contains back references, but the ovector that is passed to pcre_exec() is not big enough to remember the referenced substrings, PCRE gets a block of memory at the start of matching to use for this purpose. If the call via pcre_malloc() fails, this error is given. The memory is freed at the end of matching.

  • EXTRACTING CAPTURED SUBSTRINGS

    Captured substrings can be accessed directly by using the offsets returned by pcre_exec() in ovector. For convenience, the functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are provided for extracting captured substrings as new, separate, zero-terminated strings. A substring that contains a binary zero is correctly extracted and has a further zero added on the end, but the result does not, of course, function as a C string.

    The first three arguments are the same for all three functions: subject is the subject string which has just been successfully matched, ovector is a pointer to the vector of integer offsets that was passed to pcre_exec(), and stringcount is the number of substrings that were captured by the match, including the substring that matched the entire regular expression. This is the value returned by pcre_exec if it is greater than zero. If pcre_exec() returned zero, indicating that it ran out of space in ovector, the value passed as stringcount should be the size of the vector divided by three.

    The functions pcre_copy_substring() and pcre_get_substring() extract a single substring, whose number is given as stringnumber. A value of zero extracts the substring that matched the entire pattern, while higher values extract the captured substrings. For pcre_copy_substring(), the string is placed in buffer, whose length is given by buffersize, while for pcre_get_substring() a new block of memory is obtained via pcre_malloc, and its address is returned via stringptr. The yield of the function is the length of the string, not including the terminating zero, or one of

      PCRE_ERROR_NOMEMORY       (-6)
    

    The buffer was too small for pcre_copy_substring(), or the attempt to get memory failed for pcre_get_substring().

      PCRE_ERROR_NOSUBSTRING    (-7)
    

    There is no substring whose number is stringnumber.

    The pcre_get_substring_list() function extracts all available substrings and builds a list of pointers to them. All this is done in a single block of memory which is obtained via pcre_malloc. The address of the memory block is returned via listptr, which is also the start of the list of string pointers. The end of the list is marked by a NULL pointer. The yield of the function is zero if all went well, or

      PCRE_ERROR_NOMEMORY       (-6)
    

    if the attempt to get the memory block failed.

    When any of these functions encounter a substring that is unset, which can happen when capturing subpattern number n+1 matches some part of the subject, but subpattern n has not been used at all, they return an empty string. This can be distinguished from a genuine zero-length substring by inspecting the appropriate offset in ovector, which is negative for unset substrings.

    The two convenience functions pcre_free_substring() and pcre_free_substring_list() can be used to free the memory returned by a previous call of pcre_get_substring() or pcre_get_substring_list(), respectively. They do nothing more than call the function pointed to by pcre_free, which of course could be called directly from a C program. However, PCRE is used in some situations where it is linked via a special interface to another programming language which cannot use pcre_free directly; it is for these cases that the functions are provided.

  • LIMITATIONS

    There are some size limitations in PCRE but it is hoped that they will never in practice be relevant. The maximum length of a compiled pattern is 65539 (sic) bytes. All values in repeating quantifiers must be less than 65536. The maximum number of capturing subpatterns is 99. The maximum number of all parenthesized subpatterns, including capturing subpatterns, assertions, and other types of subpattern, is 200.

    The maximum length of a subject string is the largest positive number that an integer variable can hold. However, PCRE uses recursion to handle subpatterns and indefinite repetition. This means that the available stack space may limit the size of a subject string that can be processed by certain patterns.

  • DIFFERENCES FROM PERL

    The differences described here are with respect to Perl 5.005.

    1. By default, a whitespace character is any character that the C library function isspace() recognizes, though it is possible to compile PCRE with alternative character type tables. Normally isspace() matches space, formfeed, newline, carriage return, horizontal tab, and vertical tab. Perl 5 no longer includes vertical tab in its set of whitespace characters. The \v escape that was in the Perl documentation for a long time was never in fact recognized. However, the character itself was treated as whitespace at least up to 5.002. In 5.004 and 5.005 it does not match \s.

    2. PCRE does not allow repeat quantifiers on lookahead assertions. Perl permits them, but they do not mean what you might think. For example, (?!a){3} does not assert that the next three characters are not "a". It just asserts that the next character is not "a" three times.

    3. Capturing subpatterns that occur inside negative lookahead assertions are counted, but their entries in the offsets vector are never set. Perl sets its numerical variables from any such patterns that are matched before the assertion fails to match something (thereby succeeding), but only if the negative lookahead assertion contains just one branch.

    4. Though binary zero characters are supported in the subject string, they are not allowed in a pattern string because it is passed as a normal C string, terminated by zero. The escape sequence "\0" can be used in the pattern to represent a binary zero.

    5. The following Perl escape sequences are not supported: \l, \u, \L, \U, \E, \Q. In fact these are implemented by Perl's general string-handling and are not part of its pattern matching engine.

    6. The Perl \G assertion is not supported as it is not relevant to single pattern matches.

    7. Fairly obviously, PCRE does not support the (?{code}) and (?p{code}) constructions. However, there is some experimental support for recursive patterns using the non-Perl item (?R).

    8. There are at the time of writing some oddities in Perl 5.005_02 concerned with the settings of captured strings when part of a pattern is repeated. For example, matching "aba" against the pattern /^(a(b)?)+$/ sets $2 to the value "b", but matching "aabbaa" against /^(aa(bb)?)+$/ leaves $2 unset. However, if the pattern is changed to /^(aa(b(b))?)+$/ then $2 (and $3) are set.

    In Perl 5.004 $2 is set in both cases, and that is also true of PCRE. If in the future Perl changes to a consistent state that is different, PCRE may change to follow.

    9. Another as yet unresolved discrepancy is that in Perl 5.005_02 the pattern /^(a)?(?(1)a|b)+$/ matches the string "a", whereas in PCRE it does not. However, in both Perl and PCRE /^(a)?a/ matched against "a" leaves $1 unset.

    10. PCRE provides some extensions to the Perl regular expression facilities:

    (a) Although lookbehind assertions must match fixed length strings, each alternative branch of a lookbehind assertion can match a different length of string. Perl 5.005 requires them all to have the same length.

    (b) If PCRE_DOLLAR_ENDONLY is set and PCRE_MULTILINE is not set, the $ meta- character matches only at the very end of the string.

    (c) If PCRE_EXTRA is set, a backslash followed by a letter with no special meaning is faulted.

    (d) If PCRE_UNGREEDY is set, the greediness of the repetition quantifiers is inverted, that is, by default they are not greedy, but if followed by a question mark they are.

    (e) PCRE_ANCHORED can be used to force a pattern to be tried only at the start of the subject.

    (f) The PCRE_NOTBOL, PCRE_NOTEOL, and PCRE_NOTEMPTY options for pcre_exec() have no Perl equivalents.

    (g) The (?R) construct allows for recursive pattern matching (Perl 5.6 can do this using the (?p{code}) construct, which PCRE cannot of course support.)

  • REGULAR EXPRESSION DETAILS

    The syntax and semantics of the regular expressions supported by PCRE are described below. Regular expressions are also described in the Perl documentation and in a number of other books, some of which have copious examples. Jeffrey Friedl's "Mastering Regular Expressions", published by O'Reilly (ISBN 1-56592-257), covers them in great detail.

    The description here is intended as reference documentation. The basic operation of PCRE is on strings of bytes. However, there is the beginnings of some support for UTF-8 character strings. To use this support you must configure PCRE to include it, and then call pcre_compile() with the PCRE_UTF8 option. How this affects the pattern matching is described in the final section of this document.

    A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and match the corresponding characters in the subject. As a trivial example, the pattern

      The quick brown fox
    

    matches a portion of a subject string that is identical to itself. The power of regular expressions comes from the ability to include alternatives and repetitions in the pattern. These are encoded in the pattern by the use of meta-characters, which do not stand for themselves but instead are interpreted in some special way.

    There are two different sets of meta-characters: those that are recognized anywhere in the pattern except within square brackets, and those that are recognized in square brackets. Outside square brackets, the meta-characters are as follows:

      \      general escape character with several uses
      ^      assert start of subject (or line, in multiline mode)
      $      assert end of subject (or line, in multiline mode)
      .      match any character except newline (by default)
      [      start character class definition
      |      start of alternative branch
      (      start subpattern
      )      end subpattern
      ?      extends the meaning of (
             also 0 or 1 quantifier
             also quantifier minimizer
      *      0 or more quantifier
      +      1 or more quantifier
      {      start min/max quantifier
    

    Part of a pattern that is in square brackets is called a "character class". In a character class the only meta-characters are:

      \      general escape character
      ^      negate the class, but only if the first character
      -      indicates character range
      ]      terminates the character class
    

    The following sections describe the use of each of the meta-characters.

  • BACKSLASH

    The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes.

    For example, if you want to match a "*" character, you write "\*" in the pattern. This applies whether or not the following character would otherwise be interpreted as a meta-character, so it is always safe to precede a non-alphameric with "\" to specify that it stands for itself. In particular, if you want to match a backslash, you write "\\".

    If a pattern is compiled with the PCRE_EXTENDED option, whitespace in the pattern (other than in a character class) and characters between a "#" outside a character class and the next newline character are ignored. An escaping backslash can be used to include a whitespace or "#" character as part of the pattern.

    A second use of backslash provides a way of encoding non-printing characters in patterns in a visible manner. There is no restriction on the appearance of non-printing characters, apart from the binary zero that terminates a pattern, but when a pattern is being prepared by text editing, it is usually easier to use one of the following escape sequences than the binary character it represents:

      \a     alarm, that is, the BEL character (hex 07)
      \cx    "control-x", where x is any character
      \e     escape (hex 1B)
      \f     formfeed (hex 0C)
      \n     newline (hex 0A)
      \r     carriage return (hex 0D)
      \t     tab (hex 09)
      \xhh   character with hex code hh
      \ddd   character with octal code ddd, or backreference
    

    The precise effect of "\cx" is as follows: if "x" is a lower case letter, it is converted to upper case. Then bit 6 of the character (hex 40) is inverted. Thus "\cz" becomes hex 1A, but "\c{" becomes hex 3B, while "\c;" becomes hex 7B.

    After "\x", up to two hexadecimal digits are read (letters can be in upper or lower case).

    After "\0" up to two further octal digits are read. In both cases, if there are fewer than two digits, just those that are present are used. Thus the sequence "\0\x\07" specifies two binary zeros followed by a BEL character. Make sure you supply two digits after the initial zero if the character that follows is itself an octal digit.

    The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a back reference. A description of how this works is given later, following the discussion of parenthesized subpatterns.

    Inside a character class, or if the decimal number is greater than 9 and there have not been that many capturing subpatterns, PCRE re-reads up to three octal digits following the backslash, and generates a single byte from the least significant 8 bits of the value. Any subsequent digits stand for themselves. For example:

      \040   is another way of writing a space
      \40    is the same, provided there are fewer than 40
                previous capturing subpatterns
      \7     is always a back reference
      \11    might be a back reference, or another way of
                writing a tab
      \011   is always a tab
      \0113  is a tab followed by the character "3"
      \113   is the character with octal code 113 (since there
                can be no more than 99 back references)
      \377   is a byte consisting entirely of 1 bits
      \81    is either a back reference, or a binary zero
                followed by the two characters "8" and "1"
    

    Note that octal values of 100 or greater must not be introduced by a leading zero, because no more than three octal digits are ever read.

    All the sequences that define a single byte value can be used both inside and outside character classes. In addition, inside a character class, the sequence "\b" is interpreted as the backspace character (hex 08). Outside a character class it has a different meaning (see below).

    The third use of backslash is for specifying generic character types:

      \d     any decimal digit
      \D     any character that is not a decimal digit
      \s     any whitespace character
      \S     any character that is not a whitespace character
      \w     any "word" character
      \W     any "non-word" character
    

    Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair.

    A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is controlled by PCRE's character tables, and may vary if locale- specific matching is taking place (see "Locale support" above). For example, in the "fr" (French) locale, some character codes greater than 128 are used for accented letters, and these are matched by \w.

    These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match.

    The fourth use of backslash is for certain simple assertions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are

      \b     word boundary
      \B     not a word boundary
      \A     start of subject (independent of multiline mode)
      \Z     end of subject or newline at end (independent of multiline mode)
      \z     end of subject (independent of multiline mode)
    

    These assertions may not appear in character classes (but note that "\b" has a different meaning, namely the backspace character, inside a character class).

    A word boundary is a position in the subject string where the current character and the previous character do not both match \w or \W (i.e. one matches \w and the other matches \W), or the start or end of the string if the first or last character matches \w, respectively.

    The \A, \Z, and \z assertions differ from the traditional circumflex and dollar (described below) in that they only ever match at the very start and end of the subject string, whatever options are set. They are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options. If the startoffset argument of pcre_exec() is non-zero, \A can never match. The difference between \Z and \z is that \Z matches before a newline that is the last character of the string as well as at the end of the string, whereas \z matches only at the end.

  • CIRCUMFLEX AND DOLLAR

    Outside a character class, in the default matching mode, the circumflex character is an assertion which is true only if the current matching point is at the start of the subject string. If the startoffset argument of pcre_exec() is non-zero, circumflex can never match. Inside a character class, circumflex has an entirely different meaning (see below).

    Circumflex need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alternatives start with a circumflex, that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other constructs that can cause a pattern to be anchored.)

    A dollar character is an assertion which is true only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class.

    The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at compile or matching time. This does not affect the \Z assertion.

    The meanings of the circumflex and dollar characters are changed if the PCRE_MULTILINE option is set. When this is the case, they match immediately after and immediately before an internal "\n" character, respectively, in addition to matching at the start and end of the subject string. For example, the pattern /^abc$/ matches the subject string "def\nabc" in multiline mode, but not otherwise. Consequently, patterns that are anchored in single line mode because all branches start with "^" are not anchored in multiline mode, and a match for circumflex is possible when the startoffset argument of pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set.

    Note that the sequences \A, \Z, and \z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with \A is it always anchored, whether PCRE_MULTILINE is set or not.

  • FULL STOP (PERIOD, DOT)

    Outside a character class, a dot in the pattern matches any one character in the subject, including a non-printing character, but not (by default) newline. If the PCRE_DOTALL option is set, dots match newlines as well. The handling of dot is entirely independent of the handling of circumflex and dollar, the only relationship being that they both involve newline characters. Dot has no special meaning in a character class.

  • SQUARE BRACKETS

    An opening square bracket introduces a character class, terminated by a closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, it should be the first data character in the class (after an initial circumflex, if present) or escaped with a backslash.

    A character class matches a single character in the subject; the character must be in the set of characters defined by the class, unless the first character in the class is a circumflex, in which case the subject character must not be in the set defined by the class. If a circumflex is actually required as a member of the class, ensure it is not the first character, or escape it with a backslash.

    For example, the character class [aeiou] matches any lower case vowel, while [^aeiou] matches any character that is not a lower case vowel. Note that a circumflex is just a convenient notation for specifying the characters which are in the class by enumerating those that are not. It is not an assertion: it still consumes a character from the subject string, and fails if the current pointer is at the end of the string.

    When caseless matching is set, any letters in a class represent both their upper case and lower case versions, so for example, a caseless [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a caseful version would.

    The newline character is never treated in any special way in character classes, whatever the setting of the PCRE_DOTALL or PCRE_MULTILINE options is. A class such as [^a] will always match a newline.

    The minus (hyphen) character can be used to specify a range of characters in a character class. For example, [d-m] matches any letter between d and m, inclusive. If a minus character is required in a class, it must be escaped with a backslash or appear in a position where it cannot be interpreted as indicating a range, typically as the first or last character in the class.

    It is not possible to have the literal character "]" as the end character of a range. A pattern such as [W-]46] is interpreted as a class of two characters ("W" and "-") followed by a literal string "46]", so it would match "W46]" or "-46]". However, if the "]" is escaped with a backslash it is interpreted as the end of range, so [W-\]46] is interpreted as a single class containing a range followed by two separate characters. The octal or hexadecimal representation of "]" can also be used to end a range.

    Ranges operate in ASCII collating sequence. They can also be used for characters specified numerically, for example [\000-\037]. If a range that includes letters is used when caseless matching is set, it matches the letters in either case. For example, [W-c] is equivalent to [][\^_`wxyzabc], matched caselessly, and if character tables for the "fr" locale are in use, [\xc8-\xcb] matches accented E characters in both cases.

    The character types \d, \D, \s, \S, \w, and \W may also appear in a character class, and add the characters that they match to the class. For example, [\dABCDEF] matches any hexadecimal digit. A circumflex can conveniently be used with the upper case character types to specify a more restricted set of characters than the matching lower case type. For example, the class [^\W_] matches any letter or digit, but not underscore.

    All non-alphameric characters other than \, -, ^ (at the start) and the terminating ] are non-special in character classes, but it does no harm if they are escaped.

  • POSIX CHARACTER CLASSES

    Perl 5.6 (not yet released at the time of writing) is going to support the POSIX notation for character classes, which uses names enclosed by [: and :] within the enclosing square brackets. PCRE supports this notation. For example,

      [01[:alpha:]%]
    

    matches "0", "1", any alphabetic character, or "%". The supported class names are

      alnum    letters and digits
      alpha    letters
      ascii    character codes 0 - 127
      cntrl    control characters
      digit    decimal digits (same as \d)
      graph    printing characters, excluding space
      lower    lower case letters
      print    printing characters, including space
      punct    printing characters, excluding letters and digits
      space    white space (same as \s)
      upper    upper case letters
      word     "word" characters (same as \w)
      xdigit   hexadecimal digits
    

    The names "ascii" and "word" are Perl extensions. Another Perl extension is negation, which is indicated by a ^ character after the colon. For example,

      [12[:^digit:]]
    

    matches "1", "2", or any non-digit. PCRE (and Perl) also recogize the POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not supported, and an error is given if they are encountered.

  • VERTICAL BAR

    Vertical bar characters are used to separate alternative patterns. For example, the pattern

      gilbert|sullivan
    

    matches either "gilbert" or "sullivan". Any number of alternatives may appear, and an empty alternative is permitted (matching the empty string). The matching process tries each alternative in turn, from left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern.

  • INTERNAL OPTION SETTING

    The settings of PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and PCRE_EXTENDED can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")". The option letters are

      i  for PCRE_CASELESS
      m  for PCRE_MULTILINE
      s  for PCRE_DOTALL
      x  for PCRE_EXTENDED
    

    For example, (?im) sets caseless, multiline matching. It is also possible to unset these options by preceding the letter with a hyphen, and a combined setting and unsetting such as (?im-sx), which sets PCRE_CASELESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, is also permitted. If a letter appears both before and after the hyphen, the option is unset.

    The scope of these option changes depends on where in the pattern the setting occurs. For settings that are outside any subpattern (defined below), the effect is the same as if the options were set or unset at the start of matching. The following patterns all behave in exactly the same way:

      (?i)abc
      a(?i)bc
      ab(?i)c
      abc(?i)
    

    which in turn is the same as compiling the pattern abc with PCRE_CASELESS set. In other words, such "top level" settings apply to the whole pattern (unless there are other changes inside subpatterns). If there is more than one setting of the same option at top level, the rightmost setting is used.

    If an option change occurs inside a subpattern, the effect is different. This is a change of behaviour in Perl 5.005. An option change inside a subpattern affects only that part of the subpattern that follows it, so

      (a(?i)b)c
    

    matches abc and aBc and no other strings (assuming PCRE_CASELESS is not used). By this means, options can be made to have different settings in different parts of the pattern. Any changes made in one alternative do carry on into subsequent branches within the same subpattern. For example,

      (a(?i)b|c)
    

    matches "ab", "aB", "c", and "C", even though when matching "C" the first branch is abandoned before the option setting. This is because the effects of option settings happen at compile time. There would be some very weird behaviour otherwise.

    The PCRE-specific options PCRE_UNGREEDY and PCRE_EXTRA can be changed in the same way as the Perl-compatible options by using the characters U and X respectively. The (?X) flag setting is special in that it must always occur earlier in the pattern than any of the additional features it turns on, even when it is at top level. It is best put at the start.

  • SUBPATTERNS

    Subpatterns are delimited by parentheses (round brackets), which can be nested. Marking part of a pattern as a subpattern does two things:

    1. It localizes a set of alternatives. For example, the pattern

      cat(aract|erpillar|)
    

    matches one of the words "cat", "cataract", or "caterpillar". Without the parentheses, it would match "cataract", "erpillar" or the empty string.

    2. It sets up the subpattern as a capturing subpattern (as defined above). When the whole pattern matches, that portion of the subject string that matched the subpattern is passed back to the caller via the ovector argument of pcre_exec(). Opening parentheses are counted from left to right (starting from 1) to obtain the numbers of the capturing subpatterns.

    For example, if the string "the red king" is matched against the pattern

      the ((red|white) (king|queen))
    

    the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3.

    The fact that plain parentheses fulfil two functions is not always helpful. There are often times when a grouping subpattern is required without a capturing requirement. If an opening parenthesis is followed by "?:", the subpattern does not do any capturing, and is not counted when computing the number of any subsequent capturing subpatterns. For example, if the string "the white queen" is matched against the pattern

      the ((?:red|white) (king|queen))
    

    the captured substrings are "white queen" and "queen", and are numbered 1 and 2. The maximum number of captured substrings is 99, and the maximum number of all subpatterns, both capturing and non-capturing, is 200.

    As a convenient shorthand, if any option settings are required at the start of a non-capturing subpattern, the option letters may appear between the "?" and the ":". Thus the two patterns

      (?i:saturday|sunday)
      (?:(?i)saturday|sunday)
    

    match exactly the same set of strings. Because alternative branches are tried from left to right, and options are not reset until the end of the subpattern is reached, an option setting in one branch does affect subsequent branches, so the above patterns match "SUNDAY" as well as "Saturday".

  • REPETITION

    Repetition is specified by quantifiers, which can follow any of the following items:

      a single character, possibly escaped
      the . metacharacter
      a character class
      a back reference (see next section)
      a parenthesized subpattern (unless it is an assertion - see below)
    

    The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example:

      z{2,4}
    

    matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special character. If the second number is omitted, but the comma is present, there is no upper limit; if the second number and the comma are both omitted, the quantifier specifies an exact number of required matches. Thus

      [aeiou]{3,}
    

    matches at least 3 successive vowels, but may match many more, while

      \d{8}
    

    matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantifier, but a literal string of four characters.

    The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present.

    For convenience (and historical compatibility) the three most common quantifiers have single-character abbreviations:

      *    is equivalent to {0,}
      +    is equivalent to {1,}
      ?    is equivalent to {0,1}
    

    It is possible to construct infinite loops by following a subpattern that can match no characters with a quantifier that has no upper limit, for example:

      (a?)*
    

    Earlier versions of Perl and PCRE used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but if any repetition of the subpattern does in fact match no characters, the loop is forcibly broken.

    By default, the quantifiers are "greedy", that is, they match as much as possible (up to the maximum number of permitted times), without causing the rest of the pattern to fail. The classic example of where this gives problems is in trying to match comments in C programs. These appear between the sequences /* and */ and within the sequence, individual * and / characters may appear. An attempt to match C comments by applying the pattern

      /\*.*\*/
    

    to the string

      /* first command */  not comment  /* second comment */
    

    fails, because it matches the entire string owing to the greediness of the .* item.

    However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern

      /\*.*?\*/
    

    does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the preferred number of matches. Do not confuse this use of question mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in

      \d??\d
    

    which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches.

    If the PCRE_UNGREEDY option is set (an option which is not available in Perl), the quantifiers are not greedy by default, but individual ones can be made greedy by following them with a question mark. In other words, it inverts the default behaviour.

    When a parenthesized subpattern is quantified with a minimum repeat count that is greater than 1 or with a limited maximum, more store is required for the compiled pattern, in proportion to the size of the minimum or maximum.

    If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equivalent to Perl's /s) is set, thus allowing the . to match newlines, the pattern is implicitly anchored, because whatever follows will be tried against every character position in the subject string, so there is no point in retrying the overall match at any position after the first. PCRE treats such a pattern as though it were preceded by \A. In cases where it is known that the subject string contains no newlines, it is worth setting PCRE_DOTALL when the pattern begins with .* in order to obtain this optimization, or alternatively using ^ to indicate anchoring explicitly.

    When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For example, after

      (tweedle[dume]{3}\s*)+
    

    has matched "tweedledum tweedledee" the value of the captured substring is "tweedledee". However, if there are nested capturing subpatterns, the corresponding captured values may have been set in previous iterations. For example, after

      /(a|(b))+/
    

    matches "aba" the value of the second captured substring is "b".

  • BACK REFERENCES

    Outside a character class, a backslash followed by a digit greater than 0 (and possibly further digits) is a back reference to a capturing subpattern earlier (i.e. to its left) in the pattern, provided there have been that many previous capturing left parentheses.

    However, if the decimal number following the backslash is less than 10, it is always taken as a back reference, and causes an error only if there are not that many capturing left parentheses in the entire pattern. In other words, the parentheses that are referenced need not be to the left of the reference for numbers less than 10. See the section entitled "Backslash" above for further details of the handling of digits following a backslash.

    A back reference matches whatever actually matched the capturing subpattern in the current subject string, rather than anything matching the subpattern itself. So the pattern

      (sens|respons)e and \1ibility
    

    matches "sense and sensibility" and "response and responsibility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example,

      ((?i)rah)\s+\1
    

    matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched caselessly.

    There may be more than one back reference to the same subpattern. If a subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern

      (a|(bc))\2
    

    always fails if it starts to match "a" rather than "bc". Because there may be up to 99 back references, all digits following the backslash are taken as part of a potential back reference number. If the pattern continues with a digit character, some delimiter must be used to terminate the back reference. If the PCRE_EXTENDED option is set, this can be whitespace. Otherwise an empty comment can be used.

    A back reference that occurs inside the parentheses to which it refers fails when the subpattern is first used, so, for example, (a\1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pattern

      (a|b\1)+
    

    matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding to the previous iteration. In order for this to work, the pattern must be such that the first iteration does not need to match the back reference. This can be done using alternation, as in the example above, or by a quantifier with a minimum of zero.

  • ASSERTIONS

    An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters. The simple assertions coded as \b, \B, \A, \Z, \z, ^ and $ are described above. More complicated assertions are coded as subpatterns. There are two kinds: those that look ahead of the current position in the subject string, and those that look behind it.

    An assertion subpattern is matched in the normal way, except that it does not cause the current matching position to be changed. Lookahead assertions start with (?= for positive assertions and (?! for negative assertions. For example,

      \w+(?=;)
    

    matches a word followed by a semicolon, but does not include the semicolon in the match, and

      foo(?!bar)
    

    matches any occurrence of "foo" that is not followed by "bar". Note that the apparently similar pattern

      (?!foo)bar
    

    does not find an occurrence of "bar" that is preceded by something other than "foo"; it finds any occurrence of "bar" whatsoever, because the assertion (?!foo) is always true when the next three characters are "bar". A lookbehind assertion is needed to achieve this effect.

    Lookbehind assertions start with (?<= for positive assertions and (?<! for negative assertions. For example,

      (?<!foo)bar
    

    does find an occurrence of "bar" that is not preceded by "foo". The contents of a lookbehind assertion are restricted such that all the strings it matches must have a fixed length. However, if there are several alternatives, they do not all have to have the same fixed length. Thus

      (?<=bullock|donkey)
    

    is permitted, but

      (?<!dogs?|cats?)
    

    causes an error at compile time. Branches that match different length strings are permitted only at the top level of a lookbehind assertion. This is an extension compared with Perl 5.005, which requires all branches to match the same length of string. An assertion such as

      (?<=ab(c|de))
    

    is not permitted, because its single top-level branch can match two different lengths, but it is acceptable if rewritten to use two top-level branches:

      (?<=abc|abde)
    

    The implementation of lookbehind assertions is, for each alternative, to temporarily move the current position back by the fixed width and then try to match. If there are insufficient characters before the current position, the match is deemed to fail. Lookbehinds in conjunction with once-only subpatterns can be particularly useful for matching at the ends of strings; an example is given at the end of the section on once-only subpatterns.

    Several assertions (of any sort) may occur in succession. For example,

      (?<=\d{3})(?<!999)foo
    

    matches "foo" preceded by three digits that are not "999". Notice that each of the assertions is applied independently at the same point in the subject string. First there is a check that the previous three characters are all digits, and then there is a check that the same three characters are not "999". This pattern does not match "foo" preceded by six characters, the first of which are digits and the last three of which are not "999". For example, it doesn't match "123abcfoo". A pattern to do that is

      (?<=\d{3}...)(?<!999)foo
    

    This time the first assertion looks at the preceding six characters, checking that the first three are digits, and then the second assertion checks that the preceding three characters are not "999".

    Assertions can be nested in any combination. For example,

      (?<=(?<!foo)bar)baz
    

    matches an occurrence of "baz" that is preceded by "bar" which in turn is not preceded by "foo", while

      (?<=\d{3}(?!999)...)foo
    

    is another pattern which matches "foo" preceded by three digits and any three characters that are not "999".

    Assertion subpatterns are not capturing subpatterns, and may not be repeated, because it makes no sense to assert the same thing several times. If any kind of assertion contains capturing subpatterns within it, these are counted for the purposes of numbering the capturing subpatterns in the whole pattern. However, substring capturing is carried out only for positive assertions, because it does not make sense for negative assertions.

    Assertions count towards the maximum of 200 parenthesized subpatterns.

  • ONCE-ONLY SUBPATTERNS

    With both maximizing and minimizing repetition, failure of what follows normally causes the repeated item to be re-evaluated to see if a different number of repeats allows the rest of the pattern to match. Sometimes it is useful to prevent this, either to change the nature of the match, or to cause it fail earlier than it otherwise might, when the author of the pattern knows there is no point in carrying on.

    Consider, for example, the pattern \d+foo when applied to the subject line

      123456bar
    

    After matching all 6 digits and then failing to match "foo", the normal action of the matcher is to try again with only 5 digits matching the \d+ item, and then with 4, and so on, before ultimately failing. Once-only subpatterns provide the means for specifying that once a portion of the pattern has matched, it is not to be re-evaluated in this way, so the matcher would give up immediately on failing to match "foo" the first time. The notation is another kind of special parenthesis, starting with (?> as in this example:

      (?>\d+)bar
    

    This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from backtracking into it. Backtracking past it to previous items, however, works as normal.

    An alternative description is that a subpattern of this type matches the string of characters that an identical standalone pattern would match, if anchored at the current point in the subject string.

    Once-only subpatterns are not capturing subpatterns. Simple cases such as the above example can be thought of as a maximizing repeat that must swallow everything it can. So, while both \d+ and \d+? are prepared to adjust the number of digits they match in order to make the rest of the pattern match, (?>\d+) can only match an entire sequence of digits.

    This construction can of course contain arbitrarily complicated subpatterns, and it can be nested.

    Once-only subpatterns can be used in conjunction with lookbehind assertions to specify efficient matching at the end of the subject string. Consider a simple pattern such as

      abcd$
    

    when applied to a long string which does not match. Because matching proceeds from left to right, PCRE will look for each "a" in the subject and then see if what follows matches the rest of the pattern. If the pattern is specified as

      ^.*abcd$
    

    the initial .* matches the entire string at first, but when this fails (because there is no following "a"), it backtracks to match all but the last character, then all but the last two characters, and so on. Once again the search for "a" covers the entire string, from right to left, so we are no better off. However, if the pattern is written as

      ^(?>.*)(?<=abcd)
    

    there can be no backtracking for the .* item; it can match only the entire string. The subsequent lookbehind assertion does a single test on the last four characters. If it fails, the match fails immediately. For long strings, this approach makes a significant difference to the processing time.

    When a pattern contains an unlimited repeat inside a subpattern that can itself be repeated an unlimited number of times, the use of a once-only subpattern is the only way to avoid some failing matches taking a very long time indeed. The pattern

      (\D+|<\d+>)*[!?]
    

    matches an unlimited number of substrings that either consist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to

      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    

    it takes a long time before reporting failure. This is because the string can be divided between the two repeats in a large number of ways, and all have to be tried. (The example used [!?] rather than a single character at the end, because both PCRE and Perl have an optimization that allows for fast failure when a single character is used. They remember the last single character that is required for a match, and fail early if it is not present in the string.) If the pattern is changed to

      ((?>\D+)|<\d+>)*[!?]
    

    sequences of non-digits cannot be broken, and failure happens quickly.

  • CONDITIONAL SUBPATTERNS

    It is possible to cause the matching process to obey a subpattern conditionally or to choose between two alternative subpatterns, depending on the result of an assertion, or whether a previous capturing subpattern matched or not. The two possible forms of conditional subpattern are

      (?(condition)yes-pattern)
      (?(condition)yes-pattern|no-pattern)
    

    If the condition is satisfied, the yes-pattern is used; otherwise the no-pattern (if present) is used. If there are more than two alternatives in the subpattern, a compile-time error occurs.

    There are two kinds of condition. If the text between the parentheses consists of a sequence of digits, the condition is satisfied if the capturing subpattern of that number has previously matched. The number must be greater than zero. Consider the following pattern, which contains non-significant white space to make it more readable (assume the PCRE_EXTENDED option) and to divide it into three parts for ease of discussion:

      ( \( )?    [^()]+    (?(1) \) )
    

    The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part matches one or more characters that are not parentheses. The third part is a conditional subpattern that tests whether the first set of parentheses matched or not. If they did, that is, if subject started with an opening parenthesis, the condition is true, and so the yes-pattern is executed and a closing parenthesis is required. Otherwise, since no-pattern is not present, the subpattern matches nothing. In other words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses.

    If the condition is not a sequence of digits, it must be an assertion. This may be a positive or negative lookahead or lookbehind assertion. Consider this pattern, again containing non-significant white space, and with the two alternatives on the second line:

      (?(?=[^a-z]*[a-z])
      \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} )
    

    The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a letter is found, the subject is matched against the first alternative; otherwise it is matched against the second. This pattern matches strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits.

  • COMMENTS

    The sequence (?# marks the start of a comment which continues up to the next closing parenthesis. Nested parentheses are not permitted. The characters that make up a comment play no part in the pattern matching at all.

    If the PCRE_EXTENDED option is set, an unescaped # character outside a character class introduces a comment that continues up to the next newline character in the pattern.

  • RECURSIVE PATTERNS

    Consider the problem of matching a string in parentheses, allowing for unlimited nested parentheses. Without the use of recursion, the best that can be done is to use a pattern that matches up to some fixed depth of nesting. It is not possible to handle an arbitrary nesting depth. Perl 5.6 has provided an experimental facility that allows regular expressions to recurse (amongst other things). It does this by interpolating Perl code in the expression at run time, and the code can refer to the expression itself. A Perl pattern to solve the parentheses problem can be created like this:

      $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x;
    

    The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears. Obviously, PCRE cannot support the interpolation of Perl code. Instead, the special item (?R) is provided for the specific case of recursion. This PCRE pattern solves the parentheses problem (assume the PCRE_EXTENDED option is set so that white space is ignored):

      \( ( (?>[^()]+) | (?R) )* \)
    

    First it matches an opening parenthesis. Then it matches any number of substrings which can either be a sequence of non-parentheses, or a recursive match of the pattern itself (i.e. a correctly parenthesized substring). Finally there is a closing parenthesis.

    This particular example pattern contains nested unlimited repeats, and so the use of a once-only subpattern for matching strings of non-parentheses is important when applying the pattern to strings that do not match. For example, when it is applied to

      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()
    

    it yields "no match" quickly. However, if a once-only subpattern is not used, the match runs for a very long time indeed because there are so many different ways the + and * repeats can carve up the subject, and all have to be tested before failure can be reported.

    The values set for any capturing subpatterns are those from the outermost level of the recursion at which the subpattern value is set. If the pattern above is matched against

      (ab(cd)ef)
    

    the value for the capturing parentheses is "ef", which is the last value taken on at the top level. If additional parentheses are added, giving

      \( ( ( (?>[^()]+) | (?R) )* ) \)
         ^                        ^
         ^                        ^
    
    the string they capture is "ab(cd)ef", the contents of the top level parentheses. If there are more than 15 capturing parentheses in a pattern, PCRE has to obtain extra memory to store data during a recursion, which it does by using pcre_malloc, freeing it via pcre_free afterwards. If no memory can be obtained, it saves data for the first 15 capturing parentheses only, as there is no way to give an out-of-memory error from within a recursion.

  • PERFORMANCE

    Certain items that may appear in patterns are more efficient than others. It is more efficient to use a character class like [aeiou] than a set of alternatives such as (a|e|i|o|u). In general, the simplest construction that provides the required behaviour is usually the most efficient. Jeffrey Friedl's book contains a lot of discussion about optimizing regular expressions for efficient performance.

    When a pattern begins with .* and the PCRE_DOTALL option is set, the pattern is implicitly anchored by PCRE, since it can match only at the start of a subject string. However, if PCRE_DOTALL is not set, PCRE cannot make this optimization, because the . metacharacter does not then match a newline, and if the subject string contains newlines, the pattern may match from the character immediately following one of them instead of from the very start. For example, the pattern

      (.*) second
    

    matches the subject "first\nand second" (where \n stands for a newline character) with the first captured substring being "and". In order to do this, PCRE has to retry the match starting after every newline in the subject.

    If you are using such a pattern with subject strings that do not contain newlines, the best performance is obtained by setting PCRE_DOTALL, or starting the pattern with ^.* to indicate explicit anchoring. That saves PCRE from having to scan along the subject looking for a newline to restart at.

    Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match. Consider the pattern fragment

      (a+)*
    

    This can match "aaaa" in 33 different ways, and this number increases very rapidly as the string gets longer. (The * repeat can match 0, 1, 2, 3, or 4 times, and for each of those cases other than 0, the + repeats can match different numbers of times.) When the remainder of the pattern is such that the entire match is going to fail, PCRE has in principle to try every possible variation, and this can take an extremely long time.

    An optimization catches some of the more simple cases such as

      (a+)*b
    

    where a literal character follows. Before embarking on the standard matching procedure, PCRE checks that there is a "b" later in the subject string, and if there is not, it fails the match immediately. However, when there is no following literal this optimization cannot be used. You can see the difference by comparing the behaviour of

      (a+)*\d
    

    with the pattern above. The former gives a failure almost instantly when applied to a whole line of "a" characters, whereas the latter takes an appreciable time with strings longer than about 20 characters.

  • UTF-8 SUPPORT

    Starting at release 3.3, PCRE has some support for character strings encoded in the UTF-8 format. This is incomplete, and is regarded as experimental. In order to use it, you must configure PCRE to include UTF-8 support in the code, and, in addition, you must call pcre_compile() with the PCRE_UTF8 option flag. When you do this, both the pattern and any subject strings that are matched against it are treated as UTF-8 strings instead of just strings of bytes, but only in the cases that are mentioned below.

    If you compile PCRE with UTF-8 support, but do not use it at run time, the library will be a bit bigger, but the additional run time overhead is limited to testing the PCRE_UTF8 flag in several places, so should not be very large.

    PCRE assumes that the strings it is given contain valid UTF-8 codes. It does not diagnose invalid UTF-8 strings. If you pass invalid UTF-8 strings to PCRE, the results are undefined.

    Running with PCRE_UTF8 set causes these changes in the way PCRE works:

    1. In a pattern, the escape sequence \x{...}, where the contents of the braces is a string of hexadecimal digits, is interpreted as a UTF-8 character whose code number is the given hexadecimal number, for example: \x{1234}. This inserts from one to six literal bytes into the pattern, using the UTF-8 encoding. If a non-hexadecimal digit appears between the braces, the item is not recognized.

    2. The original hexadecimal escape sequence, \xhh, generates a two-byte UTF-8 character if its value is greater than 127.

    3. Repeat quantifiers are NOT correctly handled if they follow a multibyte character. For example, \x{100}* and \xc3+ do not work. If you want to repeat such characters, you must enclose them in non-capturing parentheses, for example (?:\x{100}), at present.

    4. The dot metacharacter matches one UTF-8 character instead of a single byte.

    5. Unlike literal UTF-8 characters, the dot metacharacter followed by a repeat quantifier does operate correctly on UTF-8 characters instead of single bytes.

    4. Although the \x{...} escape is permitted in a character class, characters whose values are greater than 255 cannot be included in a class.

    5. A class is matched against a UTF-8 character instead of just a single byte, but it can match only characters whose values are less than 256. Characters with greater values always fail to match a class.

    6. Repeated classes work correctly on multiple characters.

    7. Classes containing just a single character whose value is greater than 127 (but less than 256), for example, [\x80] or [^\x{93}], do not work because these are optimized into single byte matches. In the first case, of course, the class brackets are just redundant.

    8. Lookbehind assertions move backwards in the subject by a fixed number of characters instead of a fixed number of bytes. Simple cases have been tested to work correctly, but there may be hidden gotchas herein.

    9. The character types such as \d and \w do not work correctly with UTF-8 characters. They continue to test a single byte.

    10. Anything not explicitly mentioned here continues to work in bytes rather than in characters.

    The following UTF-8 features of Perl 5.6 are not implemented:

    1. The escape sequence \C to match a single byte.

    2. The use of Unicode tables and properties and escapes \p, \P, and \X.

  • AUTHOR

    Philip Hazel <ph10@cam.ac.uk>
    University Computing Service,
    New Museums Site,
    Cambridge CB2 3QG, England.
    Phone: +44 1223 334714

    Last updated: 28 August 2000,

      the 250th anniversary of the death of J.S. Bach.
    
    Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/authors000640 001751 001751 00000000263 10546014077 017075 0ustar00fkfk000000 000000 Written by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2000 University of Cambridge privoxy-3.0.21-stable/./pcre/doc/readme000640 001751 001751 00000030357 10546014100 016637 0ustar00fkfk000000 000000 README file for PCRE (Perl-compatible regular expression library) ----------------------------------------------------------------- The latest release of PCRE is always available from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz Please read the NEWS file if you are upgrading from a previous release. PCRE has its own native API, but a set of "wrapper" functions that are based on the POSIX API are also supplied in the library libpcreposix. Note that this just provides a POSIX calling interface to PCRE: the regular expressions themselves still follow Perl syntax and semantics. The header file for the POSIX-style functions is called pcreposix.h. The official POSIX name is regex.h, but I didn't want to risk possible problems with existing files of that name by distributing it that way. To use it with an existing program that uses the POSIX API, it will have to be renamed or pointed at by a link. Building PCRE on a Unix system ------------------------------ To build PCRE on a Unix system, run the "configure" command in the PCRE distribution directory. This is a standard GNU "autoconf" configuration script, for which generic instructions are supplied in INSTALL. On many systems just running "./configure" is sufficient, but the usual methods of changing standard defaults are available. For example, CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local specifies that the C compiler should be run with the flags '-O2 -Wall' instead of the default, and that "make install" should install PCRE under /opt/local instead of the default /usr/local. If you want to make use of the experimential, incomplete support for UTF-8 character strings in PCRE, you must add --enable-utf8 to the "configure" command. Without it, the code for handling UTF-8 is not included in the library. (Even when included, it still has to be enabled by an option at run time.) The "configure" script builds four files: . Makefile is built by copying Makefile.in and making substitutions. . config.h is built by copying config.in and making substitutions. . pcre-config is built by copying pcre-config.in and making substitutions. . RunTest is a script for running tests Once "configure" has run, you can run "make". It builds two libraries called libpcre and libpcreposix, a test program called pcretest, and the pcregrep command. You can use "make install" to copy these, and the public header file pcre.h, to appropriate live directories on your system, in the normal way. Running "make install" also installs the command pcre-config, which can be used to recall information about the PCRE configuration and installation. For example, pcre-config --version prints the version number, and pcre-config --libs outputs information about where the library is installed. This command can be included in makefiles for programs that use PCRE, saving the programmer from having to remember too many details. Shared libraries on Unix systems -------------------------------- The default distribution builds PCRE as two shared libraries. This support is new and experimental and may not work on all systems. It relies on the "libtool" scripts - these are distributed with PCRE. It should build a "libtool" script and use this to compile and link shared libraries, which are placed in a subdirectory called .libs. The programs pcretest and pcregrep are built to use these uninstalled libraries by means of wrapper scripts. When you use "make install" to install shared libraries, pcregrep and pcretest are automatically re-built to use the newly installed libraries. However, only pcregrep is installed, as pcretest is really just a test program. To build PCRE using static libraries you must use --disable-shared when configuring it. For example ./configure --prefix=/usr/gnu --disable-shared Then run "make" in the usual way. Building on non-Unix systems ---------------------------- For a non-Unix system, read the comments in the file NON-UNIX-USE. PCRE has been compiled on Windows systems and on Macintoshes, but I don't know the details because I don't use those systems. It should be straightforward to build PCRE on any system that has a Standard C compiler, because it uses only Standard C functions. Testing PCRE ------------ To test PCRE on a Unix system, run the RunTest script in the pcre directory. (This can also be run by "make runtest", "make check", or "make test".) For other systems, see the instruction in NON-UNIX-USE. The script runs the pcretest test program (which is documented in doc/pcretest.txt) on each of the testinput files (in the testdata directory) in turn, and compares the output with the contents of the corresponding testoutput file. A file called testtry is used to hold the output from pcretest. To run pcretest on just one of the test files, give its number as an argument to RunTest, for example: RunTest 3 The first and third test files can also be fed directly into the perltest script to check that Perl gives the same results. The third file requires the additional features of release 5.005, which is why it is kept separate from the main test input, which needs only Perl 5.004. In the long run, when 5.005 (or higher) is widespread, these two test files may get amalgamated. The second set of tests check pcre_fullinfo(), pcre_info(), pcre_study(), pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error detection, and run-time flags that are specific to PCRE, as well as the POSIX wrapper API. It also uses the debugging flag to check some of the internals of pcre_compile(). If you build PCRE with a locale setting that is not the standard C locale, the character tables may be different (see next paragraph). In some cases, this may cause failures in the second set of tests. For example, in a locale where the isprint() function yields TRUE for characters in the range 128-255, the use of [:isascii:] inside a character class defines a different set of characters, and this shows up in this test as a difference in the compiled code, which is being listed for checking. Where the comparison test output contains [\x00-\x7f] the test will contain [\x00-\xff], and similarly in some other cases. This is not a bug in PCRE. The fourth set of tests checks pcre_maketables(), the facility for building a set of character tables for a specific locale and using them instead of the default tables. The tests make use of the "fr" (French) locale. Before running the test, the script checks for the presence of this locale by running the "locale" command. If that command fails, or if it doesn't include "fr" in the list of available locales, the fourth test cannot be run, and a comment is output to say why. If running this test produces instances of the error ** Failed to set locale "fr" in the comparison output, it means that locale is not available on your system, despite being listed by "locale". This does not mean that PCRE is broken. The fifth test checks the experimental, incomplete UTF-8 support. It is not run automatically unless PCRE is built with UTF-8 support. This file can be fed directly to the perltest8 script, which requires Perl 5.6 or higher. The sixth file tests internal UTF-8 features of PCRE that are not relevant to Perl. Character tables ---------------- PCRE uses four tables for manipulating and identifying characters. The final argument of the pcre_compile() function is a pointer to a block of memory containing the concatenated tables. A call to pcre_maketables() can be used to generate a set of tables in the current locale. If the final argument for pcre_compile() is passed as NULL, a set of default tables that is built into the binary is used. The source file called chartables.c contains the default set of tables. This is not supplied in the distribution, but is built by the program dftables (compiled from dftables.c), which uses the ANSI C character handling functions such as isalnum(), isalpha(), isupper(), islower(), etc. to build the table sources. This means that the default C locale which is set for your system will control the contents of these default tables. You can change the default tables by editing chartables.c and then re-building PCRE. If you do this, you should probably also edit Makefile to ensure that the file doesn't ever get re-generated. The first two 256-byte tables provide lower casing and case flipping functions, respectively. The next table consists of three 32-byte bit maps which identify digits, "word" characters, and white space, respectively. These are used when building 32-byte bit maps that represent character classes. The final 256-byte table has bits indicating various character types, as follows: 1 white space character 2 letter 4 decimal digit 8 hexadecimal digit 16 alphanumeric or '_' 128 regular expression metacharacter or binary zero You should not alter the set of characters that contain the 128 bit, as that will cause PCRE to malfunction. Manifest -------- The distribution should contain the following files: (A) The actual source files of the PCRE library functions and their headers: dftables.c auxiliary program for building chartables.c get.c ) maketables.c ) study.c ) source of pcre.c ) the functions pcreposix.c ) pcre.in "source" for the header for the external API; pcre.h is built from this by "configure" pcreposix.h header for the external POSIX wrapper API internal.h header for internal use config.in template for config.h, which is built by configure (B) Auxiliary files: AUTHORS information about the author of PCRE ChangeLog log of changes to the code INSTALL generic installation instructions LICENCE conditions for the use of PCRE COPYING the same, using GNU's standard name Makefile.in template for Unix Makefile, which is built by configure NEWS important changes in this release NON-UNIX-USE notes on building PCRE on non-Unix systems README this file RunTest.in template for a Unix shell script for running tests config.guess ) files used by libtool, config.sub ) used only when building a shared library configure a configuring shell script (built by autoconf) configure.in the autoconf input used to build configure doc/Tech.Notes notes on the encoding doc/pcre.3 man page source for the PCRE functions doc/pcre.html HTML version doc/pcre.txt plain text version doc/pcreposix.3 man page source for the POSIX wrapper API doc/pcreposix.html HTML version doc/pcreposix.txt plain text version doc/pcretest.txt documentation of test program doc/perltest.txt documentation of Perl test program doc/pcregrep.1 man page source for the pcregrep utility doc/pcregrep.html HTML version doc/pcregrep.txt plain text version install-sh a shell script for installing files ltconfig ) files used to build "libtool", ltmain.sh ) used only when building a shared library pcretest.c test program perltest Perl test program perltest8 Perl test program for UTF-8 tests pcregrep.c source of a grep utility that uses PCRE pcre-config.in source of script which retains PCRE information testdata/testinput1 test data, compatible with Perl 5.004 and 5.005 testdata/testinput2 test data for error messages and non-Perl things testdata/testinput3 test data, compatible with Perl 5.005 testdata/testinput4 test data for locale-specific tests testdata/testinput5 test data for UTF-8 tests compatible with Perl 5.6 testdata/testinput6 test data for other UTF-8 tests testdata/testoutput1 test results corresponding to testinput1 testdata/testoutput2 test results corresponding to testinput2 testdata/testoutput3 test results corresponding to testinput3 testdata/testoutput4 test results corresponding to testinput4 testdata/testoutput5 test results corresponding to testinput5 testdata/testoutput6 test results corresponding to testinput6 (C) Auxiliary files for Win32 DLL dll.mk pcre.def Philip Hazel August 2000 privoxy-3.0.21-stable/./pcre/doc/copying000640 001751 001751 00000003361 10546014077 017062 0ustar00fkfk000000 000000 PCRE LICENCE ------------ PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2000 University of Cambridge Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ should also be given in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. End privoxy-3.0.21-stable/./pcre/doc/pcreposix.txt000640 001751 001751 00000014026 10546014100 020227 0ustar00fkfk000000 000000 NAME pcreposix - POSIX API for Perl-compatible regular expres- sions. SYNOPSIS #include int regcomp(regex_t *preg, const char *pattern, int cflags); int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); void regfree(regex_t *preg); DESCRIPTION This set of functions provides a POSIX-style API to the PCRE regular expression package. See the pcre documentation for a description of the native API, which contains additional functionality. The functions described here are just wrapper functions that ultimately call the native API. Their prototypes are defined in the pcreposix.h header file, and on Unix systems the library itself is called pcreposix.a, so can be accessed by adding -lpcreposix to the command for linking an application which uses them. Because the POSIX functions call the native ones, it is also necessary to add -lpcre. I have implemented only those option bits that can be rea- sonably mapped to PCRE native options. In addition, the options REG_EXTENDED and REG_NOSUB are defined with the value zero. They have no effect, but since programs that are written to the POSIX interface often use them, this makes it easier to slot in PCRE as a replacement library. Other POSIX options are not even defined. When PCRE is called via these functions, it is only the API that is POSIX-like in style. The syntax and semantics of the regular expressions themselves are still those of Perl, sub- ject to the setting of various PCRE options, as described below. The header for these functions is supplied as pcreposix.h to avoid any potential clash with other POSIX libraries. It can, of course, be renamed or aliased as regex.h, which is the "correct" name. It provides two structure types, regex_t for compiled internal forms, and regmatch_t for returning captured substrings. It also defines some constants whose names start with "REG_"; these are used for setting options and identifying error codes. COMPILING A PATTERN The function regcomp() is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument pattern. The preg argument is a pointer to a regex_t structure which is used as a base for storing information about the compiled expres- sion. The argument cflags is either zero, or contains one or more of the bits defined by the following macros: REG_ICASE The PCRE_CASELESS option is set when the expression is passed for compilation to the native function. REG_NEWLINE The PCRE_MULTILINE option is set when the expression is passed for compilation to the native function. In the absence of these flags, no options are passed to the native function. This means the the regex is compiled with PCRE default semantics. In particular, the way it handles newline characters in the subject string is the Perl way, not the POSIX way. Note that setting PCRE_MULTILINE has only some of the effects specified for REG_NEWLINE. It does not affect the way newlines are matched by . (they aren't) or a negative class such as [^a] (they are). The yield of regcomp() is zero on success, and non-zero oth- erwise. The preg structure is filled in on success, and one member of the structure is publicized: re_nsub contains the number of capturing subpatterns in the regular expression. Various error codes are defined in the header file. MATCHING A PATTERN The function regexec() is called to match a pre-compiled pattern preg against a given string, which is terminated by a zero byte, subject to the options in eflags. These can be: REG_NOTBOL The PCRE_NOTBOL option is set when calling the underlying PCRE matching function. REG_NOTEOL The PCRE_NOTEOL option is set when calling the underlying PCRE matching function. The portion of the string that was matched, and also any captured substrings, are returned via the pmatch argument, which points to an array of nmatch structures of type regmatch_t, containing the members rm_so and rm_eo. These contain the offset to the first character of each substring and the offset to the first character after the end of each substring, respectively. The 0th element of the vector relates to the entire portion of string that was matched; subsequent elements relate to the capturing subpatterns of the regular expression. Unused entries in the array have both structure members set to -1. A successful match yields a zero return; various error codes are defined in the header file, of which REG_NOMATCH is the "expected" failure code. ERROR MESSAGES The regerror() function maps a non-zero errorcode from either regcomp or regexec to a printable message. If preg is not NULL, the error should have arisen from the use of that structure. A message terminated by a binary zero is placed in errbuf. The length of the message, including the zero, is limited to errbuf_size. The yield of the function is the size of buffer needed to hold the whole message. STORAGE Compiling a regular expression causes memory to be allocated and associated with the preg structure. The function reg- free() frees all such memory, after which preg may no longer be used as a compiled expression. AUTHOR Philip Hazel University Computing Service, New Museums Site, Cambridge CB2 3QG, England. Phone: +44 1223 334714 Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/pcretest.txt000640 001751 001751 00000024456 10546014100 020054 0ustar00fkfk000000 000000 The pcretest program -------------------- This program is intended for testing PCRE, but it can also be used for experimenting with regular expressions. If it is given two filename arguments, it reads from the first and writes to the second. If it is given only one filename argument, it reads from that file and writes to stdout. Otherwise, it reads from stdin and writes to stdout, and prompts for each line of input, using "re>" to prompt for regular expressions, and "data>" to prompt for data lines. The program handles any number of sets of input on a single input file. Each set starts with a regular expression, and continues with any number of data lines to be matched against the pattern. An empty line signals the end of the data lines, at which point a new regular expression is read. The regular expressions are given enclosed in any non-alphameric delimiters other than backslash, for example /(a|bc)x+yz/ White space before the initial delimiter is ignored. A regular expression may be continued over several input lines, in which case the newline characters are included within it. See the test input files in the testdata directory for many examples. It is possible to include the delimiter within the pattern by escaping it, for example /abc\/def/ If you do so, the escape and the delimiter form part of the pattern, but since delimiters are always non-alphameric, this does not affect its interpretation. If the terminating delimiter is immediately followed by a backslash, for example, /abc/\ then a backslash is added to the end of the pattern. This is done to provide a way of testing the error condition that arises if a pattern finishes with a backslash, because /abc\/ is interpreted as the first line of a pattern that starts with "abc/", causing pcretest to read the next line as a continuation of the regular expression. PATTERN MODIFIERS ----------------- The pattern may be followed by i, m, s, or x to set the PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, or PCRE_EXTENDED options, respectively. For example: /caseless/i These modifier letters have the same effect as they do in Perl. There are others which set PCRE options that do not correspond to anything in Perl: /A, /E, and /X set PCRE_ANCHORED, PCRE_DOLLAR_ENDONLY, and PCRE_EXTRA respectively. Searching for all possible matches within each subject string can be requested by the /g or /G modifier. After finding a match, PCRE is called again to search the remainder of the subject string. The difference between /g and /G is that the former uses the startoffset argument to pcre_exec() to start searching at a new point within the entire string (which is in effect what Perl does), whereas the latter passes over a shortened substring. This makes a difference to the matching process if the pattern begins with a lookbehind assertion (including \b or \B). If any call to pcre_exec() in a /g or /G sequence matches an empty string, the next call is done with the PCRE_NOTEMPTY and PCRE_ANCHORED flags set in order to search for another, non-empty, match at the same point. If this second match fails, the start offset is advanced by one, and the normal match is retried. This imitates the way Perl handles such cases when using the /g modifier or the split() function. There are a number of other modifiers for controlling the way pcretest operates. The /+ modifier requests that as well as outputting the substring that matched the entire pattern, pcretest should in addition output the remainder of the subject string. This is useful for tests where the subject contains multiple copies of the same substring. The /L modifier must be followed directly by the name of a locale, for example, /pattern/Lfr For this reason, it must be the last modifier letter. The given locale is set, pcre_maketables() is called to build a set of character tables for the locale, and this is then passed to pcre_compile() when compiling the regular expression. Without an /L modifier, NULL is passed as the tables pointer; that is, /L applies only to the expression on which it appears. The /I modifier requests that pcretest output information about the compiled expression (whether it is anchored, has a fixed first character, and so on). It does this by calling pcre_fullinfo() after compiling an expression, and outputting the information it gets back. If the pattern is studied, the results of that are also output. The /D modifier is a PCRE debugging feature, which also assumes /I. It causes the internal form of compiled regular expressions to be output after compilation. The /S modifier causes pcre_study() to be called after the expression has been compiled, and the results used when the expression is matched. The /M modifier causes the size of memory block used to hold the compiled pattern to be output. The /P modifier causes pcretest to call PCRE via the POSIX wrapper API rather than its native API. When this is done, all other modifiers except /i, /m, and /+ are ignored. REG_ICASE is set if /i is present, and REG_NEWLINE is set if /m is present. The wrapper functions force PCRE_DOLLAR_ENDONLY always, and PCRE_DOTALL unless REG_NEWLINE is set. The /8 modifier causes pcretest to call PCRE with the PCRE_UTF8 option set. This turns on the (currently incomplete) support for UTF-8 character handling in PCRE, provided that it was compiled with this support enabled. This modifier also causes any non-printing characters in output strings to be printed using the \x{hh...} notation if they are valid UTF-8 sequences. DATA LINES ---------- Before each data line is passed to pcre_exec(), leading and trailing whitespace is removed, and it is then scanned for \ escapes. The following are recognized: \a alarm (= BEL) \b backspace \e escape \f formfeed \n newline \r carriage return \t tab \v vertical tab \nnn octal character (up to 3 octal digits) \xhh hexadecimal character (up to 2 hex digits) \x{hh...} hexadecimal UTF-8 character \A pass the PCRE_ANCHORED option to pcre_exec() \B pass the PCRE_NOTBOL option to pcre_exec() \Cdd call pcre_copy_substring() for substring dd after a successful match (any decimal number less than 32) \Gdd call pcre_get_substring() for substring dd after a successful match (any decimal number less than 32) \L call pcre_get_substringlist() after a successful match \N pass the PCRE_NOTEMPTY option to pcre_exec() \Odd set the size of the output vector passed to pcre_exec() to dd (any number of decimal digits) \Z pass the PCRE_NOTEOL option to pcre_exec() A backslash followed by anything else just escapes the anything else. If the very last character is a backslash, it is ignored. This gives a way of passing an empty line as data, since a real empty line terminates the data input. If /P was present on the regex, causing the POSIX wrapper API to be used, only \B, and \Z have any effect, causing REG_NOTBOL and REG_NOTEOL to be passed to regexec() respectively. The use of \x{hh...} to represent UTF-8 characters is not dependent on the use of the /8 modifier on the pattern. It is recognized always. There may be any number of hexadecimal digits inside the braces. The result is from one to six bytes, encoded according to the UTF-8 rules. OUTPUT FROM PCRETEST -------------------- When a match succeeds, pcretest outputs the list of captured substrings that pcre_exec() returns, starting with number 0 for the string that matched the whole pattern. Here is an example of an interactive pcretest run. $ pcretest PCRE version 2.06 08-Jun-1999 re> /^abc(\d+)/ data> abc123 0: abc123 1: 123 data> xyz No match If the strings contain any non-printing characters, they are output as \0x escapes, or as \x{...} escapes if the /8 modifier was present on the pattern. If the pattern has the /+ modifier, then the output for substring 0 is followed by the the rest of the subject string, identified by "0+" like this: re> /cat/+ data> cataract 0: cat 0+ aract If the pattern has the /g or /G modifier, the results of successive matching attempts are output in sequence, like this: re> /\Bi(\w\w)/g data> Mississippi 0: iss 1: ss 0: iss 1: ss 0: ipp 1: pp "No match" is output only if the first match attempt fails. If any of \C, \G, or \L are present in a data line that is successfully matched, the substrings extracted by the convenience functions are output with C, G, or L after the string number instead of a colon. This is in addition to the normal full list. The string length (that is, the return from the extraction function) is given in parentheses after each string for \C and \G. Note that while patterns can be continued over several lines (a plain ">" prompt is used for continuations), data lines may not. However newlines can be included in data by means of the \n escape. COMMAND LINE OPTIONS -------------------- If the -p option is given to pcretest, it is equivalent to adding /P to each regular expression: the POSIX wrapper API is used to call PCRE. None of the following flags has any effect in this case. If the option -d is given to pcretest, it is equivalent to adding /D to each regular expression: the internal form is output after compilation. If the option -i is given to pcretest, it is equivalent to adding /I to each regular expression: information about the compiled pattern is given after compilation. If the option -m is given to pcretest, it outputs the size of each compiled pattern after it has been compiled. It is equivalent to adding /M to each regular expression. For compatibility with earlier versions of pcretest, -s is a synonym for -m. If the -t option is given, each compile, study, and match is run 20000 times while being timed, and the resulting time per compile or match is output in milliseconds. Do not set -t with -m, because you will then get the size output 20000 times and the timing will be distorted. If you want to change the number of repetitions used for timing, edit the definition of LOOPREPEAT at the top of pcretest.c Philip Hazel August 2000 privoxy-3.0.21-stable/./pcre/doc/pcregrep.1000640 001751 001751 00000005022 10546014100 017337 0ustar00fkfk000000 000000 .TH PCREGREP 1 .SH NAME pcregrep - a grep with Perl-compatible regular expressions. .SH SYNOPSIS .B pcregrep [-Vchilnsvx] pattern [file] ... .SH DESCRIPTION \fBpcregrep\fR searches files for character patterns, in the same way as other grep commands do, but it uses the PCRE regular expression library to support patterns that are compatible with the regular expressions of Perl 5. See \fBpcre(3)\fR for a full description of syntax and semantics. If no files are specified, \fBpcregrep\fR reads the standard input. By default, each line that matches the pattern is copied to the standard output, and if there is more than one file, the file name is printed before each line of output. However, there are options that can change how \fBpcregrep\fR behaves. Lines are limited to BUFSIZ characters. BUFSIZ is defined in \fB\fR. The newline character is removed from the end of each line before it is matched against the pattern. .SH OPTIONS .TP 10 \fB-V\fR Write the version number of the PCRE library being used to the standard error stream. .TP \fB-c\fR Do not print individual lines; instead just print a count of the number of lines that would otherwise have been printed. If several files are given, a count is printed for each of them. .TP \fB-h\fR Suppress printing of filenames when searching multiple files. .TP \fB-i\fR Ignore upper/lower case distinctions during comparisons. .TP \fB-l\fR Instead of printing lines from the files, just print the names of the files containing lines that would have been printed. Each file name is printed once, on a separate line. .TP \fB-n\fR Precede each line by its line number in the file. .TP \fB-s\fR Work silently, that is, display nothing except error messages. The exit status indicates whether any matches were found. .TP \fB-v\fR Invert the sense of the match, so that lines which do \fInot\fR match the pattern are now the ones that are found. .TP \fB-x\fR Force the pattern to be anchored (it must start matching at the beginning of the line) and in addition, require it to match the entire line. This is equivalent to having ^ and $ characters at the start and end of each alternative branch in the regular expression. .SH SEE ALSO \fBpcre(3)\fR, Perl 5 documentation .SH DIAGNOSTICS Exit status is 0 if any matches were found, 1 if no matches were found, and 2 for syntax errors or inacessible files (even if matches were found). .SH AUTHOR Philip Hazel .br Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/Tech.Notes000640 001751 001751 00000022731 10546014077 017366 0ustar00fkfk000000 000000 Technical Notes about PCRE -------------------------- Many years ago I implemented some regular expression functions to an algorithm suggested by Martin Richards. These were not Unix-like in form, and were quite restricted in what they could do by comparison with Perl. The interesting part about the algorithm was that the amount of space required to hold the compiled form of an expression was known in advance. The code to apply an expression did not operate by backtracking, as the Henry Spencer and Perl code does, but instead checked all possibilities simultaneously by keeping a list of current states and checking all of them as it advanced through the subject string. (In the terminology of Jeffrey Friedl's book, it was a "DFA algorithm".) When the pattern was all used up, all remaining states were possible matches, and the one matching the longest subset of the subject string was chosen. This did not necessarily maximize the individual wild portions of the pattern, as is expected in Unix and Perl-style regular expressions. By contrast, the code originally written by Henry Spencer and subsequently heavily modified for Perl actually compiles the expression twice: once in a dummy mode in order to find out how much store will be needed, and then for real. The execution function operates by backtracking and maximizing (or, optionally, minimizing in Perl) the amount of the subject that matches individual wild portions of the pattern. This is an "NFA algorithm" in Friedl's terminology. For the set of functions that forms PCRE (which are unrelated to those mentioned above), I tried at first to invent an algorithm that used an amount of store bounded by a multiple of the number of characters in the pattern, to save on compiling time. However, because of the greater complexity in Perl regular expressions, I couldn't do this. In any case, a first pass through the pattern is needed, in order to find internal flag settings like (?i) at top level. So PCRE works by running a very degenerate first pass to calculate a maximum store size, and then a second pass to do the real compile - which may use a bit less than the predicted amount of store. The idea is that this is going to turn out faster because the first pass is degenerate and the second pass can just store stuff straight into the vector. It does make the compiling functions bigger, of course, but they have got quite big anyway to handle all the Perl stuff. The compiled form of a pattern is a vector of bytes, containing items of variable length. The first byte in an item is an opcode, and the length of the item is either implicit in the opcode or contained in the data bytes which follow it. A list of all the opcodes follows: Opcodes with no following data ------------------------------ These items are all just one byte long OP_END end of pattern OP_ANY match any character OP_SOD match start of data: \A OP_CIRC ^ (start of data, or after \n in multiline) OP_NOT_WORD_BOUNDARY \W OP_WORD_BOUNDARY \w OP_NOT_DIGIT \D OP_DIGIT \d OP_NOT_WHITESPACE \S OP_WHITESPACE \s OP_NOT_WORDCHAR \W OP_WORDCHAR \w OP_EODN match end of data or \n at end: \Z OP_EOD match end of data: \z OP_DOLL $ (end of data, or before \n in multiline) OP_RECURSE match the pattern recursively Repeating single characters --------------------------- The common repeats (*, +, ?) when applied to a single character appear as two-byte items using the following opcodes: OP_STAR OP_MINSTAR OP_PLUS OP_MINPLUS OP_QUERY OP_MINQUERY Those with "MIN" in their name are the minimizing versions. Each is followed by the character that is to be repeated. Other repeats make use of OP_UPTO OP_MINUPTO OP_EXACT which are followed by a two-byte count (most significant first) and the repeated character. OP_UPTO matches from 0 to the given number. A repeat with a non-zero minimum and a fixed maximum is coded as an OP_EXACT followed by an OP_UPTO (or OP_MINUPTO). Repeating character types ------------------------- Repeats of things like \d are done exactly as for single characters, except that instead of a character, the opcode for the type is stored in the data byte. The opcodes are: OP_TYPESTAR OP_TYPEMINSTAR OP_TYPEPLUS OP_TYPEMINPLUS OP_TYPEQUERY OP_TYPEMINQUERY OP_TYPEUPTO OP_TYPEMINUPTO OP_TYPEEXACT Matching a character string --------------------------- The OP_CHARS opcode is followed by a one-byte count and then that number of characters. If there are more than 255 characters in sequence, successive instances of OP_CHARS are used. Character classes ----------------- OP_CLASS is used for a character class, provided there are at least two characters in the class. If there is only one character, OP_CHARS is used for a positive class, and OP_NOT for a negative one (that is, for something like [^a]). Another set of repeating opcodes (OP_NOTSTAR etc.) are used for a repeated, negated, single-character class. The normal ones (OP_STAR etc.) are used for a repeated positive single-character class. OP_CLASS is followed by a 32-byte bit map containing a 1 bit for every character that is acceptable. The bits are counted from the least significant end of each byte. Back references --------------- OP_REF is followed by a single byte containing the reference number. Repeating character classes and back references ----------------------------------------------- Single-character classes are handled specially (see above). This applies to OP_CLASS and OP_REF. In both cases, the repeat information follows the base item. The matching code looks at the following opcode to see if it is one of OP_CRSTAR OP_CRMINSTAR OP_CRPLUS OP_CRMINPLUS OP_CRQUERY OP_CRMINQUERY OP_CRRANGE OP_CRMINRANGE All but the last two are just single-byte items. The others are followed by four bytes of data, comprising the minimum and maximum repeat counts. Brackets and alternation ------------------------ A pair of non-capturing (round) brackets is wrapped round each expression at compile time, so alternation always happens in the context of brackets. Non-capturing brackets use the opcode OP_BRA, while capturing brackets use OP_BRA+1, OP_BRA+2, etc. [Note for North Americans: "bracket" to some English speakers, including myself, can be round, square, curly, or pointy. Hence this usage.] A bracket opcode is followed by two bytes which give the offset to the next alternative OP_ALT or, if there aren't any branches, to the matching KET opcode. Each OP_ALT is followed by two bytes giving the offset to the next one, or to the KET opcode. OP_KET is used for subpatterns that do not repeat indefinitely, while OP_KETRMIN and OP_KETRMAX are used for indefinite repetitions, minimally or maximally respectively. All three are followed by two bytes giving (as a positive number) the offset back to the matching BRA opcode. If a subpattern is quantified such that it is permitted to match zero times, it is preceded by one of OP_BRAZERO or OP_BRAMINZERO. These are single-byte opcodes which tell the matcher that skipping this subpattern entirely is a valid branch. A subpattern with an indefinite maximum repetition is replicated in the compiled data its minimum number of times (or once with a BRAZERO if the minimum is zero), with the final copy terminating with a KETRMIN or KETRMAX as appropriate. A subpattern with a bounded maximum repetition is replicated in a nested fashion up to the maximum number of times, with BRAZERO or BRAMINZERO before each replication after the minimum, so that, for example, (abc){2,5} is compiled as (abc)(abc)((abc)((abc)(abc)?)?)?. The 200-bracket limit does not apply to these internally generated brackets. Assertions ---------- Forward assertions are just like other subpatterns, but starting with one of the opcodes OP_ASSERT or OP_ASSERT_NOT. Backward assertions use the opcodes OP_ASSERTBACK and OP_ASSERTBACK_NOT, and the first opcode inside the assertion is OP_REVERSE, followed by a two byte count of the number of characters to move back the pointer in the subject string. When operating in UTF-8 mode, the count is a character count rather than a byte count. A separate count is present in each alternative of a lookbehind assertion, allowing them to have different fixed lengths. Once-only subpatterns --------------------- These are also just like other subpatterns, but they start with the opcode OP_ONCE. Conditional subpatterns ----------------------- These are like other subpatterns, but they start with the opcode OP_COND. If the condition is a back reference, this is stored at the start of the subpattern using the opcode OP_CREF followed by one byte containing the reference number. Otherwise, a conditional subpattern will always start with one of the assertions. Changing options ---------------- If any of the /i, /m, or /s options are changed within a parenthesized group, an OP_OPT opcode is compiled, followed by one byte containing the new settings of these flags. If there are several alternatives in a group, there is an occurrence of OP_OPT at the start of all those following the first options change, to set appropriate options for the start of the alternative. Immediately after the end of the group there is another such item to reset the flags to their previous values. Other changes of flag within the pattern can be handled entirely at compile time, and so do not cause anything to be put into the compiled data. Philip Hazel August 2000 privoxy-3.0.21-stable/./pcre/doc/pcre.txt000640 001751 001751 00000266117 10546014100 017156 0ustar00fkfk000000 000000 NAME pcre - Perl-compatible regular expressions. SYNOPSIS #include pcre *pcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr); pcre_extra *pcre_study(const pcre *code, int options, const char **errptr); int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject, int length, int startoffset, int options, int *ovector, int ovecsize); int pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int buffersize); int pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr); void pcre_free_substring(const char *stringptr); void pcre_free_substring_list(const char **stringptr); const unsigned char *pcre_maketables(void); int pcre_fullinfo(const pcre *code, const pcre_extra *extra, int what, void *where); int pcre_info(const pcre *code, int *optptr, *firstcharptr); char *pcre_version(void); void *(*pcre_malloc)(size_t); void (*pcre_free)(void *); DESCRIPTION The PCRE library is a set of functions that implement regu- lar expression pattern matching using the same syntax and semantics as Perl 5, with just a few differences (see below). The current implementation corresponds to Perl 5.005, with some additional features from later versions. This includes some experimental, incomplete support for UTF-8 encoded strings. Details of exactly what is and what is not supported are given below. PCRE has its own native API, which is described in this document. There is also a set of wrapper functions that correspond to the POSIX regular expression API. These are described in the pcreposix documentation. The native API function prototypes are defined in the header file pcre.h, and on Unix systems the library itself is called libpcre.a, so can be accessed by adding -lpcre to the command for linking an application which calls it. The header file defines the macros PCRE_MAJOR and PCRE_MINOR to contain the major and minor release numbers for the library. Applications can use these to include support for different releases. The functions pcre_compile(), pcre_study(), and pcre_exec() are used for compiling and matching regular expressions. The functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are convenience functions for extracting captured substrings from a matched subject string; pcre_free_substring() and pcre_free_substring_list() are also provided, to free the memory used for extracted strings. The function pcre_maketables() is used (optionally) to build a set of character tables in the current locale for passing to pcre_compile(). The function pcre_fullinfo() is used to find out information about a compiled pattern; pcre_info() is an obsolete version which returns only some of the available information, but is retained for backwards compatibility. The function pcre_version() returns a pointer to a string containing the version of PCRE and its date of release. The global variables pcre_malloc and pcre_free initially contain the entry points of the standard malloc() and free() functions respectively. PCRE calls the memory management functions via these variables, so a calling program can replace them if it wishes to intercept the calls. This should be done before calling any PCRE functions. MULTI-THREADING The PCRE functions can be used in multi-threading SunOS 5.8 Last change: 2 applications, with the proviso that the memory management functions pointed to by pcre_malloc and pcre_free are shared by all threads. The compiled form of a regular expression is not altered during matching, so the same compiled pattern can safely be used by several threads at once. COMPILING A PATTERN The function pcre_compile() is called to compile a pattern into an internal form. The pattern is a C string terminated by a binary zero, and is passed in the argument pattern. A pointer to a single block of memory that is obtained via pcre_malloc is returned. This contains the compiled code and related data. The pcre type is defined for this for conveni- ence, but in fact pcre is just a typedef for void, since the contents of the block are not externally defined. It is up to the caller to free the memory when it is no longer required. The size of a compiled pattern is roughly proportional to the length of the pattern string, except that each character class (other than those containing just a single character, negated or not) requires 33 bytes, and repeat quantifiers with a minimum greater than one or a bounded maximum cause the relevant portions of the compiled pattern to be repli- cated. The options argument contains independent bits that affect the compilation. It should be zero if no options are required. Some of the options, in particular, those that are compatible with Perl, can also be set and unset from within the pattern (see the detailed description of regular expres- sions below). For these options, the contents of the options argument specifies their initial settings at the start of compilation and execution. The PCRE_ANCHORED option can be set at the time of matching as well as at compile time. If errptr is NULL, pcre_compile() returns NULL immediately. Otherwise, if compilation of a pattern fails, pcre_compile() returns NULL, and sets the variable pointed to by errptr to point to a textual error message. The offset from the start of the pattern to the character where the error was discovered is placed in the variable pointed to by erroffset, which must not be NULL. If it is, an immediate error is given. If the final argument, tableptr, is NULL, PCRE uses a default set of character tables which are built when it is compiled, using the default C locale. Otherwise, tableptr must be the result of a call to pcre_maketables(). See the section on locale support below. The following option bits are defined in the header file: PCRE_ANCHORED If this bit is set, the pattern is forced to be "anchored", that is, it is constrained to match only at the start of the string which is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself, which is the only way to do it in Perl. PCRE_CASELESS If this bit is set, letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option. PCRE_DOLLAR_ENDONLY If this bit is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before the final character if it is a newline (but not before any other new- lines). The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. There is no equivalent to this option in Perl. PCRE_DOTALL If this bit is set, a dot metacharater in the pattern matches all characters, including newlines. Without it, new- lines are excluded. This option is equivalent to Perl's /s option. A negative class such as [^a] always matches a new- line character, independent of the setting of this option. PCRE_EXTENDED If this bit is set, whitespace data characters in the pat- tern are totally ignored except when escaped or inside a character class, and characters between an unescaped # out- side a character class and the next newline character, inclusive, are also ignored. This is equivalent to Perl's /x option, and makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence (?( which introduces a conditional sub- pattern. PCRE_EXTRA This option was invented in order to turn on additional functionality of PCRE that is incompatible with Perl, but it is currently of very little use. When set, any backslash in a pattern that is followed by a letter that has no special meaning causes an error, thus reserving these combinations for future expansion. By default, as in Perl, a backslash followed by a letter with no special meaning is treated as a literal. There are at present no other features controlled by this option. It can also be set by a (?X) option setting within a pattern. PCRE_MULTILINE By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless PCRE_DOLLAR_ENDONLY is set). This is the same as Perl. When PCRE_MULTILINE it is set, the "start of line" and "end of line" constructs match immediately following or immedi- ately before any newline in the subject string, respec- tively, as well as at the very start and end. This is equivalent to Perl's /m option. If there are no "\n" charac- ters in a subject string, or no occurrences of ^ or $ in a pattern, setting PCRE_MULTILINE has no effect. PCRE_UNGREEDY This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern. PCRE_UTF8 This option causes PCRE to regard both the pattern and the subject as strings of UTF-8 characters instead of just byte strings. However, it is available only if PCRE has been built to include UTF-8 support. If not, the use of this option provokes an error. Support for UTF-8 is new, experi- mental, and incomplete. Details of exactly what it entails are given below. STUDYING A PATTERN When a pattern is going to be used several times, it is worth spending more time analyzing it in order to speed up the time taken for matching. The function pcre_study() takes a pointer to a compiled pattern as its first argument, and returns a pointer to a pcre_extra block (another void typedef) containing additional information about the pat- tern; this can be passed to pcre_exec(). If no additional information is available, NULL is returned. The second argument contains option bits. At present, no options are defined for pcre_study(), and this argument should always be zero. The third argument for pcre_study() is a pointer to an error message. If studying succeeds (even if no data is returned), the variable it points to is set to NULL. Otherwise it points to a textual error message. At present, studying a pattern is useful only for non- anchored patterns that do not have a single fixed starting character. A bitmap of possible starting characters is created. LOCALE SUPPORT PCRE handles caseless matching, and determines whether char- acters are letters, digits, or whatever, by reference to a set of tables. The library contains a default set of tables which is created in the default C locale when PCRE is com- piled. This is used when the final argument of pcre_compile() is NULL, and is sufficient for many applica- tions. An alternative set of tables can, however, be supplied. Such tables are built by calling the pcre_maketables() function, which has no arguments, in the relevant locale. The result can then be passed to pcre_compile() as often as necessary. For example, to build and use tables that are appropriate for the French locale (where accented characters with codes greater than 128 are treated as letters), the following code could be used: setlocale(LC_CTYPE, "fr"); tables = pcre_maketables(); re = pcre_compile(..., tables); The tables are built in memory that is obtained via pcre_malloc. The pointer that is passed to pcre_compile is saved with the compiled pattern, and the same tables are used via this pointer by pcre_study() and pcre_exec(). Thus for any single pattern, compilation, studying and matching all happen in the same locale, but different patterns can be compiled in different locales. It is the caller's responsi- bility to ensure that the memory containing the tables remains available for as long as it is needed. INFORMATION ABOUT A PATTERN The pcre_fullinfo() function returns information about a compiled pattern. It replaces the obsolete pcre_info() func- tion, which is nevertheless retained for backwards compabil- ity (and is documented below). The first argument for pcre_fullinfo() is a pointer to the compiled pattern. The second argument is the result of pcre_study(), or NULL if the pattern was not studied. The third argument specifies which piece of information is required, while the fourth argument is a pointer to a vari- able to receive the data. The yield of the function is zero for success, or one of the following negative numbers: PCRE_ERROR_NULL the argument code was NULL the argument where was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found PCRE_ERROR_BADOPTION the value of what was invalid The possible values for the third argument are defined in pcre.h, and are as follows: PCRE_INFO_OPTIONS Return a copy of the options with which the pattern was com- piled. The fourth argument should point to au unsigned long int variable. These option bits are those specified in the call to pcre_compile(), modified by any top-level option settings within the pattern itself, and with the PCRE_ANCHORED bit forcibly set if the form of the pattern implies that it can match only at the start of a subject string. PCRE_INFO_SIZE Return the size of the compiled pattern, that is, the value that was passed as the argument to pcre_malloc() when PCRE was getting memory in which to place the compiled data. The fourth argument should point to a size_t variable. PCRE_INFO_CAPTURECOUNT Return the number of capturing subpatterns in the pattern. The fourth argument should point to an int variable. PCRE_INFO_BACKREFMAX Return the number of the highest back reference in the pattern. The fourth argument should point to an int vari- able. Zero is returned if there are no back references. PCRE_INFO_FIRSTCHAR Return information about the first character of any matched string, for a non-anchored pattern. If there is a fixed first character, e.g. from a pattern such as (cat|cow|coyote), it is returned in the integer pointed to by where. Otherwise, if either (a) the pattern was compiled with the PCRE_MULTILINE option, and every branch starts with "^", or (b) every branch of the pattern starts with ".*" and PCRE_DOTALL is not set (if it were set, the pattern would be anchored), -1 is returned, indicating that the pattern matches only at the start of a subject string or after any "\n" within the string. Otherwise -2 is returned. For anchored patterns, -2 is returned. PCRE_INFO_FIRSTTABLE If the pattern was studied, and this resulted in the con- struction of a 256-bit table indicating a fixed set of char- acters for the first character in any matching string, a pointer to the table is returned. Otherwise NULL is returned. The fourth argument should point to an unsigned char * variable. PCRE_INFO_LASTLITERAL For a non-anchored pattern, return the value of the right- most literal character which must exist in any matched string, other than at its start. The fourth argument should point to an int variable. If there is no such character, or if the pattern is anchored, -1 is returned. For example, for the pattern /a\d+z\d+/ the returned value is 'z'. The pcre_info() function is now obsolete because its inter- face is too restrictive to return all the available data about a compiled pattern. New programs should use pcre_fullinfo() instead. The yield of pcre_info() is the number of capturing subpatterns, or one of the following negative numbers: PCRE_ERROR_NULL the argument code was NULL PCRE_ERROR_BADMAGIC the "magic number" was not found If the optptr argument is not NULL, a copy of the options with which the pattern was compiled is placed in the integer it points to (see PCRE_INFO_OPTIONS above). If the pattern is not anchored and the firstcharptr argument is not NULL, it is used to pass back information about the first character of any matched string (see PCRE_INFO_FIRSTCHAR above). MATCHING A PATTERN The function pcre_exec() is called to match a subject string against a pre-compiled pattern, which is passed in the code argument. If the pattern has been studied, the result of the study should be passed in the extra argument. Otherwise this must be NULL. The PCRE_ANCHORED option can be passed in the options argu- ment, whose unused bits must be zero. However, if a pattern was compiled with PCRE_ANCHORED, or turned out to be anchored by virtue of its contents, it cannot be made unachored at matching time. There are also three further options that can be set only at matching time: PCRE_NOTBOL The first character of the string is not the beginning of a line, so the circumflex metacharacter should not match before it. Setting this without PCRE_MULTILINE (at compile time) causes circumflex never to match. PCRE_NOTEOL The end of the string is not the end of a line, so the dol- lar metacharacter should not match it nor (except in multi- line mode) a newline immediately before it. Setting this without PCRE_MULTILINE (at compile time) causes dollar never to match. PCRE_NOTEMPTY An empty string is not considered to be a valid match if this option is set. If there are alternatives in the pat- tern, they are tried. If all the alternatives match the empty string, the entire match fails. For example, if the pattern a?b? is applied to a string not beginning with "a" or "b", it matches the empty string at the start of the subject. With PCRE_NOTEMPTY set, this match is not valid, so PCRE searches further into the string for occurrences of "a" or "b". Perl has no direct equivalent of PCRE_NOTEMPTY, but it does make a special case of a pattern match of the empty string within its split() function, and when using the /g modifier. It is possible to emulate Perl's behaviour after matching a null string by first trying the match again at the same offset with PCRE_NOTEMPTY set, and then if that fails by advancing the starting offset (see below) and trying an ordinary match again. The subject string is passed as a pointer in subject, a length in length, and a starting offset in startoffset. Unlike the pattern string, it may contain binary zero char- acters. When the starting offset is zero, the search for a match starts at the beginning of the subject, and this is by far the most common case. A non-zero starting offset is useful when searching for another match in the same subject by calling pcre_exec() again after a previous success. Setting startoffset differs from just passing over a shortened string and setting PCRE_NOTBOL in the case of a pattern that begins with any kind of lookbehind. For example, consider the pattern \Biss\B which finds occurrences of "iss" in the middle of words. (\B matches only if the current position in the subject is not a word boundary.) When applied to the string "Mississipi" the first call to pcre_exec() finds the first occurrence. If pcre_exec() is called again with just the remainder of the subject, namely "issipi", it does not match, because \B is always false at the start of the subject, which is deemed to be a word boundary. However, if pcre_exec() is passed the entire string again, but with startoffset set to 4, it finds the second occurrence of "iss" because it is able to look behind the starting point to discover that it is preceded by a letter. If a non-zero starting offset is passed when the pattern is anchored, one attempt to match at the given offset is tried. This can only succeed if the pattern does not require the match to be at the start of the subject. In general, a pattern matches a certain portion of the sub- ject, and in addition, further substrings from the subject may be picked out by parts of the pattern. Following the usage in Jeffrey Friedl's book, this is called "capturing" in what follows, and the phrase "capturing subpattern" is used for a fragment of a pattern that picks out a substring. PCRE supports several other kinds of parenthesized subpat- tern that do not cause substrings to be captured. Captured substrings are returned to the caller via a vector of integer offsets whose address is passed in ovector. The number of elements in the vector is passed in ovecsize. The first two-thirds of the vector is used to pass back captured substrings, each substring using a pair of integers. The remaining third of the vector is used as workspace by pcre_exec() while matching capturing subpatterns, and is not available for passing back information. The length passed in ovecsize should always be a multiple of three. If it is not, it is rounded down. When a match has been successful, information about captured substrings is returned in pairs of integers, starting at the beginning of ovector, and continuing up to two-thirds of its length at the most. The first element of a pair is set to the offset of the first character in a substring, and the second is set to the offset of the first character after the end of a substring. The first pair, ovector[0] and ovec- tor[1], identify the portion of the subject string matched by the entire pattern. The next pair is used for the first capturing subpattern, and so on. The value returned by pcre_exec() is the number of pairs that have been set. If there are no capturing subpatterns, the return value from a successful match is 1, indicating that just the first pair of offsets has been set. Some convenience functions are provided for extracting the captured substrings as separate strings. These are described in the following section. It is possible for an capturing subpattern number n+1 to match some part of the subject when subpattern n has not been used at all. For example, if the string "abc" is matched against the pattern (a|(z))(bc) subpatterns 1 and 3 are matched, but 2 is not. When this happens, both offset values corresponding to the unused subpattern are set to -1. If a capturing subpattern is matched repeatedly, it is the last portion of the string that it matched that gets returned. If the vector is too small to hold all the captured sub- strings, it is used as far as possible (up to two-thirds of its length), and the function returns a value of zero. In particular, if the substring offsets are not of interest, pcre_exec() may be called with ovector passed as NULL and ovecsize as zero. However, if the pattern contains back references and the ovector isn't big enough to remember the related substrings, PCRE has to get additional memory for use during matching. Thus it is usually advisable to supply an ovector. Note that pcre_info() can be used to find out how many cap- turing subpatterns there are in a compiled pattern. The smallest size for ovector that will allow for n captured substrings in addition to the offsets of the substring matched by the whole pattern is (n+1)*3. If pcre_exec() fails, it returns a negative number. The fol- lowing are defined in the header file: PCRE_ERROR_NOMATCH (-1) The subject string did not match the pattern. PCRE_ERROR_NULL (-2) Either code or subject was passed as NULL, or ovector was NULL and ovecsize was not zero. PCRE_ERROR_BADOPTION (-3) An unrecognized bit was set in the options argument. PCRE_ERROR_BADMAGIC (-4) PCRE stores a 4-byte "magic number" at the start of the com- piled code, to catch the case when it is passed a junk pointer. This is the error it gives when the magic number isn't present. PCRE_ERROR_UNKNOWN_NODE (-5) While running the pattern match, an unknown item was encoun- tered in the compiled pattern. This error could be caused by a bug in PCRE or by overwriting of the compiled pattern. PCRE_ERROR_NOMEMORY (-6) If a pattern contains back references, but the ovector that is passed to pcre_exec() is not big enough to remember the referenced substrings, PCRE gets a block of memory at the start of matching to use for this purpose. If the call via pcre_malloc() fails, this error is given. The memory is freed at the end of matching. EXTRACTING CAPTURED SUBSTRINGS Captured substrings can be accessed directly by using the SunOS 5.8 Last change: 12 offsets returned by pcre_exec() in ovector. For convenience, the functions pcre_copy_substring(), pcre_get_substring(), and pcre_get_substring_list() are provided for extracting captured substrings as new, separate, zero-terminated strings. A substring that contains a binary zero is correctly extracted and has a further zero added on the end, but the result does not, of course, function as a C string. The first three arguments are the same for all three func- tions: subject is the subject string which has just been successfully matched, ovector is a pointer to the vector of integer offsets that was passed to pcre_exec(), and stringcount is the number of substrings that were captured by the match, including the substring that matched the entire regular expression. This is the value returned by pcre_exec if it is greater than zero. If pcre_exec() returned zero, indicating that it ran out of space in ovec- tor, the value passed as stringcount should be the size of the vector divided by three. The functions pcre_copy_substring() and pcre_get_substring() extract a single substring, whose number is given as string- number. A value of zero extracts the substring that matched the entire pattern, while higher values extract the captured substrings. For pcre_copy_substring(), the string is placed in buffer, whose length is given by buffersize, while for pcre_get_substring() a new block of memory is obtained via pcre_malloc, and its address is returned via stringptr. The yield of the function is the length of the string, not including the terminating zero, or one of PCRE_ERROR_NOMEMORY (-6) The buffer was too small for pcre_copy_substring(), or the attempt to get memory failed for pcre_get_substring(). PCRE_ERROR_NOSUBSTRING (-7) There is no substring whose number is stringnumber. The pcre_get_substring_list() function extracts all avail- able substrings and builds a list of pointers to them. All this is done in a single block of memory which is obtained via pcre_malloc. The address of the memory block is returned via listptr, which is also the start of the list of string pointers. The end of the list is marked by a NULL pointer. The yield of the function is zero if all went well, or PCRE_ERROR_NOMEMORY (-6) if the attempt to get the memory block failed. When any of these functions encounter a substring that is unset, which can happen when capturing subpattern number n+1 matches some part of the subject, but subpattern n has not been used at all, they return an empty string. This can be distinguished from a genuine zero-length substring by inspecting the appropriate offset in ovector, which is nega- tive for unset substrings. The two convenience functions pcre_free_substring() and pcre_free_substring_list() can be used to free the memory returned by a previous call of pcre_get_substring() or pcre_get_substring_list(), respectively. They do nothing more than call the function pointed to by pcre_free, which of course could be called directly from a C program. How- ever, PCRE is used in some situations where it is linked via a special interface to another programming language which cannot use pcre_free directly; it is for these cases that the functions are provided. LIMITATIONS There are some size limitations in PCRE but it is hoped that they will never in practice be relevant. The maximum length of a compiled pattern is 65539 (sic) bytes. All values in repeating quantifiers must be less than 65536. The maximum number of capturing subpatterns is 99. The maximum number of all parenthesized subpatterns, including capturing sub- patterns, assertions, and other types of subpattern, is 200. The maximum length of a subject string is the largest posi- tive number that an integer variable can hold. However, PCRE uses recursion to handle subpatterns and indefinite repeti- tion. This means that the available stack space may limit the size of a subject string that can be processed by cer- tain patterns. DIFFERENCES FROM PERL The differences described here are with respect to Perl 5.005. 1. By default, a whitespace character is any character that the C library function isspace() recognizes, though it is possible to compile PCRE with alternative character type tables. Normally isspace() matches space, formfeed, newline, carriage return, horizontal tab, and vertical tab. Perl 5 no longer includes vertical tab in its set of whitespace char- acters. The \v escape that was in the Perl documentation for a long time was never in fact recognized. However, the char- acter itself was treated as whitespace at least up to 5.002. In 5.004 and 5.005 it does not match \s. 2. PCRE does not allow repeat quantifiers on lookahead assertions. Perl permits them, but they do not mean what you might think. For example, (?!a){3} does not assert that the next three characters are not "a". It just asserts that the next character is not "a" three times. 3. Capturing subpatterns that occur inside negative looka- head assertions are counted, but their entries in the offsets vector are never set. Perl sets its numerical vari- ables from any such patterns that are matched before the assertion fails to match something (thereby succeeding), but only if the negative lookahead assertion contains just one branch. 4. Though binary zero characters are supported in the sub- ject string, they are not allowed in a pattern string because it is passed as a normal C string, terminated by zero. The escape sequence "\0" can be used in the pattern to represent a binary zero. 5. The following Perl escape sequences are not supported: \l, \u, \L, \U, \E, \Q. In fact these are implemented by Perl's general string-handling and are not part of its pat- tern matching engine. 6. The Perl \G assertion is not supported as it is not relevant to single pattern matches. 7. Fairly obviously, PCRE does not support the (?{code}) and (?p{code}) constructions. However, there is some experimen- tal support for recursive patterns using the non-Perl item (?R). 8. There are at the time of writing some oddities in Perl 5.005_02 concerned with the settings of captured strings when part of a pattern is repeated. For example, matching "aba" against the pattern /^(a(b)?)+$/ sets $2 to the value "b", but matching "aabbaa" against /^(aa(bb)?)+$/ leaves $2 unset. However, if the pattern is changed to /^(aa(b(b))?)+$/ then $2 (and $3) are set. In Perl 5.004 $2 is set in both cases, and that is also true of PCRE. If in the future Perl changes to a consistent state that is different, PCRE may change to follow. 9. Another as yet unresolved discrepancy is that in Perl 5.005_02 the pattern /^(a)?(?(1)a|b)+$/ matches the string "a", whereas in PCRE it does not. However, in both Perl and PCRE /^(a)?a/ matched against "a" leaves $1 unset. 10. PCRE provides some extensions to the Perl regular expression facilities: (a) Although lookbehind assertions must match fixed length strings, each alternative branch of a lookbehind assertion can match a different length of string. Perl 5.005 requires them all to have the same length. (b) If PCRE_DOLLAR_ENDONLY is set and PCRE_MULTILINE is not set, the $ meta- character matches only at the very end of the string. (c) If PCRE_EXTRA is set, a backslash followed by a letter with no special meaning is faulted. (d) If PCRE_UNGREEDY is set, the greediness of the repeti- tion quantifiers is inverted, that is, by default they are not greedy, but if followed by a question mark they are. (e) PCRE_ANCHORED can be used to force a pattern to be tried only at the start of the subject. (f) The PCRE_NOTBOL, PCRE_NOTEOL, and PCRE_NOTEMPTY options for pcre_exec() have no Perl equivalents. (g) The (?R) construct allows for recursive pattern matching (Perl 5.6 can do this using the (?p{code}) construct, which PCRE cannot of course support.) REGULAR EXPRESSION DETAILS The syntax and semantics of the regular expressions sup- ported by PCRE are described below. Regular expressions are also described in the Perl documentation and in a number of other books, some of which have copious examples. Jeffrey Friedl's "Mastering Regular Expressions", published by O'Reilly (ISBN 1-56592-257), covers them in great detail. The description here is intended as reference documentation. The basic operation of PCRE is on strings of bytes. However, there is the beginnings of some support for UTF-8 character strings. To use this support you must configure PCRE to include it, and then call pcre_compile() with the PCRE_UTF8 option. How this affects the pattern matching is described in the final section of this document. A regular expression is a pattern that is matched against a subject string from left to right. Most characters stand for themselves in a pattern, and match the corresponding charac- ters in the subject. As a trivial example, the pattern The quick brown fox matches a portion of a subject string that is identical to itself. The power of regular expressions comes from the ability to include alternatives and repetitions in the pat- tern. These are encoded in the pattern by the use of meta- characters, which do not stand for themselves but instead are interpreted in some special way. There are two different sets of meta-characters: those that are recognized anywhere in the pattern except within square brackets, and those that are recognized in square brackets. Outside square brackets, the meta-characters are as follows: \ general escape character with several uses ^ assert start of subject (or line, in multiline mode) $ assert end of subject (or line, in multiline mode) . match any character except newline (by default) [ start character class definition | start of alternative branch ( start subpattern ) end subpattern ? extends the meaning of ( also 0 or 1 quantifier also quantifier minimizer * 0 or more quantifier + 1 or more quantifier { start min/max quantifier Part of a pattern that is in square brackets is called a "character class". In a character class the only meta- characters are: \ general escape character ^ negate the class, but only if the first character - indicates character range ] terminates the character class The following sections describe the use of each of the meta-characters. BACKSLASH The backslash character has several uses. Firstly, if it is followed by a non-alphameric character, it takes away any special meaning that character may have. This use of backslash as an escape character applies both inside and outside character classes. For example, if you want to match a "*" character, you write "\*" in the pattern. This applies whether or not the follow- ing character would otherwise be interpreted as a meta- character, so it is always safe to precede a non-alphameric with "\" to specify that it stands for itself. In particu- lar, if you want to match a backslash, you write "\\". If a pattern is compiled with the PCRE_EXTENDED option, whi- tespace in the pattern (other than in a character class) and characters between a "#" outside a character class and the next newline character are ignored. An escaping backslash can be used to include a whitespace or "#" character as part of the pattern. A second use of backslash provides a way of encoding non- printing characters in patterns in a visible manner. There is no restriction on the appearance of non-printing charac- ters, apart from the binary zero that terminates a pattern, but when a pattern is being prepared by text editing, it is usually easier to use one of the following escape sequences than the binary character it represents: \a alarm, that is, the BEL character (hex 07) \cx "control-x", where x is any character \e escape (hex 1B) \f formfeed (hex 0C) \n newline (hex 0A) \r carriage return (hex 0D) \t tab (hex 09) \xhh character with hex code hh \ddd character with octal code ddd, or backreference The precise effect of "\cx" is as follows: if "x" is a lower case letter, it is converted to upper case. Then bit 6 of the character (hex 40) is inverted. Thus "\cz" becomes hex 1A, but "\c{" becomes hex 3B, while "\c;" becomes hex 7B. After "\x", up to two hexadecimal digits are read (letters can be in upper or lower case). After "\0" up to two further octal digits are read. In both cases, if there are fewer than two digits, just those that are present are used. Thus the sequence "\0\x\07" specifies two binary zeros followed by a BEL character. Make sure you supply two digits after the initial zero if the character that follows is itself an octal digit. The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a back reference. A description of how this works is given later, following the discussion of parenthesized subpatterns. Inside a character class, or if the decimal number is greater than 9 and there have not been that many capturing subpatterns, PCRE re-reads up to three octal digits follow- ing the backslash, and generates a single byte from the least significant 8 bits of the value. Any subsequent digits stand for themselves. For example: \040 is another way of writing a space \40 is the same, provided there are fewer than 40 previous capturing subpatterns \7 is always a back reference \11 might be a back reference, or another way of writing a tab \011 is always a tab \0113 is a tab followed by the character "3" \113 is the character with octal code 113 (since there can be no more than 99 back references) \377 is a byte consisting entirely of 1 bits \81 is either a back reference, or a binary zero followed by the two characters "8" and "1" Note that octal values of 100 or greater must not be intro- duced by a leading zero, because no more than three octal digits are ever read. All the sequences that define a single byte value can be used both inside and outside character classes. In addition, inside a character class, the sequence "\b" is interpreted as the backspace character (hex 08). Outside a character class it has a different meaning (see below). The third use of backslash is for specifying generic charac- ter types: \d any decimal digit \D any character that is not a decimal digit \s any whitespace character \S any character that is not a whitespace character \w any "word" character \W any "non-word" character Each pair of escape sequences partitions the complete set of characters into two disjoint sets. Any given character matches one, and only one, of each pair. A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is con- trolled by PCRE's character tables, and may vary if locale- specific matching is taking place (see "Locale support" above). For example, in the "fr" (French) locale, some char- acter codes greater than 128 are used for accented letters, and these are matched by \w. These character type sequences can appear both inside and outside character classes. They each match one character of the appropriate type. If the current matching point is at the end of the subject string, all of them fail, since there is no character to match. The fourth use of backslash is for certain simple asser- tions. An assertion specifies a condition that has to be met at a particular point in a match, without consuming any characters from the subject string. The use of subpatterns for more complicated assertions is described below. The backslashed assertions are \b word boundary \B not a word boundary \A start of subject (independent of multiline mode) \Z end of subject or newline at end (independent of multiline mode) \z end of subject (independent of multiline mode) These assertions may not appear in character classes (but note that "\b" has a different meaning, namely the backspace character, inside a character class). A word boundary is a position in the subject string where the current character and the previous character do not both match \w or \W (i.e. one matches \w and the other matches \W), or the start or end of the string if the first or last character matches \w, respectively. The \A, \Z, and \z assertions differ from the traditional circumflex and dollar (described below) in that they only ever match at the very start and end of the subject string, whatever options are set. They are not affected by the PCRE_NOTBOL or PCRE_NOTEOL options. If the startoffset argu- ment of pcre_exec() is non-zero, \A can never match. The difference between \Z and \z is that \Z matches before a newline that is the last character of the string as well as at the end of the string, whereas \z matches only at the end. CIRCUMFLEX AND DOLLAR Outside a character class, in the default matching mode, the circumflex character is an assertion which is true only if the current matching point is at the start of the subject string. If the startoffset argument of pcre_exec() is non- zero, circumflex can never match. Inside a character class, circumflex has an entirely different meaning (see below). Circumflex need not be the first character of the pattern if a number of alternatives are involved, but it should be the first thing in each alternative in which it appears if the pattern is ever to match that branch. If all possible alter- natives start with a circumflex, that is, if the pattern is constrained to match only at the start of the subject, it is said to be an "anchored" pattern. (There are also other con- structs that can cause a pattern to be anchored.) A dollar character is an assertion which is true only if the current matching point is at the end of the subject string, or immediately before a newline character that is the last character in the string (by default). Dollar need not be the last character of the pattern if a number of alternatives are involved, but it should be the last item in any branch in which it appears. Dollar has no special meaning in a character class. The meaning of dollar can be changed so that it matches only at the very end of the string, by setting the PCRE_DOLLAR_ENDONLY option at compile or matching time. This does not affect the \Z assertion. The meanings of the circumflex and dollar characters are changed if the PCRE_MULTILINE option is set. When this is the case, they match immediately after and immediately before an internal "\n" character, respectively, in addition to matching at the start and end of the subject string. For example, the pattern /^abc$/ matches the subject string "def\nabc" in multiline mode, but not otherwise. Conse- quently, patterns that are anchored in single line mode because all branches start with "^" are not anchored in mul- tiline mode, and a match for circumflex is possible when the startoffset argument of pcre_exec() is non-zero. The PCRE_DOLLAR_ENDONLY option is ignored if PCRE_MULTILINE is set. Note that the sequences \A, \Z, and \z can be used to match the start and end of the subject in both modes, and if all branches of a pattern start with \A is it always anchored, whether PCRE_MULTILINE is set or not. FULL STOP (PERIOD, DOT) Outside a character class, a dot in the pattern matches any one character in the subject, including a non-printing char- acter, but not (by default) newline. If the PCRE_DOTALL option is set, dots match newlines as well. The handling of dot is entirely independent of the handling of circumflex and dollar, the only relationship being that they both involve newline characters. Dot has no special meaning in a character class. SQUARE BRACKETS An opening square bracket introduces a character class, ter- minated by a closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, it should be the first data character in the class (after an initial cir- cumflex, if present) or escaped with a backslash. A character class matches a single character in the subject; the character must be in the set of characters defined by the class, unless the first character in the class is a cir- cumflex, in which case the subject character must not be in the set defined by the class. If a circumflex is actually required as a member of the class, ensure it is not the first character, or escape it with a backslash. For example, the character class [aeiou] matches any lower case vowel, while [^aeiou] matches any character that is not a lower case vowel. Note that a circumflex is just a con- venient notation for specifying the characters which are in the class by enumerating those that are not. It is not an assertion: it still consumes a character from the subject string, and fails if the current pointer is at the end of the string. When caseless matching is set, any letters in a class represent both their upper case and lower case versions, so for example, a caseless [aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a case- ful version would. The newline character is never treated in any special way in character classes, whatever the setting of the PCRE_DOTALL or PCRE_MULTILINE options is. A class such as [^a] will always match a newline. The minus (hyphen) character can be used to specify a range of characters in a character class. For example, [d-m] matches any letter between d and m, inclusive. If a minus character is required in a class, it must be escaped with a backslash or appear in a position where it cannot be inter- preted as indicating a range, typically as the first or last character in the class. It is not possible to have the literal character "]" as the end character of a range. A pattern such as [W-]46] is interpreted as a class of two characters ("W" and "-") fol- lowed by a literal string "46]", so it would match "W46]" or "-46]". However, if the "]" is escaped with a backslash it is interpreted as the end of range, so [W-\]46] is inter- preted as a single class containing a range followed by two separate characters. The octal or hexadecimal representation of "]" can also be used to end a range. Ranges operate in ASCII collating sequence. They can also be used for characters specified numerically, for example [\000-\037]. If a range that includes letters is used when caseless matching is set, it matches the letters in either case. For example, [W-c] is equivalent to [][\^_`wxyzabc], matched caselessly, and if character tables for the "fr" locale are in use, [\xc8-\xcb] matches accented E characters in both cases. The character types \d, \D, \s, \S, \w, and \W may also appear in a character class, and add the characters that they match to the class. For example, [\dABCDEF] matches any hexadecimal digit. A circumflex can conveniently be used with the upper case character types to specify a more res- tricted set of characters than the matching lower case type. For example, the class [^\W_] matches any letter or digit, but not underscore. All non-alphameric characters other than \, -, ^ (at the start) and the terminating ] are non-special in character classes, but it does no harm if they are escaped. POSIX CHARACTER CLASSES Perl 5.6 (not yet released at the time of writing) is going to support the POSIX notation for character classes, which uses names enclosed by [: and :] within the enclosing square brackets. PCRE supports this notation. For example, [01[:alpha:]%] matches "0", "1", any alphabetic character, or "%". The sup- ported class names are alnum letters and digits alpha letters ascii character codes 0 - 127 cntrl control characters digit decimal digits (same as \d) graph printing characters, excluding space lower lower case letters print printing characters, including space punct printing characters, excluding letters and digits space white space (same as \s) upper upper case letters word "word" characters (same as \w) xdigit hexadecimal digits The names "ascii" and "word" are Perl extensions. Another Perl extension is negation, which is indicated by a ^ char- acter after the colon. For example, [12[:^digit:]] matches "1", "2", or any non-digit. PCRE (and Perl) also recogize the POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not supported, and an error is given if they are encountered. VERTICAL BAR Vertical bar characters are used to separate alternative patterns. For example, the pattern gilbert|sullivan matches either "gilbert" or "sullivan". Any number of alter- natives may appear, and an empty alternative is permitted (matching the empty string). The matching process tries each alternative in turn, from left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern. INTERNAL OPTION SETTING The settings of PCRE_CASELESS, PCRE_MULTILINE, PCRE_DOTALL, and PCRE_EXTENDED can be changed from within the pattern by a sequence of Perl option letters enclosed between "(?" and ")". The option letters are i for PCRE_CASELESS m for PCRE_MULTILINE s for PCRE_DOTALL x for PCRE_EXTENDED For example, (?im) sets caseless, multiline matching. It is also possible to unset these options by preceding the letter with a hyphen, and a combined setting and unsetting such as (?im-sx), which sets PCRE_CASELESS and PCRE_MULTILINE while unsetting PCRE_DOTALL and PCRE_EXTENDED, is also permitted. If a letter appears both before and after the hyphen, the option is unset. The scope of these option changes depends on where in the pattern the setting occurs. For settings that are outside any subpattern (defined below), the effect is the same as if the options were set or unset at the start of matching. The following patterns all behave in exactly the same way: (?i)abc a(?i)bc ab(?i)c abc(?i) which in turn is the same as compiling the pattern abc with PCRE_CASELESS set. In other words, such "top level" set- tings apply to the whole pattern (unless there are other changes inside subpatterns). If there is more than one set- ting of the same option at top level, the rightmost setting is used. If an option change occurs inside a subpattern, the effect is different. This is a change of behaviour in Perl 5.005. An option change inside a subpattern affects only that part of the subpattern that follows it, so (a(?i)b)c matches abc and aBc and no other strings (assuming PCRE_CASELESS is not used). By this means, options can be made to have different settings in different parts of the pattern. Any changes made in one alternative do carry on into subsequent branches within the same subpattern. For example, (a(?i)b|c) matches "ab", "aB", "c", and "C", even though when matching "C" the first branch is abandoned before the option setting. This is because the effects of option settings happen at compile time. There would be some very weird behaviour oth- erwise. The PCRE-specific options PCRE_UNGREEDY and PCRE_EXTRA can be changed in the same way as the Perl-compatible options by using the characters U and X respectively. The (?X) flag setting is special in that it must always occur earlier in the pattern than any of the additional features it turns on, even when it is at top level. It is best put at the start. SUBPATTERNS Subpatterns are delimited by parentheses (round brackets), which can be nested. Marking part of a pattern as a subpat- tern does two things: 1. It localizes a set of alternatives. For example, the pat- tern cat(aract|erpillar|) matches one of the words "cat", "cataract", or "caterpil- lar". Without the parentheses, it would match "cataract", "erpillar" or the empty string. 2. It sets up the subpattern as a capturing subpattern (as defined above). When the whole pattern matches, that por- tion of the subject string that matched the subpattern is passed back to the caller via the ovector argument of pcre_exec(). Opening parentheses are counted from left to right (starting from 1) to obtain the numbers of the captur- ing subpatterns. For example, if the string "the red king" is matched against the pattern the ((red|white) (king|queen)) the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3. The fact that plain parentheses fulfil two functions is not always helpful. There are often times when a grouping sub- pattern is required without a capturing requirement. If an opening parenthesis is followed by "?:", the subpattern does not do any capturing, and is not counted when computing the number of any subsequent capturing subpatterns. For example, if the string "the white queen" is matched against the pat- tern the ((?:red|white) (king|queen)) the captured substrings are "white queen" and "queen", and are numbered 1 and 2. The maximum number of captured sub- strings is 99, and the maximum number of all subpatterns, both capturing and non-capturing, is 200. As a convenient shorthand, if any option settings are required at the start of a non-capturing subpattern, the option letters may appear between the "?" and the ":". Thus the two patterns (?i:saturday|sunday) (?:(?i)saturday|sunday) match exactly the same set of strings. Because alternative branches are tried from left to right, and options are not reset until the end of the subpattern is reached, an option setting in one branch does affect subsequent branches, so the above patterns match "SUNDAY" as well as "Saturday". REPETITION Repetition is specified by quantifiers, which can follow any of the following items: a single character, possibly escaped the . metacharacter a character class a back reference (see next section) a parenthesized subpattern (unless it is an assertion - see below) The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second. For example: z{2,4} matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special character. If the second number is omitted, but the comma is present, there is no upper limit; if the second number and the comma are both omitted, the quantifier specifies an exact number of required matches. Thus [aeiou]{3,} matches at least 3 successive vowels, but may match many more, while \d{8} matches exactly 8 digits. An opening curly bracket that appears in a position where a quantifier is not allowed, or one that does not match the syntax of a quantifier, is taken as a literal character. For example, {,6} is not a quantif- ier, but a literal string of four characters. The quantifier {0} is permitted, causing the expression to behave as if the previous item and the quantifier were not present. For convenience (and historical compatibility) the three most common quantifiers have single-character abbreviations: * is equivalent to {0,} + is equivalent to {1,} ? is equivalent to {0,1} It is possible to construct infinite loops by following a subpattern that can match no characters with a quantifier that has no upper limit, for example: (a?)* Earlier versions of Perl and PCRE used to give an error at compile time for such patterns. However, because there are cases where this can be useful, such patterns are now accepted, but if any repetition of the subpattern does in fact match no characters, the loop is forcibly broken. By default, the quantifiers are "greedy", that is, they match as much as possible (up to the maximum number of per- mitted times), without causing the rest of the pattern to fail. The classic example of where this gives problems is in trying to match comments in C programs. These appear between the sequences /* and */ and within the sequence, individual * and / characters may appear. An attempt to match C com- ments by applying the pattern /\*.*\*/ to the string /* first command */ not comment /* second comment */ fails, because it matches the entire string owing to the greediness of the .* item. However, if a quantifier is followed by a question mark, it ceases to be greedy, and instead matches the minimum number of times possible, so the pattern /\*.*?\*/ does the right thing with the C comments. The meaning of the various quantifiers is not otherwise changed, just the pre- ferred number of matches. Do not confuse this use of ques- tion mark with its use as a quantifier in its own right. Because it has two uses, it can sometimes appear doubled, as in \d??\d which matches one digit by preference, but can match two if that is the only way the rest of the pattern matches. If the PCRE_UNGREEDY option is set (an option which is not available in Perl), the quantifiers are not greedy by default, but individual ones can be made greedy by following them with a question mark. In other words, it inverts the default behaviour. When a parenthesized subpattern is quantified with a minimum repeat count that is greater than 1 or with a limited max- imum, more store is required for the compiled pattern, in proportion to the size of the minimum or maximum. If a pattern starts with .* or .{0,} and the PCRE_DOTALL option (equivalent to Perl's /s) is set, thus allowing the . to match newlines, the pattern is implicitly anchored, because whatever follows will be tried against every charac- ter position in the subject string, so there is no point in retrying the overall match at any position after the first. PCRE treats such a pattern as though it were preceded by \A. In cases where it is known that the subject string contains no newlines, it is worth setting PCRE_DOTALL when the pat- tern begins with .* in order to obtain this optimization, or alternatively using ^ to indicate anchoring explicitly. When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration. For exam- ple, after (tweedle[dume]{3}\s*)+ has matched "tweedledum tweedledee" the value of the cap- tured substring is "tweedledee". However, if there are nested capturing subpatterns, the corresponding captured values may have been set in previous iterations. For exam- ple, after /(a|(b))+/ matches "aba" the value of the second captured substring is "b". BACK REFERENCES Outside a character class, a backslash followed by a digit greater than 0 (and possibly further digits) is a back reference to a capturing subpattern earlier (i.e. to its left) in the pattern, provided there have been that many previous capturing left parentheses. However, if the decimal number following the backslash is less than 10, it is always taken as a back reference, and causes an error only if there are not that many capturing left parentheses in the entire pattern. In other words, the parentheses that are referenced need not be to the left of the reference for numbers less than 10. See the section entitled "Backslash" above for further details of the han- dling of digits following a backslash. A back reference matches whatever actually matched the cap- turing subpattern in the current subject string, rather than anything matching the subpattern itself. So the pattern (sens|respons)e and \1ibility matches "sense and sensibility" and "response and responsi- bility", but not "sense and responsibility". If caseful matching is in force at the time of the back reference, the case of letters is relevant. For example, ((?i)rah)\s+\1 matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original capturing subpattern is matched case- lessly. There may be more than one back reference to the same sub- pattern. If a subpattern has not actually been used in a particular match, any back references to it always fail. For example, the pattern (a|(bc))\2 always fails if it starts to match "a" rather than "bc". Because there may be up to 99 back references, all digits following the backslash are taken as part of a potential back reference number. If the pattern continues with a digit character, some delimiter must be used to terminate the back reference. If the PCRE_EXTENDED option is set, this can be whitespace. Otherwise an empty comment can be used. A back reference that occurs inside the parentheses to which it refers fails when the subpattern is first used, so, for example, (a\1) never matches. However, such references can be useful inside repeated subpatterns. For example, the pat- tern (a|b\1)+ matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of the subpattern, the back reference matches the character string corresponding to the previous iteration. In order for this to work, the pattern must be such that the first iteration does not need to match the back reference. This can be done using alternation, as in the example above, or by a quantifier with a minimum of zero. ASSERTIONS An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters. The simple assertions coded as \b, \B, \A, \Z, \z, ^ and $ are described above. More compli- cated assertions are coded as subpatterns. There are two kinds: those that look ahead of the current position in the subject string, and those that look behind it. An assertion subpattern is matched in the normal way, except that it does not cause the current matching position to be changed. Lookahead assertions start with (?= for positive assertions and (?! for negative assertions. For example, \w+(?=;) matches a word followed by a semicolon, but does not include the semicolon in the match, and foo(?!bar) matches any occurrence of "foo" that is not followed by "bar". Note that the apparently similar pattern (?!foo)bar does not find an occurrence of "bar" that is preceded by something other than "foo"; it finds any occurrence of "bar" whatsoever, because the assertion (?!foo) is always true when the next three characters are "bar". A lookbehind assertion is needed to achieve this effect. Lookbehind assertions start with (?<= for positive asser- tions and (? as in this example: (?>\d+)bar This kind of parenthesis "locks up" the part of the pattern it contains once it has matched, and a failure further into the pattern is prevented from backtracking into it. Backtracking past it to previous items, however, works as normal. An alternative description is that a subpattern of this type matches the string of characters that an identical stan- dalone pattern would match, if anchored at the current point in the subject string. Once-only subpatterns are not capturing subpatterns. Simple cases such as the above example can be thought of as a max- imizing repeat that must swallow everything it can. So, while both \d+ and \d+? are prepared to adjust the number of digits they match in order to make the rest of the pattern match, (?>\d+) can only match an entire sequence of digits. This construction can of course contain arbitrarily compli- cated subpatterns, and it can be nested. Once-only subpatterns can be used in conjunction with look- behind assertions to specify efficient matching at the end of the subject string. Consider a simple pattern such as abcd$ when applied to a long string which does not match. Because matching proceeds from left to right, PCRE will look for each "a" in the subject and then see if what follows matches the rest of the pattern. If the pattern is specified as ^.*abcd$ the initial .* matches the entire string at first, but when this fails (because there is no following "a"), it back- tracks to match all but the last character, then all but the last two characters, and so on. Once again the search for "a" covers the entire string, from right to left, so we are no better off. However, if the pattern is written as ^(?>.*)(?<=abcd) there can be no backtracking for the .* item; it can match only the entire string. The subsequent lookbehind assertion does a single test on the last four characters. If it fails, the match fails immediately. For long strings, this approach makes a significant difference to the processing time. When a pattern contains an unlimited repeat inside a subpat- tern that can itself be repeated an unlimited number of times, the use of a once-only subpattern is the only way to avoid some failing matches taking a very long time indeed. The pattern (\D+|<\d+>)*[!?] matches an unlimited number of substrings that either con- sist of non-digits, or digits enclosed in <>, followed by either ! or ?. When it matches, it runs quickly. However, if it is applied to aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa it takes a long time before reporting failure. This is because the string can be divided between the two repeats in a large number of ways, and all have to be tried. (The exam- ple used [!?] rather than a single character at the end, because both PCRE and Perl have an optimization that allows for fast failure when a single character is used. They remember the last single character that is required for a match, and fail early if it is not present in the string.) If the pattern is changed to ((?>\D+)|<\d+>)*[!?] sequences of non-digits cannot be broken, and failure hap- pens quickly. CONDITIONAL SUBPATTERNS It is possible to cause the matching process to obey a sub- pattern conditionally or to choose between two alternative subpatterns, depending on the result of an assertion, or whether a previous capturing subpattern matched or not. The two possible forms of conditional subpattern are (?(condition)yes-pattern) (?(condition)yes-pattern|no-pattern) If the condition is satisfied, the yes-pattern is used; oth- erwise the no-pattern (if present) is used. If there are more than two alternatives in the subpattern, a compile-time error occurs. There are two kinds of condition. If the text between the parentheses consists of a sequence of digits, the condition is satisfied if the capturing subpattern of that number has previously matched. The number must be greater than zero. Consider the following pattern, which contains non- significant white space to make it more readable (assume the PCRE_EXTENDED option) and to divide it into three parts for ease of discussion: ( \( )? [^()]+ (?(1) \) ) The first part matches an optional opening parenthesis, and if that character is present, sets it as the first captured substring. The second part matches one or more characters that are not parentheses. The third part is a conditional subpattern that tests whether the first set of parentheses matched or not. If they did, that is, if subject started with an opening parenthesis, the condition is true, and so the yes-pattern is executed and a closing parenthesis is required. Otherwise, since no-pattern is not present, the subpattern matches nothing. In other words, this pattern matches a sequence of non-parentheses, optionally enclosed in parentheses. If the condition is not a sequence of digits, it must be an assertion. This may be a positive or negative lookahead or lookbehind assertion. Consider this pattern, again contain- ing non-significant white space, and with the two alterna- tives on the second line: (?(?=[^a-z]*[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) The condition is a positive lookahead assertion that matches an optional sequence of non-letters followed by a letter. In other words, it tests for the presence of at least one letter in the subject. If a letter is found, the subject is matched against the first alternative; otherwise it is matched against the second. This pattern matches strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits. COMMENTS The sequence (?# marks the start of a comment which contin- ues up to the next closing parenthesis. Nested parentheses are not permitted. The characters that make up a comment play no part in the pattern matching at all. If the PCRE_EXTENDED option is set, an unescaped # character outside a character class introduces a comment that contin- ues up to the next newline character in the pattern. RECURSIVE PATTERNS Consider the problem of matching a string in parentheses, allowing for unlimited nested parentheses. Without the use of recursion, the best that can be done is to use a pattern that matches up to some fixed depth of nesting. It is not possible to handle an arbitrary nesting depth. Perl 5.6 has provided an experimental facility that allows regular expressions to recurse (amongst other things). It does this by interpolating Perl code in the expression at run time, and the code can refer to the expression itself. A Perl pat- tern to solve the parentheses problem can be created like this: $re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x; The (?p{...}) item interpolates Perl code at run time, and in this case refers recursively to the pattern in which it appears. Obviously, PCRE cannot support the interpolation of Perl code. Instead, the special item (?R) is provided for the specific case of recursion. This PCRE pattern solves the parentheses problem (assume the PCRE_EXTENDED option is set so that white space is ignored): \( ( (?>[^()]+) | (?R) )* \) First it matches an opening parenthesis. Then it matches any number of substrings which can either be a sequence of non- parentheses, or a recursive match of the pattern itself (i.e. a correctly parenthesized substring). Finally there is a closing parenthesis. This particular example pattern contains nested unlimited repeats, and so the use of a once-only subpattern for match- ing strings of non-parentheses is important when applying the pattern to strings that do not match. For example, when it is applied to (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() it yields "no match" quickly. However, if a once-only sub- pattern is not used, the match runs for a very long time indeed because there are so many different ways the + and * repeats can carve up the subject, and all have to be tested before failure can be reported. The values set for any capturing subpatterns are those from the outermost level of the recursion at which the subpattern value is set. If the pattern above is matched against (ab(cd)ef) the value for the capturing parentheses is "ef", which is the last value taken on at the top level. If additional parentheses are added, giving \( ( ( (?>[^()]+) | (?R) )* ) \) ^ ^ ^ ^ the string they capture is "ab(cd)ef", the contents of the top level parentheses. If there are more than 15 capturing parentheses in a pattern, PCRE has to obtain extra memory to store data during a recursion, which it does by using pcre_malloc, freeing it via pcre_free afterwards. If no memory can be obtained, it saves data for the first 15 capturing parentheses only, as there is no way to give an out-of-memory error from within a recursion. PERFORMANCE Certain items that may appear in patterns are more efficient than others. It is more efficient to use a character class like [aeiou] than a set of alternatives such as (a|e|i|o|u). In general, the simplest construction that provides the required behaviour is usually the most efficient. Jeffrey Friedl's book contains a lot of discussion about optimizing regular expressions for efficient performance. When a pattern begins with .* and the PCRE_DOTALL option is set, the pattern is implicitly anchored by PCRE, since it can match only at the start of a subject string. However, if PCRE_DOTALL is not set, PCRE cannot make this optimization, because the . metacharacter does not then match a newline, and if the subject string contains newlines, the pattern may match from the character immediately following one of them instead of from the very start. For example, the pattern (.*) second matches the subject "first\nand second" (where \n stands for a newline character) with the first captured substring being "and". In order to do this, PCRE has to retry the match starting after every newline in the subject. If you are using such a pattern with subject strings that do not contain newlines, the best performance is obtained by setting PCRE_DOTALL, or starting the pattern with ^.* to indicate explicit anchoring. That saves PCRE from having to scan along the subject looking for a newline to restart at. Beware of patterns that contain nested indefinite repeats. These can take a long time to run when applied to a string that does not match. Consider the pattern fragment (a+)* This can match "aaaa" in 33 different ways, and this number increases very rapidly as the string gets longer. (The * repeat can match 0, 1, 2, 3, or 4 times, and for each of those cases other than 0, the + repeats can match different numbers of times.) When the remainder of the pattern is such that the entire match is going to fail, PCRE has in princi- ple to try every possible variation, and this can take an extremely long time. An optimization catches some of the more simple cases such as (a+)*b where a literal character follows. Before embarking on the standard matching procedure, PCRE checks that there is a "b" later in the subject string, and if there is not, it fails the match immediately. However, when there is no following literal this optimization cannot be used. You can see the difference by comparing the behaviour of (a+)*\d with the pattern above. The former gives a failure almost instantly when applied to a whole line of "a" characters, whereas the latter takes an appreciable time with strings longer than about 20 characters. UTF-8 SUPPORT Starting at release 3.3, PCRE has some support for character strings encoded in the UTF-8 format. This is incomplete, and is regarded as experimental. In order to use it, you must configure PCRE to include UTF-8 support in the code, and, in addition, you must call pcre_compile() with the PCRE_UTF8 option flag. When you do this, both the pattern and any sub- ject strings that are matched against it are treated as UTF-8 strings instead of just strings of bytes, but only in the cases that are mentioned below. If you compile PCRE with UTF-8 support, but do not use it at run time, the library will be a bit bigger, but the addi- tional run time overhead is limited to testing the PCRE_UTF8 flag in several places, so should not be very large. PCRE assumes that the strings it is given contain valid UTF-8 codes. It does not diagnose invalid UTF-8 strings. If you pass invalid UTF-8 strings to PCRE, the results are undefined. Running with PCRE_UTF8 set causes these changes in the way PCRE works: 1. In a pattern, the escape sequence \x{...}, where the con- tents of the braces is a string of hexadecimal digits, is interpreted as a UTF-8 character whose code number is the given hexadecimal number, for example: \x{1234}. This inserts from one to six literal bytes into the pattern, using the UTF-8 encoding. If a non-hexadecimal digit appears between the braces, the item is not recognized. 2. The original hexadecimal escape sequence, \xhh, generates a two-byte UTF-8 character if its value is greater than 127. 3. Repeat quantifiers are NOT correctly handled if they fol- low a multibyte character. For example, \x{100}* and \xc3+ do not work. If you want to repeat such characters, you must enclose them in non-capturing parentheses, for example (?:\x{100}), at present. 4. The dot metacharacter matches one UTF-8 character instead of a single byte. 5. Unlike literal UTF-8 characters, the dot metacharacter followed by a repeat quantifier does operate correctly on UTF-8 characters instead of single bytes. 4. Although the \x{...} escape is permitted in a character class, characters whose values are greater than 255 cannot be included in a class. 5. A class is matched against a UTF-8 character instead of just a single byte, but it can match only characters whose values are less than 256. Characters with greater values always fail to match a class. 6. Repeated classes work correctly on multiple characters. 7. Classes containing just a single character whose value is greater than 127 (but less than 256), for example, [\x80] or [^\x{93}], do not work because these are optimized into sin- gle byte matches. In the first case, of course, the class brackets are just redundant. 8. Lookbehind assertions move backwards in the subject by a fixed number of characters instead of a fixed number of bytes. Simple cases have been tested to work correctly, but there may be hidden gotchas herein. 9. The character types such as \d and \w do not work correctly with UTF-8 characters. They continue to test a single byte. 10. Anything not explicitly mentioned here continues to work in bytes rather than in characters. The following UTF-8 features of Perl 5.6 are not imple- mented: 1. The escape sequence \C to match a single byte. 2. The use of Unicode tables and properties and escapes \p, \P, and \X. AUTHOR Philip Hazel University Computing Service, New Museums Site, Cambridge CB2 3QG, England. Phone: +44 1223 334714 Last updated: 28 August 2000, the 250th anniversary of the death of J.S. Bach. Copyright (c) 1997-2000 University of Cambridge. privoxy-3.0.21-stable/./pcre/doc/NON-UNIX-USE000640 001751 001751 00000004310 10546014077 017252 0ustar00fkfk000000 000000 Compiling PCRE on non-Unix systems ---------------------------------- If you want to compile PCRE for a non-Unix system, note that it consists entirely of code written in Standard C, and so should compile successfully on any machine with a Standard C compiler and library, using normal compiling commands to do the following: (1) Copy or rename the file config.in as config.h, and change the macros that define HAVE_STRERROR and HAVE_MEMMOVE to define them as 1 rather than 0. Unfortunately, because of the way Unix autoconf works, the default setting has to be 0. (2) Copy or rename the file pcre.in as pcre.h, and change the macro definitions for PCRE_MAJOR, PCRE_MINOR, and PCRE_DATE near its start to the values set in configure.in. (3) Compile dftables.c as a stand-alone program, and then run it with the standard output sent to chartables.c. This generates a set of standard character tables. (4) Compile maketables.c, get.c, study.c and pcre.c and link them all together into an object library in whichever form your system keeps such libraries. This is the pcre library (chartables.c gets included by means of an #include directive). (5) Similarly, compile pcreposix.c and link it as the pcreposix library. (6) Compile the test program pcretest.c. This needs the functions in the pcre and pcreposix libraries when linking. (7) Run pcretest on the testinput files in the testdata directory, and check that the output matches the corresponding testoutput files. You must use the -i option when checking testinput2. If you have a system without "configure" but where you can use a Makefile, edit Makefile.in to create Makefile, substituting suitable values for the variables at the head of the file. Some help in building a Win32 DLL of PCRE in GnuWin32 environments was contributed by Paul.Sokolovsky@technologist.com. These environments are Mingw32 (http://www.xraylith.wisc.edu/~khan/software/gnu-win32/) and CygWin (http://sourceware.cygnus.com/cygwin/). Paul comments: For CygWin, set CFLAGS=-mno-cygwin, and do 'make dll'. You'll get pcre.dll (containing pcreposix also), libpcre.dll.a, and dynamically linked pgrep and pcretest. If you have /bin/sh, run RunTest (three main test go ok, locale not supported). **** privoxy-3.0.21-stable/./pcre/doc/ChangeLog000640 001751 001751 00000060346 10546014077 017247 0ustar00fkfk000000 000000 ChangeLog for PCRE ------------------ Version 3.4 22-Aug-00 --------------------- 1. Fixed typo in pcre.h: unsigned const char * changed to const unsigned char *. 2. Diagnose condition (?(0) as an error instead of crashing on matching. Version 3.3 01-Aug-00 --------------------- 1. If an octal character was given, but the value was greater than \377, it was not getting masked to the least significant bits, as documented. This could lead to crashes in some systems. 2. Perl 5.6 (if not earlier versions) accepts classes like [a-\d] and treats the hyphen as a literal. PCRE used to give an error; it now behaves like Perl. 3. Added the functions pcre_free_substring() and pcre_free_substring_list(). These just pass their arguments on to (pcre_free)(), but they are provided because some uses of PCRE bind it to non-C systems that can call its functions, but cannot call free() or pcre_free() directly. 4. Add "make test" as a synonym for "make check". Corrected some comments in the Makefile. 5. Add $(DESTDIR)/ in front of all the paths in the "install" target in the Makefile. 6. Changed the name of pgrep to pcregrep, because Solaris has introduced a command called pgrep for grepping around the active processes. 7. Added the beginnings of support for UTF-8 character strings. 8. Arranged for the Makefile to pass over the settings of CC, CFLAGS, and RANLIB to ./ltconfig so that they are used by libtool. I think these are all the relevant ones. (AR is not passed because ./ltconfig does its own figuring out for the ar command.) Version 3.2 12-May-00 --------------------- This is purely a bug fixing release. 1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead of ZA. This was just one example of several cases that could provoke this bug, which was introduced by change 9 of version 2.00. The code for breaking infinite loops after an iteration that matches an empty string was't working correctly. 2. The pcretest program was not imitating Perl correctly for the pattern /a*/g when matched against abbab (for example). After matching an empty string, it wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this caused it to match further down the string than it should. 3. The code contained an inclusion of sys/types.h. It isn't clear why this was there because it doesn't seem to be needed, and it causes trouble on some systems, as it is not a Standard C header. It has been removed. 4. Made 4 silly changes to the source to avoid stupid compiler warnings that were reported on the Macintosh. The changes were from while ((c = *(++ptr)) != 0 && c != '\n'); to while ((c = *(++ptr)) != 0 && c != '\n') ; Totally extraordinary, but if that's what it takes... 5. PCRE is being used in one environment where neither memmove() nor bcopy() is available. Added HAVE_BCOPY and an autoconf test for it; if neither HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which assumes the way PCRE uses memmove() (always moving upwards). 6. PCRE is being used in one environment where strchr() is not available. There was only one use in pcre.c, and writing it out to avoid strchr() probably gives faster code anyway. Version 3.1 09-Feb-00 --------------------- The only change in this release is the fixing of some bugs in Makefile.in for the "install" target: (1) It was failing to install pcreposix.h. (2) It was overwriting the pcre.3 man page with the pcreposix.3 man page. Version 3.0 01-Feb-00 --------------------- 1. Add support for the /+ modifier to perltest (to output $` like it does in pcretest). 2. Add support for the /g modifier to perltest. 3. Fix pcretest so that it behaves even more like Perl for /g when the pattern matches null strings. 4. Fix perltest so that it doesn't do unwanted things when fed an empty pattern. Perl treats empty patterns specially - it reuses the most recent pattern, which is not what we want. Replace // by /(?#)/ in order to avoid this effect. 5. The POSIX interface was broken in that it was just handing over the POSIX captured string vector to pcre_exec(), but (since release 2.00) PCRE has required a bigger vector, with some working space on the end. This means that the POSIX wrapper now has to get and free some memory, and copy the results. 6. Added some simple autoconf support, placing the test data and the documentation in separate directories, re-organizing some of the information files, and making it build pcre-config (a GNU standard). Also added libtool support for building PCRE as a shared library, which is now the default. 7. Got rid of the leading zero in the definition of PCRE_MINOR because 08 and 09 are not valid octal constants. Single digits will be used for minor values less than 10. 8. Defined REG_EXTENDED and REG_NOSUB as zero in the POSIX header, so that existing programs that set these in the POSIX interface can use PCRE without modification. 9. Added a new function, pcre_fullinfo() with an extensible interface. It can return all that pcre_info() returns, plus additional data. The pcre_info() function is retained for compatibility, but is considered to be obsolete. 10. Added experimental recursion feature (?R) to handle one common case that Perl 5.6 will be able to do with (?p{...}). 11. Added support for POSIX character classes like [:alpha:], which Perl is adopting. Version 2.08 31-Aug-99 ---------------------- 1. When startoffset was not zero and the pattern began with ".*", PCRE was not trying to match at the startoffset position, but instead was moving forward to the next newline as if a previous match had failed. 2. pcretest was not making use of PCRE_NOTEMPTY when repeating for /g and /G, and could get into a loop if a null string was matched other than at the start of the subject. 3. Added definitions of PCRE_MAJOR and PCRE_MINOR to pcre.h so the version can be distinguished at compile time, and for completeness also added PCRE_DATE. 5. Added Paul Sokolovsky's minor changes to make it easy to compile a Win32 DLL in GnuWin32 environments. Version 2.07 29-Jul-99 ---------------------- 1. The documentation is now supplied in plain text form and HTML as well as in the form of man page sources. 2. C++ compilers don't like assigning (void *) values to other pointer types. In particular this affects malloc(). Although there is no problem in Standard C, I've put in casts to keep C++ compilers happy. 3. Typo on pcretest.c; a cast of (unsigned char *) in the POSIX regexec() call should be (const char *). 4. If NOPOSIX is defined, pcretest.c compiles without POSIX support. This may be useful for non-Unix systems who don't want to bother with the POSIX stuff. However, I haven't made this a standard facility. The documentation doesn't mention it, and the Makefile doesn't support it. 5. The Makefile now contains an "install" target, with editable destinations at the top of the file. The pcretest program is not installed. 6. pgrep -V now gives the PCRE version number and date. 7. Fixed bug: a zero repetition after a literal string (e.g. /abcde{0}/) was causing the entire string to be ignored, instead of just the last character. 8. If a pattern like /"([^\\"]+|\\.)*"/ is applied in the normal way to a non-matching string, it can take a very, very long time, even for strings of quite modest length, because of the nested recursion. PCRE now does better in some of these cases. It does this by remembering the last required literal character in the pattern, and pre-searching the subject to ensure it is present before running the real match. In other words, it applies a heuristic to detect some types of certain failure quickly, and in the above example, if presented with a string that has no trailing " it gives "no match" very quickly. 9. A new runtime option PCRE_NOTEMPTY causes null string matches to be ignored; other alternatives are tried instead. Version 2.06 09-Jun-99 ---------------------- 1. Change pcretest's output for amount of store used to show just the code space, because the remainder (the data block) varies in size between 32-bit and 64-bit systems. 2. Added an extra argument to pcre_exec() to supply an offset in the subject to start matching at. This allows lookbehinds to work when searching for multiple occurrences in a string. 3. Added additional options to pcretest for testing multiple occurrences: /+ outputs the rest of the string that follows a match /g loops for multiple occurrences, using the new startoffset argument /G loops for multiple occurrences by passing an incremented pointer 4. PCRE wasn't doing the "first character" optimization for patterns starting with \b or \B, though it was doing it for other lookbehind assertions. That is, it wasn't noticing that a match for a pattern such as /\bxyz/ has to start with the letter 'x'. On long subject strings, this gives a significant speed-up. Version 2.05 21-Apr-99 ---------------------- 1. Changed the type of magic_number from int to long int so that it works properly on 16-bit systems. 2. Fixed a bug which caused patterns starting with .* not to work correctly when the subject string contained newline characters. PCRE was assuming anchoring for such patterns in all cases, which is not correct because .* will not pass a newline unless PCRE_DOTALL is set. It now assumes anchoring only if DOTALL is set at top level; otherwise it knows that patterns starting with .* must be retried after every newline in the subject. Version 2.04 18-Feb-99 ---------------------- 1. For parenthesized subpatterns with repeats whose minimum was zero, the computation of the store needed to hold the pattern was incorrect (too large). If such patterns were nested a few deep, this could multiply and become a real problem. 2. Added /M option to pcretest to show the memory requirement of a specific pattern. Made -m a synonym of -s (which does this globally) for compatibility. 3. Subpatterns of the form (regex){n,m} (i.e. limited maximum) were being compiled in such a way that the backtracking after subsequent failure was pessimal. Something like (a){0,3} was compiled as (a)?(a)?(a)? instead of ((a)((a)(a)?)?)? with disastrous performance if the maximum was of any size. Version 2.03 02-Feb-99 ---------------------- 1. Fixed typo and small mistake in man page. 2. Added 4th condition (GPL supersedes if conflict) and created separate LICENCE file containing the conditions. 3. Updated pcretest so that patterns such as /abc\/def/ work like they do in Perl, that is the internal \ allows the delimiter to be included in the pattern. Locked out the use of \ as a delimiter. If \ immediately follows the final delimiter, add \ to the end of the pattern (to test the error). 4. Added the convenience functions for extracting substrings after a successful match. Updated pcretest to make it able to test these functions. Version 2.02 14-Jan-99 ---------------------- 1. Initialized the working variables associated with each extraction so that their saving and restoring doesn't refer to uninitialized store. 2. Put dummy code into study.c in order to trick the optimizer of the IBM C compiler for OS/2 into generating correct code. Apparently IBM isn't going to fix the problem. 3. Pcretest: the timing code wasn't using LOOPREPEAT for timing execution calls, and wasn't printing the correct value for compiling calls. Increased the default value of LOOPREPEAT, and the number of significant figures in the times. 4. Changed "/bin/rm" in the Makefile to "-rm" so it works on Windows NT. 5. Renamed "deftables" as "dftables" to get it down to 8 characters, to avoid a building problem on Windows NT with a FAT file system. Version 2.01 21-Oct-98 ---------------------- 1. Changed the API for pcre_compile() to allow for the provision of a pointer to character tables built by pcre_maketables() in the current locale. If NULL is passed, the default tables are used. Version 2.00 24-Sep-98 ---------------------- 1. Since the (>?) facility is in Perl 5.005, don't require PCRE_EXTRA to enable it any more. 2. Allow quantification of (?>) groups, and make it work correctly. 3. The first character computation wasn't working for (?>) groups. 4. Correct the implementation of \Z (it is permitted to match on the \n at the end of the subject) and add 5.005's \z, which really does match only at the very end of the subject. 5. Remove the \X "cut" facility; Perl doesn't have it, and (?> is neater. 6. Remove the ability to specify CASELESS, MULTILINE, DOTALL, and DOLLAR_END_ONLY at runtime, to make it possible to implement the Perl 5.005 localized options. All options to pcre_study() were also removed. 7. Add other new features from 5.005: $(?<= positive lookbehind $(?a*))*/ (a PCRE_EXTRA facility). Version 1.00 18-Nov-97 ---------------------- 1. Added compile-time macros to support systems such as SunOS4 which don't have memmove() or strerror() but have other things that can be used instead. 2. Arranged that "make clean" removes the executables. Version 0.99 27-Oct-97 ---------------------- 1. Fixed bug in code for optimizing classes with only one character. It was initializing a 32-byte map regardless, which could cause it to run off the end of the memory it had got. 2. Added, conditional on PCRE_EXTRA, the proposed (?>REGEX) construction. Version 0.98 22-Oct-97 ---------------------- 1. Fixed bug in code for handling temporary memory usage when there are more back references than supplied space in the ovector. This could cause segfaults. Version 0.97 21-Oct-97 ---------------------- 1. Added the \X "cut" facility, conditional on PCRE_EXTRA. 2. Optimized negated single characters not to use a bit map. 3. Brought error texts together as macro definitions; clarified some of them; fixed one that was wrong - it said "range out of order" when it meant "invalid escape sequence". 4. Changed some char * arguments to const char *. 5. Added PCRE_NOTBOL and PCRE_NOTEOL (from POSIX). 6. Added the POSIX-style API wrapper in pcreposix.a and testing facilities in pcretest. Version 0.96 16-Oct-97 ---------------------- 1. Added a simple "pgrep" utility to the distribution. 2. Fixed an incompatibility with Perl: "{" is now treated as a normal character unless it appears in one of the precise forms "{ddd}", "{ddd,}", or "{ddd,ddd}" where "ddd" means "one or more decimal digits". 3. Fixed serious bug. If a pattern had a back reference, but the call to pcre_exec() didn't supply a large enough ovector to record the related identifying subpattern, the match always failed. PCRE now remembers the number of the largest back reference, and gets some temporary memory in which to save the offsets during matching if necessary, in order to ensure that backreferences always work. 4. Increased the compatibility with Perl in a number of ways: (a) . no longer matches \n by default; an option PCRE_DOTALL is provided to request this handling. The option can be set at compile or exec time. (b) $ matches before a terminating newline by default; an option PCRE_DOLLAR_ENDONLY is provided to override this (but not in multiline mode). The option can be set at compile or exec time. (c) The handling of \ followed by a digit other than 0 is now supposed to be the same as Perl's. If the decimal number it represents is less than 10 or there aren't that many previous left capturing parentheses, an octal escape is read. Inside a character class, it's always an octal escape, even if it is a single digit. (d) An escaped but undefined alphabetic character is taken as a literal, unless PCRE_EXTRA is set. Currently this just reserves the remaining escapes. (e) {0} is now permitted. (The previous item is removed from the compiled pattern). 5. Changed all the names of code files so that the basic parts are no longer than 10 characters, and abolished the teeny "globals.c" file. 6. Changed the handling of character classes; they are now done with a 32-byte bit map always. 7. Added the -d and /D options to pcretest to make it possible to look at the internals of compilation without having to recompile pcre. Version 0.95 23-Sep-97 ---------------------- 1. Fixed bug in pre-pass concerning escaped "normal" characters such as \x5c or \x20 at the start of a run of normal characters. These were being treated as real characters, instead of the source characters being re-checked. Version 0.94 18-Sep-97 ---------------------- 1. The functions are now thread-safe, with the caveat that the global variables containing pointers to malloc() and free() or alternative functions are the same for all threads. 2. Get pcre_study() to generate a bitmap of initial characters for non- anchored patterns when this is possible, and use it if passed to pcre_exec(). Version 0.93 15-Sep-97 ---------------------- 1. /(b)|(:+)/ was computing an incorrect first character. 2. Add pcre_study() to the API and the passing of pcre_extra to pcre_exec(), but not actually doing anything yet. 3. Treat "-" characters in classes that cannot be part of ranges as literals, as Perl does (e.g. [-az] or [az-]). 4. Set the anchored flag if a branch starts with .* or .*? because that tests all possible positions. 5. Split up into different modules to avoid including unneeded functions in a compiled binary. However, compile and exec are still in one module. The "study" function is split off. 6. The character tables are now in a separate module whose source is generated by an auxiliary program - but can then be edited by hand if required. There are now no calls to isalnum(), isspace(), isdigit(), isxdigit(), tolower() or toupper() in the code. 7. Turn the malloc/free funtions variables into pcre_malloc and pcre_free and make them global. Abolish the function for setting them, as the caller can now set them directly. Version 0.92 11-Sep-97 ---------------------- 1. A repeat with a fixed maximum and a minimum of 1 for an ordinary character (e.g. /a{1,3}/) was broken (I mis-optimized it). 2. Caseless matching was not working in character classes if the characters in the pattern were in upper case. 3. Make ranges like [W-c] work in the same way as Perl for caseless matching. 4. Make PCRE_ANCHORED public and accept as a compile option. 5. Add an options word to pcre_exec() and accept PCRE_ANCHORED and PCRE_CASELESS at run time. Add escapes \A and \I to pcretest to cause it to pass them. 6. Give an error if bad option bits passed at compile or run time. 7. Add PCRE_MULTILINE at compile and exec time, and (?m) as well. Add \M to pcretest to cause it to pass that flag. 8. Add pcre_info(), to get the number of identifying subpatterns, the stored options, and the first character, if set. 9. Recognize C+ or C{n,m} where n >= 1 as providing a fixed starting character. Version 0.91 10-Sep-97 ---------------------- 1. PCRE was failing to diagnose unlimited repeats of subpatterns that could match the empty string as in /(a*)*/. It was looping and ultimately crashing. 2. PCRE was looping on encountering an indefinitely repeated back reference to a subpattern that had matched an empty string, e.g. /(a|)\1*/. It now does what Perl does - treats the match as successful. **** privoxy-3.0.21-stable/./pcre/pcre.in000640 001751 001751 00000006117 10546014100 016170 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2000 University of Cambridge */ #ifndef _PCRE_H #define _PCRE_H /* The file pcre.h is build by "configure". Do not edit it; instead make changes to pcre.in. */ #define PCRE_MAJOR @PCRE_MAJOR@ #define PCRE_MINOR @PCRE_MINOR@ #define PCRE_DATE @PCRE_DATE@ /* Win32 uses DLL by default */ #ifdef _WIN32 # ifdef STATIC_PCRE # define PCRE_DL_IMPORT # else # define PCRE_DL_IMPORT __declspec(dllimport) # endif #else # define PCRE_DL_IMPORT #endif /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options */ #define PCRE_CASELESS 0x0001 #define PCRE_MULTILINE 0x0002 #define PCRE_DOTALL 0x0004 #define PCRE_EXTENDED 0x0008 #define PCRE_ANCHORED 0x0010 #define PCRE_DOLLAR_ENDONLY 0x0020 #define PCRE_EXTRA 0x0040 #define PCRE_NOTBOL 0x0080 #define PCRE_NOTEOL 0x0100 #define PCRE_UNGREEDY 0x0200 #define PCRE_NOTEMPTY 0x0400 #define PCRE_UTF8 0x0800 /* Exec-time and get-time error codes */ #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_UNKNOWN_NODE (-5) #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) /* Request types for pcre_fullinfo() */ #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_FIRSTCHAR 4 #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 /* Types */ typedef void pcre; typedef void pcre_extra; /* Store get and free functions. These can be set to alternative malloc/free functions if required. Some magic is required for Win32 DLL; it is null on other OS. */ PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t); PCRE_DL_IMPORT extern void (*pcre_free)(void *); #undef PCRE_DL_IMPORT /* Functions */ extern pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); extern int pcre_copy_substring(const char *, int *, int, int, char *, int); extern int pcre_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int); extern void pcre_free_substring(const char *); extern void pcre_free_substring_list(const char **); extern int pcre_get_substring(const char *, int *, int, int, const char **); extern int pcre_get_substring_list(const char *, int *, int, const char ***); extern int pcre_info(const pcre *, int *, int *); extern int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *); extern unsigned const char *pcre_maketables(void); extern pcre_extra *pcre_study(const pcre *, int, const char **); extern const char *pcre_version(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcre.h */ privoxy-3.0.21-stable/./pcre/study.c000640 001751 001751 00000025172 10546014100 016225 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* Include the internals header, which itself includes Standard C headers plus the external pcre header. */ #include "internal.h" /************************************************* * Set a bit and maybe its alternate case * *************************************************/ /* Given a character, set its bit in the table, and also the bit for the other version of a letter if we are caseless. Arguments: start_bits points to the bit map c is the character caseless the caseless flag cd the block with char table pointers Returns: nothing */ static void set_bit(uschar *start_bits, int c, BOOL caseless, compile_data *cd) { start_bits[c/8] |= (1 << (c&7)); if (caseless && (cd->ctypes[c] & ctype_letter) != 0) start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7)); } /************************************************* * Create bitmap of starting chars * *************************************************/ /* This function scans a compiled unanchored expression and attempts to build a bitmap of the set of initial characters. If it can't, it returns FALSE. As time goes by, we may be able to get more clever at doing this. Arguments: code points to an expression start_bits points to a 32-byte table, initialized to 0 caseless the current state of the caseless flag cd the block with char table pointers Returns: TRUE if table built, FALSE otherwise */ static BOOL set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, compile_data *cd) { register int c; /* This next statement and the later reference to dummy are here in order to trick the optimizer of the IBM C compiler for OS/2 into generating correct code. Apparently IBM isn't going to fix the problem, and we would rather not disable optimization (in this module it actually makes a big difference, and the pcre module can use all the optimization it can get). */ volatile int dummy; do { const uschar *tcode = code + 3; BOOL try_next = TRUE; while (try_next) { try_next = FALSE; /* If a branch starts with a bracket or a positive lookahead assertion, recurse to set bits from within them. That's all for this branch. */ if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT) { if (!set_start_bits(tcode, start_bits, caseless, cd)) return FALSE; } else switch(*tcode) { default: return FALSE; /* Skip over lookbehind and negative lookahead assertions */ case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: try_next = TRUE; do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); tcode += 3; break; /* Skip over an option setting, changing the caseless flag */ case OP_OPT: caseless = (tcode[1] & PCRE_CASELESS) != 0; tcode += 2; try_next = TRUE; break; /* BRAZERO does the bracket, but carries on. */ case OP_BRAZERO: case OP_BRAMINZERO: if (!set_start_bits(++tcode, start_bits, caseless, cd)) return FALSE; dummy = 1; do tcode += (tcode[1] << 8) + tcode[2]; while (*tcode == OP_ALT); tcode += 3; try_next = TRUE; break; /* Single-char * or ? sets the bit and tries the next item */ case OP_STAR: case OP_MINSTAR: case OP_QUERY: case OP_MINQUERY: set_bit(start_bits, tcode[1], caseless, cd); tcode += 2; try_next = TRUE; break; /* Single-char upto sets the bit and tries the next */ case OP_UPTO: case OP_MINUPTO: set_bit(start_bits, tcode[3], caseless, cd); tcode += 4; try_next = TRUE; break; /* At least one single char sets the bit and stops */ case OP_EXACT: /* Fall through */ tcode++; case OP_CHARS: /* Fall through */ tcode++; case OP_PLUS: case OP_MINPLUS: set_bit(start_bits, tcode[1], caseless, cd); break; /* Single character type sets the bits and stops */ case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; break; /* One or more character type fudges the pointer and restarts, knowing it will hit a single character type and stop there. */ case OP_TYPEPLUS: case OP_TYPEMINPLUS: tcode++; try_next = TRUE; break; case OP_TYPEEXACT: tcode += 3; try_next = TRUE; break; /* Zero or more repeats of character types set the bits and then try again. */ case OP_TYPEUPTO: case OP_TYPEMINUPTO: tcode += 2; /* Fall through */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: switch(tcode[1]) { case OP_NOT_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_digit]; break; case OP_DIGIT: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_digit]; break; case OP_NOT_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_space]; break; case OP_WHITESPACE: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_space]; break; case OP_NOT_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= ~cd->cbits[c+cbit_word]; break; case OP_WORDCHAR: for (c = 0; c < 32; c++) start_bits[c] |= cd->cbits[c+cbit_word]; break; } tcode += 2; try_next = TRUE; break; /* Character class: set the bits and either carry on or not, according to the repeat count. */ case OP_CLASS: { tcode++; for (c = 0; c < 32; c++) start_bits[c] |= tcode[c]; tcode += 32; switch (*tcode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: tcode++; try_next = TRUE; break; case OP_CRRANGE: case OP_CRMINRANGE: if (((tcode[1] << 8) + tcode[2]) == 0) { tcode += 5; try_next = TRUE; } break; } } break; /* End of class handling */ } /* End of switch */ } /* End of try_next loop */ code += (code[1] << 8) + code[2]; /* Advance to next branch */ } while (*code == OP_ALT); return TRUE; } /************************************************* * Study a compiled expression * *************************************************/ /* This function is handed a compiled expression that it must study to produce information that will speed up the matching. It returns a pcre_extra block which then gets handed back to pcre_exec(). Arguments: re points to the compiled expression options contains option bits errorptr points to where to place error messages; set NULL unless error Returns: pointer to a pcre_extra block, NULL on error or if no optimization possible */ pcre_extra * pcre_study(const pcre *external_re, int options, const char **errorptr) { uschar start_bits[32]; real_pcre_extra *extra; const real_pcre *re = (const real_pcre *)external_re; compile_data compile_block; *errorptr = NULL; if (re == NULL || re->magic_number != MAGIC_NUMBER) { *errorptr = "argument is not a compiled regular expression"; return NULL; } if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) { *errorptr = "unknown or incorrect option bit(s) set"; return NULL; } /* For an anchored pattern, or an unchored pattern that has a first char, or a multiline pattern that matches only at "line starts", no further processing at present. */ if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0) return NULL; /* Set the character tables in the block which is passed around */ compile_block.lcc = re->tables + lcc_offset; compile_block.fcc = re->tables + fcc_offset; compile_block.cbits = re->tables + cbits_offset; compile_block.ctypes = re->tables + ctypes_offset; /* See if we can find a fixed set of initial characters for the pattern. */ memset(start_bits, 0, 32 * sizeof(uschar)); if (!set_start_bits(re->code, start_bits, (re->options & PCRE_CASELESS) != 0, &compile_block)) return NULL; /* Get an "extra" block and put the information therein. */ extra = (real_pcre_extra *)(pcre_malloc)(sizeof(real_pcre_extra)); if (extra == NULL) { *errorptr = "failed to get memory"; return NULL; } extra->options = PCRE_STUDY_MAPPED; memcpy(extra->start_bits, start_bits, sizeof(start_bits)); return (pcre_extra *)extra; } /* End of study.c */ privoxy-3.0.21-stable/./pcre/pcre-config.in000640 001751 001751 00000002105 10546014100 017424 0ustar00fkfk000000 000000 #!/bin/sh prefix=@prefix@ exec_prefix=@exec_prefix@ exec_prefix_set=no usage="\ Usage: pcre-config [--prefix] [--exec-prefix] [--version] [--libs] [--libs-posix] [--cflags] [--cflags-posix]" if test $# -eq 0; then echo "${usage}" 1>&2 exit 1 fi while test $# -gt 0; do case "$1" in -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac case $1 in --prefix=*) prefix=$optarg if test $exec_prefix_set = no ; then exec_prefix=$optarg fi ;; --prefix) echo $prefix ;; --exec-prefix=*) exec_prefix=$optarg exec_prefix_set=yes ;; --exec-prefix) echo $exec_prefix ;; --version) echo @PCRE_VERSION@ ;; --cflags | --cflags-posix) if test @includedir@ != /usr/include ; then includes=-I@includedir@ fi echo $includes ;; --libs-posix) echo -L@libdir@ -lpcreposix -lpcre ;; --libs) echo -L@libdir@ -lpcre ;; *) echo "${usage}" 1>&2 exit 1 ;; esac shift done privoxy-3.0.21-stable/./pcre/install-sh000640 001751 001751 00000012736 10546014100 016714 0ustar00fkfk000000 000000 #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 privoxy-3.0.21-stable/./pcre/dftables000750 001751 001751 00000054605 10546014100 016425 0ustar00fkfk000000 000000 ELF ì‰4G4 (!44€4€  ÔÔ€Ô€€€ö7ö78ÈÈ#¸8¸È¸ÈÐÐ/libexec/ld-elf.so.1%,)&*+!" ' $(#   % Ü6Œo—¸Èñÿ8]fà  Ê"ªIÚ´ˆ º(ÊT ÍØÚÕÛ1% ãÁéÈôx|Öñ„E€ÖÊñÿ '1@7 >„° =iD+yKÀˆÊñÿR Éñÿ›ëñÿFEh>oivR l }olibpthread.so.2getpidmallocabort__deregister_frame_info__error__isthreaded_Jv_RegisterClassesfcntl__register_frame_infolibc.so.6___toupper_DYNAMIC__stderrpftruncate_init_DefaultRuneLocaleenvironfstatfprintffseek__progname___runetype_CurrentRuneLocalefdopenfreadmemset_init_tlsftellfclose_finiatexitfwrite_GLOBAL_OFFSET_TABLE_setbuffilenostrchr___tolower_edata__bss_start_endLIBTHREAD_1_0¬   Ê(Ê |ր֬ɰɴɸɼÉÀÉÄÉ ÈÉ ÌÉÐÉÔÉØÉÜÉàÉäÉèÉìÉðÉôÉøÉüÉ Ê!Ê%Ê& Ê'Ê(Ê+ƒì è¥è7(ƒÄ Ãÿ5¤Éÿ%¨Éÿ%¬Éhéàÿÿÿÿ%°ÉhéÐÿÿÿÿ%´ÉhéÀÿÿÿÿ%¸Éhé°ÿÿÿÿ%¼Éh é ÿÿÿÿ%ÀÉh(éÿÿÿÿ%ÄÉh0é€ÿÿÿÿ%ÈÉh8épÿÿÿÿ%ÌÉh@é`ÿÿÿÿ%ÐÉhHéPÿÿÿÿ%ÔÉhPé@ÿÿÿÿ%ØÉhXé0ÿÿÿÿ%ÜÉh`é ÿÿÿÿ%àÉhhéÿÿÿÿ%äÉhpéÿÿÿÿ%èÉhxéðþÿÿÿ%ìÉh€éàþÿÿÿ%ðÉhˆéÐþÿÿÿ%ôÉhéÀþÿÿÿ%øÉh˜é°þÿÿÿ%üÉh é þÿÿÿ%Êh¨éþÿÿÿ%Êh°é€þÿÿÿ%Êh¸épþÿÿÿ% ÊhÀé`þÿÿÿ%ÊhÈéPþÿÿÿ%ÊhÐé@þÿÿU‰åWVSƒì ƒäð‹]‰×t …Û‰5ØÚ~%‹E…Àt£È‰Á¶„Àt‰<$è+ÿÿÿÇ$„°èÿÿÿèÆýÿÿE‰t$‰$‰D$è§ ‰$è/ÿÿÿ‰Ñ‰Èë²è°þÿÿëÃU‰åƒì€=„Ö>t ë1ƒÀ£ÈÿÒ¡È‹…Òu븅Àt Ç$´ÈèDuû÷Æ„ÖÉÃU¸‰åƒì…ÀtÇD$ˆÖÇ$´Èèuû÷¡œÉ…Àt¸…Àt Ç$œÉèútû÷ÉÃU‰åVSƒìPƒ Öƒ¤Öƒì h@èaýÿÿƒÄ‰Eôƒ}ôuÇE䃨փ¬Ö騋Eô‰EðÇEì}ìÿ=ƒ°Öƒ´Ö‹Eð‰Ãƒì ÿuìEðÿè ƒÄˆEìÿƒ¸Öƒ¼ÖëºÇEì}ìÿžƒÀÖƒÄÖ‹Eð‰EàEðÿƒìhÿuìè ƒÄ…Àt!ƒÐÖƒÔÖƒì ÿuìèwƒÄˆEßë-ƒØÖƒÜÖƒì ÿuìè~ ƒÄˆE߃àÖƒäÖŠEß‹UàˆEìÿƒèÖƒìÖéUÿÿÿƒÈÖƒÌÖƒìh@jÿuðè¦üÿÿƒÄÇEì}ìÿ²ƒðÖƒôÖƒìhÿuìèYƒÄƒøÖƒüÖ…À„ž‹Eì‰E؃}ØyƒE؃׃׋UØÁú‰ÐEðX@‰ÐEðP@‹Mìƒá¸Óà ˆ‹Eì‰EÔƒ}ÔyƒEԃ׃ ׋UÔÁú‰ÐE𘠉ÐEð ‹Mìƒá¸Óà ˆƒ×ƒ×ƒìh€ÿuìèrƒÄƒ×ƒ×…À„ž‹Eì‰EЃ}ÐyƒEЃ ׃$׋UÐÁú‰ÐEðX`‰ÐEðP`‹Mìƒá¸Óà ˆ‹Eì‰Ẽ}ÌyƒẼ(׃,׋UÌÁú‰ÐE𘠉ÐEð ‹Mìƒá¸Óà ˆƒ0׃4׃ìhÿuì諃ă8׃<×…À„¤‹Eì‰Eȃ}ÈyƒEȃ@׃D׋UÈÁú‰ÐE𘀉ÐEð€‹Mìƒá¸Óà ˆ‹Eì‰Eă}ÄyƒEăH׃L׋UÄÁú‰ÐE𘠉ÐEð ‹Mìƒá¸Óà ˆƒP׃T׃}ì_uY‹Eì‰EÀƒ}ÀyƒEÀƒX׃\׋UÀÁú‰ÐE𘠉ÐEð ‹Mìƒá¸Óà ˆƒ`׃d׃ìh@ÿuìèƒÄƒh׃l×…ÀtK‹Eì‰E¼ƒ}¼yƒE¼ƒp׃t׋U¼Áú‹uð‹]ð‹Mìƒá¸Óà ˆ2ƒx׃|׃ìhÿuìè/ƒÄƒ€×ƒ„×…ÀtS‹Eì‰E¸ƒ}¸yƒE¸ƒˆ×ƒŒ×‹U¸Áú‰ÐEðX ‰ÐEðP ‹Mìƒá¸Óà ˆƒ×ƒ”׃ìhÿuì藃ă˜×ƒœ×…ÀtY‹Eì‰E´ƒ}´yƒE´ƒ ×ƒ¤×‹U´Áú‰ÐEð˜À‰ÐEðÀ‹Mìƒá¸Óà ˆƒ¨×ƒ¬×ƒìhÿuìèƒÄƒ°×ƒ´×…ÀtY‹Eì‰E°ƒ}°yƒE°ƒ¸×ƒ¼×‹U°Áú‰ÐEð˜à‰ÐEðà‹Mìƒá¸Óà ˆƒÀ׃Ä׃ìh ÿuì蛃ăÈ׃Ì×…ÀtY‹Eì‰E¬ƒ}¬yƒE¬ƒÐ׃Ô׋U¬Áú‰ÐEð˜‰ÐEð‹Mìƒá¸Óà ˆƒØ×ƒÜ׃ìhÿuìèƒÄ…ÀtY‹Eì‰E¨ƒ}¨yƒE¨ƒà׃ä׋U¨Áú‰ÐE𘠉ÐEð ‹Mìƒá¸Óà ˆƒè׃ì×Eìÿƒð׃ô×éAúÿÿEð@ÇEì}ìÿ‰ƒø×ƒü×ÇEèƒìh@ÿuìècƒÄƒØƒØ…ÀtEèÿƒØƒ ؃ìhÿuìè+ƒÄƒØƒØ…ÀtE胃؃؃ìhÿuìèƒÄƒ ؃$Ø…ÀtE胃(؃,؃ìhÿuìèكă0؃4Ø…ÀtE胃8؃<؃ìhÿuì考ąÀuƒ@؃D؃}ì_uE胃H؃L؃ìÿuìhܰè)öÿÿƒÄ…ÀtEèƒ(€ƒP؃TØ‹Eð‰Â‹EèˆEðÿEìÿƒX؃\Øéjþÿÿ‹Eô‰Eäƒ`؃dØ‹Eäeø[^ÉÃU‰åƒìƒh؃lØÇEüƒ}xMƒp؃tØ}ÿ6ƒx؃|Ø‹E‹U ‹…\Ê!Ð…ÀtÇEüƒ€Øƒ„Ø‹EüÉÃU‰åƒìƒ}xƒˆØƒŒØ}ÿ~!ƒì ÿuè¦óÿÿƒÄ‰EüƒØƒ”Øë!‹|Ö‹E‹„‚4‰Eüƒ˜ØƒœØ‹EüÉÉöU‰åƒìƒ Øƒ¤Øƒìÿu ÿuè&ƒÄ‰Eüƒ¨Øƒ¬Øƒ}ü•À¶À‰Eü‹EüÉÃU‰åƒìƒ}xƒ°Øƒ´Ø}ÿ~'ƒì ÿuè’óÿÿƒÄ‰Eü‹E !Eüƒ¸Øƒ¼Øë#‹ |Ö‹U‹E ‹T‘4!‰UüƒÀØƒÄØ‹EüÉÉöU‰åƒìƒ}xƒÈØƒÌØ}ÿ~!ƒì ÿuèôÿÿƒÄ‰EüƒÐØƒÔØë!‹|Ö‹E‹„‚4‰EüƒØØƒÜØ‹EüÉÉöU‰åƒìƒàØƒäØƒäð¸ƒÀƒÀÁèÁà)ÄèÍôÿÿƒèØƒìØ‰Eøƒì hè°èãñÿÿƒð؃ô؃ăì h-³èÅñÿÿƒÄÇEü}üÿÁƒøØƒüØ‹Eüƒà…Àu@ƒÙƒ Ùƒ}üt,ƒÙƒÙƒì h0³ègñÿÿƒÄƒÙƒÙƒì‹Eø¶PEøÿh4³è=ñÿÿƒÄ}üÿt,ƒ Ùƒ$Ùƒì h8³èñÿÿƒÄƒ(Ùƒ,ÙEüÿƒ0Ùƒ4Ùé2ÿÿÿƒÙƒÙƒì h:³èÒðÿÿƒ8Ùƒ<كăì h@³è´ðÿÿƒ@ÙƒDكăì h-³è–ðÿÿƒÄÇEü}üÿÁƒHÙƒLÙ‹Eüƒà…Àu@ƒXÙƒ\Ùƒ}üt,ƒ`ÙƒdÙƒì h0³è8ðÿÿƒÄƒhÙƒlÙƒì‹Eø¶PEøÿh4³èðÿÿƒÄ}üÿt,ƒpÙƒtÙƒì h8³èçïÿÿƒÄƒxÙƒ|ÙEüÿƒ€Ùƒ„Ùé2ÿÿÿƒPÙƒTÙƒì h:³è£ïÿÿƒˆÙƒŒÙƒÄƒì hp³è…ïÿÿƒÙƒ”كăì h-³ègïÿÿƒÄÇEü}ü?÷ƒ˜ÙƒœÙ‹Eüƒà…Àuvƒ¨Ùƒ¬Ùƒ}ütbƒ°Ùƒ´Ù‹Eüƒà…Àu,ƒ¸Ùƒ¼Ùƒì hª´èñîÿÿƒÄƒÀÙƒÄÙƒì h0³èÓîÿÿƒÄƒÈÙƒÌÙƒì‹Eø¶PEøÿh¬´è©îÿÿƒÄ}ü?t,ƒÐÙƒÔÙƒì h8³è‚îÿÿƒÄƒØÙƒÜÙEüÿƒàÙƒäÙéüþÿÿƒ Ùƒ¤Ùƒì h:³è>îÿÿƒèÙƒìكăìh€jjjjjh´´èîÿÿƒðÙƒôÙƒÄ ƒì h-³èóíÿÿƒÄÇEü}üÿçƒøÙƒüÙ‹Eüƒà…À…bƒÚƒ Úƒ}ü„JƒÚƒÚƒì hƵèíÿÿƒÚƒÚƒÄƒìh‹EüƒèPèúÿÿƒÄ…Àt5ƒ Úƒ$Úƒì‹EüƒèPh˵è?íÿÿƒÄƒ0Úƒ4Úë3ƒ(Úƒ,Úƒì‹EüƒèPhѵè íÿÿƒÄƒ8Úƒ<Úƒìh‹EüHPèùÿÿƒÄ…Àt3ƒ@ÚƒDÚƒì‹EüHPhÖµèÀìÿÿƒÄƒPÚƒTÚë1ƒHÚƒLÚƒì‹EüHPh4³èìÿÿƒÄƒXÚƒ\Úƒì hÛµèoìÿÿƒÄƒ`ÚƒdÚƒì‹Eø¶PEøÿh¬´èEìÿÿƒÄ}üÿt,ƒhÚƒlÚƒì h8³èìÿÿƒÄƒpÚƒtÚEüÿƒxÚƒ|Úé þÿÿƒÚƒÚƒì hâµèÚëÿÿƒ€Úƒ„ڃăìh‹EüƒèPè]øÿÿƒÄ…Àt5ƒˆÚƒŒÚƒì‹EüƒèPh˵èŒëÿÿƒÄƒ˜ÚƒœÚë3ƒÚƒ”Úƒì‹EüƒèPhѵèWëÿÿƒÄƒ Úƒ¤Úƒìh‹EüHPèÜ÷ÿÿƒÄ…Àt3ƒ¨Úƒ¬Úƒì‹EüHPhÖµè ëÿÿƒÄƒ¸Úƒ¼Úë1ƒ°Úƒ´Úƒì‹EüHPh4³èÚêÿÿƒÄƒÀÚƒÄÚƒì hèµè¼êÿÿƒÈÚƒÌڃĸÉÃU‰åƒì¸€Èƒì P讃ÄÉÃU‰åV‹u S‹]…ötè9SƒÃƒîuî[^]ÃU‰åVSìfÇEìfÇEîÇEØÇEÜÇEàÇEäèHêÿÿ‰Eè¡àÚ…À…ÇD$¶ÇD$ÇäÚ‹EÇìÚÇèÚÇðÚÿÿÿÿÇôÚ‰$è ëÿÿ‰Ã1À…Ûxyu؉t$ÇD$ ‰$èìéÿÿ…Àt èÃêÿÿƒ8.tÝÇD$4¶‰$èMêÿÿ…À£àÚtD…xÿÿÿ‰$‰D$èòéÿÿ…ÀxB¡àÚÇøÚÇD$‰$è¿êÿÿ¸Ä[^]É$èhéÿÿ1ÀÄ[^]áàÚ‰$è/êÿÿ1ÀÇàÚëÛè|éÿÿU‰åS‰Ãƒì¡àÚÇD$Ç$üÚ‰D$ ‰D$è+êÿÿºƒèDôÚäÚ)èÚ‰ôÚƒÄ[]ÃU‰åƒì‹àÚ…Òt/¡èÚ…Àt ‹ øÚ…Éx-‰$è™éÿÿÇàÚÇìÚ¡ôÚÇøÚÉÃèSÿÿÿ‹àÚëÆU‰åS‰Ãƒì‹èÚúÿw•üÚÚ‰èÚƒÄ[]øèÿÿÿ‹èÚ…Òtסüê£üÚ•üÚÚ‰èÚƒÄ[]ÃU¸‰åƒìè‘ÿÿÿ‹U‰ÉÃU¸‰åƒì‰$‰t$‹]‹u èmÿÿÿ‰p‰ƒÆ¸ÿÿÿÿ‹$‹t$OôÚ£ôÚ‰ì]ÃU¸‰åƒìè9ÿÿÿ‹U‰‹U ‰PÉÃU‰åVSƒì‹] ‹EÇD$ ‰$èÅÿÿÿ‹s‰$è`ÿÿÿ‹C‰$èUÿÿÿ‹F‰$èJÿÿÿ‹F‹V ‰$‰T$èOÿÿÿ‹F‹V‰$‰T$è=ÿÿÿ‹F‹V‰$‰T$è+ÿÿÿƒÄ[^]ÃU‰åS‰Ãƒì‹ ìÚ‹èÚ)Ñ9ÁsZäÚ…Éue¡àÚÇèÚ‰ ìÚ‰D$ üÚÇD$ÇD$‰$èxçÿÿÁèìÚ9Ør.£ìÚ‹èÚ£èÚ•üÚƒÄ[]Ë•üÚ£üÚë)Ã1ÀÇìÚðÚëÖU¸‰åƒìèBÿÿÿ1Ò…Àt‹‰ÐÉÃU¸‰åƒì‰]ô‰uø‰}üèÿÿÿ1Ò1É…Àt+‹01ÿ‹@‰Â‰û1À Ó‰ñ Á¸ÿÿÿÿƒûÿOôډʉ٣ôÚ‹]ô‹uø‹}ü‰ì‰Ð‰Ê]ÃU‰åƒì‰$‰t$‹]èrÿÿÿs‰èhÿÿÿ‰Cè`ÿÿÿ‰Fètÿÿÿ‰F‰V èiÿÿÿ‰F‰Vè^ÿÿÿ‰F‰V‹$‹t$‰ì]ÃU‰åSƒì¡èÚ‹]…Àu?ƒûÀƒà‰D$‰D$¡àÚ‰$èñåÿÿ¡àÚ‰$èDæÿÿÁø£äÚƒÄ[]Ãè%üÿÿëºU‰Á¸‰åƒì(úp403tW‰ÐˆUÿÆEø3ÁèÆEù0ÆEú4ˆEü‰ÐÆEûpÁèˆEý‰ÐÁèˆEþEü‰D$Eø‰D$ ‹A ÇD$ ¶‰D$¡ ʉ$èUåÿÿ1ÀÉÃUº 1À‰åWüV}ˆ‰ÑSìœó«}¸‹ÐډхÛó«‰Ôþÿÿ>ué‹Ôþÿÿ‹[…Û‰Ôþÿÿ„á‹…Ôþÿÿ‹•ÔþÿÿƒÀ‰…ÌþÿÿöBtÎM¸ƒÁ‰Ðþÿÿ‹BÇ…ÄþÿÿE¼‹B…À.tª‹EÌ‹UЋuÄ‹}ȉ…˜þÿÿ‰•œþÿÿ‹•Ìþÿÿ‹Äþÿÿ‹Ðþÿÿ‹B4È|ȉs‰{ ‹B‹•Äþÿÿ‹\Ћ Ð9œþÿÿ"|9˜þÿÿs‹…Ðþÿÿ‰˜þÿÿ‰œþÿÿ‰H‰Xƒ…Äþÿÿ‹Ìþÿÿ‹•Äþÿÿ9w‹Ôþÿÿ‹[…Û‰Ôþÿÿ…ÿÿÿ¡ÐÚ…À‰…Ôþÿÿ„º 1Àü‰Ñ½XÿÿÿÇ…¬þÿÿÇ…¨þÿÿó«‰Ñ½(ÿÿÿó«‹Ôþÿÿ‹…ÔþÿÿƒÃ‰Ìþÿÿ‹PöÂ…½1ÿÇ…Èþÿÿë ‹…Ôþÿÿ‹P¸¶ÈþÿÿÓà…Ât‹Ôþÿÿ8‹Dƒ ƒÇ‰„Øþÿÿƒ…Èþÿÿƒ½Èþÿÿv»<½‹•Ôþÿÿ‰½¸þÿÿ‹B ‰$è\øÿÿ…À…‹Ôþÿÿ‹A ÇD$8¶‰D$¡ ʉ$è"ãÿÿ‹Ôþÿÿ‹I‰Ôþÿÿ…É…ýþÿÿÄœ[^_]ÕXÿÿÿ‰ÁƒÂ‰•Ðþÿÿ‹@Ç…Äþÿÿ…\ÿÿÿ‹A…À„‹…lÿÿÿ‹•pÿÿÿ‹µdÿÿÿ‹½hÿÿÿ‰…˜þÿÿ‰•œþÿÿ‹•Ìþÿÿ‹Äþÿÿ‹Ðþÿÿ‹B4È|ȉs‰{ ‹•Ìþÿÿ‹B‹•Äþÿÿ‹\Ћ Ð9œþÿÿ"|9˜þÿÿs‹…Ðþÿÿ‰˜þÿÿ‰œþÿÿ‰H‰Xƒ…Äþÿÿ‹Ìþÿÿ‹•Äþÿÿ9w‡‹Ôþÿÿ‹Séiþÿÿè:ûÿÿ…Àt3=adcgtb‹Ôþÿÿ‹C ÇD$ض‰D$¡ ʉ$èôáÿÿè«øÿÿéÈþÿÿ‹ ðÚ…É„ƒ‹Ôþÿÿ‹•¬þÿÿ‹C …ÒºR¶‰D$¸ü¶I‰D$ë³èÈúÿÿ‰Â‹…Ôþÿÿèãûÿÿ…Àtªè²úÿÿ‰Á‹…Ôþÿÿ9H„Y‹=€Ö…ÿ…ö¡àÚ¿@ÇD$ÇD$‰$è)áÿÿ‹àÚÇøÚÿÿÿÿÇäÚÇèÚÇD$ÇD$‰$è-áÿÿ‹…¨þÿÿ…Àuü¹ ½øþÿÿ‹…¨þÿÿó«UˆM¸Ç…ÈþÿÿƒÂƒÁ‰•„þÿÿ‰€þÿÿ‹…Èþÿÿ•Xÿÿÿµ(ÿÿÿÁà½øþÿÿÂÆÇJ^¸‰°þÿÿ¶Èþÿÿ‰tþÿÿÓà‹Ôþÿÿ_…A„J‹tþÿÿ‹AƒÀ‰Aƒè„Ÿ‹B9F…­‹°þÿÿ‹A‹Q ‹tþÿÿAQ ‹…tþÿÿ‹°þÿÿ‹x‹Q‹p9׋AŒ¸9Æ‚°‹tþÿÿA‹CQƒÀ‰Cƒè„È‹€þÿÿ‹9…=‹€þÿÿ‹{‹s‹A‹Q CS ‹€þÿÿ‹Q‹A9×|9Æs‰C‰S‹€þÿÿ‹A‹QCS‹•„þÿÿ‹B…À„†‹uˆ…ö…´;C>…ª¹ ü‹µ„þÿÿ‰ßó¦>„“ÇD$ m¶‹Ôþÿÿ‹A ÇD$·‰D$¡ ʉ$èIßÿÿÇEˆÿÿÿÿë`‹F…À…|‹G…À…q‹•„þÿÿ‹B…À…zÿÿÿ‹{…ÿ„oÿÿÿ‹‰‹C‰B‹C‰B‹C ‰B ‹C‰B‹C‰B‹C‰B‹C‰Bƒ…€þÿÿ ƒ…„þÿÿ ƒ…Èþÿÿ.„çýÿÿ1ÿÇ…Èþÿÿ»1ö‰Ø¶Èþÿÿ‹•ÔþÿÿÓà…Bt‹Ôþÿÿ>ƒÇ‹D± ƒÆ‰„*Øþÿÿƒ…Èþÿÿƒ½ÈþÿÿvÀ¡ÔÚÇD$p403Ç$adcg‰…øþÿÿè"öÿÿ‹Ôþÿÿ‹C‰$è¹õÿÿÇ…´þÿÿ‹[…Û„ÝÇ…ˆþÿÿ‹…Ôþÿÿ‹•ˆþÿÿ1ÿPÇD$Ç$‰•¼þÿÿèÇõÿÿ‹¼þÿÿ‹‰$è_õÿÿ‹¼þÿÿ‹C‰$èNõÿÿÇ…ÈþÿÿÇ…”þÿÿ¡Ç…þÿÿÇ…Œþÿÿ¸¶Èþÿÿ‹ÔþÿÿÓà…C…¬ƒ…Èþÿÿ…”þÿÿƒ½ÈþÿÿvɃ…´þÿÿ‹¸þÿÿ‹Ôþÿÿˆþÿÿ‹…´þÿÿ9C‡-ÿÿÿ•(ÿÿÿÇ$¡øþÿÿ‰T$è õÿÿ‹¨þÿÿ‰ $è ÷ÿÿ‰\$Ç$£èõÿÿèÌóÿÿ…À„æùÿÿ‹•Ôþÿÿ‹B ºn¶‰D$¸h·M‰D$é¶ùÿÿ‹…¼þÿÿ‹•”þÿÿ‹t¸‰$6‰D$è–ôÿÿ‹…Œþÿÿø‹œ(Øþÿÿë‹‹SƒÃ‰$‰T$è0ôÿÿƒîƒþÿuä‹…þÿÿøƒÇ‰œ(Øþÿÿƒ…Œþÿÿƒ…þÿÿéãþÿÿ‹tþÿÿ‰A‰Q‹°þÿÿ‹A‹Q‹tþÿÿA‹CQƒÀ‰Cƒè…8üÿÿ‹•€þÿÿ‹‰é9üÿÿÇ…´þÿÿ‹•Ôþÿÿ‹r…ö…ð‹=èÚ=äÚèõÿÿ…À‰Ã.„úÿÿè õÿÿû£‰Á”Àƒù ¶ð…#…ö”Â1Àû¡•À…Â… …ö•(ÿÿÿ…øþÿÿD‰$è=õÿÿ‹àÚ…Ò¹E ôÚ…ɉ¬þÿÿ.…¬ùÿÿ…ö„lÿÿÿ¡ÔÚ9…øþÿÿ…[ÿÿÿ‰½¨þÿÿéúÿÿ‹àÚ¹…ÛE ôÚ…ɉ¬þÿÿ.…eùÿÿƒ…´þÿÿ‹Ôþÿÿ‹…´þÿÿ9C.†ÿÿÿ‹´þÿÿ‹Ôþÿÿ¯¸þÿÿ‰¼þÿÿ‹[Ù‰¼þÿÿèôÿÿ‰Ãè ôÿÿû•ƒø•À Ш…èïóÿÿ‹•¼þÿÿ;…èÜóÿÿ‹¼þÿÿ;A…ì1ÿÇ…ÈþÿÿÇ…|þÿÿ¡Ç…xþÿÿ¸¶Èþÿÿ‹ÔþÿÿÓà…Cu8ƒ…Èþÿÿ…|þÿÿƒ½Èþÿÿ.‡øþÿÿ¸¶Èþÿÿ‹ÔþÿÿÓà…CtÈ‹•xþÿÿ‹…¼þÿÿ‹T“$‹t¸‰• þÿÿè=óÿÿ‰Ãè6óÿÿ9|þÿÿ‰ÁuK69ÈuD‹xþÿÿ‰t$ûƒÇ‹„+Øþÿÿ‰$ÿ• þÿÿõ„+Øþÿÿƒ…xþÿÿéXÿÿÿ‹B‰Fébùÿÿƒ½´þÿÿÿ¸Š¶>u¸“¶‰D$ ‹Ôþÿÿ‹C ÇD$ˆ·‰D$¡ ʉ$èŽÙÿÿèEðÿÿéböÿÿ¡àÚ‰$ègÚÿÿéøÿÿU‰åWVSƒì ‹E‹…ÒuƒÄ [^_]Ãè”óÿÿ…ÀtW‹U‹r ‹ÔÚ¶>»‰ùÁá‰ÈƒëÉ1ÐÒÁø%·Á1ƒûÿuæ‰øƒÆ„ÀuСÐÚ‰ÔÚ…Àt‹U‰B‰ÐÚ‹EÇƒÄ [^_]ÃÇ${£è{Ùÿÿ¡ÐÚëÐU‰åWVSƒì èuóÿÿ‹=ÐÚ…ÿt"1Ûw¸‰ÙÓà…GuƒÃƒûuê‹…ÿuÞƒÄ [^_]Ë‹VÇD$Áà‰$ƒÆ ‰D$èÃØÿÿëÈU‰åS»ŒÉƒì¡ŒÉëƒëÿЋƒøÿuôƒÄ[]Ãì èôÙÿÿƒÄ Ã$FreeBSD: src/lib/csu/i386-elf/crti.S,v 1.7 2005/05/19 07:31:06 dfr Exp $*+?{^.$|()[/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This file is automatically written by the dftables auxiliary program. If you edit it by hand, you might like to edit the Makefile to prevent its ever being regenerated. This file is #included in the compilation of pcre.c to build the default character tables which are used when no tables are passed to the compile function. */ static unsigned char pcre_default_tables[] = { /* This table is a lower casing table. */ %3d,, /* This table is a case flipping table. */ /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, graph print, punct, and cntrl. Other classes are built from combinations. */ 0x%02x/* This table identifies various classes of character by individual bits: 0x%02x white space character 0x%02x letter 0x%02x decimal digit 0x%02x hexadecimal digit 0x%02x alphanumeric or '_' 0x%02x regular expression metacharacter or binary zero */ /* %c -%3d- %c */ };/* */ /* End of chartables.c */ /home/fk/test/privoxy/current/dftables.gcdar+bprofiling:%s:Cannot open profiling:%s:Error merging profiling:%s:Error writing functionsummariesprofiling:%s:Version mismatch - expected %.4s got %.4s profiling:%s:Not a gcov data file profiling:%s:Overflow merging profiling:%s:Invocation mismatch - some data files may have been removed%sprofiling:%s:Overflow writing profiling:%s:Merge mismatch for %s $FreeBSD: src/lib/csu/i386-elf/crtn.S,v 1.6 2005/05/19 07:31:06 dfr Exp $m¶˜É :ÔÛ‰9A˜×‘ucÐuÓ|>fþdvÈ=ßYh CA%>p403"]™¶ Ȇ Ö´‚ ˆ „°ì€ø„8‚ ®  ÉØ@‡ ‡ þÿÿo‡ÿÿÿoðÿÿo¦†ÿÿÿÿ˜ÿÿÿÿ¸ÈBˆRˆbˆrˆ‚ˆ’ˆ¢ˆ²ˆˆÒˆâˆòˆ‰‰"‰2‰B‰R‰b‰r‰‚‰’‰¢‰²‰‰Ò‰â‰$FreeBSD: src/lib/csu/common/crtbrand.c,v 1.4 2003/10/17 15:43:13 peter Exp $$FreeBSD: src/lib/csu/i386-elf/crt1.c,v 1.14 2005/05/19 07:36:07 dfr Exp $GCC: (GNU) 3.4.6 [FreeBSD] 20060305GCC: (GNU) 3.4.6 [FreeBSD] 20060305GCC: (GNU) 3.4.6 [FreeBSD] 20060305GCC: (GNU) 3.4.6 [FreeBSD] 20060305GCC: (GNU) 3.4.6 [FreeBSD] 20060305GCC: (GNU) 3.4.6 [FreeBSD] 20060305‹©+ pcre_maketableszmain±‹GNU C 3.4.6 [FreeBSD] 20060305pcre/dftables.c/home/fk/test/privoxy/currentsigned charunsigned charshort intshort unsigned intint__uint32_t8Âlong long intlong long unsigned intlong unsigned intdouble__size_t_°charlong int__ct_rune_tR©__rune_tS7¬9__min5J#__max6J#__map7J#__types8¬# ô_RuneEntry9aô>__nranges<©#__ranges=ô#²_RuneRange>Ä?T W__magicA?#__encodingBO#__sgetruneDŠ#(__sputruneE»#,__invalid_runeFJ#0__runetypeHÁ#4__maplowerIÑ#´__mapupperJÑ#´__runetype_extQú#´__maplower_extRú#¼__mapupper_extSú#Ä__variableUá#Ì__variable_lenV©#Ð O# Z _# Z yJ y  „ #y_ ¯© J ¯  µ#¯ Ñô Zÿ áJ Zÿ_RuneLocaleW u umpcre_maketables?ü‹”Uyield@ö‘tp@ö‘piA©‘lj’Í“xw©‘h¨__isctypeq©”w”U_cp7‘_fpô‘ Ö__toupperx7x”â”U_cw7‘__istypek©ä”,•U_cj7‘_fjô‘ L__maskruned©,•ž•U_cc7‘_fcô‘ z__tolower7 • –U_c~7‘´main6© –˜Ui7©‘|tables8ü‘x_DefaultRuneLocale[ã_CurrentRuneLocale\ìã_GLOBAL__I_pcre_maketables_GCOV’˜±U% $ > : ; I$ >  : ;  : ; I8  I : ; I !I/ ' I I &I .? : ; ' I@ 4: ; I  .: ; ' I@ : ; I 4: ; I? < .: ; @ ¿˜û pcre/usr/include/usr/include/sys/usr/include/machinemaketables.c_ctype.hdftables.c_types.hrunetype.h_types.h‹>\.âgMÀHÿ)EY)EY)KY_px~~~ipq‘ÿr8999?+wá q:o©:]=dbpG:2w+djGdb´G*W ÅðÿJª5 &ÇÇðÿJª5 &ÇÌðÿ,6Ǫx5 &Ç -ðÿ4Æ^%Z#Ǫt5&Æ^%Z#ÇV+cÿÿÿÿ| ˆ‹ûA…B Eƒ†V.”sA…B x”jA…B f.ä”HA…B Z.,•rA…B f. •jA…B f. –ŒA…B E.Ò. ^.˜A…B L.unsigned int.symtab.strtab.shstrtab.interp.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.data.eh_frame.dynamic.ctors.dtors.jcr.got.bss.comment.debug_aranges.debug_pubnames.debug_info.debug_abbrev.debug_line.debug_frame.debug_strÔ€Ô#ì€ìL) 8‚8À1ø„ø®9ÿÿÿo¦†¦XFþÿÿo‡ U  ‡  ^ @‡@Ø gˆb,ˆ,Àmì‰ì ˜&s„°„0 y°0fÈ8´ ‡´È´8‘¸È¸8КˆÉˆ9 ¡”É”9¨œÉœ9­ É 9x² Ê :à · :wÀ—; Ï·;/ßæ; ëBùCÃàDüÜE éE0Lp J  TåÔ€ì€8‚ø„¦†‡ ‡@‡ˆ ,ˆ ì‰ „° ° È´È¸ÈˆÉ”ÉœÉ É Ê ñÿñÿ)ñÿ8ñÿñÿCñÿNˆÉ\”Éj´È}œÉŠÈŽ„Öš€Š °ˆÖ¹ÅŠ CñÿÅÉÒ˜Éß´ÈíœÉù\° ñÿ)ñÿ8ñÿñÿ0ñÿ; •j Eä”H Nx”j X”s b,•r m˜ ñÿñÿ—0ŸX ¨åŸ_ ¹7¡® É £n Ö{£ß  àÐÚêÔÚõø¯c 6 oå¡ )¸Èñÿ2ÜT >E]Zào Êy"€ÈI—Z¯ž £Ú©ˆ ¯D  Å(ÊT ØàÚ ãØÚëñ1ùœ  ´% " :[ A OˆŸ] \Áb¢] vÈ쉒 ˆx”|Ö§ñ®„´€ÖÁÊñÿÍ´¢Y Ùà –Œ åï@õ ü„° i^¢V -+4¹ ~ Iy]ÀdÊñÿk Éñÿëñÿ†E‹>’i™‹û ©° Ä Úocrt1.c/usr/src/lib/csu/i386-elf/crti.Scrtstuff.c__CTOR_LIST____DTOR_LIST____EH_FRAME_BEGIN____JCR_LIST__p.0completed.1__do_global_dtors_auxobject.2frame_dummy__CTOR_END____DTOR_END____FRAME_END____JCR_END____do_global_ctors_aux/usr/src/lib/csu/i386-elf/crtn.Sdftables.c__tolower__istype__toupper__isctype__maskrune_GLOBAL__I_pcre_maketables_GCOVlibgcov.cgcov_write_blockgcov_write_wordsgcov_read_wordsgcov_versiongcov_exitgcov_listgcov_crc32__gcov_flushprintf___toupper__gcov_read_unsigned_DYNAMIC__gcov_opengetpidclose@@LIBTHREAD_1_0fcntl@@LIBTHREAD_1_0__stderrpmalloc__dso_handleftruncate__gcov_initabort_init__gcov_write_unsigned_DefaultRuneLocale__gcov_varenvironfstatfprintf__gcov_write_tag_length__gcov_merge_add__deregister_frame_info__gcov_write_counter__gcov_closefseek__gcov_read_counter__progname_start___runetype_CurrentRuneLocalefdopenfread__isthreaded__bss_start__gcov_seekmemsetmain_init_tlsftellfclose_fini__error@@LIBTHREAD_1_0__gcov_read_summaryatexit__gcov_write_summaryopen@@LIBTHREAD_1_0fwrite_edata_GLOBAL_OFFSET_TABLE__endexitsetbuffilenopcre_maketablesstrchr_Jv_RegisterClasses__register_frame_info___tolowerprivoxy-3.0.21-stable/./pcre/Makefile.in000640 001751 001751 00000017454 10546014100 016762 0ustar00fkfk000000 000000 # Makefile.in for PCRE (Perl-Compatible Regular Expression) library. #---------------------------------------------------------------------------# # To build mingw32 DLL uncomment the next two lines. This addition for # # mingw32 was contributed by . I (Philip # # Hazel) don't know anything about it! There are some additional targets at # # the bottom of this Makefile. # #---------------------------------------------------------------------------# # # include dll.mk # DLL_LDFLAGS=-s #---------------------------------------------------------------------------# # The next few lines are modified by "configure" to insert data that it is # # given in its arguments, or which it finds out for itself. # #---------------------------------------------------------------------------# # BINDIR is the directory in which the pcregrep command is installed. # INCDIR is the directory in which the public header file pcre.h is installed. # LIBDIR is the directory in which the libraries are installed. # MANDIR is the directory in which the man pages are installed. # The pcretest program, as it is a test program, does not get installed # anywhere. prefix = @prefix@ exec_prefix = @exec_prefix@ BINDIR = @bindir@ LIBDIR = @libdir@ INCDIR = @includedir@ MANDIR = @mandir@ CC = @CC@ CFLAGS = @CFLAGS@ RANLIB = @RANLIB@ UTF8 = @UTF8@ # LIBTOOL defaults to "./libtool", which enables the building of shared # libraries. If "configure" is called with --disable-shared-libraries, LIBTOOL # is set to "", which stops shared libraries from being built, and LIBSUFFIX # is set to "a" instead of "la", which causes the shared libraries not to be # installed. LIBTOOL = @LIBTOOL@ LIBSUFFIX = @LIBSUFFIX@ # These are the version numbers for the shared libraries PCRELIBVERSION = @PCRE_LIB_VERSION@ PCREPOSIXLIBVERSION = @PCRE_POSIXLIB_VERSION@ #---------------------------------------------------------------------------# # A copy of install-sh is in this distribution and is used by default. # #---------------------------------------------------------------------------# INSTALL = ./install-sh -c INSTALL_DATA = ${INSTALL} -m 644 #---------------------------------------------------------------------------# # For almost all systems, the command to create a library is "ar cq", but # # there is at least one where it is different, so this command must be # # configurable. However, I haven't got round to learning how to make # # "configure" find this out for itself. It is necessary to use a command # # such as "make AR='ar -rc'" if you need to vary this. The setting of AR is # # *not* passed over to ./ltconfig, because it does its own setting up. # #---------------------------------------------------------------------------# AR = ar cq ############################################################################## OBJ = maketables.o get.o study.o pcre.o LOBJ = maketables.lo get.lo study.lo pcre.lo all: libtool libpcre.$(LIBSUFFIX) libpcreposix.$(LIBSUFFIX) pcretest pcregrep libtool: config.guess config.sub ltconfig ltmain.sh @if test "$(LIBTOOL)" = "./libtool"; then \ echo '--- Building libtool ---'; \ CC=$(CC) CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)' ./ltconfig ./ltmain.sh; \ echo '--- Built libtool ---'; fi pcregrep: libpcre.$(LIBSUFFIX) pcregrep.o @echo ' ' @echo '--- Building pcregrep utility' @echo ' ' $(LIBTOOL) $(CC) $(CFLAGS) -o pcregrep pcregrep.o libpcre.$(LIBSUFFIX) pcretest: libpcre.$(LIBSUFFIX) libpcreposix.$(LIBSUFFIX) pcretest.o @echo ' ' @echo '--- Building pcretest testing program' @echo ' ' $(LIBTOOL) $(PURIFY) $(CC) $(CFLAGS) -o pcretest pcretest.o \ libpcre.$(LIBSUFFIX) libpcreposix.$(LIBSUFFIX) libpcre.a: $(OBJ) @echo ' ' @echo '--- Building static library: libpcre' @echo ' ' -rm -f libpcre.a $(AR) libpcre.a $(OBJ) $(RANLIB) libpcre.a libpcre.la: $(OBJ) @echo ' ' @echo '--- Building shared library: libpcre' @echo ' ' -rm -f libpcre.la ./libtool $(CC) -version-info '$(PCRELIBVERSION)' -o libpcre.la -rpath $(LIBDIR) $(LOBJ) libpcreposix.a: pcreposix.o @echo ' ' @echo '--- Building static library: libpcreposix' @echo ' ' -rm -f libpcreposix.a $(AR) libpcreposix.a pcreposix.o $(RANLIB) libpcreposix.a libpcreposix.la: pcreposix.o @echo ' ' @echo '--- Building shared library: libpcreposix' @echo ' ' -rm -f libpcreposix.la ./libtool $(CC) -version-info '$(PCREPOSIXLIBVERSION)' -o libpcreposix.la -rpath $(LIBDIR) pcreposix.lo pcre.o: chartables.c pcre.c pcre.h internal.h config.h Makefile $(LIBTOOL) $(CC) -c $(CFLAGS) $(UTF8) pcre.c pcreposix.o: pcreposix.c pcreposix.h internal.h pcre.h config.h Makefile $(LIBTOOL) $(CC) -c $(CFLAGS) pcreposix.c maketables.o: maketables.c pcre.h internal.h config.h Makefile $(LIBTOOL) $(CC) -c $(CFLAGS) maketables.c get.o: get.c pcre.h internal.h config.h Makefile $(LIBTOOL) $(CC) -c $(CFLAGS) get.c study.o: study.c pcre.h internal.h config.h Makefile $(LIBTOOL) $(CC) -c $(CFLAGS) $(UTF8) study.c pcretest.o: pcretest.c pcre.h config.h Makefile $(CC) -c $(CFLAGS) $(UTF8) pcretest.c pcregrep.o: pcregrep.c pcre.h Makefile config.h $(CC) -c $(CFLAGS) $(UTF8) pcregrep.c # An auxiliary program makes the default character table source chartables.c: dftables ./dftables >chartables.c dftables: dftables.c maketables.c pcre.h internal.h config.h Makefile $(CC) -o dftables $(CFLAGS) dftables.c install: all $(LIBTOOL) $(INSTALL_DATA) libpcre.$(LIBSUFFIX) $(DESTDIR)/$(LIBDIR)/libpcre.$(LIBSUFFIX) $(LIBTOOL) $(INSTALL_DATA) libpcreposix.$(LIBSUFFIX) $(DESTDIR)/$(LIBDIR)/libpcreposix.$(LIBSUFFIX) $(INSTALL_DATA) pcre.h $(DESTDIR)/$(INCDIR)/pcre.h $(INSTALL_DATA) pcreposix.h $(DESTDIR)/$(INCDIR)/pcreposix.h $(INSTALL_DATA) doc/pcre.3 $(DESTDIR)/$(MANDIR)/man3/pcre.3 $(INSTALL_DATA) doc/pcreposix.3 $(DESTDIR)/$(MANDIR)/man3/pcreposix.3 $(INSTALL_DATA) doc/pcregrep.1 $(DESTDIR)/$(MANDIR)/man1/pcregrep.1 @if test "$(LIBTOOL)" = "./libtool"; then \ echo ' '; \ echo '--- Rebuilding pcregrep to use installed shared library ---'; \ echo $(CC) $(CFLAGS) -o pcregrep pcregrep.o -L$(DESTDIR)/$(LIBDIR) -lpcre; \ $(CC) $(CFLAGS) -o pcregrep pcregrep.o -L$(DESTDIR)/$(LIBDIR) -lpcre; \ echo '--- Rebuilding pcretest to use installed shared library ---'; \ echo $(CC) $(CFLAGS) -o pcretest pcretest.o -L$(DESTDIR)/$(LIBDIR) -lpcre -lpcreposix; \ $(CC) $(CFLAGS) -o pcretest pcretest.o -L$(DESTDIR)/$(LIBDIR) -lpcre -lpcreposix; \ fi $(INSTALL) pcregrep $(DESTDIR)/$(BINDIR)/pcregrep $(INSTALL) pcre-config $(DESTDIR)/$(BINDIR)/pcre-config # We deliberately omit dftables and chartables.c from 'make clean'; once made # chartables.c shouldn't change, and if people have edited the tables by hand, # you don't want to throw them away. clean:; -rm -rf *.o *.lo *.a *.la .libs pcretest pcregrep testtry # But "make distclean" should get back to a virgin distribution distclean: clean -rm -f chartables.c libtool pcre-config pcre.h \ Makefile config.h config.status config.log config.cache check: runtest test: runtest runtest: all ./RunTest ######## MINGW32 ############### MINGW32 ############### MINGW32 ############# # This addition for mingw32 was contributed by Paul Sokolovsky # . I (PH) don't know anything about it! dll: _dll libpcre.dll.a pcregrep_d pcretest_d _dll: $(MAKE) CFLAGS=-DSTATIC pcre.dll pcre.dll: $(OBJ) pcreposix.o pcre.def libpcre.dll.a: pcre.def pcregrep_d: libpcre.dll.a pcregrep.o $(CC) $(CFLAGS) -L. -o pcregrep pcregrep.o -lpcre.dll pcretest_d: libpcre.dll.a pcretest.o $(PURIFY) $(CC) $(CFLAGS) -L. -o pcretest pcretest.o -lpcre.dll # End privoxy-3.0.21-stable/./pcre/chartables.c000640 001751 001751 00000015555 10546014100 017171 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This file is automatically written by the dftables auxiliary program. If you edit it by hand, you might like to edit the Makefile to prevent its ever being regenerated. This file is #included in the compilation of pcre.c to build the default character tables which are used when no tables are passed to the compile function. */ static unsigned char pcre_default_tables[] = { /* This table is a lower casing table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table is a case flipping table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, graph print, punct, and cntrl. Other classes are built from combinations. */ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* This table identifies various classes of character by individual bits: 0x01 white space character 0x02 letter 0x04 decimal digit 0x08 hexadecimal digit 0x10 alphanumeric or '_' 0x80 regular expression metacharacter or binary zero */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ /* End of chartables.c */ privoxy-3.0.21-stable/./pcre/ltconfig000640 001751 001751 00000274326 10546014100 016450 0ustar00fkfk000000 000000 #! /bin/sh # ltconfig - Create a system-specific libtool. # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A lot of this script is taken from autoconf-2.10. # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} echo=echo if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell. exec "$SHELL" "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null`} case X$UNAME in *-DOS) PATH_SEPARATOR=';' ;; *) PATH_SEPARATOR=':' ;; esac fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if (echo_test_string="`eval $cmd`") 2>/dev/null && echo_test_string="`eval $cmd`" && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then break fi done fi if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH /usr/ucb; do if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then echo="$dir/echo" break fi done IFS="$save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running ltconfig again with it. ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} else # Try using printf. echo='printf "%s\n"' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then # Cool, printf works : elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL $0 --fallback-echo" elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then echo="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e s/^X//' sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # The name of this program. progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` # Constants: PROGRAM=ltconfig PACKAGE=libtool VERSION=1.3.4 TIMESTAMP=" (1.385.2.196 1999/12/07 21:47:57)" ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' rm="rm -f" help="Try \`$progname --help' for more information." # Global variables: default_ofile=libtool can_build_shared=yes enable_shared=yes # All known linkers require a `.a' archive for static linking (except M$VC, # which needs '.lib'). enable_static=yes enable_fast_install=yes enable_dlopen=unknown enable_win32_dll=no ltmain= silent= srcdir= ac_config_guess= ac_config_sub= host= nonopt= ofile="$default_ofile" verify_host=yes with_gcc=no with_gnu_ld=no need_locks=yes ac_ext=c objext=o libext=a exeext= cache_file= old_AR="$AR" old_CC="$CC" old_CFLAGS="$CFLAGS" old_CPPFLAGS="$CPPFLAGS" old_LDFLAGS="$LDFLAGS" old_LD="$LD" old_LN_S="$LN_S" old_LIBS="$LIBS" old_NM="$NM" old_RANLIB="$RANLIB" old_DLLTOOL="$DLLTOOL" old_OBJDUMP="$OBJDUMP" old_AS="$AS" # Parse the command line options. args= prev= for option do case "$option" in -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then eval "$prev=\$option" prev= continue fi case "$option" in --help) cat <&2 echo "$help" 1>&2 exit 1 ;; *) if test -z "$ltmain"; then ltmain="$option" elif test -z "$host"; then # This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 # if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then # echo "$progname: warning \`$option' is not a valid host type" 1>&2 # fi host="$option" else echo "$progname: too many arguments" 1>&2 echo "$help" 1>&2 exit 1 fi ;; esac done if test -z "$ltmain"; then echo "$progname: you must specify a LTMAIN file" 1>&2 echo "$help" 1>&2 exit 1 fi if test ! -f "$ltmain"; then echo "$progname: \`$ltmain' does not exist" 1>&2 echo "$help" 1>&2 exit 1 fi # Quote any args containing shell metacharacters. ltconfig_args= for arg do case "$arg" in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ltconfig_args="$ltconfig_args '$arg'" ;; *) ltconfig_args="$ltconfig_args $arg" ;; esac done # A relevant subset of AC_INIT. # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 5 compiler messages saved in config.log # 6 checking for... messages and results if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>>./config.log # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "X${LC_ALL+set}" = Xset; then LC_ALL=C; export LC_ALL; fi if test "X${LANG+set}" = Xset; then LANG=C; export LANG; fi if test -n "$cache_file" && test -r "$cache_file"; then echo "loading cache $cache_file within ltconfig" . $cache_file fi if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi if test -z "$srcdir"; then # Assume the source directory is the same one as the path to LTMAIN. srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` test "$srcdir" = "$ltmain" && srcdir=. fi trap "$rm conftest*; exit 1" 1 2 15 if test "$verify_host" = yes; then # Check for config.guess and config.sub. ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/config.guess; then ac_aux_dir=$ac_dir break fi done if test -z "$ac_aux_dir"; then echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 echo "$help" 1>&2 exit 1 fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub # Make sure we can run config.sub. if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : else echo "$progname: cannot run $ac_config_sub" 1>&2 echo "$help" 1>&2 exit 1 fi echo $ac_n "checking host system type""... $ac_c" 1>&6 host_alias=$host case "$host_alias" in "") if host_alias=`$SHELL $ac_config_guess`; then : else echo "$progname: cannot guess host type; you must specify one" 1>&2 echo "$help" 1>&2 exit 1 fi ;; esac host=`$SHELL $ac_config_sub $host_alias` echo "$ac_t$host" 1>&6 # Make sure the host verified. test -z "$host" && exit 1 elif test -z "$host"; then echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 echo "$help" 1>&2 exit 1 else host_alias=$host fi # Transform linux* to *-*-linux-gnu*, to support old configure scripts. case "$host_os" in linux-gnu*) ;; linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` esac host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` case "$host_os" in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Determine commands to create old-style static archives. old_archive_cmds='$AR cru $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= # Set a sane default for `AR'. test -z "$AR" && AR=ar # Set a sane default for `OBJDUMP'. test -z "$OBJDUMP" && OBJDUMP=objdump # If RANLIB is not set, then run the test. if test "${RANLIB+set}" != "set"; then result=no echo $ac_n "checking for ranlib... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then RANLIB="ranlib" result="ranlib" break fi done IFS="$save_ifs" echo "$ac_t$result" 1>&6 fi if test -n "$RANLIB"; then old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" fi # Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin. test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$AS" && AS=as # Check to see if we are using GCC. if test "$with_gcc" != yes || test -z "$CC"; then # If CC is not set, then try to find GCC or a usable CC. if test -z "$CC"; then echo $ac_n "checking for gcc... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then CC="gcc" break fi done IFS="$save_ifs" if test -n "$CC"; then echo "$ac_t$CC" 1>&6 else echo "$ac_t"no 1>&6 fi fi # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". if test -z "$CC"; then echo $ac_n "checking for cc... $ac_c" 1>&6 IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" cc_rejected=no for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/cc || test -f $dir/cc$ac_exeext; then if test "$dir/cc" = "/usr/ucb/cc"; then cc_rejected=yes continue fi CC="cc" break fi done IFS="$save_ifs" if test $cc_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same name, so the bogon will be chosen # first if we set CC to just the name; use the full file name. shift set dummy "$dir/cc" "$@" shift CC="$@" fi fi if test -n "$CC"; then echo "$ac_t$CC" 1>&6 else echo "$ac_t"no 1>&6 fi if test -z "$CC"; then echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 exit 1 fi fi # Now see if the compiler is really GCC. with_gcc=no echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 echo "$progname:581: checking whether we are using GNU C" >&5 $rm conftest.c cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then with_gcc=yes fi $rm conftest.c echo "$ac_t$with_gcc" 1>&6 fi # Allow CC to be a program name with arguments. set dummy $CC compiler="$2" echo $ac_n "checking for object suffix... $ac_c" 1>&6 $rm conftest* echo 'int i = 1;' > conftest.c echo "$progname:603: checking for object suffix" >& 5 if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then # Append any warnings to the config.log. cat conftest.err 1>&5 for ac_file in conftest.*; do case $ac_file in *.c) ;; *) objext=`echo $ac_file | sed -e s/conftest.//` ;; esac done else cat conftest.err 1>&5 echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi $rm conftest* echo "$ac_t$objext" 1>&6 echo $ac_n "checking for executable suffix... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_exeext="no" $rm conftest* echo 'main () { return 0; }' > conftest.c echo "$progname:629: checking for executable suffix" >& 5 if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then # Append any warnings to the config.log. cat conftest.err 1>&5 for ac_file in conftest.*; do case $ac_file in *.c | *.err | *.$objext ) ;; *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;; esac done else cat conftest.err 1>&5 echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi $rm conftest* fi if test "X$ac_cv_exeext" = Xno; then exeext="" else exeext="$ac_cv_exeext" fi echo "$ac_t$ac_cv_exeext" 1>&6 echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 pic_flag= special_shlib_compile_flags= wl= link_static_flag= no_builtin_flag= if test "$with_gcc" = yes; then wl='-Wl,' link_static_flag='-static' case "$host_os" in beos* | irix5* | irix6* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; aix*) # Below there is a dirty hack to force normal static linking with -ldl # The problem is because libdl dynamically linked with both libc and # libC (AIX C++ library), which obviously doesn't included in libraries # list by gcc. This cause undefined symbols with -static flags. # This hack allows C programs to be linked with "-static -ldl", but # we not sure about C++ programs. link_static_flag="$link_static_flag ${wl}-lC" ;; cygwin* | mingw* | os2*) # We can build DLLs from non-PIC. ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. pic_flag='-m68020 -resident32 -malways-restore-a4' ;; sysv4*MP*) if test -d /usr/nec; then pic_flag=-Kconform_pic fi ;; *) pic_flag='-fPIC' ;; esac else # PORTME Check for PIC flags for the system compiler. case "$host_os" in aix3* | aix4*) # All AIX code is PIC. link_static_flag='-bnso -bI:/lib/syscalls.exp' ;; hpux9* | hpux10* | hpux11*) # Is there a better link_static_flag that works with the bundled CC? wl='-Wl,' link_static_flag="${wl}-a ${wl}archive" pic_flag='+Z' ;; irix5* | irix6*) wl='-Wl,' link_static_flag='-non_shared' # PIC (with -KPIC) is the default. ;; cygwin* | mingw* | os2*) # We can build DLLs from non-PIC. ;; osf3* | osf4* | osf5*) # All OSF/1 code is PIC. wl='-Wl,' link_static_flag='-non_shared' ;; sco3.2v5*) pic_flag='-Kpic' link_static_flag='-dn' special_shlib_compile_flags='-belf' ;; solaris*) pic_flag='-KPIC' link_static_flag='-Bstatic' wl='-Wl,' ;; sunos4*) pic_flag='-PIC' link_static_flag='-Bstatic' wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) pic_flag='-KPIC' link_static_flag='-Bstatic' wl='-Wl,' ;; uts4*) pic_flag='-pic' link_static_flag='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then pic_flag='-Kconform_pic' link_static_flag='-Bstatic' fi ;; *) can_build_shared=no ;; esac fi if test -n "$pic_flag"; then echo "$ac_t$pic_flag" 1>&6 # Check to make sure the pic_flag actually works. echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $pic_flag -DPIC" echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5 if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then # Append any warnings to the config.log. cat conftest.err 1>&5 case "$host_os" in hpux9* | hpux10* | hpux11*) # On HP-UX, both CC and GCC only warn that PIC is supported... then they # create non-PIC objects. So, if there were any warnings, we assume that # PIC is not supported. if test -s conftest.err; then echo "$ac_t"no 1>&6 can_build_shared=no pic_flag= else echo "$ac_t"yes 1>&6 pic_flag=" $pic_flag" fi ;; *) echo "$ac_t"yes 1>&6 pic_flag=" $pic_flag" ;; esac else # Append any errors to the config.log. cat conftest.err 1>&5 can_build_shared=no pic_flag= echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* else echo "$ac_t"none 1>&6 fi # Check to see if options -o and -c are simultaneously supported by compiler echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 $rm -r conftest 2>/dev/null mkdir conftest cd conftest $rm conftest* echo "int some_variable = 0;" > conftest.c mkdir out # According to Tom Tromey, Ian Lance Taylor reported there are C compilers # that will create temporary files in the current directory regardless of # the output directory. Thus, making CWD read-only will cause this test # to fail, enabling locking or at least warning the user not to do parallel # builds. chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.o" echo "$progname:829: checking if $compiler supports -c -o file.o" >&5 if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then echo "$ac_t"no 1>&6 compiler_c_o=no else echo "$ac_t"yes 1>&6 compiler_c_o=yes fi else # Append any errors to the config.log. cat out/conftest.err 1>&5 compiler_c_o=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" chmod u+w . $rm conftest* out/* rmdir out cd .. rmdir conftest $rm -r conftest 2>/dev/null if test x"$compiler_c_o" = x"yes"; then # Check to see if we can write to a .lo echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -c -o conftest.lo" echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5 if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then echo "$ac_t"no 1>&6 compiler_o_lo=no else echo "$ac_t"yes 1>&6 compiler_o_lo=yes fi else # Append any errors to the config.log. cat conftest.err 1>&5 compiler_o_lo=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* else compiler_o_lo=no fi # Check to see if we can do hard links to lock some files if needed hard_links="nottested" if test "$compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no echo "$ac_t$hard_links" 1>&6 $rm conftest* if test "$hard_links" = no; then echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 need_locks=warn fi else need_locks=no fi if test "$with_gcc" = yes; then # Check to see if options -fno-rtti -fno-exceptions are supported by compiler echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 $rm conftest* echo "int some_variable = 0;" > conftest.c save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then echo "$ac_t"no 1>&6 compiler_rtti_exceptions=no else echo "$ac_t"yes 1>&6 compiler_rtti_exceptions=yes fi else # Append any errors to the config.log. cat conftest.err 1>&5 compiler_rtti_exceptions=no echo "$ac_t"no 1>&6 fi CFLAGS="$save_CFLAGS" $rm conftest* if test "$compiler_rtti_exceptions" = "yes"; then no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' else no_builtin_flag=' -fno-builtin' fi fi # Check for any special shared library compilation flags. if test -n "$special_shlib_compile_flags"; then echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : else echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 can_build_shared=no fi fi echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 $rm conftest* echo 'main(){return(0);}' > conftest.c save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $link_static_flag" echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5 if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then echo "$ac_t$link_static_flag" 1>&6 else echo "$ac_t"none 1>&6 link_static_flag= fi LDFLAGS="$save_LDFLAGS" $rm conftest* if test -z "$LN_S"; then # Check to see if we can use ln -s, or we need hard links. echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 $rm conftest.dat if ln -s X conftest.dat 2>/dev/null; then $rm conftest.dat LN_S="ln -s" else LN_S=ln fi if test "$LN_S" = "ln -s"; then echo "$ac_t"yes 1>&6 else echo "$ac_t"no 1>&6 fi fi # Make sure LD is an absolute path. if test -z "$LD"; then ac_prog=ld if test "$with_gcc" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 echo "$progname:991: checking for ld used by GCC" >&5 ac_prog=`($CC -print-prog-name=ld) 2>&5` case "$ac_prog" in # Accept absolute paths. [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we are not using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld... $ac_c" 1>&6 echo "$progname:1015: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 echo "$progname:1018: checking for non-GNU ld" >&5 fi if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" fi if test -n "$LD"; then echo "$ac_t$LD" 1>&6 else echo "$ac_t"no 1>&6 fi if test -z "$LD"; then echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 exit 1 fi fi # Check to see if it really is or is not GNU ld. echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 # I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then with_gnu_ld=yes else with_gnu_ld=no fi echo "$ac_t$with_gnu_ld" 1>&6 # See if the linker supports building shared libraries. echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 allow_undefined_flag= no_undefined_flag= need_lib_prefix=unknown need_version=unknown # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments archive_cmds= archive_expsym_cmds= old_archive_from_new_cmds= export_dynamic_flag_spec= whole_archive_flag_spec= thread_safe_flag_spec= hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=unsupported runpath_var= always_export_symbols=no export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an egrep regular expression of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. case "$host_os" in cygwin* | mingw*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$with_gcc" != yes; then with_gnu_ld=no fi ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # See if GNU ld supports shared libraries. case "$host_os" in aix3* | aix4*) # On AIX, the GNU linker is very broken ld_shlibs=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF ;; amigaos*) archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=yes # Extract the symbol export list from an `--export-all' def file, # then regenerate the def file from the symbol export list, so that # the compiled dll only exports the symbol export list. export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~ sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols' archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ _lt_hint=1; for symbol in `cat $export_symbols`; do echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def; _lt_hint=`expr 1 + \$_lt_hint`; done~ test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib' # can we support soname and/or expsyms with a.out? -oliva fi ;; solaris* | sysv5*) if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = yes; then runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' case $host_os in cygwin* | mingw*) # dlltool doesn't understand --whole-archive et. al. whole_archive_flag_spec= ;; *) # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi ;; esac fi else # PORTME fill in a description of your system's linker (not GNU ld) case "$host_os" in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$with_gcc" = yes && test -z "$link_static_flag"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4*) hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib' hardcode_libdir_separator=':' if test "$with_gcc" = yes; then collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi shared_flag='-shared' else shared_flag='${wl}-bM:SRE' hardcode_direct=yes fi allow_undefined_flag=' ${wl}-berok' archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}' archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}' case "$host_os" in aix4.[01]|aix4.[01].*) # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on always_export_symbols=yes ;; esac ;; amigaos*) archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; cygwin* | mingw*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib /OUT:$oldlib$oldobjs' fix_srcfile_path='`cygpath -w $srcfile`' ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd*) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9* | hpux10* | hpux11*) case "$host_os" in hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;; *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;; esac hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_minus_L=yes # Not in the search PATH, but as the default # location of the library. export_dynamic_flag_spec='${wl}-E' ;; irix5* | irix6*) if test "$with_gcc" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF fi hardcode_libdir_flag_spec='${wl}-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; openbsd*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' ;; osf3*) if test "$with_gcc" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # As osf3* with the addition of the -msym flag if test "$with_gcc" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; sco3.2v5*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ;; solaris*) no_undefined_flag=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case "$host_os" in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv5*) no_undefined_flag=' -z text' # $CC -shared without GNU ld will not create a library from C++ # object files and a static libstdc++, better avoid it by now archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' hardcode_libdir_flag_spec= hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4.2uw2*) archive_cmds='$LD -G -o $lib $libobjs $deplibs $linkopts' hardcode_direct=yes hardcode_minus_L=no hardcode_shlibpath_var=no hardcode_runpath_var=yes runpath_var=LD_RUN_PATH ;; unixware7*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac fi echo "$ac_t$ld_shlibs" 1>&6 test "$ld_shlibs" = no && can_build_shared=no if test -z "$NM"; then echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 case "$NM" in [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path. *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then NM="$ac_dir/nm -B" break elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then NM="$ac_dir/nm -p" break else NM=${NM="$ac_dir/nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags fi fi done IFS="$ac_save_ifs" test -z "$NM" && NM=nm ;; esac echo "$ac_t$NM" 1>&6 fi # Check for command to grab the raw symbol name followed by C symbol from nm. echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Transform the above into a raw symbol and a C symbol. symxfrm='\1 \2\3 \3' # Transform an extracted symbol line into a proper C declaration global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" # Define system-specific variables. case "$host_os" in aix*) symcode='[BCDT]' ;; cygwin* | mingw*) symcode='[ABCDGISTW]' ;; hpux*) # Its linker distinguishes data from code symbols global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" ;; irix*) symcode='[BCDEGRST]' ;; solaris*) symcode='[BDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then symcode='[ABCDGISTW]' fi # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Write the raw and C identifiers. global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no $rm conftest* cat > conftest.c <&5 if { (eval echo $progname:1636: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then # Now try to grab the symbols. nlist=conftest.nm if { echo "$progname:1639: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if egrep ' nm_test_var$' "$nlist" >/dev/null; then if egrep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.c #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' cat <> conftest.c #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = { EOF sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c cat <<\EOF >> conftest.c {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$objext conftstm.$objext save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="conftstm.$objext" CFLAGS="$CFLAGS$no_builtin_flag" if { (eval echo $progname:1691: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then pipe_works=yes else echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi LIBS="$save_LIBS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.c >&5 fi $rm conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else global_symbol_pipe= fi done if test "$pipe_works" = yes; then echo "${ac_t}ok" 1>&6 else echo "${ac_t}failed" 1>&6 fi if test -z "$global_symbol_pipe"; then global_symbol_to_cdecl= fi # Check hardcoding attributes. echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var"; then # We can hardcode non-existant directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$hardcode_shlibpath_var" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi echo "$ac_t$hardcode_action" 1>&6 reload_flag= reload_cmds='$LD$reload_flag -o $output$reload_objs' echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 # PORTME Some linkers may need a different reload flag. reload_flag='-r' echo "$ac_t$reload_flag" 1>&6 test -n "$reload_flag" && reload_flag=" $reload_flag" # PORTME Fill in your ld.so characteristics library_names_spec= libname_spec='lib$name' soname_spec= postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" file_magic_cmd= file_magic_test_file= deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [regex]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given egrep regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 case "$host_os" in aix3*) version_type=linux library_names_spec='${libname}${release}.so$versuffix $libname.a' shlibpath_var=LIBPATH # AIX has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}.so$major' ;; aix4*) version_type=linux # AIX has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. # We preserve .a as extension for shared libraries though AIX4.2 # and later linker supports .so library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' shlibpath_var=LIBPATH deplibs_check_method=pass_all ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' ;; beos*) library_names_spec='${libname}.so' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH deplibs_check_method=pass_all lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; bsdi4*) version_type=linux need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' file_magic_cmd=/usr/bin/file file_magic_test_file=/shlib/libc.so sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" export_dynamic_flag_spec=-rdynamic # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw*) version_type=windows need_version=no need_lib_prefix=no if test "$with_gcc" = yes; then library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' else library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' fi dynamic_linker='Win32 ld.exe' deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' file_magic_cmd='${OBJDUMP} -f' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; freebsd1*) dynamic_linker=no ;; freebsd*) objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` version_type=freebsd-$objformat case "$version_type" in freebsd-elf*) deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /usr/lib/libc.so*` library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' need_version=no need_lib_prefix=no ;; freebsd-*) deplibs_check_method=unknown library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case "$host_os" in freebsd2* | freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes ;; *) # from 3.2 on shlibpath_overrides_runpath=no ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. dynamic_linker="$host_os dld.sl" version_type=sunos need_lib_prefix=no need_version=no shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' soname_spec='${libname}${release}.sl$major' # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; irix5* | irix6*) version_type=irix need_lib_prefix=no need_version=no soname_spec='${libname}${release}.so.$major' library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so' case "$host_os" in irix5*) libsuff= shlibsuff= # this will be overridden with pass_all, but let us keep it just in case deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" ;; *) case "$LD" in # libtool.m4 will add one of these switches to LD *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /lib${libsuff}/libc.so*` deplibs_check_method='pass_all' ;; # No shared lib support for Linux oldld, aout, or coff. linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) dynamic_linker=no ;; # This must be Linux ELF. linux-gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` if test -f /lib/ld.so.1; then dynamic_linker='GNU ld.so' else # Only the GNU ld.so supports shared libraries on MkLinux. case "$host_cpu" in powerpc*) dynamic_linker=no ;; *) dynamic_linker='Linux ld.so' ;; esac fi ;; netbsd*) version_type=sunos if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' soname_spec='${libname}${release}.so$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH ;; openbsd*) version_type=sunos if test "$with_gnu_ld" = yes; then need_lib_prefix=no need_version=no fi library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH ;; os2*) libname_spec='$name' need_lib_prefix=no library_names_spec='$libname.dll $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_version=no soname_spec='${libname}${release}.so' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' shlibpath_var=LD_LIBRARY_PATH # this will be overridden with pass_all, but let us keep it just in case deplibs_check_method='file_magic COFF format alpha shared library' file_magic_cmd=/usr/bin/file file_magic_test_file=/shlib/libc.so deplibs_check_method='pass_all' sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; sco3.2v5*) version_type=osf soname_spec='${libname}${release}.so$major' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' shlibpath_var=LD_LIBRARY_PATH ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" file_magic_cmd=/usr/bin/file file_magic_test_file=/lib/libc.so ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) version_type=linux library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH case "$host_vendor" in ncr) deplibs_check_method='pass_all' ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' file_magic_cmd=/usr/bin/file file_magic_test_file=`echo /usr/lib/libc.so*` ;; esac ;; uts4*) version_type=linux library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' soname_spec='${libname}${release}.so$major' shlibpath_var=LD_LIBRARY_PATH ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' soname_spec='$libname.so.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; *) dynamic_linker=no ;; esac echo "$ac_t$dynamic_linker" 1>&6 test "$dynamic_linker" = no && can_build_shared=no # Report the final consequences. echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 # Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in # configure.in, otherwise build static only libraries. case "$host_os" in cygwin* | mingw* | os2*) if test x$can_build_shared = xyes; then test x$enable_win32_dll = xno && can_build_shared=no echo "checking if package supports dlls... $can_build_shared" 1>&6 fi ;; esac if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then case "$deplibs_check_method" in "file_magic "*) file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | egrep "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case "$host_os" in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4*) test "$enable_shared" = yes && enable_static=no ;; esac echo "$ac_t$enable_shared" 1>&6 # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes echo "checking whether to build static libraries... $enable_static" 1>&6 if test "$hardcode_action" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi echo $ac_n "checking for objdir... $ac_c" 1>&6 rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. objdir=_libs fi rmdir .libs 2>/dev/null echo "$ac_t$objdir" 1>&6 if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then lt_cv_dlopen=no lt_cv_dlopen_libs= echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 echo "$progname:2212: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dlopen""... $ac_c" 1>&6 echo "$progname:2252: checking for dlopen" >&5 if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_dlopen) || defined (__stub___dlopen) choke me #else dlopen(); #endif ; return 0; } EOF if { (eval echo $progname:2282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_dlopen=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dlopen" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 echo "$progname:2299: checking for dld_link in -ldld" >&5 ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for shl_load""... $ac_c" 1>&6 echo "$progname:2339: checking for shl_load" >&5 if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_shl_load) || defined (__stub___shl_load) choke me #else shl_load(); #endif ; return 0; } EOF if { (eval echo $progname:2369: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_shl_load=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_shl_load=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="shl_load" else echo "$ac_t""no" 1>&6 echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 echo "$progname:2387: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else echo "$ac_t""no" 1>&6 fi fi fi fi fi fi if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes fi case "$lt_cv_dlopen" in dlopen) for ac_hdr in dlfcn.h; do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "$progname:2452: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int fnord = 0; EOF ac_try="$ac_compile >/dev/null 2>conftest.out" { (eval echo $progname:2462: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi done if test "x$ac_cv_header_dlfcn_h" = xyes; then CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" fi eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" LIBS="$lt_cv_dlopen_libs $LIBS" echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 echo "$progname:2490: checking whether a program can dlopen itself" >&5 if test "${lt_cv_dlopen_self+set}" = set; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then lt_cv_dlopen_self=cross else cat > conftest.c < #endif #include #ifdef RTLD_GLOBAL # define LTDL_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LTDL_GLOBAL DL_GLOBAL # else # define LTDL_GLOBAL 0 # endif #endif /* We may have to define LTDL_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LTDL_LAZY_OR_NOW # ifdef RTLD_LAZY # define LTDL_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LTDL_LAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LTDL_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LTDL_LAZY_OR_NOW DL_NOW # else # define LTDL_LAZY_OR_NOW 0 # endif # endif # endif # endif #endif fnord() { int i=42;} main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } EOF if { (eval echo $progname:2544: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then lt_cv_dlopen_self=yes else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* lt_cv_dlopen_self=no fi rm -fr conftest* fi fi echo "$ac_t""$lt_cv_dlopen_self" 1>&6 if test "$lt_cv_dlopen_self" = yes; then LDFLAGS="$LDFLAGS $link_static_flag" echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 echo "$progname:2563: checking whether a statically linked program can dlopen itself" >&5 if test "${lt_cv_dlopen_self_static+set}" = set; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then lt_cv_dlopen_self_static=cross else cat > conftest.c < #endif #include #ifdef RTLD_GLOBAL # define LTDL_GLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LTDL_GLOBAL DL_GLOBAL # else # define LTDL_GLOBAL 0 # endif #endif /* We may have to define LTDL_LAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LTDL_LAZY_OR_NOW # ifdef RTLD_LAZY # define LTDL_LAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LTDL_LAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LTDL_LAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LTDL_LAZY_OR_NOW DL_NOW # else # define LTDL_LAZY_OR_NOW 0 # endif # endif # endif # endif #endif fnord() { int i=42;} main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } EOF if { (eval echo $progname:2617: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then lt_cv_dlopen_self_static=yes else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* lt_cv_dlopen_self_static=no fi rm -fr conftest* fi fi echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 fi ;; esac case "$lt_cv_dlopen_self" in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case "$lt_cv_dlopen_self_static" in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # Copy echo and quote the copy, instead of the original, because it is # used later. ltecho="$echo" if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then ltecho="$CONFIG_SHELL \$0 --fallback-echo" fi LTSHELL="$SHELL" LTCONFIG_VERSION="$VERSION" # Only quote variables if we're using ltmain.sh. case "$ltmain" in *.sh) # Now quote all the things that may contain metacharacters. for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \ old_LD old_LDFLAGS old_LIBS \ old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \ AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ reload_flag reload_cmds wl \ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ thread_safe_flag_spec whole_archive_flag_spec libname_spec \ library_names_spec soname_spec \ RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ hardcode_libdir_flag_spec hardcode_libdir_separator \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do case "$var" in reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ postinstall_cmds | postuninstall_cmds | \ finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case "$ltecho" in *'\$0 --fallback-echo"') ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac trap "$rm \"$ofile\"; exit 1" 1 2 15 echo "creating $ofile" $rm "$ofile" cat < "$ofile" #! $SHELL # `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. # # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="sed -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi ### BEGIN LIBTOOL CONFIG EOF cfgfile="$ofile" ;; *) # Double-quote the variables that need it (for aesthetics). for var in old_CC old_CFLAGS old_CPPFLAGS \ old_LD old_LDFLAGS old_LIBS \ old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do eval "$var=\\\"\$var\\\"" done # Just create a config file. cfgfile="$ofile.cfg" trap "$rm \"$cfgfile\"; exit 1" 1 2 15 echo "creating $cfgfile" $rm "$cfgfile" cat < "$cfgfile" # `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) EOF ;; esac cat <> "$cfgfile" # Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # # CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ # LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\ # NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ # DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\ # $0$ltconfig_args # # Compiler and other test output produced by $progname, useful for # debugging $progname, is in ./config.log if it exists. # The version of $progname that generated this script. LTCONFIG_VERSION=$LTCONFIG_VERSION # Shell to use when invoking shell scripts. SHELL=$LTSHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host # An echo program that does not interpret backslashes. echo=$ltecho # The archiver. AR=$AR # The default C compiler. CC=$CC # The linker used to build libraries. LD=$LD # Whether we need hard or soft links. LN_S=$LN_S # A BSD-compatible nm program. NM=$NM # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$reload_flag reload_cmds=$reload_cmds # How to pass a linker flag through the compiler. wl=$wl # Object file suffix (normally "o"). objext="$objext" # Old archive suffix (normally "a"). libext="$libext" # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$pic_flag # Does compiler simultaneously support -c and -o options? compiler_c_o=$compiler_c_o # Can we write directly to a .lo ? compiler_o_lo=$compiler_o_lo # Must we lock files when doing compilation ? need_locks=$need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$link_static_flag # Compiler flag to turn off builtin functions. no_builtin_flag=$no_builtin_flag # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$whole_archive_flag_spec # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$thread_safe_flag_spec # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$library_names_spec # The coded name of the library, if different from the real name. soname_spec=$soname_spec # Commands used to build and install an old-style archive. RANLIB=$RANLIB old_archive_cmds=$old_archive_cmds old_postinstall_cmds=$old_postinstall_cmds old_postuninstall_cmds=$old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$old_archive_from_new_cmds # Commands used to build and install a shared archive. archive_cmds=$archive_cmds archive_expsym_cmds=$archive_expsym_cmds postinstall_cmds=$postinstall_cmds postuninstall_cmds=$postuninstall_cmds # Method to check whether dependent libraries are shared objects. deplibs_check_method=$deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$allow_undefined_flag # Flag that forces no undefined symbols. no_undefined_flag=$no_undefined_flag # Commands used to finish a libtool library installation in a directory. finish_cmds=$finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$global_symbol_to_cdecl # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$hardcode_libdir_separator # Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Compile-time system search path for libraries sys_lib_search_path_spec=$sys_lib_search_path_spec # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$exclude_expsyms # Symbols that must always be exported. include_expsyms=$include_expsyms EOF case "$ltmain" in *.sh) echo '### END LIBTOOL CONFIG' >> "$ofile" echo >> "$ofile" case "$host_os" in aix3*) cat <<\EOF >> "$ofile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # Append the ltmain.sh script. sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? chmod +x "$ofile" ;; *) # Compile the libtool program. echo "FIXME: would compile $ltmain" ;; esac test -n "$cache_file" || exit 0 # AC_CACHE_SAVE trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache exit 0 # Local Variables: # mode:shell-script # sh-indentation:2 # End: privoxy-3.0.21-stable/./pcre/maketables.c000640 001751 001751 00000007623 10546014100 017166 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- See the file Tech.Notes for some information on the internals. */ /* This file is compiled on its own as part of the PCRE library. However, it is also included in the compilation of dftables.c, in which case the macro DFTABLES is defined. */ #ifndef DFTABLES #include "internal.h" #endif /************************************************* * Create PCRE character tables * *************************************************/ /* This function builds a set of character tables for use by PCRE and returns a pointer to them. They are build using the ctype functions, and consequently their contents will depend upon the current locale setting. When compiled as part of the library, the store is obtained via pcre_malloc(), but when compiled inside dftables, use malloc(). Arguments: none Returns: pointer to the contiguous block of data */ unsigned const char * pcre_maketables(void) { unsigned char *yield, *p; int i; #ifndef DFTABLES yield = (unsigned char*)(pcre_malloc)(tables_length); #else yield = (unsigned char*)malloc(tables_length); #endif if (yield == NULL) return NULL; p = yield; /* First comes the lower casing table */ for (i = 0; i < 256; i++) *p++ = tolower(i); /* Next the case-flipping table */ for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); /* Then the character class tables. Don't try to be clever and save effort on exclusive ones - in some locales things may be different. */ memset(p, 0, cbit_length); for (i = 0; i < 256; i++) { if (isdigit(i)) { p[cbit_digit + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (isupper(i)) { p[cbit_upper + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (islower(i)) { p[cbit_lower + i/8] |= 1 << (i&7); p[cbit_word + i/8] |= 1 << (i&7); } if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); } p += cbit_length; /* Finally, the character type table */ for (i = 0; i < 256; i++) { int x = 0; if (isspace(i)) x += ctype_space; if (isalpha(i)) x += ctype_letter; if (isdigit(i)) x += ctype_digit; if (isxdigit(i)) x += ctype_xdigit; if (isalnum(i) || i == '_') x += ctype_word; if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; } return yield; } /* End of maketables.c */ privoxy-3.0.21-stable/./pcre/config.h000640 001751 001751 00000000114 10546014100 016314 0ustar00fkfk000000 000000 /* For Privoxy, we just use Privoxy's config.h */ #include "../config.h" privoxy-3.0.21-stable/./pcre/ltmain.sh000640 001751 001751 00000327705 10546014100 016540 0ustar00fkfk000000 000000 # ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun ltconfig. # # Copyright (C) 1996-1999 Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then echo "$modename: not configured to build any kind of library" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" # Parse our command line options once, thoroughly. while test $# -gt 0 do arg="$1" shift case "$arg" in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case "$prev" in execute_dlfiles) eval "$prev=\"\$$prev \$arg\"" ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case "$arg" in --help) show_help=yes ;; --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" exit 0 ;; --config) sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 exit 0 ;; --debug) echo "$progname: enabling shell trace mode" set -x ;; --dry-run | -n) run=: ;; --features) echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit 0 ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --quiet | --silent) show=: ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit 1 ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then case "$nonopt" in *cc | *++ | gcc* | *-gcc*) mode=link for arg do case "$arg" in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit 1 fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case "$mode" in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= lastarg= srcfile="$nonopt" suppress_output= user_target=no for arg do # Accept any command-line options. case "$arg" in -o) if test "$user_target" != "no"; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit 1 fi user_target=next ;; -static) build_old_libs=yes continue ;; esac case "$user_target" in next) # The next one is the -o target name user_target=yes continue ;; yes) # We got the output file user_target=set libobj="$arg" continue ;; esac # Accept the current argument as the source file. lastarg="$srcfile" srcfile="$arg" # Aesthetically quote the previous argument. # Backslashify any backslashes, double quotes, and dollar signs. # These are the only characters that are still specially # interpreted inside of double-quoted scrings. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly in scan # sets, so we specify it separately. case "$lastarg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) lastarg="\"$lastarg\"" ;; esac # Add the previous argument to base_compile. if test -z "$base_compile"; then base_compile="$lastarg" else base_compile="$base_compile $lastarg" fi done case "$user_target" in set) ;; no) # Get the name of the library object. libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; *) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit 1 ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSfmso]' case "$libobj" in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case "$libobj" in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit 1 ;; esac if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit 1 fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $libobj" else removelist="$libobj" fi $run $rm $removelist trap "$run $rm $removelist; exit 1" 1 2 15 # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit 1" 1 2 15 else need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until ln "$0" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi echo $srcfile > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile # All platforms use -DPIC, to notify preprocessed assembler code. command="$base_compile $srcfile $pic_flag -DPIC" if test "$build_old_libs" = yes; then lo_libobj="$libobj" dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$libobj"; then dir="$objdir" else dir="$dir/$objdir" fi libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` if test -d "$dir"; then $show "$rm $libobj" $run $rm $libobj else $show "$mkdir $dir" $run $mkdir $dir status=$? if test $status -ne 0 && test ! -d $dir; then exit $status fi fi fi if test "$compiler_o_lo" = yes; then output_obj="$libobj" command="$command -o $output_obj" elif test "$compiler_c_o" = yes; then output_obj="$obj" command="$command -o $output_obj" fi $run $rm "$output_obj" $show "$command" if $run eval "$command"; then : else test -n "$output_obj" && $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed, then go on to compile the next one if test x"$output_obj" != x"$libobj"; then $show "$mv $output_obj $libobj" if $run $mv $output_obj $libobj; then : else error=$? $run $rm $removelist exit $error fi fi # If we have no pic_flag, then copy the object into place and finish. if test -z "$pic_flag" && test "$build_old_libs" = yes; then # Rename the .lo from within objdir to obj if test -f $obj; then $show $rm $obj $run $rm $obj fi $show "$mv $libobj $obj" if $run $mv $libobj $obj; then : else error=$? $run $rm $removelist exit $error fi xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` # Now arrange that obj and lo_libobj become the same file $show "(cd $xdir && $LN_S $baseobj $libobj)" if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then exit 0 else error=$? $run $rm $removelist exit $error fi fi # Allow error messages only from the first compilation. suppress_output=' >/dev/null 2>&1' fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then command="$base_compile $srcfile" if test "$compiler_c_o" = yes; then command="$command -o $obj" output_obj="$obj" fi # Suppress compiler output if we already did a PIC compilation. command="$command$suppress_output" $run $rm "$output_obj" $show "$command" if $run eval "$command"; then : else $run $rm $removelist exit 1 fi if test "$need_locks" = warn && test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit 1 fi # Just move the object if needed if test x"$output_obj" != x"$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Create an invalid libtool object if no PIC, so that we do not # accidentally link it into a program. if test "$build_libtool_libs" != yes; then $show "echo timestamp > $libobj" $run eval "echo timestamp > \$libobj" || exit $? else # Move the .lo from within objdir $show "$mv $libobj $lo_libobj" if $run $mv $libobj $lo_libobj; then : else error=$? $run $rm $removelist exit $error fi fi fi # Unlock the critical section if it was locked if test "$need_locks" != no; then $rm "$lockfile" fi exit 0 ;; # libtool link mode link) modename="$modename: link" case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invokation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes # This is a source program that is used to create dlls on Windows # Don't remove nor modify the starting and closing comments # /* ltdll.c starts here */ # #define WIN32_LEAN_AND_MEAN # #include # #undef WIN32_LEAN_AND_MEAN # #include # # #ifndef __CYGWIN__ # # ifdef __CYGWIN32__ # # define __CYGWIN__ __CYGWIN32__ # # endif # #endif # # #ifdef __cplusplus # extern "C" { # #endif # BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); # #ifdef __cplusplus # } # #endif # # #ifdef __CYGWIN__ # #include # DECLARE_CYGWIN_DLL( DllMain ); # #endif # HINSTANCE __hDllInstance_base; # # BOOL APIENTRY # DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) # { # __hDllInstance_base = hInst; # return TRUE; # } # /* ltdll.c ends here */ # This is a source program that is used to create import libraries # on Windows for dlls which lack them. Don't remove nor modify the # starting and closing comments # /* impgen.c starts here */ # /* Copyright (C) 1999 Free Software Foundation, Inc. # # This file is part of GNU libtool. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # */ # # #include /* for printf() */ # #include /* for open(), lseek(), read() */ # #include /* for O_RDONLY, O_BINARY */ # #include /* for strdup() */ # # static unsigned int # pe_get16 (fd, offset) # int fd; # int offset; # { # unsigned char b[2]; # lseek (fd, offset, SEEK_SET); # read (fd, b, 2); # return b[0] + (b[1]<<8); # } # # static unsigned int # pe_get32 (fd, offset) # int fd; # int offset; # { # unsigned char b[4]; # lseek (fd, offset, SEEK_SET); # read (fd, b, 4); # return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); # } # # static unsigned int # pe_as32 (ptr) # void *ptr; # { # unsigned char *b = ptr; # return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); # } # # int # main (argc, argv) # int argc; # char *argv[]; # { # int dll; # unsigned long pe_header_offset, opthdr_ofs, num_entries, i; # unsigned long export_rva, export_size, nsections, secptr, expptr; # unsigned long name_rvas, nexp; # unsigned char *expdata, *erva; # char *filename, *dll_name; # # filename = argv[1]; # # dll = open(filename, O_RDONLY|O_BINARY); # if (!dll) # return 1; # # dll_name = filename; # # for (i=0; filename[i]; i++) # if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') # dll_name = filename + i +1; # # pe_header_offset = pe_get32 (dll, 0x3c); # opthdr_ofs = pe_header_offset + 4 + 20; # num_entries = pe_get32 (dll, opthdr_ofs + 92); # # if (num_entries < 1) /* no exports */ # return 1; # # export_rva = pe_get32 (dll, opthdr_ofs + 96); # export_size = pe_get32 (dll, opthdr_ofs + 100); # nsections = pe_get16 (dll, pe_header_offset + 4 +2); # secptr = (pe_header_offset + 4 + 20 + # pe_get16 (dll, pe_header_offset + 4 + 16)); # # expptr = 0; # for (i = 0; i < nsections; i++) # { # char sname[8]; # unsigned long secptr1 = secptr + 40 * i; # unsigned long vaddr = pe_get32 (dll, secptr1 + 12); # unsigned long vsize = pe_get32 (dll, secptr1 + 16); # unsigned long fptr = pe_get32 (dll, secptr1 + 20); # lseek(dll, secptr1, SEEK_SET); # read(dll, sname, 8); # if (vaddr <= export_rva && vaddr+vsize > export_rva) # { # expptr = fptr + (export_rva - vaddr); # if (export_rva + export_size > vaddr + vsize) # export_size = vsize - (export_rva - vaddr); # break; # } # } # # expdata = (unsigned char*)malloc(export_size); # lseek (dll, expptr, SEEK_SET); # read (dll, expdata, export_size); # erva = expdata - export_rva; # # nexp = pe_as32 (expdata+24); # name_rvas = pe_as32 (expdata+32); # # printf ("EXPORTS\n"); # for (i = 0; i&2 fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi else if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi fi build_libtool_libs=no build_old_libs=yes prefer_static_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test $# -gt 0; do arg="$1" shift # If the previous option needs an argument, assign it. if test -n "$prev"; then case "$prev" in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case "$prev" in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case "$arg" in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit 1 fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case "$arg" in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi prevarg="$arg" case "$arg" in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: not more than one -exported-symbols argument allowed" exit 1 fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` # We need an absolute path. case "$dir" in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 absdir="$dir" fi dir="$absdir" ;; esac case " $deplibs " in *" $arg "*) ;; *) deplibs="$deplibs $arg";; esac case " $lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir";; esac case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) dllsearchdir=`cd "$dir" && pwd || echo "$dir"` case ":$dllsearchpath:" in ::) dllsearchpath="$dllsearchdir";; *":$dllsearchdir:"*) ;; *) dllsearchpath="$dllsearchpath:$dllsearchdir";; esac ;; esac ;; -l*) if test "$arg" = "-lc"; then case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) # These systems don't actually have c library (as such) continue ;; esac elif test "$arg" = "-lm"; then case "$host" in *-*-cygwin* | *-*-beos*) # These systems don't actually have math library (as such) continue ;; esac fi deplibs="$deplibs $arg" ;; -module) module=yes continue ;; -no-undefined) allow_undefined=no continue ;; -o) prev=output ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` # We need an absolute path. case "$dir" in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit 1 ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -static) # If we have no pic_flag, then this is the same as -all-static. if test -z "$pic_flag" && test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac ;; *.o | *.obj | *.a | *.lib) # A standard object. objs="$objs $arg" ;; *.lo) # A library object. if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` prev= fi libobjs="$libobjs $arg" ;; *.la) # A libtool-controlled library. dlname= libdir= library_names= old_library= # Check to see that this really is a libtool archive. if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 exit 1 fi # If the library was installed with an old release of libtool, # it will not redefine variable installed. installed=yes # Read the .la file # If there is no directory component, then add one. case "$arg" in */* | *\\*) . $arg ;; *) . ./$arg ;; esac # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 exit 1 fi # Find the relevant object directory and library name. name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` if test "X$installed" = Xyes; then dir="$libdir" else dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$arg"; then dir="$objdir" else dir="$dir/$objdir" fi fi if test -n "$dependency_libs"; then # Extract -R and -L from dependency_libs temp_deplibs= for deplib in $dependency_libs; do case "$deplib" in -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` case " $rpath $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; -L*) case "$compile_command $temp_deplibs " in *" $deplib "*) ;; *) temp_deplibs="$temp_deplibs $deplib";; esac temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'` case " $lib_search_path " in *" $temp_dir "*) ;; *) lib_search_path="$lib_search_path $temp_dir";; esac ;; *) temp_deplibs="$temp_deplibs $deplib";; esac done dependency_libs="$temp_deplibs" fi if test -z "$libdir"; then # It is a libtool convenience library, so add in its objects. convenience="$convenience $dir/$old_library" old_convenience="$old_convenience $dir/$old_library" deplibs="$deplibs$dependency_libs" compile_command="$compile_command $dir/$old_library$dependency_libs" finalize_command="$finalize_command $dir/$old_library$dependency_libs" continue fi # This library was specified with -dlopen. if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking statically, # we need to preload. prev=dlprefiles else # We should not create a dependency on this library, but we # may need any libraries it requires. compile_command="$compile_command$dependency_libs" finalize_command="$finalize_command$dependency_libs" prev= continue fi fi # The library was specified with -dlpreopen. if test "$prev" = dlprefiles; then # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then dlprefiles="$dlprefiles $dir/$old_library" else dlprefiles="$dlprefiles $dir/$linklib" fi prev= fi if test -n "$library_names" && { test "$prefer_static_libs" = no || test -z "$old_library"; }; then link_against_libtool_libs="$link_against_libtool_libs $arg" if test -n "$shlibpath_var"; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *) temp_rpath="$temp_rpath $dir" ;; esac fi # We need an absolute path. case "$dir" in [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 absdir="$dir" fi ;; esac # This is the magic to use -rpath. # Skip directories that are in the system default run-time # search path, unless they have been requested with -R. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac lib_linked=yes case "$hardcode_action" in immediate | unsupported) if test "$hardcode_direct" = no; then compile_command="$compile_command $dir/$linklib" deplibs="$deplibs $dir/$linklib" case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2*) dllsearchdir=`cd "$dir" && pwd || echo "$dir"` if test -n "$dllsearchpath"; then dllsearchpath="$dllsearchpath:$dllsearchdir" else dllsearchpath="$dllsearchdir" fi ;; esac elif test "$hardcode_minus_L" = no; then case "$host" in *-*-sunos*) compile_shlibpath="$compile_shlibpath$dir:" ;; esac case "$compile_command " in *" -L$dir "*) ;; *) compile_command="$compile_command -L$dir";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -L$dir -l$name" elif test "$hardcode_shlibpath_var" = no; then case ":$compile_shlibpath:" in *":$dir:"*) ;; *) compile_shlibpath="$compile_shlibpath$dir:";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then compile_command="$compile_command $absdir/$linklib" deplibs="$deplibs $absdir/$linklib" elif test "$hardcode_minus_L" = yes; then case "$compile_command " in *" -L$absdir "*) ;; *) compile_command="$compile_command -L$absdir";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -L$absdir -l$name" elif test "$hardcode_shlibpath_var" = yes; then case ":$compile_shlibpath:" in *":$absdir:"*) ;; *) compile_shlibpath="$compile_shlibpath$absdir:";; esac compile_command="$compile_command -l$name" deplibs="$deplibs -l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit 1 fi # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then finalize_command="$finalize_command $libdir/$linklib" elif test "$hardcode_minus_L" = yes; then case "$finalize_command " in *" -L$libdir "*) ;; *) finalize_command="$finalize_command -L$libdir";; esac finalize_command="$finalize_command -l$name" elif test "$hardcode_shlibpath_var" = yes; then case ":$finalize_shlibpath:" in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:";; esac finalize_command="$finalize_command -l$name" else # We cannot seem to hardcode it, guess we'll fake it. case "$finalize_command " in *" -L$dir "*) ;; *) finalize_command="$finalize_command -L$libdir";; esac finalize_command="$finalize_command -l$name" fi else # Transform directly to old archives if we don't build new libraries. if test -n "$pic_flag" && test -z "$old_library"; then $echo "$modename: cannot find static library for \`$arg'" 1>&2 exit 1 fi # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_command="$compile_command $dir/$linklib" finalize_command="$finalize_command $dir/$linklib" else case "$compile_command " in *" -L$dir "*) ;; *) compile_command="$compile_command -L$dir";; esac compile_command="$compile_command -l$name" case "$finalize_command " in *" -L$dir "*) ;; *) finalize_command="$finalize_command -L$dir";; esac finalize_command="$finalize_command -l$name" fi fi # Add in any libraries that this one depends upon. compile_command="$compile_command$dependency_libs" finalize_command="$finalize_command$dependency_libs" continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac ;; esac # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi oldlibs= # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" case "$output" in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit 1 ;; *.a | *.lib) if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 exit 1 fi if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" ;; *.la) # Make sure we only generate libraries of the form `libNAME.la'. case "$outputname" in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit 1 fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi if test -n "$objs"; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 exit 1 fi # How the heck are we supposed to write a wrapper for a shared library? if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 exit 1 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test $# -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. libext=al oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi dependency_libs="$deplibs" if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit 1 fi current="$2" revision="$3" age="$4" # Check that each of the things are valid numbers. case "$current" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case "$revision" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac case "$age" in 0 | [1-9] | [1-9][0-9]*) ;; *) $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 ;; esac if test $age -gt $current; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit 1 fi # Calculate the version variables. major= versuffix= verstring= case "$version_type" in none) ;; irix) major=`expr $current - $age + 1` versuffix="$major.$revision" verstring="sgi$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test $loop != 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="sgi$major.$iface:$verstring" done ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test $loop != 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; windows) # Like Linux, but with '-' rather than '.', since we only # want one extension on Windows 95. major=`expr $current - $age` versuffix="-$major-$age-$revision" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit 1 ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= verstring="0.0" if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi dependency_libs="$deplibs" case "$host" in *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) # these systems don't actually have a c library (as such)! ;; *) # Add libc to deplibs on all other systems. deplibs="$deplibs -lc" ;; esac fi # Create the output directory, or remove our outputs if we need to. if test -d $output_objdir; then $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* else $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test $status -ne 0 && test ! -d $output_objdir; then exit $status fi fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi if test "$build_libtool_libs" = yes; then # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case "$deplibs_check_method" in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behaviour. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | sed 's/.* -> //'` case "$potliblink" in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ | sed 10q \ | egrep "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done if test -n "$a_deplib" ; then droppeddeps=yes echo echo "*** Warning: This library needs some functionality provided by $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | grep . >/dev/null; then echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" echo "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." fi fi # Done checking deplibs! deplibs=$newdeplibs fi # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Get the real and link names of the library. eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi lib="$output_objdir/$realname" for link do linknames="$linknames $link" done # Ensure that we have .o objects for linkers which dislike .lo # (e.g. aix) in case we are running --disable-static for obj in $libobjs; do xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` if test ! -f $xdir/$oldobj; then $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? fi done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols eval cmds=\"$export_symbols_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case "$xlib" in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linkopts="$linkopts $flag" fi # Do each of the archive commands. if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval cmds=\"$archive_expsym_cmds\" else eval cmds=\"$archive_cmds\" fi IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; *.lo | *.o | *.obj) if test -n "$link_against_libtool_libs"; then $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 exit 1 fi if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case "$output" in *.lo) if test -n "$objs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit 1 fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" else gentop="$output_objdir/${obj}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" for xlib in $convenience; do # Extract the objects. case "$xlib" in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` done fi fi # Create the old-style object. reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" output="$obj" eval cmds=\"$reload_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. $show "echo timestamp > $libobj" $run eval "echo timestamp > $libobj" || exit $? exit 0 fi if test -n "$pic_flag"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" eval cmds=\"$reload_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" else # Just create a symlink. $show $rm $libobj $run $rm $libobj xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$libobj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` $show "(cd $xdir && $LN_S $oldobj $baseobj)" $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? fi if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit 0 ;; # Anything else should be a program. *) if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$compile_rpath " in *" $libdir "*) ;; *) compile_rpath="$compile_rpath $libdir" ;; esac case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # Create the binary in the object directory, then wrap it. if test ! -d $output_objdir; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir status=$? if test $status -ne 0 && test ! -d $output_objdir; then exit $status fi fi if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case "$dlsyms" in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${outputname}.nm" $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" # Parse the name list into a source file. $show "creating $output_objdir/$dlsyms" test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$output.exp" $run $rm $export_symbols $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' else $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`echo "$arg" | sed -e 's%^.*/%%'` $run eval 'echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = {\ " sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr_t) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case "$host" in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; esac;; *-*-hpux*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DPIC";; esac esac # Now compile the dynamic symbol file. $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Clean up the generated files. $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" # Transform the symbol file into the correct name. compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit 1 ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` fi if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" status=$? # Delete the generated files. if test -n "$dlsyms"; then $show "$rm $output_objdir/${outputname}S.${objext}" $run $rm "$output_objdir/${outputname}S.${objext}" fi exit $status fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case "$dir" in [\\/]* | [A-Za-z]:[\\/]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $0 --fallback-echo"; then case "$0" in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; *) qecho="$SHELL `pwd`/$0 --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`echo $output|sed 's,.exe$,,'` ;; esac $rm $output trap "$rm $output; exit 1" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: link_against_libtool_libs='$link_against_libtool_libs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then echo >> $output "\ program=lt-'$outputname' progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if (cd \"\$thisdir\" && eval \$relink_command); then : else $rm \"\$progdir/\$file\" exit 1 fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in *-*-cygwin* | *-*-mingw | *-*-os2*) # win32 systems need to use the prog path for dll # lookup to work $echo >> $output "\ exec \$progdir\\\\\$program \${1+\"\$@\"} " ;; *) $echo >> $output "\ # Export the path to the program. PATH=\"\$progdir:\$PATH\" export PATH exec \$program \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" exit 1 fi else # The program doesn't exist. \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " chmod +x $output fi exit 0 ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "mkdir $gentop" $run mkdir "$gentop" status=$? if test $status -ne 0 && test ! -d "$gentop"; then exit $status fi generated="$generated $gentop" # Add in members from convenience archives. for xlib in $addlibs; do # Extract the objects. case "$xlib" in [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; *) xabs=`pwd`"/$xlib" ;; esac xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` xdir="$gentop/$xlib" $show "${rm}r $xdir" $run ${rm}r "$xdir" $show "mkdir $xdir" $run mkdir "$xdir" status=$? if test $status -ne 0 && test ! -d "$xdir"; then exit $status fi $show "(cd $xdir && $AR x $xabs)" $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` done fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then eval cmds=\"$old_archive_from_new_cmds\" else # Ensure that we have .o objects in place in case we decided # not to build a shared library, and have fallen back to building # static libs even though --disable-static was passed! for oldobj in $oldobjs; do if test ! -f $oldobj; then xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$oldobj"; then xdir="." else xdir="$xdir" fi baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` $show "(cd $xdir && ${LN_S} $obj $baseobj)" $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? fi done eval cmds=\"$old_archive_cmds\" fi IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case "$output" in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" if test -n "$xrpath"; then temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" done dependency_libs="$temp_xrpath $dependency_libs" fi # Only create the output if not a dry run. if test -z "$run"; then for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i fi $rm $output $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$dlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Directory that this library needs to be installed in: libdir='$install_libdir'\ " done fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? ;; esac exit 0 ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg="$nonopt" fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest="$arg" continue fi case "$arg" in -d) isdir=yes ;; -f) prev="-f" ;; -g) prev="-g" ;; -m) prev="-m" ;; -o) prev="-o" ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest="$arg" continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case "$arg" in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit 1 fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit 1 fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test $# -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit 1 fi fi case "$destdir" in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case "$file" in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case "$file" in *.a | *.lib) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi library_names= old_library= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" test "X$dir" = "X$file/" && dir= dir="$dir$objdir" # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift # Install the shared library and build the symlinks. $show "$install_prog $dir/$realname $destdir/$realname" $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? if test $# -gt 0; then # Delete the old symlinks, and create new ones. for linkname do if test "$linkname" != "$realname"; then $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" fi done fi # Do each command in the postinstall commands. lib="$destdir/$realname" eval cmds=\"$postinstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case "$destfile" in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.o | *.obj) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit 0 ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Do a test to see if this is really a libtool program. if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then link_against_libtool_libs= relink_command= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Check the variables that should have been set. if test -z "$link_against_libtool_libs"; then $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 exit 1 fi finalize=yes for lib in $link_against_libtool_libs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case "$lib" in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes && test -z "$run"; then tmpdir="/tmp" test -n "$TMPDIR" && tmpdir="$TMPDIR" tmpdir="$tmpdir/libtool-$$" if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : else $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 continue fi outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 ${rm}r "$tmpdir" continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file'" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && ${rm}r "$tmpdir" ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? # Do each command in the postinstall commands. eval cmds=\"$old_postinstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec $SHELL $0 --finish$current_libdirs exit 1 fi exit 0 ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. eval cmds=\"$finish_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = : && exit 0 echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do echo " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" echo "more information, such as the ld(1) and ld.so(8) manual pages." echo "----------------------------------------------------------------------" exit 0 ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit 1 fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit 1 fi dir= case "$file" in *.la) # Check to see that this really is a libtool archive. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit 1 fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit 1 fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case "$file" in -*) ;; *) # Do a test to see if this is really a libtool program. if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case "$file" in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved enviroment variables if test "${save_LC_ALL+set}" = set; then LC_ALL="$save_LC_ALL"; export LC_ALL fi if test "${save_LANG+set}" = set; then LANG="$save_LANG"; export LANG fi # Now actually exec the command. eval "exec \$cmd$args" $echo "$modename: cannot exec \$cmd$args" exit 1 else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" fi $echo "$cmd$args" exit 0 fi ;; # libtool uninstall mode uninstall) modename="$modename: uninstall" rm="$nonopt" files= for arg do case "$arg" in -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit 1 fi for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` rmfiles="$file" case "$name" in *.la) # Possibly a libtool archive, so verify it. if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $dir/$n" done test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" $show "$rm $rmfiles" $run $rm $rmfiles if test -n "$library_names"; then # Do each command in the postuninstall commands. eval cmds=\"$postuninstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. eval cmds=\"$old_postuninstall_cmds\" IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. fi ;; *.lo) if test "$build_old_libs" = yes; then oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` rmfiles="$rmfiles $dir/$oldobj" fi $show "$rm $rmfiles" $run $rm $rmfiles ;; *) $show "$rm $rmfiles" $run $rm $rmfiles ;; esac done exit 0 ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit 1 ;; esac $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit 1 fi # test -z "$show_help" # We need to display help for each of the modes. case "$mode" in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --version print version information MODE must be one of the following: compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE." exit 0 ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo \ "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit 1 ;; esac echo $echo "Try \`$modename --help' for more information about other modes." exit 0 # Local Variables: # mode:shell-script # sh-indentation:2 # End: privoxy-3.0.21-stable/./pcre/licence000640 001751 001751 00000003361 10546014100 016232 0ustar00fkfk000000 000000 PCRE LICENCE ------------ PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2000 University of Cambridge Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ should also be given in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. End privoxy-3.0.21-stable/./pcre/pcre.h000640 001751 001751 00000006071 10546014100 016010 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 1997-2000 University of Cambridge */ #ifndef _PCRE_H #define _PCRE_H /* The file pcre.h is build by "configure". Do not edit it; instead make changes to pcre.in. */ #define PCRE_MAJOR 3 #define PCRE_MINOR 4 #define PCRE_DATE 22-Aug-2000 /* Win32 uses DLL by default */ #ifdef _WIN32 # ifdef STATIC_PCRE # define PCRE_DL_IMPORT # else # define PCRE_DL_IMPORT __declspec(dllimport) # endif #else # define PCRE_DL_IMPORT #endif /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options */ #define PCRE_CASELESS 0x0001 #define PCRE_MULTILINE 0x0002 #define PCRE_DOTALL 0x0004 #define PCRE_EXTENDED 0x0008 #define PCRE_ANCHORED 0x0010 #define PCRE_DOLLAR_ENDONLY 0x0020 #define PCRE_EXTRA 0x0040 #define PCRE_NOTBOL 0x0080 #define PCRE_NOTEOL 0x0100 #define PCRE_UNGREEDY 0x0200 #define PCRE_NOTEMPTY 0x0400 #define PCRE_UTF8 0x0800 /* Exec-time and get-time error codes */ #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_UNKNOWN_NODE (-5) #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) /* Request types for pcre_fullinfo() */ #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_FIRSTCHAR 4 #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 /* Types */ typedef void pcre; typedef void pcre_extra; /* Store get and free functions. These can be set to alternative malloc/free functions if required. Some magic is required for Win32 DLL; it is null on other OS. */ PCRE_DL_IMPORT extern void *(*pcre_malloc)(size_t); PCRE_DL_IMPORT extern void (*pcre_free)(void *); #undef PCRE_DL_IMPORT /* Functions */ extern pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); extern int pcre_copy_substring(const char *, int *, int, int, char *, int); extern int pcre_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int); extern void pcre_free_substring(const char *); extern void pcre_free_substring_list(const char **); extern int pcre_get_substring(const char *, int *, int, int, const char **); extern int pcre_get_substring_list(const char *, int *, int, const char ***); extern int pcre_info(const pcre *, int *, int *); extern int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *); extern unsigned const char *pcre_maketables(void); extern pcre_extra *pcre_study(const pcre *, int, const char **); extern const char *pcre_version(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcre.h */ privoxy-3.0.21-stable/./pcre/pcreposix.c000640 001751 001751 00000021675 10546014100 017075 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. This module is a wrapper that provides a POSIX API to the underlying PCRE functions. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ #include "internal.h" #include "pcreposix.h" #include "stdlib.h" /* Corresponding tables of PCRE error messages and POSIX error codes. */ static const char *estring[] = { ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR29, ERR29, ERR30, ERR31 }; static int eint[] = { REG_EESCAPE, /* "\\ at end of pattern" */ REG_EESCAPE, /* "\\c at end of pattern" */ REG_EESCAPE, /* "unrecognized character follows \\" */ REG_BADBR, /* "numbers out of order in {} quantifier" */ REG_BADBR, /* "number too big in {} quantifier" */ REG_EBRACK, /* "missing terminating ] for character class" */ REG_ECTYPE, /* "invalid escape sequence in character class" */ REG_ERANGE, /* "range out of order in character class" */ REG_BADRPT, /* "nothing to repeat" */ REG_BADRPT, /* "operand of unlimited repeat could match the empty string" */ REG_ASSERT, /* "internal error: unexpected repeat" */ REG_BADPAT, /* "unrecognized character after (?" */ REG_ESIZE, /* "too many capturing parenthesized sub-patterns" */ REG_EPAREN, /* "missing )" */ REG_ESUBREG, /* "back reference to non-existent subpattern" */ REG_INVARG, /* "erroffset passed as NULL" */ REG_INVARG, /* "unknown option bit(s) set" */ REG_EPAREN, /* "missing ) after comment" */ REG_ESIZE, /* "too many sets of parentheses" */ REG_ESIZE, /* "regular expression too large" */ REG_ESPACE, /* "failed to get memory" */ REG_EPAREN, /* "unmatched brackets" */ REG_ASSERT, /* "internal error: code overflow" */ REG_BADPAT, /* "unrecognized character after (?<" */ REG_BADPAT, /* "lookbehind assertion is not fixed length" */ REG_BADPAT, /* "malformed number after (?(" */ REG_BADPAT, /* "conditional group containe more than two branches" */ REG_BADPAT, /* "assertion expected after (?(" */ REG_BADPAT, /* "(?p must be followed by )" */ REG_ECTYPE, /* "unknown POSIX class name" */ REG_BADPAT, /* "POSIX collating elements are not supported" */ REG_INVARG, /* "this version of PCRE is not compiled with PCRE_UTF8 support" */ REG_BADPAT, /* "characters with values > 255 are not yet supported in classes" */ REG_BADPAT, /* "character value in \x{...} sequence is too large" */ REG_BADPAT /* "invalid condition (?(0)" */ }; /* Table of texts corresponding to POSIX error codes */ static const char *pstring[] = { "", /* Dummy for value 0 */ "internal error", /* REG_ASSERT */ "invalid repeat counts in {}", /* BADBR */ "pattern error", /* BADPAT */ "? * + invalid", /* BADRPT */ "unbalanced {}", /* EBRACE */ "unbalanced []", /* EBRACK */ "collation error - not relevant", /* ECOLLATE */ "bad class", /* ECTYPE */ "bad escape sequence", /* EESCAPE */ "empty expression", /* EMPTY */ "unbalanced ()", /* EPAREN */ "bad range inside []", /* ERANGE */ "expression too big", /* ESIZE */ "failed to get memory", /* ESPACE */ "bad back reference", /* ESUBREG */ "bad argument", /* INVARG */ "match failed" /* NOMATCH */ }; /************************************************* * Translate PCRE text code to int * *************************************************/ /* PCRE compile-time errors are given as strings defined as macros. We can just look them up in a table to turn them into POSIX-style error codes. */ static int pcre_posix_error_code(const char *s) { size_t i; for (i = 0; i < sizeof(estring)/sizeof(char *); i++) if (strcmp(s, estring[i]) == 0) return eint[i]; return REG_ASSERT; } /************************************************* * Translate error code to string * *************************************************/ size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { const char *message, *addmessage; size_t length, addlength; message = (errcode >= (int)(sizeof(pstring)/sizeof(char *)))? "unknown error code" : pstring[errcode]; length = strlen(message) + 1; addmessage = " at offset "; addlength = (preg != NULL && (int)preg->re_erroffset != -1)? strlen(addmessage) + 6 : 0; if (errbuf_size > 0) { if (addlength > 0 && errbuf_size >= length + addlength) sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset); else { strncpy(errbuf, message, errbuf_size - 1); errbuf[errbuf_size-1] = 0; } } return length + addlength; } /************************************************* * Free store held by a regex * *************************************************/ void regfree(regex_t *preg) { (pcre_free)(preg->re_pcre); } /************************************************* * Compile a regular expression * *************************************************/ /* Arguments: preg points to a structure for recording the compiled expression pattern the pattern to compile cflags compilation flags Returns: 0 on success various non-zero codes on failure */ int regcomp(regex_t *preg, const char *pattern, int cflags) { const char *errorptr; int erroffset; int options = 0; if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS; if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE; preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL); preg->re_erroffset = erroffset; if (preg->re_pcre == NULL) return pcre_posix_error_code(errorptr); preg->re_nsub = pcre_info(preg->re_pcre, NULL, NULL); return 0; } /************************************************* * Match a regular expression * *************************************************/ /* Unfortunately, PCRE requires 3 ints of working space for each captured substring, so we have to get and release working store instead of just using the POSIX structures as was done in earlier releases when PCRE needed only 2 ints. */ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) { int rc; int options = 0; int *ovector = NULL; if ((eflags & REG_NOTBOL) != 0) options |= PCRE_NOTBOL; if ((eflags & REG_NOTEOL) != 0) options |= PCRE_NOTEOL; preg->re_erroffset = (size_t)(-1); /* Only has meaning after compile */ if (nmatch > 0) { ovector = (int *)malloc(sizeof(int) * nmatch * 3); if (ovector == NULL) return REG_ESPACE; } rc = pcre_exec(preg->re_pcre, NULL, string, (int)strlen(string), 0, options, ovector, nmatch * 3); if (rc == 0) rc = nmatch; /* All captured slots were filled in */ if (rc >= 0) { size_t i; for (i = 0; i < (size_t)rc; i++) { pmatch[i].rm_so = ovector[i*2]; pmatch[i].rm_eo = ovector[i*2+1]; } if (ovector != NULL) free(ovector); for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; return 0; } else { if (ovector != NULL) free(ovector); switch(rc) { case PCRE_ERROR_NOMATCH: return REG_NOMATCH; case PCRE_ERROR_NULL: return REG_INVARG; case PCRE_ERROR_BADOPTION: return REG_INVARG; case PCRE_ERROR_BADMAGIC: return REG_INVARG; case PCRE_ERROR_UNKNOWN_NODE: return REG_ASSERT; case PCRE_ERROR_NOMEMORY: return REG_ESPACE; default: return REG_ASSERT; } } } /* End of pcreposix.c */ privoxy-3.0.21-stable/./pcre/config.sub000640 001751 001751 00000057727 10546014100 016704 0ustar00fkfk000000 000000 #! /bin/sh # Configuration validation subroutine script, version 1.1. # Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. if [ x$1 = x ] then echo Configuration name missing. 1>&2 echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 echo "or $0 ALIAS" 1>&2 echo where ALIAS is a recognized configuration type. 1>&2 exit 1 fi # First pass through any local machine types. case $1 in *local*) echo $1 exit 0 ;; *) ;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in linux-gnu*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ | 580 | i960 | h8300 \ | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \ | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ | mips64orion | mips64orionel | mipstx39 | mipstx39el \ | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ | mips64vr5000 | miprs64vr5000el | mcore \ | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ | thumb | d10v | fr30) basic_machine=$basic_machine-unknown ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i[34567]86) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. # FIXME: clean up the formatting here. vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ | xmp-* | ymp-* \ | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \ | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ | clipper-* | orion-* \ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ | mips64el-* | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ | mipstx39-* | mipstx39el-* | mcore-* \ | f301-* | armv*-* | t3e-* \ | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* ) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-cbm ;; amigaos | amigados) basic_machine=m68k-cbm os=-amigaos ;; amigaunix | amix) basic_machine=m68k-cbm os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [ctj]90-cray) basic_machine=c90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i[34567]86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i[34567]86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i[34567]86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i[34567]86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; i386-go32 | go32) basic_machine=i386-unknown os=-go32 ;; i386-mingw32 | mingw32) basic_machine=i386-unknown os=-mingw32 ;; i386-qnx | qnx) basic_machine=i386-qnx ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-unknown os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; np1) basic_machine=np1-gould ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexen) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=rs6000-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sparc | sparcv9) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -opened* | -openstep* | -oskit*) # Remember, each alternative MUST END IN *, to match a version number. ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -qnx) os=-qnx4 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -*MiNT) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f301-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -*MiNT) vendor=atari ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os privoxy-3.0.21-stable/./pcre/config.guess000640 001751 001751 00000074774 10546014100 017242 0ustar00fkfk000000 000000 #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 # Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Written by Per Bothner . # The master version of this file is at the FSF in /home/gd/gnu/lib. # Please send patches to . # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit system type (host/target name). # # Only a few systems have been added to this list; please add others # (but try to keep the structure clean). # # Use $HOST_CC if defined. $CC may point to a cross-compiler if test x"$CC_FOR_BUILD" = x; then if test x"$HOST_CC" != x; then CC_FOR_BUILD="$HOST_CC" else if test x"$CC" != x; then CC_FOR_BUILD="$CC" else CC_FOR_BUILD=cc fi fi fi # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 8/24/94.) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown dummy=dummy-$$ trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. cat <$dummy.s .globl main .ent main main: .frame \$30,0,\$26,0 .prologue 0 .long 0x47e03d80 # implver $0 lda \$2,259 .long 0x47e20c21 # amask $2,$1 srl \$1,8,\$2 sll \$2,2,\$2 sll \$0,3,\$0 addl \$1,\$0,\$0 addl \$2,\$0,\$0 ret \$31,(\$26),1 .end main EOF $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then ./$dummy case "$?" in 7) UNAME_MACHINE="alpha" ;; 15) UNAME_MACHINE="alphaev5" ;; 14) UNAME_MACHINE="alphaev56" ;; 10) UNAME_MACHINE="alphapca56" ;; 16) UNAME_MACHINE="alphaev6" ;; esac fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-cbm-sysv4 exit 0;; amiga:NetBSD:*:*) echo m68k-cbm-netbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; arc64:OpenBSD:*:*) echo mips64el-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hkmips:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; arm32:NetBSD:*:*) echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` exit 0 ;; SR2?01:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; atari*:NetBSD:*:*) echo m68k-atari-netbsd${UNAME_RELEASE} exit 0 ;; atari*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; sun3*:NetBSD:*:*) echo m68k-sun-netbsd${UNAME_RELEASE} exit 0 ;; sun3*:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:NetBSD:*:*) echo m68k-apple-netbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; macppc:NetBSD:*:*) echo powerpc-apple-netbsd${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i?86:AIX:*:*) echo i386-ibm-aix exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:4) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=4.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) sed 's/^ //' << EOF >$dummy.c #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` rm -f $dummy.c $dummy esac HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i?86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; hppa*:OpenBSD:*:*) echo hppa-unknown-openbsd exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*X-MP:*:*:*) echo xmp-cray-unicos exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} exit 0 ;; CRAY*T3E:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} exit 0 ;; CRAY-2:*:*:*) echo cray2-cray-unicos exit 0 ;; F300:UNIX_System_V:*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; F301:UNIX_System_V:*:*) echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` exit 0 ;; hp3[0-9][05]:NetBSD:*:*) echo m68k-hp-netbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; i?86:BSD/386:*:* | i?86:BSD/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) if test -x /usr/bin/objformat; then if test "elf" = "`/usr/bin/objformat`"; then echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'` exit 0 fi fi echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:NetBSD:*:*) echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'` exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. ld_help_string=`cd /; ld --help 2>&1` ld_supported_emulations=`echo $ld_help_string \ | sed -ne '/supported emulations:/!d s/[ ][ ]*/ /g s/.*supported emulations: *// s/ .*// p'` case "$ld_supported_emulations" in *ia64) echo "${UNAME_MACHINE}-unknown-linux" exit 0 ;; i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; elf32arm*) echo "${UNAME_MACHINE}-unknown-linux-gnu" exit 0 ;; armelf_linux*) echo "${UNAME_MACHINE}-unknown-linux-gnu" exit 0 ;; m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" exit 0 ;; elf32ppc) # Determine Lib Version cat >$dummy.c < #if defined(__GLIBC__) extern char __libc_version[]; extern char __libc_release[]; #endif main(argc, argv) int argc; char *argv[]; { #if defined(__GLIBC__) printf("%s %s\n", __libc_version, __libc_release); #else printf("unkown\n"); #endif return 0; } EOF LIBC="" $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null if test "$?" = 0 ; then ./$dummy | grep 1\.99 > /dev/null if test "$?" = 0 ; then LIBC="libc1" fi fi rm -f $dummy.c $dummy echo powerpc-unknown-linux-gnu${LIBC} exit 0 ;; esac if test "${UNAME_MACHINE}" = "alpha" ; then sed 's/^ //' <$dummy.s .globl main .ent main main: .frame \$30,0,\$26,0 .prologue 0 .long 0x47e03d80 # implver $0 lda \$2,259 .long 0x47e20c21 # amask $2,$1 srl \$1,8,\$2 sll \$2,2,\$2 sll \$0,3,\$0 addl \$1,\$0,\$0 addl \$2,\$0,\$0 ret \$31,(\$26),1 .end main EOF LIBC="" $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then ./$dummy case "$?" in 7) UNAME_MACHINE="alpha" ;; 15) UNAME_MACHINE="alphaev5" ;; 14) UNAME_MACHINE="alphaev56" ;; 10) UNAME_MACHINE="alphapca56" ;; 16) UNAME_MACHINE="alphaev6" ;; esac objdump --private-headers $dummy | \ grep ld.so.1 > /dev/null if test "$?" = 0 ; then LIBC="libc1" fi fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 elif test "${UNAME_MACHINE}" = "mips" ; then cat >$dummy.c </dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy else # Either a pre-BFD a.out linker (linux-gnuoldld) # or one that does not give us useful --help. # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. # If ld does not provide *any* "supported emulations:" # that means it is gnuoldld. echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 case "${UNAME_MACHINE}" in i?86) VENDOR=pc; ;; *) VENDOR=unknown; ;; esac # Determine whether the default compiler is a.out or elf cat >$dummy.c < #ifdef __cplusplus int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif # else printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); # endif #else printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy fi ;; # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions # are messed up and put the nodename in both sysname and nodename. i?86:DYNIX/ptx:4*:*) echo i386-sequent-sysv4 exit 0 ;; i?86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i?86:*:5:7*) # Fixed at (any) Pentium or better UNAME_MACHINE=i586 if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} fi exit 0 ;; i?86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:*:6*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-qnx-qnx${UNAME_VERSION} exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) printf ("vax-dec-bsd\n"); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi #echo '(Unable to guess system type)' 1>&2 exit 1 privoxy-3.0.21-stable/./pcre/config.in000640 001751 001751 00000002632 10546014100 016502 0ustar00fkfk000000 000000 /* On Unix systems config.in is converted by configure into config.h. PCRE is written in Standard C, but there are a few non-standard things it can cope with, allowing it to run on SunOS4 and other "close to standard" systems. On a non-Unix system you should just copy this file into config.h and change the definitions of HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf works, these cannot be made the defaults. If your system has bcopy() and not memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your system has neither bcopy() nor memmove(), leave them both as 0; an emulation function will be used. */ /* Define to empty if the keyword does not work. */ #undef const /* Define to `unsigned' if doesn't define size_t. */ #undef size_t /* The following two definitions are mainly for the benefit of SunOS4, which doesn't have the strerror() or memmove() functions that should be present in all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should normally be defined with the value 1 for other systems, but unfortunately we can't make this the default because "configure" files generated by autoconf will only change 0 to 1; they won't change 1 to 0 if the functions are not found. If HAVE_MEMMOVE is set to 1, the value of HAVE_BCOPY is not relevant. */ #define HAVE_STRERROR 0 #define HAVE_MEMMOVE 0 #define HAVE_BCOPY 0 /* End */ privoxy-3.0.21-stable/./pcre/dftables.c000640 001751 001751 00000011035 10546014100 016632 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- See the file Tech.Notes for some information on the internals. */ /* This is a support program to generate the file chartables.c, containing character tables of various kinds. They are built according to the default C locale and used as the default tables by PCRE. Now that pcre_maketables is a function visible to the outside world, we make use of its code from here in order to be consistent. */ #include #include #include #include "internal.h" #define DFTABLES /* maketables.c notices this */ #include "maketables.c" int main(void) { int i; unsigned const char *tables = pcre_maketables(); printf( "/*************************************************\n" "* Perl-Compatible Regular Expressions *\n" "*************************************************/\n\n" "/* This file is automatically written by the dftables auxiliary \n" "program. If you edit it by hand, you might like to edit the Makefile to \n" "prevent its ever being regenerated.\n\n" "This file is #included in the compilation of pcre.c to build the default\n" "character tables which are used when no tables are passed to the compile\n" "function. */\n\n" "static unsigned char pcre_default_tables[] = {\n\n" "/* This table is a lower casing table. */\n\n"); printf(" "); for (i = 0; i < 256; i++) { if ((i & 7) == 0 && i != 0) printf("\n "); printf("%3d", *tables++); if (i != 255) printf(","); } printf(",\n\n"); printf("/* This table is a case flipping table. */\n\n"); printf(" "); for (i = 0; i < 256; i++) { if ((i & 7) == 0 && i != 0) printf("\n "); printf("%3d", *tables++); if (i != 255) printf(","); } printf(",\n\n"); printf( "/* This table contains bit maps for various character classes.\n" "Each map is 32 bytes long and the bits run from the least\n" "significant end of each byte. The classes that have their own\n" "maps are: space, xdigit, digit, upper, lower, word, graph\n" "print, punct, and cntrl. Other classes are built from combinations. */\n\n"); printf(" "); for (i = 0; i < cbit_length; i++) { if ((i & 7) == 0 && i != 0) { if ((i & 31) == 0) printf("\n"); printf("\n "); } printf("0x%02x", *tables++); if (i != cbit_length - 1) printf(","); } printf(",\n\n"); printf( "/* This table identifies various classes of character by individual bits:\n" " 0x%02x white space character\n" " 0x%02x letter\n" " 0x%02x decimal digit\n" " 0x%02x hexadecimal digit\n" " 0x%02x alphanumeric or '_'\n" " 0x%02x regular expression metacharacter or binary zero\n*/\n\n", ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word, ctype_meta); printf(" "); for (i = 0; i < 256; i++) { if ((i & 7) == 0 && i != 0) { printf(" /* "); if (isprint(i-8)) printf(" %c -", i-8); else printf("%3d-", i-8); if (isprint(i-1)) printf(" %c ", i-1); else printf("%3d", i-1); printf(" */\n "); } printf("0x%02x", *tables++); if (i != 255) printf(","); } printf("};/* "); if (isprint(i-8)) printf(" %c -", i-8); else printf("%3d-", i-8); if (isprint(i-1)) printf(" %c ", i-1); else printf("%3d", i-1); printf(" */\n\n/* End of chartables.c */\n"); return 0; } /* End of dftables.c */ privoxy-3.0.21-stable/./pcre/internal.h000640 001751 001751 00000036232 10546014100 016675 0ustar00fkfk000000 000000 /************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. See the file Tech.Notes for some information on the internals. Written by: Philip Hazel Copyright (c) 1997-2000 University of Cambridge ----------------------------------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), then the terms of that licence shall supersede any condition above with which it is incompatible. ----------------------------------------------------------------------------- */ /* This header contains definitions that are shared between the different modules, but which are not relevant to the outside. */ /* Get the definitions provided by running "configure" */ #include "config.h" /* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY is set. Otherwise, include an emulating function for those systems that have neither (there some non-Unix environments where this is the case). This assumes that all calls to memmove are moving strings upwards in store, which is the case in PCRE. */ #if ! HAVE_MEMMOVE #undef memmove /* some systems may have a macro */ #if HAVE_BCOPY #define memmove(a, b, c) bcopy(b, a, c) #else void * pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n) { int i; dest += n; src += n; for (i = 0; i < n; ++i) *(--dest) = *(--src); } #define memmove(a, b, c) pcre_memmove(a, b, c) #endif #endif /* Standard C headers plus the external interface definition */ #include #include #include #include #include #include #include "pcre.h" /* In case there is no definition of offsetof() provided - though any proper Standard C system should have one. */ #ifndef offsetof #define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) #endif /* These are the public options that can change during matching. */ #define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL) /* Private options flags start at the most significant end of the four bytes, but skip the top bit so we can use ints for convenience without getting tangled with negative values. The public options defined in pcre.h start at the least significant end. Make sure they don't overlap, though now that we have expanded to four bytes there is plenty of space. */ #define PCRE_FIRSTSET 0x40000000 /* first_char is set */ #define PCRE_REQCHSET 0x20000000 /* req_char is set */ #define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */ #define PCRE_INGROUP 0x08000000 /* compiling inside a group */ #define PCRE_ICHANGED 0x04000000 /* i option changes within regex */ /* Options for the "extra" block produced by pcre_study(). */ #define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ /* Masks for identifying the public options which are permitted at compile time, run time or study time, respectively. */ #define PUBLIC_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY) #define PUBLIC_STUDY_OPTIONS 0 /* None defined */ /* Magic number to provide a small check against being handed junk. */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ /* Miscellaneous definitions */ typedef int BOOL; #define FALSE 0 #define TRUE 1 /* These are escaped items that aren't just an encoding of a particular data value such as \n. They must have non-zero values, as check_escape() returns their negation. Also, they must appear in the same order as in the opcode definitions below, up to ESC_z. The final one must be ESC_REF as subsequent values are used for \1, \2, \3, etc. There is a test in the code for an escape greater than ESC_b and less than ESC_X to detect the types that may be repeated. If any new escapes are put in-between that don't consume a character, that code will have to change. */ enum { ESC_A = 1, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_Z, ESC_z, ESC_REF }; /* Opcode table: OP_BRA must be last, as all values >= it are used for brackets that extract substrings. Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in order to the list of escapes immediately above. */ enum { OP_END, /* End of pattern */ /* Values corresponding to backslashed metacharacters */ OP_SOD, /* Start of data: \A */ OP_NOT_WORD_BOUNDARY, /* \B */ OP_WORD_BOUNDARY, /* \b */ OP_NOT_DIGIT, /* \D */ OP_DIGIT, /* \d */ OP_NOT_WHITESPACE, /* \S */ OP_WHITESPACE, /* \s */ OP_NOT_WORDCHAR, /* \W */ OP_WORDCHAR, /* \w */ OP_EODN, /* End of data or \n at end of data: \Z. */ OP_EOD, /* End of data: \z */ OP_OPT, /* Set runtime options */ OP_CIRC, /* Start of line - varies with multiline switch */ OP_DOLL, /* End of line - varies with multiline switch */ OP_ANY, /* Match any character */ OP_CHARS, /* Match string of characters */ OP_NOT, /* Match anything but the following char */ OP_STAR, /* The maximizing and minimizing versions of */ OP_MINSTAR, /* all these opcodes must come in pairs, with */ OP_PLUS, /* the minimizing one second. */ OP_MINPLUS, /* This first set applies to single characters */ OP_QUERY, OP_MINQUERY, OP_UPTO, /* From 0 to n matches */ OP_MINUPTO, OP_EXACT, /* Exactly n matches */ OP_NOTSTAR, /* The maximizing and minimizing versions of */ OP_NOTMINSTAR, /* all these opcodes must come in pairs, with */ OP_NOTPLUS, /* the minimizing one second. */ OP_NOTMINPLUS, /* This first set applies to "not" single characters */ OP_NOTQUERY, OP_NOTMINQUERY, OP_NOTUPTO, /* From 0 to n matches */ OP_NOTMINUPTO, OP_NOTEXACT, /* Exactly n matches */ OP_TYPESTAR, /* The maximizing and minimizing versions of */ OP_TYPEMINSTAR, /* all these opcodes must come in pairs, with */ OP_TYPEPLUS, /* the minimizing one second. These codes must */ OP_TYPEMINPLUS, /* be in exactly the same order as those above. */ OP_TYPEQUERY, /* This set applies to character types such as \d */ OP_TYPEMINQUERY, OP_TYPEUPTO, /* From 0 to n matches */ OP_TYPEMINUPTO, OP_TYPEEXACT, /* Exactly n matches */ OP_CRSTAR, /* The maximizing and minimizing versions of */ OP_CRMINSTAR, /* all these opcodes must come in pairs, with */ OP_CRPLUS, /* the minimizing one second. These codes must */ OP_CRMINPLUS, /* be in exactly the same order as those above. */ OP_CRQUERY, /* These are for character classes and back refs */ OP_CRMINQUERY, OP_CRRANGE, /* These are different to the three seta above. */ OP_CRMINRANGE, OP_CLASS, /* Match a character class */ OP_REF, /* Match a back reference */ OP_RECURSE, /* Match this pattern recursively */ OP_ALT, /* Start of alternation */ OP_KET, /* End of group that doesn't have an unbounded repeat */ OP_KETRMAX, /* These two must remain together and in this */ OP_KETRMIN, /* order. They are for groups the repeat for ever. */ /* The assertions must come before ONCE and COND */ OP_ASSERT, /* Positive lookahead */ OP_ASSERT_NOT, /* Negative lookahead */ OP_ASSERTBACK, /* Positive lookbehind */ OP_ASSERTBACK_NOT, /* Negative lookbehind */ OP_REVERSE, /* Move pointer back - used in lookbehind assertions */ /* ONCE and COND must come after the assertions, with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an assertion. */ OP_ONCE, /* Once matched, don't back up into the subpattern */ OP_COND, /* Conditional group */ OP_CREF, /* Used to hold an extraction string number */ OP_BRAZERO, /* These two must remain together and in this */ OP_BRAMINZERO, /* order. */ OP_BRA /* This and greater values are used for brackets that extract substrings. */ }; /* The highest extraction number. This is limited by the number of opcodes left after OP_BRA, i.e. 255 - OP_BRA. We actually set it somewhat lower. */ #define EXTRACT_MAX 99 /* The texts of compile-time error messages are defined as macros here so that they can be accessed by the POSIX wrapper and converted into error codes. Yes, I could have used error codes in the first place, but didn't feel like changing just to accommodate the POSIX wrapper. */ #define ERR1 "\\ at end of pattern" #define ERR2 "\\c at end of pattern" #define ERR3 "unrecognized character follows \\" #define ERR4 "numbers out of order in {} quantifier" #define ERR5 "number too big in {} quantifier" #define ERR6 "missing terminating ] for character class" #define ERR7 "invalid escape sequence in character class" #define ERR8 "range out of order in character class" #define ERR9 "nothing to repeat" #define ERR10 "operand of unlimited repeat could match the empty string" #define ERR11 "internal error: unexpected repeat" #define ERR12 "unrecognized character after (?" #define ERR13 "too many capturing parenthesized sub-patterns" #define ERR14 "missing )" #define ERR15 "back reference to non-existent subpattern" #define ERR16 "erroffset passed as NULL" #define ERR17 "unknown option bit(s) set" #define ERR18 "missing ) after comment" #define ERR19 "too many sets of parentheses" #define ERR20 "regular expression too large" #define ERR21 "failed to get memory" #define ERR22 "unmatched parentheses" #define ERR23 "internal error: code overflow" #define ERR24 "unrecognized character after (?<" #define ERR25 "lookbehind assertion is not fixed length" #define ERR26 "malformed number after (?(" #define ERR27 "conditional group contains more than two branches" #define ERR28 "assertion expected after (?(" #define ERR29 "(?p must be followed by )" #define ERR30 "unknown POSIX class name" #define ERR31 "POSIX collating elements are not supported" #define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support" #define ERR33 "characters with values > 255 are not yet supported in classes" #define ERR34 "character value in \\x{...} sequence is too large" #define ERR35 "invalid condition (?(0)" /* All character handling must be done as unsigned characters. Otherwise there are problems with top-bit-set characters and functions such as isspace(). However, we leave the interface to the outside world as char *, because that should make things easier for callers. We define a short type for unsigned char to save lots of typing. I tried "uchar", but it causes problems on Digital Unix, where it is defined in sys/types, so use "uschar" instead. */ typedef unsigned char uschar; /* The real format of the start of the pcre block; the actual code vector runs on as long as necessary after the end. */ typedef struct real_pcre { unsigned long int magic_number; size_t size; const unsigned char *tables; unsigned long int options; uschar top_bracket; uschar top_backref; uschar first_char; uschar req_char; uschar code[1]; } real_pcre; /* The real format of the extra block returned by pcre_study(). */ typedef struct real_pcre_extra { uschar options; uschar start_bits[32]; } real_pcre_extra; /* Structure for passing "static" information around between the functions doing the compiling, so that they are thread-safe. */ typedef struct compile_data { const uschar *lcc; /* Points to lower casing table */ const uschar *fcc; /* Points to case-flipping table */ const uschar *cbits; /* Points to character type table */ const uschar *ctypes; /* Points to table of type maps */ } compile_data; /* Structure for passing "static" information around between the functions doing the matching, so that they are thread-safe. */ typedef struct match_data { int errorcode; /* As it says */ int *offset_vector; /* Offset vector */ int offset_end; /* One past the end */ int offset_max; /* The maximum usable for return data */ const uschar *lcc; /* Points to lower casing table */ const uschar *ctypes; /* Points to table of type maps */ BOOL offset_overflow; /* Set if too many extractions */ BOOL notbol; /* NOTBOL flag */ BOOL noteol; /* NOTEOL flag */ BOOL utf8; /* UTF8 flag */ BOOL endonly; /* Dollar not before final \n */ BOOL notempty; /* Empty string match not wanted */ const uschar *start_pattern; /* For use when recursing */ const uschar *start_subject; /* Start of the subject string */ const uschar *end_subject; /* End of the subject string */ const uschar *start_match; /* Start of this match attempt */ const uschar *end_match_ptr; /* Subject position at end match */ int end_offset_top; /* Highwater mark at end of match */ } match_data; /* Bit definitions for entries in the pcre_ctypes table. */ #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 #define ctype_xdigit 0x08 #define ctype_word 0x10 /* alphameric or '_' */ #define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ /* Offsets for the bitmap tables in pcre_cbits. Each table contains a set of bits for a class map. Some classes are built by combining these tables. */ #define cbit_space 0 /* [:space:] or \s */ #define cbit_xdigit 32 /* [:xdigit:] */ #define cbit_digit 64 /* [:digit:] or \d */ #define cbit_upper 96 /* [:upper:] */ #define cbit_lower 128 /* [:lower:] */ #define cbit_word 160 /* [:word:] or \w */ #define cbit_graph 192 /* [:graph:] */ #define cbit_print 224 /* [:print:] */ #define cbit_punct 256 /* [:punct:] */ #define cbit_cntrl 288 /* [:cntrl:] */ #define cbit_length 320 /* Length of the cbits table */ /* Offsets of the various tables from the base tables pointer, and total length. */ #define lcc_offset 0 #define fcc_offset 256 #define cbits_offset 512 #define ctypes_offset (cbits_offset + cbit_length) #define tables_length (ctypes_offset + 256) /* End of internal.h */ privoxy-3.0.21-stable/./pcre/pcretest.c000640 001751 001751 00000077456 10546014100 016722 0ustar00fkfk000000 000000 /************************************************* * PCRE testing program * *************************************************/ #include #include #include #include #include #include /* Use the internal info for displaying the results of pcre_study(). */ #include "internal.h" /* It is possible to compile this test program without including support for testing the POSIX interface, though this is not available via the standard Makefile. */ #if !defined NOPOSIX #include "pcreposix.h" #endif #ifndef CLOCKS_PER_SEC #ifdef CLK_TCK #define CLOCKS_PER_SEC CLK_TCK #else #define CLOCKS_PER_SEC 100 #endif #endif #define LOOPREPEAT 20000 static FILE *outfile; static int log_store = 0; static size_t gotten_store; static int utf8_table1[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff}; static int utf8_table2[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; static int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; /************************************************* * Convert character value to UTF-8 * *************************************************/ /* This function takes an integer value in the range 0 - 0x7fffffff and encodes it as a UTF-8 character in 0 to 6 bytes. Arguments: cvalue the character value buffer pointer to buffer for result - at least 6 bytes long Returns: number of characters placed in the buffer -1 if input character is negative 0 if input character is positive but too big (only when int is longer than 32 bits) */ static int ord2utf8(int cvalue, unsigned char *buffer) { register int i, j; for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++) if (cvalue <= utf8_table1[i]) break; if (i >= sizeof(utf8_table1)/sizeof(int)) return 0; if (cvalue < 0) return -1; *buffer++ = utf8_table2[i] | (cvalue & utf8_table3[i]); cvalue >>= 6 - i; for (j = 0; j < i; j++) { *buffer++ = 0x80 | (cvalue & 0x3f); cvalue >>= 6; } return i + 1; } /************************************************* * Convert UTF-8 string to value * *************************************************/ /* This function takes one or more bytes that represents a UTF-8 character, and returns the value of the character. Argument: buffer a pointer to the byte vector vptr a pointer to an int to receive the value Returns: > 0 => the number of bytes consumed -6 to 0 => malformed UTF-8 character at offset = (-return) */ int utf82ord(unsigned char *buffer, int *vptr) { int c = *buffer++; int d = c; int i, j, s; for (i = -1; i < 6; i++) /* i is number of additional bytes */ { if ((d & 0x80) == 0) break; d <<= 1; } if (i == -1) { *vptr = c; return 1; } /* ascii character */ if (i == 0 || i == 6) return 0; /* invalid UTF-8 */ /* i now has a value in the range 1-5 */ d = c & utf8_table3[i]; s = 6 - i; for (j = 0; j < i; j++) { c = *buffer++; if ((c & 0xc0) != 0x80) return -(j+1); d |= (c & 0x3f) << s; s += 6; } /* Check that encoding was the correct unique one */ for (j = 0; j < sizeof(utf8_table1)/sizeof(int); j++) if (d <= utf8_table1[j]) break; if (j != i) return -(i+1); /* Valid value */ *vptr = d; return i+1; } /* Debugging function to print the internal form of the regex. This is the same code as contained in pcre.c under the DEBUG macro. */ static const char *OP_names[] = { "End", "\\A", "\\B", "\\b", "\\D", "\\d", "\\S", "\\s", "\\W", "\\w", "\\Z", "\\z", "Opt", "^", "$", "Any", "chars", "not", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "{", "*", "*?", "+", "+?", "?", "??", "{", "{", "class", "Ref", "Recurse", "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cref", "Brazero", "Braminzero", "Bra" }; static void print_internals(pcre *re) { unsigned char *code = ((real_pcre *)re)->code; fprintf(outfile, "------------------------------------------------------------------\n"); for(;;) { int c; int charlength; fprintf(outfile, "%3d ", (int)(code - ((real_pcre *)re)->code)); if (*code >= OP_BRA) { fprintf(outfile, "%3d Bra %d", (code[1] << 8) + code[2], *code - OP_BRA); code += 2; } else switch(*code) { case OP_END: fprintf(outfile, " %s\n", OP_names[*code]); fprintf(outfile, "------------------------------------------------------------------\n"); return; case OP_OPT: fprintf(outfile, " %.2x %s", code[1], OP_names[*code]); code++; break; case OP_COND: fprintf(outfile, "%3d Cond", (code[1] << 8) + code[2]); code += 2; break; case OP_CREF: fprintf(outfile, " %.2d %s", code[1], OP_names[*code]); code++; break; case OP_CHARS: charlength = *(++code); fprintf(outfile, "%3d ", charlength); while (charlength-- > 0) if (isprint(c = *(++code))) fprintf(outfile, "%c", c); else fprintf(outfile, "\\x%02x", c); break; case OP_KETRMAX: case OP_KETRMIN: case OP_ALT: case OP_KET: case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: fprintf(outfile, "%3d %s", (code[1] << 8) + code[2], OP_names[*code]); code += 2; break; case OP_REVERSE: fprintf(outfile, "%3d %s", (code[1] << 8) + code[2], OP_names[*code]); code += 2; break; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: if (*code >= OP_TYPESTAR) fprintf(outfile, " %s", OP_names[code[1]]); else if (isprint(c = code[1])) fprintf(outfile, " %c", c); else fprintf(outfile, " \\x%02x", c); fprintf(outfile, "%s", OP_names[*code++]); break; case OP_EXACT: case OP_UPTO: case OP_MINUPTO: if (isprint(c = code[3])) fprintf(outfile, " %c{", c); else fprintf(outfile, " \\x%02x{", c); if (*code != OP_EXACT) fprintf(outfile, ","); fprintf(outfile, "%d}", (code[1] << 8) + code[2]); if (*code == OP_MINUPTO) fprintf(outfile, "?"); code += 3; break; case OP_TYPEEXACT: case OP_TYPEUPTO: case OP_TYPEMINUPTO: fprintf(outfile, " %s{", OP_names[code[3]]); if (*code != OP_TYPEEXACT) fprintf(outfile, "0,"); fprintf(outfile, "%d}", (code[1] << 8) + code[2]); if (*code == OP_TYPEMINUPTO) fprintf(outfile, "?"); code += 3; break; case OP_NOT: if (isprint(c = *(++code))) fprintf(outfile, " [^%c]", c); else fprintf(outfile, " [^\\x%02x]", c); break; case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: if (isprint(c = code[1])) fprintf(outfile, " [^%c]", c); else fprintf(outfile, " [^\\x%02x]", c); fprintf(outfile, "%s", OP_names[*code++]); break; case OP_NOTEXACT: case OP_NOTUPTO: case OP_NOTMINUPTO: if (isprint(c = code[3])) fprintf(outfile, " [^%c]{", c); else fprintf(outfile, " [^\\x%02x]{", c); if (*code != OP_NOTEXACT) fprintf(outfile, ","); fprintf(outfile, "%d}", (code[1] << 8) + code[2]); if (*code == OP_NOTMINUPTO) fprintf(outfile, "?"); code += 3; break; case OP_REF: fprintf(outfile, " \\%d", *(++code)); code++; goto CLASS_REF_REPEAT; case OP_CLASS: { int i, min, max; code++; fprintf(outfile, " ["); for (i = 0; i < 256; i++) { if ((code[i/8] & (1 << (i&7))) != 0) { int j; for (j = i+1; j < 256; j++) if ((code[j/8] & (1 << (j&7))) == 0) break; if (i == '-' || i == ']') fprintf(outfile, "\\"); if (isprint(i)) fprintf(outfile, "%c", i); else fprintf(outfile, "\\x%02x", i); if (--j > i) { fprintf(outfile, "-"); if (j == '-' || j == ']') fprintf(outfile, "\\"); if (isprint(j)) fprintf(outfile, "%c", j); else fprintf(outfile, "\\x%02x", j); } i = j; } } fprintf(outfile, "]"); code += 32; CLASS_REF_REPEAT: switch(*code) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: fprintf(outfile, "%s", OP_names[*code]); break; case OP_CRRANGE: case OP_CRMINRANGE: min = (code[1] << 8) + code[2]; max = (code[3] << 8) + code[4]; if (max == 0) fprintf(outfile, "{%d,}", min); else fprintf(outfile, "{%d,%d}", min, max); if (*code == OP_CRMINRANGE) fprintf(outfile, "?"); code += 4; break; default: code--; } } break; /* Anything else is just a one-node item */ default: fprintf(outfile, " %s", OP_names[*code]); break; } code++; fprintf(outfile, "\n"); } } /* Character string printing function. A "normal" and a UTF-8 version. */ static void pchars(unsigned char *p, int length, int utf8) { int c; while (length-- > 0) { if (utf8) { int rc = utf82ord(p, &c); if (rc > 0) { length -= rc - 1; p += rc; if (c < 256 && isprint(c)) fprintf(outfile, "%c", c); else fprintf(outfile, "\\x{%02x}", c); continue; } } /* Not UTF-8, or malformed UTF-8 */ if (isprint(c = *(p++))) fprintf(outfile, "%c", c); else fprintf(outfile, "\\x%02x", c); } } /* Alternative malloc function, to test functionality and show the size of the compiled re. */ static void *new_malloc(size_t size) { gotten_store = size; if (log_store) fprintf(outfile, "Memory allocation (code space): %d\n", (int)((int)size - offsetof(real_pcre, code[0]))); return malloc(size); } /* Get one piece of information from the pcre_fullinfo() function */ static void new_info(pcre *re, pcre_extra *study, int option, void *ptr) { int rc; if ((rc = pcre_fullinfo(re, study, option, ptr)) < 0) fprintf(outfile, "Error %d from pcre_fullinfo(%d)\n", rc, option); } /* Read lines from named file or stdin and write to named file or stdout; lines consist of a regular expression, in delimiters and optionally followed by options, followed by a set of test data, terminated by an empty line. */ int main(int argc, char **argv) { FILE *infile = stdin; int options = 0; int study_options = 0; int op = 1; int timeit = 0; int showinfo = 0; int showstore = 0; int posix = 0; int debug = 0; int done = 0; unsigned char buffer[30000]; unsigned char dbuffer[1024]; /* Static so that new_malloc can use it. */ outfile = stdout; /* Scan options */ while (argc > 1 && argv[op][0] == '-') { if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0) showstore = 1; else if (strcmp(argv[op], "-t") == 0) timeit = 1; else if (strcmp(argv[op], "-i") == 0) showinfo = 1; else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1; else if (strcmp(argv[op], "-p") == 0) posix = 1; else { printf("*** Unknown option %s\n", argv[op]); printf("Usage: pcretest [-d] [-i] [-p] [-s] [-t] [ []]\n"); printf(" -d debug: show compiled code; implies -i\n" " -i show information about compiled pattern\n" " -p use POSIX interface\n" " -s output store information\n" " -t time compilation and execution\n"); return 1; } op++; argc--; } /* Sort out the input and output files */ if (argc > 1) { infile = fopen(argv[op], "r"); if (infile == NULL) { printf("** Failed to open %s\n", argv[op]); return 1; } } if (argc > 2) { outfile = fopen(argv[op+1], "w"); if (outfile == NULL) { printf("** Failed to open %s\n", argv[op+1]); return 1; } } /* Set alternative malloc function */ pcre_malloc = new_malloc; /* Heading line, then prompt for first regex if stdin */ fprintf(outfile, "PCRE version %s\n\n", pcre_version()); /* Main loop */ while (!done) { pcre *re = NULL; pcre_extra *extra = NULL; #if !defined NOPOSIX /* There are still compilers that require no indent */ regex_t preg; int do_posix = 0; #endif const char *error; unsigned char *p, *pp, *ppp; unsigned const char *tables = NULL; int do_study = 0; int do_debug = debug; int do_G = 0; int do_g = 0; int do_showinfo = showinfo; int do_showrest = 0; int utf8 = 0; int erroroffset, len, delimiter; if (infile == stdin) printf(" re> "); if (fgets((char *)buffer, sizeof(buffer), infile) == NULL) break; if (infile != stdin) fprintf(outfile, "%s", (char *)buffer); p = buffer; while (isspace(*p)) p++; if (*p == 0) continue; /* Get the delimiter and seek the end of the pattern; if is isn't complete, read more. */ delimiter = *p++; if (isalnum(delimiter) || delimiter == '\\') { fprintf(outfile, "** Delimiter must not be alphameric or \\\n"); goto SKIP_DATA; } pp = p; for(;;) { while (*pp != 0) { if (*pp == '\\' && pp[1] != 0) pp++; else if (*pp == delimiter) break; pp++; } if (*pp != 0) break; len = sizeof(buffer) - (pp - buffer); if (len < 256) { fprintf(outfile, "** Expression too long - missing delimiter?\n"); goto SKIP_DATA; } if (infile == stdin) printf(" > "); if (fgets((char *)pp, len, infile) == NULL) { fprintf(outfile, "** Unexpected EOF\n"); done = 1; goto CONTINUE; } if (infile != stdin) fprintf(outfile, "%s", (char *)pp); } /* If the first character after the delimiter is backslash, make the pattern end with backslash. This is purely to provide a way of testing for the error message when a pattern ends with backslash. */ if (pp[1] == '\\') *pp++ = '\\'; /* Terminate the pattern at the delimiter */ *pp++ = 0; /* Look for options after final delimiter */ options = 0; study_options = 0; log_store = showstore; /* default from command line */ while (*pp != 0) { switch (*pp++) { case 'g': do_g = 1; break; case 'i': options |= PCRE_CASELESS; break; case 'm': options |= PCRE_MULTILINE; break; case 's': options |= PCRE_DOTALL; break; case 'x': options |= PCRE_EXTENDED; break; case '+': do_showrest = 1; break; case 'A': options |= PCRE_ANCHORED; break; case 'D': do_debug = do_showinfo = 1; break; case 'E': options |= PCRE_DOLLAR_ENDONLY; break; case 'G': do_G = 1; break; case 'I': do_showinfo = 1; break; case 'M': log_store = 1; break; #if !defined NOPOSIX case 'P': do_posix = 1; break; #endif case 'S': do_study = 1; break; case 'U': options |= PCRE_UNGREEDY; break; case 'X': options |= PCRE_EXTRA; break; case '8': options |= PCRE_UTF8; utf8 = 1; break; case 'L': ppp = pp; while (*ppp != '\n' && *ppp != ' ') ppp++; *ppp = 0; if (setlocale(LC_CTYPE, (const char *)pp) == NULL) { fprintf(outfile, "** Failed to set locale \"%s\"\n", pp); goto SKIP_DATA; } tables = pcre_maketables(); pp = ppp; break; case '\n': case ' ': break; default: fprintf(outfile, "** Unknown option '%c'\n", pp[-1]); goto SKIP_DATA; } } /* Handle compiling via the POSIX interface, which doesn't support the timing, showing, or debugging options, nor the ability to pass over local character tables. */ #if !defined NOPOSIX if (posix || do_posix) { int rc; int cflags = 0; if ((options & PCRE_CASELESS) != 0) cflags |= REG_ICASE; if ((options & PCRE_MULTILINE) != 0) cflags |= REG_NEWLINE; rc = regcomp(&preg, (char *)p, cflags); /* Compilation failed; go back for another re, skipping to blank line if non-interactive. */ if (rc != 0) { (void)regerror(rc, &preg, (char *)buffer, sizeof(buffer)); fprintf(outfile, "Failed: POSIX code %d: %s\n", rc, buffer); goto SKIP_DATA; } } /* Handle compiling via the native interface */ else #endif /* !defined NOPOSIX */ { if (timeit) { register int i; clock_t time_taken; clock_t start_time = clock(); for (i = 0; i < LOOPREPEAT; i++) { re = pcre_compile((char *)p, options, &error, &erroroffset, tables); if (re != NULL) free(re); } time_taken = clock() - start_time; fprintf(outfile, "Compile time %.3f milliseconds\n", ((double)time_taken * 1000.0) / ((double)LOOPREPEAT * (double)CLOCKS_PER_SEC)); } re = pcre_compile((char *)p, options, &error, &erroroffset, tables); /* Compilation failed; go back for another re, skipping to blank line if non-interactive. */ if (re == NULL) { fprintf(outfile, "Failed: %s at offset %d\n", error, erroroffset); SKIP_DATA: if (infile != stdin) { for (;;) { if (fgets((char *)buffer, sizeof(buffer), infile) == NULL) { done = 1; goto CONTINUE; } len = (int)strlen((char *)buffer); while (len > 0 && isspace(buffer[len-1])) len--; if (len == 0) break; } fprintf(outfile, "\n"); } goto CONTINUE; } /* Compilation succeeded; print data if required. There are now two info-returning functions. The old one has a limited interface and returns only limited data. Check that it agrees with the newer one. */ if (do_showinfo) { int old_first_char, old_options, old_count; int count, backrefmax, first_char, need_char; size_t size; if (do_debug) print_internals(re); new_info(re, NULL, PCRE_INFO_OPTIONS, &options); new_info(re, NULL, PCRE_INFO_SIZE, &size); new_info(re, NULL, PCRE_INFO_CAPTURECOUNT, &count); new_info(re, NULL, PCRE_INFO_BACKREFMAX, &backrefmax); new_info(re, NULL, PCRE_INFO_FIRSTCHAR, &first_char); new_info(re, NULL, PCRE_INFO_LASTLITERAL, &need_char); old_count = pcre_info(re, &old_options, &old_first_char); if (count < 0) fprintf(outfile, "Error %d from pcre_info()\n", count); else { if (old_count != count) fprintf(outfile, "Count disagreement: pcre_fullinfo=%d pcre_info=%d\n", count, old_count); if (old_first_char != first_char) fprintf(outfile, "First char disagreement: pcre_fullinfo=%d pcre_info=%d\n", first_char, old_first_char); if (old_options != options) fprintf(outfile, "Options disagreement: pcre_fullinfo=%d pcre_info=%d\n", options, old_options); } if (size != gotten_store) fprintf(outfile, "Size disagreement: pcre_fullinfo=%d call to malloc for %d\n", size, gotten_store); fprintf(outfile, "Capturing subpattern count = %d\n", count); if (backrefmax > 0) fprintf(outfile, "Max back reference = %d\n", backrefmax); if (options == 0) fprintf(outfile, "No options\n"); else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s\n", ((options & PCRE_ANCHORED) != 0)? " anchored" : "", ((options & PCRE_CASELESS) != 0)? " caseless" : "", ((options & PCRE_EXTENDED) != 0)? " extended" : "", ((options & PCRE_MULTILINE) != 0)? " multiline" : "", ((options & PCRE_DOTALL) != 0)? " dotall" : "", ((options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "", ((options & PCRE_EXTRA) != 0)? " extra" : "", ((options & PCRE_UNGREEDY) != 0)? " ungreedy" : "", ((options & PCRE_UTF8) != 0)? " utf8" : ""); if (((((real_pcre *)re)->options) & PCRE_ICHANGED) != 0) fprintf(outfile, "Case state changes\n"); if (first_char == -1) { fprintf(outfile, "First char at start or follows \\n\n"); } else if (first_char < 0) { fprintf(outfile, "No first char\n"); } else { if (isprint(first_char)) fprintf(outfile, "First char = \'%c\'\n", first_char); else fprintf(outfile, "First char = %d\n", first_char); } if (need_char < 0) { fprintf(outfile, "No need char\n"); } else { if (isprint(need_char)) fprintf(outfile, "Need char = \'%c\'\n", need_char); else fprintf(outfile, "Need char = %d\n", need_char); } } /* If /S was present, study the regexp to generate additional info to help with the matching. */ if (do_study) { if (timeit) { register int i; clock_t time_taken; clock_t start_time = clock(); for (i = 0; i < LOOPREPEAT; i++) extra = pcre_study(re, study_options, &error); time_taken = clock() - start_time; if (extra != NULL) free(extra); fprintf(outfile, " Study time %.3f milliseconds\n", ((double)time_taken * 1000.0)/ ((double)LOOPREPEAT * (double)CLOCKS_PER_SEC)); } extra = pcre_study(re, study_options, &error); if (error != NULL) fprintf(outfile, "Failed to study: %s\n", error); else if (extra == NULL) fprintf(outfile, "Study returned NULL\n"); else if (do_showinfo) { uschar *start_bits = NULL; new_info(re, extra, PCRE_INFO_FIRSTTABLE, &start_bits); if (start_bits == NULL) fprintf(outfile, "No starting character set\n"); else { int i; int c = 24; fprintf(outfile, "Starting character set: "); for (i = 0; i < 256; i++) { if ((start_bits[i/8] & (1<<(i%8))) != 0) { if (c > 75) { fprintf(outfile, "\n "); c = 2; } if (isprint(i) && i != ' ') { fprintf(outfile, "%c ", i); c += 2; } else { fprintf(outfile, "\\x%02x ", i); c += 5; } } } fprintf(outfile, "\n"); } } } } /* Read data lines and test them */ for (;;) { unsigned char *q; unsigned char *bptr = dbuffer; int count, c; int copystrings = 0; int getstrings = 0; int getlist = 0; int gmatched = 0; int start_offset = 0; int g_notempty = 0; int offsets[45]; int size_offsets = sizeof(offsets)/sizeof(int); options = 0; if (infile == stdin) printf("data> "); if (fgets((char *)buffer, sizeof(buffer), infile) == NULL) { done = 1; goto CONTINUE; } if (infile != stdin) fprintf(outfile, "%s", (char *)buffer); len = (int)strlen((char *)buffer); while (len > 0 && isspace(buffer[len-1])) len--; buffer[len] = 0; if (len == 0) break; p = buffer; while (isspace(*p)) p++; q = dbuffer; while ((c = *p++) != 0) { int i = 0; int n = 0; if (c == '\\') switch ((c = *p++)) { case 'a': c = 7; break; case 'b': c = '\b'; break; case 'e': c = 27; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c -= '0'; while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9') c = c * 8 + *p++ - '0'; break; case 'x': /* Handle \x{..} specially - new Perl thing for utf8 */ if (*p == '{') { unsigned char *pt = p; c = 0; while (isxdigit(*(++pt))) c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'W'); if (*pt == '}') { unsigned char buffer[8]; int ii, utn; utn = ord2utf8(c, buffer); for (ii = 0; ii < utn - 1; ii++) *q++ = buffer[ii]; c = buffer[ii]; /* Last byte */ p = pt + 1; break; } /* Not correct form; fall through */ } /* Ordinary \x */ c = 0; while (i++ < 2 && isxdigit(*p)) { c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'W'); p++; } break; case 0: /* Allows for an empty line */ p--; continue; case 'A': /* Option setting */ options |= PCRE_ANCHORED; continue; case 'B': options |= PCRE_NOTBOL; continue; case 'C': while(isdigit(*p)) n = n * 10 + *p++ - '0'; copystrings |= 1 << n; continue; case 'G': while(isdigit(*p)) n = n * 10 + *p++ - '0'; getstrings |= 1 << n; continue; case 'L': getlist = 1; continue; case 'N': options |= PCRE_NOTEMPTY; continue; case 'O': while(isdigit(*p)) n = n * 10 + *p++ - '0'; if (n <= (int)(sizeof(offsets)/sizeof(int))) size_offsets = n; continue; case 'Z': options |= PCRE_NOTEOL; continue; } *q++ = c; } *q = 0; len = q - dbuffer; /* Handle matching via the POSIX interface, which does not support timing. */ #if !defined NOPOSIX if (posix || do_posix) { int rc; int eflags = 0; regmatch_t pmatch[sizeof(offsets)/sizeof(int)]; if ((options & PCRE_NOTBOL) != 0) eflags |= REG_NOTBOL; if ((options & PCRE_NOTEOL) != 0) eflags |= REG_NOTEOL; rc = regexec(&preg, (const char *)bptr, size_offsets, pmatch, eflags); if (rc != 0) { (void)regerror(rc, &preg, (char *)buffer, sizeof(buffer)); fprintf(outfile, "No match: POSIX code %d: %s\n", rc, buffer); } else { size_t i; for (i = 0; i < size_offsets; i++) { if (pmatch[i].rm_so >= 0) { fprintf(outfile, "%2d: ", (int)i); pchars(dbuffer + pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so, utf8); fprintf(outfile, "\n"); if (i == 0 && do_showrest) { fprintf(outfile, " 0+ "); pchars(dbuffer + pmatch[i].rm_eo, len - pmatch[i].rm_eo, utf8); fprintf(outfile, "\n"); } } } } } /* Handle matching via the native interface - repeats for /g and /G */ else #endif /* !defined NOPOSIX */ for (;; gmatched++) /* Loop for /g or /G */ { if (timeit) { register int i; clock_t time_taken; clock_t start_time = clock(); for (i = 0; i < LOOPREPEAT; i++) count = pcre_exec(re, extra, (char *)bptr, len, start_offset, options | g_notempty, offsets, size_offsets); time_taken = clock() - start_time; fprintf(outfile, "Execute time %.3f milliseconds\n", ((double)time_taken * 1000.0)/ ((double)LOOPREPEAT * (double)CLOCKS_PER_SEC)); } count = pcre_exec(re, extra, (char *)bptr, len, start_offset, options | g_notempty, offsets, size_offsets); if (count == 0) { fprintf(outfile, "Matched, but too many substrings\n"); count = size_offsets/3; } /* Matched */ if (count >= 0) { int i; for (i = 0; i < count * 2; i += 2) { if (offsets[i] < 0) fprintf(outfile, "%2d: \n", i/2); else { fprintf(outfile, "%2d: ", i/2); pchars(bptr + offsets[i], offsets[i+1] - offsets[i], utf8); fprintf(outfile, "\n"); if (i == 0) { if (do_showrest) { fprintf(outfile, " 0+ "); pchars(bptr + offsets[i+1], len - offsets[i+1], utf8); fprintf(outfile, "\n"); } } } } for (i = 0; i < 32; i++) { if ((copystrings & (1 << i)) != 0) { char copybuffer[16]; int rc = pcre_copy_substring((char *)bptr, offsets, count, i, copybuffer, sizeof(copybuffer)); if (rc < 0) fprintf(outfile, "copy substring %d failed %d\n", i, rc); else fprintf(outfile, "%2dC %s (%d)\n", i, copybuffer, rc); } } for (i = 0; i < 32; i++) { if ((getstrings & (1 << i)) != 0) { const char *substring; int rc = pcre_get_substring((char *)bptr, offsets, count, i, &substring); if (rc < 0) fprintf(outfile, "get substring %d failed %d\n", i, rc); else { fprintf(outfile, "%2dG %s (%d)\n", i, substring, rc); /* free((void *)substring); */ pcre_free_substring(substring); } } } if (getlist) { const char **stringlist; int rc = pcre_get_substring_list((char *)bptr, offsets, count, &stringlist); if (rc < 0) fprintf(outfile, "get substring list failed %d\n", rc); else { for (i = 0; i < count; i++) fprintf(outfile, "%2dL %s\n", i, stringlist[i]); if (stringlist[i] != NULL) fprintf(outfile, "string list not terminated by NULL\n"); /* free((void *)stringlist); */ pcre_free_substring_list(stringlist); } } } /* Failed to match. If this is a /g or /G loop and we previously set g_notempty after a null match, this is not necessarily the end. We want to advance the start offset, and continue. Fudge the offset values to achieve this. We won't be at the end of the string - that was checked before setting g_notempty. */ else { if (g_notempty != 0) { offsets[0] = start_offset; offsets[1] = start_offset + 1; } else { if (gmatched == 0) /* Error if no previous matches */ { if (count == -1) fprintf(outfile, "No match\n"); else fprintf(outfile, "Error %d\n", count); } break; /* Out of the /g loop */ } } /* If not /g or /G we are done */ if (!do_g && !do_G) break; /* If we have matched an empty string, first check to see if we are at the end of the subject. If so, the /g loop is over. Otherwise, mimic what Perl's /g options does. This turns out to be rather cunning. First we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the same point. If this fails (picked up above) we advance to the next character. */ g_notempty = 0; if (offsets[0] == offsets[1]) { if (offsets[0] == len) break; g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED; } /* For /g, update the start offset, leaving the rest alone */ if (do_g) start_offset = offsets[1]; /* For /G, update the pointer and length */ else { bptr += offsets[1]; len -= offsets[1]; } } /* End of loop for /g and /G */ } /* End of loop for data lines */ CONTINUE: #if !defined NOPOSIX if (posix || do_posix) regfree(&preg); #endif if (re != NULL) free(re); if (extra != NULL) free(extra); if (tables != NULL) { free((void *)tables); setlocale(LC_CTYPE, "C"); } } fprintf(outfile, "\n"); return 0; } /* End */ privoxy-3.0.21-stable/./pcre/pcre.def000640 001751 001751 00000000324 10546014100 016312 0ustar00fkfk000000 000000 EXPORTS pcre_malloc DATA pcre_free DATA pcre_compile pcre_copy_substring pcre_exec pcre_get_substring pcre_get_substring_list pcre_info pcre_maketables pcre_study pcre_version regcomp regexec regerror regfree privoxy-3.0.21-stable/./pcre/RunTest.in000640 001751 001751 00000006542 10546014100 016645 0ustar00fkfk000000 000000 #! /bin/sh # This file is generated by configure from RunTest.in. Make any changes # to that file. # Run PCRE tests cf=diff # Select which tests to run; if no selection, run all do1=no do2=no do3=no do4=no do5=no do6=no while [ $# -gt 0 ] ; do case $1 in 1) do1=yes;; 2) do2=yes;; 3) do3=yes;; 4) do4=yes;; 5) do5=yes;; 6) do6=yes;; *) echo "Unknown test number $1"; exit 1;; esac shift done if [ "@UTF8@" = "" ] ; then if [ $do5 = yes ] ; then echo "Can't run test 5 because UFT8 support is not configured" exit 1 fi if [ $do6 = yes ] ; then echo "Can't run test 6 because UFT8 support is not configured" exit 1 fi fi if [ $do1 = no -a $do2 = no -a $do3 = no -a $do4 = no -a\ $do5 = no -a $do6 = no ] ; then do1=yes do2=yes do3=yes do4=yes if [ "@UTF8@" != "" ] ; then do5=yes; fi if [ "@UTF8@" != "" ] ; then do6=yes; fi fi # Primary test, Perl-compatible if [ $do1 = yes ] ; then echo "Testing main functionality (Perl compatible)" ./pcretest testdata/testinput1 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput1 if [ $? != 0 ] ; then exit 1; fi else exit 1 fi fi # PCRE tests that are not Perl-compatible - API & error tests, mostly if [ $do2 = yes ] ; then echo "Testing API and error handling (not Perl compatible)" ./pcretest -i testdata/testinput2 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput2 if [ $? != 0 ] ; then exit 1; fi else exit 1 fi fi # Additional Perl-compatible tests for Perl 5.005's new features if [ $do3 = yes ] ; then echo "Testing Perl 5.005 features (Perl 5.005 compatible)" ./pcretest testdata/testinput3 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput3 if [ $? != 0 ] ; then exit 1; fi else exit 1 fi fi if [ $do1 = yes -a $do2 = yes -a $do3 = yes ] ; then echo " " echo "The three main tests all ran OK" echo " " fi # Locale-specific tests, provided the "fr" locale is available if [ $do4 = yes ] ; then locale -a | grep '^fr$' >/dev/null if [ $? -eq 0 ] ; then echo "Testing locale-specific features (using 'fr' locale)" ./pcretest testdata/testinput4 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput4 if [ $? != 0 ] ; then echo " " echo "Locale test did not run entirely successfully." echo "This usually means that there is a problem with the locale" echo "settings rather than a bug in PCRE." else echo "Locale test ran OK" fi echo " " else exit 1 fi else echo "Cannot test locale-specific features - 'fr' locale not found," echo "or the \"locale\" command is not available to check for it." echo " " fi fi # Additional tests for UTF8 support if [ $do5 = yes ] ; then echo "Testing experimental, incomplete UTF8 support (Perl compatible)" ./pcretest testdata/testinput5 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput5 if [ $? != 0 ] ; then exit 1; fi else exit 1 fi echo "UTF8 test ran OK" echo " " fi if [ $do6 = yes ] ; then echo "Testing API and internals for UTF8 support (not Perl compatible)" ./pcretest testdata/testinput6 testtry if [ $? = 0 ] ; then $cf testtry testdata/testoutput6 if [ $? != 0 ] ; then exit 1; fi else exit 1 fi echo "UTF8 internals test ran OK" echo " " fi # End privoxy-3.0.21-stable/./pcre/install000640 001751 001751 00000017561 10546014100 016305 0ustar00fkfk000000 000000 Basic Installation ================== These are generic installation instructions that apply to systems that can run the `configure' shell script - Unix systems and any that imitate it. They are not specific to PCRE. There are PCRE-specific instructions for non-Unix systems in the file NON-UNIX-USE. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. privoxy-3.0.21-stable/./config.sub000750 001751 001751 00000105162 11657466213 015764 0ustar00fkfk000000 000000 #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011 Free Software Foundation, Inc. timestamp='2011-11-11' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: privoxy-3.0.21-stable/./mkinstalldirs000640 001751 001751 00000001334 11217504052 016563 0ustar00fkfk000000 000000 #! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs,v 1.4 2006/07/18 14:48:47 david__schmidt Exp $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here privoxy-3.0.21-stable/./loaders.h000640 001751 001751 00000010611 12060362131 015555 0ustar00fkfk000000 000000 #ifndef LOADERS_H_INCLUDED #define LOADERS_H_INCLUDED #define LOADERS_H_VERSION "$Id: loaders.h,v 1.30 2012/12/07 12:43:05 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loaders.h,v $ * * Purpose : Functions to load and unload the various * configuration files. Also contains code to manage * the list of active loaders, and to automatically * unload files that are no longer in use. * * Copyright : Written by and Copyright (C) 2001-2010 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif /* Structures taken from project.h */ struct client_state; struct file_list; struct configuration_spec; struct url_spec; extern unsigned int sweep(void); extern char *read_config_line(FILE *fp, unsigned long *linenum, char **buf); extern int check_file_changed(const struct file_list * current, const char * filename, struct file_list ** newfl); extern jb_err edit_read_line(FILE *fp, char **raw_out, char **prefix_out, char **data_out, int *newline, unsigned long *line_number); extern jb_err simple_read_line(FILE *fp, char **dest, int *newline); /* * Various types of newlines that a file may contain. */ #define NEWLINE_UNKNOWN 0 /* Newline convention in file is unknown */ #define NEWLINE_UNIX 1 /* Newline convention in file is '\n' (ASCII 10) */ #define NEWLINE_DOS 2 /* Newline convention in file is '\r\n' (ASCII 13,10) */ #define NEWLINE_MAC 3 /* Newline convention in file is '\r' (ASCII 13) */ /* * Types of newlines that a file may contain, as strings. If you have an * extremely weird compiler that does not have '\r' == CR == ASCII 13 and * '\n' == LF == ASCII 10), then fix CHAR_CR and CHAR_LF in loaders.c as * well as these definitions. */ #define NEWLINE(style) ((style)==NEWLINE_DOS ? "\r\n" : \ ((style)==NEWLINE_MAC ? "\r" : "\n")) extern short int MustReload; extern int load_action_files(struct client_state *csp); extern int load_re_filterfiles(struct client_state *csp); #ifdef FEATURE_TRUST extern int load_trustfile(struct client_state *csp); #endif /* def FEATURE_TRUST */ #ifdef FEATURE_GRACEFUL_TERMINATION #ifdef FEATURE_TRUST void unload_current_trust_file(void); #endif void unload_current_re_filterfile(void); #endif /* FEATURE_GRACEFUL_TERMINATION */ void unload_forward_spec(struct forward_spec *fwd); extern void add_loader(int (*loader)(struct client_state *), struct configuration_spec * config); extern int run_loader(struct client_state *csp); extern int any_loaded_file_changed(const struct client_state *csp); /* Revision control strings from this header and associated .c file */ extern const char loaders_rcs[]; extern const char loaders_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef LOADERS_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32svrapi.h000640 001751 001751 00000012051 11630656300 015772 0ustar00fkfk000000 000000 #ifndef W32_SVRAPI_H_INCLUDED #define W32_SVRAPI_H_INCLUDED #define W32_SVRAPI_H_VERSION "$Id: w32svrapi.h,v 1.3 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32svrapi.h,v $ * * Purpose : Win32 Services API for Privoxy. * Provides the implementation of an Win32 service to * allow the code to directly register and run as a * native Windows service application. * * Since Win9x/ME platforms don't provide or support * running programs as services, this code uses runtime * loading and calling of the Win32 Service API, to * prevent the possibility of getting "entry point not * found" type errors on unsupported platforms. This adds * a little more complexity to the code, but it is worth * doing to provide that isolation. * * Copyright : Written by and Copyright (C) 2003 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 2003 Ian Cummings * * * Special thanks to Mates Dolák for * some very helpful feedback and suggestions during the * development of this code. * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 extern char szThisServiceName[]; extern BOOL bRunAsService; extern SERVICE_TABLE_ENTRY w32ServiceDispatchTable[]; extern BOOL install_service(const char *service_name); extern BOOL uninstall_service(const char *service_name); extern void w32_service_exit_notify(void); extern void w32_set_service_cwd(void); extern void w32_service_listen_loop(void *p); extern BOOL CanSystemSupportServices(); extern SC_HANDLE w32_open_sc_manager( LPCTSTR lpMachineName, /* computer name */ LPCTSTR lpDatabaseName, /* SCM database name */ DWORD dwDesiredAccess); /* access type */ extern BOOL w32_close_service_handle( SC_HANDLE hSCObject); /* handle to service or SCM object */ extern SC_HANDLE w32_open_service( SC_HANDLE hSCManager, /* handle to SCM database */ LPCTSTR lpServiceName, /* service name */ DWORD dwDesiredAccess); /* access */ extern SC_HANDLE w32_create_service( SC_HANDLE hSCManager, /* handle to SCM database */ LPCTSTR lpServiceName, /* name of service to start */ LPCTSTR lpDisplayName, /* display name */ DWORD dwDesiredAccess, /* type of access to service */ DWORD dwServiceType, /* type of service */ DWORD dwStartType, /* when to start service */ DWORD dwErrorControl, /* severity of service failure */ LPCTSTR lpBinaryPathName, /* name of binary file */ LPCTSTR lpLoadOrderGroup, /* name of load ordering group */ LPDWORD lpdwTagId, /* tag identifier */ LPCTSTR lpDependencies, /* array of dependency names */ LPCTSTR lpServiceStartName, /* account name */ LPCTSTR lpPassword); /* account password */ extern BOOL w32_delete_service( SC_HANDLE hService); /* handle to service */ extern BOOL w32_query_service_config( SC_HANDLE hService, /* handle to service */ LPQUERY_SERVICE_CONFIG lpServiceConfig, /* buffer */ DWORD cbBufSize, /* size of buffer */ LPDWORD pcbBytesNeeded); /* bytes needed */ extern BOOL w32_start_service_ctrl_dispatcher( CONST LPSERVICE_TABLE_ENTRY lpServiceTable); /* service table */ extern SERVICE_STATUS_HANDLE w32_register_service_ctrl_handler( LPCTSTR lpServiceName, /* service name */ LPHANDLER_FUNCTION lpHandlerProc); /* handler function */ extern BOOL w32_set_service_status( SERVICE_STATUS_HANDLE hServiceStatus, /* service status handle */ LPSERVICE_STATUS lpServiceStatus); /* status buffer */ #endif /* def _WIN32 */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef W32_SVRAPI_H_INCLUDED */ privoxy-3.0.21-stable/./cgiedit.c000640 001751 001751 00000411263 12003243315 015536 0ustar00fkfk000000 000000 const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.76 2012/07/23 12:42:53 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $ * * Purpose : CGI-based actionsfile editor. * * NOTE: The CGIs in this file use parameter names * such as "f" and "s" which are really *BAD* choices. * However, I'm trying to save bytes in the * edit-actions-list HTML page - the standard actions * file generated a 550kbyte page, which is ridiculous. * * Stick to the short names in this file for consistency. * * Copyright : Written by and Copyright (C) 2001-2008 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "config.h" /* * FIXME: Following includes copied from cgi.c - which are actually needed? */ #include #include #include #include #include #include #include #include "project.h" #include "cgi.h" #include "cgiedit.h" #include "cgisimple.h" #include "list.h" #include "encode.h" #include "actions.h" #include "miscutil.h" #include "errlog.h" #include "loaders.h" #ifdef FEATURE_TOGGLE /* loadcfg.h is for global_toggle_state only */ #include "loadcfg.h" #endif /* def FEATURE_TOGGLE */ #include "urlmatch.h" const char cgiedit_h_rcs[] = CGIEDIT_H_VERSION; #ifdef FEATURE_CGI_EDIT_ACTIONS /** * A line in an editable_file. */ struct file_line { /** Next entry in the linked list */ struct file_line * next; /** The raw data, to write out if this line is unmodified. */ char * raw; /** Comments and/or whitespace to put before this line if it's modified and then written out. */ char * prefix; /** The actual data, as a string. Line continuation and comment removal are performed on the data read from file before it's stored here, so it will be a single line of data. */ char * unprocessed; /** The type of data on this line. One of the FILE_LINE_xxx constants. */ int type; /** The actual data, processed into some sensible data type. */ union { /** An action specification. */ struct action_spec action[1]; /** A name=value pair. */ struct { /** The name in the name=value pair. */ char * name; /** The value in the name=value pair, as a string. */ char * svalue; /** The value in the name=value pair, as an integer. */ int ivalue; } setting; /* Add more data types here... e.g. struct url_spec url[1]; struct { struct action_spec action[1]; const char * name; } alias; */ } data; }; /** This file_line has not been processed yet. */ #define FILE_LINE_UNPROCESSED 1 /** This file_line is blank. Can only appear at the end of a file, due to the way the parser works. */ #define FILE_LINE_BLANK 2 /** This file_line says {{alias}}. */ #define FILE_LINE_ALIAS_HEADER 3 /** This file_line defines an alias. */ #define FILE_LINE_ALIAS_ENTRY 4 /** This file_line defines an {action}. */ #define FILE_LINE_ACTION 5 /** This file_line specifies a URL pattern. */ #define FILE_LINE_URL 6 /** This file_line says {{settings}}. */ #define FILE_LINE_SETTINGS_HEADER 7 /** This file_line is in a {{settings}} block. */ #define FILE_LINE_SETTINGS_ENTRY 8 /** This file_line says {{description}}. */ #define FILE_LINE_DESCRIPTION_HEADER 9 /** This file_line is in a {{description}} block. */ #define FILE_LINE_DESCRIPTION_ENTRY 10 /* * Number of file modification time mismatches * before the CGI editor gets turned off. */ #define ACCEPTABLE_TIMESTAMP_MISMATCHES 3 /** * A configuration file, in a format that can be edited and written back to * disk. */ struct editable_file { struct file_line * lines; /**< The contents of the file. A linked list of lines. */ const char * filename; /**< Full pathname - e.g. "/etc/privoxy/wibble.action". */ unsigned identifier; /**< The file name's position in csp->config->actions_file[]. */ const char * version_str; /**< Last modification time, as a string. For CGI param. */ /**< Can be used in URL without using url_param(). */ unsigned version; /**< Last modification time - prevents chaos with the browser's "back" button. Note that this is a time_t cast to an unsigned. When comparing, always cast the time_t to an unsigned, and *NOT* vice-versa. This may lose the top few bits, but they're not significant anyway. */ int newline; /**< Newline convention - one of the NEWLINE_xxx constants. Note that changing this after the file has been read in will cause a mess. */ struct file_line * parse_error; /**< On parse error, this is the offending line. */ const char * parse_error_text; /**< On parse error, this is the problem. (Statically allocated) */ }; /** * Information about the filter types. * Used for macro replacement in cgi_edit_actions_for_url. */ struct filter_type_info { const int multi_action_index; /**< The multi action index as defined in project.h */ const char *macro_name; /**< Name of the macro that has to be replaced with the prepared templates. For example "content-filter-params" */ const char *type; /**< Name of the filter type, for example "server-header-filter". */ /* XXX: check if these two can be combined. */ const char *disable_all_option; /**< Name of the catch-all radio option that has to be checked or unchecked for this filter type. */ const char *disable_all_param; /**< Name of the parameter that causes all filters of this type to be disabled. */ const char *abbr_type; /**< Abbreviation of the filter type, usually the first or second character capitalized */ const char *anchor; /**< Anchor for the User Manual link, for example "SERVER-HEADER-FILTER" */ }; /* Accessed by index, keep the order in the way the FT_ macros are defined. */ static const struct filter_type_info filter_type_info[] = { { ACTION_MULTI_FILTER, "content-filter-params", "filter", "filter-all", "filter_all", "F", "FILTER" }, { ACTION_MULTI_CLIENT_HEADER_FILTER, "client-header-filter-params", "client-header-filter", "client-header-filter-all", "client_header_filter_all", "C", "CLIENT-HEADER-FILTER" }, { ACTION_MULTI_SERVER_HEADER_FILTER, "server-header-filter-params", "server-header-filter", "server-header-filter-all", "server_header_filter_all", "S", "SERVER-HEADER-FILTER" }, { ACTION_MULTI_CLIENT_HEADER_TAGGER, "client-header-tagger-params", "client-header-tagger", "client-header-tagger-all", "client_header_tagger_all", "L", "CLIENT-HEADER-TAGGER" }, { ACTION_MULTI_SERVER_HEADER_TAGGER, "server-header-tagger-params", "server-header-tagger", "server-header-tagger-all", "server_header_tagger_all", "E", "SERVER-HEADER-TAGGER" }, }; /* FIXME: Following non-static functions should be prototyped in .h or made static */ /* Functions to read and write arbitrary config files */ jb_err edit_read_file(struct client_state *csp, const struct map *parameters, int require_version, struct editable_file **pfile); jb_err edit_write_file(struct editable_file * file); void edit_free_file(struct editable_file * file); /* Functions to read and write actions files */ jb_err edit_parse_actions_file(struct editable_file * file); jb_err edit_read_actions_file(struct client_state *csp, struct http_response *rsp, const struct map *parameters, int require_version, struct editable_file **pfile); /* Error handlers */ jb_err cgi_error_modified(struct client_state *csp, struct http_response *rsp, const char *filename); jb_err cgi_error_parse(struct client_state *csp, struct http_response *rsp, struct editable_file *file); jb_err cgi_error_file(struct client_state *csp, struct http_response *rsp, const char *filename); jb_err cgi_error_file_read_only(struct client_state *csp, struct http_response *rsp, const char *filename); /* Internal arbitrary config file support functions */ static jb_err edit_read_file_lines(FILE *fp, struct file_line ** pfile, int *newline); static void edit_free_file_lines(struct file_line * first_line); /* Internal actions file support functions */ static int match_actions_file_header_line(const char * line, const char * name); static jb_err split_line_on_equals(const char * line, char ** pname, char ** pvalue); /* Internal parameter parsing functions */ static jb_err get_url_spec_param(struct client_state *csp, const struct map *parameters, const char *name, char **pvalue); /* Internal actionsfile <==> HTML conversion functions */ static jb_err map_radio(struct map * exports, const char * optionname, const char * values, int value); static jb_err actions_to_radio(struct map * exports, const struct action_spec *action); static jb_err actions_from_radio(const struct map * parameters, struct action_spec *action); static jb_err map_copy_parameter_html(struct map *out, const struct map *in, const char *name); static jb_err get_file_name_param(struct client_state *csp, const struct map *parameters, const char *param_name, const char **pfilename); /* Internal convenience functions */ static char *section_target(const unsigned sectionid); /********************************************************************* * * Function : section_target * * Description : Given an unsigned (section id) n, produce a dynamically * allocated string of the form #l, for use in link * targets. * * XXX: The hash should be moved into the templates * to make this function more generic and render * stringify() obsolete. * * Parameters : * 1 : sectionid = start line number of section * * Returns : String with link target, or NULL if out of * memory * *********************************************************************/ static char *section_target(const unsigned sectionid) { char buf[30]; snprintf(buf, sizeof(buf), "#l%d", sectionid); return(strdup(buf)); } /********************************************************************* * * Function : stringify * * Description : Convert a number into a dynamically allocated string. * * Parameters : * 1 : number = The number to convert. * * Returns : String with link target, or NULL if out of memory * *********************************************************************/ static char *stringify(const unsigned number) { char buf[6]; snprintf(buf, sizeof(buf), "%i", number); return strdup(buf); } /********************************************************************* * * Function : map_copy_parameter_html * * Description : Copy a CGI parameter from one map to another, HTML * encoding it. * * Parameters : * 1 : out = target map * 2 : in = source map * 3 : name = name of cgi parameter to copy * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the parameter doesn't exist * in the source map * *********************************************************************/ static jb_err map_copy_parameter_html(struct map *out, const struct map *in, const char *name) { const char * value; jb_err err; assert(out); assert(in); assert(name); value = lookup(in, name); err = map(out, name, 1, html_encode(value), 0); if (err) { /* Out of memory */ return err; } else if (*value == '\0') { return JB_ERR_CGI_PARAMS; } else { return JB_ERR_OK; } } /********************************************************************* * * Function : cgi_edit_actions_url_form * * Description : CGI function that displays a form for * edit-actions-url * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters * i : (action index) Identifies the file to edit * v : (version) File's last-modified time * p : (pattern) Line number of pattern to edit * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the CGI parameters are not * specified or not valid. * *********************************************************************/ jb_err cgi_edit_actions_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map * exports; unsigned patternid; struct editable_file * file; struct file_line * cur_line; unsigned line_number; unsigned section_start_line_number = 0; jb_err err; assert(csp); assert(rsp); assert(parameters); if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { return cgi_error_disabled(csp, rsp); } err = get_number_param(csp, parameters, "p", &patternid); if (err) { return err; } err = edit_read_actions_file(csp, rsp, parameters, 1, &file); if (err) { /* No filename specified, can't read file, modified, or out of memory. */ return (err == JB_ERR_FILE ? JB_ERR_OK : err); } cur_line = file->lines; for (line_number = 1; (cur_line != NULL) && (line_number < patternid); line_number++) { if (cur_line->type == FILE_LINE_ACTION) { section_start_line_number = line_number; } cur_line = cur_line->next; } if ( (cur_line == NULL) || (line_number != patternid) || (patternid < 1U) || (cur_line->type != FILE_LINE_URL)) { /* Invalid "patternid" parameter */ edit_free_file(file); return JB_ERR_CGI_PARAMS; } if (NULL == (exports = default_exports(csp, NULL))) { edit_free_file(file); return JB_ERR_MEMORY; } err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "p", 1, url_encode(lookup(parameters, "p")), 0); if (!err) err = map(exports, "u", 1, html_encode(cur_line->unprocessed), 0); if (!err) err = map(exports, "jumptarget", 1, section_target(section_start_line_number), 0); edit_free_file(file); if (err) { free_map(exports); return err; } return template_fill_for_cgi(csp, "edit-actions-url-form", exports, rsp); } /********************************************************************* * * Function : cgi_edit_actions_add_url_form * * Description : CGI function that displays a form for * edit-actions-url * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * f : (filename) Identifies the file to edit * v : (version) File's last-modified time * s : (section) Line number of section to edit * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the CGI parameters are not * specified or not valid. * *********************************************************************/ jb_err cgi_edit_actions_add_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map *exports; jb_err err; assert(csp); assert(rsp); assert(parameters); if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { return cgi_error_disabled(csp, rsp); } if (NULL == (exports = default_exports(csp, NULL))) { return JB_ERR_MEMORY; } err = map_copy_parameter_html(exports, parameters, "f"); if (!err) err = map_copy_parameter_html(exports, parameters, "v"); if (!err) err = map_copy_parameter_html(exports, parameters, "s"); if (err) { free_map(exports); return err; } return template_fill_for_cgi(csp, "edit-actions-add-url-form", exports, rsp); } /********************************************************************* * * Function : cgi_edit_actions_remove_url_form * * Description : CGI function that displays a form for * edit-actions-url * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * f : (number) The action file identifier. * v : (version) File's last-modified time * p : (pattern) Line number of pattern to edit * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the CGI parameters are not * specified or not valid. * *********************************************************************/ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map * exports; unsigned patternid; struct editable_file * file; struct file_line * cur_line; unsigned line_number; unsigned section_start_line_number = 0; jb_err err; assert(csp); assert(rsp); assert(parameters); if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { return cgi_error_disabled(csp, rsp); } err = get_number_param(csp, parameters, "p", &patternid); if (err) { return err; } err = edit_read_actions_file(csp, rsp, parameters, 1, &file); if (err) { /* No filename specified, can't read file, modified, or out of memory. */ return (err == JB_ERR_FILE ? JB_ERR_OK : err); } cur_line = file->lines; for (line_number = 1; (cur_line != NULL) && (line_number < patternid); line_number++) { if (cur_line->type == FILE_LINE_ACTION) { section_start_line_number = line_number; } cur_line = cur_line->next; } if ( (cur_line == NULL) || (line_number != patternid) || (patternid < 1U) || (cur_line->type != FILE_LINE_URL)) { /* Invalid "patternid" parameter */ edit_free_file(file); return JB_ERR_CGI_PARAMS; } if (NULL == (exports = default_exports(csp, NULL))) { edit_free_file(file); return JB_ERR_MEMORY; } err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "p", 1, url_encode(lookup(parameters, "p")), 0); if (!err) err = map(exports, "u", 1, html_encode(cur_line->unprocessed), 0); if (!err) err = map(exports, "jumptarget", 1, section_target(section_start_line_number), 0); if (!err) err = map(exports, "actions-file", 1, html_encode(file->filename), 0); edit_free_file(file); if (err) { free_map(exports); return err; } return template_fill_for_cgi(csp, "edit-actions-remove-url-form", exports, rsp); } /********************************************************************* * * Function : edit_write_file * * Description : Write a complete file to disk. * * Parameters : * 1 : file = File to write. * * Returns : JB_ERR_OK on success * JB_ERR_FILE on error writing to file. * JB_ERR_MEMORY on out of memory * *********************************************************************/ jb_err edit_write_file(struct editable_file * file) { FILE * fp; struct file_line * cur_line; struct stat statbuf[1]; char version_buf[22]; /* 22 = ceil(log10(2^64)) + 2 = max number of digits in time_t, assuming this is a 64-bit machine, plus null terminator, plus one for paranoia */ assert(file); assert(file->filename); if (NULL == (fp = fopen(file->filename, "wb"))) { return JB_ERR_FILE; } cur_line = file->lines; while (cur_line != NULL) { if (cur_line->raw) { if (fputs(cur_line->raw, fp) < 0) { fclose(fp); return JB_ERR_FILE; } } else { if (cur_line->prefix) { if (fputs(cur_line->prefix, fp) < 0) { fclose(fp); return JB_ERR_FILE; } } if (cur_line->unprocessed) { if (NULL != strchr(cur_line->unprocessed, '#')) { /* Must quote '#' characters */ int numhash = 0; size_t len; char * src; char * dest; char * str; /* Count number of # characters, so we know length of output string */ src = cur_line->unprocessed; while (NULL != (src = strchr(src, '#'))) { numhash++; src++; } assert(numhash > 0); /* Allocate new memory for string */ len = strlen(cur_line->unprocessed) + (size_t)numhash; str = malloc_or_die(len + 1); /* Copy string but quote hashes */ src = cur_line->unprocessed; dest = str; while (*src) { if (*src == '#') { *dest++ = '\\'; numhash--; assert(numhash >= 0); } *dest++ = *src++; } *dest = '\0'; assert(numhash == 0); assert(strlen(str) == len); assert(str == dest - len); assert(src - len <= cur_line->unprocessed); if ((strlen(str) != len) || (numhash != 0)) { /* * Escaping didn't work as expected, go spread the news. * Only reached in non-debugging builds. */ log_error(LOG_LEVEL_ERROR, "Looks like hash escaping failed. %s might be corrupted now.", file->filename); } if (fputs(str, fp) < 0) { free(str); fclose(fp); return JB_ERR_FILE; } free(str); } else { /* Can write without quoting '#' characters. */ if (fputs(cur_line->unprocessed, fp) < 0) { fclose(fp); return JB_ERR_FILE; } } if (fputs(NEWLINE(file->newline), fp) < 0) { fclose(fp); return JB_ERR_FILE; } } else { /* FIXME: Write data from file->data->whatever */ assert(0); } } cur_line = cur_line->next; } fclose(fp); /* Update the version stamp in the file structure, since we just * wrote to the file & changed it's date. */ if (stat(file->filename, statbuf) < 0) { /* Error, probably file not found. */ return JB_ERR_FILE; } file->version = (unsigned)statbuf->st_mtime; /* Correct file->version_str */ freez(file->version_str); snprintf(version_buf, sizeof(version_buf), "%u", file->version); version_buf[sizeof(version_buf)-1] = '\0'; file->version_str = strdup(version_buf); if (version_buf == NULL) { return JB_ERR_MEMORY; } return JB_ERR_OK; } /********************************************************************* * * Function : edit_free_file * * Description : Free a complete file in memory. * * Parameters : * 1 : file = Data structure to free. * * Returns : N/A * *********************************************************************/ void edit_free_file(struct editable_file * file) { if (!file) { /* Silently ignore NULL pointer */ return; } edit_free_file_lines(file->lines); freez(file->version_str); file->version = 0; file->parse_error_text = NULL; /* Statically allocated */ file->parse_error = NULL; free(file); } /********************************************************************* * * Function : edit_free_file_lines * * Description : Free an entire linked list of file lines. * * Parameters : * 1 : first_line = Data structure to free. * * Returns : N/A * *********************************************************************/ static void edit_free_file_lines(struct file_line * first_line) { struct file_line * next_line; while (first_line != NULL) { next_line = first_line->next; first_line->next = NULL; freez(first_line->raw); freez(first_line->prefix); freez(first_line->unprocessed); switch(first_line->type) { case 0: /* special case if memory zeroed */ case FILE_LINE_UNPROCESSED: case FILE_LINE_BLANK: case FILE_LINE_ALIAS_HEADER: case FILE_LINE_SETTINGS_HEADER: case FILE_LINE_DESCRIPTION_HEADER: case FILE_LINE_DESCRIPTION_ENTRY: case FILE_LINE_ALIAS_ENTRY: case FILE_LINE_URL: /* No data is stored for these */ break; case FILE_LINE_ACTION: free_action(first_line->data.action); break; case FILE_LINE_SETTINGS_ENTRY: freez(first_line->data.setting.name); freez(first_line->data.setting.svalue); break; default: /* Should never happen */ assert(0); break; } first_line->type = 0; /* paranoia */ free(first_line); first_line = next_line; } } /********************************************************************* * * Function : match_actions_file_header_line * * Description : Match an actions file {{header}} line * * Parameters : * 1 : line = String from file * 2 : name = Header to match against * * Returns : 0 iff they match. * *********************************************************************/ static int match_actions_file_header_line(const char * line, const char * name) { size_t len; assert(line); assert(name); /* Look for "{{" */ if ((line[0] != '{') || (line[1] != '{')) { return 1; } line += 2; /* Look for optional whitespace */ while ((*line == ' ') || (*line == '\t')) { line++; } /* Look for the specified name (case-insensitive) */ len = strlen(name); if (0 != strncmpic(line, name, len)) { return 1; } line += len; /* Look for optional whitespace */ while ((*line == ' ') || (*line == '\t')) { line++; } /* Look for "}}" and end of string*/ if ((line[0] != '}') || (line[1] != '}') || (line[2] != '\0')) { return 1; } /* It matched!! */ return 0; } /********************************************************************* * * Function : match_actions_file_header_line * * Description : Match an actions file {{header}} line * * Parameters : * 1 : line = String from file. Must not start with * whitespace (else infinite loop!) * 2 : pname = Destination for name * 2 : pvalue = Destination for value * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_PARSE if there's no "=" sign, or if there's * nothing before the "=" sign (but empty * values *after* the "=" sign are legal). * *********************************************************************/ static jb_err split_line_on_equals(const char * line, char ** pname, char ** pvalue) { const char * name_end; const char * value_start; size_t name_len; assert(line); assert(pname); assert(pvalue); assert(*line != ' '); assert(*line != '\t'); *pname = NULL; *pvalue = NULL; value_start = strchr(line, '='); if ((value_start == NULL) || (value_start == line)) { return JB_ERR_PARSE; } name_end = value_start - 1; /* Eat any whitespace before the '=' */ while ((*name_end == ' ') || (*name_end == '\t')) { /* * we already know we must have at least 1 non-ws char * at start of buf - no need to check */ name_end--; } name_len = (size_t)(name_end - line) + 1; /* Length excluding \0 */ *pname = malloc_or_die(name_len + 1); strncpy(*pname, line, name_len); (*pname)[name_len] = '\0'; /* Eat any the whitespace after the '=' */ value_start++; while ((*value_start == ' ') || (*value_start == '\t')) { value_start++; } if (NULL == (*pvalue = strdup(value_start))) { free(*pname); *pname = NULL; return JB_ERR_MEMORY; } return JB_ERR_OK; } /********************************************************************* * * Function : edit_parse_actions_file * * Description : Parse an actions file in memory. * * Passed linked list must have the "data" member * zeroed, and must contain valid "next" and * "unprocessed" fields. The "raw" and "prefix" * fields are ignored, and "type" is just overwritten. * * Note that on error the file may have been * partially parsed. * * Parameters : * 1 : file = Actions file to be parsed in-place. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_PARSE on error * *********************************************************************/ jb_err edit_parse_actions_file(struct editable_file * file) { struct file_line * cur_line; size_t len; const char * text; /* Text from a line */ char * name; /* For lines of the form name=value */ char * value; /* For lines of the form name=value */ struct action_alias * alias_list = NULL; jb_err err = JB_ERR_OK; /* alias_list contains the aliases defined in this file. * It might be better to use the "file_line.data" fields * in the relavent places instead. */ cur_line = file->lines; /* A note about blank line support: Blank lines should only * ever occur as the last line in the file. This function * is more forgiving than that - FILE_LINE_BLANK can occur * anywhere. */ /* Skip leading blanks. Should only happen if file is * empty (which is valid, but pointless). */ while ((cur_line != NULL) && (cur_line->unprocessed[0] == '\0')) { /* Blank line */ cur_line->type = FILE_LINE_BLANK; cur_line = cur_line->next; } if ((cur_line != NULL) && (cur_line->unprocessed[0] != '{')) { /* File doesn't start with a header */ file->parse_error = cur_line; file->parse_error_text = "First (non-comment) line of the file must contain a header."; return JB_ERR_PARSE; } if ((cur_line != NULL) && (0 == match_actions_file_header_line(cur_line->unprocessed, "settings"))) { cur_line->type = FILE_LINE_SETTINGS_HEADER; cur_line = cur_line->next; while ((cur_line != NULL) && (cur_line->unprocessed[0] != '{')) { if (cur_line->unprocessed[0]) { cur_line->type = FILE_LINE_SETTINGS_ENTRY; err = split_line_on_equals(cur_line->unprocessed, &cur_line->data.setting.name, &cur_line->data.setting.svalue); if (err == JB_ERR_MEMORY) { return err; } else if (err != JB_ERR_OK) { /* Line does not contain a name=value pair */ file->parse_error = cur_line; file->parse_error_text = "Expected a name=value pair on this {{description}} line, but couldn't find one."; return JB_ERR_PARSE; } } else { cur_line->type = FILE_LINE_BLANK; } cur_line = cur_line->next; } } if ((cur_line != NULL) && (0 == match_actions_file_header_line(cur_line->unprocessed, "description"))) { cur_line->type = FILE_LINE_DESCRIPTION_HEADER; cur_line = cur_line->next; while ((cur_line != NULL) && (cur_line->unprocessed[0] != '{')) { if (cur_line->unprocessed[0]) { cur_line->type = FILE_LINE_DESCRIPTION_ENTRY; } else { cur_line->type = FILE_LINE_BLANK; } cur_line = cur_line->next; } } if ((cur_line != NULL) && (0 == match_actions_file_header_line(cur_line->unprocessed, "alias"))) { cur_line->type = FILE_LINE_ALIAS_HEADER; cur_line = cur_line->next; while ((cur_line != NULL) && (cur_line->unprocessed[0] != '{')) { if (cur_line->unprocessed[0]) { /* define an alias */ struct action_alias * new_alias; cur_line->type = FILE_LINE_ALIAS_ENTRY; err = split_line_on_equals(cur_line->unprocessed, &name, &value); if (err == JB_ERR_MEMORY) { return err; } else if (err != JB_ERR_OK) { /* Line does not contain a name=value pair */ file->parse_error = cur_line; file->parse_error_text = "Expected a name=value pair on this {{alias}} line, but couldn't find one."; return JB_ERR_PARSE; } if ((new_alias = zalloc(sizeof(*new_alias))) == NULL) { /* Out of memory */ free(name); free(value); free_alias_list(alias_list); return JB_ERR_MEMORY; } err = get_actions(value, alias_list, new_alias->action); if (err) { /* Invalid action or out of memory */ free(name); free(value); free(new_alias); free_alias_list(alias_list); if (err == JB_ERR_MEMORY) { return err; } else { /* Line does not contain a name=value pair */ file->parse_error = cur_line; file->parse_error_text = "This alias does not specify a valid set of actions."; return JB_ERR_PARSE; } } free(value); new_alias->name = name; /* add to list */ new_alias->next = alias_list; alias_list = new_alias; } else { cur_line->type = FILE_LINE_BLANK; } cur_line = cur_line->next; } } /* Header done, process the main part of the file */ while (cur_line != NULL) { /* At this point, (cur_line->unprocessed[0] == '{') */ assert(cur_line->unprocessed[0] == '{'); text = cur_line->unprocessed + 1; len = strlen(text) - 1; if (text[len] != '}') { /* No closing } on header */ free_alias_list(alias_list); file->parse_error = cur_line; file->parse_error_text = "Headers starting with '{' must have a " "closing bracket ('}'). Headers starting with two brackets ('{{') " "must close with two brackets ('}}')."; return JB_ERR_PARSE; } if (text[0] == '{') { /* An invalid {{ header. */ free_alias_list(alias_list); file->parse_error = cur_line; file->parse_error_text = "Unknown or unexpected two-bracket header. " "Please remember that the system (two-bracket) headers must " "appear in the order {{settings}}, {{description}}, {{alias}}, " "and must appear before any actions (one-bracket) headers. " "Also note that system headers may not be repeated."; return JB_ERR_PARSE; } while ((*text == ' ') || (*text == '\t')) { text++; len--; } while ((len > (size_t)0) && ((text[len - 1] == ' ') || (text[len - 1] == '\t'))) { len--; } cur_line->type = FILE_LINE_ACTION; /* Remove {} and make copy */ value = malloc_or_die(len + 1); strncpy(value, text, len); value[len] = '\0'; /* Get actions */ err = get_actions(value, alias_list, cur_line->data.action); if (err) { /* Invalid action or out of memory */ free(value); free_alias_list(alias_list); if (err == JB_ERR_MEMORY) { return err; } else { /* Line does not contain a name=value pair */ file->parse_error = cur_line; file->parse_error_text = "This header does not specify a valid set of actions."; return JB_ERR_PARSE; } } /* Done with string - it was clobbered anyway */ free(value); /* Process next line */ cur_line = cur_line->next; /* Loop processing URL patterns */ while ((cur_line != NULL) && (cur_line->unprocessed[0] != '{')) { if (cur_line->unprocessed[0]) { /* Could parse URL here, but this isn't currently needed */ cur_line->type = FILE_LINE_URL; } else { cur_line->type = FILE_LINE_BLANK; } cur_line = cur_line->next; } } /* End main while(cur_line != NULL) loop */ free_alias_list(alias_list); return JB_ERR_OK; } /********************************************************************* * * Function : edit_read_file_lines * * Description : Read all the lines of a file into memory. * Handles whitespace, comments and line continuation. * * Parameters : * 1 : fp = File to read from. On return, this will be * at EOF but it will not have been closed. * 2 : pfile = Destination for a linked list of file_lines. * Will be set to NULL on error. * 3 : newline = How to handle newlines. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * *********************************************************************/ jb_err edit_read_file_lines(FILE *fp, struct file_line ** pfile, int *newline) { struct file_line * first_line; /* Keep for return value or to free */ struct file_line * cur_line; /* Current line */ struct file_line * prev_line; /* Entry with prev_line->next = cur_line */ jb_err rval; assert(fp); assert(pfile); *pfile = NULL; cur_line = first_line = zalloc(sizeof(struct file_line)); if (cur_line == NULL) { return JB_ERR_MEMORY; } cur_line->type = FILE_LINE_UNPROCESSED; rval = edit_read_line(fp, &cur_line->raw, &cur_line->prefix, &cur_line->unprocessed, newline, NULL); if (rval) { /* Out of memory or empty file. */ /* Note that empty file is not an error we propagate up */ free(cur_line); return ((rval == JB_ERR_FILE) ? JB_ERR_OK : rval); } do { prev_line = cur_line; cur_line = prev_line->next = zalloc(sizeof(struct file_line)); if (cur_line == NULL) { /* Out of memory */ edit_free_file_lines(first_line); return JB_ERR_MEMORY; } cur_line->type = FILE_LINE_UNPROCESSED; rval = edit_read_line(fp, &cur_line->raw, &cur_line->prefix, &cur_line->unprocessed, newline, NULL); if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE)) { /* Out of memory */ edit_free_file_lines(first_line); return JB_ERR_MEMORY; } } while (rval != JB_ERR_FILE); /* EOF */ /* We allocated one too many - free it */ prev_line->next = NULL; free(cur_line); *pfile = first_line; return JB_ERR_OK; } /********************************************************************* * * Function : edit_read_file * * Description : Read a complete file into memory. * Handles CGI parameter parsing. If requested, also * checks the file's modification timestamp. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters. * 3 : require_version = true to check "ver" parameter. * 4 : pfile = Destination for the file. Will be set * to NULL on error. * * CGI Parameters : * f : The action file identifier. * ver : (Only if require_version is nonzero) * Timestamp of the actions file. If wrong, this * function fails with JB_ERR_MODIFIED. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if "filename" was not specified * or is not valid. * JB_ERR_FILE if the file cannot be opened or * contains no data * JB_ERR_MODIFIED if version checking was requested and * failed - the file was modified outside * of this CGI editor instance. * *********************************************************************/ jb_err edit_read_file(struct client_state *csp, const struct map *parameters, int require_version, struct editable_file **pfile) { struct file_line * lines; FILE * fp; jb_err err; const char *filename = NULL; struct editable_file * file; unsigned version = 0; struct stat statbuf[1]; char version_buf[22]; int newline = NEWLINE_UNKNOWN; unsigned i; assert(csp); assert(parameters); assert(pfile); *pfile = NULL; err = get_number_param(csp, parameters, "f", &i); if ((JB_ERR_OK == err) && (i < MAX_AF_FILES) && (NULL != csp->config->actions_file[i])) { filename = csp->config->actions_file[i]; } else if (JB_ERR_CGI_PARAMS == err) { /* * Probably an old-school URL like * http://config.privoxy.org/edit-actions-list?f=default */ get_file_name_param(csp, parameters, "f", &filename); } if (NULL == filename || stat(filename, statbuf) < 0) { /* Error, probably file not found. */ return JB_ERR_FILE; } version = (unsigned) statbuf->st_mtime; if (require_version) { unsigned specified_version; err = get_number_param(csp, parameters, "v", &specified_version); if (err) { return err; } if (version != specified_version) { return JB_ERR_MODIFIED; } } if (NULL == (fp = fopen(filename,"rb"))) { return JB_ERR_FILE; } err = edit_read_file_lines(fp, &lines, &newline); fclose(fp); if (err) { return err; } file = (struct editable_file *) zalloc(sizeof(*file)); if (err) { edit_free_file_lines(lines); return err; } file->lines = lines; file->newline = newline; file->filename = filename; file->version = version; file->identifier = i; /* Correct file->version_str */ freez(file->version_str); snprintf(version_buf, sizeof(version_buf), "%u", file->version); version_buf[sizeof(version_buf)-1] = '\0'; file->version_str = strdup(version_buf); if (version_buf == NULL) { edit_free_file(file); return JB_ERR_MEMORY; } *pfile = file; return JB_ERR_OK; } /********************************************************************* * * Function : edit_read_actions_file * * Description : Read a complete actions file into memory. * Handles CGI parameter parsing. If requested, also * checks the file's modification timestamp. * * If this function detects an error in the categories * JB_ERR_FILE, JB_ERR_MODIFIED, or JB_ERR_PARSE, * then it handles it by filling in the specified * response structure and returning JB_ERR_FILE. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = HTTP response. Only filled in on error. * 2 : parameters = map of cgi parameters. * 3 : require_version = true to check "ver" parameter. * 4 : pfile = Destination for the file. Will be set * to NULL on error. * * CGI Parameters : * f : The actions file identifier. * ver : (Only if require_version is nonzero) * Timestamp of the actions file. If wrong, this * function fails with JB_ERR_MODIFIED. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if "filename" was not specified * or is not valid. * JB_ERR_FILE if the file does not contain valid data, * or if file cannot be opened or * contains no data, or if version * checking was requested and failed. * *********************************************************************/ jb_err edit_read_actions_file(struct client_state *csp, struct http_response *rsp, const struct map *parameters, int require_version, struct editable_file **pfile) { jb_err err; struct editable_file *file; static int acceptable_failures = ACCEPTABLE_TIMESTAMP_MISMATCHES - 1; assert(csp); assert(parameters); assert(pfile); *pfile = NULL; err = edit_read_file(csp, parameters, require_version, &file); if (err) { /* Try to handle if possible */ if (err == JB_ERR_FILE) { err = cgi_error_file(csp, rsp, lookup(parameters, "f")); } else if (err == JB_ERR_MODIFIED) { assert(require_version); err = cgi_error_modified(csp, rsp, lookup(parameters, "f")); log_error(LOG_LEVEL_ERROR, "Blocking CGI edit request due to modification time mismatch."); if (acceptable_failures > 0) { log_error(LOG_LEVEL_INFO, "The CGI editor will be turned off after another %d mismatche(s).", acceptable_failures); acceptable_failures--; } else { log_error(LOG_LEVEL_INFO, "Timestamp mismatch limit reached, turning CGI editor off. " "Reload the configuration file to re-enable it."); csp->config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS; } } if (err == JB_ERR_OK) { /* * Signal to higher-level CGI code that there was a problem but we * handled it, they should just return JB_ERR_OK. */ err = JB_ERR_FILE; } return err; } err = edit_parse_actions_file(file); if (err) { if (err == JB_ERR_PARSE) { err = cgi_error_parse(csp, rsp, file); if (err == JB_ERR_OK) { /* * Signal to higher-level CGI code that there was a problem but we * handled it, they should just return JB_ERR_OK. */ err = JB_ERR_FILE; } } edit_free_file(file); return err; } *pfile = file; return JB_ERR_OK; } /********************************************************************* * * Function : get_file_name_param * * Description : Get the name of the file to edit from the parameters * passed to a CGI function using the old syntax. * This function handles security checks and only * accepts files that Privoxy already knows. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters * 3 : param_name = The name of the parameter to read * 4 : pfilename = pointer to the filename in * csp->config->actions_file[] if found. Set to NULL on error. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if "filename" was not specified * or is not valid. * *********************************************************************/ static jb_err get_file_name_param(struct client_state *csp, const struct map *parameters, const char *param_name, const char **pfilename) { const char *param; const char suffix[] = ".action"; const char *s; char *name; char *fullpath; char ch; size_t len; size_t name_size; int i; assert(csp); assert(parameters); assert(pfilename); *pfilename = NULL; param = lookup(parameters, param_name); if (!*param) { return JB_ERR_CGI_PARAMS; } len = strlen(param); if (len >= FILENAME_MAX) { /* Too long. */ return JB_ERR_CGI_PARAMS; } /* * Check every character to see if it's legal. * Totally unnecessary but we do it anyway. */ s = param; while ((ch = *s++) != '\0') { if ( ((ch < 'A') || (ch > 'Z')) && ((ch < 'a') || (ch > 'z')) && ((ch < '0') || (ch > '9')) && (ch != '-') && (ch != '_')) { /* Probable hack attempt. */ return JB_ERR_CGI_PARAMS; } } /* Append extension */ name_size = len + strlen(suffix) + 1; name = malloc_or_die(name_size); strlcpy(name, param, name_size); strlcat(name, suffix, name_size); /* Prepend path */ fullpath = make_path(csp->config->confdir, name); free(name); if (fullpath == NULL) { return JB_ERR_MEMORY; } /* Check if the file is known */ for (i = 0; i < MAX_AF_FILES; i++) { if (NULL != csp->config->actions_file[i] && !strcmp(fullpath, csp->config->actions_file[i])) { /* Success */ *pfilename = csp->config->actions_file[i]; freez(fullpath); return JB_ERR_OK; } } freez(fullpath); return JB_ERR_CGI_PARAMS; } /********************************************************************* * * Function : get_url_spec_param * * Description : Get a URL pattern from the parameters * passed to a CGI function. Removes leading/trailing * spaces and validates it. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters * 3 : name = Name of CGI parameter to read * 4 : pvalue = destination for value. Will be malloc()'d. * Set to NULL on error. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_CGI_PARAMS if the parameter was not specified * or is not valid. * *********************************************************************/ static jb_err get_url_spec_param(struct client_state *csp, const struct map *parameters, const char *name, char **pvalue) { const char *orig_param; char *param; char *s; struct url_spec compiled[1]; jb_err err; assert(csp); assert(parameters); assert(name); assert(pvalue); *pvalue = NULL; orig_param = lookup(parameters, name); if (!*orig_param) { return JB_ERR_CGI_PARAMS; } /* Copy and trim whitespace */ param = strdup(orig_param); if (param == NULL) { return JB_ERR_MEMORY; } chomp(param); /* Must be non-empty, and can't allow 1st character to be '{' */ if (param[0] == '\0' || param[0] == '{') { free(param); return JB_ERR_CGI_PARAMS; } /* Check for embedded newlines */ for (s = param; *s != '\0'; s++) { if ((*s == '\r') || (*s == '\n')) { free(param); return JB_ERR_CGI_PARAMS; } } /* Check that regex is valid */ s = strdup(param); if (s == NULL) { free(param); return JB_ERR_MEMORY; } err = create_url_spec(compiled, s); free(s); if (err) { free(param); return (err == JB_ERR_MEMORY) ? JB_ERR_MEMORY : JB_ERR_CGI_PARAMS; } free_url_spec(compiled); if (param[strlen(param) - 1] == '\\') { /* * Must protect trailing '\\' from becoming line continuation character. * Two methods: 1) If it's a domain only, add a trailing '/'. * 2) For path, add the do-nothing PCRE expression (?:) to the end */ if (strchr(param, '/') == NULL) { err = string_append(¶m, "/"); } else { err = string_append(¶m, "(?:)"); } if (err) { return err; } /* Check that the modified regex is valid */ s = strdup(param); if (s == NULL) { free(param); return JB_ERR_MEMORY; } err = create_url_spec(compiled, s); free(s); if (err) { free(param); return (err == JB_ERR_MEMORY) ? JB_ERR_MEMORY : JB_ERR_CGI_PARAMS; } free_url_spec(compiled); } *pvalue = param; return JB_ERR_OK; } /********************************************************************* * * Function : map_radio * * Description : Map a set of radio button values. E.g. if you have * 3 radio buttons, declare them as: *
  • %s
  • \n", t->spec); string_append(&p, buf); } err = map(exports, "trusted-referrers", 1, p, 0); if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Export the trust info, if available */ if (csp->config->trust_info->first) { struct list_entry *l; p = strdup(""); for (l = csp->config->trust_info->first; l ; l = l->next) { snprintf(buf, sizeof(buf), "
  • %s
    \n", l->str, l->str); string_append(&p, buf); } err = map(exports, "trust-info", 1, p, 0); } else { err = map_block_killer(exports, "have-trust-info"); } if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Export the force conditional block killer if * * - Privoxy was compiled without FEATURE_FORCE_LOAD, or * - Privoxy is configured to enforce blocks, or * - it's a CONNECT request and enforcing wouldn't work anyway. */ #ifdef FEATURE_FORCE_LOAD if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS) || (0 == strcmpic(csp->http->gpc, "connect"))) { err = map_block_killer(exports, "force-support"); } else { err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); } #else /* ifndef FEATURE_FORCE_LOAD */ err = map_block_killer(exports, "force-support"); #endif /* ndef FEATURE_FORCE_LOAD */ if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Build the response */ err = template_fill_for_cgi(csp, "untrusted", exports, rsp); if (err) { free_http_response(rsp); return cgi_error_memory(); } rsp->crunch_reason = UNTRUSTED; return finish_http_response(csp, rsp); } #endif /* def FEATURE_TRUST */ /********************************************************************* * * Function : compile_dynamic_pcrs_job_list * * Description : Compiles a dynamic pcrs job list (one with variables * resolved at request time) * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : b = The filter list to compile * * Returns : NULL in case of errors, otherwise the * pcrs job list. * *********************************************************************/ pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const struct re_filterfile_spec *b) { struct list_entry *pattern; pcrs_job *job_list = NULL; pcrs_job *dummy = NULL; pcrs_job *lastjob = NULL; int error = 0; const struct pcrs_variable variables[] = { {"url", csp->http->url, 1}, {"path", csp->http->path, 1}, {"host", csp->http->host, 1}, {"origin", csp->ip_addr_str, 1}, {NULL, NULL, 1} }; for (pattern = b->patterns->first; pattern != NULL; pattern = pattern->next) { assert(pattern->str != NULL); dummy = pcrs_compile_dynamic_command(pattern->str, variables, &error); if (NULL == dummy) { log_error(LOG_LEVEL_ERROR, "Compiling dynamic pcrs job '%s' for '%s' failed with error code %d: %s", pattern->str, b->name, error, pcrs_strerror(error)); continue; } else { if (error == PCRS_WARN_TRUNCATION) { log_error(LOG_LEVEL_ERROR, "At least one of the variables in \'%s\' had to " "be truncated before compilation", pattern->str); } if (job_list == NULL) { job_list = dummy; } else { lastjob->next = dummy; } lastjob = dummy; } } return job_list; } /********************************************************************* * * Function : rewrite_url * * Description : Rewrites a URL with a single pcrs command * and returns the result if it differs from the * original and isn't obviously invalid. * * Parameters : * 1 : old_url = URL to rewrite. * 2 : pcrs_command = pcrs command formatted as string (s@foo@bar@) * * * Returns : NULL if the pcrs_command didn't change the url, or * the result of the modification. * *********************************************************************/ char *rewrite_url(char *old_url, const char *pcrs_command) { char *new_url = NULL; int hits; assert(old_url); assert(pcrs_command); new_url = pcrs_execute_single_command(old_url, pcrs_command, &hits); if (hits == 0) { log_error(LOG_LEVEL_REDIRECTS, "pcrs command \"%s\" didn't change \"%s\".", pcrs_command, old_url); freez(new_url); } else if (hits < 0) { log_error(LOG_LEVEL_REDIRECTS, "executing pcrs command \"%s\" to rewrite %s failed: %s", pcrs_command, old_url, pcrs_strerror(hits)); freez(new_url); } else if (strncmpic(new_url, "http://", 7) && strncmpic(new_url, "https://", 8)) { log_error(LOG_LEVEL_ERROR, "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s), " "but the result doesn't look like a valid URL and will be ignored.", pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts"); freez(new_url); } else { log_error(LOG_LEVEL_REDIRECTS, "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s).", pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts"); } return new_url; } #ifdef FEATURE_FAST_REDIRECTS /********************************************************************* * * Function : get_last_url * * Description : Search for the last URL inside a string. * If the string already is a URL, it will * be the first URL found. * * Parameters : * 1 : subject = the string to check * 2 : redirect_mode = +fast-redirect{} mode * * Returns : NULL if no URL was found, or * the last URL found. * *********************************************************************/ char *get_last_url(char *subject, const char *redirect_mode) { char *new_url = NULL; char *tmp; assert(subject); assert(redirect_mode); subject = strdup(subject); if (subject == NULL) { log_error(LOG_LEVEL_ERROR, "Out of memory while searching for redirects."); return NULL; } if (0 == strcmpic(redirect_mode, "check-decoded-url") && strchr(subject, '%')) { char *url_segment = NULL; char **url_segments; size_t max_segments; int segments; log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for encoded redirects.", subject); /* * Check each parameter in the URL separately. * Sectionize the URL at "?" and "&", * go backwards through the segments, URL-decode them * and look for a URL in the decoded result. * Stop the search after the first match. * * XXX: This estimate is guaranteed to be high enough as we * let ssplit() ignore empty fields, but also a bit wasteful. */ max_segments = strlen(subject) / 2; url_segments = malloc(max_segments * sizeof(char *)); if (NULL == url_segments) { log_error(LOG_LEVEL_ERROR, "Out of memory while decoding URL: %s", subject); freez(subject); return NULL; } segments = ssplit(subject, "?&", url_segments, max_segments); while (segments-- > 0) { char *dtoken = url_decode(url_segments[segments]); if (NULL == dtoken) { log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", url_segments[segments]); continue; } url_segment = strstr(dtoken, "http://"); if (NULL == url_segment) { url_segment = strstr(dtoken, "https://"); } if (NULL != url_segment) { url_segment = strdup(url_segment); freez(dtoken); if (url_segment == NULL) { log_error(LOG_LEVEL_ERROR, "Out of memory while searching for redirects."); return NULL; } break; } freez(dtoken); } freez(subject); freez(url_segments); if (url_segment == NULL) { return NULL; } subject = url_segment; } else { /* Look for a URL inside this one, without decoding anything. */ log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for unencoded redirects.", subject); } /* * Find the last URL encoded in the request */ tmp = subject; while ((tmp = strstr(tmp, "http://")) != NULL) { new_url = tmp++; } tmp = (new_url != NULL) ? new_url : subject; while ((tmp = strstr(tmp, "https://")) != NULL) { new_url = tmp++; } if ((new_url != NULL) && ( (new_url != subject) || (0 == strncmpic(subject, "http://", 7)) || (0 == strncmpic(subject, "https://", 8)) )) { /* * Return new URL if we found a redirect * or if the subject already was a URL. * * The second case makes sure that we can * chain get_last_url after another redirection check * (like rewrite_url) without losing earlier redirects. */ new_url = strdup(new_url); freez(subject); return new_url; } freez(subject); return NULL; } #endif /* def FEATURE_FAST_REDIRECTS */ /********************************************************************* * * Function : redirect_url * * Description : Checks if Privoxy should answer the request with * a HTTP redirect and generates the redirect if * necessary. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : NULL if the request can pass, HTTP redirect otherwise. * *********************************************************************/ struct http_response *redirect_url(struct client_state *csp) { struct http_response *rsp; #ifdef FEATURE_FAST_REDIRECTS /* * XXX: Do we still need FEATURE_FAST_REDIRECTS * as compile-time option? The user can easily disable * it in his action file. */ char * redirect_mode; #endif /* def FEATURE_FAST_REDIRECTS */ char *old_url = NULL; char *new_url = NULL; char *redirection_string; if ((csp->action->flags & ACTION_REDIRECT)) { redirection_string = csp->action->string[ACTION_STRING_REDIRECT]; /* * If the redirection string begins with 's', * assume it's a pcrs command, otherwise treat it as * properly formatted URL and use it for the redirection * directly. * * According to RFC 2616 section 14.30 the URL * has to be absolute and if the user tries: * +redirect{shit/this/will/be/parsed/as/pcrs_command.html} * she would get undefined results anyway. * */ if (*redirection_string == 's') { old_url = csp->http->url; new_url = rewrite_url(old_url, redirection_string); } else { log_error(LOG_LEVEL_REDIRECTS, "No pcrs command recognized, assuming that \"%s\" is already properly formatted.", redirection_string); new_url = strdup(redirection_string); } } #ifdef FEATURE_FAST_REDIRECTS if ((csp->action->flags & ACTION_FAST_REDIRECTS)) { redirect_mode = csp->action->string[ACTION_STRING_FAST_REDIRECTS]; /* * If it exists, use the previously rewritten URL as input * otherwise just use the old path. */ old_url = (new_url != NULL) ? new_url : strdup(csp->http->path); new_url = get_last_url(old_url, redirect_mode); freez(old_url); } /* * Disable redirect checkers, so that they * will be only run more than once if the user * also enables them through tags. * * From a performance point of view * it doesn't matter, but the duplicated * log messages are annoying. */ csp->action->flags &= ~ACTION_FAST_REDIRECTS; #endif /* def FEATURE_FAST_REDIRECTS */ csp->action->flags &= ~ACTION_REDIRECT; /* Did any redirect action trigger? */ if (new_url) { if (url_requires_percent_encoding(new_url)) { char *encoded_url; log_error(LOG_LEVEL_REDIRECTS, "Percent-encoding redirect URL: %N", strlen(new_url), new_url); encoded_url = percent_encode_url(new_url); freez(new_url); if (encoded_url == NULL) { return cgi_error_memory(); } new_url = encoded_url; assert(FALSE == url_requires_percent_encoding(new_url)); } if (0 == strcmpic(new_url, csp->http->url)) { log_error(LOG_LEVEL_ERROR, "New URL \"%s\" and old URL \"%s\" are the same. Redirection loop prevented.", csp->http->url, new_url); freez(new_url); } else { log_error(LOG_LEVEL_REDIRECTS, "New URL is: %s", new_url); if (NULL == (rsp = alloc_http_response())) { freez(new_url); return cgi_error_memory(); } if (enlist_unique_header(rsp->headers, "Location", new_url) || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy")))) { freez(new_url); free_http_response(rsp); return cgi_error_memory(); } rsp->crunch_reason = REDIRECTED; freez(new_url); return finish_http_response(csp, rsp); } } /* Only reached if no redirect is required */ return NULL; } #ifdef FEATURE_IMAGE_BLOCKING /********************************************************************* * * Function : is_imageurl * * Description : Given a URL, decide whether it is an image or not, * using either the info from a previous +image action * or, #ifdef FEATURE_IMAGE_DETECT_MSIE, and the browser * is MSIE and not on a Mac, tell from the browser's accept * header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : True (nonzero) if URL is an image, false (0) * otherwise * *********************************************************************/ int is_imageurl(const struct client_state *csp) { #ifdef FEATURE_IMAGE_DETECT_MSIE char *tmp; tmp = get_header_value(csp->headers, "User-Agent:"); if (tmp && strstr(tmp, "MSIE") && !strstr(tmp, "Mac_")) { tmp = get_header_value(csp->headers, "Accept:"); if (tmp && strstr(tmp, "image/gif")) { /* Client will accept HTML. If this seems counterintuitive, * blame Microsoft. */ return(0); } else { return(1); } } #endif /* def FEATURE_IMAGE_DETECT_MSIE */ return ((csp->action->flags & ACTION_IMAGE) != 0); } #endif /* def FEATURE_IMAGE_BLOCKING */ #ifdef FEATURE_TRUST /********************************************************************* * * Function : is_untrusted_url * * Description : Should we "distrust" this URL (and block it)? * * Yes if it matches a line in the trustfile, or if the * referrer matches a line starting with "+" in the * trustfile. * No otherwise. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => trusted, 1 => untrusted * *********************************************************************/ int is_untrusted_url(const struct client_state *csp) { struct file_list *fl; struct block_spec *b; struct url_spec **trusted_url; struct http_request rhttp[1]; const char * referer; jb_err err; /* * If we don't have a trustlist, we trust everybody */ if (((fl = csp->tlist) == NULL) || ((b = fl->f) == NULL)) { return 0; } memset(rhttp, '\0', sizeof(*rhttp)); /* * Do we trust the request URL itself? */ for (b = b->next; b ; b = b->next) { if (url_match(b->url, csp->http)) { return b->reject; } } if (NULL == (referer = get_header_value(csp->headers, "Referer:"))) { /* no referrer was supplied */ return 1; } /* * If not, do we maybe trust its referrer? */ err = parse_http_url(referer, rhttp, REQUIRE_PROTOCOL); if (err) { return 1; } for (trusted_url = csp->config->trust_list; *trusted_url != NULL; trusted_url++) { if (url_match(*trusted_url, rhttp)) { /* if the URL's referrer is from a trusted referrer, then * add the target spec to the trustfile as an unblocked * domain and return 0 (which means it's OK). */ FILE *fp; if (NULL != (fp = fopen(csp->config->trustfile, "a"))) { char * path; char * path_end; char * new_entry = strdup("~"); string_append(&new_entry, csp->http->hostport); path = csp->http->path; if ( (path[0] == '/') && (path[1] == '~') && ((path_end = strchr(path + 2, '/')) != NULL)) { /* since this path points into a user's home space * be sure to include this spec in the trustfile. */ long path_len = path_end - path; /* save offset */ path = strdup(path); /* Copy string */ if (path != NULL) { path_end = path + path_len; /* regenerate ptr to new buffer */ *(path_end + 1) = '\0'; /* Truncate path after '/' */ } string_join(&new_entry, path); } /* * Give a reason for generating this entry. */ string_append(&new_entry, " # Trusted referrer was: "); string_append(&new_entry, referer); if (new_entry != NULL) { if (-1 == fprintf(fp, "%s\n", new_entry)) { log_error(LOG_LEVEL_ERROR, "Failed to append \'%s\' to trustfile \'%s\': %E", new_entry, csp->config->trustfile); } freez(new_entry); } else { /* FIXME: No way to handle out-of memory, so mostly ignoring it */ log_error(LOG_LEVEL_ERROR, "Out of memory adding pattern to trust file"); } fclose(fp); } else { log_error(LOG_LEVEL_ERROR, "Failed to append new entry for \'%s\' to trustfile \'%s\': %E", csp->http->hostport, csp->config->trustfile); } return 0; } } return 1; } #endif /* def FEATURE_TRUST */ /********************************************************************* * * Function : pcrs_filter_response * * Description : Execute all text substitutions from all applying * +filter actions on the text buffer that's been * accumulated in csp->iob->buf. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : a pointer to the (newly allocated) modified buffer. * or NULL if there were no hits or something went wrong * *********************************************************************/ static char *pcrs_filter_response(struct client_state *csp) { int hits = 0; int i; size_t size, prev_size; char *old = NULL; char *new = NULL; pcrs_job *job; struct file_list *fl; struct re_filterfile_spec *b; struct list_entry *filtername; /* * Sanity first */ if (csp->iob->cur >= csp->iob->eod) { return(NULL); } if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "content filtering enabled, but no content filters available."); return(NULL); } size = (size_t)(csp->iob->eod - csp->iob->cur); old = csp->iob->cur; for (i = 0; i < MAX_AF_FILES; i++) { fl = csp->rlist[i]; if ((NULL == fl) || (NULL == fl->f)) { /* * Either there are no filter files * left, or this filter file just * contains no valid filters. * * Continue to be sure we don't miss * valid filter files that are chained * after empty or invalid ones. */ continue; } /* * For all applying +filter actions, look if a filter by that * name exists and if yes, execute it's pcrs_joblist on the * buffer. */ for (b = fl->f; b; b = b->next) { if (b->type != FT_CONTENT_FILTER) { /* Skip header filters */ continue; } for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first; filtername ; filtername = filtername->next) { if (strcmp(b->name, filtername->str) == 0) { int current_hits = 0; /* Number of hits caused by this filter */ int job_number = 0; /* Which job we're currently executing */ int job_hits = 0; /* How many hits the current job caused */ pcrs_job *joblist = b->joblist; if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b); if (NULL == joblist) { log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name); continue; } prev_size = size; /* Apply all jobs from the joblist */ for (job = joblist; NULL != job; job = job->next) { job_number++; job_hits = pcrs_execute(job, old, size, &new, &size); if (job_hits >= 0) { /* * That went well. Continue filtering * and use the result of this job as * input for the next one. */ current_hits += job_hits; if (old != csp->iob->cur) { freez(old); } old = new; } else { /* * This job caused an unexpected error. Inform the user * and skip the rest of the jobs in this filter. We could * continue with the next job, but usually the jobs * depend on each other or are similar enough to * fail for the same reason. * * At the moment our pcrs expects the error codes of pcre 3.4, * but newer pcre versions can return additional error codes. * As a result pcrs_strerror()'s error message might be * "Unknown error ...", therefore we print the numerical value * as well. * * XXX: Is this important enough for LOG_LEVEL_ERROR or * should we use LOG_LEVEL_RE_FILTER instead? */ log_error(LOG_LEVEL_ERROR, "Skipped filter \'%s\' after job number %u: %s (%d)", b->name, job_number, pcrs_strerror(job_hits), job_hits); break; } } if (b->dynamic) pcrs_free_joblist(joblist); log_error(LOG_LEVEL_RE_FILTER, "filtering %s%s (size %d) with \'%s\' produced %d hits (new size %d).", csp->http->hostport, csp->http->path, prev_size, b->name, current_hits, size); hits += current_hits; } } } } /* * If there were no hits, destroy our copy and let * chat() use the original in csp->iob */ if (!hits) { freez(new); return(NULL); } csp->flags |= CSP_FLAG_MODIFIED; csp->content_length = size; clear_iob(csp->iob); return(new); } /********************************************************************* * * Function : gif_deanimate_response * * Description : Deanimate the GIF image that has been accumulated in * csp->iob->buf, set csp->content_length to the modified * size and raise the CSP_FLAG_MODIFIED flag. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : a pointer to the (newly allocated) modified buffer. * or NULL in case something went wrong. * *********************************************************************/ static char *gif_deanimate_response(struct client_state *csp) { struct binbuffer *in, *out; char *p; size_t size; size = (size_t)(csp->iob->eod - csp->iob->cur); if ( (NULL == (in = (struct binbuffer *)zalloc(sizeof *in ))) || (NULL == (out = (struct binbuffer *)zalloc(sizeof *out))) ) { log_error(LOG_LEVEL_DEANIMATE, "failed! (no mem)"); return NULL; } in->buffer = csp->iob->cur; in->size = size; if (gif_deanimate(in, out, strncmp("last", csp->action->string[ACTION_STRING_DEANIMATE], 4))) { log_error(LOG_LEVEL_DEANIMATE, "failed! (gif parsing)"); freez(in); buf_free(out); return(NULL); } else { if ((int)size == out->offset) { log_error(LOG_LEVEL_DEANIMATE, "GIF not changed."); } else { log_error(LOG_LEVEL_DEANIMATE, "Success! GIF shrunk from %d bytes to %d.", size, out->offset); } csp->content_length = out->offset; csp->flags |= CSP_FLAG_MODIFIED; p = out->buffer; freez(in); freez(out); return(p); } } /********************************************************************* * * Function : get_filter_function * * Description : Decides which content filter function has * to be applied (if any). * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : The content filter function to run, or * NULL if no content filter is active * *********************************************************************/ static filter_function_ptr get_filter_function(const struct client_state *csp) { filter_function_ptr filter_function = NULL; /* * Choose the applying filter function based on * the content type and action settings. */ if ((csp->content_type & CT_TEXT) && (csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) { filter_function = pcrs_filter_response; } else if ((csp->content_type & CT_GIF) && (csp->action->flags & ACTION_DEANIMATE)) { filter_function = gif_deanimate_response; } return filter_function; } /********************************************************************* * * Function : remove_chunked_transfer_coding * * Description : In-situ remove the "chunked" transfer coding as defined * in rfc2616 from a buffer. * * Parameters : * 1 : buffer = Pointer to the text buffer * 2 : size = In: Number of bytes to be processed, * Out: Number of bytes after de-chunking. * (undefined in case of errors) * * Returns : JB_ERR_OK for success, * JB_ERR_PARSE otherwise * *********************************************************************/ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) { size_t newsize = 0; unsigned int chunksize = 0; char *from_p, *to_p; assert(buffer); from_p = to_p = buffer; if (sscanf(buffer, "%x", &chunksize) != 1) { log_error(LOG_LEVEL_ERROR, "Invalid first chunksize while stripping \"chunked\" transfer coding"); return JB_ERR_PARSE; } while (chunksize > 0U) { if (NULL == (from_p = strstr(from_p, "\r\n"))) { log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding"); return JB_ERR_PARSE; } if (chunksize >= *size - newsize) { log_error(LOG_LEVEL_ERROR, "Chunk size %u exceeds buffered data left. " "Already digested %u of %u buffered bytes.", chunksize, (unsigned int)newsize, (unsigned int)*size); return JB_ERR_PARSE; } newsize += chunksize; from_p += 2; memmove(to_p, from_p, (size_t) chunksize); to_p = buffer + newsize; from_p += chunksize + 2; if (sscanf(from_p, "%x", &chunksize) != 1) { log_error(LOG_LEVEL_INFO, "Invalid \"chunked\" transfer encoding detected and ignored."); break; } } /* XXX: Should get its own loglevel. */ log_error(LOG_LEVEL_RE_FILTER, "De-chunking successful. Shrunk from %d to %d", *size, newsize); *size = newsize; return JB_ERR_OK; } /********************************************************************* * * Function : prepare_for_filtering * * Description : If necessary, de-chunks and decompresses * the content so it can get filterd. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK for success, * JB_ERR_PARSE otherwise * *********************************************************************/ static jb_err prepare_for_filtering(struct client_state *csp) { jb_err err = JB_ERR_OK; /* * If the body has a "chunked" transfer-encoding, * get rid of it, adjusting size and iob->eod */ if (csp->flags & CSP_FLAG_CHUNKED) { size_t size = (size_t)(csp->iob->eod - csp->iob->cur); log_error(LOG_LEVEL_RE_FILTER, "Need to de-chunk first"); err = remove_chunked_transfer_coding(csp->iob->cur, &size); if (JB_ERR_OK == err) { csp->iob->eod = csp->iob->cur + size; csp->flags |= CSP_FLAG_MODIFIED; } else { return JB_ERR_PARSE; } } #ifdef FEATURE_ZLIB /* * If the body has a supported transfer-encoding, * decompress it, adjusting size and iob->eod. */ if (csp->content_type & (CT_GZIP|CT_DEFLATE)) { if (0 == csp->iob->eod - csp->iob->cur) { /* Nothing left after de-chunking. */ return JB_ERR_OK; } err = decompress_iob(csp); if (JB_ERR_OK == err) { csp->flags |= CSP_FLAG_MODIFIED; csp->content_type &= ~CT_TABOO; } else { /* * Unset CT_GZIP and CT_DEFLATE to remember not * to modify the Content-Encoding header later. */ csp->content_type &= ~CT_GZIP; csp->content_type &= ~CT_DEFLATE; } } #endif return err; } /********************************************************************* * * Function : execute_content_filters * * Description : Executes a given content filter. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : Pointer to the modified buffer, or * NULL if filtering failed or wasn't necessary. * *********************************************************************/ char *execute_content_filters(struct client_state *csp) { filter_function_ptr content_filter; assert(content_filters_enabled(csp->action)); if (0 == csp->iob->eod - csp->iob->cur) { /* * No content (probably status code 301, 302 ...), * no filtering necessary. */ return NULL; } if (JB_ERR_OK != prepare_for_filtering(csp)) { /* * failed to de-chunk or decompress. */ return NULL; } if (0 == csp->iob->eod - csp->iob->cur) { /* * Clown alarm: chunked and/or compressed nothing delivered. */ return NULL; } content_filter = get_filter_function(csp); return ((*content_filter)(csp)); } /********************************************************************* * * Function : get_url_actions * * Description : Gets the actions for this URL. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : http = http_request request for blocked URLs * * Returns : N/A * *********************************************************************/ void get_url_actions(struct client_state *csp, struct http_request *http) { struct file_list *fl; struct url_actions *b; int i; init_current_action(csp->action); for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL)) { return; } apply_url_actions(csp->action, http, b); } return; } /********************************************************************* * * Function : apply_url_actions * * Description : Applies a list of URL actions. * * Parameters : * 1 : action = Destination. * 2 : http = Current URL * 3 : b = list of URL actions to apply * * Returns : N/A * *********************************************************************/ void apply_url_actions(struct current_action_spec *action, struct http_request *http, struct url_actions *b) { if (b == NULL) { /* Should never happen */ return; } for (b = b->next; NULL != b; b = b->next) { if (url_match(b->url, http)) { merge_current_action(action, b->action); } } } /********************************************************************* * * Function : get_forward_override_settings * * Description : Returns forward settings as specified with the * forward-override{} action. forward-override accepts * forward lines similar to the one used in the * configuration file, but without the URL pattern. * * For example: * * forward / . * * in the configuration file can be replaced with * the action section: * * {+forward-override{forward .}} * / * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : Pointer to forwarding structure in case of success. * Invalid syntax is fatal. * *********************************************************************/ const static struct forward_spec *get_forward_override_settings(struct client_state *csp) { const char *forward_override_line = csp->action->string[ACTION_STRING_FORWARD_OVERRIDE]; char forward_settings[BUFFER_SIZE]; char *http_parent = NULL; /* variable names were chosen for consistency reasons. */ struct forward_spec *fwd = NULL; int vec_count; char *vec[3]; assert(csp->action->flags & ACTION_FORWARD_OVERRIDE); /* Should be enforced by load_one_actions_file() */ assert(strlen(forward_override_line) < sizeof(forward_settings) - 1); /* Create a copy ssplit can modify */ strlcpy(forward_settings, forward_override_line, sizeof(forward_settings)); if (NULL != csp->fwd) { /* * XXX: Currently necessary to prevent memory * leaks when the show-url-info cgi page is visited. */ unload_forward_spec(csp->fwd); } /* * allocate a new forward node, valid only for * the lifetime of this request. Save its location * in csp as well, so sweep() can free it later on. */ fwd = csp->fwd = zalloc(sizeof(*fwd)); if (NULL == fwd) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for forward-override{%s}", forward_override_line); /* Never get here - LOG_LEVEL_FATAL causes program exit */ return NULL; } vec_count = ssplit(forward_settings, " \t", vec, SZ(vec)); if ((vec_count == 2) && !strcasecmp(vec[0], "forward")) { fwd->type = SOCKS_NONE; /* Parse the parent HTTP proxy host:port */ http_parent = vec[1]; } else if (vec_count == 3) { char *socks_proxy = NULL; if (!strcasecmp(vec[0], "forward-socks4")) { fwd->type = SOCKS_4; socks_proxy = vec[1]; } else if (!strcasecmp(vec[0], "forward-socks4a")) { fwd->type = SOCKS_4A; socks_proxy = vec[1]; } else if (!strcasecmp(vec[0], "forward-socks5")) { fwd->type = SOCKS_5; socks_proxy = vec[1]; } else if (!strcasecmp(vec[0], "forward-socks5t")) { fwd->type = SOCKS_5T; socks_proxy = vec[1]; } if (NULL != socks_proxy) { /* Parse the SOCKS proxy host[:port] */ fwd->gateway_port = 1080; parse_forwarder_address(socks_proxy, &fwd->gateway_host, &fwd->gateway_port); http_parent = vec[2]; } } if (NULL == http_parent) { log_error(LOG_LEVEL_FATAL, "Invalid forward-override syntax in: %s", forward_override_line); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } /* Parse http forwarding settings */ if (strcmp(http_parent, ".") != 0) { fwd->forward_port = 8000; parse_forwarder_address(http_parent, &fwd->forward_host, &fwd->forward_port); } assert (NULL != fwd); log_error(LOG_LEVEL_CONNECT, "Overriding forwarding settings based on \'%s\'", forward_override_line); return fwd; } /********************************************************************* * * Function : forward_url * * Description : Should we forward this to another proxy? * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : http = http_request request for current URL * * Returns : Pointer to forwarding information. * *********************************************************************/ const struct forward_spec *forward_url(struct client_state *csp, const struct http_request *http) { static const struct forward_spec fwd_default[1] = { FORWARD_SPEC_INITIALIZER }; struct forward_spec *fwd = csp->config->forward; if (csp->action->flags & ACTION_FORWARD_OVERRIDE) { return get_forward_override_settings(csp); } if (fwd == NULL) { return fwd_default; } while (fwd != NULL) { if (url_match(fwd->url, http)) { return fwd; } fwd = fwd->next; } return fwd_default; } /********************************************************************* * * Function : direct_response * * Description : Check if Max-Forwards == 0 for an OPTIONS or TRACE * request and if so, return a HTTP 501 to the client. * * FIXME: I have a stupid name and I should handle the * requests properly. Still, what we do here is rfc- * compliant, whereas ignoring or forwarding are not. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : http_response if , NULL if nonmatch or handler fail * *********************************************************************/ struct http_response *direct_response(struct client_state *csp) { struct http_response *rsp; struct list_entry *p; if ((0 == strcmpic(csp->http->gpc, "trace")) || (0 == strcmpic(csp->http->gpc, "options"))) { for (p = csp->headers->first; (p != NULL) ; p = p->next) { if (!strncmpic(p->str, "Max-Forwards:", 13)) { unsigned int max_forwards; /* * If it's a Max-Forwards value of zero, * we have to intercept the request. */ if (1 == sscanf(p->str+12, ": %u", &max_forwards) && max_forwards == 0) { /* * FIXME: We could handle at least TRACE here, * but that would require a verbatim copy of * the request which we don't have anymore */ log_error(LOG_LEVEL_HEADER, "Detected header \'%s\' in OPTIONS or TRACE request. Returning 501.", p->str); /* Get mem for response or fail*/ if (NULL == (rsp = alloc_http_response())) { return cgi_error_memory(); } if (NULL == (rsp->status = strdup("501 Not Implemented"))) { free_http_response(rsp); return cgi_error_memory(); } rsp->is_static = 1; rsp->crunch_reason = UNSUPPORTED; return(finish_http_response(csp, rsp)); } } } } return NULL; } /********************************************************************* * * Function : content_requires_filtering * * Description : Checks whether there are any content filters * enabled for the current request and if they * can actually be applied.. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : TRUE for yes, FALSE otherwise * *********************************************************************/ int content_requires_filtering(struct client_state *csp) { if ((csp->content_type & CT_TABOO) && !(csp->action->flags & ACTION_FORCE_TEXT_MODE)) { return FALSE; } /* * Are we enabling text mode by force? */ if (csp->action->flags & ACTION_FORCE_TEXT_MODE) { /* * Do we really have to? */ if (csp->content_type & CT_TEXT) { log_error(LOG_LEVEL_HEADER, "Text mode is already enabled."); } else { csp->content_type |= CT_TEXT; log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!"); } } if (!(csp->content_type & CT_DECLARED)) { /* * The server didn't bother to declare a MIME-Type. * Assume it's text that can be filtered. * * This also regulary happens with 304 responses, * therefore logging anything here would cause * too much noise. */ csp->content_type |= CT_TEXT; } /* * Choose the applying filter function based on * the content type and action settings. */ if ((csp->content_type & CT_TEXT) && (csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) { return TRUE; } else if ((csp->content_type & CT_GIF) && (csp->action->flags & ACTION_DEANIMATE)) { return TRUE; } return FALSE; } /********************************************************************* * * Function : content_filters_enabled * * Description : Checks whether there are any content filters * enabled for the current request. * * Parameters : * 1 : action = Action spec to check. * * Returns : TRUE for yes, FALSE otherwise * *********************************************************************/ int content_filters_enabled(const struct current_action_spec *action) { return ((action->flags & ACTION_DEANIMATE) || !list_is_empty(action->multi[ACTION_MULTI_FILTER])); } /********************************************************************* * * Function : filters_available * * Description : Checks whether there are any filters available. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ int filters_available(const struct client_state *csp) { int i; for (i = 0; i < MAX_AF_FILES; i++) { const struct file_list *fl = csp->rlist[i]; if ((NULL != fl) && (NULL != fl->f)) { return TRUE; } } return FALSE; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./ChangeLog000640 001751 001751 00000270140 12116121460 015532 0ustar00fkfk000000 000000 -------------------------------------------------------------------- ChangeLog for Privoxy -------------------------------------------------------------------- *** Version 3.0.21 stable *** - Bug fixes: - On POSIX-like platforms, network sockets with file descriptor values above FD_SETSIZE are properly rejected. Previously they could cause memory corruption in configurations that allowed the limit to be reached. - Proxy authentication headers are removed unless the new directive enable-proxy-authentication-forwarding is used. Forwarding the headers potentionally allows malicious sites to trick the user into providing them with login information. Reported by Chris John Riley. - Compiles on OS/2 again now that unistd.h is only included on platforms that have it. - General improvements: - The show-status page shows the FEATURE_STRPTIME_SANITY_CHECKS status. - A couple of assert()s that could theoretically dereference NULL pointers in debug builds have been relocated. - Added an LSB info block to the generic start script. Based on a patch from Natxo Asenjo. - The max-client-connections default has been changed to 128 which should be more than enough for most setups. - Action file improvements: - Block rover.ebay./ar.*\&adtype= instead of "/.*\&adtype=" which caused too man false positives. Reported by u302320 in #360284, additional feedback from Adam Piggott. - Unblock '.advrider.com/' and '/.*ADVrider'. Anonymously reported in #3603636. - Stop blocking '/js/slider\.js'. Reported by Adam Piggott in #3606635 and _lvm in #2791160. - Filter file improvements: - Added an iframes filter. - Documentation improvements: - The whole GPLv2 text is included in the user manual now, so Privoxy can serve it itself and the user can read it without having to wade through GPLv3 ads first. - Properly numbered and underlined a couple of section titles in the config that where previously overlooked due to a flaw in the conversion script. Reported by Ralf Jungblut. - Improved the support instruction to hopefully make it harder to unintentionally provide insufficient information when requesting support. Previously it wasn't obvious that the information we need in bug reports is usually also required in support requests. - Removed documentation about packages that haven't been provided in years. - Privoxy-Regression-Test: - Only log the test number when not running in verbose mode The position of the test is rarely relevant and it previously wasn't exactly obvious which one of the numbers was useful to repeat the test with --test-number. - GNUmakefile improvements: - Factor generate-config-file out of config-file to make testing more convenient. - The clean target now also takes care of patch leftovers. *** Version 3.0.20 beta *** - Bug fixes: - Client sockets are now properly shutdown and drained before being closed. This fixes page truncation issues with clients that aggressively pipeline data on platforms that otherwise discard already written data. The issue mainly affected Opera users and was initially reported by Kevin in #3464439, szotsaki provided additional information to track down the cause. - Fix latency calculation for shared connections (disabled by default). It was broken since their introduction in 2009. The calculated latency for most connections would be 0 in which case the timeout detection failed to account for the real latency. - Reject URLs with invalid port. Previously they were parsed incorrectly and characters between the port number and the first slash were silently dropped as shown by curl test 187. - The default-server-timeout and socket-timeout directives accept 0 as valid value. - Fix a race condition on Windows that could cause Privoxy to become unresponsive after toggling it on or off through the taskbar icon. Reported by Tim H. in #3525694. - Fix the compilation on Windows when configured without IPv6 support. - Fix an assertion that could cause debug builds to abort() in case of socks5 connection failures with "debug 2" enabled. - Fix an assertion that could cause debug builds to abort() if a filter contained nul bytes in the replacement text. - General improvements: - Significantly improved keep-alive support for both client and server connections. - New debug log level 65536 which logs all actions that were applied to the request. - New directive client-header-order to forward client headers in a different order than the one in which they arrived. - New directive tolerate-pipelining to allow client-side pipelining. If enabled (3.0.20 beta enables it by default), Privoxy will keep pipelined client requests around to deal with them once the current request has been served. - New --config-test option to let Privoxy exit after checking whether or not the configuration seems valid. The limitations noted in TODO #22 and #23 still apply. Based on a patch by Ramkumar Chinchani. - New limit-cookie-lifetime{} action to let cookies expire before the end of the session. Suggested by Rick Sykes in #1049575. - Increase the hard-coded maximum number of actions and filter files from 10 to 30 (each). It doesn't significantly affect Privoxy's memory usage and recompiling wasn't an option for all Privoxy users that reached the limit. - Add support for chunk-encoded client request bodies. Previously chunk-encoded request bodies weren't guaranteed to be forwarded correctly, so this can also be considered a bug fix although chunk-encoded request bodies aren't commonly used in the real world. - Add support for Tor's optimistic-data SOCKS extension, which can reduce the latency for requests on newly created connections. Currently only the headers are sent optimistically and only if the client request has already been read completely which rules out requests with large bodies. - After preventing the client from pipelining, don't signal keep-alive intentions. When looking at the response headers alone, it previously wasn't obvious from the client's perspective that no additional responses should be expected. - Stop considering client sockets tainted after receiving a request with body. It hasn't been necessary for a while now and unnecessarily causes test failures when using curl's test suite. - Allow HTTP/1.0 clients to signal interest in keep-alive through the Proxy-Connection header. While such client are rare in the real world, it doesn't hurt and couple of curl tests rely on it. - Only remove duplicated Content-Type headers when filters are enabled. If they are not it doesn't cause ill effects and the user might not want it. Downgrade the removal message to LOG_LEVEL_HEADER to clarify that it's not an error in Privoxy and is unlikely to cause any problems in general. Anonymously reported in #3599335. - Set the socket option SO_LINGER for the client socket. - Move several variable declarations to the beginning of their code block. It's required when compiling with gcc 2.95 which is still used on some platforms. Initial patch submitted by Simon South in #3564815. - Optionally try to sanity-check strptime() results before trusting them. Broken strptime() implementations have caused problems in the past and the most recent offender seems to be FreeBSD's libc (standards/173421). - When filtering is enabled, let Range headers pass if the range starts at the beginning. This should work around (or at least reduce) the video playback issues with various Apple clients as reported by Duc in #3426305. - Do not confuse a client hanging up with a connection time out. If a client closes its side of the connection without sending a request line, do not send the CLIENT_CONNECTION_TIMEOUT_RESPONSE, but report the condition properly. - Allow closing curly braces as part of action values as long as they are escaped. - On Windows, the logfile is now written before showing the GUI error message which blocks until the user acknowledges it. Reported by Adriaan in #3593603. - Remove an unreasonable parameter limit in the CGI interface. The new parameter limit depends on the memory available and is currently unlikely to be reachable, due to other limits in both Privoxy and common clients. Reported by Andrew on ijbswa-users@. - Decrease the chances of parse failures after requests with unsupported methods were sent to the CGI interface. - Action file improvements: - Remove the comment that indicated that updated default.action versions are released on their own. - Block 'optimize.indieclick.com/' and 'optimized-by.rubiconproject.com/' - Unblock 'adjamblog.wordpress.com/' and 'adjamblog.files.wordpress.com/'. Reported by Ryan Farmer in #3496116. - Unblock '/.*Bugtracker'. Reported by pwhk in #3522341. - Add test URLs for '.freebsd.org' and '.watson.org'. - Unblock '.urbandictionary.com/popular'. - Block '.adnxs.com/'. - Block 'farm.plista.com/widgetdata.php'. - Block 'rotation.linuxnewmedia.com/'. - Block 'reklamy.sfd.pl/'. Reported by kacperdominik in #3399948. - Block 'g.adspeed.net/'. - Unblock 'websupport.wdc.com/'. Reported by Adam Piggot in #3577851. - Block '/openx/www/delivery/'. - Disable fast-redirects for '.googleapis.com/'. - Block 'imp.double.net/'. Reported by David Bo in #3070411. - Block 'gm-link.com/' which is used for email tracking. Reported by David Bo in #1812733. - Verify that requests to "bwp." are blocked. URL taken from #1736879 submitted by Francois Marier. - Block '/.*bannerid='. Reported by Adam Piggott in #2975779. - Block 'cltomedia.info/delivery/' and '.adexprt.com/'. Anonymously reported in #2965254. - Block 'de17a.com/'. Reported by David Bo in #3061472. - Block 'oskar.tradera.com/'. Reported by David Bo in #3060596. - Block '/scripts/webtrends\.js'. Reported by johnd16 in #3002729. - Block requests for 'pool.*.adhese.com/'. Reported by johnd16 in #3002716. - Update path pattern for Coremetrics and add tests. Pattern and URLs submitted by Adam Piggott #3168443. - Enable +fast-redirects{check-decoded-url} for 'tr.anp.se/'. Reported by David Bo in #3268832. - Unblock '.conrad.se/newsletter/banners/'. Reported by David Bo in #3413824. - Block '.tynt.com/'. Reported by Dan Stahlke in #3421767. - Unblock '.bbci.co.uk/radio/'. Reported by Adam Piggott in #3569603. - Block requests to 'service.maxymiser.net/'. Reported by johnd16 in #3118401 (with a previous URL). - Disable fast-redirects for Google's "let's pretend your computer is infected" page. - Unblock '/.*download' to resolve actionsfile feedback #3498129. Submitted by Steven Kolins (soundcloud.com not working). - Unblock '.wlxrs.com/' which is required by hotmail.com. Fixes #3413827 submitted by David Bo. - Add two unblock patterns for popup radio and TV players. Submitted by Adam Piggott in #3596089. - Filter file improvements & bug fixes: - Add a referer tagger. - Reduce the likelihood that the google filter messes up HTML-generating JavaScript. Reported by Zeno Kugy in #3520260. - Documentation improvements: - Revised all OS X sections due to new packaging module (OSXPackageBuilder). - Update the list of supported operating systems to clarify that all Windows versions after 95 are expected to work and note that the platform-specific code for AmigaOS and QNX currently isn't maintained. - Update 'Signals' section, the only explicitly handled signals are SIGINT, SIGTERM and SIGHUP. - Add Haiku to the list of operating systems on which Privoxy is known to run. - Add DragonFly to the list of BSDs on which Privoxy is known to run. - Removed references to redhat-specific documentation set since it no longer exists. - Removed references to building PDFs since we no longer do so. - Multiple listen-address directives are supported since 3.0.18, correct the documentation to say so. - Remove bogus section about long and short being preferable to int. - Corrected some Internet JunkBuster references to Privoxy. - Removed references to www.junkbusters.com since it is no longer maintained. Reported by Angelina Matson. - Various grammar and spelling corrections - Add a client-header-tagger{} example for disabling filtering for range requests. - Correct a URL in the "Privoxy with Tor" FAQ. - Spell 'refresh-tags' correctly. Reported by Don in #3571927. - Sort manpage options alphabetically. - Remove an incorrect sentence in the toggle section. The toggle state doesn't affect whether or not the Windows version uses the tray icon. Reported by Zeno Kugy in #3596395. - Add new contributors since 3.0.19. - Log message improvements: - When stopping to watch a client socket due to pipelining, additionally log the socket number. - Log the client socket and its condition before closing it. This makes it more obvious that the socket actually gets closed and should help when diagnosing problems like #3464439. - In case of SOCKS5 failures, do not explicitly log the server's response. It hasn't helped so far and the response can already be logged by enabling "debug 32768" anyway. This reverts v1.81 and the follow-up bug fix v1.84. - Relocate the connection-accepted message from listen_loop() to serve(). This way it's printed by the thread that is actually serving the connection which is nice when grepping for thread ids in log files. - Code cleanups: - Remove compatibility layer for versions prior to 3.0 since it has been obsolete for more than 10 years now. - Remove the ijb_isupper() and ijb_tolower() macros from parsers.c since they aren't used in this file. - Removed the 'Functions declared include:' comment sections since they tend to be incomplete, incorrect and out of date and the benefit seems questionable. - Various comment grammar and comprehensibility improvements. - Remove a pointless fflush() call in chat(). Flushing all streams pretty much all the time for no obvious reason is ridiculous. - Relocate ijb_isupper()'s definition to project.h and get the ijb_tolower() definition from there, too. - Relocate ijb_isdigit()'s definition to project.h. - Rename ijb_foo macros to privoxy_foo. - Add malloc_or_die() which will allow to simplify code paths where malloc() failures don't need to be handled gracefully. - Add strdup_or_die() which will allow to simplify code paths where strdup() failures don't need to be handled gracefully. - Replace strdup() calls with strdup_or_die() calls where it's safe and simplifies the code. - Fix white-space around parentheses. - Add missing white-space behind if's and the following parentheses. - Unwrap a memcpy() call in resolve_hostname_to_ip(). - Declare pcrs_get_delimiter()'s delimiters[] static const. - Various optimisations to remove dead code and merge inefficient code structures for improved clarity, performance or code compactness. - Various data type corrections. - Change visibility of several code segments when compiling without FEATURE_CONNECTION_KEEP_ALIVE enabled for clarity. - In pcrs_get_delimiter(), do not use delimiters outside the ASCII range. Fixes a clang complaint. - Fix an error message in get_last_url() nobody is supposed to see. Reported by Matthew Fischer in #3507301. - Fix a typo in the no-zlib-support complaint. Patch submitted by Matthew Fischer in #3507304. - Shorten ssplit()'s prototype by removing the last two arguments. We always want to skip empty fields and ignore leading delimiters, so having parameters for this only complicates the API. - Use an enum for the type of the action value. - Rename action_name's member takes_value to value_type as it isn't used as boolean. - Turn family mismatches in match_sockaddr() into fatal errors. - Let enlist_unique_header() verify that the caller didn't pass a header containing either \r or \n. - Change the hashes used in load_config() to unsigned int. That's what hash_string() actually returns and using a potentially larger type is at best useless. - Use privoxy_tolower() instead of vanilla tolower() with manual casting of the argument. - Catch ssplit() failures in parse_cgi_parameters(). - Privoxy-Regression-Test: - Add an 'Overwrite condition' directive to skip any matching tests before it. As it has a global scope, using it is more convenient than clowning around with the Ignore directive. - Log to STDOUT instead of STDERR. - Include the Privoxy version in the output. - Various grammar and spelling corrections in documentation and code. - Additional tests for range requests with filtering enabled. - Tests with mostly invalid range request. - Add a couple of hide-if-modified-since{} tests with different date formats. - Cleaned up the format of the regression-tests.action file to match the format of default.action. - Remove the "Copyright" line from print_version(). When using --help, every line of screen space matters and thus shouldn't be wasted on things the user doesn't care about. - Privoxy-Log-Parser: - Improve the --statistics performance by skipping sanity checks for input that shouldn't affect the results anyway. Add a --strict-checks option that enables some of the checks again, just in case anybody cares. - The distribution of client requests per connection is included in the --statistic output. - The --accept-unknown-messages option has been removed and the behavior is now the default. - Accept and (mostly) highlight new log messages introduced with Privoxy 3.0.20. - uagen: - Bump generated Firefox version to 17. - GNUmakefile improvements: - The dok-tidy target no longer taints documents with a tidy-mark - Change RA_MODE from 0664 to 0644. Suggested by Markus Dittrich in #3505445. - Remove tidy's clean flag as it changes the scope of attributes. Link-specific colors end up being applied to all text. Reported by Adam Piggott in #3569551. - Leave it up to the user whether or not smart tags are inserted. - Let w3m itself do the line wrapping for the config file. It works better than fmt as it can honour pre tags causing less unintentional line breaks. - Ditch a pointless '-r' passed to rm to delete files. - The config-file target now requires less manual intervention and updates the original config. - Change WDUMP to generate ASCII. Add WDUMP_UTF8 to allow UTF-8 in the AUTHORS file so the names are right. - Stop pretending that lynx and links are supported for the documentation. - configure improvements: - On Haiku, do not pass -lpthread to the compiler. Haiku's pthreads implementation is contained in its system library, libroot, so no additional library needs to be searched. Patch submitted by Simon South in #3564815. - Additional Haiku-specific improvements. Disable checks intended for multi-user systems as Haiku is presently single-user. Group Haiku-specific settings in their own section, following the pattern for Solaris, OS/2 and AmigaOS. Add additional library-related settings to remove the need for providing configure with custom LDFLAGS. Submitted by Simon South in #3574538. *** Version 3.0.19 Stable *** - Bug fixes: - Prevent a segmentation fault when de-chunking buffered content. It could be triggered by malicious web servers if Privoxy was configured to filter the content and running on a platform where SIZE_T_MAX isn't larger than UINT_MAX, which probably includes most 32-bit systems. On those platforms, all Privoxy versions before 3.0.19 appear to be affected. To be on the safe side, this bug should be presumed to allow code execution as proving that it doesn't seems unrealistic. - Do not expect a response from the SOCKS4/4A server until it got something to respond to. This regression was introduced in 3.0.18 and prevented the SOCKS4/4A negotiation from working. Reported by qqqqqw in #3459781. - General improvements: - Fix an off-by-one in an error message about connect failures. - Use a GNUMakefile variable for the webserver root directory and update the path. Sourceforge changed it which broke various web-related targets. - Update the CODE_STATUS description. *** Version 3.0.18 Stable *** - Bug fixes: - If a generated redirect URL contains characters RFC 3986 doesn't permit, they are (re)encoded. Not doing this makes Privoxy versions from 3.0.5 to 3.0.17 susceptible to HTTP response splitting (CWE-113) attacks if the +fast-redirects{check-decoded-url} action is used. - Fix a logic bug that could cause Privoxy to reuse a server socket after it got tainted by a server-header-tagger-induced block that was triggered before the whole server response had been read. If keep-alive was enabled and the request following the blocked one was to the same host and using the same forwarding settings, Privoxy would send it on the tainted server socket. While the server would simply treat it as a pipelined request, Privoxy would later on fail to properly parse the server's response as it would try to parse the unread data from the first response as server headers for the second one. Regression introduced in 3.0.17. - When implying keep-alive in client_connection(), remember that the client didn't. Fixes a regression introduced in 3.0.13 that would cause Privoxy to wait for additional client requests after receiving a HTTP/1.1 request with "Connection: close" set and connection sharing enabled. With clients which terminates the client connection after detecting that the whole body has been received it doesn't really matter, but with clients that don't the connection would be kept open until it timed out. - Fix a subtle race condition between prepare_csp_for_next_request() and sweep(). A thread preparing itself for the next client request could briefly appear to be inactive. If all other threads were already using more recent files, the thread could get its files swept away under its feet. So far this has only been reproduced while stress testing in valgrind while touching action files in a loop. It's unlikely to have caused any actual problems in the real world. - Disable filters if SDCH compression is used unless filtering is forced. If SDCH was combined with a supported compression algorithm, Privoxy previously could try to decompress it and ditch the Content-Encoding header even though the SDCH compression wasn't dealt with. Reported by zebul666 in #3225863. - Make a copy of the --user value and only mess with that when splitting user and group. On some operating systems modifying the value directly is reflected in the output of ps and friends and can be misleading. Reported by zepard in #3292710. - If forwarded-connect-retries is set, only retry if Privoxy is actually forwarding the request. Previously direct connections would be retried as well. - Fixed a small memory leak when retrying connections with IPv6 support enabled. - Remove an incorrect assertion in compile_dynamic_pcrs_job_list() It could be triggered by a pcrs job with an invalid pcre pattern (for example one that contains a lone quantifier). - If the --user argument user[.group] contains a dot, always bail out if no group has been specified. Previously the intended, but undocumented (and apparently untested), behaviour was to try interpreting the whole argument as user name, but the detection was flawed and checked for '0' instead of '\0', thus merely preventing group names beginning with a zero. - In html_code_map[], use a numeric character reference instead of ' which wasn't standardized before XHTML 1.0. - Fix an invalid free when compiled with FEATURE_GRACEFUL_TERMINATION and shut down through http://config.privoxy.org/die - In get_actions(), fix the "temporary" backwards compatibility hack to accept block actions without reason. It also covered other actions that should be rejected as invalid. Reported by Billy Crook. - General improvements: - Privoxy can (re)compress buffered content before delivering it to the client. Disabled by default as most users wouldn't benefit from it. - The +fast-redirects{check-decoded-url} action checks URL segments separately. If there are other parameters behind the redirect URL, this makes it unnecessary to cut them off by additionally using a +redirect{} pcrs command. Initial patch submitted by Jamie Zawinski in #3429848. - When loading action sections, verify that the referenced filters exist. Currently missing filters only result in an error message, but eventually the severity will be upgraded to fatal. - Allow to bind to multiple separate addresses. Patch set submitted by Petr Pisar in #3354485. - Set socket_error to errno if connecting fails in rfc2553_connect_to(). Previously rejected direct connections could be incorrectly reported as DNS issues if Privoxy was compiled with IPv6 support. - Adjust url_code_map[] so spaces are replaced with %20 instead of '+' While '+' can be used by client's submitting form data, this is not actually what Privoxy is using the lookups for. This is more of a cosmetic issue and doesn't fix any known problems. - When compiled without FEATURE_FAST_REDIRECTS, do not silently ignore +fast-redirect{} directives - Added a workaround for GNU libc's strptime() reporting negative year values when the parsed year is only specified with two digits. On affected systems cookies with such a date would not be turned into session cookies by the +session-cookies-only action. Reported by Vaeinoe in #3403560 - Fixed bind failures with certain GNU libc versions if no non-loopback IP address has been configured on the system. This is mainly an issue if the system is using DHCP and Privoxy is started before the network is completely configured. Reported by Raphael Marichez in #3349356. Additional insight from Petr Pisar. - Privoxy log messages now use the ISO 8601 date format %Y-%m-%d. It's only slightly longer than the old format, but contains the full date including the year and allows sorting by date (when grepping in multiple log files) without hassle. - In get_last_url(), do not bother trying to decode URLs that do not contain at least one '%' sign. It reduces the log noise and a number of unnecessary memory allocations. - In case of SOCKS5 failures, dump the socks response in the log message. - Simplify the signal setup in main(). - Streamline socks5_connect() slightly. - In socks5_connect(), require a complete socks response from the server. Previously Privoxy didn't care how much data the server response contained as long as the first two bytes contained the expected values. While at it, shrink the buffer size so Privoxy can't read more than a whole socks response. - In chat(), do not bother to generate a client request in case of direct CONNECT requests. It will not be used anyway. - Reduce server_last_modified()'s stack size. - Shorten get_http_time() by using strftime(). - Constify the known_http_methods pointers in unknown_method(). - Constify the time_formats pointers in parse_header_time(). - Constify the formerly_valid_actions pointers in action_used_to_be_valid(). - Introduce a GNUMakefile MAN_PAGE variable that defaults to privoxy.1. The Debian package uses section 8 for the man page and this should simplify the patch. - Deduplicate the INADDR_NONE definition for Solaris by moving it to jbsockets.h - In block_url(), ditch the obsolete workaround for ancient Netscape versions that supposedly couldn't properly deal with status code 403. - Remove a useless NULL pointer check in load_trustfile(). - Remove two useless NULL pointer checks in load_one_re_filterfile(). - Change url_code_map[] from an array of pointers to an array of arrays It removes an unnecessary layer of indirection and on 64bit system reduces the size of the binary a bit. - Fix various typos. Fixes taken from Debian's 29_typos.dpatch by Roland Rosenfeld. - Add a dok-tidy GNUMakefile target to clean up the messy HTML generated by the other dok targets. - GNUisms in the GNUMakefile have been removed. - Change the HTTP version in static responses to 1.1 - Synced config.sub and config.guess with upstream 2011-11-11/386c7218162c145f5f9e1ff7f558a3fbb66c37c5. - Add a dedicated function to parse the values of toggles. Reduces duplicated code in load_config() and provides better error handling. Invalid or missing toggle values are now a fatal error instead of being silently ignored. - Terminate HTML lines in static error messages with \n instead of \r\n. - Simplify cgi_error_unknown() a bit. - In LogPutString(), don't bother looking at pszText when not actually logging anything. - Change ssplit()'s fourth parameter from int to size_t. Fixes a clang complaint. - Add a warning that the statistics currently can't be trusted. Mention Privoxy-Log-Parser's --statistics option as an alternative for the time being. - In rfc2553_connect_to(), start setting cgi->error_message on error. - Change the expected status code returned for http://p.p/die depending on whether or not FEATURE_GRACEFUL_TERMINATION is available. - In cgi_die(), mark the client connection for closing. If the client will fetch the style sheet through another connection it gets the main thread out of the accept() state and should thus trigger the actual shutdown. - Add a proper CGI message for cgi_die(). - Don't enforce a logical line length limit in read_config_line(). - Slightly refactor server_last_modified() to remove useless gmtime*() calls. - In get_content_type(), also recognize '.jpeg' as JPEG extension. - Add '.png' to the list of recognized file extensions in get_content_type(). - In block_url(), consistently use the block reason "Request blocked by Privoxy" In two places the reason was "Request for blocked URL" which hides the fact that the request got blocked by Privoxy and isn't necessarily correct as the block may be due to tags. - In listen_loop(), reload the configuration files after accepting a new connection instead of before. Previously the first connection that arrived after a configuration change would still be handled with the old configuration. - In chat()'s receive-data loop, skip a client socket check if the socket will be written to right away anyway. This can increase the transfer speed for unfiltered content on fast network connections. - The socket timeout is used for SOCKS negotiations as well which previously couldn't timeout. - Don't keep the client connection alive if any configuration file changed since the time the connection came in. This is closer to Privoxy's behaviour before keep-alive support for client connection has been added and also less confusing in general. - Treat all Content-Type header values containing the pattern 'script' as a sign of text. Reported by pribog in #3134970. - Action file improvements: - Moved the site-specific block pattern section below the one for the generic patterns so for requests that are matched in both, the block reason for the domain is shown which is usually more useful than showing the one for the generic pattern. - Remove -prevent-compression from the fragile alias. It's no longer used anywhere by default and isn't known to break stuff anyway. - Add a (disabled) section to block various Facebook tracking URLs. Reported by Dan Stahlke in #3421764. - Add a (disabled) section to rewrite and redirect click-tracking URLs used on news.google.com. Reported by Dan Stahlke in #3421755. - Unblock linuxcounter.net/. Reported by Dan Stahlke in #3422612. - Block 'www91.intel.com/' which is used by Omniture. Reported by Adam Piggott in #3167370. - Disable the handle-as-empty-doc-returns-ok option and mark it as deprecated. Reminded by tceverling in #2790091. - Add ".ivwbox.de/" to the "Cross-site user tracking" section. Reported by Nettozahler in #3172525. - Unblock and fast-redirect ".awin1.com/.*=http://". Reported by Adam Piggott in #3170921. - Block "b.collective-media.net/". - Widen the Debian popcon exception to "qa.debian.org/popcon". Seen in Debian's 05_default_action.dpatch by Roland Rosenfeld. - Block ".gemius.pl/" which only seems to be used for user tracking. Reported by johnd16 in #3002731. Additional input from Lee and movax. - Disable banners-by-size filters for '.thinkgeek.com/'. The filter only seems to catch pictures of the inventory. - Block requests for 'go.idmnet.bbelements.com/please/showit/'. Reported by kacperdominik in #3372959. - Unblock adainitiative.org/. - Add a fast-redirects exception for '.googleusercontent.com/.*=cache'. - Add a fast-redirects exception for webcache.googleusercontent.com/. - Unblock http://adassier.wordpress.com/ and http://adassier.files.wordpress.com/. - Filter file improvements: - Let the yahoo filter hide '.ads'. - Let the msn filter hide overlay ads for Facebook 'likes' in search results and elements with the id 's_notf_div'. They only seem to be used to advertise site 'enhancements'. - Let the js-events filter additionally disarm setInterval(). Suggested by dg1727 in #3423775. - Documentation improvements: - Clarify the effect of compiling Privoxy with zlib support. Suggested by dg1727 in #3423782. - Point out that the SourceForge messaging system works like a black hole and should thus not be used to contact individual developers. - Mention some of the problems one can experience when not explicitly configuring an IP addresses as listen address. - Explicitly mention that hostnames can be used instead of IP addresses for the listen-address, that only the first address returned will be used and what happens if the address is invalid. Requested by Calestyo in #3302213. - Log message improvements: - If only the server connection is kept alive, do not pretend to wait for a new client request. - Remove a superfluous log message in forget_connection(). - In chat(), properly report missing server responses as such instead of calling them empty. - In forwarded_connect(), fix a log message nobody should ever see. - Fix a log message in socks5_connect(), a failed write operation was logged as failed read operation. - Let load_one_actions_file() properly complain about a missing '{' at the beginning of the file. Simply stating that a line is invalid isn't particularly helpful. - Do not claim to listen on a socket until Privoxy actually does. Patch submitted by Petr Pisar #3354485 - Prevent a duplicated LOG_LEVEL_CLF message when sending out the "no-server-data" response. - Also log the client socket when dropping a connection. - Include the destination host in the 'Request ... marked for blocking. limit-connect{...} doesn't allow CONNECT ...' message Patch submitted by Saperski in #3296250. - Prevent a duplicated log message if none of the resolved IP addresses were reachable. - In connect_to(), do not pretend to retry if forwarded-connect-retries is zero or unset. - When a specified user or group can't be found, put the name in single-quotes when logging it. - In rfc2553_connect_to(), explain getnameinfo() errors better. - Remove a useless log message in chat(). - When retrying to connect, also log the maximum number of connection attempts. - Rephrase a log message in compile_dynamic_pcrs_job_list(). Divide the error code and its meaning with a colon. Call the pcrs job dynamic and not the filter. Filters may contain dynamic and non-dynamic pcrs jobs at the same time. Only mention the name of the filter or tagger, but don't claim it's a filter when it could be a tagger. - In a fatal error message in load_one_actions_file(), cover both URL and TAG patterns. - In pcrs_strerror(), properly report unknown positive error code values as such. Previously they were handled like 0 (no error). - In compile_dynamic_pcrs_job_list(), also log the actual error code as pcrs_strerror() doesn't handle all errors reported by pcre. - Don't bother trying to continue chatting if the client didn't ask for it. Reduces log noise a bit. - Make two fatal error message in load_one_actions_file() more descriptive. - In cgi_send_user_manual(), log when rejecting a file name due to '/' or '..'. - In load_file(), log a message if opening a file failed. The CGI error message alone isn't too helpful. - In connection_destination_matches(), improve two log messages to help understand why the destinations don't match. - Rephrase a log message in serve(). Client request arrival should be differentiated from closed client connections now. - In serve(), log if a client connection isn't reused due to a configuration file change. - Let mark_server_socket_tainted() always mark the server socket tainted, just don't talk about it in cases where it has no effect. It doesn't change Privoxy's behaviour, but makes understanding the log file easier. - configure: - Added a --disable-ipv6-support switch for platforms where support is detected but doesn't actually work. - Do not check for the existence of strerror() and memmove() twice - Remove a useless test for setpgrp(2). Privoxy doesn't need it and it can cause problems when cross-compiling. - Rename the --disable-acl-files switch to --disable-acl-support. Since about 2001, ACL directives are specified in the standard config file. - Update the URL of the 'Removing outdated PCRE version after the next stable release' posting. The old URL stopped working after one of SF's recent site "optimizations". Reported by Han Liu. - Privoxy-Regression-Test: - Added --shuffle-tests option to increase the chances of detection race conditions. - Added a --local-test-file option that allows to use Privoxy-Regression-Test without Privoxy. - Added tests for missing socks4 and socks4a forwarders. - The --privoxy-address option now works with IPv6 addresses containing brackets, too. - Perform limited sanity checks for parameters that are supposed to have numerical values. - Added a --sleep-time option to specify a number of seconds to sleep between tests, defaults to 0. - Disable the range-requests tagger for tests that break if it's enabled. - Log messages use the ISO 8601 date format %Y-%m-%d. - Fix spelling in two error messages. - In the --help output, include a list of supported tests and their default levels. - Adjust the tests to properly deal with FEATURE_TOGGLE being disabled. - Privoxy-Log-Parser: - Perform limited sanity checks for command line parameters that are supposed to have numerical values. - Implement a --unbreak-lines-only option to try to revert MUA breakage. - Accept and highlight: Added header: Content-Encoding: deflate - Accept and highlight: Compressed content from 29258 to 8630 bytes. - Accept and highlight: Client request arrived in time on socket 21. - Highlight: Didn't receive data in time: a.fsdn.com:443 - Accept log messages with ISO 8601 time stamps, too. - uagen: - Bump generated Firefox version to 8.0. - Only randomize the release date if the new --randomize-release-date option is enabled. Firefox versions after 4 use a fixed date string without meaning. *** Version 3.0.17 Stable *** - Fixed last-chunk-detection for responses where the body was small enough to be read with the headers, causing Privoxy to wait for the end of the content until the server closed the connection or the request timed out. Reported by "Karsten" in #3028326. - Responses with status code 204 weren't properly detected as body-less like RFC2616 mandates. Like the previous bug, this caused Privoxy to wait for the end of the content until the server closed the connection or the request timed out. Fixes #3022042 and #3025553, reported by a user with no visible name. Most likely also fixes a bunch of other AJAX-related problem reports that got closed in the past due to insufficient information and lack of feedback. - Fixed an ACL bug that made it impossible to build a blacklist. Usually the ACL directives are used in a whitelist, which worked as expected, but blacklisting is still useful for public proxies where one only needs to deny known abusers access. - Added LOG_LEVEL_RECEIVED to log the not-yet-parsed data read from the network. This should make debugging various parsing issues a lot easier. - The IPv6 code is enabled by default on Windows versions that support it. Patch submitted by oCameLo in #2942729. - In mingw32 versions, the user.filter file is reachable through the GUI, just like default.filter is. Feature request 3040263. - Added the configure option --enable-large-file-support to set a few defines that are required by platforms like GNU/Linux to support files larger then 2GB. Mainly interesting for users without proper logfile management. - Logging with "debug 16" no longer stops at the first nul byte which is pretty useless. Non-printable characters are replaced with their hex value so the result can't span multiple lines making parsing them harder then necessary. - Privoxy logs when reading an action, filter or trust file. - Fixed incorrect regression test markup which caused a test in 3.0.16 to fail while Privoxy itself was working correctly. While Privoxy accepts hide-referer, too, the action name is actually hide-referrer which is also the name used one the final results page, where the test expected the alias. - CGI interface improvements: - In finish_http_response(), continue to add the 'Connection: close' header if the client connection will not be kept alive. Anonymously pointed out in #2987454. - Apostrophes in block messages no longer cause parse errors when the blocked page is viewed with JavaScript enabled. Reported by dg1727 in #3062296. - Fix a bunch of anchors that used underscores instead of dashes. - Allow to keep the client connection alive after crunching the previous request. Already opened server connections can be kept alive, too. - In cgi_show_url_info(), don't forget to prefix URLs that only contain http:// or https:// in the path. Fixes #2975765 reported by Adam Piggott. - Show the 404 CGI page if cgi_send_user_manual() is called while local user manual delivery is disabled. - Action file improvements: - Enable user.filter by default. Suggested by David White in #3001830. - Block .sitestat.com/. Reported by johnd16 in #3002725. - Block .atemda.com/. Reported by johnd16 in #3002723. - Block js.adlink.net/. Reported by johnd16 in #3002720. - Block .analytics.yahoo.com/. Reported by johnd16 in #3002713. - Block sb.scorecardresearch.com, too. Reported by dg1727 in #2992652. - Fix problems noticed on Yahoo mail and news pages. - Remove the too broad yahoo section, only keeping the fast-redirects exception as discussed on ijbswa-devel@. - Don't block adesklets.sourceforge.net. Reported in #2974204. - Block chartbeat ping tracking. Reported in #2975895. - Tag CSS and image requests with cautious and medium settings, too. - Don't handle view.atdmt.com as image. It's used for click-throughs so users should be able to "go there anyway". Reported by Adam Piggott in #2975927. - Also let the refresh-tags filter remove invalid refresh tags where the 'url=' part is missing. Anonymously reported in #2986382. While at it, update the description to mention the fact that only refresh tags with refresh times above 9 seconds are covered. - javascript needs to be blocked with +handle-as-empty-document to work around Firefox bug 492459. So move .js blockers from +block{Might be a web-bug.} -handle-as-empty-document to +block{Might be a web-bug.} +handle-as-empty-document. - ijbswa-Feature Requests-3006719 - Block 160x578 Banners. - Block another omniture tracking domain. - Added a range-requests tagger. - Added two sections to get Flickr's Ajax interface working with default pre-settings. If you change the configuration to block cookies by default, you'll need additional exceptions. Reported by Mathias Homann in #3101419 and by Patrick on ijbswa-users@. - Documentation improvements: - Explicitly mention how to match all URLs. - Consistently recommend socks5 in the Tor FAQ entry and mention its advantage compared to socks4a. Reported by David in #2960129. - Slightly improve the explanation of why filtering may appear slower than it is. - Grammar fixes for the ACL section. - Fixed a link to the 'intercepting' entry and add another one. - Rename the 'Other' section to 'Mailing Lists' and reword it to make it clear that nobody is forced to use the trackers - Note that 'anonymously' posting on the trackers may not always be possible. - Suggest to enable debug 32768 when suspecting parsing problems. - Privoxy-Log-Parser improvements: - Gather statistics for ressources, methods, and HTTP versions used by the client. - Also gather statistics for blocked and redirected requests. - Provide the percentage of keep-alive offers the client accepted. - Add a --url-statistics-threshold option. - Add a --host-statistics-threshold option to also gather statistics about how many request where made per host. - Fix a bug in handle_loglevel_header() where a 'scan: ' got lost. - Add a --shorten-thread-ids option to replace the thread id with a decimal number. - Accept and ignore: Looks like we got the last chunk together with the server headers. We better stop reading. - Accept and ignore: Continue hack in da house. - Accept and higlight: Rejecting connection from 10.0.0.2. Maximum number of connections reached. - Accept and highlight: Loading actions file: /usr/local/etc/privoxy/default.action - Accept and highlight: Loading filter file: /usr/local/etc/privoxy/default.filter - Accept and highlight: Killed all-caps Host header line: HOST: bestproxydb.com - Accept and highlight: Reducing expected bytes to 0. Marking the server socket tainted after throwing 4 bytes away. - Accept: Merged multiple header lines to: 'X-FORWARDED-PROTO: http X-HOST: 127.0.0.1' - Code cleanups: - Remove the next member from the client_state struct. Only the main thread needs access to all client states so give it its own struct. - Garbage-collect request_contains_null_bytes(). - Ditch redundant code in unload_configfile(). - Ditch LogGetURLUnderCursor() which doesn't seem to be used anywhere. - In write_socket(), remove the write-only variable write_len in an ifdef __OS2__ block. Spotted by cppcheck. - In connect_to(), don't declare the variable 'flags' on OS/2 where it isn't used. Spotted by cppcheck. - Limit the scope of various variables. Spotted by cppcheck. - In add_to_iob(), turn an interestingly looking for loop into a boring while loop. - Code cleanup in preparation for external filters. - In listen_loop(), mention the socket on which we accepted the connection, not just the source IP address. - In write_socket(), also log the socket we're writing to. - In log_error(), assert that escaped characters get logged completely or not at all. - In log_error(), assert that ival and sval have reasonable values. There's no reason not to abort() if they don't. - Remove an incorrect cgi_error_unknown() call in a cannot-happen-situation in send_crunch_response(). - Clean up white-space in http_response definition and move the crunch_reason to the beginning. - Turn http_response.reason into an enum and rename it to http_response.crunch_reason. - Silence a 'gcc (Debian 4.3.2-1.1) 4.3.2' warning on i686 GNU/Linux. - Fix white-space in a log message in remove_chunked_transfer_coding(). While at it, add a note that the message doesn't seem to be entirely correct and should be improved later on. - GNUmakefile improvements: - Use $(SSH) instead of ssh, so one only needs to specify a username once. - Removed references to the action feedback thingy that hasn't been working for years. - Consistently use shell.sourceforge.net instead of shell.sf.net so one doesn't need to check server fingerprints twice. - Removed GNUisms in the webserver and webactions targets so they work with standard tar. *** Version 3.0.16 Stable *** - Added the config file option handle-as-empty-doc-returns-ok to work around Firefox bug #492459, which causes Firefox to hang if JavaScripts are blocked in certain situations. The option is enabled in the default config file. - Added the config file option default-server-timeout to control the assumed default server timeout. Since Privoxy no longer returns an error message for connection resets on reused client connections, assuming larger server timeout values appears to actually work pretty well as long as connections aren't shared. - Added optional support for FreeBSD's accf_http(9). Use the configure option --enable-accept-filter to enable it. - Added fancier Privoxy icons for win32. Contributed by Jeff H. - In daemon mode, fd 0, 1 and 2 are bound to /dev/null. - Resolve localhost using whatever address family the operating system feels like. Previous betas would try to use IPv4 as this is what most users expect, but this didn't work reliably on GNU/Linux systems. - In the action lists on CGI pages, actions and their parameters are no longer separated with a space. The action file parser doesn't actually allow this and will throw an invalid syntax error if actions and parameters in the action files are separated. Not adding the spaces means copy and pasting CGI output into the action files works. - The default keep-alive timeout has been reduced to 5 seconds to work around hangs in clients that treat the proxy like any other host and stop allowing any new connections if the "maximum number of connections per host" is reached. - Several webbug URLs that look like they are leading to images are now blocked as image instead of empty documents. Doing the latter causes WebKit-based clients to show a "missing image" icon which may mess up the layout. - The no-such-domain template is used for DNS resolution problems with FEATURE_IPV6_SUPPORT enabled. Previously the connect-failed template was used. Reported by 'zebul666'. - Accepts quoted expiration dates even though RFC 2109 10.1.2 doesn't seem to allow them. Reported anonymously. - Don't try to forget connections if connection sharing is disabled. This wasn't a real problem but caused an unnecessary log message. - The still undocumented --enable-extended-host-patterns configure option has a better description. - Fixed an error message that would claim a write to the server failed when actually writing to the client failed. - Log the crunch reason before trying to write to the client. The log is easier to read that way. - Several log messages about client connections also mention the socket number. - handle-as-empty-document no longer depends on the image blocking code being enabled. - Privoxy-Log-Parser is roughly 40% faster in highlighting mode. - uagen, a Firefox User-Agent generator for Privoxy and Mozilla browsers has been imported and is available in the tarball's tools directory. - The scripts in the tools directory treat unknown parameters as fatal errors. *** Version 3.0.15 beta *** - In case of missing server data, no error message is send to the client if the request arrived on a reused connection. The client is then supposed to silently retry the request without bothering the user. This should significantly reduce the frequency of the "No server or forwarder data received" error message many users reported. - More reliable detection of prematurely closed client sockets with keep-alive enabled. - FEATURE_CONNECTION_KEEP_ALIVE is decoupled from FEATURE_CONNECTION_SHARING and now available on all platforms. - Improved handling of POST requests on reused connections. Should fix problems with stalled connections after submitting form data with some browser configurations. - Fixed various latency calculation issues. - Allows the client to pass NTLM authentication requests to a forwarding proxy. This was already assumed and hinted to work in 3.0.13 beta but actually didn't. Now it's confirmed to work with IE, Firefox and Chrome. Thanks to Francois Botha and Wan-Teh Chang - Fixed a calculation problem if receiving the server headers takes more than two reads, that could cause Privoxy to terminate the connection prematurely. Reported by Oliver. - Compiles again on platforms such as OpenBSD and systems using earlier glibc version that don't support AI_ADDRCONFIG. Anonymously submitted in #2872591. - A bunch of MS VC project files and Suse and Redhat RPM spec files have been removed as they were no longer maintained for quite some time. - Overly long action lines are properly rejected with a proper error message. Previously they would be either rejected as invalid or cause a core dump through abort(). - Already timed-out connections are no longer temporarily remembered. They weren't reused anyway, but wasted a socket slot. - len refers to the number of bytes actually read which might differ from the ones received. Adjust log messages accordingly. - The optional JavaScript on the CGI page uses encodeURIComponent() instead of escape() which doesn't encode all characters that matter. Anonymously reported in #2832722. - Fix gcc45 warnings in decompress_iob(). - Various log message improvements. - Privoxy-Regression-Test supports redirect tests. - Privoxy-Log-Parser can gather some connection statistics. *** Version 3.0.14 beta *** - The latency is taken into account when evaluating whether or not to reuse a connection. This should significantly reduce the number of connections problems several users reported. - If the server doesn't specify how long the connection stays alive, Privoxy errs on the safe side of caution and assumes it's only a second. - The error pages for connection timeouts or missing server data use a Last-Modified date in the past. Retry attempts are detected and Privoxy removes the If-Modified-Since header to prevent the server from responding with status code 304 in which case the client would reuse the error message. - Setting keep-alive-timeout to 0 disables keep-alive support. Previously Privoxy would claim to allow persistence but not reuse the connection. - Pipelined requests are less likely to be mistaken for the request body of the previous request. Note that Privoxy still has no real pipeline support and will either serialize pipelined requests or drop them in which case the client has to resent them. - Fixed a crash on some Windows versions when header randomization is enabled and the date couldn't be parsed. - Privoxy's keep-alive timeout for the current connection is reduced to the one specified in the client's Keep-Alive header. - For HTTP/1.1 requests, Privoxy implies keep-alive support by not setting any Connection header instead of using 'Connection: keep-alive'. - If the socket isn't reusable, Privoxy doesn't temporarily waste a socket slot to remember the connection. - If keep-alive support is disabled but compiled in, the client's Keep-Alive header is removed. - Fixed a bug on mingw32 where downloading large files failed if keep-alive support was enabled. - Fixed a bug that (at least theoretically) could cause log timestamps to be occasionally off by about a second. - No Proxy-Connection header if added if there already is one. - The configure script respects the $PATH variable when searching for groups and id. *** Version 3.0.13 beta *** - Added IPv6 support. Thanks to Petr Pisar who not only provided the initial patch but also helped a lot with the integration. - Added client-side keep-alive support. - The connection sharing code is only used if the connection-sharing option is enabled. - The max-client-connections option has been added to restrict the number of client connections below a value enforced by the operating system. - Fixed a regression reintroduced in 3.0.12 that could cause crashes on mingw32 if header date randomization was enabled. - Compressed content with extra fields couldn't be decompressed and would get passed to the client unfiltered. This problem has only be detected through statical analysis with clang as nobody seems to be using extra fields anyway. - If the server resets the Connection after sending only the headers Privoxy forwards what it got to the client. Previously Privoxy would deliver an error message instead. - Error messages in case of connection timeouts use the right HTTP status code. - If spawning a child to handle a request fails, the client gets an error message and Privoxy continues to listen for new requests right away. - The error messages in case of server-connection timeouts or prematurely closed server connections are now template-based. - If zlib support isn't compiled in, Privoxy no longer tries to filter compressed content unless explicitly asked to do so. - In case of connections that are denied based on ACL directives, the memory used for the client IP is no longer leaked. - Fixed another small memory leak if the client request times out while waiting for client headers other than the request line. - The client socket is kept open until the server socket has been marked as unused. This should increase the chances that the still-open connection will be reused for the client's next request to the same destination. Note that this only matters if connection-sharing is enabled. - A TODO list has been added to the source tarball to give potential volunteers a better idea of what the current goals are. Donations are still welcome too: http://www.privoxy.org/faq/general.html#DONATE *** Version 3.0.12 *** - The socket-timeout option now also works on platforms whose select() implementation modifies the timeout structure. Previously the timeout was triggered even if the connection didn't stall. Reported by cyberpatrol. - The Connection: keep-alive code properly deals with files larger than 2GB. Previously the connection was closed too early. - The content length for files above 2GB is logged correctly. - The user-manual directive on the show-status page links to the documentation location specified with the directive, not to the Privoxy website. - When running in daemon mode, Privoxy doesn't log anything to the console unless there are errors before the logfile has been opened. - The show-status page prints warnings about invalid directives on the same line as the directives themselves. - Fixed several justified (but harmless) compiler warnings, mostly on 64 bit platforms. - The mingw32 version explicitly requests the default charset to prevent display problems with some fonts available on more recent Windows versions. Patch by Burberry. - The mingw32 version uses the Privoxy icon in the alt-tab windows. Patch by Burberry. - The timestamp and the thread id is omitted in the "Fatal error" message box on mingw32. - Fixed two related mingw32-only buffer overflows. Triggering them required control over the configuration file, therefore this isn't seen as a security issue. - In verbose mode, or if the new option --show-skipped-tests is used, Privoxy-Regression-Test logs skipped tests and the skip reason. *** Version 3.0.11 *** - On most platforms, outgoing connections can be kept alive and reused if the server supports it. Whether or not this improves things depends on the connection. - When dropping privileges, membership in supplementary groups is given up as well. Not doing that can lead to Privoxy running with more rights than necessary and violates the principle of least privilege. Users of the --user option are advised to update. Thanks to Matthias Drochner for reporting the problem, providing the initial patch and testing the final version. - Passing invalid users or groups with the --user option didn't lead to program exit. Regression introduced in 3.0.7. - The match all section has been moved from default.action to a new file called match-all.action. As a result the default.action no longer needs to be touched by the user and can be safely overwritten by updates. - The standard.action file has been removed. Its content is now part of the default.action file. - In some situations the logged content length was slightly too low. - Crunched requests are logged with their own log level. If you used "debug 1" in the past, you'll probably want to additionally enable "debug 1024", otherwise only passed requests will be logged. If you only care about crunched requests, simply replace "debug 1" with "debug 1024". - The crunch reason has been moved to the beginning of the crunch message. For HTTP URLs, the protocol is logged as well. - Log messages are shortened by printing the thread id on its own (as opposed to putting it inside the string "Privoxy()"). - The config option socket-timeout has been added to control the time Privoxy waits for data to arrive on a socket. - Support for remote toggling is controlled by the configure option --disable-toggle only. In previous versions it also depended on the action editor and thus configuring with the --disable-editor option would disable remote toggling support as well. - Requests with invalid HTTP versions are rejected. - The template symbol @date@ can be used to include a date(1)-like time string. Initial patch submitted by Endre Szabo. - Responses from shoutcast servers are accepted again. Problem reported and fix suggested by Stefan. - The hide-forwarded-for-headers action has been replaced with the change-x-forwarded-for{} action which can also be used to add X-Forwarded-For headers. The latter functionality already existed in Privoxy versions prior to 3.0.7 but has been removed as it was often used unintentionally (by not using the hide-forwarded-for-headers action). - A "clear log" view option was added to the mingw32 version to clear out all of the lines in the Privoxy log window. Based on a patch submitted by T Ford. - The mingw32 version uses "critical sections" now, which prevents log message corruption under load. As a side effect, the "no thread-safe PRNG" warning could be removed as well. - The mingw32 version's task bar icon is crossed out and the color changed to gray if Privoxy is toggled off. *** Version 3.0.10 *** - Ordinary configuration file changes no longer cause program termination on OS/2 if the name of the logfile hasn't been changed as well. This regression probably crept in with the logging improvements in 3.0.7. Reported by Maynard. - The img-reorder filter is less likely to mess up JavaScript code in img tags. Problem and solution reported by Glenn Washburn in #2014552. - The source tar ball now includes Privoxy-Log-Parser, a syntax-highlighter for Privoxy logs. For fancy screenshots see: http://www.fabiankeil.de/sourcecode/privoxy-log-parser/ Documentation is available through perldoc(1). *** Version 3.0.9 beta *** - Added SOCKS5 support (with address resolution done by the SOCKS5 server). Patch provided by Eric M. Hopper. - The "blocked" CGI pages include a block reason that was provided as argument to the last-applying block action. - If enable-edit-actions is disabled (the default since 3.0.7 beta) the show-status page hides the edit buttons and explains why. Previously the user would get the "this feature has been disabled" message after using the edit button. - Forbidden CONNECT requests are treated like blocks by default. The now-pointless treat-forbidden-connects-like-blocks action has been removed. - Not enabling limit-connect now allows CONNECT requests to all ports. In previous versions it would only allow CONNECT requests to port 443. Use +limit-connect{443} if you think you need the old default behaviour. - The CGI editor gets turned off after three edit requests with invalid file modification timestamps. This makes life harder for attackers who can leverage browser bugs to send fake Referers and intend to brute-force edit URLs. - Action settings for multiple patterns in the same section are shared in memory. As a result these sections take up less space (and are loaded slightly faster). Problem reported by Franz Schwartau. - Linear white space in HTTP headers will be normalized to single spaces before parsing the header's content, headers split across multiple lines get merged first. This should prevent problems like: * letting the session-cookies-only action slip some Cookies through unmodified, * only suppressing the first line of a header, thus creating an invalid one, and * to incorrectly block headers with valid timestamps that weren't properly recognized. Headers that could trigger these problems are unlikely to appear in "normal" web traffic, but could be intentionally generated to fool some of Privoxy's header parsers. - Host information is gathered outside the main thread so it's less likely to delay other incoming connections if the host is misconfigured. - New config option "hostname" to use a hostname other than the one returned by the operating system. Useful to speed-up responses for CGI requests on misconfigured systems. Requested by Max Khon. - The CGI editor supports the "disable all filters of this type" directives "-client-header-filter", "-server-header-filter", "-client-header-tagger" and "-server-header-tagger". - Fixed false-positives with the link-by-url filter and URLs that contain the pattern "/jump/". - The less-download-windows filter no longer messes "Content-Type: application/x-shockwave-flash" headers up. - In the show-url-info page's "Final results" section active and inactive actions are listed separately. Patch provided by Lee. - The GNUmakefile supports the DESTDIR variable. Patch for the install target submitted by Radoslaw Zielinski. - Embedding the content of configuration files in the show-status page is significantly faster now. For a largish action file (1 MB) a speedup of about 2450 times has been measured. This is mostly interesting if you are using large action files or regularly use Privoxy-Regression-Test while running Privoxy through Valgrind, for stock configuration files it doesn't really matter. - If zlib support is unavailable and there are content filters active but the prevent-compression action is disabled, the show-url-info page includes a warning that compression might prevent filtering. - The show-url-info page provides an OpenSearch Description that allows to access the page through browser search plugins. - Custom client-header filters that rewrite the request line incorrectly no longer cause Privoxy to crash. Reported by din_a4. - The obsolete kill-popups action has been removed as the PCRS-based popup filters can do the same and are slightly less unreliable. - The inspect-jpegs action has been removed. - The send-wafer and send-vanilla-wafer actions have been removed. They weren't particular useful and their behaviour could be emulated with add-header anyway. - Privoxy-Regression-Test has been significantly improved. - Most sections in the default.action file contain tests for Privoxy-Regression-Test to verify that they are working as intended. - Parts of Privoxy have been refactored to increase maintainability. - Building with zlib (if available) is done by default. *** Version 3.0.8 *** - Fixed a small memory leak when listen-address only specifies the port. - The source tar balls now include Privoxy-Regression-Test which (upon other things) can be used to automatically detect some packaging problems. Packagers are welcome to give it a try. - Reverted a change in 3.0.7 that caused path patterns to be checked even if the host pattern match already failed. While this doesn't noticeable affect the performance, it makes it less likely to run out of stack space with overly-complex path patterns the user might have added. - Updated the msn, yahoo and google filters to work as advertised again. - The warning message shown by the show-status CGI page is easier to understand. Previously it wasn't clear that the error message is shown below the invalid directive. (Reported by Lee) - When regenerating Content-Disposition headers the more common spelling is used for the name. Previously it was written without caps. - Less confusing log message if the content type isn't overwritten because force-text-type wasn't used but the old type doesn't look like content that would be filtered normally. - Better log messages if the user tries to execute filters that don't exist. - Treat the non-standard Request-Range headers like standard range headers and suppress them if content filtering is enabled. - Prevent the log messages for CONNECT requests to unacceptable ports from printing the limit-connect argument as [null] if limit-connect hasn't been explicitly enabled. - Don't disable the mingw32 log window if the logfile directive isn't used. While it was an intentional change in 3.0.7 at least one user perceived it as a regression and the same effect can be achieved by disabling all debug directives. - Fixed two minor problems related to the win32 build process: a css file was not being in the installer and the trustfile comment in the config.txt referenced a nonexisting file - Minor documentation fixes. *** Version 3.0.7 beta *** - Added zlib support to filter content with gzip and deflate encoding. (Patch provided by Wil Mahan) - Dedicated filters and actions are used for header filtering. "filter-client-headers" and "filter-client-headers" are no longer supported, use server-header-filter{} and client-header-filter{} instead. - Tags can be used to change actions based on HTTP headers. - New server-header filter: less-download-windows. - New client-header taggers: css-requests, image-requests, client-ip-address, http-method, allow-post, complete-url, user-agent and privoxy-control. - New server-header taggers: content-type and privoxy-control. - The forward-override{} action allows to change the forwarding settings through the action files, for example based on client headers like the User-Agent, or the request origin. - Socks errors are no longer handled by the CGI page for DNS resolution failures. - CGI pages use favicons to signal whether they are error or control pages. This is useful if you rely heavily on browser tabs. - The show-url-info CGI page shows the forwarding settings. - "Crunch!" log messages (used when Privoxy answers requests by itself) now also contain the reason. - Allow to rewrite the request destination behind the client's back. - Fix socks requests on big-endian platforms. Patch provided by Song Weijia. - Fixes possible deadlocks and crashes on OpenBSD. Patch provided by Ralf Horstmann. - The CGI action editor allows to edit actionfiles with previously forbidden characters like dots. - New trust entries are saved with a comment that contains the trusted referring URL (Suggested by Daniel Griscom). - Filter descriptions are HTML encoded automatically. - New config option "split-large-forms" to work around a browser bug that caused IE6 and IE7 to ignore the Submit button on the edit-actions-for-url CGI page. - New config option "allow-cgi-request-crunching" to allow requests for Privoxy's CGI pages to be blocked, redirected or (un)trusted like ordinary requests. - Empty filter files no longer interrupt the filtering process prematurely and are correctly listed on the show-status CGI page. - New config option "accept-intercepted-requests" to combine Privoxy with any packet filter to build an intercepting proxy for HTTP/1.1 requests (and for HTTP/1.0 requests with Host header set). - fast-redirects{} catch redirects to https URLs as well. - redirect{s@foo@bar@} can be used to redirect to a rewritten version of the original URL. - Trap unsupported gopher proxy requests. - Fixed a bug in the User Manual delivery on Windows (mingw32 only). Images now show up correctly and HTML pages are no longer padded with garbage data. - Fixed several minor memory leaks, most of them discovered with Valgrind. - Only unlink the pidfile if it's actually used. - Retries after connection problems with forced requests aren't blocked again. - On Unix SIGABRT causes a core dump as expected and is no longer treated as normal shutdown signal. - The "access denied" CGI page is more descriptive and allows retries to circumvent the referrer check. - Updated PCRS to handle unexpected PCRE errors properly. Fixed crashes that could occur if Privoxy was build with external PCRE versions newer than Privoxy's internal one. (Reported by Chung-chieh Shan) - Fixed crashes with null bytes in PCRS replacement strings (Patch provided by Felix Gröbert). - Fixed crashes with header time randomization on mingw32. - The CGI style sheet is no longer delivered if the referring page isn't a Privoxy CGI page. This prevents a JavaScript-based Privoxy detection "attack". Note that detecting Privoxy is still possible through other ways and Privoxy was never intended to be invisible anyway. - Added support for AmigaOS 4, fixed build for AmigaOS 3.x. - The show-url-info CGI page displays a warning if Privoxy is currently toggled off. - The show-status CGI page suppresses the edit button for action files if Privoxy has no write access. - Most CGI error pages react properly to HEAD requests. - Requests with RFC 3253 HTTP methods (used by Subversion) are accepted. (Patch provided by Petr Kadlec) - New config option "templdir" to change the location of the CGI templates to make sure customized templates aren't "updated". - Better handling of "HTTP/1.1 100 Continue" responses. - The background of the PNG pattern is transparent. - Fixed XML syntax errors caused by banners-by-size and banners-by-url. - Fixed crashes and possible action file corruptions when lines containing hashes are written through the CGI editor. - Supports dynamic filters which can contain variables. - Supports tags to change the actions based on client or server headers. - Incorrect actions are logged before program termination. - The "actionsfile" syntax in the configuration file is consistent with the rest of the configuration options and requires the whole file name. This is an incompatible change, if you use an old configuration file you might have to append ".action" to your "actionsfile" directives. - With the configuration file option "enforce-blocks" the "go there anyway" mechanism can be disabled without recompiling Privoxy. - More precise error messages in case of incorrect acl syntax. - Logs a warning if filtering is enabled but impossible due to lack of zlib support or use of the prevent-compression action. - Less noisy handling of Cookie:" and "Connection:" headers. - Improved error messages in case of connection problems. - Fix a command-line-parsing bug that was introduced before 3.0.5 beta and caused Privoxy to treat the last argument as configuration file if no configuration file was specified. - Treat unknown command line options as fatal errors instead of silently ignoring them. - Use string functions with length checks more often. - Don't log CONNECT requests twice. - Allow to log the source address for ACL-related connection drops. - Don't ignore applying filters if the server didn't specify a Content-Type. Bug reported by Amuro Namie. - Rejected CONNECT requests are logged with log level info (enabled by default) and the reason for the block. - New command line option "--pre-chroot-nslookup hostname" to intialize the resolver library before chroot'ing. On some systems this reduces the number of files that must be copied into the chroot tree. (Patch provided by Stephen Gildea) - Fix a long-standing memory corruption bug that could cause Privoxy to overwrite a single byte in memory it didn't explicitly allocate (but that probably was allocated anyway due to bucket size). - Send template-based CGI pages as HTTP/1.1 unless the client asked for HTTP/1.0. - Let the first line in connection established responses end in \r\n as required by RFC1945. Reported by Bert van Leeuwen. - If no log file has been specified, disable logging instead of logging to stderr. - Don't block stderr when in daemon mode. - Ignore missing zero-chunks when filtering chunk-encoded content. Earlier Privoxy versions would buffer and then forward the content unmodified which caused some browsers to simply show empty pages. - Fix double free in cgi_edit_actions_list(). Reported by Venustech AD-LAB. - The code to add X-Forwarded-For headers when the hide-forwarded-for-headers action isn't being used has been removed. - Fixed trustfile feature which previously didn't work without FEATURE_TOGGLE. Reported by Lee. - Minor code clean-ups, filter and action file updates. (Some of them reported by Davide Alberani, Markus Elfring, Stefan Huehner and Adam Piggott) *** Version 3.0.6 *** - New content filters: no-ping, google, msn, yahoo and blogspot. - New header filters: x-httpd-php-to-html, html-to-xml, xml-to-html and hide-tor-exit-notation. - The special header "X-Filter: No" now disables header filtering as well. - Improved the filters img-reorder, js-annoyances, webbugs, banners-by-size, banners-by-link and ie-exploits to make them less likely to break anything. - Removed outdated URL patterns in default.action and added new ones. - Added redirection from http://p.p/user-manual to http://p.p/user-manual/ - Changed webinterface default values for hide-user-agent, hide-referrer and set-image-blocker. *** Version 3.0.5 beta *** - Windows version can be installed/started as a service. - Windows icon stays blue when Privoxy is idle, green when busy. - Integrated Fabian Keil's extensive patch. See: http://www.fabiankeil.de/sourcecode/privoxy/. Includes the following new or significantly improved actions (among many other improvements): content-type-overwrite{} crunch-client-header{string} crunch-if-none-match crunch-server-header{string} fast-redirects{check-decoded-url} filter-client-headers filter-server-headers force-text-mode handle-as-empty-document hide-accept-language{} hide-content-disposition{} hide-if-modified-since hide-referrer{conditional-block} overwrite-last-modified{} redirect{URL} treat-forbidden-connects-like-blocks - Standard-compliant clients are prevented from displaying cached copies of Privoxy's error messages after the cause of the problem has gone. - Improved DNS error handling. - Multiple filter files can now be specified in config. - Added jpeg filtering to defend against MS jpeg vulnerability MS04-028 with the new inspect-jpegs action. - Removed the "arbitrary" 1000 filter limit - addresses tracker #911950 - Thanks to Jindrich Makovicka for a race condition fix for the log file. The race condition remains for non-pthread implementations. Reference patch #1175720. Various other logging enhancements. - A pile of assorted bug fixes, memory leaks, enhancements, etc. - Moved Actions file reporting mechanism to SF tracker. - Two new options for config: enable-remote-http-toggle and forwarded-connect-retries. - Trap unsupported FTP requests. - Let text/xml be filtered. - Numerous updates to default.action - Increase the compiled in limit of trusted referrers from 64 to 512 (for trustfile users). *** Version 3.0.3 *** - Fixed yet another two memory leaks. Process growth seems stopped now. - Further tightened security against malicious toggle-off links. - Excluded text/plain MIME types from filtering. This fixes a couple of client-crashing, download corruption and Privoxy performance issues, whose root cause lies in web servers labelling content of unknown type as text/plain. - Assorted fixes for POSIX compliance, signal handling, graceful termination, compiler warnings, OSX support, Win32 systray, error logging, hostname wildcards, correct detection of NetBSD. - Workarounds for client (iTunes etc) and server (PHP < 4.2.3) bugs including the notorious "blank page" problem. - Various filter improvements; most notably the unsolicited-popups filter became less destructive - Major revamp of the actions file *** Version 3.0.2 *** - Fixed two memory leaks, one serious - Fixed bug in pcrs which could cause crashes with user-defined filters - Fixed bug in domain name matching - Assorted small fixes (Win32 menu, CGI URL editor, ..) - Added basic support for the OPTIONS and TRACE http methods - Added workaround for Bug in Mac OSX that made Privoxy crash occasionally - Refined the default action file through >400 items of user feedback - Filter changes: - Assorted refinements, optimizations and fixes in the js-annoyances, img-reorder, banners-by-size, banners-by-link, webbugs, refresh-tags, html-annoyances, content-cookies and fun filters - Replaced filter "popups" by choice between two modes: - "unsolicited-popups" tries to catch only the unsolicited ones - "all-popups" tries to kill them all (as before) - New filter "tiny-textforms" Help those tiny or hard-wrap textareas. - New filter "jumping-windows" that prevents windows from resizing and moving themselves - New filter "demoronizer" which fixes MS's abuse of std charsets (common cases anyway). - Replaced "nimda" with more general "ie-exploits" filter in which all filters for exploits shall be collected - Improved cookie logging - Rewrote make install target. Added uninstall and install-strip targets. - Fixed a potential (application-level, NOT OS-level!) security problem involving remote toggling and action file manipulation by mailicious websites. - Added ability to chroot (thanks to Sviatoslav Sviridov) - Added more action aliases for prehistoric action names - Add Slackware support to Makefile. *** Version 3.0 *** - Fixed Windows startmenu items, log window and tray icon menus. - Added warning for bogus install target - Added quicktime-kioskmode filter and improved frameset-borders - Updated default.action based on latest feedback - New PDF doc build process - Add a user contrib module to cvs: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/ijbswa/contrib/ *** Version 2.9.18 *** - Added workaround for IE bug that broke CGI interface - Bugfix: String actions now reliably editable through CGI interface - Three filters fixed (again!) - Assorted small fixes and doc enhancements *** Version 2.9.16 *** - Major revamp of default.action to get rid of years of cruft. - Same for default.filter - Re-design and major improvements to the CGI editor interface. - Address spurious 'out of memory' error due to incorrect file permissions. - Impose buffer limits while reading client and server headers. - Better memory and CPU optimization. - Add Conectiva Linux package. - user-manual directive added to config for help links from within CGI editor. - Multiple actions files can now be specified in config. - Actions files are changed to: default.action, standard.action, and user.action. user.action is for personal/local configuration. - The usual many small and miscellaneous bug and security fixes. *** Version 2.9.14 beta *** - Fix Solaris compile problem (gateway.h and filters.h) - Makefile fixes for Solaris, FreeBSD (?) - Fix build failure where certain features were disabled. - 'blocked-compact' template is removed. Various CGI improvements, including an adaptive 'blocked' template. - Various tweaks for actions file to get ready for stable 3.0 - Included a 'Bookmarklet' and PHP scripts for reporting actions file problems via web interface at privoxy.org. Accessed via internal CGIs. - Include cgi-style.css for templates. - #include mechansim for common text in templates - Various other minor fixes. *** Version 2.9.13 beta *** - *NEWS*: The project has been renamed to Privoxy! The new name is reflected throughout (file locations, etc). - ijb.action is now default.action. re_filterfile is now default.filter. - http://i.j.b/ is now http://p.p/ - The 'logo' option for replacing ad iamges is removed now. 'Pattern' (checkerboard) is now the default. - RPM spec file make over. *** Version 2.9.12 beta *** - **READ**: The default listening PORT is NOW 8118!!! Changed from 8000 due to conflict with NAS (Network Audio Server, whatever that is.) - More CGI actions editor fixes and improvements. - Win32 command line fix ups. - re_filterfile now has modular sections that can be activated on a per site basis. Some new goodies there too. - +filter now takes arguments to match FILTER sections in re_filterfile for even more flexibility. - Added a new image blocker option: +image-blocker{pattern}, which displays a checkerboard patthern and scales better than the logo. - PNG images will be used in place of GIF for JB built-in images if configured with --enable-no-gif. - Clean up compiler warnings (mostly). - Improved handling of failed DNS lookups & diagnostics for failed bind to listen socket - Made --no-daemon mode log to tty instead of logfile. - Various spec file and init script cleanups and improvements (Redhat and SuSE). - CGI Editor works on OS/2 now. - Fix restart failure where sockets were in TIME_WAIT. - Fixes for actions cgi editor, make sure we have right file. - A --pidfile command line option now, in addition to --help, --version, --no-daemon, --user and configfile. --no-daemon replaces the former -d option and _DEBUG define. --user will drop privileges to the specified user. - Signal handling cleanups (*nix). - CGI actions editor improvements and fixes. - Error handling improvements, especially out of memory. - Default re_filterfile fix that caused spurious IJB logos (instead of 'blank'). - configure.in threading fixes for Solaris. - Various other minor fixes. *** Version 2.9.11 beta Changes *** - Add "session" cookie concept where cookies exist for the life of that browser session only (ie never goes to disk). - Checks for correct header length. - Fix user:pass@host.domain.com auth bug. - Better signal handling on *nix. - Fix CFLAGS hard-coded in configure.in - Fix threading bug re: gethostbyname() that caused random URLs to fail in some cases. *** Version 2.9.11 Alpha Changes *** - A web-based editor for the actions file is included (go to http://i.j.b/). - Web-based toggle IJB on/off support. - Cookie handling has changed - the new +no-cookies-keep feature is now the default. - actionsfile is renamed to ijb.action. - junkbstr.txt is now config.txt on Win32. - Support for running IJB as a UNIX daemon process has improved. - Unix daemon now returns error code on failed start. - Timestamps in logfile and jarfile now. - Fix for the Netscape bug reintroduced in 2.9.9. - make should now abort if gmake (GNU make) not present. - Many other minor bugfixes - Start a ChangeLog :) *** Version 2.9.3 pre-Alpha Changes *** - Amiga support (completely untested by me - I don't have an Amiga) - "tinygif 3" support (redirects blocked images to a specified URL, so the browser doesn't have to load and cache many copies of the same image). - one case where there were both local and global "referrer" variables (yuck!) clarified by renaming the local one to "refer". - Fixed some places where close() was used instead of close_socket(). Thanks to Jörg Strohmayer (joergs at users.sourceforge.net) for these. - Temporary hack to get FORCE_LOAD to work with IE. I just lowercased the FORCE_LOAD_PREFIX. Needs fixing properly. - Most URLs hardcoded into Junkbuster were changed to go through a script e.g. http://ijbswa.sourceforge.net/redirect.php?v=2.9.3&to=faq The only other URLs left are the GNU GPL: http://www.fsf.org/copyleft/gpl.html and the home page: http://ijbswa.sourceforge.net/ ... and various URLs which will be intercepted by Junkbuster anyway. TODO: Still need to do something with the URLs in Junkbuster Corp's copyright/trademark notice on the bottom of the show-proxy-args page. - PCRE or GNU Regex is now a #define option. *** Version 2.9.2 pre-Alpha Changes *** - Andreas applied the latest version of the FORCE patch. *** Version 2.9.1 pre-Alpha Changes *** - in parsers.c, fixed two #ifdef FORCE to #ifdef FORCE_LOAD (BTW: I think FORCE is precise enough, since loading remote data is the whole purpose of a proxy..) - Set the FORCE_PREFIX (back) to 'IJB-FORCE-LOAD-'. While 'noijb.' is more elegant and looks like a hostname in the URL, it doesn't make clear to the inexperienced user that the proxy is bypassed. It also has a higher name collision risk. - Filled in the function header templates for my functions in parsers.c (again). They obviously got lost in our current patch war ;-) - Cut the credit for the §-referrer-option from the config file, that Stefan had placed there. - Improved the re_filterfile *** Version 2.9.0 pre-Alpha Changes *** - Now use PCRE, not GNU REGEX. I have not yet had chance to check the syntax of the block/image/cookie file to ensure that they match what is expected - however they seem to work. - Replaced "configure" script with one generated by "autoconf". Also use a header "config.h" (was ijbconfig.h in my previous release) for the #defines. "config.h" is now generated with "autoheader" from "acconfig.h" and "configure.in". (Note that to install you do not need autoconf or autoheader - just run "./configure".) To see command-line options, run "./configure --help". This is my first ever autoconf script, so it has some rough edges (how PCRE is handled is the roughest). - Error logging code replaced with new module errlog.c, based on the one from JunkbusterMT (but with the threading code removed). - Most of Rodney's 0.21 and 0.21A patches applied. (Marked *). I did not apply all of these, since I had already independently done conditional popup file, conditional image file, and integration of popup code. - ACL, Jar and trust files conditionally compiled. - New source file headers. - Various cosmetic changes. (But I have not consistently ordered the config files - I think that's worthwhile, but it's 1am and I want to get this released!) - RCS tags on .h files. - RCS tags are const char[] rather than const char *. (Saves 4 bytes per tag ;-) - VC++ project files renamed to vc_junkbuster.*. - show-proxy-args now shows status of all conditionals, not just REGEX - Various functions moved around. Most notably all the system-specific sockets code which was spread between jcc.c, bind.c, and connect.c, has been moved to "jbsockets.c". The non-system-specific code from connect.c and socks4.c has been movet to "gateway.c". Also, the config file loader and the global variables it writes to have been moved to "loadcfg.c". (Maybe this should go into loaders.c?) And candidate for the "worst filename ever" award is "miscutil.c", which contains, well, miscellaneous utility functions like zalloc. (Suggestions for a better name for this file are welcome!) - Loaders now use a common function to read a line and skip comments, and this function also stores the proxy_args. - Added ./junkbuster --help (Not for Win32 GUI) - Added ./junkbuster --version (Not for Win32 GUI) - Win32 resources are now all marked as "U.S. English", rather than being a mix of "U.S. English", "U.K. English" and "Irish English". - Version number changes to 2.9.0 ---------------------------------------------------------------------- Copyright : Written by and Copyright (C) 2001-2013 the Privoxy team. http://www.privoxy.org/ Based on the Internet Junkbuster originally written by and Copyright (C) 1997 Anonymous Coders and Junkbusters Corporation. http://www.junkbusters.com/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The GNU General Public License should be included with this file. If not, you can view it at http://www.gnu.org/copyleft/gpl.html or write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. privoxy-3.0.21-stable/./slackware/rc.privoxy.orig000640 001751 001751 00000004404 12076563712 020756 0ustar00fkfk000000 000000 #!/bin/sh # ******************************************************************** # This script uses exit to return proper error codes, # sourcing (. /path/to/rc.privoxy) it in your system's # rc files is a bad idea. # ******************************************************************** RETVAL=1 PRIVOXY_PRG="%PROGRAM%" PRIVOXY_BIN="%SBIN_DEST%/$PRIVOXY_PRG" PRIVOXY_CONF="%CONF_DEST%/config" PRIVOXY_USER="%USER%" PRIVOXY_GROUP="%GROUP%" PRIVOXY_PID="/var/run/$PRIVOXY_PRG.pid" declare -i check check=(`/bin/ps -e|/bin/grep $PRIVOXY_PRG|/usr/bin/wc -l`) # some checks for us if [ ! -x $PRIVOXY_BIN ] ; then exit 0 ;fi if [ ! -f $PRIVOXY_CONF ] ; then exit 0 ;fi # See how we were called. PRIVOXY="$PRIVOXY_BIN --user $PRIVOXY_USER.$PRIVOXY_GROUP --pidfile $PRIVOXY_PID $PRIVOXY_CONF" start () { # start daemon echo -n $"Starting $PRIVOXY_PRG: " if [ ! -f $PRIVOXY_PID ]; then ( $PRIVOXY 2>/dev/tty9 ) \ && echo " OK" \ && /bin/touch /var/lock/$PRIVOXY_PRG \ && RETVAL=0 elif [ $check -lt 3 ]; then echo "Zombie lock file found" /bin/rm -f /var/lock/$PRIVOXY_PRG $PRIVOXY_PID echo "Retrying..." start else echo "Already running" fi echo } stop () { # stop daemon echo -n $"Stopping $PRIVOXY_PRG: " if [ -f $PRIVOXY_PID ]; then /bin/kill `/bin/cat $PRIVOXY_PID` \ && /bin/rm -f /var/lock/$PRIVOXY_PRG $PRIVOXY_PID \ && echo " OK" \ && RETVAL=0 echo else echo " Not Running" fi } case "$1" in start) start ;; stop) stop ;; reload) if [ -f $PRIVOXY_PID ] ; then /bin/kill -HUP `cat $PRIVOXY_PID` \ && RETVAL=0 fi ;; restart) stop start ;; kill) echo "Kill all Privoxy" /bin/rm -f /var/lock/$PRIVOXY_PRG $PRIVOXY_PID /bin/killall $PRIVOXY ;; condrestart) # restart only if already running if [ -f $PRIVOXY_PID ] ; then stop start fi ;; status) /bin/ps ax|/bin/grep $PRIVOXY_PRG|/bin/grep -v 'grep\|init\.d\|rc\.d' RETVAL=0 ;; top) if [ -f $PRIVOXY_PID ]; then a="" for i in `/sbin/pidof $PRIVOXY_PRG` ; do a="$a -p $i" done /usr/bin/top $a fi ;; *) echo $"Usage: $PRIVOXY_PRG {start|stop|reload|restart|condrestart|status|top|kill}" exit 1 esac exit $RETVAL privoxy-3.0.21-stable/./README000640 001751 001751 00000033544 12114407603 014651 0ustar00fkfk000000 000000 /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/README,v $ * * Purpose : README file to give a short intro. * * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA * *********************************************************************/ This README is included with Privoxy 3.0.21. See http://www.privoxy.org/ for more information. The current code maturity level is "stable". ------------------------------------------------------------------------------- Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks. Privoxy is Free Software and licensed under the GNU GPLv2. Privoxy is an associated project of Software in the Public Interest (SPI). Helping hands and donations are welcome: * http://www.privoxy.org/faq/general.html#PARTICIPATE * http://www.privoxy.org/faq/general.html#DONATE ------------------------------------------------------------------------------- 1. CHANGES For a list of changes in this release, please have a look at the "ChangeLog", the "What's New" section or the "Upgrader's Notes" in the User Manual. ------------------------------------------------------------------------------- 2. INSTALL See the INSTALL file in this directory, for installing from raw source, and the User Manual, for all other installation types. ------------------------------------------------------------------------------- 3. RUN privoxy [--help] [--version] [--no-daemon] [--pidfile PIDFILE] [--user USER [.GROUP]] [--chroot] [--pre-chroot-nslookup HOSTNAME ][config_file] See the man page or User Manual for an explanation of each option, and other configuration and usage issues. If no config_file is specified on the command line, Privoxy will look for a file named 'config' in the current directory (except Win32 which will look for 'config.txt'). If no config_file is found, Privoxy will fail to start. ------------------------------------------------------------------------------- 4. CONFIGURATION See: 'config', 'default.action', 'user.action', 'default.filter', and 'user.filter'. 'user.action' and 'user.filter' are for personal and local configuration preferences. These are all well commented. Most of the magic is in '*.action' files. 'user.action' should be used for any actions customizations. On Unix-like systems, these files are typically installed in / etc/privoxy. On Windows, then wherever the executable itself is installed. There are many significant changes and advances from earlier versions. The User Manual has an explanation of all configuration options, and examples: http:// www.privoxy.org/user-manual/. Be sure to set your browser(s) for HTTP/HTTPS Proxy at :, or whatever you specify in the config file under 'listen-address'. DEFAULT is 127.0.0.1:8118. Note that Privoxy ONLY proxies HTTP (and HTTPS) traffic. Do not try it with FTP or other protocols for the simple reason it does not work. The actions list can be configured via the web interface accessed via http:// p.p/, as well other options. ------------------------------------------------------------------------------- 5. DOCUMENTATION There should be documentation in the 'doc' subdirectory. In particular, see the User Manual there, the FAQ, and those interested in Privoxy development, should look at developer-manual. The source and configuration files are all well commented. The main configuration files are: 'config', 'default.action', and 'default.filter'. Included documentation may vary according to platform and packager. All documentation is posted on http://www.privoxy.org, in case you don't have it, or can't find it. ------------------------------------------------------------------------------- 6. CONTACTING THE DEVELOPERS, BUG REPORTING AND FEATURE REQUESTS We value your feedback. In fact, we rely on it to improve Privoxy and its configuration. However, please note the following hints, so we can provide you with the best support. ------------------------------------------------------------------------------- 6.1. Please provide sufficient information A lot of support requests don't contain enough information and can't be solved without a lot of back and forth which causes unnecessary delays. Reading this section should help to prevent that. Before contacting us to report a problem, please try to verify that it is a Privoxy problem, and not a browser or site problem or documented behaviour that just happens to be different than what you expected. If unsure, try toggling off Privoxy, and see if the problem persists. If you are using your own custom configuration, please try the default configuration to see if the problem is configuration related. If you're having problems with a feature that is disabled by default, please ask around on the mailing list if others can reproduce the problem. If you aren't using the latest Privoxy version, the problem may have been found and fixed in the meantime. We would appreciate if you could take the time to upgrade to the latest version and verify that the problem still exists. Please be sure to provide the following information when reporting problems or requesting support: * The exact Privoxy version you are using. * The operating system and versions you run Privoxy on, e.g. Windows XP SP2. * The name, platform, and version of the browser you were using (e.g. Internet Explorer v5.5 for Mac). * The URL where the problem occurred, or some way for us to duplicate the problem (e.g. http://somesite.example.com/?somethingelse=123). * Whether your version of Privoxy is one supplied by the Privoxy developers via SourceForge, or if you got your copy somewhere else. * Whether you are using Privoxy together with another proxy such as Tor. If so, please temporary disable the other proxy to see if the symptoms change. * Whether you are using a personal firewall product. If so, does Privoxy work without it? * Any other pertinent information to help identify the problem such as config or log file excerpts (yes, you should have log file entries for each action taken). To get a meaningful logfile, please make sure that the logfile directive is being used and the following debug options are enabled (all of them): debug 1 # Log the destination for each request Privoxy let through. See also debug 1024. debug 2 # show each connection status debug 4 # show I/O status debug 8 # show header parsing debug 128 # debug redirects debug 256 # debug GIF de-animation debug 512 # Common Log Format debug 1024 # Log the destination for requests Privoxy didn't let through, and the reason why. debug 4096 # Startup banner and warnings. debug 8192 # Non-fatal errors If you are having trouble with a filter, please additionally enable debug 64 # debug regular expression filters If you are using Privoxy 3.0.17 or later and suspect that it interprets the request or the response incorrectly, please enable debug 32768 # log all data read from the network It's easy for us to ignore log messages that aren't relevant but missing log messages may make it impossible to investigate a problem. If you aren't sure which of the debug directives are relevant, please just enable all of them and let us worry about it. Note that Privoxy log files may contain sensitive information so please don't submit any logfiles you didn't read first. You can mask sensitive information as long as it's clear that you removed something. You don't have to tell us your actual name when filing a problem report, but if you don't, please use a nickname so we can differentiate between your messages and the ones entered by other "anonymous" users that may respond to your request if they have the same problem or already found a solution. Note that due to spam the trackers may not always allow to post without being logged into SourceForge. If that's the case, you are still free to create a login that isn't directly linked to your name, though. Please also check the status of your request a few days after submitting it, as we may request additional information. If you use a SF id, you should automatically get a mail when someone responds to your request. Please don't bother to add an email address when using the tracker. If you prefer to communicate through email, just use one of the mailing lists directly. If you are new to reporting problems, you might be interested in How to Report Bugs Effectively. The appendix of the Privoxy User Manual also has helpful information on understanding actions, and action debugging. ------------------------------------------------------------------------------- 6.2. Get Support For casual users, our support forum at SourceForge is probably best suited: http://sourceforge.net/tracker/?group_id=11118&atid=211118 All users are of course welcome to discuss their issues on the users mailing list, where the developers also hang around. Please don't send private support requests to individual Privoxy developers, either use the mailing lists or the support trackers. If you have to contact a Privoxy developer directly for other reasons, please send a real mail and do not bother with SourceForge's messaging system. Answers to SourceForge messages are usually bounced by SourceForge's mail server in which case the developer wasted time writing a response you don't get. From your point of view it will look like your message has been completely ignored, so this is frustrating for all parties involved. Note that the Privoxy mailing lists are moderated. Posts from unsubscribed addresses have to be accepted manually by a moderator. This may cause a delay of several days and if you use a subject that doesn't clearly mention Privoxy or one of its features, your message may be accidentally discarded as spam. If you aren't subscribed, you should therefore spend a few seconds to come up with a proper subject. Additionally you should make it clear that you want to get CC'd. Otherwise some responses will be directed to the mailing list only, and you won't see them. ------------------------------------------------------------------------------- 6.3. Reporting Problems "Problems" for our purposes, come in two forms: * Configuration issues, such as ads that slip through, or sites that don't function properly due to one Privoxy "action" or another being turned "on". * "Bugs" in the programming code that makes up Privoxy, such as that might cause a crash. ------------------------------------------------------------------------------- 6.3.1. Reporting Ads or Other Configuration Problems Please send feedback on ads that slipped through, innocent images that were blocked, sites that don't work properly, and other configuration related problem of default.action file, to http://sourceforge.net/tracker/?group_id= 11118&atid=460288, the Actions File Tracker. New, improved default.action files may occasionally be made available based on your feedback. These will be announced on the ijbswa-announce list and available from our the files section of our project page. ------------------------------------------------------------------------------- 6.3.2. Reporting Bugs Please report all bugs through our bug tracker: http://sourceforge.net/tracker /?group_id=11118&atid=111118. Before doing so, please make sure that the bug has not already been submitted and observe the additional hints at the top of the submit form. If already submitted, please feel free to add any info to the original report that might help to solve the issue. ------------------------------------------------------------------------------- 6.4. Request New Features You are welcome to submit ideas on new features or other proposals for improvement through our feature request tracker at http://sourceforge.net/ tracker/?atid=361118&group_id=11118. ------------------------------------------------------------------------------- 6.5. Mailing Lists If you prefer to communicate through email, instead of using a web interface, feel free to use one of the mailing lists. To discuss issues that haven't been completely diagnosed yet, please use the Privoxy users list. Technically interested users and people who wish to contribute to the project are always welcome on the developers list. You can find an overview of all Privoxy-related mailing lists, including list archives, at: http://sourceforge.net/mail/? group_id=11118. privoxy-3.0.21-stable/./errlog.c000640 001751 001751 00000107067 12061101736 015430 0ustar00fkfk000000 000000 const char errlog_rcs[] = "$Id: errlog.c,v 1.117 2012/12/09 12:28:14 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/errlog.c,v $ * * Purpose : Log errors to a designated destination in an elegant, * printf-like fashion. * * Copyright : Written by and Copyright (C) 2001-2010 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include #include #include #include #include #include "config.h" #include "miscutil.h" /* For gettimeofday() */ #include #if !defined(_WIN32) && !defined(__OS2__) #include #endif /* !defined(_WIN32) && !defined(__OS2__) */ #include #include #ifdef _WIN32 #ifndef STRICT #define STRICT #endif #include #ifndef _WIN_CONSOLE #include "w32log.h" #endif /* ndef _WIN_CONSOLE */ #endif /* def _WIN32 */ #ifdef _MSC_VER #define inline __inline #endif /* def _MSC_VER */ #ifdef __OS2__ #include /* For sock_errno */ #define INCL_DOS #include #endif #include "errlog.h" #include "project.h" #include "jcc.h" const char errlog_h_rcs[] = ERRLOG_H_VERSION; /* * LOG_LEVEL_FATAL cannot be turned off. (There are * some exceptional situations where we need to get a * message to the user). */ #define LOG_LEVEL_MINIMUM LOG_LEVEL_FATAL /* where to log (default: stderr) */ static FILE *logfp = NULL; /* logging detail level. XXX: stupid name. */ static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR); /* static functions */ static void fatal_error(const char * error_message); #ifdef _WIN32 static char *w32_socket_strerr(int errcode, char *tmp_buf); #endif #ifdef __OS2__ static char *os2_socket_strerr(int errcode, char *tmp_buf); #endif #ifdef MUTEX_LOCKS_AVAILABLE static inline void lock_logfile(void) { privoxy_mutex_lock(&log_mutex); } static inline void unlock_logfile(void) { privoxy_mutex_unlock(&log_mutex); } static inline void lock_loginit(void) { privoxy_mutex_lock(&log_init_mutex); } static inline void unlock_loginit(void) { privoxy_mutex_unlock(&log_init_mutex); } #else /* ! MUTEX_LOCKS_AVAILABLE */ /* * FIXME we need a cross-platform locking mechanism. * The locking/unlocking functions below should be * fleshed out for non-pthread implementations. */ static inline void lock_logfile() {} static inline void unlock_logfile() {} static inline void lock_loginit() {} static inline void unlock_loginit() {} #endif /********************************************************************* * * Function : fatal_error * * Description : Displays a fatal error to standard error (or, on * a WIN32 GUI, to a dialog box), and exits Privoxy * with status code 1. * * Parameters : * 1 : error_message = The error message to display. * * Returns : Does not return. * *********************************************************************/ static void fatal_error(const char *error_message) { if (logfp != NULL) { fputs(error_message, logfp); } #if defined(_WIN32) && !defined(_WIN_CONSOLE) { /* Skip timestamp and thread id for the message box. */ const char *box_message = strstr(error_message, "Fatal error"); if (NULL == box_message) { /* Shouldn't happen but ... */ box_message = error_message; } MessageBox(g_hwndLogFrame, box_message, "Privoxy Error", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); /* Cleanup - remove taskbar icon etc. */ TermLogWindow(); } #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ #if defined(unix) if (pidfile) { unlink(pidfile); } #endif /* unix */ exit(1); } /********************************************************************* * * Function : show_version * * Description : Logs the Privoxy version and the program name. * * Parameters : * 1 : prog_name = The program name. * * Returns : Nothing. * *********************************************************************/ void show_version(const char *prog_name) { log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION); if (prog_name != NULL) { log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name); } } /********************************************************************* * * Function : init_log_module * * Description : Initializes the logging module to log to stderr. * Can only be called while stderr hasn't been closed * yet and is only supposed to be called once. * * Parameters : * 1 : prog_name = The program name. * * Returns : Nothing. * *********************************************************************/ void init_log_module(void) { lock_logfile(); logfp = stderr; unlock_logfile(); set_debug_level(debug); } /********************************************************************* * * Function : set_debug_level * * Description : Sets the debug level to the provided value * plus LOG_LEVEL_MINIMUM. * * XXX: we should only use the LOG_LEVEL_MINIMUM * until the first time the configuration file has * been parsed. * * Parameters : 1: debug_level = The debug level to set. * * Returns : Nothing. * *********************************************************************/ void set_debug_level(int debug_level) { debug = debug_level | LOG_LEVEL_MINIMUM; } /********************************************************************* * * Function : debug_level_is_enabled * * Description : Checks if a certain debug level is enabled. * * Parameters : 1: debug_level = The debug level to check. * * Returns : Nothing. * *********************************************************************/ int debug_level_is_enabled(int debug_level) { return (0 != (debug & debug_level)); } /********************************************************************* * * Function : disable_logging * * Description : Disables logging. * * Parameters : None. * * Returns : Nothing. * *********************************************************************/ void disable_logging(void) { if (logfp != NULL) { log_error(LOG_LEVEL_INFO, "No logfile configured. Please enable it before reporting any problems."); lock_logfile(); fclose(logfp); logfp = NULL; unlock_logfile(); } } /********************************************************************* * * Function : init_error_log * * Description : Initializes the logging module to log to a file. * * XXX: should be renamed. * * Parameters : * 1 : prog_name = The program name. * 2 : logfname = The logfile to (re)open. * * Returns : N/A * *********************************************************************/ void init_error_log(const char *prog_name, const char *logfname) { FILE *fp; assert(NULL != logfname); lock_loginit(); if ((logfp != NULL) && (logfp != stderr)) { log_error(LOG_LEVEL_INFO, "(Re-)Opening logfile \'%s\'", logfname); } /* set the designated log file */ fp = fopen(logfname, "a"); if ((NULL == fp) && (logfp != NULL)) { /* * Some platforms (like OS/2) don't allow us to open * the same file twice, therefore we give it another * shot after closing the old file descriptor first. * * We don't do it right away because it prevents us * from logging the "can't open logfile" message to * the old logfile. * * XXX: this is a lame workaround and once the next * release is out we should stop bothering reopening * the logfile unless we have to. * * Currently we reopen it every time the config file * has been reloaded, but actually we only have to * reopen it if the file name changed or if the * configuration reload was caused by a SIGHUP. */ log_error(LOG_LEVEL_INFO, "Failed to reopen logfile: \'%s\'. " "Retrying after closing the old file descriptor first. If that " "doesn't work, Privoxy will exit without being able to log a message.", logfname); lock_logfile(); fclose(logfp); logfp = NULL; unlock_logfile(); fp = fopen(logfname, "a"); } if (NULL == fp) { log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: \'%s\'", logfname); } /* set logging to be completely unbuffered */ setbuf(fp, NULL); lock_logfile(); if (logfp != NULL) { fclose(logfp); } #ifdef unix if (daemon_mode && (logfp == stderr)) { if (dup2(1, 2) == -1) { /* * We only use fatal_error() to clear the pid * file and to exit. Given that stderr has just * been closed, the user will not see the error * message. */ fatal_error("Failed to reserve fd 2."); } } #endif logfp = fp; unlock_logfile(); show_version(prog_name); unlock_loginit(); } /* init_error_log */ /********************************************************************* * * Function : get_thread_id * * Description : Returns a number that is different for each thread. * * XXX: Should be moved elsewhere (miscutil.c?) * * Parameters : None * * Returns : thread_id * *********************************************************************/ static long get_thread_id(void) { long this_thread = 1; /* was: pthread_t this_thread;*/ #ifdef __OS2__ PTIB ptib; APIRET ulrc; /* XXX: I have no clue what this does */ #endif /* __OS2__ */ /* FIXME get current thread id */ #ifdef FEATURE_PTHREAD this_thread = (long)pthread_self(); #ifdef __MACH__ /* * Mac OSX (and perhaps other Mach instances) doesn't have a debuggable * value at the first 4 bytes of pthread_self()'s return value, a pthread_t. * pthread_t is supposed to be opaque... but it's fairly random, though, so * we make it mostly presentable. */ this_thread = abs(this_thread % 1000); #endif /* def __MACH__ */ #elif defined(_WIN32) this_thread = GetCurrentThreadId(); #elif defined(__OS2__) ulrc = DosGetInfoBlocks(&ptib, NULL); if (ulrc == 0) this_thread = ptib -> tib_ptib2 -> tib2_ultid; #endif /* def FEATURE_PTHREAD */ return this_thread; } /********************************************************************* * * Function : get_log_timestamp * * Description : Generates the time stamp for the log message prefix. * * Parameters : * 1 : buffer = Storage buffer * 2 : buffer_size = Size of storage buffer * * Returns : Number of written characters or 0 for error. * *********************************************************************/ static inline size_t get_log_timestamp(char *buffer, size_t buffer_size) { size_t length; time_t now; struct tm tm_now; struct timeval tv_now; /* XXX: stupid name */ long msecs; int msecs_length = 0; gettimeofday(&tv_now, NULL); msecs = tv_now.tv_usec / 1000; now = tv_now.tv_sec; #ifdef HAVE_LOCALTIME_R tm_now = *localtime_r(&now, &tm_now); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&localtime_mutex); tm_now = *localtime(&now); privoxy_mutex_unlock(&localtime_mutex); #else tm_now = *localtime(&now); #endif length = strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", &tm_now); if (length > (size_t)0) { msecs_length = snprintf(buffer+length, buffer_size - length, ".%.3ld", msecs); } if (msecs_length > 0) { length += (size_t)msecs_length; } else { length = 0; } return length; } /********************************************************************* * * Function : get_clf_timestamp * * Description : Generates a Common Log Format time string. * * Parameters : * 1 : buffer = Storage buffer * 2 : buffer_size = Size of storage buffer * * Returns : Number of written characters or 0 for error. * *********************************************************************/ static inline size_t get_clf_timestamp(char *buffer, size_t buffer_size) { /* * Complex because not all OSs have tm_gmtoff or * the %z field in strftime() */ time_t now; struct tm *tm_now; struct tm gmt; #ifdef HAVE_LOCALTIME_R struct tm dummy; #endif int days, hrs, mins; size_t length; int tz_length = 0; time (&now); #ifdef HAVE_GMTIME_R gmt = *gmtime_r(&now, &gmt); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); gmt = *gmtime(&now); privoxy_mutex_unlock(&gmtime_mutex); #else gmt = *gmtime(&now); #endif #ifdef HAVE_LOCALTIME_R tm_now = localtime_r(&now, &dummy); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&localtime_mutex); tm_now = localtime(&now); privoxy_mutex_unlock(&localtime_mutex); #else tm_now = localtime(&now); #endif days = tm_now->tm_yday - gmt.tm_yday; hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour); mins = hrs * 60 + tm_now->tm_min - gmt.tm_min; length = strftime(buffer, buffer_size, "%d/%b/%Y:%H:%M:%S ", tm_now); if (length > (size_t)0) { tz_length = snprintf(buffer+length, buffer_size-length, "%+03d%02d", mins / 60, abs(mins) % 60); } if (tz_length > 0) { length += (size_t)tz_length; } else { length = 0; } return length; } /********************************************************************* * * Function : get_log_level_string * * Description : Translates a numerical loglevel into a string. * * Parameters : * 1 : loglevel = LOG_LEVEL_FOO * * Returns : Log level string. * *********************************************************************/ static inline const char *get_log_level_string(int loglevel) { char *log_level_string = NULL; assert(0 < loglevel); switch (loglevel) { case LOG_LEVEL_ERROR: log_level_string = "Error"; break; case LOG_LEVEL_FATAL: log_level_string = "Fatal error"; break; case LOG_LEVEL_GPC: log_level_string = "Request"; break; case LOG_LEVEL_CONNECT: log_level_string = "Connect"; break; case LOG_LEVEL_WRITING: log_level_string = "Writing"; break; case LOG_LEVEL_RECEIVED: log_level_string = "Received"; break; case LOG_LEVEL_HEADER: log_level_string = "Header"; break; case LOG_LEVEL_INFO: log_level_string = "Info"; break; case LOG_LEVEL_RE_FILTER: log_level_string = "Re-Filter"; break; #ifdef FEATURE_FORCE_LOAD case LOG_LEVEL_FORCE: log_level_string = "Force"; break; #endif /* def FEATURE_FORCE_LOAD */ case LOG_LEVEL_REDIRECTS: log_level_string = "Redirect"; break; case LOG_LEVEL_DEANIMATE: log_level_string = "Gif-Deanimate"; break; case LOG_LEVEL_CRUNCH: log_level_string = "Crunch"; break; case LOG_LEVEL_CGI: log_level_string = "CGI"; break; case LOG_LEVEL_ACTIONS: log_level_string = "Actions"; break; default: log_level_string = "Unknown log level"; break; } assert(NULL != log_level_string); return log_level_string; } /********************************************************************* * * Function : log_error * * Description : This is the error-reporting and logging function. * * Parameters : * 1 : loglevel = the type of message to be logged * 2 : fmt = the main string we want logged, printf-like * 3 : ... = arguments to be inserted in fmt (printf-like). * * Returns : N/A * *********************************************************************/ void log_error(int loglevel, const char *fmt, ...) { va_list ap; char *outbuf = NULL; static char *outbuf_save = NULL; char tempbuf[BUFFER_SIZE]; size_t length = 0; const char * src = fmt; long thread_id; char timestamp[30]; /* * XXX: Make this a config option, * why else do we allocate instead of using * an array? */ size_t log_buffer_size = BUFFER_SIZE; #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* * Irrespective of debug setting, a GET/POST/CONNECT makes * the taskbar icon animate. (There is an option to disable * this but checking that is handled inside LogShowActivity()). */ if ((loglevel == LOG_LEVEL_GPC) || (loglevel == LOG_LEVEL_CRUNCH)) { LogShowActivity(); } #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ /* * verify that the loglevel applies to current * settings and that logging is enabled. * Bail out otherwise. */ if ((0 == (loglevel & debug)) #ifndef _WIN32 || (logfp == NULL) #endif ) { if (loglevel == LOG_LEVEL_FATAL) { fatal_error("Fatal error. You're not supposed to" "see this message. Please file a bug report."); } return; } thread_id = get_thread_id(); get_log_timestamp(timestamp, sizeof(timestamp)); /* protect the whole function because of the static buffer (outbuf) */ lock_logfile(); if (NULL == outbuf_save) { outbuf_save = (char*)zalloc(log_buffer_size + 1); /* +1 for paranoia */ if (NULL == outbuf_save) { snprintf(tempbuf, sizeof(tempbuf), "%s %08lx Fatal error: Out of memory in log_error().", timestamp, thread_id); fatal_error(tempbuf); /* Exit */ return; } } outbuf = outbuf_save; /* * Memsetting the whole buffer to zero (in theory) * makes things easier later on. */ memset(outbuf, 0, log_buffer_size); /* Add prefix for everything but Common Log Format messages */ if (loglevel != LOG_LEVEL_CLF) { length = (size_t)snprintf(outbuf, log_buffer_size, "%s %08lx %s: ", timestamp, thread_id, get_log_level_string(loglevel)); } /* get ready to scan var. args. */ va_start(ap, fmt); /* build formatted message from fmt and var-args */ while ((*src) && (length < log_buffer_size-2)) { const char *sval = NULL; /* %N string */ int ival; /* %N string length or an error code */ unsigned uval; /* %u value */ long lval; /* %l value */ unsigned long ulval; /* %ul value */ char ch; const char *format_string = tempbuf; ch = *src++; if (ch != '%') { outbuf[length++] = ch; /* * XXX: Only necessary on platforms where multiple threads * can write to the buffer at the same time because we * don't support mutexes (OS/2 for example). */ outbuf[length] = '\0'; continue; } outbuf[length] = '\0'; ch = *src++; switch (ch) { case '%': tempbuf[0] = '%'; tempbuf[1] = '\0'; break; case 'd': ival = va_arg(ap, int); snprintf(tempbuf, sizeof(tempbuf), "%d", ival); break; case 'u': uval = va_arg(ap, unsigned); snprintf(tempbuf, sizeof(tempbuf), "%u", uval); break; case 'l': /* this is a modifier that must be followed by u, lu, or d */ ch = *src++; if (ch == 'd') { lval = va_arg(ap, long); snprintf(tempbuf, sizeof(tempbuf), "%ld", lval); } else if (ch == 'u') { ulval = va_arg(ap, unsigned long); snprintf(tempbuf, sizeof(tempbuf), "%lu", ulval); } else if ((ch == 'l') && (*src == 'u')) { unsigned long long lluval = va_arg(ap, unsigned long long); snprintf(tempbuf, sizeof(tempbuf), "%llu", lluval); src++; } else { snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt); loglevel = LOG_LEVEL_FATAL; } break; case 'c': /* * Note that char paramaters are converted to int, so we need to * pass "int" to va_arg. (See K&R, 2nd ed, section A7.3.2, page 202) */ tempbuf[0] = (char) va_arg(ap, int); tempbuf[1] = '\0'; break; case 's': format_string = va_arg(ap, char *); if (format_string == NULL) { format_string = "[null]"; } break; case 'N': /* * Non-standard: Print a counted unterminated string, * replacing unprintable bytes with their hex value. * Takes 2 parameters: int length, const char * string. */ ival = va_arg(ap, int); assert(ival >= 0); sval = va_arg(ap, char *); assert(sval != NULL); while ((ival-- > 0) && (length < log_buffer_size - 6)) { if (isprint((int)*sval) && (*sval != '\\')) { outbuf[length++] = *sval; outbuf[length] = '\0'; } else { int ret = snprintf(outbuf + length, log_buffer_size - length - 2, "\\x%.2x", (unsigned char)*sval); assert(ret == 4); length += 4; } sval++; } /* * XXX: In case of printable characters at the end of * the %N string, we're not using the whole buffer. */ format_string = (length < log_buffer_size - 6) ? "" : "[too long]"; break; case 'E': /* Non-standard: Print error code from errno */ #ifdef _WIN32 ival = WSAGetLastError(); format_string = w32_socket_strerr(ival, tempbuf); #elif __OS2__ ival = sock_errno(); if (ival != 0) { format_string = os2_socket_strerr(ival, tempbuf); } else { ival = errno; format_string = strerror(ival); } #else /* ifndef _WIN32 */ ival = errno; #ifdef HAVE_STRERROR format_string = strerror(ival); #else /* ifndef HAVE_STRERROR */ format_string = NULL; #endif /* ndef HAVE_STRERROR */ if (sval == NULL) { snprintf(tempbuf, sizeof(tempbuf), "(errno = %d)", ival); } #endif /* ndef _WIN32 */ break; case 'T': /* Non-standard: Print a Common Log File timestamp */ get_clf_timestamp(tempbuf, sizeof(tempbuf)); break; default: snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt); loglevel = LOG_LEVEL_FATAL; break; } assert(length < log_buffer_size); length += strlcpy(outbuf + length, format_string, log_buffer_size - length); if (length >= log_buffer_size-2) { static const char warning[] = "... [too long, truncated]"; length = log_buffer_size - sizeof(warning) - 1; length += strlcpy(outbuf + length, warning, log_buffer_size - length); assert(length < log_buffer_size); break; } } /* done with var. args */ va_end(ap); assert(length < log_buffer_size); length += strlcpy(outbuf + length, "\n", log_buffer_size - length); /* Some sanity checks */ if ((length >= log_buffer_size) || (outbuf[log_buffer_size-1] != '\0') || (outbuf[log_buffer_size] != '\0') ) { /* Repeat as assertions */ assert(length < log_buffer_size); assert(outbuf[log_buffer_size-1] == '\0'); /* * outbuf's real size is log_buffer_size+1, * so while this looks like an off-by-one, * we're only checking our paranoia byte. */ assert(outbuf[log_buffer_size] == '\0'); snprintf(outbuf, log_buffer_size, "%s %08lx Fatal error: log_error()'s sanity checks failed." "length: %d. Exiting.", timestamp, thread_id, (int)length); loglevel = LOG_LEVEL_FATAL; } #ifndef _WIN32 /* * On Windows this is acceptable in case * we are logging to the GUI window only. */ assert(NULL != logfp); #endif if (loglevel == LOG_LEVEL_FATAL) { fatal_error(outbuf_save); /* Never get here */ } if (logfp != NULL) { fputs(outbuf_save, logfp); } #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Write to display */ LogPutString(outbuf_save); #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ unlock_logfile(); } /********************************************************************* * * Function : jb_err_to_string * * Description : Translates JB_ERR_FOO codes into strings. * * XXX: the type of error codes is jb_err * but the typedef'inition is currently not * visible to all files that include errlog.h. * * Parameters : * 1 : jb_error = a valid jb_err code * * Returns : A string with the jb_err translation * *********************************************************************/ const char *jb_err_to_string(int jb_error) { switch (jb_error) { case JB_ERR_OK: return "Success, no error"; case JB_ERR_MEMORY: return "Out of memory"; case JB_ERR_CGI_PARAMS: return "Missing or corrupt CGI parameters"; case JB_ERR_FILE: return "Error opening, reading or writing a file"; case JB_ERR_PARSE: return "Parse error"; case JB_ERR_MODIFIED: return "File has been modified outside of the CGI actions editor."; case JB_ERR_COMPRESS: return "(De)compression failure"; default: assert(0); return "Unknown error"; } assert(0); return "Internal error"; } #ifdef _WIN32 /********************************************************************* * * Function : w32_socket_strerr * * Description : Translate the return value from WSAGetLastError() * into a string. * * Parameters : * 1 : errcode = The return value from WSAGetLastError(). * 2 : tmp_buf = A temporary buffer that might be used to * store the string. * * Returns : String representing the error code. This may be * a global string constant or a string stored in * tmp_buf. * *********************************************************************/ static char *w32_socket_strerr(int errcode, char *tmp_buf) { #define TEXT_FOR_ERROR(code,text) \ if (errcode == code) \ { \ return #code " - " text; \ } TEXT_FOR_ERROR(WSAEACCES, "Permission denied") TEXT_FOR_ERROR(WSAEADDRINUSE, "Address already in use.") TEXT_FOR_ERROR(WSAEADDRNOTAVAIL, "Cannot assign requested address."); TEXT_FOR_ERROR(WSAEAFNOSUPPORT, "Address family not supported by protocol family."); TEXT_FOR_ERROR(WSAEALREADY, "Operation already in progress."); TEXT_FOR_ERROR(WSAECONNABORTED, "Software caused connection abort."); TEXT_FOR_ERROR(WSAECONNREFUSED, "Connection refused."); TEXT_FOR_ERROR(WSAECONNRESET, "Connection reset by peer."); TEXT_FOR_ERROR(WSAEDESTADDRREQ, "Destination address required."); TEXT_FOR_ERROR(WSAEFAULT, "Bad address."); TEXT_FOR_ERROR(WSAEHOSTDOWN, "Host is down."); TEXT_FOR_ERROR(WSAEHOSTUNREACH, "No route to host."); TEXT_FOR_ERROR(WSAEINPROGRESS, "Operation now in progress."); TEXT_FOR_ERROR(WSAEINTR, "Interrupted function call."); TEXT_FOR_ERROR(WSAEINVAL, "Invalid argument."); TEXT_FOR_ERROR(WSAEISCONN, "Socket is already connected."); TEXT_FOR_ERROR(WSAEMFILE, "Too many open sockets."); TEXT_FOR_ERROR(WSAEMSGSIZE, "Message too long."); TEXT_FOR_ERROR(WSAENETDOWN, "Network is down."); TEXT_FOR_ERROR(WSAENETRESET, "Network dropped connection on reset."); TEXT_FOR_ERROR(WSAENETUNREACH, "Network is unreachable."); TEXT_FOR_ERROR(WSAENOBUFS, "No buffer space available."); TEXT_FOR_ERROR(WSAENOPROTOOPT, "Bad protocol option."); TEXT_FOR_ERROR(WSAENOTCONN, "Socket is not connected."); TEXT_FOR_ERROR(WSAENOTSOCK, "Socket operation on non-socket."); TEXT_FOR_ERROR(WSAEOPNOTSUPP, "Operation not supported."); TEXT_FOR_ERROR(WSAEPFNOSUPPORT, "Protocol family not supported."); TEXT_FOR_ERROR(WSAEPROCLIM, "Too many processes."); TEXT_FOR_ERROR(WSAEPROTONOSUPPORT, "Protocol not supported."); TEXT_FOR_ERROR(WSAEPROTOTYPE, "Protocol wrong type for socket."); TEXT_FOR_ERROR(WSAESHUTDOWN, "Cannot send after socket shutdown."); TEXT_FOR_ERROR(WSAESOCKTNOSUPPORT, "Socket type not supported."); TEXT_FOR_ERROR(WSAETIMEDOUT, "Connection timed out."); TEXT_FOR_ERROR(WSAEWOULDBLOCK, "Resource temporarily unavailable."); TEXT_FOR_ERROR(WSAHOST_NOT_FOUND, "Host not found."); TEXT_FOR_ERROR(WSANOTINITIALISED, "Successful WSAStartup not yet performed."); TEXT_FOR_ERROR(WSANO_DATA, "Valid name, no data record of requested type."); TEXT_FOR_ERROR(WSANO_RECOVERY, "This is a non-recoverable error."); TEXT_FOR_ERROR(WSASYSNOTREADY, "Network subsystem is unavailable."); TEXT_FOR_ERROR(WSATRY_AGAIN, "Non-authoritative host not found."); TEXT_FOR_ERROR(WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range."); TEXT_FOR_ERROR(WSAEDISCON, "Graceful shutdown in progress."); /* * The following error codes are documented in the Microsoft WinSock * reference guide, but don't actually exist. * * TEXT_FOR_ERROR(WSA_INVALID_HANDLE, "Specified event object handle is invalid."); * TEXT_FOR_ERROR(WSA_INVALID_PARAMETER, "One or more parameters are invalid."); * TEXT_FOR_ERROR(WSAINVALIDPROCTABLE, "Invalid procedure table from service provider."); * TEXT_FOR_ERROR(WSAINVALIDPROVIDER, "Invalid service provider version number."); * TEXT_FOR_ERROR(WSA_IO_PENDING, "Overlapped operations will complete later."); * TEXT_FOR_ERROR(WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state."); * TEXT_FOR_ERROR(WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available."); * TEXT_FOR_ERROR(WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider."); * TEXT_FOR_ERROR(WSASYSCALLFAILURE, "System call failure."); * TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted."); */ sprintf(tmp_buf, "(error number %d)", errcode); return tmp_buf; } #endif /* def _WIN32 */ #ifdef __OS2__ /********************************************************************* * * Function : os2_socket_strerr * * Description : Translate the return value from sock_errno() * into a string. * * Parameters : * 1 : errcode = The return value from sock_errno(). * 2 : tmp_buf = A temporary buffer that might be used to * store the string. * * Returns : String representing the error code. This may be * a global string constant or a string stored in * tmp_buf. * *********************************************************************/ static char *os2_socket_strerr(int errcode, char *tmp_buf) { #define TEXT_FOR_ERROR(code,text) \ if (errcode == code) \ { \ return #code " - " text; \ } TEXT_FOR_ERROR(SOCEPERM , "Not owner.") TEXT_FOR_ERROR(SOCESRCH , "No such process.") TEXT_FOR_ERROR(SOCEINTR , "Interrupted system call.") TEXT_FOR_ERROR(SOCENXIO , "No such device or address.") TEXT_FOR_ERROR(SOCEBADF , "Bad file number.") TEXT_FOR_ERROR(SOCEACCES , "Permission denied.") TEXT_FOR_ERROR(SOCEFAULT , "Bad address.") TEXT_FOR_ERROR(SOCEINVAL , "Invalid argument.") TEXT_FOR_ERROR(SOCEMFILE , "Too many open files.") TEXT_FOR_ERROR(SOCEPIPE , "Broken pipe.") TEXT_FOR_ERROR(SOCEWOULDBLOCK , "Operation would block.") TEXT_FOR_ERROR(SOCEINPROGRESS , "Operation now in progress.") TEXT_FOR_ERROR(SOCEALREADY , "Operation already in progress.") TEXT_FOR_ERROR(SOCENOTSOCK , "Socket operation on non-socket.") TEXT_FOR_ERROR(SOCEDESTADDRREQ , "Destination address required.") TEXT_FOR_ERROR(SOCEMSGSIZE , "Message too long.") TEXT_FOR_ERROR(SOCEPROTOTYPE , "Protocol wrong type for socket.") TEXT_FOR_ERROR(SOCENOPROTOOPT , "Protocol not available.") TEXT_FOR_ERROR(SOCEPROTONOSUPPORT, "Protocol not supported.") TEXT_FOR_ERROR(SOCESOCKTNOSUPPORT, "Socket type not supported.") TEXT_FOR_ERROR(SOCEOPNOTSUPP , "Operation not supported.") TEXT_FOR_ERROR(SOCEPFNOSUPPORT , "Protocol family not supported.") TEXT_FOR_ERROR(SOCEAFNOSUPPORT , "Address family not supported by protocol family.") TEXT_FOR_ERROR(SOCEADDRINUSE , "Address already in use.") TEXT_FOR_ERROR(SOCEADDRNOTAVAIL , "Can't assign requested address.") TEXT_FOR_ERROR(SOCENETDOWN , "Network is down.") TEXT_FOR_ERROR(SOCENETUNREACH , "Network is unreachable.") TEXT_FOR_ERROR(SOCENETRESET , "Network dropped connection on reset.") TEXT_FOR_ERROR(SOCECONNABORTED , "Software caused connection abort.") TEXT_FOR_ERROR(SOCECONNRESET , "Connection reset by peer.") TEXT_FOR_ERROR(SOCENOBUFS , "No buffer space available.") TEXT_FOR_ERROR(SOCEISCONN , "Socket is already connected.") TEXT_FOR_ERROR(SOCENOTCONN , "Socket is not connected.") TEXT_FOR_ERROR(SOCESHUTDOWN , "Can't send after socket shutdown.") TEXT_FOR_ERROR(SOCETOOMANYREFS , "Too many references: can't splice.") TEXT_FOR_ERROR(SOCETIMEDOUT , "Operation timed out.") TEXT_FOR_ERROR(SOCECONNREFUSED , "Connection refused.") TEXT_FOR_ERROR(SOCELOOP , "Too many levels of symbolic links.") TEXT_FOR_ERROR(SOCENAMETOOLONG , "File name too long.") TEXT_FOR_ERROR(SOCEHOSTDOWN , "Host is down.") TEXT_FOR_ERROR(SOCEHOSTUNREACH , "No route to host.") TEXT_FOR_ERROR(SOCENOTEMPTY , "Directory not empty.") TEXT_FOR_ERROR(SOCEOS2ERR , "OS/2 Error.") sprintf(tmp_buf, "(error number %d)", errcode); return tmp_buf; } #endif /* def __OS2__ */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./Makefile000640 001751 001751 00000007061 11217504046 015426 0ustar00fkfk000000 000000 # $Id: Makefile,v 1.11 2006/07/18 14:48:45 david__schmidt Exp $ # # Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Based on the Internet Junkbuster originally written # by and Copyright (C) 1997 Anonymous Coders and # Junkbusters Corporation. http://www.junkbusters.com # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # $Log: Makefile,v $ # Revision 1.11 2006/07/18 14:48:45 david__schmidt # Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch) # with what was really the latest development (the v_3_0_branch branch) # # Revision 1.5.2.2 2002/10/25 02:44:23 hal9 # Port of make install, etc from main trunk. Needs testing! Add Slackware # support, and other related changes. Update related docs. # # Revision 1.5.2.1 2002/08/05 17:46:13 oes # Change make to gmake to fix auto-build on Solaris # # Revision 1.5 2002/04/11 12:51:34 oes # Bugfix # # Revision 1.4 2002/04/09 16:38:10 oes # Added option to run the whole build process # # Revision 1.3 2002/03/26 22:29:54 swa # we have a new homepage! # # Revision 1.2 2002/03/24 13:25:42 swa # name change related issues # # Revision 1.1 2001/12/01 11:24:29 jongfoster # Will display a warning if non-GNU make is used # # ############################################################################# GNU_MAKE_CMD = gmake MAKE_CMD = make error: @if [ -f GNUmakefile ]; then \ echo "***"; \ echo "*** You are not using the GNU version of Make - maybe it's called gmake"; \ echo "*** or it's in a different PATH? Please read INSTALL." ; \ echo "***"; \ exit 1; \ elif test -n "$(HOST_ARCH)" && test -z "$(MAKE_VERSION)" ; then \ echo "***"; \ echo "*** You are not using GNU Make on Solaris, please make sure you do" ; \ echo "*** and re-run 'make' "; \ echo "***"; \ exit 1 ; \ elif test -n "$(MACHINE_ARCH)" && test -z "$(MAKE_VERSION)" ; then \ echo "***"; \ echo "*** You are not using GNU Make on FreeBSD, please make sure you do" ; \ echo "*** and re-run 'make' "; \ echo "***"; \ exit 1 ; \ else \ echo "***"; \ echo "*** To build this program, you must run"; \ echo "*** autoheader && autoconf && ./configure and then run GNU make."; \ echo "***"; \ echo -n "*** Shall I do this for you now? (y/n) "; \ read answer; \ if [ "$$answer" = "y" ]; then \ autoheader && autoconf && ./configure || exit 1; \ if $(GNU_MAKE_CMD) -v |grep GNU >/dev/null 2>/dev/null; then \ $(GNU_MAKE_CMD) ;\ elif $(MAKE_CMD) -v |grep GNU >/dev/null 2>/dev/null; then \ $(MAKE_CMD) ;\ else \ echo "Neither 'make' nor 'gmake' are GNU compatible!" ; \ echo "Please read INSTALL." ; \ exit 1 ; \ fi ;\ fi; \ fi .PHONY: error ############################################################################# ## Local Variables: ## tab-width: 3 ## end: privoxy-3.0.21-stable/./acconfig.h000640 001751 001751 00000020422 12061101565 015701 0ustar00fkfk000000 000000 #ifndef CONFIG_H_INCLUDED #define CONFIG_H_INCLUDED /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/acconfig.h,v $ * * Purpose : This file should be the first thing included in every * .c file. (Before even system headers). It contains * #define statements for various features. It was * introduced because the compile command line started * getting ludicrously long with feature defines. * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ @TOP@ /* * Version number - Major (X._._) */ #undef VERSION_MAJOR /* * Version number - Minor (_.X._) */ #undef VERSION_MINOR /* * Version number - Point (_._.X) */ #undef VERSION_POINT /* * Version number, as a string */ #undef VERSION /* * Status of the code: "alpha", "beta" or "stable". */ #undef CODE_STATUS /* * Should pcre be statically built in instead of linkling with libpcre? * (This is determined by configure depending on the availiability of * libpcre and user preferences). The name is ugly, but pcre needs it. * Don't bother to change this here! Use configure instead. */ #undef STATIC_PCRE /* * Should pcrs be statically built in instead of linkling with libpcrs? * (This is determined by configure depending on the availiability of * libpcrs and user preferences). * Don't bother to change this here! Use configure instead. */ #undef STATIC_PCRS /* * Allows the use of an ACL to control access to the proxy by IP address. */ #undef FEATURE_ACL /* * Allow Privoxy to use accf_http(9) if supported. */ #undef FEATURE_ACCEPT_FILTER /* * Enables the web-based configuration (actionsfile) editor. If you * have a shared proxy, you might want to turn this off. */ #undef FEATURE_CGI_EDIT_ACTIONS /* * Locally redirect remote script-redirect URLs */ #undef FEATURE_FAST_REDIRECTS /* * Bypass filtering for 1 page only */ #undef FEATURE_FORCE_LOAD /* * Allow blocking using images as well as HTML. * If you do not define this then everything is blocked as HTML. * * Note that this is required if you want to use FEATURE_IMAGE_DETECT_MSIE. */ #undef FEATURE_IMAGE_BLOCKING /* * Detect image requests automatically for MSIE. Will fall back to * other image-detection methods (i.e. "+image" permission) for other * browsers. * * You must also define FEATURE_IMAGE_BLOCKING to use this feature. * * It detects the following header pair as an image request: * * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) * Accept: * / * * * And the following as a HTML request: * * User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) * Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, * / * * * And no, I haven't got that backwards - IE is being weird. * * Known limitations: * 1) If you press shift-reload on a blocked HTML page, you get * the image "blocked" page, not the HTML "blocked" page. * 2) Once an image "blocked" page has been sent, viewing it * in it's own browser window *should* bring up the HTML * "blocked" page, but it doesn't. You need to clear the * browser cache to get the HTML version again. * * These limitations are due to IE making inconsistent choices * about which "Accept:" header to send. */ #undef FEATURE_IMAGE_DETECT_MSIE /* * Use PNG instead of GIF for built-in images */ #undef FEATURE_NO_GIFS /* * Allow to shutdown Privoxy through the webinterface. */ #undef FEATURE_GRACEFUL_TERMINATION /* * Allow PCRE syntax in host patterns. */ #undef FEATURE_EXTENDED_HOST_PATTERNS /* * Keep connections alive if possible. */ #undef FEATURE_CONNECTION_KEEP_ALIVE /* * Allow to share outgoing connections between incoming connections. */ #undef FEATURE_CONNECTION_SHARING /* * Use POSIX threads instead of native threads. */ #undef FEATURE_PTHREAD /* * Enables statistics function. */ #undef FEATURE_STATISTICS /* * Enable strptime() sanity checks. */ #undef FEATURE_STRPTIME_SANITY_CHECKS /* * Allow Privoxy to be "disabled" so it is just a normal non-blocking * non-anonymizing proxy. This is useful if you're trying to access a * blocked or broken site - just change the setting in the config file, * or use the handy "Disable" menu option in the Windows GUI. */ #undef FEATURE_TOGGLE /* * Allows the use of trust files. */ #undef FEATURE_TRUST /* * Defined on Solaris only. Makes the system libraries thread safe. */ #undef _REENTRANT /* * Defined on Solaris only. Without this, many important functions are not * defined in the system headers. */ #undef __EXTENSIONS__ /* * Defined always. * FIXME: Don't know what it does or why we need it. * (presumably something to do with MultiThreading?) */ #undef __MT__ /* If the (nonstandard and thread-safe) function gethostbyname_r * is available, select which signature to use */ #undef HAVE_GETHOSTBYNAME_R_6_ARGS #undef HAVE_GETHOSTBYNAME_R_5_ARGS #undef HAVE_GETHOSTBYNAME_R_3_ARGS /* If the (nonstandard and thread-safe) function gethostbyaddr_r * is available, select which signature to use */ #undef HAVE_GETHOSTBYADDR_R_8_ARGS #undef HAVE_GETHOSTBYADDR_R_7_ARGS #undef HAVE_GETHOSTBYADDR_R_5_ARGS /* Defined if you have gmtime_r and localtime_r with a signature * of (struct time *, struct tm *) */ #undef HAVE_GMTIME_R #undef HAVE_LOCALTIME_R /* Define to 'int' if doesn't have it. */ #undef socklen_t /* Define if pcre.h must be included as */ #undef PCRE_H_IN_SUBDIR /* Define if pcreposix.h must be included as */ #undef PCREPOSIX_H_IN_SUBDIR @BOTTOM@ /* * Defined always. * FIXME: Don't know what it does or why we need it. * (presumably something to do with ANSI Standard C?) */ #ifndef __STDC__ #define __STDC__ 1 #endif /* ndef __STDC__ */ /* * Need to set up this define only for the Pthreads library for * Win32, available from http://sources.redhat.com/pthreads-win32/ */ #if defined(FEATURE_PTHREAD) && defined(_WIN32) #define __CLEANUP_C #endif /* defined(FEATURE_PTHREAD) && defined(_WIN32) */ /* * BEOS does not currently support POSIX threads. * This *should* be detected by ./configure, but let's be sure. */ #if defined(FEATURE_PTHREAD) && defined(__BEOS__) #error BEOS does not support pthread - please run ./configure again with "--disable-pthread" #endif /* defined(FEATURE_PTHREAD) && defined(__BEOS__) */ /* * On OpenBSD and maybe also FreeBSD, gcc doesn't define the cpp * symbol unix; it defines __unix__ and sometimes not even that: */ #if ( defined(__unix__) || defined(__NetBSD__) ) && !defined(unix) #define unix 1 #endif /* * It's too easy to accidentally use a Cygwin or MinGW32 version of config.h * under VC++, and it usually gives many weird error messages. Let's make * the error messages understandable, by bailing out now. */ #ifdef _MSC_VER #error For MS VC++, please use vc_config_winthreads.h or vc_config_pthreads.h. You can usually do this by selecting the "Build", "Clean" menu option. #endif /* def _MSC_VER */ #endif /* CONFIG_H_INCLUDED */ privoxy-3.0.21-stable/./gateway.h000640 001751 001751 00000006430 12041467224 015601 0ustar00fkfk000000 000000 #ifndef GATEWAY_H_INCLUDED #define GATEWAY_H_INCLUDED #define GATEWAY_H_VERSION "$Id: gateway.h,v 1.22 2012/10/23 10:16:52 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/gateway.h,v $ * * Purpose : Contains functions to connect to a server, possibly * using a "gateway" (i.e. HTTP proxy and/or SOCKS4 * proxy). Also contains the list of gateway types. * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif struct forward_spec; struct http_request; struct client_state; extern jb_socket forwarded_connect(const struct forward_spec * fwd, struct http_request *http, struct client_state *csp); /* * Default number of seconds after which an * open connection will no longer be reused. */ #define DEFAULT_KEEP_ALIVE_TIMEOUT 180 #ifdef FEATURE_CONNECTION_SHARING extern void set_keep_alive_timeout(unsigned int timeout); extern void initialize_reusable_connections(void); extern void forget_connection(jb_socket sfd); extern void remember_connection(const struct reusable_connection *connection); extern int close_unusable_connections(void); #endif /* FEATURE_CONNECTION_SHARING */ extern void mark_connection_closed(struct reusable_connection *closed_connection); #ifdef FEATURE_CONNECTION_KEEP_ALIVE extern int connection_destination_matches(const struct reusable_connection *connection, const struct http_request *http, const struct forward_spec *fwd); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /* * Revision control strings from this header and associated .c file */ extern const char gateway_rcs[]; extern const char gateway_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef GATEWAY_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./urlmatch.h000640 001751 001751 00000005633 11655471121 015764 0ustar00fkfk000000 000000 #ifndef URLMATCH_H_INCLUDED #define URLMATCH_H_INCLUDED #define URLMATCH_H_VERSION "$Id: urlmatch.h,v 1.18 2011/11/06 11:41:05 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/urlmatch.h,v $ * * Purpose : Declares functions to match URLs against URL * patterns. * * Copyright : Written by and Copyright (C) 2001-2002, 2006 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif extern void free_http_request(struct http_request *http); #ifndef FEATURE_EXTENDED_HOST_PATTERNS extern jb_err init_domain_components(struct http_request *http); #endif extern jb_err parse_http_request(const char *req, struct http_request *http); extern jb_err parse_http_url(const char *url, struct http_request *http, int require_protocol); extern int url_requires_percent_encoding(const char *url); #define REQUIRE_PROTOCOL 1 extern int url_match(const struct url_spec *pattern, const struct http_request *http); extern jb_err create_url_spec(struct url_spec *url, char *buf); extern void free_url_spec(struct url_spec *url); extern int match_portlist(const char *portlist, int port); extern jb_err parse_forwarder_address(char *address, char **hostname, int *port); /* Revision control strings from this header and associated .c file */ extern const char urlmatch_rcs[]; extern const char urlmatch_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef URLMATCH_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./list.c000640 001751 001751 00000073105 11726442046 015115 0ustar00fkfk000000 000000 const char list_rcs[] = "$Id: list.c,v 1.29 2012/03/09 17:55:50 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/list.c,v $ * * Purpose : Declares functions to handle lists. * * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifndef _WIN32 /* FIXME: The following headers are not needed for Win32. Are they * needed on other platforms? */ #include #include #include #include #endif #include #if !defined(_WIN32) && !defined(__OS2__) #include #endif #include #include "project.h" #include "list.h" #include "miscutil.h" const char list_h_rcs[] = LIST_H_VERSION; static int list_is_valid (const struct list *the_list); /********************************************************************* * * Function : init_list * * Description : Create a new, empty list in user-allocated memory. * Caller should allocate a "struct list" variable, * then pass it to this function. * (Implementation note: Rather than calling this * function, you can also just memset the memory to * zero, e.g. if you have a larger structure you * want to initialize quickly. However, that isn't * really good design.) * * Parameters : * 1 : the_list = pointer to list * * Returns : N/A * *********************************************************************/ void init_list(struct list *the_list) { memset(the_list, '\0', sizeof(*the_list)); } /********************************************************************* * * Function : destroy_list * * Description : Destroy a string list (opposite of list_init). * On return, the memory used by the list entries has * been freed, but not the memory used by the_list * itself. You should not re-use the_list without * calling list_init(). * * (Implementation note: You *can* reuse the_list * without calling list_init(), but please don't. * If you want to remove all entries from a list * and still have a usable list, then use * list_remove_all().) * * Parameters : * 1 : the_list = pointer to list * * Returns : N/A * *********************************************************************/ void destroy_list (struct list *the_list) { struct list_entry *cur_entry, *next_entry; assert(the_list); for (cur_entry = the_list->first; cur_entry ; cur_entry = next_entry) { next_entry = cur_entry->next; freez(cur_entry->str); free(cur_entry); } the_list->first = NULL; the_list->last = NULL; } /********************************************************************* * * Function : list_is_valid * * Description : Check that a string list is valid. The intended * usage is "assert(list_is_valid(the_list))". * Currently this checks that "the_list->last" * is correct, and that the list dosn't contain * circular references. It is likely to crash if * it's passed complete garbage. * * Parameters : * 1 : the_list = pointer to list. Must be non-null. * * Returns : 1 if list is valid, 0 otherwise. * *********************************************************************/ static int list_is_valid (const struct list *the_list) { /* * If you don't want this check, just change the line below * from "#if 1" to "#if 0". */ #if 1 const struct list_entry *cur_entry; const struct list_entry *last_entry = NULL; int entry = 0; assert(the_list); for (cur_entry = the_list->first; cur_entry ; cur_entry = cur_entry->next) { last_entry = cur_entry; if (cur_entry->str) { /* * Just check that this string can be accessed - i.e. it's a valid * pointer. */ (void)strlen(cur_entry->str); } /* * Check for looping back to first */ if ((entry++ != 0) && (cur_entry == the_list->first)) { return 0; } /* * Arbitrarily limit list length to prevent infinite loops. * Note that the 1000 limit was hit by a real user in tracker 911950; * removing it for now. Real circular references should eventually * be caught by the check above, anyway. */ /* if (entry > 1000) { return 0; } */ /* * Check this isn't marked as the last entry, unless of course it's * *really* the last entry. */ if ((the_list->last == cur_entry) && (cur_entry->next != NULL)) { /* This is the last entry, but there's data after it !!?? */ return 0; } } return (the_list->last == last_entry); #else return 1; #endif } /********************************************************************* * * Function : enlist * * Description : Append a string into a specified string list. * * Parameters : * 1 : the_list = pointer to list * 2 : str = string to add to the list (maybe NULL) * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, the_list will be unchanged. * *********************************************************************/ jb_err enlist(struct list *the_list, const char *str) { struct list_entry *cur; assert(the_list); assert(list_is_valid(the_list)); if (NULL == (cur = (struct list_entry *)zalloc(sizeof(*cur)))) { return JB_ERR_MEMORY; } if (str) { if (NULL == (cur->str = strdup(str))) { free(cur); return JB_ERR_MEMORY; } } /* else { cur->str = NULL; } - implied by zalloc */ /* cur->next = NULL; - implied by zalloc */ if (the_list->last) { the_list->last->next = cur; the_list->last = cur; } else { the_list->first = cur; the_list->last = cur; } assert(list_is_valid(the_list)); return JB_ERR_OK; } /********************************************************************* * * Function : enlist_first * * Description : Append a string as first element into a specified * string list. * * Parameters : * 1 : the_list = pointer to list * 2 : str = string to add to the list (maybe NULL) * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, the_list will be unchanged. * *********************************************************************/ jb_err enlist_first(struct list *the_list, const char *str) { struct list_entry *cur; assert(the_list); assert(list_is_valid(the_list)); if (NULL == (cur = (struct list_entry *)zalloc(sizeof(*cur)))) { return JB_ERR_MEMORY; } if (str) { if (NULL == (cur->str = strdup(str))) { free(cur); return JB_ERR_MEMORY; } } /* else { cur->str = NULL; } - implied by zalloc */ cur->next = the_list->first; the_list->first = cur; if (the_list->last == NULL) { the_list->last = cur; } assert(list_is_valid(the_list)); return JB_ERR_OK; } /********************************************************************* * * Function : enlist_unique * * Description : Append a string into a specified string list, * if & only if it's not there already. * If the num_significant_chars argument is nonzero, * only compare up to the nth character. * * Parameters : * 1 : the_list = pointer to list * 2 : str = string to add to the list * 3 : num_significant_chars = number of chars to use * for uniqueness test, or 0 to require an exact match. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, the_list will be unchanged. * "Success" does not indicate whether or not the * item was already in the list. * *********************************************************************/ jb_err enlist_unique(struct list *the_list, const char *str, size_t num_significant_chars) { struct list_entry *cur_entry; assert(the_list); assert(list_is_valid(the_list)); assert(str); assert(num_significant_chars >= 0); assert(num_significant_chars <= strlen(str)); if (num_significant_chars > 0) { for (cur_entry = the_list->first; cur_entry != NULL; cur_entry = cur_entry->next) { if ((cur_entry->str != NULL) && (0 == strncmp(str, cur_entry->str, num_significant_chars))) { /* Already there */ return JB_ERR_OK; } } } else { /* Test whole string */ for (cur_entry = the_list->first; cur_entry != NULL; cur_entry = cur_entry->next) { if ((cur_entry->str != NULL) && (0 == strcmp(str, cur_entry->str))) { /* Already there */ return JB_ERR_OK; } } } return enlist(the_list, str); } /********************************************************************* * * Function : enlist_unique_header * * Description : Make a HTTP header from the two strings name and value, * and append the result into a specified string list, * if & only if there isn't already a header with that name. * * Parameters : * 1 : the_list = pointer to list * 2 : name = HTTP header name (e.g. "Content-type") * 3 : value = HTTP header value (e.g. "text/html") * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, the_list will be unchanged. * "Success" does not indicate whether or not the * header was already in the list. * *********************************************************************/ jb_err enlist_unique_header(struct list *the_list, const char *name, const char *value) { jb_err result = JB_ERR_MEMORY; char *header; size_t header_size; assert(the_list); assert(list_is_valid(the_list)); assert(name); assert(value); /* + 2 for the ': ', + 1 for the \0 */ header_size = strlen(name) + 2 + strlen(value) + 1; header = (char *)malloc(header_size); if (NULL != header) { const size_t bytes_to_compare = strlen(name) + 2; char *p = header; snprintf(header, header_size, "%s: %s", name, value); /* * The trailing "\r\n" is added by list_to_text(), * if the caller passed them anyway, cut the header * at the first one or dump core if this is a debug * build. */ do { if ((*p == '\r') || (*p == '\n')) { assert(*p != '\r'); assert(*p != '\n'); *p = '\0'; } } while (*p++); result = enlist_unique(the_list, header, bytes_to_compare); free(header); assert(list_is_valid(the_list)); } return result; } /********************************************************************* * * Function : list_remove_all * * Description : Remove all entries from a list. On return, the_list * is a valid, empty list. Note that this is similar * to destroy_list(), but the difference is that this * function guarantees that the list structure is still * valid after the call. * * Parameters : * 1 : the_list = pointer to list * * Returns : N/A * *********************************************************************/ void list_remove_all(struct list *the_list) { struct list_entry *cur_entry; struct list_entry *next_entry; assert(the_list); assert(list_is_valid(the_list)); for (cur_entry = the_list->first; cur_entry ; cur_entry = next_entry) { next_entry = cur_entry->next; freez(cur_entry->str); free(cur_entry); } the_list->first = the_list->last = NULL; assert(list_is_valid(the_list)); } /********************************************************************* * * Function : list_to_text * * Description : "Flatten" a string list into 1 long \r\n delimited string, * adding an empty line at the end. NULL entries are ignored. * This function does not change the_list. * * XXX: Should probably be renamed as it's only * useful (and used) to flatten header lists. * * Parameters : * 1 : the_list = pointer to list * * Returns : NULL on malloc error, else new long string. * Caller must free() it. * *********************************************************************/ char *list_to_text(const struct list *the_list) { struct list_entry *cur_entry; char *text; size_t text_length; char *cursor; size_t bytes_left; assert(the_list); assert(list_is_valid(the_list)); /* * Calculate the length of the final text. * '2' because of the '\r\n' at the end of * each string and at the end of the text. */ text_length = 2; for (cur_entry = the_list->first; cur_entry; cur_entry = cur_entry->next) { if (cur_entry->str) { text_length += strlen(cur_entry->str) + 2; } } bytes_left = text_length + 1; text = (char *)malloc(bytes_left); if (NULL == text) { return NULL; } cursor = text; for (cur_entry = the_list->first; cur_entry; cur_entry = cur_entry->next) { if (cur_entry->str) { const int written = snprintf(cursor, bytes_left, "%s\r\n", cur_entry->str); assert(written > 0); assert(written < bytes_left); bytes_left -= (size_t)written; cursor += (size_t)written; } } assert(bytes_left == 3); *cursor++ = '\r'; *cursor++ = '\n'; *cursor = '\0'; assert(text_length == cursor - text); assert(text[text_length] == '\0'); return text; } /********************************************************************* * * Function : list_remove_item * * Description : Remove a string from a specified string list. * * Parameters : * 1 : the_list = pointer to list * 2 : str = string to remove from the list - non-NULL * * Returns : Number of times it was removed. * *********************************************************************/ int list_remove_item(struct list *the_list, const char *str) { struct list_entry *prev = NULL; struct list_entry *cur; struct list_entry *next; int count = 0; assert(the_list); assert(list_is_valid(the_list)); assert(str); cur = the_list->first; while (cur != NULL) { next = cur->next; if ((cur->str != NULL) && (0 == strcmp(str, cur->str))) { count++; if (prev != NULL) { prev->next = next; } else { the_list->first = next; } free((char *)cur->str); free(cur); } else { prev = cur; } cur = next; } the_list->last = prev; assert(list_is_valid(the_list)); return count; } /********************************************************************* * * Function : list_remove_list * * Description : Remove all strings in one list from another list. * This is currently a brute-force algorithm * (it compares every pair of strings). * * Parameters : * 1 : dest = list to change * 2 : src = list of strings to remove * * Returns : Total number of strings removed. * *********************************************************************/ int list_remove_list(struct list *dest, const struct list *src) { struct list_entry *cur; int count = 0; assert(src); assert(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); for (cur = src->first; cur != NULL; cur = cur->next) { if (cur->str != NULL) { count += list_remove_item(dest, cur->str); } } assert(list_is_valid(src)); assert(list_is_valid(dest)); return count; } /********************************************************************* * * Function : list_duplicate * * Description : Copy a string list * * Parameters : * 1 : dest = Destination list. Must be a valid list. * All existing entries will be removed. * 1 : src = pointer to source list for copy. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, dest will be empty. * *********************************************************************/ jb_err list_duplicate(struct list *dest, const struct list *src) { struct list_entry * cur_src; struct list_entry * cur_dest; assert(src); assert(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); list_remove_all(dest); /* Need to process first entry specially so we can set dest->first */ cur_src = src->first; if (cur_src) { cur_dest = dest->first = (struct list_entry *)zalloc(sizeof(*cur_dest)); if (cur_dest == NULL) { destroy_list(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_MEMORY; } if (cur_src->str) { cur_dest->str = strdup(cur_src->str); if (cur_dest->str == NULL) { destroy_list(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_MEMORY; } } /* else { cur_dest->str = NULL; } - implied by zalloc */ /* Now process the rest */ for (cur_src = cur_src->next; cur_src; cur_src = cur_src->next) { cur_dest = cur_dest->next = (struct list_entry *)zalloc(sizeof(*cur_dest)); if (cur_dest == NULL) { destroy_list(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_MEMORY; } if (cur_src->str) { cur_dest->str = strdup(cur_src->str); if (cur_dest->str == NULL) { destroy_list(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_MEMORY; } } /* else { cur_dest->str = NULL; } - implied by zalloc */ } dest->last = cur_dest; } assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_OK; } /********************************************************************* * * Function : list_append_list_unique * * Description : Append a string list to another list. * Duplicate items are not added. * * Parameters : * 1 : dest = pointer to destination list for merge. * 2 : src = pointer to source for merge. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * On error, some (but not all) of src might have * been copied into dest. * *********************************************************************/ jb_err list_append_list_unique(struct list *dest, const struct list *src) { struct list_entry * cur; assert(src); assert(dest); assert(list_is_valid(src)); assert(list_is_valid(dest)); for (cur = src->first; cur; cur = cur->next) { if (cur->str) { if (enlist_unique(dest, cur->str, 0)) { assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_MEMORY; } } } assert(list_is_valid(src)); assert(list_is_valid(dest)); return JB_ERR_OK; } /********************************************************************* * * Function : list_is_empty * * Description : Test whether a list is empty. Does not change the list. * * Parameters : * 1 : the_list = pointer to list to test. * * Returns : Nonzero if the list contains no entries. * *********************************************************************/ int list_is_empty(const struct list *the_list) { assert(the_list); assert(list_is_valid(the_list)); return (the_list->first == NULL); } /********************************************************************* * * Function : list_contains_item * * Description : Tests whether a list item is already set. * Does not change the list. * * Parameters : * 1 : the_list = list to search in * 2 : str = string to search for * * Returns : TRUE if the item was found, * FALSE otherwise. * *********************************************************************/ int list_contains_item(const struct list *the_list, const char *str) { struct list_entry *entry; assert(the_list); assert(list_is_valid(the_list)); assert(str); for (entry = the_list->first; entry != NULL; entry = entry->next) { if (entry->str == NULL) { /* * NULL pointers are allowed in some lists. * For example for csp->headers in case a * header was removed. */ continue; } if (0 == strcmp(str, entry->str)) { /* Item found */ return TRUE; } } return FALSE; } /********************************************************************* * * Function : new_map * * Description : Create a new, empty map. * * Parameters : N/A * * Returns : A new, empty map, or NULL if out of memory. * *********************************************************************/ struct map *new_map(void) { return (struct map *) zalloc(sizeof(struct map)); } /********************************************************************* * * Function : free_map * * Description : Free the memory occupied by a map and its * depandant strings * * Parameters : * 1 : the_map = map to be freed. May be NULL. * * Returns : N/A * *********************************************************************/ void free_map(struct map *the_map) { struct map_entry *cur_entry; struct map_entry *next_entry; if (the_map == NULL) { return; } for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = next_entry) { freez(cur_entry->name); freez(cur_entry->value); next_entry = cur_entry->next; free(cur_entry); } the_map->first = the_map->last = NULL; free(the_map); } /********************************************************************* * * Function : map * * Description : Add a mapping from given name to given value to a * given map. * * Note: Since all strings will be free()d in free_map() * later, set the copy flags for constants or * strings that will be independently free()d. * * Note2: This function allows NULL parameters - it * returns JB_ERR_MEMORY in that case. * * Note3: If this function returns JB_ERR_MEMORY, * it will free(name) unless you specify * name_needs_copying, and similarly it will * free(value) unless you specify * value_needs_copying. * * Due to Note2 and Note3 above, the following code * is legal, and will never crash or leak memory even * if the system runs out of memory: * * err = map(mymap, "xyz", 1, html_encode(somestring), 0); * * err will be set to JB_ERR_MEMORY if either call runs * out-of-memory. Without these features, you would * need to check the return value of html_encode in the * above example for NULL, which (at least) doubles the * amount of error-checking code needed. * * Parameters : * 1 : the_map = map to add to * 2 : name = name to add * 3 : name_needs_copying = flag set if a copy of name should be used * 4 : value = value to add * 5 : value_needs_copying = flag set if a copy of value should be used * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err map(struct map *the_map, const char *name, int name_needs_copying, const char *value, int value_needs_copying) { struct map_entry *new_entry; assert(the_map); if ( (NULL == value) || (NULL == name) || (NULL == (new_entry = zalloc(sizeof(*new_entry))))) { if ((name != NULL) && (!name_needs_copying)) { free((char *)name); } if ((value != NULL) && (!value_needs_copying)) { free((char *)value); } return JB_ERR_MEMORY; } if (name_needs_copying) { if (NULL == (name = strdup(name))) { free(new_entry); if (!value_needs_copying) { free((char *)value); } return JB_ERR_MEMORY; } } if (value_needs_copying) { if (NULL == (value = strdup(value))) { free((char *)name); free(new_entry); return JB_ERR_MEMORY; } } new_entry->name = name; new_entry->value = value; /* new_entry->next = NULL; - implied by zalloc */ if (the_map->last) { the_map->last->next = new_entry; the_map->last = new_entry; } else { the_map->first = new_entry; the_map->last = new_entry; } return JB_ERR_OK; } /********************************************************************* * * Function : unmap * * Description : Remove all map_entry structs with a given name from * a given map. * * Parameters : * 1 : the_map = map to look in * 2 : name = name to unmap * * Returns : JB_ERR_OK * *********************************************************************/ jb_err unmap(struct map *the_map, const char *name) { struct map_entry *cur_entry, *last_entry; assert(the_map); assert(name); last_entry = the_map->first; for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = cur_entry->next) { if (!strcmp(name, cur_entry->name)) { /* * Update the incoming pointer */ if (cur_entry == the_map->first) { the_map->first = cur_entry->next; } else { last_entry->next = cur_entry->next; } /* * Update the map's last pointer */ if (cur_entry == the_map->last) { the_map->last = last_entry; } /* * Free the map_entry */ freez(cur_entry->name); freez(cur_entry->value); freez(cur_entry); cur_entry = last_entry; } else { last_entry = cur_entry; } } return JB_ERR_OK; } /********************************************************************* * * Function : lookup * * Description : Look up an item with a given name in a map, and * return its value * * Parameters : * 1 : the_map = map to look in * 2 : name = name parameter to look for * * Returns : the value if found, else the empty string. * Return value is alloced as part of the map, so * it is freed when the map is destroyed. Caller * must not free or modify it. * *********************************************************************/ const char *lookup(const struct map *the_map, const char *name) { const struct map_entry *cur_entry; assert(the_map); assert(name); for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = cur_entry->next) { if (!strcmp(name, cur_entry->name)) { return cur_entry->value; } } return ""; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./strptime.h000640 001751 001751 00000057174 11217504052 016015 0ustar00fkfk000000 000000 /* Convert a string representation of time to a time value. Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* XXX This version of the implementation is not really complete. Some of the fields cannot add information alone. But if seeing some of them in the same format (such as year, week and weekday) this is enough information for determining the date. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #ifdef _LIBC # include "../locale/localeinfo.h" #endif #ifndef __P # if defined (__GNUC__) || (defined (__STDC__) && __STDC__) # define __P(args) args # else # define __P(args) () # endif /* GCC. */ #endif /* Not __P. */ #if ! HAVE_LOCALTIME_R && ! defined localtime_r # ifdef _LIBC # define localtime_r __localtime_r # else /* Approximate localtime_r as best we can in its absence. */ # define localtime_r my_localtime_r static struct tm *localtime_r __P ((const time_t *, struct tm *)); static struct tm * localtime_r (t, tp) const time_t *t; struct tm *tp; { struct tm *l = localtime (t); if (! l) return 0; *tp = *l; return tp; } # endif /* ! _LIBC */ #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ #define match_char(ch1, ch2) if (ch1 != ch2) return NULL #if defined __GNUC__ && __GNUC__ >= 2 # define match_string(cs1, s2) \ ({ size_t len = strlen (cs1); \ int result = strncasecmp ((cs1), (s2), len) == 0; \ if (result) (s2) += len; \ result; }) #else /* Oh come on. Get a reasonable compiler. */ # define match_string(cs1, s2) \ (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) #endif /* We intentionally do not use isdigit() for testing because this will lead to problems with the wide character version. */ #define get_number(from, to, n) \ do { \ int __n = n; \ val = 0; \ while (*rp == ' ') \ ++rp; \ if (*rp < '0' || *rp > '9') \ return NULL; \ do { \ val *= 10; \ val += *rp++ - '0'; \ } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \ if (val < from || val > to) \ return NULL; \ } while (0) #ifdef _NL_CURRENT # define get_alt_number(from, to, n) \ ({ \ __label__ do_normal; \ if (*decided != raw) \ { \ const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \ int __n = n; \ int any = 0; \ while (*rp == ' ') \ ++rp; \ val = 0; \ do { \ val *= 10; \ while (*alts != '\0') \ { \ size_t len = strlen (alts); \ if (strncasecmp (alts, rp, len) == 0) \ break; \ alts += len + 1; \ ++val; \ } \ if (*alts == '\0') \ { \ if (*decided == not && ! any) \ goto do_normal; \ /* If we haven't read anything it's an error. */ \ if (! any) \ return NULL; \ /* Correct the premature multiplication. */ \ val /= 10; \ break; \ } \ else \ *decided = loc; \ } while (--__n > 0 && val * 10 <= to); \ if (val < from || val > to) \ return NULL; \ } \ else \ { \ do_normal: \ get_number (from, to, n); \ } \ 0; \ }) #else # define get_alt_number(from, to, n) \ /* We don't have the alternate representation. */ \ get_number(from, to, n) #endif #define recursive(new_fmt) \ (*(new_fmt) != '\0' \ && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL) #ifdef _LIBC /* This is defined in locale/C-time.c in the GNU libc. */ extern const struct locale_data _nl_C_LC_TIME; extern const unsigned short int __mon_yday[2][13]; # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string) # define ab_weekday_name \ (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string) # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string) # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string) # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string) # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string) # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string) # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string) # define HERE_T_FMT_AMPM \ (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string) # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string) # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n) #else static char const weekday_name[][10] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static char const ab_weekday_name[][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char const month_name[][10] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static char const ab_month_name[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" # define HERE_D_FMT "%m/%d/%y" # define HERE_AM_STR "AM" # define HERE_PM_STR "PM" # define HERE_T_FMT_AMPM "%I:%M:%S %p" # define HERE_T_FMT "%H:%M:%S" const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; #endif /* Status of lookup: do we use the locale data or the raw data? */ enum locale_status { not, loc, raw }; #ifndef __isleap /* Nonzero if YEAR is a leap year (every 4 years, except every 100th isn't, and every 400th is). */ # define __isleap(year) \ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) #endif /* Compute the day of the week. */ static void day_of_the_week (struct tm *tm) { /* We know that January 1st 1970 was a Thursday (= 4). Compute the the difference between this data in the one on TM and so determine the weekday. */ int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); int wday = (-473 + (365 * (tm->tm_year - 70)) + (corr_year / 4) - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) + (((corr_year / 4) / 25) / 4) + __mon_yday[0][tm->tm_mon] + tm->tm_mday - 1); tm->tm_wday = ((wday % 7) + 7) % 7; } /* Compute the day of the year. */ static void day_of_the_year (struct tm *tm) { tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] + (tm->tm_mday - 1)); } static char * #ifdef _LIBC internal_function #endif strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm, enum locale_status *decided, int era_cnt)); static char * #ifdef _LIBC internal_function #endif strptime_internal (rp, fmt, tm, decided, era_cnt) const char *rp; const char *fmt; struct tm *tm; enum locale_status *decided; int era_cnt; { const char *rp_backup; int cnt; size_t val; int have_I, is_pm; int century, want_century; int want_era; int have_wday, want_xday; int have_yday; int have_mon, have_mday; #ifdef _NL_CURRENT size_t num_eras; #endif struct era_entry *era; have_I = is_pm = 0; century = -1; want_century = 0; want_era = 0; era = NULL; have_wday = want_xday = have_yday = have_mon = have_mday = 0; while (*fmt != '\0') { /* A white space in the format string matches 0 more or white space in the input string. */ if (isspace (*fmt)) { while (isspace (*rp)) ++rp; ++fmt; continue; } /* Any character but `%' must be matched by the same character in the iput string. */ if (*fmt != '%') { match_char (*fmt++, *rp++); continue; } ++fmt; #ifndef _NL_CURRENT /* We need this for handling the `E' modifier. */ start_over: #endif /* Make back up of current processing pointer. */ rp_backup = rp; switch (*fmt++) { case '%': /* Match the `%' character itself. */ match_char ('%', *rp++); break; case 'a': case 'A': /* Match day of week. */ for (cnt = 0; cnt < 7; ++cnt) { #ifdef _NL_CURRENT if (*decided !=raw) { if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), weekday_name[cnt])) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), ab_weekday_name[cnt])) *decided = loc; break; } } #endif if (*decided != loc && (match_string (weekday_name[cnt], rp) || match_string (ab_weekday_name[cnt], rp))) { *decided = raw; break; } } if (cnt == 7) /* Does not match a weekday name. */ return NULL; tm->tm_wday = cnt; have_wday = 1; break; case 'b': case 'B': case 'h': /* Match month name. */ for (cnt = 0; cnt < 12; ++cnt) { #ifdef _NL_CURRENT if (*decided !=raw) { if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), month_name[cnt])) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp)) { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), ab_month_name[cnt])) *decided = loc; break; } } #endif if (match_string (month_name[cnt], rp) || match_string (ab_month_name[cnt], rp)) { *decided = raw; break; } } if (cnt == 12) /* Does not match a month name. */ return NULL; tm->tm_mon = cnt; want_xday = 1; break; case 'c': /* Match locale's date and time format. */ #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } #endif if (!recursive (HERE_D_T_FMT)) return NULL; want_xday = 1; break; case 'C': /* Match century number. */ #ifdef _NL_CURRENT match_century: #endif get_number (0, 99, 2); century = val; want_xday = 1; break; case 'd': case 'e': /* Match day of month. */ get_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'F': if (!recursive ("%Y-%m-%d")) return NULL; want_xday = 1; break; case 'x': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } #endif /* Fall through. */ case 'D': /* Match standard day format. */ if (!recursive (HERE_D_FMT)) return NULL; want_xday = 1; break; case 'k': case 'H': /* Match hour in 24-hour clock. */ get_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock. */ get_number (1, 12, 2); tm->tm_hour = val % 12; have_I = 1; break; case 'j': /* Match day number of year. */ get_number (1, 366, 3); tm->tm_yday = val - 1; have_yday = 1; break; case 'm': /* Match number of month. */ get_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minute. */ get_number (0, 59, 2); tm->tm_min = val; break; case 'n': case 't': /* Match any white space. */ while (isspace (*rp)) ++rp; break; case 'p': /* Match locale's equivalent of AM/PM. */ #ifdef _NL_CURRENT if (*decided != raw) { if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) *decided = loc; break; } if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) *decided = loc; is_pm = 1; break; } *decided = raw; } #endif if (!match_string (HERE_AM_STR, rp)) if (match_string (HERE_PM_STR, rp)) is_pm = 1; else return NULL; break; case 'r': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (*decided == not && strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), HERE_T_FMT_AMPM)) *decided = loc; break; } *decided = raw; } #endif if (!recursive (HERE_T_FMT_AMPM)) return NULL; break; case 'R': if (!recursive ("%H:%M")) return NULL; break; case 's': { /* The number of seconds may be very high so we cannot use the `get_number' macro. Instead read the number character for character and construct the result while doing this. */ time_t secs = 0; if (*rp < '0' || *rp > '9') /* We need at least one digit. */ return NULL; do { secs *= 10; secs += *rp++ - '0'; } while (*rp >= '0' && *rp <= '9'); if (localtime_r (&secs, tm) == NULL) /* Error in function. */ return NULL; } break; case 'S': get_number (0, 61, 2); tm->tm_sec = val; break; case 'X': #ifdef _NL_CURRENT if (*decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) *decided = loc; break; } *decided = raw; } #endif /* Fall through. */ case 'T': if (!recursive (HERE_T_FMT)) return NULL; break; case 'u': get_number (1, 7, 1); tm->tm_wday = val % 7; have_wday = 1; break; case 'g': get_number (0, 99, 2); /* XXX This cannot determine any field in TM. */ break; case 'G': if (*rp < '0' || *rp > '9') return NULL; /* XXX Ignore the number since we would need some more information to compute a real date. */ do ++rp; while (*rp >= '0' && *rp <= '9'); break; case 'U': case 'V': case 'W': get_number (0, 53, 2); /* XXX This cannot determine any field in TM without some information. */ break; case 'w': /* Match number of weekday. */ get_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': #ifdef _NL_CURRENT match_year_in_century: #endif /* Match year within century. */ get_number (0, 99, 2); /* The "Year 2000: The Millennium Rollover" paper suggests that values in the range 69-99 refer to the twentieth century. */ tm->tm_year = val >= 69 ? val : val + 100; /* Indicate that we want to use the century, if specified. */ want_century = 1; want_xday = 1; break; case 'Y': /* Match year including century number. */ get_number (0, 9999, 4); tm->tm_year = val - 1900; want_century = 0; want_xday = 1; break; case 'Z': /* XXX How to handle this? */ break; case 'E': #ifdef _NL_CURRENT switch (*fmt++) { case 'c': /* Match locale's alternate date and time format. */ if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_T_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_T_FMT)) *decided = loc; want_xday = 1; break; } *decided = raw; } /* The C locale has no era information, so use the normal representation. */ if (!recursive (HERE_D_T_FMT)) return NULL; want_xday = 1; break; case 'C': if (*decided != raw) { if (era_cnt >= 0) { era = _nl_select_era_entry (era_cnt); if (match_string (era->era_name, rp)) { *decided = loc; break; } else return NULL; } else { num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt, rp = rp_backup) { era = _nl_select_era_entry (era_cnt); if (match_string (era->era_name, rp)) { *decided = loc; break; } } if (era_cnt == (int) num_eras) { era_cnt = -1; if (*decided == loc) return NULL; } else break; } *decided = raw; } /* The C locale has no era information, so use the normal representation. */ goto match_century; case 'y': if (*decided == raw) goto match_year_in_century; get_number(0, 9999, 4); tm->tm_year = val; want_era = 1; want_xday = 1; break; case 'Y': if (*decided != raw) { num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (era_cnt = 0; era_cnt < (int) num_eras; ++era_cnt, rp = rp_backup) { era = _nl_select_era_entry (era_cnt); if (recursive (era->era_format)) break; } if (era_cnt == (int) num_eras) { era_cnt = -1; if (*decided == loc) return NULL; else rp = rp_backup; } else { *decided = loc; era_cnt = -1; break; } *decided = raw; } get_number (0, 9999, 4); tm->tm_year = val - 1900; want_century = 0; want_xday = 1; break; case 'x': if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_FMT)) *decided = loc; break; } *decided = raw; } if (!recursive (HERE_D_FMT)) return NULL; break; case 'X': if (*decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, T_FMT); if (!recursive (fmt)) { if (*decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_T_FMT)) *decided = loc; break; } *decided = raw; } if (!recursive (HERE_T_FMT)) return NULL; break; default: return NULL; } break; #else /* We have no information about the era format. Just use the normal format. */ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' && *fmt != 'x' && *fmt != 'X') /* This is an illegal format. */ return NULL; goto start_over; #endif case 'O': switch (*fmt++) { case 'd': case 'e': /* Match day of month using alternate numeric symbols. */ get_alt_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'H': /* Match hour in 24-hour clock using alternate numeric symbols. */ get_alt_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_hour = val - 1; have_I = 1; break; case 'm': /* Match month using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minutes using alternate numeric symbols. */ get_alt_number (0, 59, 2); tm->tm_min = val; break; case 'S': /* Match seconds using alternate numeric symbols. */ get_alt_number (0, 61, 2); tm->tm_sec = val; break; case 'U': case 'V': case 'W': get_alt_number (0, 53, 2); /* XXX This cannot determine any field in TM without further information. */ break; case 'w': /* Match number of weekday using alternate numeric symbols. */ get_alt_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': /* Match year within century using alternate numeric symbols. */ get_alt_number (0, 99, 2); tm->tm_year = val >= 69 ? val : val + 100; want_xday = 1; break; default: return NULL; } break; default: return NULL; } } if (have_I && is_pm) tm->tm_hour += 12; if (century != -1) { if (want_century) tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; else /* Only the century, but not the year. Strange, but so be it. */ tm->tm_year = (century - 19) * 100; } #ifdef _NL_CURRENT if (era_cnt != -1) { era = _nl_select_era_entry(era_cnt); if (want_era) tm->tm_year = (era->start_date[0] + ((tm->tm_year - era->offset) * era->absolute_direction)); else /* Era start year assumed. */ tm->tm_year = era->start_date[0]; } else #endif if (want_era) return NULL; if (want_xday && !have_wday) { if ( !(have_mon && have_mday) && have_yday) { /* We don't have tm_mon and/or tm_mday, compute them. */ int t_mon = 0; while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) t_mon++; if (!have_mon) tm->tm_mon = t_mon - 1; if (!have_mday) tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); } day_of_the_week (tm); } if (want_xday && !have_yday) day_of_the_year (tm); return (char *) rp; } char * strptime (buf, format, tm) const char *buf; const char *format; struct tm *tm; { enum locale_status decided; #ifdef _NL_CURRENT decided = not; #else decided = raw; #endif return strptime_internal (buf, format, tm, &decided, -1); } privoxy-3.0.21-stable/./parsers.c000640 001751 001751 00000440137 12116117562 015620 0ustar00fkfk000000 000000 const char parsers_rcs[] = "$Id: parsers.c,v 1.275 2013/03/07 14:08:50 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifndef _WIN32 #include #include #endif #include #include #include #include #ifdef __GLIBC__ /* * Convince GNU's libc to provide a strptime prototype. */ #define __USE_XOPEN #endif /*__GLIBC__ */ #include #ifdef FEATURE_ZLIB #include #define GZIP_IDENTIFIER_1 0x1f #define GZIP_IDENTIFIER_2 0x8b #define GZIP_FLAG_CHECKSUM 0x02 #define GZIP_FLAG_EXTRA_FIELDS 0x04 #define GZIP_FLAG_FILE_NAME 0x08 #define GZIP_FLAG_COMMENT 0x10 #define GZIP_FLAG_RESERVED_BITS 0xe0 #endif #if !defined(_WIN32) && !defined(__OS2__) #include #endif #include "project.h" #ifdef FEATURE_PTHREAD #include "jcc.h" /* jcc.h is for mutex semapores only */ #endif /* def FEATURE_PTHREAD */ #include "list.h" #include "parsers.h" #include "ssplit.h" #include "errlog.h" #include "jbsockets.h" #include "miscutil.h" #include "list.h" #include "actions.h" #include "filters.h" #ifndef HAVE_STRPTIME #include "strptime.h" #endif const char parsers_h_rcs[] = PARSERS_H_VERSION; static char *get_header_line(struct iob *iob); static jb_err scan_headers(struct client_state *csp); static jb_err header_tagger(struct client_state *csp, char *header); static jb_err parse_header_time(const char *header_time, time_t *result); static jb_err crumble (struct client_state *csp, char **header); static jb_err filter_header (struct client_state *csp, char **header); static jb_err client_connection (struct client_state *csp, char **header); static jb_err client_referrer (struct client_state *csp, char **header); static jb_err client_uagent (struct client_state *csp, char **header); static jb_err client_ua (struct client_state *csp, char **header); static jb_err client_from (struct client_state *csp, char **header); static jb_err client_send_cookie (struct client_state *csp, char **header); static jb_err client_x_forwarded (struct client_state *csp, char **header); static jb_err client_accept_encoding (struct client_state *csp, char **header); static jb_err client_te (struct client_state *csp, char **header); static jb_err client_max_forwards (struct client_state *csp, char **header); static jb_err client_host (struct client_state *csp, char **header); static jb_err client_if_modified_since (struct client_state *csp, char **header); static jb_err client_accept_language (struct client_state *csp, char **header); static jb_err client_if_none_match (struct client_state *csp, char **header); static jb_err crunch_client_header (struct client_state *csp, char **header); static jb_err client_x_filter (struct client_state *csp, char **header); static jb_err client_range (struct client_state *csp, char **header); static jb_err server_set_cookie (struct client_state *csp, char **header); static jb_err server_connection (struct client_state *csp, char **header); static jb_err server_content_type (struct client_state *csp, char **header); static jb_err server_adjust_content_length(struct client_state *csp, char **header); static jb_err server_content_md5 (struct client_state *csp, char **header); static jb_err server_content_encoding (struct client_state *csp, char **header); static jb_err server_transfer_coding (struct client_state *csp, char **header); static jb_err server_http (struct client_state *csp, char **header); static jb_err crunch_server_header (struct client_state *csp, char **header); static jb_err server_last_modified (struct client_state *csp, char **header); static jb_err server_content_disposition(struct client_state *csp, char **header); #ifdef FEATURE_ZLIB static jb_err server_adjust_content_encoding(struct client_state *csp, char **header); #endif #ifdef FEATURE_CONNECTION_KEEP_ALIVE static jb_err server_save_content_length(struct client_state *csp, char **header); static jb_err server_keep_alive(struct client_state *csp, char **header); static jb_err server_proxy_connection(struct client_state *csp, char **header); static jb_err client_keep_alive(struct client_state *csp, char **header); static jb_err client_save_content_length(struct client_state *csp, char **header); static jb_err client_proxy_connection(struct client_state *csp, char **header); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ static jb_err client_host_adder (struct client_state *csp); static jb_err client_xtra_adder (struct client_state *csp); static jb_err client_x_forwarded_for_adder(struct client_state *csp); static jb_err client_connection_header_adder(struct client_state *csp); static jb_err server_connection_adder(struct client_state *csp); #ifdef FEATURE_CONNECTION_KEEP_ALIVE static jb_err server_proxy_connection_adder(struct client_state *csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ static jb_err proxy_authentication(struct client_state *csp, char **header); static jb_err create_forged_referrer(char **header, const char *hostport); static jb_err create_fake_referrer(char **header, const char *fake_referrer); static jb_err handle_conditional_hide_referrer_parameter(char **header, const char *host, const int parameter_conditional_block); static void create_content_length_header(unsigned long long content_length, char *header, size_t buffer_length); /* * List of functions to run on a list of headers. */ struct parsers { /** The header prefix to match */ const char *str; /** The length of the prefix to match */ const size_t len; /** The function to apply to this line */ const parser_func_ptr parser; }; static const struct parsers client_patterns[] = { { "referer:", 8, client_referrer }, { "user-agent:", 11, client_uagent }, { "ua-", 3, client_ua }, { "from:", 5, client_from }, { "cookie:", 7, client_send_cookie }, { "x-forwarded-for:", 16, client_x_forwarded }, { "Accept-Encoding:", 16, client_accept_encoding }, { "TE:", 3, client_te }, { "Host:", 5, client_host }, { "if-modified-since:", 18, client_if_modified_since }, #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Keep-Alive:", 11, client_keep_alive }, { "Content-Length:", 15, client_save_content_length }, { "Proxy-Connection:", 17, client_proxy_connection }, #else { "Keep-Alive:", 11, crumble }, { "Proxy-Connection:", 17, crumble }, #endif { "connection:", 11, client_connection }, { "max-forwards:", 13, client_max_forwards }, { "Accept-Language:", 16, client_accept_language }, { "if-none-match:", 14, client_if_none_match }, { "Range:", 6, client_range }, { "Request-Range:", 14, client_range }, { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, { "Proxy-Authorization:", 20, proxy_authentication }, #if 0 { "Transfer-Encoding:", 18, client_transfer_encoding }, #endif { "*", 0, crunch_client_header }, { "*", 0, filter_header }, { NULL, 0, NULL } }; static const struct parsers server_patterns[] = { { "HTTP/", 5, server_http }, { "set-cookie:", 11, server_set_cookie }, { "connection:", 11, server_connection }, { "Content-Type:", 13, server_content_type }, { "Content-MD5:", 12, server_content_md5 }, { "Content-Encoding:", 17, server_content_encoding }, #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Content-Length:", 15, server_save_content_length }, { "Keep-Alive:", 11, server_keep_alive }, { "Proxy-Connection:", 17, server_proxy_connection }, #else { "Keep-Alive:", 11, crumble }, #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ { "Transfer-Encoding:", 18, server_transfer_coding }, { "content-disposition:", 20, server_content_disposition }, { "Last-Modified:", 14, server_last_modified }, { "Proxy-Authenticate:", 19, proxy_authentication }, { "*", 0, crunch_server_header }, { "*", 0, filter_header }, { NULL, 0, NULL } }; static const add_header_func_ptr add_client_headers[] = { client_host_adder, client_x_forwarded_for_adder, client_xtra_adder, client_connection_header_adder, NULL }; static const add_header_func_ptr add_server_headers[] = { server_connection_adder, #ifdef FEATURE_CONNECTION_KEEP_ALIVE server_proxy_connection_adder, #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ NULL }; /********************************************************************* * * Function : flush_socket * * Description : Write any pending "buffered" content. * * Parameters : * 1 : fd = file descriptor of the socket to read * 2 : iob = The I/O buffer to flush, usually csp->iob. * * Returns : On success, the number of bytes written are returned (zero * indicates nothing was written). On error, -1 is returned, * and errno is set appropriately. If count is zero and the * file descriptor refers to a regular file, 0 will be * returned without causing any other effect. For a special * file, the results are not portable. * *********************************************************************/ long flush_socket(jb_socket fd, struct iob *iob) { long len = iob->eod - iob->cur; if (len <= 0) { return(0); } if (write_socket(fd, iob->cur, (size_t)len)) { return(-1); } iob->eod = iob->cur = iob->buf; return(len); } /********************************************************************* * * Function : add_to_iob * * Description : Add content to the buffer, expanding the * buffer if necessary. * * Parameters : * 1 : iob = Destination buffer. * 2 : buffer_limit = Limit to which the destination may grow * 3 : src = holds the content to be added * 4 : n = number of bytes to be added * * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory * or buffer limit reached. * *********************************************************************/ jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, char *src, long n) { size_t used, offset, need; char *p; if (n <= 0) return JB_ERR_OK; used = (size_t)(iob->eod - iob->buf); offset = (size_t)(iob->cur - iob->buf); need = used + (size_t)n + 1; /* * If the buffer can't hold the new data, extend it first. * Use the next power of two if possible, else use the actual need. */ if (need > buffer_limit) { log_error(LOG_LEVEL_INFO, "Buffer limit reached while extending the buffer (iob). Needed: %d. Limit: %d", need, buffer_limit); return JB_ERR_MEMORY; } if (need > iob->size) { size_t want = iob->size ? iob->size : 512; while (want <= need) { want *= 2; } if (want <= buffer_limit && NULL != (p = (char *)realloc(iob->buf, want))) { iob->size = want; } else if (NULL != (p = (char *)realloc(iob->buf, need))) { iob->size = need; } else { log_error(LOG_LEVEL_ERROR, "Extending the buffer (iob) failed: %E"); return JB_ERR_MEMORY; } /* Update the iob pointers */ iob->cur = p + offset; iob->eod = p + used; iob->buf = p; } /* copy the new data into the iob buffer */ memcpy(iob->eod, src, (size_t)n); /* point to the end of the data */ iob->eod += n; /* null terminate == cheap insurance */ *iob->eod = '\0'; return JB_ERR_OK; } /********************************************************************* * * Function : clear_iob * * Description : Frees the memory allocated for an I/O buffer and * resets the structure. * * Parameters : * 1 : iob = I/O buffer to clear. * * Returns : JB_ERR_OK on success, JB_ERR_MEMORY if out-of-memory * or buffer limit reached. * *********************************************************************/ void clear_iob(struct iob *iob) { free(iob->buf); memset(iob, '\0', sizeof(*iob));; } #ifdef FEATURE_ZLIB /********************************************************************* * * Function : decompress_iob * * Description : Decompress buffered page, expanding the * buffer as necessary. csp->iob->cur * should point to the the beginning of the * compressed data block. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, * JB_ERR_MEMORY if out-of-memory limit reached, and * JB_ERR_COMPRESS if error decompressing buffer. * *********************************************************************/ jb_err decompress_iob(struct client_state *csp) { char *buf; /* new, uncompressed buffer */ char *cur; /* Current iob position (to keep the original * iob->cur unmodified if we return early) */ size_t bufsize; /* allocated size of the new buffer */ size_t old_size; /* Content size before decompression */ size_t skip_size; /* Number of bytes at the beginning of the iob that we should NOT decompress. */ int status; /* return status of the inflate() call */ z_stream zstr; /* used by calls to zlib */ assert(csp->iob->cur - csp->iob->buf > 0); assert(csp->iob->eod - csp->iob->cur > 0); bufsize = csp->iob->size; skip_size = (size_t)(csp->iob->cur - csp->iob->buf); old_size = (size_t)(csp->iob->eod - csp->iob->cur); cur = csp->iob->cur; if (bufsize < (size_t)10) { /* * This is to protect the parsing of gzipped data, * but it should(?) be valid for deflated data also. */ log_error(LOG_LEVEL_ERROR, "Buffer too small decompressing iob"); return JB_ERR_COMPRESS; } if (csp->content_type & CT_GZIP) { /* * Our task is slightly complicated by the facts that data * compressed by gzip does not include a zlib header, and * that there is no easily accessible interface in zlib to * handle a gzip header. We strip off the gzip header by * hand, and later inform zlib not to expect a header. */ /* * Strip off the gzip header. Please see RFC 1952 for more * explanation of the appropriate fields. */ if (((*cur++ & 0xff) != GZIP_IDENTIFIER_1) || ((*cur++ & 0xff) != GZIP_IDENTIFIER_2) || (*cur++ != Z_DEFLATED)) { log_error(LOG_LEVEL_ERROR, "Invalid gzip header when decompressing"); return JB_ERR_COMPRESS; } else { int flags = *cur++; if (flags & GZIP_FLAG_RESERVED_BITS) { /* The gzip header has reserved bits set; bail out. */ log_error(LOG_LEVEL_ERROR, "Invalid gzip header flags when decompressing"); return JB_ERR_COMPRESS; } /* * Skip mtime (4 bytes), extra flags (1 byte) * and OS type (1 byte). */ cur += 6; /* Skip extra fields if necessary. */ if (flags & GZIP_FLAG_EXTRA_FIELDS) { /* * Skip a given number of bytes, specified * as a 16-bit little-endian value. * * XXX: this code is untested and should probably be removed. */ int skip_bytes; skip_bytes = *cur++; skip_bytes += *cur++ << 8; /* * The number of bytes to skip should be positive * and we'd like to stay in the buffer. */ if ((skip_bytes < 0) || (skip_bytes >= (csp->iob->eod - cur))) { log_error(LOG_LEVEL_ERROR, "Unreasonable amount of bytes to skip (%d). Stopping decompression", skip_bytes); return JB_ERR_COMPRESS; } log_error(LOG_LEVEL_INFO, "Skipping %d bytes for gzip compression. Does this sound right?", skip_bytes); cur += skip_bytes; } /* Skip the filename if necessary. */ if (flags & GZIP_FLAG_FILE_NAME) { /* A null-terminated string is supposed to follow. */ while (*cur++ && (cur < csp->iob->eod)); } /* Skip the comment if necessary. */ if (flags & GZIP_FLAG_COMMENT) { /* A null-terminated string is supposed to follow. */ while (*cur++ && (cur < csp->iob->eod)); } /* Skip the CRC if necessary. */ if (flags & GZIP_FLAG_CHECKSUM) { cur += 2; } if (cur >= csp->iob->eod) { /* * If the current position pointer reached or passed * the buffer end, we were obviously tricked to skip * too much. */ log_error(LOG_LEVEL_ERROR, "Malformed gzip header detected. Aborting decompression."); return JB_ERR_COMPRESS; } } } else if (csp->content_type & CT_DEFLATE) { /* * In theory (that is, according to RFC 1950), deflate-compressed * data should begin with a two-byte zlib header and have an * adler32 checksum at the end. It seems that in practice only * the raw compressed data is sent. Note that this means that * we are not RFC 1950-compliant here, but the advantage is that * this actually works. :) * * We add a dummy null byte to tell zlib where the data ends, * and later inform it not to expect a header. * * Fortunately, add_to_iob() has thoughtfully null-terminated * the buffer; we can just increment the end pointer to include * the dummy byte. */ csp->iob->eod++; } else { log_error(LOG_LEVEL_ERROR, "Unable to determine compression format for decompression"); return JB_ERR_COMPRESS; } /* Set up the fields required by zlib. */ zstr.next_in = (Bytef *)cur; zstr.avail_in = (unsigned int)(csp->iob->eod - cur); zstr.zalloc = Z_NULL; zstr.zfree = Z_NULL; zstr.opaque = Z_NULL; /* * Passing -MAX_WBITS to inflateInit2 tells the library * that there is no zlib header. */ if (inflateInit2(&zstr, -MAX_WBITS) != Z_OK) { log_error(LOG_LEVEL_ERROR, "Error initializing decompression"); return JB_ERR_COMPRESS; } /* * Next, we allocate new storage for the inflated data. * We don't modify the existing iob yet, so in case there * is error in decompression we can recover gracefully. */ buf = zalloc(bufsize); if (NULL == buf) { log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); return JB_ERR_MEMORY; } assert(bufsize >= skip_size); memcpy(buf, csp->iob->buf, skip_size); zstr.avail_out = (uInt)(bufsize - skip_size); zstr.next_out = (Bytef *)buf + skip_size; /* Try to decompress the whole stream in one shot. */ while (Z_BUF_ERROR == (status = inflate(&zstr, Z_FINISH))) { /* We need to allocate more memory for the output buffer. */ char *tmpbuf; /* used for realloc'ing the buffer */ size_t oldbufsize = bufsize; /* keep track of the old bufsize */ if (0 == zstr.avail_in) { /* * If zlib wants more data then there's a problem, because * the complete compressed file should have been buffered. */ log_error(LOG_LEVEL_ERROR, "Unexpected end of compressed iob. Using what we got so far."); break; } /* * If we reached the buffer limit and still didn't have enough * memory, just give up. Due to the ceiling enforced by the next * if block we could actually check for equality here, but as it * can be easily mistaken for a bug we don't. */ if (bufsize >= csp->config->buffer_limit) { log_error(LOG_LEVEL_ERROR, "Buffer limit reached while decompressing iob"); return JB_ERR_MEMORY; } /* Try doubling the buffer size each time. */ bufsize *= 2; /* Don't exceed the buffer limit. */ if (bufsize > csp->config->buffer_limit) { bufsize = csp->config->buffer_limit; } /* Try to allocate the new buffer. */ tmpbuf = realloc(buf, bufsize); if (NULL == tmpbuf) { log_error(LOG_LEVEL_ERROR, "Out of memory decompressing iob"); freez(buf); return JB_ERR_MEMORY; } else { char *oldnext_out = (char *)zstr.next_out; /* * Update the fields for inflate() to use the new * buffer, which may be in a location different from * the old one. */ zstr.avail_out += (uInt)(bufsize - oldbufsize); zstr.next_out = (Bytef *)tmpbuf + bufsize - zstr.avail_out; /* * Compare with an uglier method of calculating these values * that doesn't require the extra oldbufsize variable. */ assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out); assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf)); buf = tmpbuf; } } if (Z_STREAM_ERROR == inflateEnd(&zstr)) { log_error(LOG_LEVEL_ERROR, "Inconsistent stream state after decompression: %s", zstr.msg); /* * XXX: Intentionally no return. * * According to zlib.h, Z_STREAM_ERROR is returned * "if the stream state was inconsistent". * * I assume in this case inflate()'s status * would also be something different than Z_STREAM_END * so this check should be redundant, but lets see. */ } if ((status != Z_STREAM_END) && (0 != zstr.avail_in)) { /* * We failed to decompress the stream and it's * not simply because of missing data. */ log_error(LOG_LEVEL_ERROR, "Unexpected error while decompressing to the buffer (iob): %s", zstr.msg); return JB_ERR_COMPRESS; } /* * Finally, we can actually update the iob, since the * decompression was successful. First, free the old * buffer. */ freez(csp->iob->buf); /* Now, update the iob to use the new buffer. */ csp->iob->buf = buf; csp->iob->cur = csp->iob->buf + skip_size; csp->iob->eod = (char *)zstr.next_out; csp->iob->size = bufsize; /* * Make sure the new uncompressed iob obeys some minimal * consistency conditions. */ if ((csp->iob->buf < csp->iob->cur) && (csp->iob->cur <= csp->iob->eod) && (csp->iob->eod <= csp->iob->buf + csp->iob->size)) { const size_t new_size = (size_t)(csp->iob->eod - csp->iob->cur); if (new_size > (size_t)0) { log_error(LOG_LEVEL_RE_FILTER, "Decompression successful. Old size: %d, new size: %d.", old_size, new_size); } else { /* zlib thinks this is OK, so lets do the same. */ log_error(LOG_LEVEL_INFO, "Decompression didn't result in any content."); } } else { /* It seems that zlib did something weird. */ log_error(LOG_LEVEL_ERROR, "Unexpected error decompressing the buffer (iob): %d==%d, %d>%d, %d<%d", csp->iob->cur, csp->iob->buf + skip_size, csp->iob->eod, csp->iob->buf, csp->iob->eod, csp->iob->buf + csp->iob->size); return JB_ERR_COMPRESS; } return JB_ERR_OK; } #endif /* defined(FEATURE_ZLIB) */ /********************************************************************* * * Function : normalize_lws * * Description : Reduces unquoted linear white space in headers * to a single space in accordance with RFC 2616 2.2. * This simplifies parsing and filtering later on. * * XXX: Remove log messages before * the next stable release? * * Parameters : * 1 : header = A header with linear white space to reduce. * * Returns : N/A * *********************************************************************/ static void normalize_lws(char *header) { char *p = header; while (*p != '\0') { if (privoxy_isspace(*p) && privoxy_isspace(*(p+1))) { char *q = p+1; while (privoxy_isspace(*q)) { q++; } log_error(LOG_LEVEL_HEADER, "Reducing white space in '%s'", header); string_move(p+1, q); } if (*p == '\t') { log_error(LOG_LEVEL_HEADER, "Converting tab to space in '%s'", header); *p = ' '; } else if (*p == '"') { char *end_of_token = strstr(p+1, "\""); if (NULL != end_of_token) { /* Don't mess with quoted text. */ p = end_of_token; } else { log_error(LOG_LEVEL_HEADER, "Ignoring single quote in '%s'", header); } } p++; } p = strchr(header, ':'); if ((p != NULL) && (p != header) && privoxy_isspace(*(p-1))) { /* * There's still space before the colon. * We don't want it. */ string_move(p-1, p); } } /********************************************************************* * * Function : get_header * * Description : This (odd) routine will parse the csp->iob * to get the next complete header. * * Parameters : * 1 : iob = The I/O buffer to parse, usually csp->iob. * * Returns : Any one of the following: * * 1) a pointer to a dynamically allocated string that contains a header line * 2) NULL indicating that the end of the header was reached * 3) "" indicating that the end of the iob was reached before finding * a complete header line. * *********************************************************************/ char *get_header(struct iob *iob) { char *header; header = get_header_line(iob); if ((header == NULL) || (*header == '\0')) { /* * No complete header read yet, tell the client. */ return header; } while ((iob->cur[0] == ' ') || (iob->cur[0] == '\t')) { /* * Header spans multiple lines, append the next one. */ char *continued_header; continued_header = get_header_line(iob); if ((continued_header == NULL) || (*continued_header == '\0')) { /* * No complete header read yet, return what we got. * XXX: Should "unread" header instead. */ log_error(LOG_LEVEL_INFO, "Failed to read a multi-line header properly: '%s'", header); break; } if (JB_ERR_OK != string_join(&header, continued_header)) { log_error(LOG_LEVEL_FATAL, "Out of memory while appending multiple headers."); } else { /* XXX: remove before next stable release. */ log_error(LOG_LEVEL_HEADER, "Merged multiple header lines to: '%s'", header); } } normalize_lws(header); return header; } /********************************************************************* * * Function : get_header_line * * Description : This (odd) routine will parse the csp->iob * to get the next header line. * * Parameters : * 1 : iob = The I/O buffer to parse, usually csp->iob. * * Returns : Any one of the following: * * 1) a pointer to a dynamically allocated string that contains a header line * 2) NULL indicating that the end of the header was reached * 3) "" indicating that the end of the iob was reached before finding * a complete header line. * *********************************************************************/ static char *get_header_line(struct iob *iob) { char *p, *q, *ret; if ((iob->cur == NULL) || ((p = strchr(iob->cur, '\n')) == NULL)) { return(""); /* couldn't find a complete header */ } *p = '\0'; ret = strdup(iob->cur); if (ret == NULL) { /* FIXME No way to handle error properly */ log_error(LOG_LEVEL_FATAL, "Out of memory in get_header_line()"); } assert(ret != NULL); iob->cur = p+1; if ((q = strchr(ret, '\r')) != NULL) *q = '\0'; /* is this a blank line (i.e. the end of the header) ? */ if (*ret == '\0') { freez(ret); return NULL; } return ret; } /********************************************************************* * * Function : get_header_value * * Description : Get the value of a given header from a chained list * of header lines or return NULL if no such header is * present in the list. * * Parameters : * 1 : header_list = pointer to list * 2 : header_name = string with name of header to look for. * Trailing colon required, capitalization * doesn't matter. * * Returns : NULL if not found, else value of header * *********************************************************************/ char *get_header_value(const struct list *header_list, const char *header_name) { struct list_entry *cur_entry; char *ret = NULL; size_t length = 0; assert(header_list); assert(header_name); length = strlen(header_name); for (cur_entry = header_list->first; cur_entry ; cur_entry = cur_entry->next) { if (cur_entry->str) { if (!strncmpic(cur_entry->str, header_name, length)) { /* * Found: return pointer to start of value */ ret = cur_entry->str + length; while (*ret && privoxy_isspace(*ret)) ret++; return ret; } } } /* * Not found */ return NULL; } /********************************************************************* * * Function : scan_headers * * Description : Scans headers, applies tags and updates action bits. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK * *********************************************************************/ static jb_err scan_headers(struct client_state *csp) { struct list_entry *h; /* Header */ jb_err err = JB_ERR_OK; for (h = csp->headers->first; (err == JB_ERR_OK) && (h != NULL) ; h = h->next) { /* Header crunch()ed in previous run? -> ignore */ if (h->str == NULL) continue; log_error(LOG_LEVEL_HEADER, "scan: %s", h->str); err = header_tagger(csp, h->str); } return err; } /********************************************************************* * * Function : enforce_header_order * * Description : Enforces a given header order. * * Parameters : * 1 : headers = List of headers to order. * 2 : ordered_headers = List of ordered header names. * * Returns : N/A * *********************************************************************/ static void enforce_header_order(struct list *headers, const struct list *ordered_headers) { struct list_entry *sorted_header; struct list new_headers[1]; struct list_entry *header; init_list(new_headers); /* The request line is always the first "header" */ assert(NULL != headers->first->str); enlist(new_headers, headers->first->str); freez(headers->first->str) /* Enlist the specified headers in the given order */ for (sorted_header = ordered_headers->first; sorted_header != NULL; sorted_header = sorted_header->next) { const size_t sorted_header_length = strlen(sorted_header->str); for (header = headers->first; header != NULL; header = header->next) { /* Header enlisted in previous run? -> ignore */ if (header->str == NULL) continue; if (0 == strncmpic(sorted_header->str, header->str, sorted_header_length) && (header->str[sorted_header_length] == ':')) { log_error(LOG_LEVEL_HEADER, "Enlisting sorted header %s", header->str); if (JB_ERR_OK != enlist(new_headers, header->str)) { log_error(LOG_LEVEL_HEADER, "Failed to enlist %s", header->str); } freez(header->str); } } } /* Enlist the rest of the headers behind the ordered ones */ for (header = headers->first; header != NULL; header = header->next) { /* Header enlisted in previous run? -> ignore */ if (header->str == NULL) continue; log_error(LOG_LEVEL_HEADER, "Enlisting left-over header %s", header->str); if (JB_ERR_OK != enlist(new_headers, header->str)) { log_error(LOG_LEVEL_HEADER, "Failed to enlist %s", header->str); } freez(header->str); } list_remove_all(headers); list_duplicate(headers, new_headers); list_remove_all(new_headers); return; } /********************************************************************* * * Function : sed * * Description : add, delete or modify lines in the HTTP header streams. * On entry, it receives a linked list of headers space * that was allocated dynamically (both the list nodes * and the header contents). * * As a side effect it frees the space used by the original * header lines. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : filter_server_headers = Boolean to switch between * server and header filtering. * * Returns : JB_ERR_OK in case off success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err sed(struct client_state *csp, int filter_server_headers) { /* XXX: use more descriptive names. */ struct list_entry *p; const struct parsers *v; const add_header_func_ptr *f; jb_err err = JB_ERR_OK; if (filter_server_headers) { v = server_patterns; f = add_server_headers; } else { v = client_patterns; f = add_client_headers; } scan_headers(csp); while ((err == JB_ERR_OK) && (v->str != NULL)) { for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next) { /* Header crunch()ed in previous run? -> ignore */ if (p->str == NULL) continue; /* Does the current parser handle this header? */ if ((strncmpic(p->str, v->str, v->len) == 0) || (v->len == CHECK_EVERY_HEADER_REMAINING)) { err = v->parser(csp, &(p->str)); } } v++; } /* place additional headers on the csp->headers list */ while ((err == JB_ERR_OK) && (*f)) { err = (*f)(csp); f++; } if (!filter_server_headers && !list_is_empty(csp->config->ordered_client_headers)) { enforce_header_order(csp->headers, csp->config->ordered_client_headers); } return err; } /********************************************************************* * * Function : update_server_headers * * Description : Updates server headers after the body has been modified. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK in case off success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err update_server_headers(struct client_state *csp) { jb_err err = JB_ERR_OK; static const struct parsers server_patterns_light[] = { { "Content-Length:", 15, server_adjust_content_length }, { "Transfer-Encoding:", 18, server_transfer_coding }, #ifdef FEATURE_ZLIB { "Content-Encoding:", 17, server_adjust_content_encoding }, #endif /* def FEATURE_ZLIB */ { NULL, 0, NULL } }; if (strncmpic(csp->http->cmd, "HEAD", 4)) { const struct parsers *v; struct list_entry *p; for (v = server_patterns_light; (err == JB_ERR_OK) && (v->str != NULL); v++) { for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next) { /* Header crunch()ed in previous run? -> ignore */ if (p->str == NULL) continue; /* Does the current parser handle this header? */ if (strncmpic(p->str, v->str, v->len) == 0) { err = v->parser(csp, (char **)&(p->str)); } } } } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((JB_ERR_OK == err) && (csp->flags & CSP_FLAG_MODIFIED) && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET)) { char header[50]; create_content_length_header(csp->content_length, header, sizeof(header)); err = enlist(csp->headers, header); if (JB_ERR_OK == err) { log_error(LOG_LEVEL_HEADER, "Content modified with no Content-Length header set. " "Created: %s.", header); csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; } } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_COMPRESSION if ((JB_ERR_OK == err) && (csp->flags & CSP_FLAG_BUFFERED_CONTENT_DEFLATED)) { err = enlist_unique_header(csp->headers, "Content-Encoding", "deflate"); if (JB_ERR_OK == err) { log_error(LOG_LEVEL_HEADER, "Added header: Content-Encoding: deflate"); } } #endif return err; } /********************************************************************* * * Function : header_tagger * * Description : Executes all text substitutions from applying * tag actions and saves the result as tag. * * XXX: Shares enough code with filter_header() and * pcrs_filter_response() to warrant some helper functions. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = Header that is used as tagger input * * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ static jb_err header_tagger(struct client_state *csp, char *header) { int wanted_filter_type; int multi_action_index; int i; pcrs_job *job; struct file_list *fl; struct re_filterfile_spec *b; struct list_entry *tag_name; const size_t header_length = strlen(header); if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) { wanted_filter_type = FT_SERVER_HEADER_TAGGER; multi_action_index = ACTION_MULTI_SERVER_HEADER_TAGGER; } else { wanted_filter_type = FT_CLIENT_HEADER_TAGGER; multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER; } if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "tagging enabled, but no taggers available."); return JB_ERR_OK; } for (i = 0; i < MAX_AF_FILES; i++) { fl = csp->rlist[i]; if ((NULL == fl) || (NULL == fl->f)) { /* * Either there are no filter files * left, or this filter file just * contains no valid filters. * * Continue to be sure we don't miss * valid filter files that are chained * after empty or invalid ones. */ continue; } /* For all filters, */ for (b = fl->f; b; b = b->next) { if (b->type != wanted_filter_type) { /* skip the ones we don't care about, */ continue; } /* leaving only taggers that could apply, of which we use the ones, */ for (tag_name = csp->action->multi[multi_action_index]->first; NULL != tag_name; tag_name = tag_name->next) { /* that do apply, and */ if (strcmp(b->name, tag_name->str) == 0) { char *modified_tag = NULL; char *tag = header; size_t size = header_length; pcrs_job *joblist = b->joblist; if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b); if (NULL == joblist) { log_error(LOG_LEVEL_RE_FILTER, "Tagger %s has empty joblist. Nothing to do.", b->name); continue; } /* execute their pcrs_joblist on the header. */ for (job = joblist; NULL != job; job = job->next) { const int hits = pcrs_execute(job, tag, size, &modified_tag, &size); if (0 < hits) { /* Success, continue with the modified version. */ if (tag != header) { freez(tag); } tag = modified_tag; } else { /* Tagger doesn't match */ if (0 > hits) { /* Regex failure, log it but continue anyway. */ assert(NULL != header); log_error(LOG_LEVEL_ERROR, "Problems with tagger \'%s\' and header \'%s\': %s", b->name, *header, pcrs_strerror(hits)); } freez(modified_tag); } } if (b->dynamic) pcrs_free_joblist(joblist); /* If this tagger matched */ if (tag != header) { if (0 == size) { /* * There is to technical limitation which makes * it impossible to use empty tags, but I assume * no one would do it intentionally. */ freez(tag); log_error(LOG_LEVEL_INFO, "Tagger \'%s\' created an empty tag. Ignored.", b->name); continue; } if (!list_contains_item(csp->tags, tag)) { if (JB_ERR_OK != enlist(csp->tags, tag)) { log_error(LOG_LEVEL_ERROR, "Insufficient memory to add tag \'%s\', " "based on tagger \'%s\' and header \'%s\'", tag, b->name, *header); } else { char *action_message; /* * update the action bits right away, to make * tagging based on tags set by earlier taggers * of the same kind possible. */ if (update_action_bits_for_tag(csp, tag)) { action_message = "Action bits updated accordingly."; } else { action_message = "No action bits update necessary."; } log_error(LOG_LEVEL_HEADER, "Tagger \'%s\' added tag \'%s\'. %s", b->name, tag, action_message); } } else { /* XXX: Is this log-worthy? */ log_error(LOG_LEVEL_HEADER, "Tagger \'%s\' didn't add tag \'%s\'. " "Tag already present", b->name, tag); } freez(tag); } /* if the tagger matched */ } /* if the tagger applies */ } /* for every tagger that could apply */ } /* for all filters */ } /* for all filter files */ return JB_ERR_OK; } /* here begins the family of parser functions that reformat header lines */ /********************************************************************* * * Function : filter_header * * Description : Executes all text substitutions from all applying * +(server|client)-header-filter actions on the header. * Most of the code was copied from pcrs_filter_response, * including the rather short variable names * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ static jb_err filter_header(struct client_state *csp, char **header) { int hits=0; int matches; size_t size = strlen(*header); char *newheader = NULL; pcrs_job *job; struct file_list *fl; struct re_filterfile_spec *b; struct list_entry *filtername; int i; int wanted_filter_type; int multi_action_index; if (csp->flags & CSP_FLAG_NO_FILTERING) { return JB_ERR_OK; } if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) { wanted_filter_type = FT_SERVER_HEADER_FILTER; multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER; } else { wanted_filter_type = FT_CLIENT_HEADER_FILTER; multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; } if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "header filtering enabled, but no matching filters available."); return JB_ERR_OK; } for (i = 0; i < MAX_AF_FILES; i++) { fl = csp->rlist[i]; if ((NULL == fl) || (NULL == fl->f)) { /* * Either there are no filter files * left, or this filter file just * contains no valid filters. * * Continue to be sure we don't miss * valid filter files that are chained * after empty or invalid ones. */ continue; } /* * For all applying +filter actions, look if a filter by that * name exists and if yes, execute its pcrs_joblist on the * buffer. */ for (b = fl->f; b; b = b->next) { if (b->type != wanted_filter_type) { /* Skip other filter types */ continue; } for (filtername = csp->action->multi[multi_action_index]->first; filtername ; filtername = filtername->next) { if (strcmp(b->name, filtername->str) == 0) { int current_hits = 0; pcrs_job *joblist = b->joblist; if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b); if (NULL == joblist) { log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name); continue; } log_error(LOG_LEVEL_RE_FILTER, "filtering \'%s\' (size %d) with \'%s\' ...", *header, size, b->name); /* Apply all jobs from the joblist */ for (job = joblist; NULL != job; job = job->next) { matches = pcrs_execute(job, *header, size, &newheader, &size); if (0 < matches) { current_hits += matches; log_error(LOG_LEVEL_HEADER, "Transforming \"%s\" to \"%s\"", *header, newheader); freez(*header); *header = newheader; } else if (0 == matches) { /* Filter doesn't change header */ freez(newheader); } else { /* RegEx failure */ log_error(LOG_LEVEL_ERROR, "Filtering \'%s\' with \'%s\' didn't work out: %s", *header, b->name, pcrs_strerror(matches)); if (newheader != NULL) { log_error(LOG_LEVEL_ERROR, "Freeing what's left: %s", newheader); freez(newheader); } } } if (b->dynamic) pcrs_free_joblist(joblist); log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size); hits += current_hits; } } } } /* * Additionally checking for hits is important because if * the continue hack is triggered, server headers can * arrive empty to separate multiple heads from each other. */ if ((0 == size) && hits) { log_error(LOG_LEVEL_HEADER, "Removing empty header %s", *header); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : server_connection * * Description : Makes sure a proper "Connection:" header is * set and signals connection_header_adder to * do nothing. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success. * *********************************************************************/ static jb_err server_connection(struct client_state *csp, char **header) { if (!strcmpic(*header, "Connection: keep-alive") #ifdef FEATURE_CONNECTION_KEEP_ALIVE && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) #endif ) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) { csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE; } if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)) { log_error(LOG_LEVEL_HEADER, "Keeping the server header '%s' around.", *header); } else #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ { char *old_header = *header; *header = strdup_or_die("Connection: close"); log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header); freez(old_header); } } /* Signal server_connection_adder() to return early. */ csp->flags |= CSP_FLAG_SERVER_CONNECTION_HEADER_SET; return JB_ERR_OK; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : server_keep_alive * * Description : Stores the server's keep alive timeout. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK. * *********************************************************************/ static jb_err server_keep_alive(struct client_state *csp, char **header) { unsigned int keep_alive_timeout; const char *timeout_position = strstr(*header, "timeout="); if ((NULL == timeout_position) || (1 != sscanf(timeout_position, "timeout=%u", &keep_alive_timeout))) { log_error(LOG_LEVEL_ERROR, "Couldn't parse: %s", *header); } else { if (keep_alive_timeout < csp->server_connection.keep_alive_timeout) { log_error(LOG_LEVEL_HEADER, "Reducing keep-alive timeout from %u to %u.", csp->server_connection.keep_alive_timeout, keep_alive_timeout); csp->server_connection.keep_alive_timeout = keep_alive_timeout; } else { /* XXX: Is this log worthy? */ log_error(LOG_LEVEL_HEADER, "Server keep-alive timeout is %u. Sticking with %u.", keep_alive_timeout, csp->server_connection.keep_alive_timeout); } csp->flags |= CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET; } return JB_ERR_OK; } /********************************************************************* * * Function : server_proxy_connection * * Description : Figures out whether or not we should add a * Proxy-Connection header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK. * *********************************************************************/ static jb_err server_proxy_connection(struct client_state *csp, char **header) { csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET; return JB_ERR_OK; } /********************************************************************* * * Function : proxy_authentication * * Description : Removes headers that are relevant for proxy * authentication unless forwarding them has * been explicitly requested. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK. * *********************************************************************/ static jb_err proxy_authentication(struct client_state *csp, char **header) { if ((csp->config->feature_flags & RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS) == 0) { log_error(LOG_LEVEL_HEADER, "Forwarding proxy authentication headers is disabled. Crunching: %s", *header); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : client_keep_alive * * Description : Stores the client's keep alive timeout. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK. * *********************************************************************/ static jb_err client_keep_alive(struct client_state *csp, char **header) { unsigned int keep_alive_timeout; const char *timeout_position = strstr(*header, ": "); if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) { log_error(LOG_LEVEL_HEADER, "keep-alive support is disabled. Crunching: %s.", *header); freez(*header); return JB_ERR_OK; } if ((NULL == timeout_position) || (1 != sscanf(timeout_position, ": %u", &keep_alive_timeout))) { log_error(LOG_LEVEL_ERROR, "Couldn't parse: %s", *header); } else { if (keep_alive_timeout < csp->config->keep_alive_timeout) { log_error(LOG_LEVEL_HEADER, "Reducing keep-alive timeout from %u to %u.", csp->config->keep_alive_timeout, keep_alive_timeout); csp->server_connection.keep_alive_timeout = keep_alive_timeout; } else { /* XXX: Is this log worthy? */ log_error(LOG_LEVEL_HEADER, "Client keep-alive timeout is %u. Sticking with %u.", keep_alive_timeout, csp->config->keep_alive_timeout); } } return JB_ERR_OK; } /********************************************************************* * * Function : get_content_length * * Description : Gets the content length specified in a * Content-Length header. * * Parameters : * 1 : header_value = The Content-Length header value. * 2 : length = Storage to return the value. * * Returns : JB_ERR_OK on success, or * JB_ERR_PARSE if no value is recognized. * *********************************************************************/ static jb_err get_content_length(const char *header_value, unsigned long long *length) { #ifdef _WIN32 assert(sizeof(unsigned long long) > 4); if (1 != sscanf(header_value, "%I64u", length)) #else if (1 != sscanf(header_value, "%llu", length)) #endif { return JB_ERR_PARSE; } return JB_ERR_OK; } /********************************************************************* * * Function : client_save_content_length * * Description : Save the Content-Length sent by the client. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_save_content_length(struct client_state *csp, char **header) { unsigned long long content_length = 0; const char *header_value; assert(*(*header+14) == ':'); header_value = *header + 15; if (JB_ERR_OK != get_content_length(header_value, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } else { csp->expected_client_content_length = content_length; } return JB_ERR_OK; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : client_connection * * Description : Makes sure a proper "Connection:" header is * set and signals connection_header_adder * to do nothing. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success. * *********************************************************************/ static jb_err client_connection(struct client_state *csp, char **header) { static const char connection_close[] = "Connection: close"; if (!strcmpic(*header, connection_close)) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { if (!strcmpic(csp->http->ver, "HTTP/1.1")) { log_error(LOG_LEVEL_HEADER, "Removing \'%s\' to imply keep-alive.", *header); freez(*header); /* * While we imply keep-alive to the server, * we have to remember that the client didn't. */ csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } else { char *old_header = *header; *header = strdup_or_die("Connection: keep-alive"); log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header); freez(old_header); } } else { log_error(LOG_LEVEL_HEADER, "Keeping the client header '%s' around. " "The connection will not be kept alive.", *header); csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } } else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_HEADER, "Keeping the client header '%s' around. " "The server connection will be kept alive if possible.", *header); csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ } else { char *old_header = *header; *header = strdup_or_die(connection_close); log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header); freez(old_header); } /* Signal client_connection_header_adder() to return early. */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET; return JB_ERR_OK; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : client_proxy_connection * * Description : Sets the CLIENT_CONNECTION_KEEP_ALIVE flag when * appropriate and removes the Proxy-Connection * header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK * *********************************************************************/ static jb_err client_proxy_connection(struct client_state *csp, char **header) { if (0 == (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && (csp->http->ssl == 0) && (NULL == strstr(*header, "close"))) { log_error(LOG_LEVEL_HEADER, "The client connection can be kept alive due to: %s", *header); csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } crumble(csp, header); return JB_ERR_OK; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : client_transfer_encoding * * Description : Raise the CSP_FLAG_CHUNKED_CLIENT_BODY flag if * the request body is "chunked" * * XXX: Currently not called through sed() as we * need the flag earlier on. Should be fixed. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * *********************************************************************/ jb_err client_transfer_encoding(struct client_state *csp, char **header) { if (strstr(*header, "chunked")) { csp->flags |= CSP_FLAG_CHUNKED_CLIENT_BODY; log_error(LOG_LEVEL_HEADER, "Expecting chunked client body"); } return JB_ERR_OK; } /********************************************************************* * * Function : crumble * * Description : This is called if a header matches a pattern to "crunch" * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err crumble(struct client_state *csp, char **header) { (void)csp; log_error(LOG_LEVEL_HEADER, "crumble crunched: %s!", *header); freez(*header); return JB_ERR_OK; } /********************************************************************* * * Function : crunch_server_header * * Description : Crunch server header if it matches a string supplied by the * user. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ static jb_err crunch_server_header(struct client_state *csp, char **header) { const char *crunch_pattern; /* Do we feel like crunching? */ if ((csp->action->flags & ACTION_CRUNCH_SERVER_HEADER)) { crunch_pattern = csp->action->string[ACTION_STRING_SERVER_HEADER]; /* Is the current header the lucky one? */ if (strstr(*header, crunch_pattern)) { log_error(LOG_LEVEL_HEADER, "Crunching server header: %s (contains: %s)", *header, crunch_pattern); freez(*header); } } return JB_ERR_OK; } /********************************************************************* * * Function : server_content_type * * Description : Set the content-type for filterable types (text/.*, * .*xml.*, .*script.* and image/gif) unless filtering has been * forbidden (CT_TABOO) while parsing earlier headers. * NOTE: Since text/plain is commonly used by web servers * for files whose correct type is unknown, we don't * set CT_TEXT for it. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_content_type(struct client_state *csp, char **header) { /* Remove header if it isn't the first Content-Type header */ if ((csp->content_type & CT_DECLARED)) { if (content_filters_enabled(csp->action)) { /* * Making sure the client interprets the content the same way * Privoxy did is only relevant if Privoxy modified it. * * Checking for this is "hard" as it's not yet known when * this function is called, thus go shopping and and just * check if Privoxy could filter it. * * The main thing is that we don't mess with the headers * unless the user signalled that it's acceptable. */ log_error(LOG_LEVEL_HEADER, "Multiple Content-Type headers detected. " "Removing and ignoring: %s", *header); freez(*header); } return JB_ERR_OK; } /* * Signal that the Content-Type has been set. */ csp->content_type |= CT_DECLARED; if (!(csp->content_type & CT_TABOO)) { /* * XXX: The assumption that text/plain is a sign of * binary data seems to be somewhat unreasonable nowadays * and should be dropped after 3.0.8 is out. */ if ((strstr(*header, "text/") && !strstr(*header, "plain")) || strstr(*header, "xml") || strstr(*header, "script")) { csp->content_type |= CT_TEXT; } else if (strstr(*header, "image/gif")) { csp->content_type |= CT_GIF; } } /* * Are we messing with the content type? */ if (csp->action->flags & ACTION_CONTENT_TYPE_OVERWRITE) { /* * Make sure the user doesn't accidentally * change the content type of binary documents. */ if ((csp->content_type & CT_TEXT) || (csp->action->flags & ACTION_FORCE_TEXT_MODE)) { freez(*header); *header = strdup_or_die("Content-Type: "); string_append(header, csp->action->string[ACTION_STRING_CONTENT_TYPE]); if (header == NULL) { log_error(LOG_LEVEL_HEADER, "Insufficient memory to replace Content-Type!"); return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "Modified: %s!", *header); } else { log_error(LOG_LEVEL_HEADER, "%s not replaced. " "It doesn't look like a content type that should be filtered. " "Enable force-text-mode if you know what you're doing.", *header); } } return JB_ERR_OK; } /********************************************************************* * * Function : server_transfer_coding * * Description : - Prohibit filtering (CT_TABOO) if transfer coding compresses * - Raise the CSP_FLAG_CHUNKED flag if coding is "chunked" * - Remove header if body was chunked but has been * de-chunked for filtering. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_transfer_coding(struct client_state *csp, char **header) { /* * Turn off pcrs and gif filtering if body compressed */ if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate")) { #ifdef FEATURE_ZLIB /* * XXX: Added to test if we could use CT_GZIP and CT_DEFLATE here. */ log_error(LOG_LEVEL_INFO, "Marking content type for %s as CT_TABOO because of %s.", csp->http->cmd, *header); #endif /* def FEATURE_ZLIB */ csp->content_type = CT_TABOO; } /* * Raise flag if body chunked */ if (strstr(*header, "chunked")) { csp->flags |= CSP_FLAG_CHUNKED; /* * If the body was modified, it has been de-chunked first * and the header must be removed. * * FIXME: If there is more than one transfer encoding, * only the "chunked" part should be removed here. */ if (csp->flags & CSP_FLAG_MODIFIED) { log_error(LOG_LEVEL_HEADER, "Removing: %s", *header); freez(*header); } } return JB_ERR_OK; } /********************************************************************* * * Function : server_content_encoding * * Description : Used to check if the content is compressed, and if * FEATURE_ZLIB is disabled, filtering is disabled as * well. * * If FEATURE_ZLIB is enabled and the compression type * supported, the content is marked for decompression. * * XXX: Doesn't properly deal with multiple or with * unsupported but unknown encodings. * Is case-sensitive but shouldn't be. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_content_encoding(struct client_state *csp, char **header) { #ifdef FEATURE_ZLIB if (strstr(*header, "sdch")) { /* * Shared Dictionary Compression over HTTP isn't supported, * filtering it anyway is pretty much guaranteed to mess up * the encoding. */ csp->content_type |= CT_TABOO; /* * Log a warning if the user expects the content to be filtered. */ if ((csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) { log_error(LOG_LEVEL_INFO, "SDCH-compressed content detected, content filtering disabled. " "Consider suppressing SDCH offers made by the client."); } } else if (strstr(*header, "gzip")) { /* Mark for gzip decompression */ csp->content_type |= CT_GZIP; } else if (strstr(*header, "deflate")) { /* Mark for zlib decompression */ csp->content_type |= CT_DEFLATE; } else if (strstr(*header, "compress")) { /* * We can't decompress this; therefore we can't filter * it either. */ csp->content_type |= CT_TABOO; } #else /* !defined(FEATURE_ZLIB) */ /* * XXX: Using a black list here isn't the right approach. * * In case of SDCH, building with zlib support isn't * going to help. */ if (strstr(*header, "gzip") || strstr(*header, "compress") || strstr(*header, "deflate") || strstr(*header, "sdch")) { /* * Body is compressed, turn off pcrs and gif filtering. */ csp->content_type |= CT_TABOO; /* * Log a warning if the user expects the content to be filtered. */ if ((csp->rlist != NULL) && (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) { log_error(LOG_LEVEL_INFO, "Compressed content detected, content filtering disabled. " "Consider recompiling Privoxy with zlib support or " "enable the prevent-compression action."); } } #endif /* defined(FEATURE_ZLIB) */ return JB_ERR_OK; } #ifdef FEATURE_ZLIB /********************************************************************* * * Function : server_adjust_content_encoding * * Description : Remove the Content-Encoding header if the * decompression was successful and the content * has been modifed. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_adjust_content_encoding(struct client_state *csp, char **header) { if ((csp->flags & CSP_FLAG_MODIFIED) && (csp->content_type & (CT_GZIP | CT_DEFLATE))) { /* * We successfully decompressed the content, * and have to clean the header now, so the * client no longer expects compressed data. * * XXX: There is a difference between cleaning * and removing it completely. */ log_error(LOG_LEVEL_HEADER, "Crunching: %s", *header); freez(*header); } return JB_ERR_OK; } #endif /* defined(FEATURE_ZLIB) */ /********************************************************************* * * Function : server_adjust_content_length * * Description : Adjust Content-Length header if we modified * the body. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_adjust_content_length(struct client_state *csp, char **header) { /* Regenerate header if the content was modified. */ if (csp->flags & CSP_FLAG_MODIFIED) { const size_t header_length = 50; freez(*header); *header = malloc(header_length); if (*header == NULL) { return JB_ERR_MEMORY; } create_content_length_header(csp->content_length, *header, header_length); log_error(LOG_LEVEL_HEADER, "Adjusted Content-Length to %llu", csp->content_length); } return JB_ERR_OK; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : server_save_content_length * * Description : Save the Content-Length sent by the server. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_save_content_length(struct client_state *csp, char **header) { unsigned long long content_length = 0; const char *header_value; assert(*(*header+14) == ':'); header_value = *header + 15; if (JB_ERR_OK != get_content_length(header_value, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } else { csp->expected_content_length = content_length; csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; } return JB_ERR_OK; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : server_content_md5 * * Description : Crumble any Content-MD5 headers if the document was * modified. FIXME: Should we re-compute instead? * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_content_md5(struct client_state *csp, char **header) { if (csp->flags & CSP_FLAG_MODIFIED) { log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5"); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : server_content_disposition * * Description : If enabled, blocks or modifies the "Content-Disposition" header. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_content_disposition(struct client_state *csp, char **header) { const char *newval; /* * Are we messing with the Content-Disposition header? */ if ((csp->action->flags & ACTION_HIDE_CONTENT_DISPOSITION) == 0) { /* Me tinks not */ return JB_ERR_OK; } newval = csp->action->string[ACTION_STRING_CONTENT_DISPOSITION]; if ((newval == NULL) || (0 == strcmpic(newval, "block"))) { /* * Blocking content-disposition header */ log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header); freez(*header); return JB_ERR_OK; } else { /* * Replacing Content-Disposition header */ freez(*header); *header = strdup("Content-Disposition: "); string_append(header, newval); if (*header != NULL) { log_error(LOG_LEVEL_HEADER, "Content-Disposition header crunched and replaced with: %s", *header); } } return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } /********************************************************************* * * Function : server_last_modified * * Description : Changes Last-Modified header to the actual date * to help hide-if-modified-since. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_last_modified(struct client_state *csp, char **header) { const char *newval; time_t last_modified; char newheader[50]; /* * Are we messing with the Last-Modified header? */ if ((csp->action->flags & ACTION_OVERWRITE_LAST_MODIFIED) == 0) { /*Nope*/ return JB_ERR_OK; } newval = csp->action->string[ACTION_STRING_LAST_MODIFIED]; if (0 == strcmpic(newval, "block")) { /* * Blocking Last-Modified header. Useless but why not. */ log_error(LOG_LEVEL_HEADER, "Crunching %s!", *header); freez(*header); return JB_ERR_OK; } else if (0 == strcmpic(newval, "reset-to-request-time")) { /* * Setting Last-Modified Header to now. */ char buf[30]; get_http_time(0, buf, sizeof(buf)); freez(*header); *header = strdup("Last-Modified: "); string_append(header, buf); if (*header == NULL) { log_error(LOG_LEVEL_HEADER, "Insufficient memory. Last-Modified header got lost, boohoo."); } else { log_error(LOG_LEVEL_HEADER, "Reset to present time: %s", *header); } } else if (0 == strcmpic(newval, "randomize")) { const char *header_time = *header + sizeof("Last-Modified:"); log_error(LOG_LEVEL_HEADER, "Randomizing: %s", *header); if (JB_ERR_OK != parse_header_time(header_time, &last_modified)) { log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header); freez(*header); } else { time_t now; struct tm *timeptr = NULL; long int rtime; #ifdef HAVE_GMTIME_R struct tm gmt; #endif now = time(NULL); rtime = (long int)difftime(now, last_modified); if (rtime) { long int days, hours, minutes, seconds; const int negative_delta = (rtime < 0); if (negative_delta) { rtime *= -1; log_error(LOG_LEVEL_HEADER, "Server time in the future."); } rtime = pick_from_range(rtime); if (negative_delta) { rtime *= -1; } last_modified += rtime; #ifdef HAVE_GMTIME_R timeptr = gmtime_r(&last_modified, &gmt); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&last_modified); privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&last_modified); #endif if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } freez(*header); *header = strdup("Last-Modified: "); string_append(header, newheader); if (*header == NULL) { log_error(LOG_LEVEL_ERROR, "Insufficient memory, header crunched without replacement."); return JB_ERR_MEMORY; } days = rtime / (3600 * 24); hours = rtime / 3600 % 24; minutes = rtime / 60 % 60; seconds = rtime % 60; log_error(LOG_LEVEL_HEADER, "Randomized: %s (added %d da%s %d hou%s %d minut%s %d second%s", *header, days, (days == 1) ? "y" : "ys", hours, (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)"); } else { log_error(LOG_LEVEL_HEADER, "Randomized ... or not. No time difference to work with."); } } } return JB_ERR_OK; } /********************************************************************* * * Function : client_accept_encoding * * Description : Rewrite the client's Accept-Encoding header so that * if doesn't allow compression, if the action applies. * Note: For HTTP/1.0 the absence of the header is enough. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_accept_encoding(struct client_state *csp, char **header) { #ifdef FEATURE_COMPRESSION if ((csp->config->feature_flags & RUNTIME_FEATURE_COMPRESSION) && strstr(*header, "deflate")) { csp->flags |= CSP_FLAG_CLIENT_SUPPORTS_DEFLATE; } #endif if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content"); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : client_te * * Description : Rewrite the client's TE header so that * if doesn't allow compression, if the action applies. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_te(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_NO_COMPRESSION) != 0) { freez(*header); log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress transfer"); } return JB_ERR_OK; } /********************************************************************* * * Function : client_referrer * * Description : Handle the "referer" config setting properly. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_referrer(struct client_state *csp, char **header) { const char *parameter; /* booleans for parameters we have to check multiple times */ int parameter_conditional_block; int parameter_conditional_forge; #ifdef FEATURE_FORCE_LOAD /* * Since the referrer can include the prefix even * if the request itself is non-forced, we must * clean it unconditionally. * * XXX: strclean is too broad */ strclean(*header, FORCE_PREFIX); #endif /* def FEATURE_FORCE_LOAD */ if ((csp->action->flags & ACTION_HIDE_REFERER) == 0) { /* Nothing left to do */ return JB_ERR_OK; } parameter = csp->action->string[ACTION_STRING_REFERER]; assert(parameter != NULL); parameter_conditional_block = (0 == strcmpic(parameter, "conditional-block")); parameter_conditional_forge = (0 == strcmpic(parameter, "conditional-forge")); if (!parameter_conditional_block && !parameter_conditional_forge) { /* * As conditional-block and conditional-forge are the only * parameters that rely on the original referrer, we can * remove it now for all the others. */ freez(*header); } if (0 == strcmpic(parameter, "block")) { log_error(LOG_LEVEL_HEADER, "Referer crunched!"); return JB_ERR_OK; } else if (parameter_conditional_block || parameter_conditional_forge) { return handle_conditional_hide_referrer_parameter(header, csp->http->hostport, parameter_conditional_block); } else if (0 == strcmpic(parameter, "forge")) { return create_forged_referrer(header, csp->http->hostport); } else { /* interpret parameter as user-supplied referer to fake */ return create_fake_referrer(header, parameter); } } /********************************************************************* * * Function : client_accept_language * * Description : Handle the "Accept-Language" config setting properly. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_accept_language(struct client_state *csp, char **header) { const char *newval; /* * Are we messing with the Accept-Language? */ if ((csp->action->flags & ACTION_HIDE_ACCEPT_LANGUAGE) == 0) { /*I don't think so*/ return JB_ERR_OK; } newval = csp->action->string[ACTION_STRING_LANGUAGE]; if ((newval == NULL) || (0 == strcmpic(newval, "block"))) { /* * Blocking Accept-Language header */ log_error(LOG_LEVEL_HEADER, "Crunching Accept-Language!"); freez(*header); return JB_ERR_OK; } else { /* * Replacing Accept-Language header */ freez(*header); *header = strdup("Accept-Language: "); string_append(header, newval); if (*header == NULL) { log_error(LOG_LEVEL_ERROR, "Insufficient memory. Accept-Language header crunched without replacement."); } else { log_error(LOG_LEVEL_HEADER, "Accept-Language header crunched and replaced with: %s", *header); } } return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } /********************************************************************* * * Function : crunch_client_header * * Description : Crunch client header if it matches a string supplied by the * user. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success and always succeeds * *********************************************************************/ static jb_err crunch_client_header(struct client_state *csp, char **header) { const char *crunch_pattern; /* Do we feel like crunching? */ if ((csp->action->flags & ACTION_CRUNCH_CLIENT_HEADER)) { crunch_pattern = csp->action->string[ACTION_STRING_CLIENT_HEADER]; /* Is the current header the lucky one? */ if (strstr(*header, crunch_pattern)) { log_error(LOG_LEVEL_HEADER, "Crunching client header: %s (contains: %s)", *header, crunch_pattern); freez(*header); } } return JB_ERR_OK; } /********************************************************************* * * Function : client_uagent * * Description : Handle the "user-agent" config setting properly * and remember its original value to enable browser * bug workarounds. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_uagent(struct client_state *csp, char **header) { const char *newval; if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0) { return JB_ERR_OK; } newval = csp->action->string[ACTION_STRING_USER_AGENT]; if (newval == NULL) { return JB_ERR_OK; } freez(*header); *header = strdup("User-Agent: "); string_append(header, newval); log_error(LOG_LEVEL_HEADER, "Modified: %s", *header); return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } /********************************************************************* * * Function : client_ua * * Description : Handle "ua-" headers properly. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_ua(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0) { log_error(LOG_LEVEL_HEADER, "crunched User-Agent!"); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : client_from * * Description : Handle the "from" config setting properly. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_from(struct client_state *csp, char **header) { const char *newval; if ((csp->action->flags & ACTION_HIDE_FROM) == 0) { return JB_ERR_OK; } freez(*header); newval = csp->action->string[ACTION_STRING_FROM]; /* * Are we blocking the e-mail address? */ if ((newval == NULL) || (0 == strcmpic(newval, "block"))) { log_error(LOG_LEVEL_HEADER, "crunched From!"); return JB_ERR_OK; } log_error(LOG_LEVEL_HEADER, " modified"); *header = strdup("From: "); string_append(header, newval); return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK; } /********************************************************************* * * Function : client_send_cookie * * Description : Crunches the "cookie" header if necessary. * Called from `sed'. * * XXX: Stupid name, doesn't send squat. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_send_cookie(struct client_state *csp, char **header) { if (csp->action->flags & ACTION_CRUNCH_OUTGOING_COOKIES) { log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie: %s", *header); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : client_x_forwarded * * Description : Handle the "x-forwarded-for" config setting properly, * also used in the add_client_headers list. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err client_x_forwarded(struct client_state *csp, char **header) { if (0 != (csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR)) { const char *parameter = csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR]; if (0 == strcmpic(parameter, "block")) { freez(*header); log_error(LOG_LEVEL_HEADER, "crunched x-forwarded-for!"); } else if (0 == strcmpic(parameter, "add")) { string_append(header, ", "); string_append(header, csp->ip_addr_str); if (*header == NULL) { return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "Appended client IP address to %s", *header); csp->flags |= CSP_FLAG_X_FORWARDED_FOR_APPENDED; } else { log_error(LOG_LEVEL_FATAL, "Invalid change-x-forwarded-for parameter: '%s'", parameter); } } return JB_ERR_OK; } /********************************************************************* * * Function : client_max_forwards * * Description : If the HTTP method is OPTIONS or TRACE, subtract one * from the value of the Max-Forwards header field. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_max_forwards(struct client_state *csp, char **header) { int max_forwards; if ((0 == strcmpic(csp->http->gpc, "trace")) || (0 == strcmpic(csp->http->gpc, "options"))) { assert(*(*header+12) == ':'); if (1 == sscanf(*header+12, ": %d", &max_forwards)) { if (max_forwards > 0) { snprintf(*header, strlen(*header)+1, "Max-Forwards: %d", --max_forwards); log_error(LOG_LEVEL_HEADER, "Max-Forwards value for %s request reduced to %d.", csp->http->gpc, max_forwards); } else if (max_forwards < 0) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } } else { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); } } return JB_ERR_OK; } /********************************************************************* * * Function : client_host * * Description : If the request URI did not contain host and * port information, parse and evaluate the Host * header field. * * Also, kill ill-formed HOST: headers as sent by * Apple's iTunes software when used with a proxy. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_host(struct client_state *csp, char **header) { char *p, *q; /* * If the header field name is all upper-case, chances are that it's * an ill-formed one from iTunes. BTW, killing innocent headers here is * not a problem -- they are regenerated later. */ if ((*header)[1] == 'O') { log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header); freez(*header); return JB_ERR_OK; } if (!csp->http->hostport || (*csp->http->hostport == '*') || *csp->http->hostport == ' ' || *csp->http->hostport == '\0') { p = strdup_or_die((*header)+6); chomp(p); q = strdup_or_die(p); freez(csp->http->hostport); csp->http->hostport = p; freez(csp->http->host); csp->http->host = q; q = strchr(csp->http->host, ':'); if (q != NULL) { /* Terminate hostname and evaluate port string */ *q++ = '\0'; csp->http->port = atoi(q); } else { csp->http->port = csp->http->ssl ? 443 : 80; } log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d", csp->http->hostport, csp->http->host, csp->http->port); } /* Signal client_host_adder() to return right away */ csp->flags |= CSP_FLAG_HOST_HEADER_IS_SET; return JB_ERR_OK; } /********************************************************************* * * Function : client_if_modified_since * * Description : Remove or modify the If-Modified-Since header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_if_modified_since(struct client_state *csp, char **header) { char newheader[50]; #ifdef HAVE_GMTIME_R struct tm gmt; #endif struct tm *timeptr = NULL; time_t tm = 0; const char *newval; char * endptr; if (0 == strcmpic(*header, "If-Modified-Since: Wed, 08 Jun 1955 12:00:00 GMT")) { /* * The client got an error message because of a temporary problem, * the problem is gone and the client now tries to revalidate our * error message on the real server. The revalidation would always * end with the transmission of the whole document and there is * no need to expose the bogus If-Modified-Since header. */ log_error(LOG_LEVEL_HEADER, "Crunching useless If-Modified-Since header."); freez(*header); } else if (csp->action->flags & ACTION_HIDE_IF_MODIFIED_SINCE) { newval = csp->action->string[ACTION_STRING_IF_MODIFIED_SINCE]; if ((0 == strcmpic(newval, "block"))) { log_error(LOG_LEVEL_HEADER, "Crunching %s", *header); freez(*header); } else /* add random value */ { const char *header_time = *header + sizeof("If-Modified-Since:"); if (JB_ERR_OK != parse_header_time(header_time, &tm)) { log_error(LOG_LEVEL_HEADER, "Couldn't parse: %s in %s (crunching!)", header_time, *header); freez(*header); } else { long int hours, minutes, seconds; long int rtime = strtol(newval, &endptr, 0); const int negative_range = (rtime < 0); if (rtime) { log_error(LOG_LEVEL_HEADER, "Randomizing: %s (random range: %d minut%s)", *header, rtime, (rtime == 1 || rtime == -1) ? "e": "es"); if (negative_range) { rtime *= -1; } rtime *= 60; rtime = pick_from_range(rtime); } else { log_error(LOG_LEVEL_ERROR, "Random range is 0. Assuming time transformation test.", *header); } tm += rtime * (negative_range ? -1 : 1); #ifdef HAVE_GMTIME_R timeptr = gmtime_r(&tm, &gmt); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&tm); privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&tm); #endif if ((NULL == timeptr) || !strftime(newheader, sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr)) { log_error(LOG_LEVEL_ERROR, "Randomizing '%s' failed. Crunching the header without replacement.", *header); freez(*header); return JB_ERR_OK; } freez(*header); *header = strdup("If-Modified-Since: "); string_append(header, newheader); if (*header == NULL) { log_error(LOG_LEVEL_HEADER, "Insufficient memory, header crunched without replacement."); return JB_ERR_MEMORY; } hours = rtime / 3600; minutes = rtime / 60 % 60; seconds = rtime % 60; log_error(LOG_LEVEL_HEADER, "Randomized: %s (%s %d hou%s %d minut%s %d second%s", *header, (negative_range) ? "subtracted" : "added", hours, (hours == 1) ? "r" : "rs", minutes, (minutes == 1) ? "e" : "es", seconds, (seconds == 1) ? ")" : "s)"); } } } return JB_ERR_OK; } /********************************************************************* * * Function : client_if_none_match * * Description : Remove the If-None-Match header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_if_none_match(struct client_state *csp, char **header) { if (csp->action->flags & ACTION_CRUNCH_IF_NONE_MATCH) { log_error(LOG_LEVEL_HEADER, "Crunching %s", *header); freez(*header); } return JB_ERR_OK; } /********************************************************************* * * Function : client_x_filter * * Description : Disables filtering if the client set "X-Filter: No". * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success * *********************************************************************/ jb_err client_x_filter(struct client_state *csp, char **header) { if (0 == strcmpic(*header, "X-Filter: No")) { if (!(csp->config->feature_flags & RUNTIME_FEATURE_HTTP_TOGGLE)) { log_error(LOG_LEVEL_INFO, "Ignored the client's request to fetch without filtering."); } else { if (csp->action->flags & ACTION_FORCE_TEXT_MODE) { log_error(LOG_LEVEL_HEADER, "force-text-mode overruled the client's request to fetch without filtering!"); } else { csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */ csp->flags |= CSP_FLAG_NO_FILTERING; log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering."); } log_error(LOG_LEVEL_HEADER, "Crunching %s", *header); freez(*header); } } return JB_ERR_OK; } /********************************************************************* * * Function : client_range * * Description : Removes Range, Request-Range and If-Range headers if * content filtering is enabled and the range doesn't * start at byte 0. * * If the client's version of the document has been * altered by Privoxy, the server could interpret the * range differently than the client intended in which * case the user could end up with corrupted content. * * If the range starts at byte 0 this isn't an issue * so the header can pass. Partial requests like this * are used to render preview images for videos without * downloading the whole video. * * While HTTP doesn't require that range requests are * honoured and the client could simply abort the download * after receiving a sufficient amount of data, various * clients don't handle complete responses to range * requests gracefully and emit misleading error messages * instead. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK * *********************************************************************/ static jb_err client_range(struct client_state *csp, char **header) { if (content_filters_enabled(csp->action) && (0 != strncmpic(strstr(*header, ":"), ": bytes=0-", 10))) { log_error(LOG_LEVEL_HEADER, "Content filtering is enabled." " Crunching: \'%s\' to prevent range-mismatch problems.", *header); freez(*header); } return JB_ERR_OK; } /* the following functions add headers directly to the header list */ /********************************************************************* * * Function : client_host_adder * * Description : Adds the Host: header field if it is missing. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_host_adder(struct client_state *csp) { char *p; jb_err err; if (csp->flags & CSP_FLAG_HOST_HEADER_IS_SET) { /* Header already set by the client, nothing to do. */ return JB_ERR_OK; } if (!csp->http->hostport || !*(csp->http->hostport)) { /* XXX: When does this happen and why is it OK? */ log_error(LOG_LEVEL_INFO, "Weirdness in client_host_adder detected and ignored."); return JB_ERR_OK; } /* * remove 'user:pass@' from 'proto://user:pass@host' */ if ((p = strchr( csp->http->hostport, '@')) != NULL) { p++; } else { p = csp->http->hostport; } /* XXX: Just add it, we already made sure that it will be unique */ log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p); err = enlist_unique_header(csp->headers, "Host", p); return err; } /********************************************************************* * * Function : client_xtra_adder * * Description : Used in the add_client_headers list. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_xtra_adder(struct client_state *csp) { struct list_entry *lst; jb_err err; for (lst = csp->action->multi[ACTION_MULTI_ADD_HEADER]->first; lst ; lst = lst->next) { log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str); err = enlist(csp->headers, lst->str); if (err) { return err; } } return JB_ERR_OK; } /********************************************************************* * * Function : client_x_forwarded_for_adder * * Description : Used in the add_client_headers list. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_x_forwarded_for_adder(struct client_state *csp) { char *header = NULL; jb_err err; if (!((csp->action->flags & ACTION_CHANGE_X_FORWARDED_FOR) && (0 == strcmpic(csp->action->string[ACTION_STRING_CHANGE_X_FORWARDED_FOR], "add"))) || (csp->flags & CSP_FLAG_X_FORWARDED_FOR_APPENDED)) { /* * If we aren't adding X-Forwarded-For headers, * or we already appended an existing X-Forwarded-For * header, there's nothing left to do here. */ return JB_ERR_OK; } header = strdup("X-Forwarded-For: "); string_append(&header, csp->ip_addr_str); if (header == NULL) { return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "addh: %s", header); err = enlist(csp->headers, header); freez(header); return err; } /********************************************************************* * * Function : server_connection_adder * * Description : Adds an appropriate "Connection:" header to csp->headers * unless the header was already present. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_connection_adder(struct client_state *csp) { const unsigned int flags = csp->flags; const char *response_status_line = csp->headers->first->str; static const char connection_close[] = "Connection: close"; if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) && (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET)) { return JB_ERR_OK; } /* * XXX: if we downgraded the response, this check will fail. */ if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && (NULL != response_status_line) && !strncmpic(response_status_line, "HTTP/1.1", 8) #ifdef FEATURE_CONNECTION_KEEP_ALIVE && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) #endif ) { log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response " "without Connection header implies keep-alive."); csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE; return JB_ERR_OK; } log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close); return enlist(csp->headers, connection_close); } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : server_proxy_connection_adder * * Description : Adds a "Proxy-Connection: keep-alive" header to * csp->headers when appropriate. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_proxy_connection_adder(struct client_state *csp) { static const char proxy_connection_header[] = "Proxy-Connection: keep-alive"; jb_err err = JB_ERR_OK; if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET) && ((csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET) || (csp->flags & CSP_FLAG_CHUNKED))) { log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header); err = enlist(csp->headers, proxy_connection_header); } return err; } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : client_connection_header_adder * * Description : Adds a proper "Connection:" header to csp->headers * unless the header was already present. Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err client_connection_header_adder(struct client_state *csp) { static const char connection_close[] = "Connection: close"; if (!(csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET)) { return JB_ERR_OK; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && (csp->http->ssl == 0) && !strcmpic(csp->http->ver, "HTTP/1.1")) { csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; return JB_ERR_OK; } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close); return enlist(csp->headers, connection_close); } /********************************************************************* * * Function : server_http * * Description : - Save the HTTP Status into csp->http->status * - Set CT_TABOO to prevent filtering if the answer * is a partial range (HTTP status 206) * - Rewrite HTTP/1.1 answers to HTTP/1.0 if +downgrade * action applies. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_http(struct client_state *csp, char **header) { sscanf(*header, "HTTP/%*d.%*d %d", &(csp->http->status)); if (csp->http->status == 206) { csp->content_type = CT_TABOO; } if ((csp->action->flags & ACTION_DOWNGRADE) != 0) { /* XXX: Should we do a real validity check here? */ if (strlen(*header) > 8) { (*header)[7] = '0'; log_error(LOG_LEVEL_HEADER, "Downgraded answer to HTTP/1.0"); } else { /* * XXX: Should we block the request or * enlist a valid status code line here? */ log_error(LOG_LEVEL_INFO, "Malformed server response detected. " "Downgrading to HTTP/1.0 impossible."); } } return JB_ERR_OK; } /********************************************************************* * * Function : add_cooky_expiry_date * * Description : Adds a cookie expiry date to a string. * * Parameters : * 1 : cookie = On input, pointer to cookie to modify. * On output, pointer to the modified header. * The original string is freed. * 2 : lifetime = Seconds the cookie should be valid * * Returns : N/A * *********************************************************************/ static void add_cookie_expiry_date(char **cookie, time_t lifetime) { char tmp[50]; struct tm *timeptr = NULL; time_t expiry_date = time(NULL) + lifetime; #ifdef HAVE_GMTIME_R struct tm gmt; timeptr = gmtime_r(&expiry_date, &gmt); #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&gmtime_mutex); timeptr = gmtime(&expiry_date); privoxy_mutex_unlock(&gmtime_mutex); #else timeptr = gmtime(&expiry_date); #endif if (NULL == timeptr) { log_error(LOG_LEVEL_FATAL, "Failed to get the time in add_cooky_expiry_date()"); } strftime(tmp, sizeof(tmp), "; expires=%a, %d-%b-%Y %H:%M:%S GMT", timeptr); if (JB_ERR_OK != string_append(cookie, tmp)) { log_error(LOG_LEVEL_FATAL, "Out of memory in add_cooky_expiry()"); } } /********************************************************************* * * Function : server_set_cookie * * Description : Handle the server "cookie" header properly. * Crunch, accept or rewrite it to a session cookie. * Called from `sed'. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. * On output, pointer to the modified header, or NULL * to remove the header. This function frees the * original string if necessary. * * Returns : JB_ERR_OK on success, or * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err server_set_cookie(struct client_state *csp, char **header) { if ((csp->action->flags & ACTION_CRUNCH_INCOMING_COOKIES) != 0) { log_error(LOG_LEVEL_HEADER, "Crunching incoming cookie: %s", *header); freez(*header); } else if ((0 != (csp->action->flags & ACTION_SESSION_COOKIES_ONLY)) || (0 != (csp->action->flags & ACTION_LIMIT_COOKIE_LIFETIME))) { time_t now; time_t cookie_time; long cookie_lifetime = 0; enum { NO_EXPIRY_DATE_SPECIFIED, EXPIRY_DATE_ACCEPTABLE, EXPIRY_DATE_UNACCEPTABLE } expiry_date_status = NO_EXPIRY_DATE_SPECIFIED; /* A variable to store the tag we're working on */ char *cur_tag; /* Skip "Set-Cookie:" (11 characters) in header */ cur_tag = *header + 11; /* skip whitespace between "Set-Cookie:" and value */ while (*cur_tag && privoxy_isspace(*cur_tag)) { cur_tag++; } time(&now); if ((csp->action->flags & ACTION_LIMIT_COOKIE_LIFETIME) != 0) { const char *param = csp->action->string[ACTION_STRING_LIMIT_COOKIE_LIFETIME]; cookie_lifetime = strtol(param, NULL, 0); if (cookie_lifetime < 0) { log_error(LOG_LEVEL_FATAL, "Invalid cookie lifetime limit: %s", param); } cookie_lifetime *= 60; } /* Loop through each tag in the cookie */ while (*cur_tag) { /* Find next tag */ char *next_tag = strchr(cur_tag, ';'); if (next_tag != NULL) { /* Skip the ';' character itself */ next_tag++; /* skip whitespace ";" and start of tag */ while (*next_tag && privoxy_isspace(*next_tag)) { next_tag++; } } else { /* "Next tag" is the end of the string */ next_tag = cur_tag + strlen(cur_tag); } /* * Check the expiration date to see * if the cookie is still valid, if yes, * rewrite it to a session cookie. */ if ((strncmpic(cur_tag, "expires=", 8) == 0) && *(cur_tag + 8)) { char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */ if ((expiration_date[0] == '"') && (expiration_date[1] != '\0')) { /* * Skip quotation mark. RFC 2109 10.1.2 seems to hint * that the expiration date isn't supposed to be quoted, * but some servers do it anyway. */ expiration_date++; } /* Did we detect the date properly? */ if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time)) { /* * Nope, treat it as if it was still valid. * * XXX: Should we remove the whole cookie instead? */ log_error(LOG_LEVEL_ERROR, "Can't parse \'%s\', send by %s. Unsupported time format?", cur_tag, csp->http->url); string_move(cur_tag, next_tag); expiry_date_status = EXPIRY_DATE_UNACCEPTABLE; } else { /* * Yes. Check if the cookie is still valid. * * If the cookie is already expired it's probably * a delete cookie and even if it isn't, the browser * will discard it anyway. */ /* * XXX: timegm() isn't available on some AmigaOS * versions and our replacement doesn't work. * * Our options are to either: * * - disable session-cookies-only completely if timegm * is missing, * * - to simply remove all expired tags, like it has * been done until Privoxy 3.0.6 and to live with * the consequence that it can cause login/logout * problems on servers that don't validate their * input properly, or * * - to replace it with mktime in which * case there is a slight chance of valid cookies * passing as already expired. * * This is the way it's currently done and it's not * as bad as it sounds. If the missing GMT offset is * enough to change the result of the expiration check * the cookie will be only valid for a few hours * anyway, which in many cases will be shorter * than a browser session. */ if (cookie_time < now) { log_error(LOG_LEVEL_HEADER, "Cookie \'%s\' is already expired and can pass unmodified.", *header); /* Just in case some clown sets more then one expiration date */ cur_tag = next_tag; expiry_date_status = EXPIRY_DATE_ACCEPTABLE; } else if ((cookie_lifetime != 0) && (cookie_time < (now + cookie_lifetime))) { log_error(LOG_LEVEL_HEADER, "Cookie \'%s\' can pass unmodified. " "Its lifetime is below the limit.", *header); /* Just in case some clown sets more then one expiration date */ cur_tag = next_tag; expiry_date_status = EXPIRY_DATE_ACCEPTABLE; } else { /* * Still valid, delete expiration date by copying * the rest of the string over it. */ string_move(cur_tag, next_tag); /* That changed the header, need to issue a log message */ expiry_date_status = EXPIRY_DATE_UNACCEPTABLE; /* * Note that the next tag has now been moved to *cur_tag, * so we do not need to update the cur_tag pointer. */ } } } else { /* Move on to next cookie tag */ cur_tag = next_tag; } } if (expiry_date_status != EXPIRY_DATE_ACCEPTABLE) { assert(NULL != *header); if (cookie_lifetime != 0) { add_cookie_expiry_date(header, cookie_lifetime); log_error(LOG_LEVEL_HEADER, "Cookie rewritten to: %s", *header); } else if (expiry_date_status != NO_EXPIRY_DATE_SPECIFIED) { log_error(LOG_LEVEL_HEADER, "Cookie rewritten to a temporary one: %s", *header); } } } return JB_ERR_OK; } #ifdef FEATURE_FORCE_LOAD /********************************************************************* * * Function : strclean * * Description : In-Situ-Eliminate all occurrences of substring in * string * * Parameters : * 1 : string = string to clean * 2 : substring = substring to eliminate * * Returns : Number of eliminations * *********************************************************************/ int strclean(char *string, const char *substring) { int hits = 0; size_t len; char *pos, *p; len = strlen(substring); while((pos = strstr(string, substring)) != NULL) { p = pos + len; do { *(p - len) = *p; } while (*p++ != '\0'); hits++; } return(hits); } #endif /* def FEATURE_FORCE_LOAD */ /********************************************************************* * * Function : parse_header_time * * Description : Parses time formats used in HTTP header strings * to get the numerical respresentation. * * Parameters : * 1 : header_time = HTTP header time as string. * 2 : result = storage for header_time in seconds * * Returns : JB_ERR_OK if the time format was recognized, or * JB_ERR_PARSE otherwise. * *********************************************************************/ static jb_err parse_header_time(const char *header_time, time_t *result) { struct tm gmt; /* * Checking for two-digit years first in an * attempt to work around GNU libc's strptime() * reporting negative year values when using %Y. */ static const char time_formats[][22] = { /* Tue, 02-Jun-37 20:00:00 */ "%a, %d-%b-%y %H:%M:%S", /* Tue, 02 Jun 2037 20:00:00 */ "%a, %d %b %Y %H:%M:%S", /* Tue, 02-Jun-2037 20:00:00 */ "%a, %d-%b-%Y %H:%M:%S", /* Tuesday, 02-Jun-2037 20:00:00 */ "%A, %d-%b-%Y %H:%M:%S", /* Tuesday Jun 02 20:00:00 2037 */ "%A %b %d %H:%M:%S %Y" }; unsigned int i; for (i = 0; i < SZ(time_formats); i++) { /* * Zero out gmt to prevent time zone offsets. * Documented to be required for GNU libc. */ memset(&gmt, 0, sizeof(gmt)); if (NULL != strptime(header_time, time_formats[i], &gmt)) { /* Sanity check for GNU libc. */ if (gmt.tm_year < 0) { log_error(LOG_LEVEL_HEADER, "Failed to parse '%s' using '%s'. Moving on.", header_time, time_formats[i]); continue; } *result = timegm(&gmt); #ifdef FEATURE_STRPTIME_SANITY_CHECKS /* * Verify that parsing the date recreated from the first * parse operation gets the previous result. If it doesn't, * either strptime() or strftime() are malfunctioning. * * We could string-compare the recreated date with the original * header date, but this leads to false positives as strptime() * may let %a accept all day formats while strftime() will only * create one. */ { char recreated_date[100]; struct tm *tm; time_t result2; tm = gmtime(result); strftime(recreated_date, sizeof(recreated_date), time_formats[i], tm); memset(&gmt, 0, sizeof(gmt)); if (NULL == strptime(recreated_date, time_formats[i], &gmt)) { log_error(LOG_LEVEL_ERROR, "Failed to parse '%s' generated with '%s' to recreate '%s'.", recreated_date, time_formats[i], header_time); continue; } result2 = timegm(&gmt); if (*result != result2) { log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. " "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.", time_formats[i], header_time, recreated_date, *result, result2); continue; } } #endif return JB_ERR_OK; } } return JB_ERR_PARSE; } /********************************************************************* * * Function : get_destination_from_headers * * Description : Parse the "Host:" header to get the request's destination. * Only needed if the client's request was forcefully * redirected into Privoxy. * * Code mainly copied from client_host() which is currently * run too late for this purpose. * * Parameters : * 1 : headers = List of headers (one of them hopefully being * the "Host:" header) * 2 : http = storage for the result (host, port and hostport). * * Returns : JB_ERR_MEMORY (or terminates) in case of memory problems, * JB_ERR_PARSE if the host header couldn't be found, * JB_ERR_OK otherwise. * *********************************************************************/ jb_err get_destination_from_headers(const struct list *headers, struct http_request *http) { char *q; char *p; char *host; host = get_header_value(headers, "Host:"); if (NULL == host) { log_error(LOG_LEVEL_ERROR, "No \"Host:\" header found."); return JB_ERR_PARSE; } p = strdup_or_die(host); chomp(p); q = strdup_or_die(p); freez(http->hostport); http->hostport = p; freez(http->host); http->host = q; q = strchr(http->host, ':'); if (q != NULL) { /* Terminate hostname and evaluate port string */ *q++ = '\0'; http->port = atoi(q); } else { http->port = http->ssl ? 443 : 80; } /* Rebuild request URL */ freez(http->url); http->url = strdup(http->ssl ? "https://" : "http://"); string_append(&http->url, http->hostport); string_append(&http->url, http->path); if (http->url == NULL) { return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "Destination extracted from \"Host:\" header. New request URL: %s", http->url); return JB_ERR_OK; } /********************************************************************* * * Function : create_forged_referrer * * Description : Helper for client_referrer to forge a referer as * 'http://hostname[:port]/' to fool stupid * checks for in-site links * * Parameters : * 1 : header = Pointer to header pointer * 2 : hostport = Host and optionally port as string * * Returns : JB_ERR_OK in case of success, or * JB_ERR_MEMORY in case of memory problems. * *********************************************************************/ static jb_err create_forged_referrer(char **header, const char *hostport) { assert(NULL == *header); *header = strdup("Referer: http://"); string_append(header, hostport); string_append(header, "/"); if (NULL == *header) { return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header); return JB_ERR_OK; } /********************************************************************* * * Function : create_fake_referrer * * Description : Helper for client_referrer to create a fake referrer * based on a string supplied by the user. * * Parameters : * 1 : header = Pointer to header pointer * 2 : hosthost = Referrer to fake * * Returns : JB_ERR_OK in case of success, or * JB_ERR_MEMORY in case of memory problems. * *********************************************************************/ static jb_err create_fake_referrer(char **header, const char *fake_referrer) { assert(NULL == *header); if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8))) { log_error(LOG_LEVEL_HEADER, "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer); } *header = strdup("Referer: "); string_append(header, fake_referrer); if (NULL == *header) { return JB_ERR_MEMORY; } log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header); return JB_ERR_OK; } /********************************************************************* * * Function : handle_conditional_hide_referrer_parameter * * Description : Helper for client_referrer to crunch or forge * the referrer header if the host has changed. * * Parameters : * 1 : header = Pointer to header pointer * 2 : host = The target host (may include the port) * 3 : parameter_conditional_block = Boolean to signal * if we're in conditional-block mode. If not set, * we're in conditional-forge mode. * * Returns : JB_ERR_OK in case of success, or * JB_ERR_MEMORY in case of memory problems. * *********************************************************************/ static jb_err handle_conditional_hide_referrer_parameter(char **header, const char *host, const int parameter_conditional_block) { char *referer = strdup_or_die(*header); const size_t hostlength = strlen(host); const char *referer_url = NULL; /* referer begins with 'Referer: http[s]://' */ if ((hostlength+17) < strlen(referer)) { /* * Shorten referer to make sure the referer is blocked * if www.example.org/www.example.com-shall-see-the-referer/ * links to www.example.com/ */ referer[hostlength+17] = '\0'; } referer_url = strstr(referer, "http://"); if ((NULL == referer_url) || (NULL == strstr(referer_url, host))) { /* Host has changed, Referer is invalid or a https URL. */ if (parameter_conditional_block) { log_error(LOG_LEVEL_HEADER, "New host is: %s. Crunching %s!", host, *header); freez(*header); } else { freez(*header); freez(referer); return create_forged_referrer(header, host); } } freez(referer); return JB_ERR_OK; } /********************************************************************* * * Function : create_content_length_header * * Description : Creates a Content-Length header. * * Parameters : * 1 : content_length = The content length to be used in the header. * 2 : header = Allocated space to safe the header. * 3 : buffer_length = The length of the allocated space. * * Returns : void * *********************************************************************/ static void create_content_length_header(unsigned long long content_length, char *header, size_t buffer_length) { snprintf(header, buffer_length, "Content-Length: %llu", content_length); } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : get_expected_content_length * * Description : Figures out the content length from a list of headers. * * Parameters : * 1 : headers = List of headers * * Returns : Number of bytes to expect * *********************************************************************/ unsigned long long get_expected_content_length(struct list *headers) { const char *content_length_header; unsigned long long content_length = 0; content_length_header = get_header_value(headers, "Content-Length:"); if (content_length_header != NULL) { if (JB_ERR_OK != get_content_length(content_length_header, &content_length)) { log_error(LOG_LEVEL_ERROR, "Failed to get the Content-Length in %s", content_length_header); /* XXX: The header will be removed later on */ return 0; } } return content_length; } #endif /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./jcc.c000640 001751 001751 00000375124 12114163632 014700 0ustar00fkfk000000 000000 const char jcc_rcs[] = "$Id: jcc.c,v 1.424 2013/03/01 17:38:34 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ * * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #include #include #include #include #ifdef _WIN32 # ifndef FEATURE_PTHREAD # ifndef STRICT # define STRICT # endif # include # include # endif /* ndef FEATURE_PTHREAD */ # include "win32.h" # ifndef _WIN_CONSOLE # include "w32log.h" # endif /* ndef _WIN_CONSOLE */ # include "w32svrapi.h" #else /* ifndef _WIN32 */ # if !defined (__OS2__) # include # include # endif /* ndef __OS2__ */ # include # include # include #ifdef sun #include #endif /* sun */ #ifdef unix #include #include #endif # include # ifdef __BEOS__ # include /* BeOS has select() for sockets only. */ # include /* declarations for threads and stuff. */ # endif # if defined(__EMX__) || defined(__OS2__) # include /* OS/2/EMX needs a little help with select */ # endif # ifdef __OS2__ #define INCL_DOS # include #define bzero(B,N) memset(B,0x00,n) # endif # ifndef FD_ZERO # include # endif #endif #include "project.h" #include "list.h" #include "jcc.h" #include "filters.h" #include "loaders.h" #include "parsers.h" #include "miscutil.h" #include "errlog.h" #include "jbsockets.h" #include "gateway.h" #include "actions.h" #include "cgi.h" #include "loadcfg.h" #include "urlmatch.h" const char jcc_h_rcs[] = JCC_H_VERSION; const char project_h_rcs[] = PROJECT_H_VERSION; int daemon_mode = 1; struct client_states clients[1]; struct file_list files[1]; #ifdef FEATURE_STATISTICS int urls_read = 0; /* total nr of urls read inc rejected */ int urls_rejected = 0; /* total nr of urls rejected */ #endif /* def FEATURE_STATISTICS */ #ifdef FEATURE_GRACEFUL_TERMINATION int g_terminate = 0; #endif #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) static void sig_handler(int the_signal); #endif static int client_protocol_is_unsupported(const struct client_state *csp, char *req); static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers); static jb_err get_server_headers(struct client_state *csp); static const char *crunch_reason(const struct http_response *rsp); static void send_crunch_response(const struct client_state *csp, struct http_response *rsp); static char *get_request_line(struct client_state *csp); static jb_err receive_client_request(struct client_state *csp); static jb_err parse_client_request(struct client_state *csp); static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line); static jb_err change_request_destination(struct client_state *csp); static void chat(struct client_state *csp); static void serve(struct client_state *csp); #if !defined(_WIN32) || defined(_WIN_CONSOLE) static void usage(const char *myname); #endif static void initialize_mutexes(void); static jb_socket bind_port_helper(const char *haddr, int hport); static void bind_ports_helper(struct configuration_spec *config, jb_socket sockets[]); static void close_ports_helper(jb_socket sockets[]); static void listen_loop(void); #ifdef AMIGA void serve(struct client_state *csp); #else /* ifndef AMIGA */ static void serve(struct client_state *csp); #endif /* def AMIGA */ #ifdef __BEOS__ static int32 server_thread(void *data); #endif /* def __BEOS__ */ #ifdef _WIN32 #define sleep(N) Sleep(((N) * 1000)) #endif #ifdef __OS2__ #define sleep(N) DosSleep(((N) * 100)) #endif #ifdef MUTEX_LOCKS_AVAILABLE /* * XXX: Does the locking stuff really belong in this file? */ privoxy_mutex_t log_mutex; privoxy_mutex_t log_init_mutex; privoxy_mutex_t connection_reuse_mutex; #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) privoxy_mutex_t resolver_mutex; #endif /* !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) */ #ifndef HAVE_GMTIME_R privoxy_mutex_t gmtime_mutex; #endif /* ndef HAVE_GMTIME_R */ #ifndef HAVE_LOCALTIME_R privoxy_mutex_t localtime_mutex; #endif /* ndef HAVE_GMTIME_R */ #ifndef HAVE_RANDOM privoxy_mutex_t rand_mutex; #endif /* ndef HAVE_RANDOM */ #endif /* def MUTEX_LOCKS_AVAILABLE */ #if defined(unix) const char *basedir = NULL; const char *pidfile = NULL; static int received_hup_signal = 0; #endif /* defined unix */ /* HTTP snipplets. */ static const char CSUCCEED[] = "HTTP/1.1 200 Connection established\r\n" "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n"; static const char CHEADER[] = "HTTP/1.1 400 Invalid header received from client\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid header received from client.\r\n"; static const char FTP_RESPONSE[] = "HTTP/1.1 400 Invalid request received from client\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support FTP.\r\n"; static const char GOPHER_RESPONSE[] = "HTTP/1.1 400 Invalid request received from client\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support gopher.\r\n"; /* XXX: should be a template */ static const char MISSING_DESTINATION_RESPONSE[] = "HTTP/1.1 400 Bad request received from client\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad request. Privoxy was unable to extract the destination.\r\n"; /* XXX: should be a template */ static const char INVALID_SERVER_HEADERS_RESPONSE[] = "HTTP/1.1 502 Server or forwarder response invalid\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad response. The server or forwarder response doesn't look like HTTP.\r\n"; /* XXX: should be a template */ static const char MESSED_UP_REQUEST_RESPONSE[] = "HTTP/1.1 400 Malformed request after rewriting\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad request. Messed up with header filters.\r\n"; static const char TOO_MANY_CONNECTIONS_RESPONSE[] = "HTTP/1.1 503 Too many open connections\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Maximum number of open connections reached.\r\n"; static const char CLIENT_CONNECTION_TIMEOUT_RESPONSE[] = "HTTP/1.1 504 Connection timeout\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "The connection timed out because the client request didn't arrive in time.\r\n"; static const char CLIENT_BODY_PARSE_ERROR_RESPONSE[] = "HTTP/1.1 400 Failed reading client body\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Failed parsing or buffering the chunk-encoded client body.\r\n"; /* A function to crunch a response */ typedef struct http_response *(*crunch_func_ptr)(struct client_state *); /* Crunch function flags */ #define CF_NO_FLAGS 0 /* Cruncher applies to forced requests as well */ #define CF_IGNORE_FORCE 1 /* Crunched requests are counted for the block statistics */ #define CF_COUNT_AS_REJECT 2 /* A crunch function and its flags */ struct cruncher { const crunch_func_ptr cruncher; const int flags; }; static int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]); /* Complete list of cruncher functions */ static const struct cruncher crunchers_all[] = { { direct_response, CF_COUNT_AS_REJECT|CF_IGNORE_FORCE}, { block_url, CF_COUNT_AS_REJECT }, #ifdef FEATURE_TRUST { trust_url, CF_COUNT_AS_REJECT }, #endif /* def FEATURE_TRUST */ { redirect_url, CF_NO_FLAGS }, { dispatch_cgi, CF_IGNORE_FORCE}, { NULL, 0 } }; /* Light version, used after tags are applied */ static const struct cruncher crunchers_light[] = { { block_url, CF_COUNT_AS_REJECT }, { redirect_url, CF_NO_FLAGS }, { NULL, 0 } }; /* * XXX: Don't we really mean * * #if defined(unix) * * here? */ #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) /********************************************************************* * * Function : sig_handler * * Description : Signal handler for different signals. * Exit gracefully on TERM and INT * or set a flag that will cause the errlog * to be reopened by the main thread on HUP. * * Parameters : * 1 : the_signal = the signal cause this function to call * * Returns : - * *********************************************************************/ static void sig_handler(int the_signal) { switch(the_signal) { case SIGTERM: case SIGINT: log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", the_signal); #if defined(unix) if (pidfile) { unlink(pidfile); } #endif /* unix */ exit(the_signal); break; case SIGHUP: #if defined(unix) received_hup_signal = 1; #endif break; default: /* * We shouldn't be here, unless we catch signals * in main() that we can't handle here! */ log_error(LOG_LEVEL_FATAL, "sig_handler: exiting on unexpected signal %d", the_signal); } return; } #endif /********************************************************************* * * Function : client_protocol_is_unsupported * * Description : Checks if the client used a known unsupported * protocol and deals with it by sending an error * response. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : req = the first request line send by the client * * Returns : TRUE if an error response has been generated, or * FALSE if the request doesn't look invalid. * *********************************************************************/ static int client_protocol_is_unsupported(const struct client_state *csp, char *req) { /* * If it's a FTP or gopher request, we don't support it. * * These checks are better than nothing, but they might * not work in all configurations and some clients might * have problems digesting the answer. * * They should, however, never cause more problems than * Privoxy's old behaviour (returning the misleading HTML * error message: * * "Could not resolve http://(ftp|gopher)://example.org"). */ if (!strncmpic(req, "GET ftp://", 10) || !strncmpic(req, "GET gopher://", 13)) { const char *response = NULL; const char *protocol = NULL; if (!strncmpic(req, "GET ftp://", 10)) { response = FTP_RESPONSE; protocol = "FTP"; } else { response = GOPHER_RESPONSE; protocol = "GOPHER"; } log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as %s proxy: %s", csp->ip_addr_str, protocol, req); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req); freez(req); write_socket(csp->cfd, response, strlen(response)); return TRUE; } return FALSE; } /********************************************************************* * * Function : get_request_destination_elsewhere * * Description : If the client's request was redirected into * Privoxy without the client's knowledge, * the request line lacks the destination host. * * This function tries to get it elsewhere, * provided accept-intercepted-requests is enabled. * * "Elsewhere" currently only means "Host: header", * but in the future we may ask the redirecting * packet filter to look the destination up. * * If the destination stays unknown, an error * response is send to the client and headers * are freed so that chat() can return directly. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : headers = a header list * * Returns : JB_ERR_OK if the destination is now known, or * JB_ERR_PARSE if it isn't. * *********************************************************************/ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) { char *req; if (!(csp->config->feature_flags & RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS)) { log_error(LOG_LEVEL_ERROR, "%s's request: \'%s\' is invalid." " Privoxy isn't configured to accept intercepted requests.", csp->ip_addr_str, csp->http->cmd); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, csp->http->cmd); write_socket(csp->cfd, CHEADER, strlen(CHEADER)); destroy_list(headers); return JB_ERR_PARSE; } else if (JB_ERR_OK == get_destination_from_headers(headers, csp->http)) { #ifndef FEATURE_EXTENDED_HOST_PATTERNS /* Split the domain we just got for pattern matching */ init_domain_components(csp->http); #endif return JB_ERR_OK; } else { /* We can't work without destination. Go spread the news.*/ req = list_to_text(headers); chomp(req); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, csp->http->cmd); log_error(LOG_LEVEL_ERROR, "Privoxy was unable to get the destination for %s's request:\n%s\n%s", csp->ip_addr_str, csp->http->cmd, req); freez(req); write_socket(csp->cfd, MISSING_DESTINATION_RESPONSE, strlen(MISSING_DESTINATION_RESPONSE)); destroy_list(headers); return JB_ERR_PARSE; } /* * TODO: If available, use PF's ioctl DIOCNATLOOK as last resort * to get the destination IP address, use it as host directly * or do a reverse DNS lookup first. */ } /********************************************************************* * * Function : get_server_headers * * Description : Parses server headers in iob and fills them * into csp->headers so that they can later be * handled by sed(). * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK if everything went fine, or * JB_ERR_PARSE if the headers were incomplete. * *********************************************************************/ static jb_err get_server_headers(struct client_state *csp) { int continue_hack_in_da_house = 0; char * header; while (((header = get_header(csp->iob)) != NULL) || continue_hack_in_da_house) { if (header == NULL) { /* * continue hack in da house. Ignore the ending of * this head and continue enlisting header lines. * The reason is described below. */ enlist(csp->headers, ""); continue_hack_in_da_house = 0; continue; } else if (0 == strncmpic(header, "HTTP/1.1 100", 12)) { /* * It's a bodyless continue response, don't * stop header parsing after reaching its end. * * As a result Privoxy will concatenate the * next response's head and parse and deliver * the headers as if they belonged to one request. * * The client will separate them because of the * empty line between them. * * XXX: What we're doing here is clearly against * the intended purpose of the continue header, * and under some conditions (HTTP/1.0 client request) * it's a standard violation. * * Anyway, "sort of against the spec" is preferable * to "always getting confused by Continue responses" * (Privoxy's behaviour before this hack was added) */ log_error(LOG_LEVEL_HEADER, "Continue hack in da house."); continue_hack_in_da_house = 1; } else if (*header == '\0') { /* * If the header is empty, but the Continue hack * isn't active, we can assume that we reached the * end of the buffer before we hit the end of the * head. * * Inform the caller an let it decide how to handle it. */ return JB_ERR_PARSE; } if (JB_ERR_MEMORY == enlist(csp->headers, header)) { /* * XXX: Should we quit the request and return a * out of memory error page instead? */ log_error(LOG_LEVEL_ERROR, "Out of memory while enlisting server headers. %s lost.", header); } freez(header); } return JB_ERR_OK; } /********************************************************************* * * Function : crunch_reason * * Description : Translates the crunch reason code into a string. * * Parameters : * 1 : rsp = a http_response * * Returns : A string with the crunch reason or an error description. * *********************************************************************/ static const char *crunch_reason(const struct http_response *rsp) { char * reason = NULL; assert(rsp != NULL); if (rsp == NULL) { return "Internal error while searching for crunch reason"; } switch (rsp->crunch_reason) { case UNSUPPORTED: reason = "Unsupported HTTP feature"; break; case BLOCKED: reason = "Blocked"; break; case UNTRUSTED: reason = "Untrusted"; break; case REDIRECTED: reason = "Redirected"; break; case CGI_CALL: reason = "CGI Call"; break; case NO_SUCH_DOMAIN: reason = "DNS failure"; break; case FORWARDING_FAILED: reason = "Forwarding failed"; break; case CONNECT_FAILED: reason = "Connection failure"; break; case OUT_OF_MEMORY: reason = "Out of memory (may mask other reasons)"; break; case CONNECTION_TIMEOUT: reason = "Connection timeout"; break; case NO_SERVER_DATA: reason = "No server data received"; break; default: reason = "No reason recorded"; break; } return reason; } /********************************************************************* * * Function : log_applied_actions * * Description : Logs the applied actions if LOG_LEVEL_ACTIONS is * enabled. * * Parameters : * 1 : actions = Current action spec to log * * Returns : Nothing. * *********************************************************************/ static void log_applied_actions(const struct current_action_spec *actions) { /* * The conversion to text requires lots of memory allocations so * we only do the conversion if the user is actually interested. */ if (debug_level_is_enabled(LOG_LEVEL_ACTIONS)) { char *actions_as_text = actions_to_line_of_text(actions); log_error(LOG_LEVEL_ACTIONS, "%s", actions_as_text); freez(actions_as_text); } } /********************************************************************* * * Function : send_crunch_response * * Description : Delivers already prepared response for * intercepted requests, logs the interception * and frees the response. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 1 : rsp = Fully prepared response. Will be freed on exit. * * Returns : Nothing. * *********************************************************************/ static void send_crunch_response(const struct client_state *csp, struct http_response *rsp) { const struct http_request *http = csp->http; char status_code[4]; assert(rsp != NULL); assert(rsp->head != NULL); if (rsp == NULL) { log_error(LOG_LEVEL_FATAL, "NULL response in send_crunch_response."); } /* * Extract the status code from the actual head * that will be send to the client. It is the only * way to get it right for all requests, including * the fixed ones for out-of-memory problems. * * A head starts like this: 'HTTP/1.1 200...' * 0123456789|11 * 10 */ status_code[0] = rsp->head[9]; status_code[1] = rsp->head[10]; status_code[2] = rsp->head[11]; status_code[3] = '\0'; /* Log that the request was crunched and why. */ log_applied_actions(csp->action); log_error(LOG_LEVEL_CRUNCH, "%s: %s", crunch_reason(rsp), http->url); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" %s %u", csp->ip_addr_str, http->ocmd, status_code, rsp->content_length); /* Write the answer to the client */ if (write_socket(csp->cfd, rsp->head, rsp->head_length) || write_socket(csp->cfd, rsp->body, rsp->content_length)) { /* There is nothing we can do about it. */ log_error(LOG_LEVEL_ERROR, "Couldn't deliver the error message through client socket %d: %E", csp->cfd); } /* Clean up and return */ if (cgi_error_memory() != rsp) { free_http_response(rsp); } return; } /********************************************************************* * * Function : crunch_response_triggered * * Description : Checks if the request has to be crunched, * and delivers the crunch response if necessary. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : crunchers = list of cruncher functions to run * * Returns : TRUE if the request was answered with a crunch response * FALSE otherwise. * *********************************************************************/ static int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]) { struct http_response *rsp = NULL; const struct cruncher *c; /* * If CGI request crunching is disabled, * check the CGI dispatcher out of order to * prevent unintentional blocks or redirects. */ if (!(csp->config->feature_flags & RUNTIME_FEATURE_CGI_CRUNCHING) && (NULL != (rsp = dispatch_cgi(csp)))) { /* Deliver, log and free the interception response. */ send_crunch_response(csp, rsp); csp->flags |= CSP_FLAG_CRUNCHED; return TRUE; } for (c = crunchers; c->cruncher != NULL; c++) { /* * Check the cruncher if either Privoxy is toggled * on and the request isn't forced, or if the cruncher * applies to forced requests as well. */ if (((csp->flags & CSP_FLAG_TOGGLED_ON) && !(csp->flags & CSP_FLAG_FORCED)) || (c->flags & CF_IGNORE_FORCE)) { rsp = c->cruncher(csp); if (NULL != rsp) { /* Deliver, log and free the interception response. */ send_crunch_response(csp, rsp); csp->flags |= CSP_FLAG_CRUNCHED; #ifdef FEATURE_STATISTICS if (c->flags & CF_COUNT_AS_REJECT) { csp->flags |= CSP_FLAG_REJECTED; } #endif /* def FEATURE_STATISTICS */ return TRUE; } } } return FALSE; } /********************************************************************* * * Function : build_request_line * * Description : Builds the HTTP request line. * * If a HTTP forwarder is used it expects the whole URL, * web servers only get the path. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : fwd = The forwarding spec used for the request * XXX: Should use http->fwd instead. * 3 : request_line = The old request line which will be replaced. * * Returns : Nothing. Terminates in case of memory problems. * *********************************************************************/ static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line) { struct http_request *http = csp->http; assert(http->ssl == 0); /* * Downgrade http version from 1.1 to 1.0 * if +downgrade action applies. */ if ((csp->action->flags & ACTION_DOWNGRADE) && (!strcmpic(http->ver, "HTTP/1.1"))) { freez(http->ver); http->ver = strdup_or_die("HTTP/1.0"); } /* * Rebuild the request line. */ freez(*request_line); *request_line = strdup(http->gpc); string_append(request_line, " "); if (fwd->forward_host) { string_append(request_line, http->url); } else { string_append(request_line, http->path); } string_append(request_line, " "); string_append(request_line, http->ver); if (*request_line == NULL) { log_error(LOG_LEVEL_FATAL, "Out of memory writing HTTP command"); } log_error(LOG_LEVEL_HEADER, "New HTTP Request-Line: %s", *request_line); } /********************************************************************* * * Function : change_request_destination * * Description : Parse a (rewritten) request line and regenerate * the http request data. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : Forwards the parse_http_request() return code. * Terminates in case of memory problems. * *********************************************************************/ static jb_err change_request_destination(struct client_state *csp) { struct http_request *http = csp->http; jb_err err; log_error(LOG_LEVEL_REDIRECTS, "Rewrite detected: %s", csp->headers->first->str); free_http_request(http); err = parse_http_request(csp->headers->first->str, http); if (JB_ERR_OK != err) { log_error(LOG_LEVEL_ERROR, "Couldn't parse rewritten request: %s.", jb_err_to_string(err)); } else { /* XXX: ocmd is a misleading name */ http->ocmd = strdup_or_die(http->cmd); } return err; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : server_response_is_complete * * Description : Determines whether we should stop reading * from the server socket. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : content_length = Length of content received so far. * * Returns : TRUE if the response is complete, * FALSE otherwise. * *********************************************************************/ static int server_response_is_complete(struct client_state *csp, unsigned long long content_length) { int content_length_known = !!(csp->flags & CSP_FLAG_CONTENT_LENGTH_SET); if (!strcmpic(csp->http->gpc, "HEAD")) { /* * "HEAD" implies no body, we are thus expecting * no content. XXX: incomplete "list" of methods? */ csp->expected_content_length = 0; content_length_known = TRUE; csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; } if (csp->http->status == 204 || csp->http->status == 304) { /* * Expect no body. XXX: incomplete "list" of status codes? */ csp->expected_content_length = 0; content_length_known = TRUE; csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET; } return (content_length_known && ((0 == csp->expected_content_length) || (csp->expected_content_length <= content_length))); } #ifdef FEATURE_CONNECTION_SHARING /********************************************************************* * * Function : wait_for_alive_connections * * Description : Waits for alive connections to timeout. * * Parameters : N/A * * Returns : N/A * *********************************************************************/ static void wait_for_alive_connections(void) { int connections_alive = close_unusable_connections(); while (0 < connections_alive) { log_error(LOG_LEVEL_CONNECT, "Waiting for %d connections to timeout.", connections_alive); sleep(60); connections_alive = close_unusable_connections(); } log_error(LOG_LEVEL_CONNECT, "No connections to wait for left."); } #endif /* def FEATURE_CONNECTION_SHARING */ /********************************************************************* * * Function : save_connection_destination * * Description : Remembers a connection for reuse later on. * * Parameters : * 1 : sfd = Open socket to remember. * 2 : http = The destination for the connection. * 3 : fwd = The forwarder settings used. * 3 : server_connection = storage. * * Returns : void * *********************************************************************/ void save_connection_destination(jb_socket sfd, const struct http_request *http, const struct forward_spec *fwd, struct reusable_connection *server_connection) { assert(sfd != JB_INVALID_SOCKET); assert(NULL != http->host); server_connection->sfd = sfd; server_connection->host = strdup_or_die(http->host); server_connection->port = http->port; assert(NULL != fwd); assert(server_connection->gateway_host == NULL); assert(server_connection->gateway_port == 0); assert(server_connection->forwarder_type == 0); assert(server_connection->forward_host == NULL); assert(server_connection->forward_port == 0); server_connection->forwarder_type = fwd->type; if (NULL != fwd->gateway_host) { server_connection->gateway_host = strdup_or_die(fwd->gateway_host); } else { server_connection->gateway_host = NULL; } server_connection->gateway_port = fwd->gateway_port; if (NULL != fwd->forward_host) { server_connection->forward_host = strdup_or_die(fwd->forward_host); } else { server_connection->forward_host = NULL; } server_connection->forward_port = fwd->forward_port; } /********************************************************************* * * Function : verify_request_length * * Description : Checks if we already got the whole client requests * and sets CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ if * we do. * * Data that doesn't belong to the current request is * either thrown away to let the client retry on a clean * socket, or stashed to be dealt with after the current * request is served. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : void * *********************************************************************/ static void verify_request_length(struct client_state *csp) { unsigned long long buffered_request_bytes = (unsigned long long)(csp->client_iob->eod - csp->client_iob->cur); if ((csp->expected_client_content_length != 0) && (buffered_request_bytes != 0)) { if (csp->expected_client_content_length >= buffered_request_bytes) { csp->expected_client_content_length -= buffered_request_bytes; log_error(LOG_LEVEL_CONNECT, "Reduced expected bytes to %llu " "to account for the %llu ones we already got.", csp->expected_client_content_length, buffered_request_bytes); } else { assert(csp->client_iob->eod > csp->client_iob->cur + csp->expected_client_content_length); csp->client_iob->eod = csp->client_iob->cur + csp->expected_client_content_length; log_error(LOG_LEVEL_CONNECT, "Reducing expected bytes to 0. " "Marking the server socket tainted after throwing %llu bytes away.", buffered_request_bytes - csp->expected_client_content_length); csp->expected_client_content_length = 0; csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } if (csp->expected_client_content_length == 0) { csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; } } if (!(csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ) && ((csp->client_iob->cur < csp->client_iob->eod) || (csp->expected_client_content_length != 0))) { if (strcmpic(csp->http->gpc, "GET") && strcmpic(csp->http->gpc, "HEAD") && strcmpic(csp->http->gpc, "TRACE") && strcmpic(csp->http->gpc, "OPTIONS") && strcmpic(csp->http->gpc, "DELETE")) { /* XXX: this is an incomplete hack */ csp->flags &= ~CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; log_error(LOG_LEVEL_CONNECT, "There better be a request body."); } else { csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; if ((csp->config->feature_flags & RUNTIME_FEATURE_TOLERATE_PIPELINING) == 0) { csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; log_error(LOG_LEVEL_CONNECT, "Possible pipeline attempt detected. The connection will not " "be kept alive and we will only serve the first request."); /* Nuke the pipelined requests from orbit, just to be sure. */ clear_iob(csp->client_iob); } else { /* * Keep the pipelined data around for now, we'll deal with * it once we're done serving the current request. */ csp->flags |= CSP_FLAG_PIPELINED_REQUEST_WAITING; assert(csp->client_iob->eod >= csp->client_iob->cur); log_error(LOG_LEVEL_CONNECT, "Complete client request followed by " "%d bytes of pipelined data received.", (int)(csp->client_iob->eod - csp->client_iob->cur)); } } } else { csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; log_error(LOG_LEVEL_CONNECT, "Complete client request received."); } } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : mark_server_socket_tainted * * Description : Makes sure we don't reuse a server socket * (if we didn't read everything the server sent * us reusing the socket would lead to garbage). * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : void. * *********************************************************************/ static void mark_server_socket_tainted(struct client_state *csp) { /* * For consistency we always mark the server socket * tainted, however, to reduce the log noise we only * emit a log message if the server socket could have * actually been reused. */ if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_CONNECT, "Marking the server socket %d tainted.", csp->server_connection.sfd); } csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } /********************************************************************* * * Function : get_request_line * * Description : Read the client request line. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : Pointer to request line or NULL in case of errors. * *********************************************************************/ static char *get_request_line(struct client_state *csp) { char buf[BUFFER_SIZE]; char *request_line = NULL; int len; memset(buf, 0, sizeof(buf)); if ((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) != 0) { /* * If there are multiple pipelined requests waiting, * the flag will be set again once the next request * has been parsed. */ csp->flags &= ~CSP_FLAG_PIPELINED_REQUEST_WAITING; request_line = get_header(csp->client_iob); if ((NULL != request_line) && ('\0' != *request_line)) { return request_line; } else { log_error(LOG_LEVEL_CONNECT, "No complete request line " "received yet. Continuing reading from %d.", csp->cfd); } } do { if (!data_is_available(csp->cfd, csp->config->socket_timeout)) { if (socket_is_still_alive(csp->cfd)) { log_error(LOG_LEVEL_CONNECT, "No request line on socket %d received in time. Timeout: %d.", csp->cfd, csp->config->socket_timeout); write_socket(csp->cfd, CLIENT_CONNECTION_TIMEOUT_RESPONSE, strlen(CLIENT_CONNECTION_TIMEOUT_RESPONSE)); } else { log_error(LOG_LEVEL_CONNECT, "The client side of the connection on socket %d got " "closed without sending a complete request line.", csp->cfd); } return NULL; } len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) return NULL; /* * If there is no memory left for buffering the * request, there is nothing we can do but hang up */ if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len)) { return NULL; } request_line = get_header(csp->client_iob); } while ((NULL != request_line) && ('\0' == *request_line)); return request_line; } enum chunk_status { CHUNK_STATUS_MISSING_DATA, CHUNK_STATUS_BODY_COMPLETE, CHUNK_STATUS_PARSE_ERROR }; /********************************************************************* * * Function : chunked_body_is_complete * * Description : Figures out wheter or not a chunked body is complete. * * Currently it always starts at the beginning of the * buffer which is somewhat wasteful and prevents Privoxy * from starting to forward the correctly parsed chunks * as soon as theoretically possible. * * Should be modified to work with a common buffer, * and allow the caller to skip already parsed chunks. * * This would allow the function to be used for unbuffered * response bodies as well. * * Parameters : * 1 : iob = Buffer with the body to check. * 2 : length = Length of complete body * * Returns : Enum with the result of the check. * *********************************************************************/ static enum chunk_status chunked_body_is_complete(struct iob *iob, size_t *length) { unsigned int chunksize; char *p = iob->cur; do { /* * We need at least a single digit, followed by "\r\n", * followed by an unknown amount of data, followed by "\r\n". */ if (p + 5 > iob->eod) { return CHUNK_STATUS_MISSING_DATA; } if (sscanf(p, "%x", &chunksize) != 1) { return CHUNK_STATUS_PARSE_ERROR; } /* * We want at least a single digit, followed by "\r\n", * followed by the specified amount of data, followed by "\r\n". */ if (p + chunksize + 5 > iob->eod) { return CHUNK_STATUS_MISSING_DATA; } /* Skip chunk-size. */ p = strstr(p, "\r\n"); if (NULL == p) { return CHUNK_STATUS_PARSE_ERROR; } /* * Skip "\r\n", the chunk data and another "\r\n". * Moving p to either the beginning of the next chunk-size * or one byte beyond the end of the chunked data. */ p += 2 + chunksize + 2; } while (chunksize > 0U); *length = (size_t)(p - iob->cur); assert(*length <= (size_t)(iob->eod - iob->cur)); assert(p <= iob->eod); return CHUNK_STATUS_BODY_COMPLETE; } /********************************************************************* * * Function : receive_chunked_client_request_body * * Description : Read the chunk-encoded client request body. * Failures are dealt with. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK or JB_ERR_PARSE * *********************************************************************/ static jb_err receive_chunked_client_request_body(struct client_state *csp) { size_t body_length; enum chunk_status status; while (CHUNK_STATUS_MISSING_DATA == (status = chunked_body_is_complete(csp->client_iob,&body_length))) { char buf[BUFFER_SIZE]; int len; if (!data_is_available(csp->cfd, csp->config->socket_timeout)) { log_error(LOG_LEVEL_ERROR, "Timeout while waiting for the client body."); break; } len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { log_error(LOG_LEVEL_ERROR, "Read the client body failed: %E"); break; } if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len)) { break; } } if (status != CHUNK_STATUS_BODY_COMPLETE) { write_socket(csp->cfd, CLIENT_BODY_PARSE_ERROR_RESPONSE, strlen(CLIENT_BODY_PARSE_ERROR_RESPONSE)); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Failed reading chunked client body\" 400 0", csp->ip_addr_str); return JB_ERR_PARSE; } log_error(LOG_LEVEL_CONNECT, "Chunked client body completely read. Length: %d", body_length); csp->expected_client_content_length = body_length; return JB_ERR_OK; } /********************************************************************* * * Function : receive_client_request * * Description : Read the client's request (more precisely the * client headers) and answer it if necessary. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK, JB_ERR_PARSE or JB_ERR_MEMORY * *********************************************************************/ static jb_err receive_client_request(struct client_state *csp) { char buf[BUFFER_SIZE]; char *p; char *req = NULL; struct http_request *http; int len; jb_err err; /* Temporary copy of the client's headers before they get enlisted in csp->headers */ struct list header_list; struct list *headers = &header_list; /* We don't care if the arriving data is a valid HTTP request or not. */ csp->requests_received_total++; http = csp->http; memset(buf, 0, sizeof(buf)); req = get_request_line(csp); if (req == NULL) { mark_server_socket_tainted(csp); return JB_ERR_PARSE; } assert(*req != '\0'); if (client_protocol_is_unsupported(csp, req)) { return JB_ERR_PARSE; } #ifdef FEATURE_FORCE_LOAD /* * If this request contains the FORCE_PREFIX and blocks * aren't enforced, get rid of it and set the force flag. */ if (strstr(req, FORCE_PREFIX)) { if (csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS) { log_error(LOG_LEVEL_FORCE, "Ignored force prefix in request: \"%s\".", req); } else { strclean(req, FORCE_PREFIX); log_error(LOG_LEVEL_FORCE, "Enforcing request: \"%s\".", req); csp->flags |= CSP_FLAG_FORCED; } } #endif /* def FEATURE_FORCE_LOAD */ err = parse_http_request(req, http); freez(req); if (JB_ERR_OK != err) { write_socket(csp->cfd, CHEADER, strlen(CHEADER)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, "Couldn't parse request line received from %s: %s", csp->ip_addr_str, jb_err_to_string(err)); free_http_request(http); return JB_ERR_PARSE; } /* grab the rest of the client's headers */ init_list(headers); for (;;) { p = get_header(csp->client_iob); if (p == NULL) { /* There are no additional headers to read. */ break; } if (*p == '\0') { /* * We didn't receive a complete header * line yet, get the rest of it. */ if (!data_is_available(csp->cfd, csp->config->socket_timeout)) { log_error(LOG_LEVEL_ERROR, "Stopped grabbing the client headers."); destroy_list(headers); return JB_ERR_PARSE; } len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { log_error(LOG_LEVEL_ERROR, "read from client failed: %E"); destroy_list(headers); return JB_ERR_PARSE; } if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len)) { /* * If there is no memory left for buffering the * request, there is nothing we can do but hang up */ destroy_list(headers); return JB_ERR_MEMORY; } } else { if (!strncmpic(p, "Transfer-Encoding:", 18)) { /* * XXX: should be called through sed() * but currently can't. */ client_transfer_encoding(csp, &p); } /* * We were able to read a complete * header and can finally enlist it. */ enlist(headers, p); freez(p); } } if (http->host == NULL) { /* * If we still don't know the request destination, * the request is invalid or the client uses * Privoxy without its knowledge. */ if (JB_ERR_OK != get_request_destination_elsewhere(csp, headers)) { /* * Our attempts to get the request destination * elsewhere failed or Privoxy is configured * to only accept proxy requests. * * An error response has already been send * and we're done here. */ return JB_ERR_PARSE; } } /* * Determine the actions for this URL */ #ifdef FEATURE_TOGGLE if (!(csp->flags & CSP_FLAG_TOGGLED_ON)) { /* Most compatible set of actions (i.e. none) */ init_current_action(csp->action); } else #endif /* ndef FEATURE_TOGGLE */ { get_url_actions(csp, http); } /* * Save a copy of the original request for logging */ http->ocmd = strdup_or_die(http->cmd); enlist(csp->headers, http->cmd); /* Append the previously read headers */ list_append_list_unique(csp->headers, headers); destroy_list(headers); return JB_ERR_OK; } /********************************************************************* * * Function : parse_client_request * * Description : Parses the client's request and decides what to do * with it. * * Note that since we're not using select() we could get * blocked here if a client connected, then didn't say * anything! * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_ERR_OK or JB_ERR_PARSE * *********************************************************************/ static jb_err parse_client_request(struct client_state *csp) { struct http_request *http = csp->http; jb_err err; #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && (!strcmpic(csp->http->ver, "HTTP/1.1")) && (csp->http->ssl == 0)) { /* Assume persistence until further notice */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } if (csp->http->ssl == 0) { /* * This whole block belongs to chat() but currently * has to be executed before sed(). */ if (csp->flags & CSP_FLAG_CHUNKED_CLIENT_BODY) { if (receive_chunked_client_request_body(csp) != JB_ERR_OK) { return JB_ERR_PARSE; } } else { csp->expected_client_content_length = get_expected_content_length(csp->headers); } verify_request_length(csp); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ err = sed(csp, FILTER_CLIENT_HEADERS); if (JB_ERR_OK != err) { /* XXX: Should be handled in sed(). */ assert(err == JB_ERR_PARSE); log_error(LOG_LEVEL_FATAL, "Failed to parse client headers."); } csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE; /* Check request line for rewrites. */ if ((NULL == csp->headers->first->str) || (strcmp(http->cmd, csp->headers->first->str) && (JB_ERR_OK != change_request_destination(csp)))) { /* * A header filter broke the request line - bail out. */ write_socket(csp->cfd, MESSED_UP_REQUEST_RESPONSE, strlen(MESSED_UP_REQUEST_RESPONSE)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request generated\" 500 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, "Invalid request line after applying header filters."); free_http_request(http); return JB_ERR_PARSE; } return JB_ERR_OK; } /********************************************************************* * * Function : chat * * Description : Once a connection from the client has been accepted, * this function is called (via serve()) to handle the * main business of the communication. This function * returns after dealing with a single request. It can * be called multiple times with the same client socket * if the client is keeping the connection alive. * * The decision whether or not a client connection will * be kept alive is up to the caller which also must * close the client socket when done. * * FIXME: chat is nearly thousand lines long. * Ridiculous. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : Nothing. * *********************************************************************/ static void chat(struct client_state *csp) { char buf[BUFFER_SIZE]; char *hdr; char *p; fd_set rfds; int n; jb_socket maxfd; int server_body; int ms_iis5_hack = 0; unsigned long long byte_count = 0; const struct forward_spec *fwd; struct http_request *http; long len = 0; /* for buffer sizes (and negative error codes) */ int buffer_and_filter_content = 0; /* Skeleton for HTTP response, if we should intercept the request */ struct http_response *rsp; struct timeval timeout; #ifdef FEATURE_CONNECTION_KEEP_ALIVE int watch_client_socket; #endif memset(buf, 0, sizeof(buf)); http = csp->http; if (receive_client_request(csp) != JB_ERR_OK) { return; } if (parse_client_request(csp) != JB_ERR_OK) { return; } /* decide how to route the HTTP request */ fwd = forward_url(csp, http); if (NULL == fwd) { log_error(LOG_LEVEL_FATAL, "gateway spec is NULL!?!? This can't happen!"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ return; } /* * build the http request to send to the server * we have to do one of the following: * * create = use the original HTTP request to create a new * HTTP request that has either the path component * without the http://domainspec (w/path) or the * full orininal URL (w/url) * Note that the path and/or the HTTP version may * have been altered by now. * * connect = Open a socket to the host:port of the server * and short-circuit server and client socket. * * pass = Pass the request unchanged if forwarding a CONNECT * request to a parent proxy. Note that we'll be sending * the CFAIL message ourselves if connecting to the parent * fails, but we won't send a CSUCCEED message if it works, * since that would result in a double message (ours and the * parent's). After sending the request to the parent, we simply * tunnel. * * here's the matrix: * SSL * 0 1 * +--------+--------+ * | | | * 0 | create | connect| * | w/path | | * Forwarding +--------+--------+ * | | | * 1 | create | pass | * | w/url | | * +--------+--------+ * */ if (http->ssl && connect_port_is_forbidden(csp)) { const char *acceptable_connect_ports = csp->action->string[ACTION_STRING_LIMIT_CONNECT]; assert(NULL != acceptable_connect_ports); log_error(LOG_LEVEL_INFO, "Request from %s marked for blocking. " "limit-connect{%s} doesn't allow CONNECT requests to %s", csp->ip_addr_str, acceptable_connect_ports, csp->http->hostport); csp->action->flags |= ACTION_BLOCK; http->ssl = 0; } if (http->ssl == 0) { freez(csp->headers->first->str); build_request_line(csp, fwd, &csp->headers->first->str); } /* * We have a request. Check if one of the crunchers wants it. */ if (crunch_response_triggered(csp, crunchers_all)) { /* * Yes. The client got the crunch response and we're done here. */ return; } log_applied_actions(csp->action); log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path); if (fwd->forward_host) { log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s", fwd->forward_host, fwd->forward_port, http->hostport); } else { log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport); } /* here we connect to the server, gateway, or the forwarder */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->server_connection.sfd != JB_INVALID_SOCKET) && socket_is_still_alive(csp->server_connection.sfd) && connection_destination_matches(&csp->server_connection, http, fwd)) { log_error(LOG_LEVEL_CONNECT, "Reusing server socket %d connected to %s. Total requests: %u.", csp->server_connection.sfd, csp->server_connection.host, csp->server_connection.requests_sent_total); } else { if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) { remember_connection(&csp->server_connection); } else #endif /* def FEATURE_CONNECTION_SHARING */ { log_error(LOG_LEVEL_CONNECT, "Closing server socket %d connected to %s. Total requests: %u.", csp->server_connection.sfd, csp->server_connection.host, csp->server_connection.requests_sent_total); close_socket(csp->server_connection.sfd); } mark_connection_closed(&csp->server_connection); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ csp->server_connection.sfd = forwarded_connect(fwd, http, csp); if (csp->server_connection.sfd == JB_INVALID_SOCKET) { if (fwd->type != SOCKS_NONE) { /* Socks error. */ rsp = error_response(csp, "forwarding-failed"); } else if (errno == EINVAL) { rsp = error_response(csp, "no-such-domain"); } else { rsp = error_response(csp, "connect-failed"); } /* Write the answer to the client */ if (rsp != NULL) { send_crunch_response(csp, rsp); } return; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE save_connection_destination(csp->server_connection.sfd, http, fwd, &csp->server_connection); csp->server_connection.keep_alive_timeout = (unsigned)csp->config->keep_alive_timeout; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ csp->server_connection.requests_sent_total++; if ((fwd->type == SOCKS_5T) && (NULL == csp->headers->first)) { /* Client headers have been sent optimistically */ assert(csp->headers->last == NULL); } else if (fwd->forward_host || (http->ssl == 0)) { int write_failure; hdr = list_to_text(csp->headers); if (hdr == NULL) { /* FIXME Should handle error properly */ log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header"); } list_remove_all(csp->headers); /* * Write the client's (modified) header to the server * (along with anything else that may be in the buffer) */ write_failure = 0 != write_socket(csp->server_connection.sfd, hdr, strlen(hdr)); freez(hdr); if (write_failure) { log_error(LOG_LEVEL_CONNECT, "Failed sending request headers to: %s: %E", http->hostport); } else if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0) && (flush_socket(csp->server_connection.sfd, csp->client_iob) < 0)) { write_failure = 1; log_error(LOG_LEVEL_CONNECT, "Failed sending request body to: %s: %E", http->hostport); } if (write_failure) { rsp = error_response(csp, "connect-failed"); if (rsp) { send_crunch_response(csp, rsp); } return; } } else { /* * We're running an SSL tunnel and we're not forwarding, * so just ditch the client headers, send the "connect succeeded" * message to the client, flush the rest, and get out of the way. */ list_remove_all(csp->headers); if (write_socket(csp->cfd, CSUCCEED, strlen(CSUCCEED))) { return; } clear_iob(csp->client_iob); } log_error(LOG_LEVEL_CONNECT, "to %s successful", http->hostport); /* XXX: should the time start earlier for optimistically sent data? */ csp->server_connection.request_sent = time(NULL); maxfd = (csp->cfd > csp->server_connection.sfd) ? csp->cfd : csp->server_connection.sfd; /* pass data between the client and server * until one or the other shuts down the connection. */ server_body = 0; #ifdef FEATURE_CONNECTION_KEEP_ALIVE watch_client_socket = 0 == (csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING); #endif for (;;) { #ifdef __OS2__ /* * FD_ZERO here seems to point to an errant macro which crashes. * So do this by hand for now... */ memset(&rfds,0x00,sizeof(fd_set)); #else FD_ZERO(&rfds); #endif #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (!watch_client_socket) { maxfd = csp->server_connection.sfd; } else #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ { FD_SET(csp->cfd, &rfds); } FD_SET(csp->server_connection.sfd, &rfds); #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->flags & CSP_FLAG_CHUNKED) && !(csp->flags & CSP_FLAG_CONTENT_LENGTH_SET) && ((csp->iob->eod - csp->iob->cur) >= 5) && !memcmp(csp->iob->eod-5, "0\r\n\r\n", 5)) { /* * XXX: This check should be obsolete now, * but let's wait a while to be sure. */ log_error(LOG_LEVEL_CONNECT, "Looks like we got the last chunk together with " "the server headers but didn't detect it earlier. " "We better stop reading."); byte_count = (unsigned long long)(csp->iob->eod - csp->iob->cur); csp->expected_content_length = byte_count; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; } if (server_body && server_response_is_complete(csp, byte_count)) { if (csp->expected_content_length == byte_count) { log_error(LOG_LEVEL_CONNECT, "Done reading from server. Content length: %llu as expected. " "Bytes most recently read: %d.", byte_count, len); } else { log_error(LOG_LEVEL_CONNECT, "Done reading from server. Expected content length: %llu. " "Actual content length: %llu. Bytes most recently read: %d.", csp->expected_content_length, byte_count, len); } len = 0; /* * XXX: should not jump around, * chat() is complicated enough already. */ goto reading_done; } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ timeout.tv_sec = csp->config->socket_timeout; timeout.tv_usec = 0; n = select((int)maxfd+1, &rfds, NULL, NULL, &timeout); if (n == 0) { log_error(LOG_LEVEL_ERROR, "Didn't receive data in time: %s", http->url); if ((byte_count == 0) && (http->ssl == 0)) { send_crunch_response(csp, error_response(csp, "connection-timeout")); } mark_server_socket_tainted(csp); return; } else if (n < 0) { log_error(LOG_LEVEL_ERROR, "select() failed!: %E"); mark_server_socket_tainted(csp); return; } /* * This is the body of the browser's request, * just read and write it. * * XXX: Make sure the client doesn't use pipelining * behind Privoxy's back. */ if (FD_ISSET(csp->cfd, &rfds)) { int max_bytes_to_read = sizeof(buf) - 1; #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ)) { if (data_is_available(csp->cfd, 0)) { /* * If the next request is already waiting, we have * to stop select()ing the client socket. Otherwise * we would always return right away and get nothing * else done. */ watch_client_socket = 0; log_error(LOG_LEVEL_CONNECT, "Stopping to watch the client socket %d. " "There's already another request waiting.", csp->cfd); continue; } /* * If the client socket is set, but there's no data * available on the socket, the client went fishing * and continuing talking to the server makes no sense. */ log_error(LOG_LEVEL_CONNECT, "The client closed socket %d while " "the server socket %d is still open.", csp->cfd, csp->server_connection.sfd); mark_server_socket_tainted(csp); break; } if (csp->expected_client_content_length != 0) { if (csp->expected_client_content_length < (sizeof(buf) - 1)) { max_bytes_to_read = (int)csp->expected_client_content_length; } log_error(LOG_LEVEL_CONNECT, "Waiting for up to %d bytes from the client.", max_bytes_to_read); } assert(max_bytes_to_read < sizeof(buf)); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ len = read_socket(csp->cfd, buf, max_bytes_to_read); if (len <= 0) { /* XXX: not sure if this is necessary. */ mark_server_socket_tainted(csp); break; /* "game over, man" */ } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (csp->expected_client_content_length != 0) { assert(len <= max_bytes_to_read); csp->expected_client_content_length -= (unsigned)len; log_error(LOG_LEVEL_CONNECT, "Expected client content length set to %llu " "after reading %d bytes.", csp->expected_client_content_length, len); if (csp->expected_client_content_length == 0) { log_error(LOG_LEVEL_CONNECT, "Done reading from the client."); csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; } } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ if (write_socket(csp->server_connection.sfd, buf, (size_t)len)) { log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host); mark_server_socket_tainted(csp); return; } continue; } /* * The server wants to talk. It could be the header or the body. * If `hdr' is null, then it's the header otherwise it's the body. * FIXME: Does `hdr' really mean `host'? No. */ if (FD_ISSET(csp->server_connection.sfd, &rfds)) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE /* * If we are buffering content, we don't want to eat up to * buffer-limit bytes if the client no longer cares about them. * If we aren't buffering, however, a dead client socket will be * noticed pretty much right away anyway, so we can reduce the * overhead by skipping the check. */ if (buffer_and_filter_content && !socket_is_still_alive(csp->cfd)) { #ifdef _WIN32 log_error(LOG_LEVEL_CONNECT, "The server still wants to talk, but the client may already have hung up on us."); #else log_error(LOG_LEVEL_CONNECT, "The server still wants to talk, but the client hung up on us."); mark_server_socket_tainted(csp); return; #endif /* def _WIN32 */ } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ len = read_socket(csp->server_connection.sfd, buf, sizeof(buf) - 1); if (len < 0) { log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host); if (http->ssl && (fwd->forward_host == NULL)) { /* * Just hang up. We already confirmed the client's CONNECT * request with status code 200 and unencrypted content is * no longer welcome. */ log_error(LOG_LEVEL_ERROR, "CONNECT already confirmed. Unable to tell the client about the problem."); return; } else if (byte_count) { /* * Just hang up. We already transmitted the original headers * and parts of the original content and therefore missed the * chance to send an error message (without risking data corruption). * * XXX: we could retry with a fancy range request here. */ log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. " "Unable to tell the client about the problem."); mark_server_socket_tainted(csp); return; } /* * XXX: Consider handling the cases above the same. */ mark_server_socket_tainted(csp); len = 0; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (csp->flags & CSP_FLAG_CHUNKED) { if ((len >= 5) && !memcmp(buf+len-5, "0\r\n\r\n", 5)) { /* XXX: this is a temporary hack */ log_error(LOG_LEVEL_CONNECT, "Looks like we reached the end of the last chunk. " "We better stop reading."); csp->expected_content_length = byte_count + (unsigned long long)len; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; } } reading_done: #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ /* * Add a trailing zero to let be able to use string operations. * XXX: do we still need this with filter_popups gone? */ buf[len] = '\0'; /* * Normally, this would indicate that we've read * as much as the server has sent us and we can * close the client connection. However, Microsoft * in its wisdom has released IIS/5 with a bug that * prevents it from sending the trailing \r\n in * a 302 redirect header (and possibly other headers). * To work around this if we've haven't parsed * a full header we'll append a trailing \r\n * and see if this now generates a valid one. * * This hack shouldn't have any impacts. If we've * already transmitted the header or if this is a * SSL connection, then we won't bother with this * hack. So we only work on partially received * headers. If we append a \r\n and this still * doesn't generate a valid header, then we won't * transmit anything to the client. */ if (len == 0) { if (server_body || http->ssl) { /* * If we have been buffering up the document, * now is the time to apply content modification * and send the result to the client. */ if (buffer_and_filter_content) { p = execute_content_filters(csp); /* * If content filtering fails, use the original * buffer and length. * (see p != NULL ? p : csp->iob->cur below) */ if (NULL == p) { csp->content_length = (size_t)(csp->iob->eod - csp->iob->cur); } #ifdef FEATURE_COMPRESSION else if ((csp->flags & CSP_FLAG_CLIENT_SUPPORTS_DEFLATE) && (csp->content_length > LOWER_LENGTH_LIMIT_FOR_COMPRESSION)) { char *compressed_content = compress_buffer(p, (size_t *)&csp->content_length, csp->config->compression_level); if (compressed_content != NULL) { freez(p); p = compressed_content; csp->flags |= CSP_FLAG_BUFFERED_CONTENT_DEFLATED; } } #endif if (JB_ERR_OK != update_server_headers(csp)) { log_error(LOG_LEVEL_FATAL, "Failed to update server headers. after filtering."); } hdr = list_to_text(csp->headers); if (hdr == NULL) { /* FIXME Should handle error properly */ log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } if (write_socket(csp->cfd, hdr, strlen(hdr)) || write_socket(csp->cfd, ((p != NULL) ? p : csp->iob->cur), (size_t)csp->content_length)) { log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E"); freez(hdr); freez(p); mark_server_socket_tainted(csp); return; } freez(hdr); freez(p); } break; /* "game over, man" */ } /* * This is NOT the body, so * Let's pretend the server just sent us a blank line. */ snprintf(buf, sizeof(buf), "\r\n"); len = (int)strlen(buf); /* * Now, let the normal header parsing algorithm below do its * job. If it fails, we'll exit instead of continuing. */ ms_iis5_hack = 1; } /* * If this is an SSL connection or we're in the body * of the server document, just write it to the client, * unless we need to buffer the body for later content-filtering */ if (server_body || http->ssl) { if (buffer_and_filter_content) { /* * If there is no memory left for buffering the content, or the buffer limit * has been reached, switch to non-filtering mode, i.e. make & write the * header, flush the iob and buf, and get out of the way. */ if (add_to_iob(csp->iob, csp->config->buffer_limit, buf, len)) { size_t hdrlen; long flushed; log_error(LOG_LEVEL_INFO, "Flushing header and buffers. Stepping back from filtering."); hdr = list_to_text(csp->headers); if (hdr == NULL) { /* * Memory is too tight to even generate the header. * Send our static "Out-of-memory" page. */ log_error(LOG_LEVEL_ERROR, "Out of memory while trying to flush."); rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); return; } hdrlen = strlen(hdr); if (write_socket(csp->cfd, hdr, hdrlen) || ((flushed = flush_socket(csp->cfd, csp->iob)) < 0) || (write_socket(csp->cfd, buf, (size_t)len))) { log_error(LOG_LEVEL_CONNECT, "Flush header and buffers to client failed: %E"); freez(hdr); mark_server_socket_tainted(csp); return; } /* * Reset the byte_count to the amount of bytes * we just flushed. len will be added a few lines below, * hdrlen doesn't matter for LOG_LEVEL_CLF. */ byte_count = (unsigned long long)flushed; freez(hdr); buffer_and_filter_content = 0; server_body = 1; } } else { if (write_socket(csp->cfd, buf, (size_t)len)) { log_error(LOG_LEVEL_ERROR, "write to client failed: %E"); mark_server_socket_tainted(csp); return; } } byte_count += (unsigned long long)len; continue; } else { /* * We're still looking for the end of the server's header. * Buffer up the data we just read. If that fails, there's * little we can do but send our static out-of-memory page. */ if (add_to_iob(csp->iob, csp->config->buffer_limit, buf, len)) { log_error(LOG_LEVEL_ERROR, "Out of memory while looking for end of server headers."); rsp = cgi_error_memory(); send_crunch_response(csp, rsp); mark_server_socket_tainted(csp); return; } /* Convert iob into something sed() can digest */ if (JB_ERR_PARSE == get_server_headers(csp)) { if (ms_iis5_hack) { /* * Well, we tried our MS IIS/5 hack and it didn't work. * The header is incomplete and there isn't anything * we can do about it. */ log_error(LOG_LEVEL_ERROR, "Invalid server headers. " "Applying the MS IIS5 hack didn't help."); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE)); mark_server_socket_tainted(csp); return; } else { /* * Since we have to wait for more from the server before * we can parse the headers we just continue here. */ log_error(LOG_LEVEL_CONNECT, "Continuing buffering server headers from socket %d. " "Bytes most recently read: %d.", csp->cfd, len); continue; } } else { /* * Account for the content bytes we * might have gotten with the headers. */ assert(csp->iob->eod >= csp->iob->cur); byte_count = (unsigned long long)(csp->iob->eod - csp->iob->cur); } /* Did we actually get anything? */ if (NULL == csp->headers->first) { if ((csp->flags & CSP_FLAG_REUSED_CLIENT_CONNECTION)) { log_error(LOG_LEVEL_ERROR, "No server or forwarder response received on socket %d. " "Closing client socket %d without sending data.", csp->server_connection.sfd, csp->cfd); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); } else { log_error(LOG_LEVEL_ERROR, "No server or forwarder response received on socket %d.", csp->server_connection.sfd); send_crunch_response(csp, error_response(csp, "no-server-data")); } free_http_request(http); mark_server_socket_tainted(csp); return; } assert(csp->headers->first->str); assert(!http->ssl); if (strncmpic(csp->headers->first->str, "HTTP", 4) && strncmpic(csp->headers->first->str, "ICY", 3)) { /* * It doesn't look like a HTTP (or Shoutcast) response: * tell the client and log the problem. */ if (strlen(csp->headers->first->str) > 30) { csp->headers->first->str[30] = '\0'; } log_error(LOG_LEVEL_ERROR, "Invalid server or forwarder response. Starts with: %s", csp->headers->first->str); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE)); free_http_request(http); mark_server_socket_tainted(csp); return; } /* * We have now received the entire server header, * filter it and send the result to the client */ if (JB_ERR_OK != sed(csp, FILTER_SERVER_HEADERS)) { log_error(LOG_LEVEL_FATAL, "Failed to parse server headers."); } hdr = list_to_text(csp->headers); if (hdr == NULL) { /* FIXME Should handle error properly */ log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } if ((csp->flags & CSP_FLAG_CHUNKED) && !(csp->flags & CSP_FLAG_CONTENT_LENGTH_SET) && ((csp->iob->eod - csp->iob->cur) >= 5) && !memcmp(csp->iob->eod-5, "0\r\n\r\n", 5)) { log_error(LOG_LEVEL_CONNECT, "Looks like we got the last chunk together with " "the server headers. We better stop reading."); byte_count = (unsigned long long)(csp->iob->eod - csp->iob->cur); csp->expected_content_length = byte_count; csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET; } csp->server_connection.response_received = time(NULL); if (crunch_response_triggered(csp, crunchers_light)) { /* * One of the tags created by a server-header * tagger triggered a crunch. We already * delivered the crunch response to the client * and are done here after cleaning up. */ freez(hdr); mark_server_socket_tainted(csp); return; } /* Buffer and pcrs filter this if appropriate. */ if (!http->ssl) /* We talk plaintext */ { buffer_and_filter_content = content_requires_filtering(csp); } /* * Only write if we're not buffering for content modification */ if (!buffer_and_filter_content) { /* * Write the server's (modified) header to * the client (along with anything else that * may be in the buffer) */ if (write_socket(csp->cfd, hdr, strlen(hdr)) || ((len = flush_socket(csp->cfd, csp->iob)) < 0)) { log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E"); /* * The write failed, so don't bother mentioning it * to the client... it probably can't hear us anyway. */ freez(hdr); mark_server_socket_tainted(csp); return; } } /* we're finished with the server's header */ freez(hdr); server_body = 1; /* * If this was a MS IIS/5 hack then it means the server * has already closed the connection. Nothing more to read. * Time to bail. */ if (ms_iis5_hack) { log_error(LOG_LEVEL_ERROR, "Closed server connection detected. " "Applying the MS IIS5 hack didn't help."); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, strlen(INVALID_SERVER_HEADERS_RESPONSE)); mark_server_socket_tainted(csp); return; } } continue; } mark_server_socket_tainted(csp); return; /* huh? we should never get here */ } if (csp->content_length == 0) { /* * If Privoxy didn't recalculate the Content-Length, * byte_count is still correct. */ csp->content_length = byte_count; } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->flags & CSP_FLAG_CONTENT_LENGTH_SET) && (csp->expected_content_length != byte_count)) { log_error(LOG_LEVEL_CONNECT, "Received %llu bytes while expecting %llu.", byte_count, csp->expected_content_length); mark_server_socket_tainted(csp); } #endif log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %llu", csp->ip_addr_str, http->ocmd, csp->content_length); csp->server_connection.timestamp = time(NULL); } #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : prepare_csp_for_next_request * * Description : Put the csp in a mostly vergin state. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : N/A * *********************************************************************/ static void prepare_csp_for_next_request(struct client_state *csp) { unsigned int toggled_on_flag_set = (0 != (csp->flags & CSP_FLAG_TOGGLED_ON)); csp->content_type = 0; csp->content_length = 0; csp->expected_content_length = 0; csp->expected_client_content_length = 0; list_remove_all(csp->headers); clear_iob(csp->iob); freez(csp->error_message); free_http_request(csp->http); destroy_list(csp->headers); destroy_list(csp->tags); free_current_action(csp->action); if (NULL != csp->fwd) { unload_forward_spec(csp->fwd); csp->fwd = NULL; } /* XXX: Store per-connection flags someplace else. */ csp->flags = (CSP_FLAG_ACTIVE | CSP_FLAG_REUSED_CLIENT_CONNECTION); if (toggled_on_flag_set) { csp->flags |= CSP_FLAG_TOGGLED_ON; } if (csp->client_iob->eod > csp->client_iob->cur) { long bytes_to_shift = csp->client_iob->cur - csp->client_iob->buf; size_t data_length = (size_t)(csp->client_iob->eod - csp->client_iob->cur); assert(bytes_to_shift > 0); assert(data_length > 0); log_error(LOG_LEVEL_CONNECT, "Shifting %d pipelined bytes by %d bytes", data_length, bytes_to_shift); memmove(csp->client_iob->buf, csp->client_iob->cur, data_length); csp->client_iob->cur = csp->client_iob->buf; assert(csp->client_iob->eod == csp->client_iob->buf + bytes_to_shift + data_length); csp->client_iob->eod = csp->client_iob->buf + data_length; memset(csp->client_iob->eod, '\0', (size_t)bytes_to_shift); csp->flags |= CSP_FLAG_PIPELINED_REQUEST_WAITING; } else { /* * We mainly care about resetting client_iob->cur so we don't * waste buffer space at the beginning and don't mess up the * request restoration done by cgi_show_request(). * * Freeing the buffer itself isn't technically necessary, * but makes debugging more convenient. */ clear_iob(csp->client_iob); } } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ /********************************************************************* * * Function : serve * * Description : This is little more than chat. We only "serve" to * to close (or remember) any socket that chat may have * opened. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : N/A * *********************************************************************/ #ifdef AMIGA void serve(struct client_state *csp) #else /* ifndef AMIGA */ static void serve(struct client_state *csp) #endif /* def AMIGA */ { int config_file_change_detected = 0; /* Only used for debugging */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE #ifdef FEATURE_CONNECTION_SHARING static int monitor_thread_running = 0; #endif /* def FEATURE_CONNECTION_SHARING */ int continue_chatting = 0; log_error(LOG_LEVEL_CONNECT, "Accepted connection from %s on socket %d", csp->ip_addr_str, csp->cfd); do { unsigned int latency; chat(csp); /* * If the request has been crunched, * the calculated latency is zero. */ latency = (unsigned)(csp->server_connection.response_received - csp->server_connection.request_sent) / 2; if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && (csp->flags & CSP_FLAG_CRUNCHED) && (csp->expected_client_content_length != 0)) { csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; log_error(LOG_LEVEL_CONNECT, "Tainting client socket %d due to unread data.", csp->cfd); } continue_chatting = (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && (csp->cfd != JB_INVALID_SOCKET) && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && ((csp->flags & CSP_FLAG_SERVER_CONTENT_LENGTH_SET) || (csp->flags & CSP_FLAG_CHUNKED)); if (!(csp->flags & CSP_FLAG_CRUNCHED) && (csp->server_connection.sfd != JB_INVALID_SOCKET)) { if (!(csp->flags & CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET)) { csp->server_connection.keep_alive_timeout = csp->config->default_server_timeout; } if (!(csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) || (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) || !socket_is_still_alive(csp->server_connection.sfd) || !(latency < csp->server_connection.keep_alive_timeout)) { log_error(LOG_LEVEL_CONNECT, "Closing server socket %d connected to %s. " "Keep-alive %u. Tainted: %u. Socket alive %u. Timeout: %u.", csp->server_connection.sfd, csp->server_connection.host, 0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE), 0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED), socket_is_still_alive(csp->server_connection.sfd), csp->server_connection.keep_alive_timeout); #ifdef FEATURE_CONNECTION_SHARING if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) { forget_connection(csp->server_connection.sfd); } #endif /* def FEATURE_CONNECTION_SHARING */ close_socket(csp->server_connection.sfd); mark_connection_closed(&csp->server_connection); } } if (continue_chatting && any_loaded_file_changed(csp)) { continue_chatting = 0; config_file_change_detected = 1; } if (continue_chatting) { if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) != 0) && socket_is_still_alive(csp->cfd)) { log_error(LOG_LEVEL_CONNECT, "Client request %d has been " "pipelined on socket %d and the socket is still alive.", csp->requests_received_total+1, csp->cfd); prepare_csp_for_next_request(csp); continue; } if (0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)) { if (csp->server_connection.sfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, "Waiting for the next client request on socket %d. " "Keeping the server socket %d to %s open.", csp->cfd, csp->server_connection.sfd, csp->server_connection.host); } else { log_error(LOG_LEVEL_CONNECT, "Waiting for the next client request on socket %d. " "No server socket to keep open.", csp->cfd); } } if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) && data_is_available(csp->cfd, (int)csp->config->keep_alive_timeout) && socket_is_still_alive(csp->cfd)) { log_error(LOG_LEVEL_CONNECT, "Client request %u arrived in time on socket %d.", csp->requests_received_total+1, csp->cfd); prepare_csp_for_next_request(csp); } else { #ifdef FEATURE_CONNECTION_SHARING if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) && (csp->server_connection.sfd != JB_INVALID_SOCKET) && (socket_is_still_alive(csp->server_connection.sfd))) { time_t time_open = time(NULL) - csp->server_connection.timestamp; if (csp->server_connection.keep_alive_timeout < time_open - (time_t)latency) { break; } remember_connection(&csp->server_connection); csp->server_connection.sfd = JB_INVALID_SOCKET; drain_and_close_socket(csp->cfd); csp->cfd = JB_INVALID_SOCKET; privoxy_mutex_lock(&connection_reuse_mutex); if (!monitor_thread_running) { monitor_thread_running = 1; privoxy_mutex_unlock(&connection_reuse_mutex); wait_for_alive_connections(); privoxy_mutex_lock(&connection_reuse_mutex); monitor_thread_running = 0; } privoxy_mutex_unlock(&connection_reuse_mutex); } #endif /* def FEATURE_CONNECTION_SHARING */ break; } } else if (csp->server_connection.sfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, "Closing server socket %d connected to %s. Keep-alive: %u. " "Tainted: %u. Socket alive: %u. Timeout: %u. " "Configuration file change detected: %u", csp->server_connection.sfd, csp->server_connection.host, 0 != (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE), 0 != (csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED), socket_is_still_alive(csp->server_connection.sfd), csp->server_connection.keep_alive_timeout, config_file_change_detected); } } while (continue_chatting); #else chat(csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING if (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) { forget_connection(csp->server_connection.sfd); } #endif /* def FEATURE_CONNECTION_SHARING */ close_socket(csp->server_connection.sfd); } #ifdef FEATURE_CONNECTION_KEEP_ALIVE mark_connection_closed(&csp->server_connection); #endif if (csp->cfd != JB_INVALID_SOCKET) { log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. " "Keep-alive: %u. Socket alive: %u. Data available: %u. " "Configuration file change detected: %u. Requests received: %u.", csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE), socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0), config_file_change_detected, csp->requests_received_total); drain_and_close_socket(csp->cfd); } csp->flags &= ~CSP_FLAG_ACTIVE; } #ifdef __BEOS__ /********************************************************************* * * Function : server_thread * * Description : We only exist to call `serve' in a threaded environment. * * Parameters : * 1 : data = Current client state (buffers, headers, etc...) * * Returns : Always 0. * *********************************************************************/ static int32 server_thread(void *data) { serve((struct client_state *) data); return 0; } #endif #if !defined(_WIN32) || defined(_WIN_CONSOLE) /********************************************************************* * * Function : usage * * Description : Print usage info & exit. * * Parameters : Pointer to argv[0] for identifying ourselves * * Returns : No. ,-) * *********************************************************************/ static void usage(const char *myname) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n" "Usage: %s [--config-test] " #if defined(unix) "[--chroot] " #endif /* defined(unix) */ "[--help] " #if defined(unix) "[--no-daemon] [--pidfile pidfile] [--pre-chroot-nslookup hostname] [--user user[.group]] " #endif /* defined(unix) */ "[--version] [configfile]\n" "Aborting\n", myname); exit(2); } #endif /* #if !defined(_WIN32) || defined(_WIN_CONSOLE) */ #ifdef MUTEX_LOCKS_AVAILABLE /********************************************************************* * * Function : privoxy_mutex_lock * * Description : Locks a mutex. * * Parameters : * 1 : mutex = The mutex to lock. * * Returns : Void. May exit in case of errors. * *********************************************************************/ void privoxy_mutex_lock(privoxy_mutex_t *mutex) { #ifdef FEATURE_PTHREAD int err = pthread_mutex_lock(mutex); if (err) { if (mutex != &log_mutex) { log_error(LOG_LEVEL_FATAL, "Mutex locking failed: %s.\n", strerror(err)); } exit(1); } #else EnterCriticalSection(mutex); #endif /* def FEATURE_PTHREAD */ } /********************************************************************* * * Function : privoxy_mutex_unlock * * Description : Unlocks a mutex. * * Parameters : * 1 : mutex = The mutex to unlock. * * Returns : Void. May exit in case of errors. * *********************************************************************/ void privoxy_mutex_unlock(privoxy_mutex_t *mutex) { #ifdef FEATURE_PTHREAD int err = pthread_mutex_unlock(mutex); if (err) { if (mutex != &log_mutex) { log_error(LOG_LEVEL_FATAL, "Mutex unlocking failed: %s.\n", strerror(err)); } exit(1); } #else LeaveCriticalSection(mutex); #endif /* def FEATURE_PTHREAD */ } /********************************************************************* * * Function : privoxy_mutex_init * * Description : Prepares a mutex. * * Parameters : * 1 : mutex = The mutex to initialize. * * Returns : Void. May exit in case of errors. * *********************************************************************/ static void privoxy_mutex_init(privoxy_mutex_t *mutex) { #ifdef FEATURE_PTHREAD int err = pthread_mutex_init(mutex, 0); if (err) { printf("Fatal error. Mutex initialization failed: %s.\n", strerror(err)); exit(1); } #else InitializeCriticalSection(mutex); #endif /* def FEATURE_PTHREAD */ } #endif /* def MUTEX_LOCKS_AVAILABLE */ /********************************************************************* * * Function : initialize_mutexes * * Description : Prepares mutexes if mutex support is available. * * Parameters : None * * Returns : Void, exits in case of errors. * *********************************************************************/ static void initialize_mutexes(void) { #ifdef MUTEX_LOCKS_AVAILABLE /* * Prepare global mutex semaphores */ privoxy_mutex_init(&log_mutex); privoxy_mutex_init(&log_init_mutex); privoxy_mutex_init(&connection_reuse_mutex); /* * XXX: The assumptions below are a bit naive * and can cause locks that aren't necessary. * * For example older FreeBSD versions (< 6.x?) * have no gethostbyname_r, but gethostbyname is * thread safe. */ #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) privoxy_mutex_init(&resolver_mutex); #endif /* !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) */ /* * XXX: should we use a single mutex for * localtime() and gmtime() as well? */ #ifndef HAVE_GMTIME_R privoxy_mutex_init(&gmtime_mutex); #endif /* ndef HAVE_GMTIME_R */ #ifndef HAVE_LOCALTIME_R privoxy_mutex_init(&localtime_mutex); #endif /* ndef HAVE_GMTIME_R */ #ifndef HAVE_RANDOM privoxy_mutex_init(&rand_mutex); #endif /* ndef HAVE_RANDOM */ #endif /* def MUTEX_LOCKS_AVAILABLE */ } /********************************************************************* * * Function : main * * Description : Load the config file and start the listen loop. * This function is a lot more *sane* with the `load_config' * and `listen_loop' functions; although it stills does * a *little* too much for my taste. * * Parameters : * 1 : argc = Number of parameters (including $0). * 2 : argv = Array of (char *)'s to the parameters. * * Returns : 1 if : can't open config file, unrecognized directive, * stats requested in multi-thread mode, can't open the * log file, can't open the jar file, listen port is invalid, * any load fails, and can't bind port. * * Else main never returns, the process must be signaled * to terminate execution. Or, on Windows, use the * "File", "Exit" menu option. * *********************************************************************/ #ifdef __MINGW32__ int real_main(int argc, char **argv) #else int main(int argc, char **argv) #endif { int argc_pos = 0; int do_config_test = 0; unsigned int random_seed; #ifdef unix struct passwd *pw = NULL; struct group *grp = NULL; int do_chroot = 0; char *pre_chroot_nslookup_to_load_resolver = NULL; #endif Argc = argc; Argv = argv; configfile = #if !defined(_WIN32) "config" #else "config.txt" #endif ; /* Prepare mutexes if supported and necessary. */ initialize_mutexes(); /* Enable logging until further notice. */ init_log_module(); /* * Parse the command line arguments * * XXX: simply printing usage information in case of * invalid arguments isn't particularly user friendly. */ while (++argc_pos < argc) { #ifdef _WIN32 /* Check to see if the service must be installed or uninstalled */ if (strncmp(argv[argc_pos], "--install", 9) == 0) { const char *pName = argv[argc_pos] + 9; if (*pName == ':') pName++; exit((install_service(pName)) ? 0 : 1); } else if (strncmp(argv[argc_pos], "--uninstall", 11) == 0) { const char *pName = argv[argc_pos] + 11; if (*pName == ':') pName++; exit((uninstall_service(pName)) ? 0 : 1); } else if (strcmp(argv[argc_pos], "--service") == 0) { bRunAsService = TRUE; w32_set_service_cwd(); atexit(w32_service_exit_notify); } else #endif /* defined(_WIN32) */ #if !defined(_WIN32) || defined(_WIN_CONSOLE) if (strcmp(argv[argc_pos], "--help") == 0) { usage(argv[0]); } else if (strcmp(argv[argc_pos], "--version") == 0) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n"); exit(0); } #if defined(unix) else if (strcmp(argv[argc_pos], "--no-daemon") == 0) { set_debug_level(LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO); daemon_mode = 0; } else if (strcmp(argv[argc_pos], "--pidfile") == 0) { if (++argc_pos == argc) usage(argv[0]); pidfile = strdup_or_die(argv[argc_pos]); } else if (strcmp(argv[argc_pos], "--user") == 0) { char *user_arg; char *group_name; if (++argc_pos == argc) usage(argv[argc_pos]); user_arg = strdup_or_die(argv[argc_pos]); group_name = strchr(user_arg, '.'); if (NULL != group_name) { /* Nul-terminate the user name */ *group_name = '\0'; /* Skip the former delimiter to actually reach the group name */ group_name++; grp = getgrnam(group_name); if (NULL == grp) { log_error(LOG_LEVEL_FATAL, "Group '%s' not found.", group_name); } } pw = getpwnam(user_arg); if (NULL == pw) { log_error(LOG_LEVEL_FATAL, "User '%s' not found.", user_arg); } freez(user_arg); } else if (strcmp(argv[argc_pos], "--pre-chroot-nslookup") == 0) { if (++argc_pos == argc) usage(argv[0]); pre_chroot_nslookup_to_load_resolver = strdup_or_die(argv[argc_pos]); } else if (strcmp(argv[argc_pos], "--chroot") == 0) { do_chroot = 1; } #endif /* defined(unix) */ else if (strcmp(argv[argc_pos], "--config-test") == 0) { do_config_test = 1; } else if (argc_pos + 1 != argc) { /* * This is neither the last command line * option, nor was it recognized before, * therefore it must be invalid. */ usage(argv[0]); } else #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ { configfile = argv[argc_pos]; } } /* -END- while (more arguments) */ show_version(Argv[0]); #if defined(unix) if (*configfile != '/') { char cwd[BUFFER_SIZE]; char *abs_file; size_t abs_file_size; /* make config-filename absolute here */ if (NULL == getcwd(cwd, sizeof(cwd))) { perror("failed to get current working directory"); exit(1); } basedir = strdup_or_die(cwd); /* XXX: why + 5? */ abs_file_size = strlen(cwd) + strlen(configfile) + 5; abs_file = malloc_or_die(abs_file_size); strlcpy(abs_file, basedir, abs_file_size); strlcat(abs_file, "/", abs_file_size); strlcat(abs_file, configfile, abs_file_size); configfile = abs_file; } #endif /* defined unix */ files->next = NULL; clients->next = NULL; /* XXX: factor out initialising after the next stable release. */ #ifdef AMIGA InitAmiga(); #elif defined(_WIN32) InitWin32(); #endif random_seed = (unsigned int)time(NULL); #ifdef HAVE_RANDOM srandom(random_seed); #else srand(random_seed); #endif /* ifdef HAVE_RANDOM */ /* * Unix signal handling * * Catch the abort, interrupt and terminate signals for a graceful exit * Catch the hangup signal so the errlog can be reopened. * Ignore the broken pipe signals (FIXME: Why?) */ #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) { int idx; const int catched_signals[] = { SIGTERM, SIGINT, SIGHUP }; for (idx = 0; idx < SZ(catched_signals); idx++) { #ifdef sun /* FIXME: Is it safe to check for HAVE_SIGSET instead? */ if (sigset(catched_signals[idx], sig_handler) == SIG_ERR) #else if (signal(catched_signals[idx], sig_handler) == SIG_ERR) #endif /* ifdef sun */ { log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", catched_signals[idx]); } } if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { log_error(LOG_LEVEL_FATAL, "Can't set ignore-handler for SIGPIPE: %E"); } } #else /* ifdef _WIN32 */ # ifdef _WIN_CONSOLE /* * We *are* in a windows console app. * Print a verbose messages about FAQ's and such */ printf("%s", win32_blurb); # endif /* def _WIN_CONSOLE */ #endif /* def _WIN32 */ if (do_config_test) { exit(NULL == load_config()); } /* Initialize the CGI subsystem */ cgi_init_error_messages(); /* * If runnig on unix and without the --nodaemon * option, become a daemon. I.e. fork, detach * from tty and get process group leadership */ #if defined(unix) { if (daemon_mode) { int fd; pid_t pid = fork(); if (pid < 0) /* error */ { perror("fork"); exit(3); } else if (pid != 0) /* parent */ { int status; pid_t wpid; /* * must check for errors * child died due to missing files aso */ sleep(1); wpid = waitpid(pid, &status, WNOHANG); if (wpid != 0) { exit(1); } exit(0); } /* child */ setsid(); /* * stderr (fd 2) will be closed later on, * when the config file has been parsed. */ close(0); close(1); /* * Reserve fd 0 and 1 to prevent abort() and friends * from sending stuff to the clients or servers. */ fd = open("/dev/null", O_RDONLY); if (fd == -1) { log_error(LOG_LEVEL_FATAL, "Failed to open /dev/null: %E"); } else if (fd != 0) { if (dup2(fd, 0) == -1) { log_error(LOG_LEVEL_FATAL, "Failed to reserve fd 0: %E"); } close(fd); } fd = open("/dev/null", O_WRONLY); if (fd == -1) { log_error(LOG_LEVEL_FATAL, "Failed to open /dev/null: %E"); } else if (fd != 1) { if (dup2(fd, 1) == -1) { log_error(LOG_LEVEL_FATAL, "Failed to reserve fd 1: %E"); } close(fd); } chdir("/"); } /* -END- if (daemon_mode) */ /* * As soon as we have written the PID file, we can switch * to the user and group ID indicated by the --user option */ write_pid_file(); if (NULL != pw) { if (setgid((NULL != grp) ? grp->gr_gid : pw->pw_gid)) { log_error(LOG_LEVEL_FATAL, "Cannot setgid(): Insufficient permissions."); } if (NULL != grp) { if (setgroups(1, &grp->gr_gid)) { log_error(LOG_LEVEL_FATAL, "setgroups() failed: %E"); } } else if (initgroups(pw->pw_name, pw->pw_gid)) { log_error(LOG_LEVEL_FATAL, "initgroups() failed: %E"); } if (do_chroot) { if (!pw->pw_dir) { log_error(LOG_LEVEL_FATAL, "Home directory for %s undefined", pw->pw_name); } /* Read the time zone file from /etc before doing chroot. */ tzset(); if (NULL != pre_chroot_nslookup_to_load_resolver && '\0' != pre_chroot_nslookup_to_load_resolver[0]) { /* Initialize resolver library. */ (void) resolve_hostname_to_ip(pre_chroot_nslookup_to_load_resolver); } if (chroot(pw->pw_dir) < 0) { log_error(LOG_LEVEL_FATAL, "Cannot chroot to %s", pw->pw_dir); } if (chdir ("/")) { log_error(LOG_LEVEL_FATAL, "Cannot chdir /"); } } if (setuid(pw->pw_uid)) { log_error(LOG_LEVEL_FATAL, "Cannot setuid(): Insufficient permissions."); } if (do_chroot) { char putenv_dummy[64]; strlcpy(putenv_dummy, "HOME=/", sizeof(putenv_dummy)); if (putenv(putenv_dummy) != 0) { log_error(LOG_LEVEL_FATAL, "Cannot putenv(): HOME"); } snprintf(putenv_dummy, sizeof(putenv_dummy), "USER=%s", pw->pw_name); if (putenv(putenv_dummy) != 0) { log_error(LOG_LEVEL_FATAL, "Cannot putenv(): USER"); } } } else if (do_chroot) { log_error(LOG_LEVEL_FATAL, "Cannot chroot without --user argument."); } } #endif /* defined unix */ #ifdef _WIN32 /* This will be FALSE unless the command line specified --service */ if (bRunAsService) { /* Yup, so now we must attempt to establish a connection * with the service dispatcher. This will only work if this * process was launched by the service control manager to * actually run as a service. If this isn't the case, i've * known it take around 30 seconds or so for the call to return. */ /* The StartServiceCtrlDispatcher won't return until the service is stopping */ if (w32_start_service_ctrl_dispatcher(w32ServiceDispatchTable)) { /* Service has run, and at this point is now being stopped, so just return */ return 0; } #ifdef _WIN_CONSOLE printf("Warning: Failed to connect to Service Control Dispatcher\nwhen starting as a service!\n"); #endif /* An error occurred. Usually it's because --service was wrongly specified * and we were unable to connect to the Service Control Dispatcher because * it wasn't expecting us and is therefore not listening. * * For now, just continue below to call the listen_loop function. */ } #endif /* def _WIN32 */ listen_loop(); /* NOTREACHED */ return(-1); } /********************************************************************* * * Function : bind_port_helper * * Description : Bind the listen port. Handles logging, and aborts * on failure. * * Parameters : * 1 : haddr = Host addres to bind to. Use NULL to bind to * INADDR_ANY. * 2 : hport = Specifies port to bind to. * * Returns : Port that was opened. * *********************************************************************/ static jb_socket bind_port_helper(const char *haddr, int hport) { int result; jb_socket bfd; result = bind_port(haddr, hport, &bfd); if (result < 0) { const char *bind_address = (NULL != haddr) ? haddr : "INADDR_ANY"; switch(result) { case -3: log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: There may be another Privoxy " "or some other proxy running on port %d", bind_address, hport, hport); case -2: log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: The hostname is not resolvable", bind_address, hport); default: log_error(LOG_LEVEL_FATAL, "can't bind to %s:%d: %E", bind_address, hport); } /* shouldn't get here */ return JB_INVALID_SOCKET; } #ifndef _WIN32 if (bfd >= FD_SETSIZE) { log_error(LOG_LEVEL_FATAL, "Bind socket number too high to use select(): %d >= %d", bfd, FD_SETSIZE); } #endif if (haddr == NULL) { log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses", hport); } else { log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s", hport, haddr); } return bfd; } /********************************************************************* * * Function : bind_ports_helper * * Description : Bind the listen ports. Handles logging, and aborts * on failure. * * Parameters : * 1 : config = Privoxy configuration. Specifies ports * to bind to. * 2 : sockets = Preallocated array of opened sockets * corresponding to specification in config. * All non-opened sockets will be set to * JB_INVALID_SOCKET. * * Returns : Nothing. Inspect sockets argument. * *********************************************************************/ static void bind_ports_helper(struct configuration_spec * config, jb_socket sockets[]) { int i; for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { if (config->hport[i]) { sockets[i] = bind_port_helper(config->haddr[i], config->hport[i]); } else { sockets[i] = JB_INVALID_SOCKET; } } config->need_bind = 0; } /********************************************************************* * * Function : close_ports_helper * * Description : Close listenings ports. * * Parameters : * 1 : sockets = Array of opened and non-opened sockets to * close. All sockets will be set to * JB_INVALID_SOCKET. * * Returns : Nothing. * *********************************************************************/ static void close_ports_helper(jb_socket sockets[]) { int i; for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { if (JB_INVALID_SOCKET != sockets[i]) { close_socket(sockets[i]); } sockets[i] = JB_INVALID_SOCKET; } } #ifdef _WIN32 /* Without this simple workaround we get this compiler warning from _beginthread * warning C4028: formal parameter 1 different from declaration */ void w32_service_listen_loop(void *p) { listen_loop(); } #endif /* def _WIN32 */ /********************************************************************* * * Function : listen_loop * * Description : bind the listen port and enter a "FOREVER" listening loop. * * Parameters : N/A * * Returns : Never. * *********************************************************************/ static void listen_loop(void) { struct client_states *csp_list = NULL; struct client_state *csp = NULL; jb_socket bfds[MAX_LISTENING_SOCKETS]; struct configuration_spec *config; unsigned int active_threads = 0; config = load_config(); #ifdef FEATURE_CONNECTION_SHARING /* * XXX: Should be relocated once it no * longer needs to emit log messages. */ initialize_reusable_connections(); #endif /* def FEATURE_CONNECTION_SHARING */ bind_ports_helper(config, bfds); #ifdef FEATURE_GRACEFUL_TERMINATION while (!g_terminate) #else for (;;) #endif { #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) while (waitpid(-1, NULL, WNOHANG) > 0) { /* zombie children */ } #endif /* !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ /* * Free data that was used by died threads */ active_threads = sweep(); #if defined(unix) /* * Re-open the errlog after HUP signal */ if (received_hup_signal) { if (NULL != config->logfile) { init_error_log(Argv[0], config->logfile); } received_hup_signal = 0; } #endif csp_list = (struct client_states *)zalloc(sizeof(*csp_list)); if (NULL == csp_list) { log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp_list failed: %E", sizeof(*csp_list)); continue; } csp = &csp_list->csp; log_error(LOG_LEVEL_CONNECT, "Listening for new connections ... "); if (!accept_connection(csp, bfds)) { log_error(LOG_LEVEL_CONNECT, "accept failed: %E"); #ifdef AMIGA if (!childs) { exit(1); } #endif freez(csp_list); continue; } csp->flags |= CSP_FLAG_ACTIVE; csp->server_connection.sfd = JB_INVALID_SOCKET; csp->config = config = load_config(); if (config->need_bind) { /* * Since we were listening to the "old port", we will not see * a "listen" param change until the next request. So, at * least 1 more request must be made for us to find the new * setting. I am simply closing the old socket and binding the * new one. * * Which-ever is correct, we will serve 1 more page via the * old settings. This should probably be a "show-proxy-args" * request. This should not be a so common of an operation * that this will hurt people's feelings. */ close_ports_helper(bfds); bind_ports_helper(config, bfds); } #ifdef FEATURE_TOGGLE if (global_toggle_state) #endif /* def FEATURE_TOGGLE */ { csp->flags |= CSP_FLAG_TOGGLED_ON; } if (run_loader(csp)) { log_error(LOG_LEVEL_FATAL, "a loader failed - must exit"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } #ifdef FEATURE_ACL if (block_acl(NULL,csp)) { log_error(LOG_LEVEL_CONNECT, "Connection from %s on socket %d dropped due to ACL", csp->ip_addr_str, csp->cfd); close_socket(csp->cfd); freez(csp->ip_addr_str); freez(csp_list); continue; } #endif /* def FEATURE_ACL */ if ((0 != config->max_client_connections) && (active_threads >= config->max_client_connections)) { log_error(LOG_LEVEL_CONNECT, "Rejecting connection from %s. Maximum number of connections reached.", csp->ip_addr_str); write_socket(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE, strlen(TOO_MANY_CONNECTIONS_RESPONSE)); close_socket(csp->cfd); freez(csp->ip_addr_str); freez(csp_list); continue; } /* add it to the list of clients */ csp_list->next = clients->next; clients->next = csp_list; if (config->multi_threaded) { int child_id; /* this is a switch () statement in the C preprocessor - ugh */ #undef SELECTED_ONE_OPTION /* Use Pthreads in preference to native code */ #if defined(FEATURE_PTHREAD) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION { pthread_t the_thread; pthread_attr_t attrs; pthread_attr_init(&attrs); pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); errno = pthread_create(&the_thread, &attrs, (void * (*)(void *))serve, csp); child_id = errno ? -1 : 0; pthread_attr_destroy(&attrs); } #endif #if defined(_WIN32) && !defined(_CYGWIN) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION child_id = _beginthread( (void (*)(void *))serve, 64 * 1024, csp); #endif #if defined(__OS2__) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION child_id = _beginthread( (void(* _Optlink)(void*))serve, NULL, 64 * 1024, csp); #endif #if defined(__BEOS__) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION { thread_id tid = spawn_thread (server_thread, "server", B_NORMAL_PRIORITY, csp); if ((tid >= 0) && (resume_thread(tid) == B_OK)) { child_id = (int) tid; } else { child_id = -1; } } #endif #if defined(AMIGA) && !defined(SELECTED_ONE_OPTION) #define SELECTED_ONE_OPTION csp->cfd = ReleaseSocket(csp->cfd, -1); #ifdef __amigaos4__ child_id = (int)CreateNewProcTags(NP_Entry, (ULONG)server_thread, NP_Output, Output(), NP_CloseOutput, FALSE, NP_Name, (ULONG)"privoxy child", NP_Child, TRUE, TAG_DONE); #else child_id = (int)CreateNewProcTags(NP_Entry, (ULONG)server_thread, NP_Output, Output(), NP_CloseOutput, FALSE, NP_Name, (ULONG)"privoxy child", NP_StackSize, 200*1024, TAG_DONE); #endif if (0 != child_id) { childs++; ((struct Task *)child_id)->tc_UserData = csp; Signal((struct Task *)child_id, SIGF_SINGLE); Wait(SIGF_SINGLE); } #endif #if !defined(SELECTED_ONE_OPTION) child_id = fork(); /* This block is only needed when using fork(). * When using threads, the server thread was * created and run by the call to _beginthread(). */ if (child_id == 0) /* child */ { int rc = 0; #ifdef FEATURE_TOGGLE int inherited_toggle_state = global_toggle_state; #endif /* def FEATURE_TOGGLE */ serve(csp); /* * If we've been toggled or we've blocked the request, tell Mom */ #ifdef FEATURE_TOGGLE if (inherited_toggle_state != global_toggle_state) { rc |= RC_FLAG_TOGGLED; } #endif /* def FEATURE_TOGGLE */ #ifdef FEATURE_STATISTICS if (csp->flags & CSP_FLAG_REJECTED) { rc |= RC_FLAG_BLOCKED; } #endif /* ndef FEATURE_STATISTICS */ _exit(rc); } else if (child_id > 0) /* parent */ { /* in a fork()'d environment, the parent's * copy of the client socket and the CSP * are not used. */ int child_status; #if !defined(_WIN32) && !defined(__CYGWIN__) wait(&child_status); /* * Evaluate child's return code: If the child has * - been toggled, toggle ourselves * - blocked its request, bump up the stats counter */ #ifdef FEATURE_TOGGLE if (WIFEXITED(child_status) && (WEXITSTATUS(child_status) & RC_FLAG_TOGGLED)) { global_toggle_state = !global_toggle_state; } #endif /* def FEATURE_TOGGLE */ #ifdef FEATURE_STATISTICS urls_read++; if (WIFEXITED(child_status) && (WEXITSTATUS(child_status) & RC_FLAG_BLOCKED)) { urls_rejected++; } #endif /* def FEATURE_STATISTICS */ #endif /* !defined(_WIN32) && defined(__CYGWIN__) */ close_socket(csp->cfd); csp->flags &= ~CSP_FLAG_ACTIVE; } #endif #undef SELECTED_ONE_OPTION /* end of cpp switch () */ if (child_id < 0) { /* * Spawning the child failed, assume it's because * there are too many children running already. * XXX: If you assume ... */ log_error(LOG_LEVEL_ERROR, "Unable to take any additional connections: %E"); write_socket(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE, strlen(TOO_MANY_CONNECTIONS_RESPONSE)); close_socket(csp->cfd); csp->flags &= ~CSP_FLAG_ACTIVE; } } else { serve(csp); } } /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */ /* Clean up. Aim: free all memory (no leaks) */ #ifdef FEATURE_GRACEFUL_TERMINATION log_error(LOG_LEVEL_ERROR, "Graceful termination requested"); unload_current_config_file(); unload_current_actions_file(); unload_current_re_filterfile(); #ifdef FEATURE_TRUST unload_current_trust_file(); #endif if (config->multi_threaded) { int i = 60; do { sleep(1); sweep(); } while ((clients->next != NULL) && (--i > 0)); if (i <= 0) { log_error(LOG_LEVEL_ERROR, "Graceful termination failed - still some live clients after 1 minute wait."); } } sweep(); sweep(); #if defined(unix) freez(basedir); #endif #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Cleanup - remove taskbar icon etc. */ TermLogWindow(); #endif exit(0); #endif /* FEATURE_GRACEFUL_TERMINATION */ } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./actions.c000640 001751 001751 00000165153 12054151244 015577 0ustar00fkfk000000 000000 const char actions_rcs[] = "$Id: actions.c,v 1.87 2012/11/24 13:59:00 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actions.c,v $ * * Purpose : Declares functions to work with actions files * * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #ifdef FEATURE_PTHREAD #include #endif #include "project.h" #include "jcc.h" #include "list.h" #include "actions.h" #include "miscutil.h" #include "errlog.h" #include "loaders.h" #include "encode.h" #include "urlmatch.h" #include "cgi.h" #include "ssplit.h" const char actions_h_rcs[] = ACTIONS_H_VERSION; /* * We need the main list of options. * * First, we need a way to tell between boolean, string, and multi-string * options. For string and multistring options, we also need to be * able to tell the difference between a "+" and a "-". (For bools, * the "+"/"-" information is encoded in "add" and "mask"). So we use * an enumerated type (well, the preprocessor equivalent). Here are * the values: */ enum action_value_type { AV_NONE = 0, /* +opt -opt */ AV_ADD_STRING = 1, /* +stropt{string} */ AV_REM_STRING = 2, /* -stropt */ AV_ADD_MULTI = 3, /* +multiopt{string} +multiopt{string2} */ AV_REM_MULTI = 4 /* -multiopt{string} -multiopt */ }; /* * We need a structure to hold the name, flag changes, * type, and string index. */ struct action_name { const char * name; unsigned long mask; /* a bit set to "0" = remove action */ unsigned long add; /* a bit set to "1" = add action */ enum action_value_type value_type; /* an AV_... constant */ int index; /* index into strings[] or multi[] */ }; /* * And with those building blocks in place, here's the array. */ static const struct action_name action_names[] = { /* * Well actually there's no data here - it's in actionlist.h * This keeps it together to make it easy to change. * * Here's the macros used to format it: */ #define DEFINE_ACTION_MULTI(name,index) \ { "+" name, ACTION_MASK_ALL, 0, AV_ADD_MULTI, index }, \ { "-" name, ACTION_MASK_ALL, 0, AV_REM_MULTI, index }, #define DEFINE_ACTION_STRING(name,flag,index) \ { "+" name, ACTION_MASK_ALL, flag, AV_ADD_STRING, index }, \ { "-" name, ~flag, 0, AV_REM_STRING, index }, #define DEFINE_ACTION_BOOL(name,flag) \ { "+" name, ACTION_MASK_ALL, flag }, \ { "-" name, ~flag, 0 }, #define DEFINE_ACTION_ALIAS 1 /* Want aliases please */ #include "actionlist.h" #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS { NULL, 0, 0 } /* End marker */ }; static int load_one_actions_file(struct client_state *csp, int fileid); /********************************************************************* * * Function : merge_actions * * Description : Merge two actions together. * Similar to "dest += src". * * Parameters : * 1 : dest = Actions to modify. * 2 : src = Action to add. * * Returns : JB_ERR_OK or JB_ERR_MEMORY * *********************************************************************/ jb_err merge_actions (struct action_spec *dest, const struct action_spec *src) { int i; jb_err err; dest->mask &= src->mask; dest->add &= src->mask; dest->add |= src->add; for (i = 0; i < ACTION_STRING_COUNT; i++) { char * str = src->string[i]; if (str) { freez(dest->string[i]); dest->string[i] = strdup_or_die(str); } } for (i = 0; i < ACTION_MULTI_COUNT; i++) { if (src->multi_remove_all[i]) { /* Remove everything from dest */ list_remove_all(dest->multi_remove[i]); dest->multi_remove_all[i] = 1; err = list_duplicate(dest->multi_add[i], src->multi_add[i]); } else if (dest->multi_remove_all[i]) { /* * dest already removes everything, so we only need to worry * about what we add. */ list_remove_list(dest->multi_add[i], src->multi_remove[i]); err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]); } else { /* No "remove all"s to worry about. */ list_remove_list(dest->multi_add[i], src->multi_remove[i]); err = list_append_list_unique(dest->multi_remove[i], src->multi_remove[i]); if (!err) err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]); } if (err) { return err; } } return JB_ERR_OK; } /********************************************************************* * * Function : copy_action * * Description : Copy an action_specs. * Similar to "dest = src". * * Parameters : * 1 : dest = Destination of copy. * 2 : src = Source for copy. * * Returns : JB_ERR_OK or JB_ERR_MEMORY * *********************************************************************/ jb_err copy_action (struct action_spec *dest, const struct action_spec *src) { int i; jb_err err = JB_ERR_OK; free_action(dest); memset(dest, '\0', sizeof(*dest)); dest->mask = src->mask; dest->add = src->add; for (i = 0; i < ACTION_STRING_COUNT; i++) { char * str = src->string[i]; if (str) { str = strdup_or_die(str); dest->string[i] = str; } } for (i = 0; i < ACTION_MULTI_COUNT; i++) { dest->multi_remove_all[i] = src->multi_remove_all[i]; err = list_duplicate(dest->multi_remove[i], src->multi_remove[i]); if (err) { return err; } err = list_duplicate(dest->multi_add[i], src->multi_add[i]); if (err) { return err; } } return err; } /********************************************************************* * * Function : free_action_spec * * Description : Frees an action_spec and the memory used by it. * * Parameters : * 1 : src = Source to free. * * Returns : N/A * *********************************************************************/ void free_action_spec(struct action_spec *src) { free_action(src); freez(src); } /********************************************************************* * * Function : free_action * * Description : Destroy an action_spec. Frees memory used by it, * except for the memory used by the struct action_spec * itself. * * Parameters : * 1 : src = Source to free. * * Returns : N/A * *********************************************************************/ void free_action (struct action_spec *src) { int i; if (src == NULL) { return; } for (i = 0; i < ACTION_STRING_COUNT; i++) { freez(src->string[i]); } for (i = 0; i < ACTION_MULTI_COUNT; i++) { destroy_list(src->multi_remove[i]); destroy_list(src->multi_add[i]); } memset(src, '\0', sizeof(*src)); } /********************************************************************* * * Function : get_action_token * * Description : Parses a line for the first action. * Modifies its input array, doesn't allocate memory. * e.g. given: * *line=" +abc{def} -ghi " * Returns: * *line=" -ghi " * *name="+abc" * *value="def" * * Parameters : * 1 : line = [in] The line containing the action. * [out] Start of next action on line, or * NULL if we reached the end of line before * we found an action. * 2 : name = [out] Start of action name, null * terminated. NULL on EOL * 3 : value = [out] Start of action value, null * terminated. NULL if none or EOL. * * Returns : JB_ERR_OK => Ok * JB_ERR_PARSE => Mismatched {} (line was trashed anyway) * *********************************************************************/ jb_err get_action_token(char **line, char **name, char **value) { char * str = *line; char ch; /* set default returns */ *line = NULL; *name = NULL; *value = NULL; /* Eat any leading whitespace */ while ((*str == ' ') || (*str == '\t')) { str++; } if (*str == '\0') { return 0; } if (*str == '{') { /* null name, just value is prohibited */ return JB_ERR_PARSE; } *name = str; /* parse option */ while (((ch = *str) != '\0') && (ch != ' ') && (ch != '\t') && (ch != '{')) { if (ch == '}') { /* error, '}' without '{' */ return JB_ERR_PARSE; } str++; } *str = '\0'; if (ch != '{') { /* no value */ if (ch == '\0') { /* EOL - be careful not to run off buffer */ *line = str; } else { /* More to parse next time. */ *line = str + 1; } return JB_ERR_OK; } str++; *value = str; /* The value ends with the first non-escaped closing curly brace */ while ((str = strchr(str, '}')) != NULL) { if (str[-1] == '\\') { /* Overwrite the '\' so the action doesn't see it. */ string_move(str-1, str); continue; } break; } if (str == NULL) { /* error */ *value = NULL; return JB_ERR_PARSE; } /* got value */ *str = '\0'; *line = str + 1; chomp(*value); return JB_ERR_OK; } /********************************************************************* * * Function : action_used_to_be_valid * * Description : Checks if unrecognized actions were valid in earlier * releases. * * Parameters : * 1 : action = The string containing the action to check. * * Returns : True if yes, otherwise false. * *********************************************************************/ static int action_used_to_be_valid(const char *action) { static const char * const formerly_valid_actions[] = { "inspect-jpegs", "kill-popups", "send-vanilla-wafer", "send-wafer", "treat-forbidden-connects-like-blocks", "vanilla-wafer", "wafer" }; unsigned int i; for (i = 0; i < SZ(formerly_valid_actions); i++) { if (0 == strcmpic(action, formerly_valid_actions[i])) { return TRUE; } } return FALSE; } /********************************************************************* * * Function : get_actions * * Description : Parses a list of actions. * * Parameters : * 1 : line = The string containing the actions. * Will be written to by this function. * 2 : alias_list = Custom alias list, or NULL for none. * 3 : cur_action = Where to store the action. Caller * allocates memory. * * Returns : JB_ERR_OK => Ok * JB_ERR_PARSE => Parse error (line was trashed anyway) * nonzero => Out of memory (line was trashed anyway) * *********************************************************************/ jb_err get_actions(char *line, struct action_alias * alias_list, struct action_spec *cur_action) { jb_err err; init_action(cur_action); cur_action->mask = ACTION_MASK_ALL; while (line) { char * option = NULL; char * value = NULL; err = get_action_token(&line, &option, &value); if (err) { return err; } if (option) { /* handle option in 'option' */ /* Check for standard action name */ const struct action_name * action = action_names; while ((action->name != NULL) && (0 != strcmpic(action->name, option))) { action++; } if (action->name != NULL) { /* Found it */ cur_action->mask &= action->mask; cur_action->add &= action->mask; cur_action->add |= action->add; switch (action->value_type) { case AV_NONE: /* ignore any option. */ break; case AV_ADD_STRING: { /* add single string. */ if ((value == NULL) || (*value == '\0')) { if (0 == strcmpic(action->name, "+block")) { /* * XXX: Temporary backwards compatibility hack. * XXX: should include line number. */ value = "No reason specified."; log_error(LOG_LEVEL_ERROR, "block action without reason found. This may " "become a fatal error in future versions."); } else { return JB_ERR_PARSE; } } /* FIXME: should validate option string here */ freez (cur_action->string[action->index]); cur_action->string[action->index] = strdup(value); if (NULL == cur_action->string[action->index]) { return JB_ERR_MEMORY; } break; } case AV_REM_STRING: { /* remove single string. */ freez (cur_action->string[action->index]); break; } case AV_ADD_MULTI: { /* append multi string. */ struct list * remove_p = cur_action->multi_remove[action->index]; struct list * add_p = cur_action->multi_add[action->index]; if ((value == NULL) || (*value == '\0')) { return JB_ERR_PARSE; } list_remove_item(remove_p, value); err = enlist_unique(add_p, value, 0); if (err) { return err; } break; } case AV_REM_MULTI: { /* remove multi string. */ struct list * remove_p = cur_action->multi_remove[action->index]; struct list * add_p = cur_action->multi_add[action->index]; if ((value == NULL) || (*value == '\0') || ((*value == '*') && (value[1] == '\0'))) { /* * no option, or option == "*". * * Remove *ALL*. */ list_remove_all(remove_p); list_remove_all(add_p); cur_action->multi_remove_all[action->index] = 1; } else { /* Valid option - remove only 1 option */ if (!cur_action->multi_remove_all[action->index]) { /* there isn't a catch-all in the remove list already */ err = enlist_unique(remove_p, value, 0); if (err) { return err; } } list_remove_item(add_p, value); } break; } default: /* Shouldn't get here unless there's memory corruption. */ assert(0); return JB_ERR_PARSE; } } else { /* try user aliases. */ const struct action_alias * alias = alias_list; while ((alias != NULL) && (0 != strcmpic(alias->name, option))) { alias = alias->next; } if (alias != NULL) { /* Found it */ merge_actions(cur_action, alias->action); } else if (((size_t)2 < strlen(option)) && action_used_to_be_valid(option+1)) { log_error(LOG_LEVEL_ERROR, "Action '%s' is no longer valid " "in this Privoxy release. Ignored.", option+1); } else if (((size_t)2 < strlen(option)) && 0 == strcmpic(option+1, "hide-forwarded-for-headers")) { log_error(LOG_LEVEL_FATAL, "The action 'hide-forwarded-for-headers' " "is no longer valid in this Privoxy release. " "Use 'change-x-forwarded-for' instead."); } else { /* Bad action name */ /* * XXX: This is a fatal error and Privoxy will later on exit * in load_one_actions_file() because of an "invalid line". * * It would be preferable to name the offending option in that * error message, but currently there is no way to do that and * we have to live with two error messages for basically the * same reason. */ log_error(LOG_LEVEL_ERROR, "Unknown action or alias: %s", option); return JB_ERR_PARSE; } } } } return JB_ERR_OK; } /********************************************************************* * * Function : init_current_action * * Description : Zero out an action. * * Parameters : * 1 : dest = An uninitialized current_action_spec. * * Returns : N/A * *********************************************************************/ void init_current_action (struct current_action_spec *dest) { memset(dest, '\0', sizeof(*dest)); dest->flags = ACTION_MOST_COMPATIBLE; } /********************************************************************* * * Function : init_action * * Description : Zero out an action. * * Parameters : * 1 : dest = An uninitialized action_spec. * * Returns : N/A * *********************************************************************/ void init_action (struct action_spec *dest) { memset(dest, '\0', sizeof(*dest)); } /********************************************************************* * * Function : merge_current_action * * Description : Merge two actions together. * Similar to "dest += src". * Differences between this and merge_actions() * is that this one doesn't allocate memory for * strings (so "src" better be in memory for at least * as long as "dest" is, and you'd better free * "dest" using "free_current_action"). * Also, there is no mask or remove lists in dest. * (If we're applying it to a URL, we don't need them) * * Parameters : * 1 : dest = Current actions, to modify. * 2 : src = Action to add. * * Returns 0 : no error * !=0 : error, probably JB_ERR_MEMORY. * *********************************************************************/ jb_err merge_current_action (struct current_action_spec *dest, const struct action_spec *src) { int i; jb_err err = JB_ERR_OK; dest->flags &= src->mask; dest->flags |= src->add; for (i = 0; i < ACTION_STRING_COUNT; i++) { char * str = src->string[i]; if (str) { str = strdup_or_die(str); freez(dest->string[i]); dest->string[i] = str; } } for (i = 0; i < ACTION_MULTI_COUNT; i++) { if (src->multi_remove_all[i]) { /* Remove everything from dest, then add src->multi_add */ err = list_duplicate(dest->multi[i], src->multi_add[i]); if (err) { return err; } } else { list_remove_list(dest->multi[i], src->multi_remove[i]); err = list_append_list_unique(dest->multi[i], src->multi_add[i]); if (err) { return err; } } } return err; } /********************************************************************* * * Function : update_action_bits_for_tag * * Description : Updates the action bits based on the action sections * whose tag patterns match a provided tag. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : tag = The tag on which the update should be based on * * Returns : 0 if no tag matched, or * 1 otherwise * *********************************************************************/ int update_action_bits_for_tag(struct client_state *csp, const char *tag) { struct file_list *fl; struct url_actions *b; int updated = 0; int i; assert(tag); assert(list_contains_item(csp->tags, tag)); /* Run through all action files, */ for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL)) { /* Skip empty files */ continue; } /* and through all the action patterns, */ for (b = b->next; NULL != b; b = b->next) { /* skip the URL patterns, */ if (NULL == b->url->tag_regex) { continue; } /* and check if one of the tag patterns matches the tag, */ if (0 == regexec(b->url->tag_regex, tag, 0, NULL, 0)) { /* if it does, update the action bit map, */ if (merge_current_action(csp->action, b->action)) { log_error(LOG_LEVEL_ERROR, "Out of memory while changing action bits"); } /* and signal the change. */ updated = 1; } } } return updated; } /********************************************************************* * * Function : free_current_action * * Description : Free memory used by a current_action_spec. * Does not free the current_action_spec itself. * * Parameters : * 1 : src = Source to free. * * Returns : N/A * *********************************************************************/ void free_current_action(struct current_action_spec *src) { int i; for (i = 0; i < ACTION_STRING_COUNT; i++) { freez(src->string[i]); } for (i = 0; i < ACTION_MULTI_COUNT; i++) { destroy_list(src->multi[i]); } memset(src, '\0', sizeof(*src)); } static struct file_list *current_actions_file[MAX_AF_FILES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #ifdef FEATURE_GRACEFUL_TERMINATION /********************************************************************* * * Function : unload_current_actions_file * * Description : Unloads current actions file - reset to state at * beginning of program. * * Parameters : None * * Returns : N/A * *********************************************************************/ void unload_current_actions_file(void) { int i; for (i = 0; i < MAX_AF_FILES; i++) { if (current_actions_file[i]) { current_actions_file[i]->unloader = unload_actions_file; current_actions_file[i] = NULL; } } } #endif /* FEATURE_GRACEFUL_TERMINATION */ /********************************************************************* * * Function : unload_actions_file * * Description : Unloads an actions module. * * Parameters : * 1 : file_data = the data structure associated with the * actions file. * * Returns : N/A * *********************************************************************/ void unload_actions_file(void *file_data) { struct url_actions * next; struct url_actions * cur = (struct url_actions *)file_data; while (cur != NULL) { next = cur->next; free_url_spec(cur->url); if ((next == NULL) || (next->action != cur->action)) { /* * As the action settings might be shared, * we can only free them if the current * url pattern is the last one, or if the * next one is using different settings. */ free_action_spec(cur->action); } freez(cur); cur = next; } } /********************************************************************* * * Function : free_alias_list * * Description : Free memory used by a list of aliases. * * Parameters : * 1 : alias_list = Linked list to free. * * Returns : N/A * *********************************************************************/ void free_alias_list(struct action_alias *alias_list) { while (alias_list != NULL) { struct action_alias * next = alias_list->next; alias_list->next = NULL; freez(alias_list->name); free_action(alias_list->action); free(alias_list); alias_list = next; } } /********************************************************************* * * Function : load_action_files * * Description : Read and parse all the action files and add to files * list. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int load_action_files(struct client_state *csp) { int i; int result; for (i = 0; i < MAX_AF_FILES; i++) { if (csp->config->actions_file[i]) { result = load_one_actions_file(csp, i); if (result) { return result; } } else if (current_actions_file[i]) { current_actions_file[i]->unloader = unload_actions_file; current_actions_file[i] = NULL; } } return 0; } /********************************************************************* * * Function : referenced_filters_are_missing * * Description : Checks if any filters of a certain type referenced * in an action spec are missing. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : cur_action = The action spec to check. * 3 : multi_index = The index where to look for the filter. * 4 : filter_type = The filter type the caller is interested in. * * Returns : 0 => All referenced filters exists, everything else is an error. * *********************************************************************/ static int referenced_filters_are_missing(const struct client_state *csp, const struct action_spec *cur_action, int multi_index, enum filter_type filter_type) { int i; struct file_list *fl; struct re_filterfile_spec *b; struct list_entry *filtername; for (filtername = cur_action->multi_add[multi_index]->first; filtername; filtername = filtername->next) { int filter_found = 0; for (i = 0; i < MAX_AF_FILES; i++) { fl = csp->rlist[i]; if ((NULL == fl) || (NULL == fl->f)) { continue; } for (b = fl->f; b; b = b->next) { if (b->type != filter_type) { continue; } if (strcmp(b->name, filtername->str) == 0) { filter_found = 1; } } } if (!filter_found) { log_error(LOG_LEVEL_ERROR, "Missing filter '%s'", filtername->str); return 1; } } return 0; } /********************************************************************* * * Function : action_spec_is_valid * * Description : Should eventually figure out if an action spec * is valid, but currently only checks that the * referenced filters are accounted for. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : cur_action = The action spec to check. * * Returns : 0 => No problems detected, everything else is an error. * *********************************************************************/ static int action_spec_is_valid(struct client_state *csp, const struct action_spec *cur_action) { struct { int multi_index; enum filter_type filter_type; } filter_map[] = { {ACTION_MULTI_FILTER, FT_CONTENT_FILTER}, {ACTION_MULTI_CLIENT_HEADER_FILTER, FT_CLIENT_HEADER_FILTER}, {ACTION_MULTI_SERVER_HEADER_FILTER, FT_SERVER_HEADER_FILTER}, {ACTION_MULTI_CLIENT_HEADER_TAGGER, FT_CLIENT_HEADER_TAGGER}, {ACTION_MULTI_SERVER_HEADER_TAGGER, FT_SERVER_HEADER_TAGGER} }; int errors = 0; int i; for (i = 0; i < SZ(filter_map); i++) { errors += referenced_filters_are_missing(csp, cur_action, filter_map[i].multi_index, filter_map[i].filter_type); } return errors; } /********************************************************************* * * Function : load_one_actions_file * * Description : Read and parse a action file and add to files * list. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : fileid = File index to load. * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ static int load_one_actions_file(struct client_state *csp, int fileid) { /* * Parser mode. * Note: Keep these in the order they occur in the file, they are * sometimes tested with <= */ enum { MODE_START_OF_FILE = 1, MODE_SETTINGS = 2, MODE_DESCRIPTION = 3, MODE_ALIAS = 4, MODE_ACTIONS = 5 } mode; FILE *fp; struct url_actions *last_perm; struct url_actions *perm; char *buf; struct file_list *fs; struct action_spec * cur_action = NULL; int cur_action_used = 0; struct action_alias * alias_list = NULL; unsigned long linenum = 0; mode = MODE_START_OF_FILE; if (!check_file_changed(current_actions_file[fileid], csp->config->actions_file[fileid], &fs)) { /* No need to load */ csp->actions_list[fileid] = current_actions_file[fileid]; return 0; } if (!fs) { log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': %E. " "Note that beginning with Privoxy 3.0.7, actions files have to be specified " "with their complete file names.", csp->config->actions_file[fileid]); return 1; /* never get here */ } fs->f = last_perm = (struct url_actions *)zalloc(sizeof(*last_perm)); if (last_perm == NULL) { log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!", csp->config->actions_file[fileid]); return 1; /* never get here */ } if ((fp = fopen(csp->config->actions_file[fileid], "r")) == NULL) { log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': error opening file: %E", csp->config->actions_file[fileid]); return 1; /* never get here */ } log_error(LOG_LEVEL_INFO, "Loading actions file: %s", csp->config->actions_file[fileid]); while (read_config_line(fp, &linenum, &buf) != NULL) { if (*buf == '{') { /* It's a header block */ if (buf[1] == '{') { /* It's {{settings}} or {{alias}} */ size_t len = strlen(buf); char * start = buf + 2; char * end = buf + len - 1; if ((len < (size_t)5) || (*end-- != '}') || (*end-- != '}')) { /* too short */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } /* Trim leading and trailing whitespace. */ end[1] = '\0'; chomp(start); if (*start == '\0') { /* too short */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid line (%lu): {{ }}", csp->config->actions_file[fileid], linenum); return 1; /* never get here */ } /* * An actionsfile can optionally contain the following blocks. * They *MUST* be in this order, to simplify processing: * * {{settings}} * name=value... * * {{description}} * ...free text, format TBD, but no line may start with a '{'... * * {{alias}} * name=actions... * * The actual actions must be *after* these special blocks. * None of these special blocks may be repeated. * */ if (0 == strcmpic(start, "settings")) { /* it's a {{settings}} block */ if (mode >= MODE_SETTINGS) { /* {{settings}} must be first thing in file and must only * appear once. */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': line %lu: {{settings}} must only appear once, and it must be before anything else.", csp->config->actions_file[fileid], linenum); } mode = MODE_SETTINGS; } else if (0 == strcmpic(start, "description")) { /* it's a {{description}} block */ if (mode >= MODE_DESCRIPTION) { /* {{description}} is a singleton and only {{settings}} may proceed it */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': line %lu: {{description}} must only appear once, and only a {{settings}} block may be above it.", csp->config->actions_file[fileid], linenum); } mode = MODE_DESCRIPTION; } else if (0 == strcmpic(start, "alias")) { /* it's an {{alias}} block */ if (mode >= MODE_ALIAS) { /* {{alias}} must be first thing in file, possibly after * {{settings}} and {{description}} * * {{alias}} must only appear once. * * Note that these are new restrictions introduced in * v2.9.10 in order to make actionsfile editing simpler. * (Otherwise, reordering actionsfile entries without * completely rewriting the file becomes non-trivial) */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': line %lu: {{alias}} must only appear once, and it must be before all actions.", csp->config->actions_file[fileid], linenum); } mode = MODE_ALIAS; } else { /* invalid {{something}} block */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid line (%lu): {{%s}}", csp->config->actions_file[fileid], linenum, start); return 1; /* never get here */ } } else { /* It's an actions block */ char *actions_buf; char * end; /* set mode */ mode = MODE_ACTIONS; /* free old action */ if (cur_action) { if (!cur_action_used) { free_action_spec(cur_action); } cur_action = NULL; } cur_action_used = 0; cur_action = (struct action_spec *)zalloc(sizeof(*cur_action)); if (cur_action == NULL) { fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory", csp->config->actions_file[fileid]); return 1; /* never get here */ } init_action(cur_action); /* * Copy the buffer before messing with it as we may need the * unmodified version in for the fatal error messages. Given * that this is not a common event, we could instead simply * read the line again. * * buf + 1 to skip the leading '{' */ actions_buf = strdup_or_die(buf + 1); /* check we have a trailing } and then trim it */ end = actions_buf + strlen(actions_buf) - 1; if (*end != '}') { /* No closing } */ fclose(fp); freez(actions_buf); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': " "Missing trailing '}' in action section starting at line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } *end = '\0'; /* trim any whitespace immediately inside {} */ chomp(actions_buf); if (get_actions(actions_buf, alias_list, cur_action)) { /* error */ fclose(fp); freez(actions_buf); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': " "can't completely parse the action section starting at line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } if (action_spec_is_valid(csp, cur_action)) { log_error(LOG_LEVEL_ERROR, "Invalid action section in file '%s', " "starting at line %lu: %s", csp->config->actions_file[fileid], linenum, buf); } freez(actions_buf); } } else if (mode == MODE_SETTINGS) { /* * Part of the {{settings}} block. * For now only serves to check if the file's minimum Privoxy * version requirement is met, but we may want to read & check * permissions when we go multi-user. */ if (!strncmp(buf, "for-privoxy-version=", 20)) { char *version_string, *fields[3]; int num_fields; version_string = strdup_or_die(buf + 20); num_fields = ssplit(version_string, ".", fields, SZ(fields)); if (num_fields < 1 || atoi(fields[0]) == 0) { log_error(LOG_LEVEL_ERROR, "While loading actions file '%s': invalid line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); } else if ( (atoi(fields[0]) > VERSION_MAJOR) || ((num_fields > 1) && (atoi(fields[1]) > VERSION_MINOR)) || ((num_fields > 2) && (atoi(fields[2]) > VERSION_POINT))) { fclose(fp); log_error(LOG_LEVEL_FATAL, "Actions file '%s', line %lu requires newer Privoxy version: %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } free(version_string); } } else if (mode == MODE_DESCRIPTION) { /* * Part of the {{description}} block. * Ignore for now. */ } else if (mode == MODE_ALIAS) { /* * define an alias */ char actions_buf[BUFFER_SIZE]; struct action_alias * new_alias; char * start = strchr(buf, '='); char * end = start; if ((start == NULL) || (start == buf)) { log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid alias line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } if ((new_alias = zalloc(sizeof(*new_alias))) == NULL) { fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!", csp->config->actions_file[fileid]); return 1; /* never get here */ } /* Eat any the whitespace before the '=' */ end--; while ((*end == ' ') || (*end == '\t')) { /* * we already know we must have at least 1 non-ws char * at start of buf - no need to check */ end--; } end[1] = '\0'; /* Eat any the whitespace after the '=' */ start++; while ((*start == ' ') || (*start == '\t')) { start++; } if (*start == '\0') { log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid alias line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } new_alias->name = strdup_or_die(buf); strlcpy(actions_buf, start, sizeof(actions_buf)); if (get_actions(actions_buf, alias_list, new_alias->action)) { /* error */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': invalid alias line (%lu): %s = %s", csp->config->actions_file[fileid], linenum, buf, start); return 1; /* never get here */ } /* add to list */ new_alias->next = alias_list; alias_list = new_alias; } else if (mode == MODE_ACTIONS) { /* it's an URL pattern */ /* allocate a new node */ if ((perm = zalloc(sizeof(*perm))) == NULL) { fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!", csp->config->actions_file[fileid]); return 1; /* never get here */ } perm->action = cur_action; cur_action_used = 1; /* Save the URL pattern */ if (create_url_spec(perm->url, buf)) { fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': line %lu: cannot create URL or TAG pattern from: %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } /* add it to the list */ last_perm->next = perm; last_perm = perm; } else if (mode == MODE_START_OF_FILE) { /* oops - please have a {} line as 1st line in file. */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': line %lu should begin with a '{': %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } else { /* How did we get here? This is impossible! */ fclose(fp); log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': INTERNAL ERROR - mode = %d", csp->config->actions_file[fileid], mode); return 1; /* never get here */ } freez(buf); } fclose(fp); if (!cur_action_used) { free_action_spec(cur_action); } free_alias_list(alias_list); /* the old one is now obsolete */ if (current_actions_file[fileid]) { current_actions_file[fileid]->unloader = unload_actions_file; } fs->next = files->next; files->next = fs; current_actions_file[fileid] = fs; csp->actions_list[fileid] = fs; return(0); } /********************************************************************* * * Function : actions_to_text * * Description : Converts a actionsfile entry from the internal * structure into a text line. The output is split * into one line for each action with line continuation. * * Parameters : * 1 : action = The action to format. * * Returns : A string. Caller must free it. * NULL on out-of-memory error. * *********************************************************************/ char * actions_to_text(const struct action_spec *action) { unsigned long mask = action->mask; unsigned long add = action->add; char *result = strdup_or_die(""); struct list_entry * lst; /* sanity - prevents "-feature +feature" */ mask |= add; #define DEFINE_ACTION_BOOL(__name, __bit) \ if (!(mask & __bit)) \ { \ string_append(&result, " -" __name " \\\n"); \ } \ else if (add & __bit) \ { \ string_append(&result, " +" __name " \\\n"); \ } #define DEFINE_ACTION_STRING(__name, __bit, __index) \ if (!(mask & __bit)) \ { \ string_append(&result, " -" __name " \\\n"); \ } \ else if (add & __bit) \ { \ string_append(&result, " +" __name "{"); \ string_append(&result, action->string[__index]); \ string_append(&result, "} \\\n"); \ } #define DEFINE_ACTION_MULTI(__name, __index) \ if (action->multi_remove_all[__index]) \ { \ string_append(&result, " -" __name " \\\n"); \ } \ else \ { \ lst = action->multi_remove[__index]->first; \ while (lst) \ { \ string_append(&result, " -" __name "{"); \ string_append(&result, lst->str); \ string_append(&result, "} \\\n"); \ lst = lst->next; \ } \ } \ lst = action->multi_add[__index]->first; \ while (lst) \ { \ string_append(&result, " +" __name "{"); \ string_append(&result, lst->str); \ string_append(&result, "} \\\n"); \ lst = lst->next; \ } #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */ #include "actionlist.h" #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS return result; } /********************************************************************* * * Function : actions_to_html * * Description : Converts a actionsfile entry from numeric form * ("mask" and "add") to a
    -separated HTML string * in which each action is linked to its chapter in * the user manual. * * Parameters : * 1 : csp = Client state (for config) * 2 : action = Action spec to be converted * * Returns : A string. Caller must free it. * NULL on out-of-memory error. * *********************************************************************/ char * actions_to_html(const struct client_state *csp, const struct action_spec *action) { unsigned long mask = action->mask; unsigned long add = action->add; char *result = strdup_or_die(""); struct list_entry * lst; /* sanity - prevents "-feature +feature" */ mask |= add; #define DEFINE_ACTION_BOOL(__name, __bit) \ if (!(mask & __bit)) \ { \ string_append(&result, "\n
    -"); \ string_join(&result, add_help_link(__name, csp->config)); \ } \ else if (add & __bit) \ { \ string_append(&result, "\n
    +"); \ string_join(&result, add_help_link(__name, csp->config)); \ } #define DEFINE_ACTION_STRING(__name, __bit, __index) \ if (!(mask & __bit)) \ { \ string_append(&result, "\n
    -"); \ string_join(&result, add_help_link(__name, csp->config)); \ } \ else if (add & __bit) \ { \ string_append(&result, "\n
    +"); \ string_join(&result, add_help_link(__name, csp->config)); \ string_append(&result, "{"); \ string_join(&result, html_encode(action->string[__index])); \ string_append(&result, "}"); \ } #define DEFINE_ACTION_MULTI(__name, __index) \ if (action->multi_remove_all[__index]) \ { \ string_append(&result, "\n
    -"); \ string_join(&result, add_help_link(__name, csp->config)); \ } \ else \ { \ lst = action->multi_remove[__index]->first; \ while (lst) \ { \ string_append(&result, "\n
    -"); \ string_join(&result, add_help_link(__name, csp->config)); \ string_append(&result, "{"); \ string_join(&result, html_encode(lst->str)); \ string_append(&result, "}"); \ lst = lst->next; \ } \ } \ lst = action->multi_add[__index]->first; \ while (lst) \ { \ string_append(&result, "\n
    +"); \ string_join(&result, add_help_link(__name, csp->config)); \ string_append(&result, "{"); \ string_join(&result, html_encode(lst->str)); \ string_append(&result, "}"); \ lst = lst->next; \ } #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */ #include "actionlist.h" #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS /* trim leading
    */ if (result && *result) { char * s = result; result = strdup(result + 5); free(s); } return result; } /********************************************************************* * * Function : current_actions_to_html * * Description : Converts a curren action spec to a
    separated HTML * text in which each action is linked to its chapter in * the user manual. * * Parameters : * 1 : csp = Client state (for config) * 2 : action = Current action spec to be converted * * Returns : A string. Caller must free it. * NULL on out-of-memory error. * *********************************************************************/ char *current_action_to_html(const struct client_state *csp, const struct current_action_spec *action) { unsigned long flags = action->flags; struct list_entry * lst; char *result = strdup_or_die(""); char *active = strdup_or_die(""); char *inactive = strdup_or_die(""); #define DEFINE_ACTION_BOOL(__name, __bit) \ if (flags & __bit) \ { \ string_append(&active, "\n
    +"); \ string_join(&active, add_help_link(__name, csp->config)); \ } \ else \ { \ string_append(&inactive, "\n
    -"); \ string_join(&inactive, add_help_link(__name, csp->config)); \ } #define DEFINE_ACTION_STRING(__name, __bit, __index) \ if (flags & __bit) \ { \ string_append(&active, "\n
    +"); \ string_join(&active, add_help_link(__name, csp->config)); \ string_append(&active, "{"); \ string_join(&active, html_encode(action->string[__index])); \ string_append(&active, "}"); \ } \ else \ { \ string_append(&inactive, "\n
    -"); \ string_join(&inactive, add_help_link(__name, csp->config)); \ } #define DEFINE_ACTION_MULTI(__name, __index) \ lst = action->multi[__index]->first; \ if (lst == NULL) \ { \ string_append(&inactive, "\n
    -"); \ string_join(&inactive, add_help_link(__name, csp->config)); \ } \ else \ { \ while (lst) \ { \ string_append(&active, "\n
    +"); \ string_join(&active, add_help_link(__name, csp->config)); \ string_append(&active, "{"); \ string_join(&active, html_encode(lst->str)); \ string_append(&active, "}"); \ lst = lst->next; \ } \ } #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */ #include "actionlist.h" #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS if (active != NULL) { string_append(&result, active); freez(active); } string_append(&result, "\n
    "); if (inactive != NULL) { string_append(&result, inactive); freez(inactive); } return result; } /********************************************************************* * * Function : action_to_line_of_text * * Description : Converts a action spec to a single text line * listing the enabled actions. * * Parameters : * 1 : action = Current action spec to be converted * * Returns : A string. Caller must free it. * Out-of-memory errors are fatal. * *********************************************************************/ char *actions_to_line_of_text(const struct current_action_spec *action) { char buffer[200]; struct list_entry *lst; char *active; const unsigned long flags = action->flags; active = strdup_or_die(""); #define DEFINE_ACTION_BOOL(__name, __bit) \ if (flags & __bit) \ { \ snprintf(buffer, sizeof(buffer), "+%s ", __name); \ string_append(&active, buffer); \ } \ #define DEFINE_ACTION_STRING(__name, __bit, __index) \ if (flags & __bit) \ { \ snprintf(buffer, sizeof(buffer), "+%s{%s} ", \ __name, action->string[__index]); \ string_append(&active, buffer); \ } \ #define DEFINE_ACTION_MULTI(__name, __index) \ lst = action->multi[__index]->first; \ while (lst != NULL) \ { \ snprintf(buffer, sizeof(buffer), "+%s{%s} ", \ __name, lst->str); \ string_append(&active, buffer); \ lst = lst->next; \ } \ #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */ #include "actionlist.h" #undef DEFINE_ACTION_MULTI #undef DEFINE_ACTION_STRING #undef DEFINE_ACTION_BOOL #undef DEFINE_ACTION_ALIAS if (active == NULL) { log_error(LOG_LEVEL_FATAL, "Out of memory in action_to_line_of_text()"); } return active; } privoxy-3.0.21-stable/./loadcfg.h000640 001751 001751 00000005515 11630656300 015540 0ustar00fkfk000000 000000 #ifndef LOADCFG_H_INCLUDED #define LOADCFG_H_INCLUDED #define LOADCFG_H_VERSION "$Id: loadcfg.h,v 1.16 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.h,v $ * * Purpose : Loads settings from the configuration file into * global variables. This file contains both the * routine to load the configuration and the global * variables it writes to. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif /* Don't need project.h, only this: */ struct configuration_spec; /* Global variables */ #ifdef FEATURE_TOGGLE /* Privoxy's toggle state */ extern int global_toggle_state; #endif /* def FEATURE_TOGGLE */ extern const char *configfile; /* The load_config function is now going to call: * init_proxy_args, so it will need argc and argv. * Since load_config will also be a signal handler, * we need to have these globally available. */ extern int Argc; extern char * const * Argv; extern short int MustReload; extern struct configuration_spec * load_config(void); #ifdef FEATURE_GRACEFUL_TERMINATION void unload_current_config_file(void); #endif /* Revision control strings from this header and associated .c file */ extern const char loadcfg_rcs[]; extern const char loadcfg_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef LOADCFG_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./win32.h000640 001751 001751 00000004302 11630656300 015074 0ustar00fkfk000000 000000 #ifndef WIN32_H_INCLUDED #define WIN32_H_INCLUDED #define WIN32_H_VERSION "$Id: win32.h,v 1.9 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/win32.h,v $ * * Purpose : Win32 User Interface initialization and message loop * * Copyright : Written by and Copyright (C) 2001-2002 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 1999 Adam Lock * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif extern const char win32_blurb[]; extern void InitWin32(void); #ifdef _WIN_CONSOLE extern int hideConsole; #endif /*def _WIN_CONSOLE */ extern HINSTANCE g_hInstance; extern int g_nCmdShow; extern int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); /* Revision control strings from this header and associated .c file */ extern const char win32_rcs[]; extern const char win32_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef WIN32_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./cgisimple.c000640 001751 001751 00000164451 12100755154 016115 0ustar00fkfk000000 000000 const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.120 2013/01/26 13:30:20 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgisimple.c,v $ * * Purpose : Simple CGIs to get information about Privoxy's * status. * * Copyright : Written by and Copyright (C) 2001-2013 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "config.h" #include #include #include #include #include #include #if defined (HAVE_ACCESS) && defined (HAVE_UNISTD_H) #include #endif /* def HAVE_ACCESS && HAVE_UNISTD_H */ #include "project.h" #include "cgi.h" #include "cgisimple.h" #include "list.h" #include "encode.h" #include "jcc.h" #include "filters.h" #include "actions.h" #include "miscutil.h" #include "loadcfg.h" #include "parsers.h" #include "urlmatch.h" #include "errlog.h" const char cgisimple_h_rcs[] = CGISIMPLE_H_VERSION; static char *show_rcs(void); static jb_err show_defines(struct map *exports); static jb_err cgi_show_file(struct client_state *csp, struct http_response *rsp, const struct map *parameters); static jb_err load_file(const char *filename, char **buffer, size_t *length); /********************************************************************* * * Function : cgi_default * * Description : CGI function that is called for the CGI_SITE_1_HOST * and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs. * Boring - only exports the default exports. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * *********************************************************************/ jb_err cgi_default(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map *exports; (void)parameters; assert(csp); assert(rsp); if (NULL == (exports = default_exports(csp, ""))) { return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "default", exports, rsp); } /********************************************************************* * * Function : cgi_error_404 * * Description : CGI function that is called if an unknown action was * given. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_error_404(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map *exports; assert(csp); assert(rsp); assert(parameters); if (NULL == (exports = default_exports(csp, NULL))) { return JB_ERR_MEMORY; } rsp->status = strdup("404 Privoxy configuration page not found"); if (rsp->status == NULL) { free_map(exports); return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp); } #ifdef FEATURE_GRACEFUL_TERMINATION /********************************************************************* * * Function : cgi_die * * Description : CGI function to shut down Privoxy. * NOTE: Turning this on in a production build * would be a BAD idea. An EXTREMELY BAD idea. * In short, don't do it. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_die (struct client_state *csp, struct http_response *rsp, const struct map *parameters) { static const char status[] = "200 OK Privoxy shutdown request received"; static const char body[] = "\n" "\n" " Privoxy shutdown request received\n" " \n" " \n" "\n" "\n" "

    Privoxy shutdown request received

    \n" "

    Privoxy is going to shut down after the next request.

    \n" "\n" "\n"; assert(csp); assert(rsp); assert(parameters); /* quit */ g_terminate = 1; csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; rsp->content_length = 0; rsp->head_length = 0; rsp->is_static = 0; rsp->body = strdup(body); rsp->status = strdup(status); if ((rsp->body == NULL) || (rsp->status == NULL)) { return JB_ERR_MEMORY; } return JB_ERR_OK; } #endif /* def FEATURE_GRACEFUL_TERMINATION */ /********************************************************************* * * Function : cgi_show_request * * Description : Show the client's request and what sed() would have * made of it. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_show_request(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { char *p; struct map *exports; assert(csp); assert(rsp); assert(parameters); if (NULL == (exports = default_exports(csp, "show-request"))) { return JB_ERR_MEMORY; } /* * Repair the damage done to the IOB by get_header() */ for (p = csp->client_iob->buf; p < csp->client_iob->cur; p++) { if (*p == '\0') *p = '\n'; } /* * Export the original client's request and the one we would * be sending to the server if this wasn't a CGI call */ if (map(exports, "client-request", 1, html_encode(csp->client_iob->buf), 0)) { free_map(exports); return JB_ERR_MEMORY; } if (map(exports, "processed-request", 1, html_encode_and_free_original(list_to_text(csp->headers)), 0)) { free_map(exports); return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "show-request", exports, rsp); } /********************************************************************* * * Function : cgi_send_banner * * Description : CGI function that returns a banner. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * type : Selects the type of banner between "trans", "logo", * and "auto". Defaults to "logo" if absent or invalid. * "auto" means to select as if we were image-blocking. * (Only the first character really counts; b and t are * equivalent). * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_banner(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { char imagetype = lookup(parameters, "type")[0]; /* * If type is auto, then determine the right thing * to do from the set-image-blocker action */ if (imagetype == 'a') { /* * Default to pattern */ imagetype = 'p'; #ifdef FEATURE_IMAGE_BLOCKING if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0) { static const char prefix1[] = CGI_PREFIX "send-banner?type="; static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type="; const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER]; if (p == NULL) { /* Use default - nothing to do here. */ } else if (0 == strcmpic(p, "blank")) { imagetype = 'b'; } else if (0 == strcmpic(p, "pattern")) { imagetype = 'p'; } /* * If the action is to call this CGI, determine * the argument: */ else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1)) { imagetype = p[sizeof(prefix1) - 1]; } else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1)) { imagetype = p[sizeof(prefix2) - 1]; } /* * Everything else must (should) be a URL to * redirect to. */ else { imagetype = 'r'; } } #endif /* def FEATURE_IMAGE_BLOCKING */ } /* * Now imagetype is either the non-auto type we were called with, * or it was auto and has since been determined. In any case, we * can proceed to actually answering the request by sending a redirect * or an image as appropriate: */ if (imagetype == 'r') { rsp->status = strdup("302 Local Redirect from Privoxy"); if (rsp->status == NULL) { return JB_ERR_MEMORY; } if (enlist_unique_header(rsp->headers, "Location", csp->action->string[ACTION_STRING_IMAGE_BLOCKER])) { return JB_ERR_MEMORY; } } else { if ((imagetype == 'b') || (imagetype == 't')) { rsp->body = bindup(image_blank_data, image_blank_length); rsp->content_length = image_blank_length; } else { rsp->body = bindup(image_pattern_data, image_pattern_length); rsp->content_length = image_pattern_length; } if (rsp->body == NULL) { return JB_ERR_MEMORY; } if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE)) { return JB_ERR_MEMORY; } rsp->is_static = 1; } return JB_ERR_OK; } /********************************************************************* * * Function : cgi_transparent_image * * Description : CGI function that sends a 1x1 transparent image. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_transparent_image(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { (void)csp; (void)parameters; rsp->body = bindup(image_blank_data, image_blank_length); rsp->content_length = image_blank_length; if (rsp->body == NULL) { return JB_ERR_MEMORY; } if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE)) { return JB_ERR_MEMORY; } rsp->is_static = 1; return JB_ERR_OK; } /********************************************************************* * * Function : cgi_send_default_favicon * * Description : CGI function that sends the standard favicon. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_default_favicon(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { static const char default_favicon_data[] = "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260" "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000" "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000" "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000" "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077" "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000" "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000" "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036" "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360" "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360" "\017\000\000"; static const size_t favicon_length = sizeof(default_favicon_data) - 1; (void)csp; (void)parameters; rsp->body = bindup(default_favicon_data, favicon_length); rsp->content_length = favicon_length; if (rsp->body == NULL) { return JB_ERR_MEMORY; } if (enlist(rsp->headers, "Content-Type: image/x-icon")) { return JB_ERR_MEMORY; } rsp->is_static = 1; return JB_ERR_OK; } /********************************************************************* * * Function : cgi_send_error_favicon * * Description : CGI function that sends the favicon for error pages. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_error_favicon(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { static const char error_favicon_data[] = "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260" "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000" "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000" "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000" "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077" "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000" "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000" "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036" "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360" "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360" "\017\000\000"; static const size_t favicon_length = sizeof(error_favicon_data) - 1; (void)csp; (void)parameters; rsp->body = bindup(error_favicon_data, favicon_length); rsp->content_length = favicon_length; if (rsp->body == NULL) { return JB_ERR_MEMORY; } if (enlist(rsp->headers, "Content-Type: image/x-icon")) { return JB_ERR_MEMORY; } rsp->is_static = 1; return JB_ERR_OK; } /********************************************************************* * * Function : cgi_send_stylesheet * * Description : CGI function that sends a css stylesheet found * in the cgi-style.css template * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_stylesheet(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { jb_err err; assert(csp); assert(rsp); (void)parameters; err = template_load(csp, &rsp->body, "cgi-style.css", 0); if (err == JB_ERR_FILE) { /* * No way to tell user; send empty stylesheet */ log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template"); } else if (err) { return err; /* JB_ERR_MEMORY */ } if (enlist(rsp->headers, "Content-Type: text/css")) { return JB_ERR_MEMORY; } return JB_ERR_OK; } /********************************************************************* * * Function : cgi_send_url_info_osd * * Description : CGI function that sends the OpenSearch Description * template for the show-url-info page. It allows to * access the page through "search engine plugins". * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_url_info_osd(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { jb_err err = JB_ERR_MEMORY; struct map *exports = default_exports(csp, NULL); (void)csp; (void)parameters; if (NULL != exports) { err = template_fill_for_cgi(csp, "url-info-osd.xml", exports, rsp); if (JB_ERR_OK == err) { err = enlist(rsp->headers, "Content-Type: application/opensearchdescription+xml"); } } return err; } /********************************************************************* * * Function : get_content_type * * Description : Use the file extension to guess the content type * header we should use to serve the file. * * Parameters : * 1 : filename = Name of the file whose content type * we care about * * Returns : The guessed content type. * *********************************************************************/ static const char *get_content_type(const char *filename) { int i; struct content_type { const char *extension; const char *content_type; }; static const struct content_type content_types[] = { {".css", "text/css"}, {".jpg", "image/jpeg"}, {".jpeg", "image/jpeg"}, {".png", "image/png"}, }; for (i = 0; i < SZ(content_types); i++) { if (strstr(filename, content_types[i].extension)) { return content_types[i].content_type; } } /* No match by extension, default to html */ return "text/html"; } /********************************************************************* * * Function : cgi_send_user_manual * * Description : CGI function that sends a file in the user * manual directory. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : file=name.html, the name of the HTML file * (relative to user-manual from config) * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_send_user_manual(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { const char *filename; char *full_path; jb_err err = JB_ERR_OK; const char *content_type; assert(csp); assert(rsp); assert(parameters); if (0 == strncmpic(csp->config->usermanual, "http://", 7)) { log_error(LOG_LEVEL_CGI, "Request for local user-manual " "received while user-manual delivery is disabled."); return cgi_error_404(csp, rsp, parameters); } if (!parameters->first) { /* requested http://p.p/user-manual (without trailing slash) */ return cgi_redirect(rsp, CGI_PREFIX "user-manual/"); } get_string_param(parameters, "file", &filename); if (filename == NULL) { /* It's '/' so serve the index.html if there is one. */ filename = "index.html"; } else if (NULL != strchr(filename, '/') || NULL != strstr(filename, "..")) { /* * We currently only support a flat file * hierarchy for the documentation. */ log_error(LOG_LEVEL_ERROR, "Rejecting the request to serve '%s' as it contains '/' or '..'", filename); return JB_ERR_CGI_PARAMS; } full_path = make_path(csp->config->usermanual, filename); if (full_path == NULL) { return JB_ERR_MEMORY; } err = load_file(full_path, &rsp->body, &rsp->content_length); if (JB_ERR_OK != err) { assert((JB_ERR_FILE == err) || (JB_ERR_MEMORY == err)); if (JB_ERR_FILE == err) { err = cgi_error_no_template(csp, rsp, full_path); } freez(full_path); return err; } freez(full_path); content_type = get_content_type(filename); log_error(LOG_LEVEL_CGI, "Content-Type guessed for %s: %s", filename, content_type); return enlist_unique_header(rsp->headers, "Content-Type", content_type); } /********************************************************************* * * Function : cgi_show_version * * Description : CGI function that returns a a web page describing the * file versions of Privoxy. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : none * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_show_version(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { struct map *exports; assert(csp); assert(rsp); assert(parameters); if (NULL == (exports = default_exports(csp, "show-version"))) { return JB_ERR_MEMORY; } if (map(exports, "sourceversions", 1, show_rcs(), 0)) { free_map(exports); return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "show-version", exports, rsp); } /********************************************************************* * * Function : cgi_show_status * * Description : CGI function that returns a web page describing the * current status of Privoxy. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * file : Which file to show. Only first letter is checked, * valid values are: * - "a"ction file * - "r"egex * - "t"rust * Default is to show menu and other information. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_show_status(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { char *s = NULL; unsigned i; int j; char buf[BUFFER_SIZE]; #ifdef FEATURE_STATISTICS float perc_rej; /* Percentage of http requests rejected */ int local_urls_read; int local_urls_rejected; #endif /* ndef FEATURE_STATISTICS */ jb_err err = JB_ERR_OK; struct map *exports; assert(csp); assert(rsp); assert(parameters); if ('\0' != *(lookup(parameters, "file"))) { return cgi_show_file(csp, rsp, parameters); } if (NULL == (exports = default_exports(csp, "show-status"))) { return JB_ERR_MEMORY; } s = strdup(""); for (j = 0; (s != NULL) && (j < Argc); j++) { if (!err) err = string_join (&s, html_encode(Argv[j])); if (!err) err = string_append(&s, " "); } if (!err) err = map(exports, "invocation", 1, s, 0); if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1); if (!err) err = show_defines(exports); if (err) { free_map(exports); return JB_ERR_MEMORY; } #ifdef FEATURE_STATISTICS local_urls_read = urls_read; local_urls_rejected = urls_rejected; /* * Need to alter the stats not to include the fetch of this * page. * * Can't do following thread safely! doh! * * urls_read--; * urls_rejected--; * This will be incremented subsequently * */ if (local_urls_read == 0) { if (!err) err = map_block_killer(exports, "have-stats"); } else { if (!err) err = map_block_killer(exports, "have-no-stats"); perc_rej = (float)local_urls_rejected * 100.0F / (float)local_urls_read; snprintf(buf, sizeof(buf), "%d", local_urls_read); if (!err) err = map(exports, "requests-received", 1, buf, 1); snprintf(buf, sizeof(buf), "%d", local_urls_rejected); if (!err) err = map(exports, "requests-blocked", 1, buf, 1); snprintf(buf, sizeof(buf), "%6.2f", perc_rej); if (!err) err = map(exports, "percent-blocked", 1, buf, 1); } #else /* ndef FEATURE_STATISTICS */ err = err || map_block_killer(exports, "statistics"); #endif /* ndef FEATURE_STATISTICS */ /* * List all action files in use, together with view and edit links, * except for standard.action, which should only be viewable. (Not * enforced in the editor itself) * FIXME: Shouldn't include hardwired HTML here, use line template instead! */ s = strdup(""); for (i = 0; i < MAX_AF_FILES; i++) { if (csp->actions_list[i] != NULL) { if (!err) err = string_append(&s, ""); if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename)); snprintf(buf, sizeof(buf), "View", i); if (!err) err = string_append(&s, buf); #ifdef FEATURE_CGI_EDIT_ACTIONS if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS) && (NULL == strstr(csp->actions_list[i]->filename, "standard.action")) && (NULL != csp->config->actions_file_short[i])) { #ifdef HAVE_ACCESS if (access(csp->config->actions_file[i], W_OK) == 0) { #endif /* def HAVE_ACCESS */ snprintf(buf, sizeof(buf), "  Edit", i); if (!err) err = string_append(&s, buf); #ifdef HAVE_ACCESS } else { if (!err) err = string_append(&s, "  No write access."); } #endif /* def HAVE_ACCESS */ } #endif if (!err) err = string_append(&s, "\n"); } } if (*s != '\0') { if (!err) err = map(exports, "actions-filenames", 1, s, 0); } else { if (!err) err = map(exports, "actions-filenames", 1, "None specified", 1); } /* * List all re_filterfiles in use, together with view options. * FIXME: Shouldn't include hardwired HTML here, use line template instead! */ s = strdup(""); for (i = 0; i < MAX_AF_FILES; i++) { if (csp->rlist[i] != NULL) { if (!err) err = string_append(&s, ""); if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename)); snprintf(buf, sizeof(buf), "View", i); if (!err) err = string_append(&s, buf); if (!err) err = string_append(&s, "\n"); } } if (*s != '\0') { if (!err) err = map(exports, "re-filter-filenames", 1, s, 0); } else { if (!err) err = map(exports, "re-filter-filenames", 1, "None specified", 1); if (!err) err = map_block_killer(exports, "have-filterfile"); } #ifdef FEATURE_TRUST if (csp->tlist) { if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0); } else { if (!err) err = map(exports, "trust-filename", 1, "None specified", 1); if (!err) err = map_block_killer(exports, "have-trustfile"); } #else if (!err) err = map_block_killer(exports, "trust-support"); #endif /* ndef FEATURE_TRUST */ #ifdef FEATURE_CGI_EDIT_ACTIONS if (!err && (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { err = map_block_killer(exports, "cgi-editor-is-disabled"); } #endif /* ndef CGI_EDIT_ACTIONS */ if (err) { free_map(exports); return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "show-status", exports, rsp); } /********************************************************************* * * Function : cgi_show_url_info * * Description : CGI function that determines and shows which actions * Privoxy will perform for a given url, and which * matches starting from the defaults have lead to that. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * url : The url whose actions are to be determined. * If url is unset, the url-given conditional will be * set, so that all but the form can be suppressed in * the template. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_show_url_info(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { char *url_param; struct map *exports; char buf[150]; assert(csp); assert(rsp); assert(parameters); if (NULL == (exports = default_exports(csp, "show-url-info"))) { return JB_ERR_MEMORY; } /* * Get the url= parameter (if present) and remove any leading/trailing spaces. */ url_param = strdup(lookup(parameters, "url")); if (url_param == NULL) { free_map(exports); return JB_ERR_MEMORY; } chomp(url_param); /* * Handle prefixes. 4 possibilities: * 1) "http://" or "https://" prefix present and followed by URL - OK * 2) Only the "http://" or "https://" part is present, no URL - change * to empty string so it will be detected later as "no URL". * 3) Parameter specified but doesn't start with "http(s?)://" - add a * "http://" prefix. * 4) Parameter not specified or is empty string - let this fall through * for now, next block of code will handle it. */ if (0 == strncmp(url_param, "http://", 7)) { if (url_param[7] == '\0') { /* * Empty URL (just prefix). * Make it totally empty so it's caught by the next if () */ url_param[0] = '\0'; } } else if (0 == strncmp(url_param, "https://", 8)) { if (url_param[8] == '\0') { /* * Empty URL (just prefix). * Make it totally empty so it's caught by the next if () */ url_param[0] = '\0'; } } else if ((url_param[0] != '\0') && ((NULL == strstr(url_param, "://") || (strstr(url_param, "://") > strstr(url_param, "/"))))) { /* * No prefix or at least no prefix before * the first slash - assume http:// */ char *url_param_prefixed = strdup("http://"); if (JB_ERR_OK != string_join(&url_param_prefixed, url_param)) { free_map(exports); return JB_ERR_MEMORY; } url_param = url_param_prefixed; } /* * Hide "toggle off" warning if Privoxy is toggled on. */ if ( #ifdef FEATURE_TOGGLE (global_toggle_state == 1) && #endif /* def FEATURE_TOGGLE */ map_block_killer(exports, "privoxy-is-toggled-off") ) { free_map(exports); return JB_ERR_MEMORY; } if (url_param[0] == '\0') { /* URL paramater not specified, display query form only. */ free(url_param); if (map_block_killer(exports, "url-given") || map(exports, "url", 1, "", 1)) { free_map(exports); return JB_ERR_MEMORY; } } else { /* Given a URL, so query it. */ jb_err err; char *matches; char *s; int hits = 0; struct file_list *fl; struct url_actions *b; struct http_request url_to_query[1]; struct current_action_spec action[1]; int i; if (map(exports, "url", 1, html_encode(url_param), 0)) { free(url_param); free_map(exports); return JB_ERR_MEMORY; } init_current_action(action); if (map(exports, "default", 1, current_action_to_html(csp, action), 0)) { free_current_action(action); free(url_param); free_map(exports); return JB_ERR_MEMORY; } memset(url_to_query, '\0', sizeof(url_to_query)); err = parse_http_url(url_param, url_to_query, REQUIRE_PROTOCOL); assert((err != JB_ERR_OK) || (url_to_query->ssl == !strncmpic(url_param, "https://", 8))); free(url_param); if (err == JB_ERR_MEMORY) { free_http_request(url_to_query); free_current_action(action); free_map(exports); return JB_ERR_MEMORY; } else if (err) { /* Invalid URL */ err = map(exports, "matches", 1, "[Invalid URL specified!]" , 1); if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1); if (!err) err = map_block_killer(exports, "valid-url"); free_current_action(action); free_http_request(url_to_query); if (err) { free_map(exports); return JB_ERR_MEMORY; } return template_fill_for_cgi(csp, "show-url-info", exports, rsp); } /* * We have a warning about SSL paths. Hide it for unencrypted sites. */ if (!url_to_query->ssl) { if (map_block_killer(exports, "https")) { free_current_action(action); free_map(exports); free_http_request(url_to_query); return JB_ERR_MEMORY; } } matches = strdup(""); for (i = 0; i < MAX_AF_FILES; i++) { if (NULL == csp->config->actions_file_short[i] || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue; b = NULL; hits = 1; if ((fl = csp->actions_list[i]) != NULL) { if ((b = fl->f) != NULL) { /* FIXME: Hardcoded HTML! */ string_append(&matches, "\n"); hits = 0; b = b->next; } } for (; (b != NULL) && (matches != NULL); b = b->next) { if (url_match(b->url, url_to_query)) { string_append(&matches, "\n"); if (merge_current_action(action, b->action)) { freez(matches); free_http_request(url_to_query); free_current_action(action); free_map(exports); return JB_ERR_MEMORY; } hits++; } } if (!hits) { string_append(&matches, "\n"); } } string_append(&matches, "
    In file: "); string_join (&matches, html_encode(csp->config->actions_file_short[i])); snprintf(buf, sizeof(buf), " ", i); string_append(&matches, buf); string_append(&matches, "View"); #ifdef FEATURE_CGI_EDIT_ACTIONS if (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS) { #ifdef HAVE_ACCESS if (access(csp->config->actions_file[i], W_OK) == 0) { #endif /* def HAVE_ACCESS */ snprintf(buf, sizeof(buf), " ", i); string_append(&matches, buf); string_append(&matches, "Edit"); #ifdef HAVE_ACCESS } else { string_append(&matches, " No write access."); } #endif /* def HAVE_ACCESS */ } #endif /* FEATURE_CGI_EDIT_ACTIONS */ string_append(&matches, "
    {"); string_join (&matches, actions_to_html(csp, b->action)); string_append(&matches, " }
    \n"); string_join (&matches, html_encode(b->url->spec)); string_append(&matches, "
    (no matches in this file)
    \n"); /* * XXX: Kludge to make sure the "Forward settings" section * shows what forward-override{} would do with the requested URL. * No one really cares how the CGI request would be forwarded * if it wasn't intercepted as CGI request in the first place. * * From here on the action bitmask will no longer reflect * the real url (http://config.privoxy.org/show-url-info?url=.*), * but luckily it's no longer required later on anyway. */ free_current_action(csp->action); get_url_actions(csp, url_to_query); /* * Fill in forwarding settings. * * The possibilities are: * - no forwarding * - http forwarding only * - socks4(a) forwarding only * - socks4(a) and http forwarding. * * XXX: Parts of this code could be reused for the * "forwarding-failed" template which currently doesn't * display the proxy port and an eventual second forwarder. */ { const struct forward_spec *fwd = forward_url(csp, url_to_query); if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL)) { if (!err) err = map_block_killer(exports, "socks-forwarder"); if (!err) err = map_block_killer(exports, "http-forwarder"); } else { char port[10]; /* We save proxy ports as int but need a string here */ if (!err) err = map_block_killer(exports, "no-forwarder"); if (fwd->gateway_host != NULL) { char *socks_type = NULL; switch (fwd->type) { case SOCKS_4: socks_type = "socks4"; break; case SOCKS_4A: socks_type = "socks4a"; break; case SOCKS_5: socks_type = "socks5"; break; case SOCKS_5T: socks_type = "socks5t"; break; default: log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type); } if (!err) err = map(exports, "socks-type", 1, socks_type, 1); if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1); snprintf(port, sizeof(port), "%d", fwd->gateway_port); if (!err) err = map(exports, "gateway-port", 1, port, 1); } else { if (!err) err = map_block_killer(exports, "socks-forwarder"); } if (fwd->forward_host != NULL) { if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1); snprintf(port, sizeof(port), "%d", fwd->forward_port); if (!err) err = map(exports, "forward-port", 1, port, 1); } else { if (!err) err = map_block_killer(exports, "http-forwarder"); } } } free_http_request(url_to_query); if (err || matches == NULL) { free_current_action(action); free_map(exports); return JB_ERR_MEMORY; } #ifdef FEATURE_CGI_EDIT_ACTIONS if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { err = map_block_killer(exports, "cgi-editor-is-disabled"); } #endif /* FEATURE_CGI_EDIT_ACTIONS */ /* * If zlib support is available, if no content filters * are enabled or if the prevent-compression action is enabled, * suppress the "compression could prevent filtering" warning. */ #ifndef FEATURE_ZLIB if (!content_filters_enabled(action) || (action->flags & ACTION_NO_COMPRESSION)) #endif { if (!err) err = map_block_killer(exports, "filters-might-be-ineffective"); } if (err || map(exports, "matches", 1, matches , 0)) { free_current_action(action); free_map(exports); return JB_ERR_MEMORY; } s = current_action_to_html(csp, action); free_current_action(action); if (map(exports, "final", 1, s, 0)) { free_map(exports); return JB_ERR_MEMORY; } } return template_fill_for_cgi(csp, "show-url-info", exports, rsp); } /********************************************************************* * * Function : cgi_robots_txt * * Description : CGI function to return "/robots.txt". * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : None * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ jb_err cgi_robots_txt(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { char buf[100]; jb_err err; (void)csp; (void)parameters; rsp->body = strdup( "# This is the Privoxy control interface.\n" "# It isn't very useful to index it, and you're likely to break stuff.\n" "# So go away!\n" "\n" "User-agent: *\n" "Disallow: /\n" "\n"); if (rsp->body == NULL) { return JB_ERR_MEMORY; } err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13); rsp->is_static = 1; get_http_time(7 * 24 * 60 * 60, buf, sizeof(buf)); /* 7 days into future */ if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf); return (err ? JB_ERR_MEMORY : JB_ERR_OK); } /********************************************************************* * * Function : show_defines * * Description : Add to a map the state od all conditional #defines * used when building * * Parameters : * 1 : exports = map to extend * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err show_defines(struct map *exports) { jb_err err = JB_ERR_OK; #ifdef FEATURE_ACCEPT_FILTER if (!err) err = map_conditional(exports, "FEATURE_ACCEPT_FILTER", 1); #else /* ifndef FEATURE_ACCEPT_FILTER */ if (!err) err = map_conditional(exports, "FEATURE_ACCEPT_FILTER", 0); #endif /* ndef FEATURE_ACCEPT_FILTER */ #ifdef FEATURE_ACL if (!err) err = map_conditional(exports, "FEATURE_ACL", 1); #else /* ifndef FEATURE_ACL */ if (!err) err = map_conditional(exports, "FEATURE_ACL", 0); #endif /* ndef FEATURE_ACL */ #ifdef FEATURE_CGI_EDIT_ACTIONS if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 1); #else /* ifndef FEATURE_CGI_EDIT_ACTIONS */ if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 0); #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */ #ifdef FEATURE_COMPRESSION if (!err) err = map_conditional(exports, "FEATURE_COMPRESSION", 1); #else /* ifndef FEATURE_COMPRESSION */ if (!err) err = map_conditional(exports, "FEATURE_COMPRESSION", 0); #endif /* ndef FEATURE_COMPRESSION */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_KEEP_ALIVE", 1); #else /* ifndef FEATURE_CONNECTION_KEEP_ALIVE */ if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_KEEP_ALIVE", 0); #endif /* ndef FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_CONNECTION_SHARING if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_SHARING", 1); #else /* ifndef FEATURE_CONNECTION_SHARING */ if (!err) err = map_conditional(exports, "FEATURE_CONNECTION_SHARING", 0); #endif /* ndef FEATURE_CONNECTION_SHARING */ #ifdef FEATURE_FAST_REDIRECTS if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 1); #else /* ifndef FEATURE_FAST_REDIRECTS */ if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 0); #endif /* ndef FEATURE_FAST_REDIRECTS */ #ifdef FEATURE_FORCE_LOAD if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 1); if (!err) err = map(exports, "FORCE_PREFIX", 1, FORCE_PREFIX, 1); #else /* ifndef FEATURE_FORCE_LOAD */ if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 0); if (!err) err = map(exports, "FORCE_PREFIX", 1, "(none - disabled)", 1); #endif /* ndef FEATURE_FORCE_LOAD */ #ifdef FEATURE_GRACEFUL_TERMINATION if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 1); #else /* ifndef FEATURE_GRACEFUL_TERMINATION */ if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 0); #endif /* ndef FEATURE_GRACEFUL_TERMINATION */ #ifdef FEATURE_IMAGE_BLOCKING if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 1); #else /* ifndef FEATURE_IMAGE_BLOCKING */ if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 0); #endif /* ndef FEATURE_IMAGE_BLOCKING */ #ifdef FEATURE_IMAGE_DETECT_MSIE if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 1); #else /* ifndef FEATURE_IMAGE_DETECT_MSIE */ if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 0); #endif /* ndef FEATURE_IMAGE_DETECT_MSIE */ #ifdef HAVE_RFC2553 if (!err) err = map_conditional(exports, "FEATURE_IPV6_SUPPORT", 1); #else /* ifndef HAVE_RFC2553 */ if (!err) err = map_conditional(exports, "FEATURE_IPV6_SUPPORT", 0); #endif /* ndef HAVE_RFC2553 */ #ifdef FEATURE_NO_GIFS if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 1); #else /* ifndef FEATURE_NO_GIFS */ if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 0); #endif /* ndef FEATURE_NO_GIFS */ #ifdef FEATURE_PTHREAD if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 1); #else /* ifndef FEATURE_PTHREAD */ if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 0); #endif /* ndef FEATURE_PTHREAD */ #ifdef FEATURE_STATISTICS if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 1); #else /* ifndef FEATURE_STATISTICS */ if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 0); #endif /* ndef FEATURE_STATISTICS */ #ifdef FEATURE_STRPTIME_SANITY_CHECKS if (!err) err = map_conditional(exports, "FEATURE_STRPTIME_SANITY_CHECKS", 1); #else /* ifndef FEATURE_STRPTIME_SANITY_CHECKS */ if (!err) err = map_conditional(exports, "FEATURE_STRPTIME_SANITY_CHECKS", 0); #endif /* ndef FEATURE_STRPTIME_SANITY_CHECKS */ #ifdef FEATURE_TOGGLE if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 1); #else /* ifndef FEATURE_TOGGLE */ if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 0); #endif /* ndef FEATURE_TOGGLE */ #ifdef FEATURE_TRUST if (!err) err = map_conditional(exports, "FEATURE_TRUST", 1); #else /* ifndef FEATURE_TRUST */ if (!err) err = map_conditional(exports, "FEATURE_TRUST", 0); #endif /* ndef FEATURE_TRUST */ #ifdef FEATURE_ZLIB if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 1); #else /* ifndef FEATURE_ZLIB */ if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 0); #endif /* ndef FEATURE_ZLIB */ #ifdef STATIC_PCRE if (!err) err = map_conditional(exports, "STATIC_PCRE", 1); #else /* ifndef STATIC_PCRE */ if (!err) err = map_conditional(exports, "STATIC_PCRE", 0); #endif /* ndef STATIC_PCRE */ #ifdef STATIC_PCRS if (!err) err = map_conditional(exports, "STATIC_PCRS", 1); #else /* ifndef STATIC_PCRS */ if (!err) err = map_conditional(exports, "STATIC_PCRS", 0); #endif /* ndef STATIC_PCRS */ return err; } /********************************************************************* * * Function : show_rcs * * Description : Create a string with the rcs info for all sourcefiles * * Parameters : None * * Returns : A string, or NULL on out-of-memory. * *********************************************************************/ static char *show_rcs(void) { char *result = strdup(""); char buf[BUFFER_SIZE]; /* Instead of including *all* dot h's in the project (thus creating a * tremendous amount of dependencies), I will concede to declaring them * as extern's. This forces the developer to add to this list, but oh well. */ #define SHOW_RCS(__x) \ { \ extern const char __x[]; \ snprintf(buf, sizeof(buf), " %s\n", __x); \ string_append(&result, buf); \ } /* In alphabetical order */ SHOW_RCS(actions_h_rcs) SHOW_RCS(actions_rcs) #ifdef AMIGA SHOW_RCS(amiga_h_rcs) SHOW_RCS(amiga_rcs) #endif /* def AMIGA */ SHOW_RCS(cgi_h_rcs) SHOW_RCS(cgi_rcs) #ifdef FEATURE_CGI_EDIT_ACTIONS SHOW_RCS(cgiedit_h_rcs) SHOW_RCS(cgiedit_rcs) #endif /* def FEATURE_CGI_EDIT_ACTIONS */ SHOW_RCS(cgisimple_h_rcs) SHOW_RCS(cgisimple_rcs) #ifdef __MINGW32__ SHOW_RCS(cygwin_h_rcs) #endif SHOW_RCS(deanimate_h_rcs) SHOW_RCS(deanimate_rcs) SHOW_RCS(encode_h_rcs) SHOW_RCS(encode_rcs) SHOW_RCS(errlog_h_rcs) SHOW_RCS(errlog_rcs) SHOW_RCS(filters_h_rcs) SHOW_RCS(filters_rcs) SHOW_RCS(gateway_h_rcs) SHOW_RCS(gateway_rcs) SHOW_RCS(jbsockets_h_rcs) SHOW_RCS(jbsockets_rcs) SHOW_RCS(jcc_h_rcs) SHOW_RCS(jcc_rcs) SHOW_RCS(list_h_rcs) SHOW_RCS(list_rcs) SHOW_RCS(loadcfg_h_rcs) SHOW_RCS(loadcfg_rcs) SHOW_RCS(loaders_h_rcs) SHOW_RCS(loaders_rcs) SHOW_RCS(miscutil_h_rcs) SHOW_RCS(miscutil_rcs) SHOW_RCS(parsers_h_rcs) SHOW_RCS(parsers_rcs) SHOW_RCS(pcrs_rcs) SHOW_RCS(pcrs_h_rcs) SHOW_RCS(project_h_rcs) SHOW_RCS(ssplit_h_rcs) SHOW_RCS(ssplit_rcs) SHOW_RCS(urlmatch_h_rcs) SHOW_RCS(urlmatch_rcs) #ifdef _WIN32 #ifndef _WIN_CONSOLE SHOW_RCS(w32log_h_rcs) SHOW_RCS(w32log_rcs) SHOW_RCS(w32res_h_rcs) SHOW_RCS(w32taskbar_h_rcs) SHOW_RCS(w32taskbar_rcs) #endif /* ndef _WIN_CONSOLE */ SHOW_RCS(win32_h_rcs) SHOW_RCS(win32_rcs) #endif /* def _WIN32 */ #undef SHOW_RCS return result; } /********************************************************************* * * Function : cgi_show_file * * Description : CGI function that shows the content of a * configuration file. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : rsp = http_response data structure for output * 3 : parameters = map of cgi parameters * * CGI Parameters : * file : Which file to show. Only first letter is checked, * valid values are: * - "a"ction file * - "r"egex * - "t"rust * Default is to show menu and other information. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory error. * *********************************************************************/ static jb_err cgi_show_file(struct client_state *csp, struct http_response *rsp, const struct map *parameters) { unsigned i; const char * filename = NULL; char * file_description = NULL; assert(csp); assert(rsp); assert(parameters); switch (*(lookup(parameters, "file"))) { case 'a': if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i]) { filename = csp->actions_list[i]->filename; file_description = "Actions File"; } break; case 'f': if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i]) { filename = csp->rlist[i]->filename; file_description = "Filter File"; } break; #ifdef FEATURE_TRUST case 't': if (csp->tlist) { filename = csp->tlist->filename; file_description = "Trust File"; } break; #endif /* def FEATURE_TRUST */ } if (NULL != filename) { struct map *exports; char *s; jb_err err; size_t length; exports = default_exports(csp, "show-status"); if (NULL == exports) { return JB_ERR_MEMORY; } if (map(exports, "file-description", 1, file_description, 1) || map(exports, "filepath", 1, html_encode(filename), 0)) { free_map(exports); return JB_ERR_MEMORY; } err = load_file(filename, &s, &length); if (JB_ERR_OK != err) { if (map(exports, "contents", 1, "

    ERROR OPENING FILE!

    ", 1)) { free_map(exports); return JB_ERR_MEMORY; } } else { s = html_encode_and_free_original(s); if (NULL == s) { return JB_ERR_MEMORY; } if (map(exports, "contents", 1, s, 0)) { free_map(exports); return JB_ERR_MEMORY; } } return template_fill_for_cgi(csp, "show-status-file", exports, rsp); } return JB_ERR_CGI_PARAMS; } /********************************************************************* * * Function : load_file * * Description : Loads a file into a buffer. * * Parameters : * 1 : filename = Name of the file to be loaded. * 2 : buffer = Used to return the file's content. * 3 : length = Used to return the size of the file. * * Returns : JB_ERR_OK in case of success, * JB_ERR_FILE in case of ordinary file loading errors * (fseek() and ftell() errors are fatal) * JB_ERR_MEMORY in case of out-of-memory. * *********************************************************************/ static jb_err load_file(const char *filename, char **buffer, size_t *length) { FILE *fp; long ret; jb_err err = JB_ERR_OK; fp = fopen(filename, "rb"); if (NULL == fp) { log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", filename); return JB_ERR_FILE; } /* Get file length */ if (fseek(fp, 0, SEEK_END)) { log_error(LOG_LEVEL_FATAL, "Unexpected error while fseek()ing to the end of %s: %E", filename); } ret = ftell(fp); if (-1 == ret) { log_error(LOG_LEVEL_FATAL, "Unexpected ftell() error while loading %s: %E", filename); } *length = (size_t)ret; /* Go back to the beginning. */ if (fseek(fp, 0, SEEK_SET)) { log_error(LOG_LEVEL_FATAL, "Unexpected error while fseek()ing to the beginning of %s: %E", filename); } *buffer = (char *)zalloc(*length + 1); if (NULL == *buffer) { err = JB_ERR_MEMORY; } else if (!fread(*buffer, *length, 1, fp)) { /* * May happen if the file size changes between fseek() and * fread(). If it does, we just log it and serve what we got. */ log_error(LOG_LEVEL_ERROR, "Couldn't completely read file %s.", filename); err = JB_ERR_FILE; } fclose(fp); return err; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32.rc000640 001751 001751 00000016735 11431720347 014741 0ustar00fkfk000000 000000 /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32.rc,v $ * * Purpose : Windows GUI resource script. * * Copyright : Written by and Copyright (C) 2001-2009 members of * the Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifndef STRICT #define STRICT #endif #include #include "w32res.h" #ifdef __MINGW32__ #include "cygwin.h" #endif /**************************************************************************** * Language-neutral resources ****************************************************************************/ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) #ifdef _WIN32 /* LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL */ #pragma code_page(1252) #endif /* _WIN32 */ /* * Icons * * Icon with lowest ID value placed first to ensure application icon * remains consistent on all systems. */ IDI_MAINICON ICON DISCARDABLE "icons/privoxy.ico" IDI_ANIMATED1 ICON DISCARDABLE "icons/radar-01.ico" IDI_ANIMATED2 ICON DISCARDABLE "icons/radar-02.ico" IDI_ANIMATED3 ICON DISCARDABLE "icons/radar-03.ico" IDI_ANIMATED4 ICON DISCARDABLE "icons/radar-04.ico" IDI_ANIMATED5 ICON DISCARDABLE "icons/radar-05.ico" IDI_ANIMATED6 ICON DISCARDABLE "icons/radar-06.ico" IDI_ANIMATED7 ICON DISCARDABLE "icons/radar-07.ico" IDI_ANIMATED8 ICON DISCARDABLE "icons/radar-08.ico" IDI_IDLE ICON DISCARDABLE "icons/privoxy.ico" IDI_OFF ICON DISCARDABLE "icons/off.ico" #endif /* Neutral resources */ /**************************************************************************** * English (U.S.) resources ****************************************************************************/ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 /* LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US */ #pragma code_page(1252) #endif /* def _WIN32 */ /* * File Version */ #ifndef _MAC VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0 PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "The Privoxy team - www.privoxy.org\0" VALUE "FileDescription", "Privoxy\0" VALUE "FileVersion", VERSION "\0" VALUE "InternalName", "Privoxy\0" VALUE "LegalCopyright", "Distributed under the GNU GPL\0" VALUE "OriginalFilename", "privoxy.exe\0" VALUE "ProductName", "Privoxy\0" VALUE "ProductVersion", VERSION "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif /* ndef _MAC */ /* * Menus */ IDR_TRAYMENU MENU DISCARDABLE BEGIN POPUP "Popup" BEGIN MENUITEM "E&xit Privoxy", ID_FILE_EXIT MENUITEM SEPARATOR POPUP "E&dit.." BEGIN MENUITEM "&Main Configuration", ID_TOOLS_EDITCONFIG MENUITEM "&Default Actions", ID_TOOLS_EDITDEFAULTACTIONS MENUITEM "&User Actions", ID_TOOLS_EDITUSERACTIONS MENUITEM "Default &Filters", ID_TOOLS_EDITDEFAULTFILTERS MENUITEM "U&ser Filters", ID_TOOLS_EDITUSERFILTERS #ifdef FEATURE_TRUST MENUITEM "&Trust list", ID_TOOLS_EDITTRUST #endif /* def FEATURE_TRUST */ END MENUITEM SEPARATOR #ifdef FEATURE_TOGGLE MENUITEM "&Enable", ID_TOGGLE_ENABLED, CHECKED #endif /* def FEATURE_TOGGLE */ MENUITEM "Show Privoxy &Window", ID_TOGGLE_SHOWWINDOW, CHECKED END END IDR_LOGVIEW MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Edit" BEGIN MENUITEM "Copy", ID_EDIT_COPY END POPUP "&View" BEGIN MENUITEM "&Clear Log\tCtrl+D", ID_VIEW_CLEARLOG MENUITEM SEPARATOR MENUITEM "&Log Messages", ID_VIEW_LOGMESSAGES, CHECKED MENUITEM "Message &Highlighting", ID_VIEW_MESSAGEHIGHLIGHTING, CHECKED MENUITEM "Limit &Buffer Size", ID_VIEW_LIMITBUFFERSIZE, CHECKED MENUITEM "&Activity Animation", ID_VIEW_ACTIVITYANIMATION, CHECKED END POPUP "&Options" BEGIN #ifdef FEATURE_TOGGLE MENUITEM "&Enable", ID_TOGGLE_ENABLED, CHECKED MENUITEM SEPARATOR #endif /* def FEATURE_TOGGLE */ MENUITEM "Edit Main &Configuration", ID_TOOLS_EDITCONFIG MENUITEM "Edit &Default Actions", ID_TOOLS_EDITDEFAULTACTIONS MENUITEM "Edit &User Actions", ID_TOOLS_EDITUSERACTIONS MENUITEM "Edit Default &Filters", ID_TOOLS_EDITDEFAULTFILTERS MENUITEM "Edit U&ser Filters", ID_TOOLS_EDITUSERFILTERS #ifdef FEATURE_TRUST MENUITEM "Edit &Trust list", ID_TOOLS_EDITTRUST #endif /* def FEATURE_TRUST */ END POPUP "&Help" BEGIN MENUITEM "Privoxy &FAQ", ID_HELP_FAQ MENUITEM "Privoxy &Manual", ID_HELP_MANUAL MENUITEM "GNU &General Public Licence", ID_HELP_GPL MENUITEM SEPARATOR MENUITEM "Privoxy Status...", ID_HELP_STATUS MENUITEM SEPARATOR MENUITEM "About Privoxy...", ID_HELP_ABOUT END END IDR_POPUP_SELECTION MENU DISCARDABLE BEGIN POPUP "Popup" BEGIN MENUITEM "&Copy", ID_EDIT_COPY END END /* * Accelerators */ IDR_ACCELERATOR ACCELERATORS DISCARDABLE BEGIN "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT "D", ID_VIEW_CLEARLOG, VIRTKEY, CONTROL, NOINVERT END #endif /* English (U.S.) resources */ privoxy-3.0.21-stable/./loaders.c000640 001751 001751 00000115256 12074552346 015601 0ustar00fkfk000000 000000 const char loaders_rcs[] = "$Id: loaders.c,v 1.95 2013/01/13 15:38:14 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loaders.c,v $ * * Purpose : Functions to load and unload the various * configuration files. Also contains code to manage * the list of active loaders, and to automatically * unload files that are no longer in use. * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #include #include #include #include #if !defined(_WIN32) && !defined(__OS2__) #include #endif #include "project.h" #include "list.h" #include "loaders.h" #include "filters.h" #include "parsers.h" #include "jcc.h" #include "miscutil.h" #include "errlog.h" #include "actions.h" #include "urlmatch.h" #include "encode.h" const char loaders_h_rcs[] = LOADERS_H_VERSION; /* * Currently active files. * These are also entered in the main linked list of files. */ #ifdef FEATURE_TRUST static struct file_list *current_trustfile = NULL; #endif /* def FEATURE_TRUST */ static int load_one_re_filterfile(struct client_state *csp, int fileid); static struct file_list *current_re_filterfile[MAX_AF_FILES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /********************************************************************* * * Function : sweep * * Description : Basically a mark and sweep garbage collector, it is run * (by the parent thread) every once in a while to reclaim memory. * * It uses a mark and sweep strategy: * 1) mark all files as inactive * * 2) check with each client: * if it is active, mark its files as active * if it is inactive, free its resources * * 3) free the resources of all of the files that * are still marked as inactive (and are obsolete). * * N.B. files that are not obsolete don't have an unloader defined. * * Parameters : None * * Returns : The number of threads that are still active. * *********************************************************************/ unsigned int sweep(void) { struct file_list *fl, *nfl; struct client_state *csp; struct client_states *last_active, *client_list; int i; unsigned int active_threads = 0; /* clear all of the file's active flags */ for (fl = files->next; NULL != fl; fl = fl->next) { fl->active = 0; } last_active = clients; client_list = clients->next; while (NULL != client_list) { csp = &client_list->csp; if (csp->flags & CSP_FLAG_ACTIVE) { /* Mark this client's files as active */ /* * Always have a configuration file. * (Also note the slightly non-standard extra * indirection here.) */ csp->config->config_file_list->active = 1; /* * Actions files */ for (i = 0; i < MAX_AF_FILES; i++) { if (csp->actions_list[i]) { csp->actions_list[i]->active = 1; } } /* * Filter files */ for (i = 0; i < MAX_AF_FILES; i++) { if (csp->rlist[i]) { csp->rlist[i]->active = 1; } } /* * Trust file */ #ifdef FEATURE_TRUST if (csp->tlist) { csp->tlist->active = 1; } #endif /* def FEATURE_TRUST */ active_threads++; last_active = client_list; client_list = client_list->next; } else /* * This client is not active. Free its resources. */ { last_active->next = client_list->next; freez(csp->ip_addr_str); freez(csp->client_iob->buf); freez(csp->iob->buf); freez(csp->error_message); if (csp->action->flags & ACTION_FORWARD_OVERRIDE && NULL != csp->fwd) { unload_forward_spec(csp->fwd); } free_http_request(csp->http); destroy_list(csp->headers); destroy_list(csp->tags); free_current_action(csp->action); #ifdef FEATURE_STATISTICS urls_read++; if (csp->flags & CSP_FLAG_REJECTED) { urls_rejected++; } #endif /* def FEATURE_STATISTICS */ freez(client_list); client_list = last_active->next; } } nfl = files; fl = files->next; while (fl != NULL) { if ((0 == fl->active) && (NULL != fl->unloader)) { nfl->next = fl->next; (fl->unloader)(fl->f); freez(fl->filename); freez(fl); fl = nfl->next; } else { nfl = fl; fl = fl->next; } } return active_threads; } /********************************************************************* * * Function : check_file_changed * * Description : Helper function to check if a file needs reloading. * If "current" is still current, return it. Otherwise * allocates a new (zeroed) "struct file_list", fills * in the disk file name and timestamp, and returns it. * * Parameters : * 1 : current = The file_list currently being used - will * be checked to see if it is out of date. * May be NULL (which is treated as out of * date). * 2 : filename = Name of file to check. * 3 : newfl = New file list. [Output only] * This will be set to NULL, OR a struct * file_list newly allocated on the * heap, with the filename and lastmodified * fields filled, and all others zeroed. * * Returns : If file unchanged: 0 (and sets newfl == NULL) * If file changed: 1 and sets newfl != NULL * On error: 1 and sets newfl == NULL * *********************************************************************/ int check_file_changed(const struct file_list * current, const char * filename, struct file_list ** newfl) { struct file_list *fs; struct stat statbuf[1]; *newfl = NULL; if (stat(filename, statbuf) < 0) { /* Error, probably file not found. */ return 1; } if (current && (current->lastmodified == statbuf->st_mtime) && (0 == strcmp(current->filename, filename))) { return 0; } fs = (struct file_list *)zalloc(sizeof(struct file_list)); if (fs == NULL) { /* Out of memory error */ return 1; } fs->filename = strdup(filename); fs->lastmodified = statbuf->st_mtime; if (fs->filename == NULL) { /* Out of memory error */ freez (fs); return 1; } *newfl = fs; return 1; } /********************************************************************* * * Function : simple_read_line * * Description : Read a single line from a file and return it. * This is basically a version of fgets() that malloc()s * it's own line buffer. Note that the buffer will * always be a multiple of BUFFER_SIZE bytes long. * Therefore if you are going to keep the string for * an extended period of time, you should probably * strdup() it and free() the original, to save memory. * * * Parameters : * 1 : dest = destination for newly malloc'd pointer to * line data. Will be set to NULL on error. * 2 : fp = File to read from * 3 : newline = Standard for newlines in the file. * Will be unchanged if it's value on input is not * NEWLINE_UNKNOWN. * On output, may be changed from NEWLINE_UNKNOWN to * actual convention in file. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_FILE on EOF. * *********************************************************************/ jb_err simple_read_line(FILE *fp, char **dest, int *newline) { size_t len = 0; size_t buflen = BUFFER_SIZE; char * buf; char * p; int ch; int realnewline = NEWLINE_UNKNOWN; if (NULL == (buf = malloc(buflen))) { return JB_ERR_MEMORY; } p = buf; /* * Character codes. If you have a weird compiler and the following are * incorrect, you also need to fix NEWLINE() in loaders.h */ #define CHAR_CR '\r' /* ASCII 13 */ #define CHAR_LF '\n' /* ASCII 10 */ for (;;) { ch = getc(fp); if (ch == EOF) { if (len > 0) { *p = '\0'; *dest = buf; return JB_ERR_OK; } else { free(buf); *dest = NULL; return JB_ERR_FILE; } } else if (ch == CHAR_CR) { ch = getc(fp); if (ch == CHAR_LF) { if (*newline == NEWLINE_UNKNOWN) { *newline = NEWLINE_DOS; } } else { if (ch != EOF) { ungetc(ch, fp); } if (*newline == NEWLINE_UNKNOWN) { *newline = NEWLINE_MAC; } } *p = '\0'; *dest = buf; if (*newline == NEWLINE_UNKNOWN) { *newline = realnewline; } return JB_ERR_OK; } else if (ch == CHAR_LF) { *p = '\0'; *dest = buf; if (*newline == NEWLINE_UNKNOWN) { *newline = NEWLINE_UNIX; } return JB_ERR_OK; } else if (ch == 0) { *p = '\0'; *dest = buf; return JB_ERR_OK; } *p++ = (char)ch; if (++len >= buflen) { buflen += BUFFER_SIZE; if (NULL == (p = realloc(buf, buflen))) { free(buf); return JB_ERR_MEMORY; } buf = p; p = buf + len; } } } /********************************************************************* * * Function : edit_read_line * * Description : Read a single non-empty line from a file and return * it. Trims comments, leading and trailing whitespace * and respects escaping of newline and comment char. * Provides the line in 2 alternative forms: raw and * preprocessed. * - raw is the raw data read from the file. If the * line is not modified, then this should be written * to the new file. * - prefix is any comments and blank lines that were * read from the file. If the line is modified, then * this should be written out to the file followed * by the modified data. (If this string is non-empty * then it will have a newline at the end). * - data is the actual data that will be parsed * further by appropriate routines. * On EOF, the 3 strings will all be set to NULL and * 0 will be returned. * * Parameters : * 1 : fp = File to read from * 2 : raw_out = destination for newly malloc'd pointer to * raw line data. May be NULL if you don't want it. * 3 : prefix_out = destination for newly malloc'd pointer to * comments. May be NULL if you don't want it. * 4 : data_out = destination for newly malloc'd pointer to * line data with comments and leading/trailing spaces * removed, and line continuation performed. May be * NULL if you don't want it. * 5 : newline = Standard for newlines in the file. * On input, set to value to use or NEWLINE_UNKNOWN. * On output, may be changed from NEWLINE_UNKNOWN to * actual convention in file. May be NULL if you * don't want it. * 6 : line_number = Line number in file. In "lines" as * reported by a text editor, not lines containing data. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory * JB_ERR_FILE on EOF. * *********************************************************************/ jb_err edit_read_line(FILE *fp, char **raw_out, char **prefix_out, char **data_out, int *newline, unsigned long *line_number) { char *p; /* Temporary pointer */ char *linebuf; /* Line read from file */ char *linestart; /* Start of linebuf, usually first non-whitespace char */ int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */ int is_empty = 1; /* Flag if not got any data yet */ char *raw = NULL; /* String to be stored in raw_out */ char *prefix = NULL; /* String to be stored in prefix_out */ char *data = NULL; /* String to be stored in data_out */ int scrapnewline; /* Used for (*newline) if newline==NULL */ jb_err rval = JB_ERR_OK; assert(fp); assert(raw_out || data_out); assert(newline == NULL || *newline == NEWLINE_UNKNOWN || *newline == NEWLINE_UNIX || *newline == NEWLINE_DOS || *newline == NEWLINE_MAC); if (newline == NULL) { scrapnewline = NEWLINE_UNKNOWN; newline = &scrapnewline; } /* Set output parameters to NULL */ if (raw_out) { *raw_out = NULL; } if (prefix_out) { *prefix_out = NULL; } if (data_out) { *data_out = NULL; } /* Set string variables to new, empty strings. */ if (raw_out) { raw = strdup(""); if (NULL == raw) { return JB_ERR_MEMORY; } } if (prefix_out) { prefix = strdup(""); if (NULL == prefix) { freez(raw); return JB_ERR_MEMORY; } } if (data_out) { data = strdup(""); if (NULL == data) { freez(raw); freez(prefix); return JB_ERR_MEMORY; } } /* Main loop. Loop while we need more data & it's not EOF. */ while ((contflag || is_empty) && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline)))) { if (line_number) { (*line_number)++; } if (raw) { string_append(&raw,linebuf); if (string_append(&raw,NEWLINE(*newline))) { freez(prefix); freez(data); free(linebuf); return JB_ERR_MEMORY; } } /* Line continuation? Trim escape and set flag. */ p = linebuf + strlen(linebuf) - 1; contflag = ((*linebuf != '\0') && (*p == '\\')); if (contflag) { *p = '\0'; } /* Trim leading spaces if we're at the start of the line */ linestart = linebuf; assert(NULL != data); if (*data == '\0') { /* Trim leading spaces */ while (*linestart && isspace((int)(unsigned char)*linestart)) { linestart++; } } /* Handle comment characters. */ p = linestart; while ((p = strchr(p, '#')) != NULL) { /* Found a comment char.. */ if ((p != linebuf) && (*(p-1) == '\\')) { /* ..and it's escaped, left-shift the line over the escape. */ char *q = p - 1; while ((*q = *(q + 1)) != '\0') { q++; } /* Now scan from just after the "#". */ } else { /* Real comment. Save it... */ if (p == linestart) { /* Special case: Line only contains a comment, so all the * previous whitespace is considered part of the comment. * Undo the whitespace skipping, if any. */ linestart = linebuf; p = linestart; } if (prefix) { string_append(&prefix,p); if (string_append(&prefix, NEWLINE(*newline))) { freez(raw); freez(data); free(linebuf); return JB_ERR_MEMORY; } } /* ... and chop off the rest of the line */ *p = '\0'; } } /* END while (there's a # character) */ /* Write to the buffer */ if (*linestart) { is_empty = 0; if (data) { if (string_append(&data, linestart)) { freez(raw); freez(prefix); free(linebuf); return JB_ERR_MEMORY; } } } free(linebuf); } /* END while(we need more data) */ /* Handle simple_read_line() errors - ignore EOF */ if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE)) { freez(raw); freez(prefix); freez(data); return rval; } if (raw ? (*raw == '\0') : is_empty) { /* EOF and no data there. (Definition of "data" depends on whether * the caller cares about "raw" or just "data"). */ freez(raw); freez(prefix); freez(data); return JB_ERR_FILE; } else { /* Got at least some data */ /* Remove trailing whitespace */ chomp(data); if (raw_out) { *raw_out = raw; } else { freez(raw); } if (prefix_out) { *prefix_out = prefix; } else { freez(prefix); } if (data_out) { *data_out = data; } else { freez(data); } return JB_ERR_OK; } } /********************************************************************* * * Function : read_config_line * * Description : Read a single non-empty line from a file and return * it. Trims comments, leading and trailing whitespace * and respects escaping of newline and comment char. * * Parameters : * 1 : fp = File to read from * 2 : linenum = linenumber in file * 3 : buf = Pointer to a pointer to set to the data buffer. * * Returns : NULL on EOF or error * Otherwise, returns buf. * *********************************************************************/ char *read_config_line(FILE *fp, unsigned long *linenum, char **buf) { jb_err err; err = edit_read_line(fp, NULL, NULL, buf, NULL, linenum); if (err) { if (err == JB_ERR_MEMORY) { log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file"); } *buf = NULL; } return *buf; } #ifdef FEATURE_TRUST /********************************************************************* * * Function : unload_trustfile * * Description : Unloads a trustfile. * * Parameters : * 1 : f = the data structure associated with the trustfile. * * Returns : N/A * *********************************************************************/ static void unload_trustfile(void *f) { struct block_spec *cur = (struct block_spec *)f; struct block_spec *next; while (cur != NULL) { next = cur->next; free_url_spec(cur->url); free(cur); cur = next; } } #ifdef FEATURE_GRACEFUL_TERMINATION /********************************************************************* * * Function : unload_current_trust_file * * Description : Unloads current trust file - reset to state at * beginning of program. * * Parameters : None * * Returns : N/A * *********************************************************************/ void unload_current_trust_file(void) { if (current_trustfile) { current_trustfile->unloader = unload_trustfile; current_trustfile = NULL; } } #endif /* FEATURE_GRACEFUL_TERMINATION */ /********************************************************************* * * Function : load_trustfile * * Description : Read and parse a trustfile and add to files list. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int load_trustfile(struct client_state *csp) { FILE *fp; struct block_spec *b, *bl; struct url_spec **tl; char *buf = NULL; int reject, trusted; struct file_list *fs; unsigned long linenum = 0; int trusted_referrers = 0; if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs)) { /* No need to load */ csp->tlist = current_trustfile; return(0); } if (!fs) { goto load_trustfile_error; } fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl)); if (bl == NULL) { goto load_trustfile_error; } if ((fp = fopen(csp->config->trustfile, "r")) == NULL) { goto load_trustfile_error; } log_error(LOG_LEVEL_INFO, "Loading trust file: %s", csp->config->trustfile); tl = csp->config->trust_list; while (read_config_line(fp, &linenum, &buf) != NULL) { trusted = 0; reject = 1; if (*buf == '+') { trusted = 1; *buf = '~'; } if (*buf == '~') { char *p; char *q; reject = 0; p = buf; q = p+1; while ((*p++ = *q++) != '\0') { /* nop */ } } /* skip blank lines */ if (*buf == '\0') { freez(buf); continue; } /* allocate a new node */ if ((b = zalloc(sizeof(*b))) == NULL) { fclose(fp); goto load_trustfile_error; } /* add it to the list */ b->next = bl->next; bl->next = b; b->reject = reject; /* Save the URL pattern */ if (create_url_spec(b->url, buf)) { fclose(fp); goto load_trustfile_error; } /* * save a pointer to URL's spec in the list of trusted URL's, too */ if (trusted) { if (++trusted_referrers < MAX_TRUSTED_REFERRERS) { *tl++ = b->url; } } freez(buf); } if (trusted_referrers >= MAX_TRUSTED_REFERRERS) { /* * FIXME: ... after Privoxy 3.0.4 is out. */ log_error(LOG_LEVEL_ERROR, "Too many trusted referrers. Current limit is %d, you are using %d.\n" " Additional trusted referrers are treated like ordinary trusted URLs.\n" " (You can increase this limit by changing MAX_TRUSTED_REFERRERS in project.h and recompiling).", MAX_TRUSTED_REFERRERS, trusted_referrers); } *tl = NULL; fclose(fp); /* the old one is now obsolete */ if (current_trustfile) { current_trustfile->unloader = unload_trustfile; } fs->next = files->next; files->next = fs; current_trustfile = fs; csp->tlist = fs; return(0); load_trustfile_error: log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E", csp->config->trustfile); freez(buf); return(-1); } #endif /* def FEATURE_TRUST */ /********************************************************************* * * Function : unload_re_filterfile * * Description : Unload the re_filter list by freeing all chained * re_filterfile specs and their data. * * Parameters : * 1 : f = the data structure associated with the filterfile. * * Returns : N/A * *********************************************************************/ static void unload_re_filterfile(void *f) { struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f; while (b != NULL) { a = b->next; destroy_list(b->patterns); pcrs_free_joblist(b->joblist); freez(b->name); freez(b->description); freez(b); b = a; } return; } /********************************************************************* * * Function : unload_forward_spec * * Description : Unload the forward spec settings by freeing all * memory referenced by members and the memory for * the spec itself. * * Parameters : * 1 : fwd = the forward spec. * * Returns : N/A * *********************************************************************/ void unload_forward_spec(struct forward_spec *fwd) { free_url_spec(fwd->url); freez(fwd->gateway_host); freez(fwd->forward_host); free(fwd); return; } #ifdef FEATURE_GRACEFUL_TERMINATION /********************************************************************* * * Function : unload_current_re_filterfile * * Description : Unloads current re_filter file - reset to state at * beginning of program. * * Parameters : None * * Returns : N/A * *********************************************************************/ void unload_current_re_filterfile(void) { int i; for (i = 0; i < MAX_AF_FILES; i++) { if (current_re_filterfile[i]) { current_re_filterfile[i]->unloader = unload_re_filterfile; current_re_filterfile[i] = NULL; } } } #endif /********************************************************************* * * Function : load_re_filterfiles * * Description : Loads all the filterfiles. * Generate a chained list of re_filterfile_spec's from * the "FILTER: " blocks, compiling all their substitutions * into chained lists of pcrs_job structs. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int load_re_filterfiles(struct client_state *csp) { int i; int result; for (i = 0; i < MAX_AF_FILES; i++) { if (csp->config->re_filterfile[i]) { result = load_one_re_filterfile(csp, i); if (result) { return result; } } else if (current_re_filterfile[i]) { current_re_filterfile[i]->unloader = unload_re_filterfile; current_re_filterfile[i] = NULL; } } return 0; } /********************************************************************* * * Function : load_one_re_filterfile * * Description : Load a re_filterfile. * Generate a chained list of re_filterfile_spec's from * the "FILTER: " blocks, compiling all their substitutions * into chained lists of pcrs_job structs. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int load_one_re_filterfile(struct client_state *csp, int fileid) { FILE *fp; struct re_filterfile_spec *new_bl, *bl = NULL; struct file_list *fs; char *buf = NULL; int error; unsigned long linenum = 0; pcrs_job *dummy, *lastjob = NULL; /* * No need to reload if unchanged */ if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs)) { csp->rlist[fileid] = current_re_filterfile[fileid]; return(0); } if (!fs) { goto load_re_filterfile_error; } /* * Open the file or fail */ if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL) { goto load_re_filterfile_error; } log_error(LOG_LEVEL_INFO, "Loading filter file: %s", csp->config->re_filterfile[fileid]); /* * Read line by line */ while (read_config_line(fp, &linenum, &buf) != NULL) { enum filter_type new_filter = FT_INVALID_FILTER; if (strncmp(buf, "FILTER:", 7) == 0) { new_filter = FT_CONTENT_FILTER; } else if (strncmp(buf, "SERVER-HEADER-FILTER:", 21) == 0) { new_filter = FT_SERVER_HEADER_FILTER; } else if (strncmp(buf, "CLIENT-HEADER-FILTER:", 21) == 0) { new_filter = FT_CLIENT_HEADER_FILTER; } else if (strncmp(buf, "CLIENT-HEADER-TAGGER:", 21) == 0) { new_filter = FT_CLIENT_HEADER_TAGGER; } else if (strncmp(buf, "SERVER-HEADER-TAGGER:", 21) == 0) { new_filter = FT_SERVER_HEADER_TAGGER; } /* * If this is the head of a new filter block, make it a * re_filterfile spec of its own and chain it to the list: */ if (new_filter != FT_INVALID_FILTER) { new_bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl)); if (new_bl == NULL) { goto load_re_filterfile_error; } if (new_filter == FT_CONTENT_FILTER) { new_bl->name = chomp(buf + 7); } else { new_bl->name = chomp(buf + 21); } new_bl->type = new_filter; /* * If a filter description is available, * encode it to HTML and save it. */ if (NULL != (new_bl->description = strpbrk(new_bl->name, " \t"))) { *new_bl->description++ = '\0'; new_bl->description = html_encode(chomp(new_bl->description)); if (NULL == new_bl->description) { new_bl->description = strdup("Out of memory while encoding this filter's description to HTML"); } } else { new_bl->description = strdup("No description available for this filter"); } new_bl->name = strdup(chomp(new_bl->name)); /* * If this is the first filter block, chain it * to the file_list rather than its (nonexistant) * predecessor */ if (fs->f == NULL) { fs->f = new_bl; } else { assert(NULL != bl); bl->next = new_bl; } bl = new_bl; log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description); freez(buf); continue; } /* * Else, save the expression, make it a pcrs_job * and chain it into the current filter's joblist */ if (bl != NULL) { error = enlist(bl->patterns, buf); if (JB_ERR_MEMORY == error) { log_error(LOG_LEVEL_FATAL, "Out of memory while enlisting re_filter job \'%s\' for filter %s.", buf, bl->name); } assert(JB_ERR_OK == error); if (pcrs_job_is_dynamic(buf)) { /* * Dynamic pattern that might contain variables * and has to be recompiled for every request */ if (bl->joblist != NULL) { pcrs_free_joblist(bl->joblist); bl->joblist = NULL; } bl->dynamic = 1; log_error(LOG_LEVEL_RE_FILTER, "Adding dynamic re_filter job \'%s\' to filter %s succeeded.", buf, bl->name); freez(buf); continue; } else if (bl->dynamic) { /* * A previous job was dynamic and as we * recompile the whole filter anyway, it * makes no sense to compile this job now. */ log_error(LOG_LEVEL_RE_FILTER, "Adding static re_filter job \'%s\' to dynamic filter %s succeeded.", buf, bl->name); freez(buf); continue; } if ((dummy = pcrs_compile_command(buf, &error)) == NULL) { log_error(LOG_LEVEL_ERROR, "Adding re_filter job \'%s\' to filter %s failed with error %d.", buf, bl->name, error); freez(buf); continue; } else { if (bl->joblist == NULL) { bl->joblist = dummy; } else if (NULL != lastjob) { lastjob->next = dummy; } lastjob = dummy; log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job \'%s\' to filter %s succeeded.", buf, bl->name); } } else { log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d", buf, csp->config->re_filterfile[fileid], linenum); } freez(buf); } fclose(fp); /* * Schedule the now-obsolete old data for unloading */ if (NULL != current_re_filterfile[fileid]) { current_re_filterfile[fileid]->unloader = unload_re_filterfile; } /* * Chain this file into the global list of loaded files */ fs->next = files->next; files->next = fs; current_re_filterfile[fileid] = fs; csp->rlist[fileid] = fs; return(0); load_re_filterfile_error: log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E", csp->config->re_filterfile[fileid]); return(-1); } /********************************************************************* * * Function : add_loader * * Description : Called from `load_config'. Called once for each input * file found in config. * * Parameters : * 1 : loader = pointer to a function that can parse and load * the appropriate config file. * 2 : config = The configuration_spec to add the loader to. * * Returns : N/A * *********************************************************************/ void add_loader(int (*loader)(struct client_state *), struct configuration_spec * config) { int i; for (i = 0; i < NLOADERS; i++) { if (config->loaders[i] == NULL) { config->loaders[i] = loader; break; } } } /********************************************************************* * * Function : run_loader * * Description : Called from `load_config' and `listen_loop'. This * function keeps the "csp" current with any file mods * since the last loop. If a file is unchanged, the * loader functions do NOT reload the file. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * Must be non-null. Reads: "csp->config" * Writes: various data members. * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int run_loader(struct client_state *csp) { int ret = 0; int i; for (i = 0; i < NLOADERS; i++) { if (csp->config->loaders[i] == NULL) { break; } ret |= (csp->config->loaders[i])(csp); } return(ret); } /********************************************************************* * * Function : file_has_been_modified * * Description : Helper function to check if a file has been changed * * Parameters : * 1 : filename = The name of the file to check * 2 : last_known_modification = The time of the last known * modification * * Returns : TRUE if the file has been changed, * FALSE otherwise. * *********************************************************************/ static int file_has_been_modified(const char *filename, time_t last_know_modification) { struct stat statbuf[1]; if (stat(filename, statbuf) < 0) { /* Error, probably file not found which counts as change. */ return 1; } return (last_know_modification != statbuf->st_mtime); } /********************************************************************* * * Function : any_loaded_file_changed * * Description : Helper function to check if any loaded file has been * changed since the time it has been loaded. * * XXX: Should we cache the return value for x seconds? * * Parameters : * 1 : files_to_check = List of files to check * * Returns : TRUE if any file has been changed, * FALSE otherwise. * *********************************************************************/ int any_loaded_file_changed(const struct client_state *csp) { const struct file_list *file_to_check = csp->config->config_file_list; int i; if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified)) { return TRUE; } for (i = 0; i < MAX_AF_FILES; i++) { if (csp->actions_list[i]) { file_to_check = csp->actions_list[i]; if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified)) { return TRUE; } } } for (i = 0; i < MAX_AF_FILES; i++) { if (csp->rlist[i]) { file_to_check = csp->rlist[i]; if (file_has_been_modified(file_to_check->filename, file_to_check->lastmodified)) { return TRUE; } } } #ifdef FEATURE_TRUST if (csp->tlist) { if (file_has_been_modified(csp->tlist->filename, csp->tlist->lastmodified)) { return TRUE; } } #endif /* def FEATURE_TRUST */ return FALSE; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32svrapi.c000640 001751 001751 00000072237 11630656300 016001 0ustar00fkfk000000 000000 const char w32_svrapi_rcs[] = "$Id: w32svrapi.c,v 1.5 2011/09/04 11:10:56 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32svrapi.c,v $ * * Purpose : Win32 Services API for Privoxy. * Provides the implementation of an Win32 service to * allow the code to directly register and run as a * native Windows service application. * * Since Win9x/ME platforms don't provide or support * running programs as services, this code uses runtime * loading and calling of the Win32 Service API, to * prevent the possibility of getting "entry point not * found" type errors on unsupported platforms. This adds * a little more complexity to the code, but it is worth * doing to provide that isolation. * * Copyright : Written by and Copyright (C) 2003, 2006 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 2003 Ian Cummings * * * Special thanks to Mates Dolák for * some very helpful feedback and suggestions during the * development of this code. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifdef _WIN32 #include #ifndef STRICT #define STRICT #endif #include #include #ifndef _WIN_CONSOLE # include "w32log.h" #endif /* ndef _WIN_CONSOLE */ #include "w32svrapi.h" const char w32_svrapi_h_rcs[] = W32_SVRAPI_H_VERSION; /* Only the ANSI Win32 APIs are used at this time. If for some * reason, we're building under unicode then we must stop */ #ifdef UNICODE #error "Privoxy interface to Win32 Services only runs under ANSI builds. Unicode is not supported at present, but you can volunteer for the job if you like! :)" #endif /* Default to not running as service, unless the command line says so */ BOOL bRunAsService = FALSE; /* According to the Win32 docs for CreateService, * the max length for the service name is 256 chars */ char szThisServiceName[260]; static BOOL get_service_description(const char *pszServiceName, char *pszDisplayName, DWORD dwDispSize); static void WINAPI privoxy_w32_service_start(DWORD dw, LPSTR* psz); static void WINAPI privoxy_w32_service_handler(DWORD dwOpcode); SERVICE_TABLE_ENTRY w32ServiceDispatchTable[] = {{"", privoxy_w32_service_start}, {NULL, NULL}}; static SERVICE_STATUS_HANDLE hSrv_status = 0; static SERVICE_STATUS srv_status; /********************************************************************* * This function returns TRUE if we are running on an OS that can * support services, like NT, etc. It returns FALSE for Win9x/ME. *********************************************************************/ static BOOL HasServiceControlManager() { HMODULE hDll; FARPROC pFunc; SC_HANDLE hScm; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { printf("Can't load Advapi32.dll -- LoadLibrary failed!\n"); return FALSE; } /* Get the address of the ANSI OpenSCManager function, or return a failure status */ pFunc = GetProcAddress(hDll, "OpenSCManagerA"); if (pFunc == NULL) { printf("Can't find OpenSCManagerA -- GetProcAddress failed!\n"); FreeLibrary(hDll); return FALSE; } /* Try and connect to the SCM. If it fails check and see if the error * code is ERROR_CALL_NOT_IMPLEMENTED, which means: * "This function is not supported on this system." */ hScm = (SC_HANDLE)(*pFunc)(NULL, NULL, SC_MANAGER_CONNECT); if (hScm == NULL) { DWORD dwErr = GetLastError(); if (dwErr == ERROR_CALL_NOT_IMPLEMENTED) { /* Expected error under Win9x/Me, so don't print any debug info * here as we'll leave that up to the calling function to do */ FreeLibrary(hDll); return FALSE; } printf("Call to OpenSCManager failed -- GetLastError() returned %lu!\n", dwErr); FreeLibrary(hDll); return FALSE; } w32_close_service_handle(hScm); /* OpenSCManager function exists and works, so we're on an NT type platform */ FreeLibrary(hDll); return TRUE; } /* -END- HasServiceControlManager */ BOOL CanSystemSupportServices() { BOOL bHasScm = HasServiceControlManager(); return bHasScm; } /* -END- CanSystemSupportServices */ /********************************************************************* * * The Service functions are defined in which is where * the declarations used in this file are taken from * *********************************************************************/ /********************************************************************* * Open a connection to the service control manager *********************************************************************/ SC_HANDLE w32_open_sc_manager( LPCTSTR lpMachineName, /* computer name */ LPCTSTR lpDatabaseName, /* SCM database name */ DWORD dwDesiredAccess) /* access type */ { HMODULE hDll = NULL; SC_HANDLE hScm = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; /* Load the DLL with the SCM functions or return failure */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return NULL; } /* Get the address of the ANSI OpenSCManager function, or return failure */ pFunc = GetProcAddress(hDll, "OpenSCManagerA"); if (pFunc == NULL) { FreeLibrary(hDll); return NULL; } /* Call the SCM function, and save the error code */ hScm = (SC_HANDLE)(*pFunc)(lpMachineName, lpDatabaseName, dwDesiredAccess); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return hScm; } /* -END- w32_open_sc_manager */ BOOL w32_close_service_handle( SC_HANDLE hSCObject) /* handle to service or SCM object */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; BOOL bRet; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return FALSE; } /* Get the address of the CloseServiceHandle function, or return a failure status */ pFunc = GetProcAddress(hDll, "CloseServiceHandle"); if (pFunc == NULL) { FreeLibrary(hDll); return FALSE; } /* Close the handle, and save the error code */ bRet = (BOOL)(*pFunc)(hSCObject); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return bRet; } /* -END- w32_close_service_handle */ /********************************************************************* * Open a service *********************************************************************/ SC_HANDLE w32_open_service( SC_HANDLE hSCManager, /* handle to SCM database */ LPCTSTR lpServiceName, /* service name */ DWORD dwDesiredAccess) /* access */ { HMODULE hDll = NULL; SC_HANDLE hSrv = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; /* Load the DLL with the SCM functions or return failure */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return NULL; } /* Get the address of the ANSI OpenService function, or return failure */ pFunc = GetProcAddress(hDll, "OpenServiceA"); if (pFunc == NULL) { FreeLibrary(hDll); return NULL; } /* Call the SCM function, and save the error code */ hSrv = (SC_HANDLE)(*pFunc)(hSCManager, lpServiceName, dwDesiredAccess); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return hSrv; } /* -END- w32_open_service */ SC_HANDLE w32_create_service( SC_HANDLE hSCManager, /* handle to SCM database */ LPCTSTR lpServiceName, /* name of service to start */ LPCTSTR lpDisplayName, /* display name */ DWORD dwDesiredAccess, /* type of access to service */ DWORD dwServiceType, /* type of service */ DWORD dwStartType, /* when to start service */ DWORD dwErrorControl, /* severity of service failure */ LPCTSTR lpBinaryPathName, /* name of binary file */ LPCTSTR lpLoadOrderGroup, /* name of load ordering group */ LPDWORD lpdwTagId, /* tag identifier */ LPCTSTR lpDependencies, /* array of dependency names */ LPCTSTR lpServiceStartName, /* account name */ LPCTSTR lpPassword) /* account password */ { HMODULE hDll = NULL; SC_HANDLE hSrv = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; /* Load the DLL with the SCM functions or return failure */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return NULL; } /* Get the address of the ANSI CreateService function, or return failure */ pFunc = GetProcAddress(hDll, "CreateServiceA"); if (pFunc == NULL) { FreeLibrary(hDll); return NULL; } /* Call the SCM function, and save the error code */ hSrv = (SC_HANDLE)(*pFunc)(hSCManager, /* handle to SCM database */ lpServiceName, /* name of service to start */ lpDisplayName, /* display name */ dwDesiredAccess, /* type of access to service */ dwServiceType, /* type of service */ dwStartType, /* when to start service */ dwErrorControl, /* severity of service failure */ lpBinaryPathName, /* name of binary file */ lpLoadOrderGroup, /* name of load ordering group */ lpdwTagId, /* tag identifier */ lpDependencies, /* array of dependency names */ lpServiceStartName, /* account name */ lpPassword); /* account password */ dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return hSrv; } /* -END- w32_create_service */ BOOL w32_delete_service( SC_HANDLE hService) /* handle to service */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; BOOL bRet; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return FALSE; } /* Get the address of the DeleteService function, or return a failure status */ pFunc = GetProcAddress(hDll, "DeleteService"); if (pFunc == NULL) { FreeLibrary(hDll); return FALSE; } /* Close the handle, and save the error code */ bRet = (BOOL)(*pFunc)(hService); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return bRet; } /* -END- w32_delete_service */ BOOL w32_query_service_config( SC_HANDLE hService, /* handle to service */ LPQUERY_SERVICE_CONFIG lpServiceConfig, /* buffer */ DWORD cbBufSize, /* size of buffer */ LPDWORD pcbBytesNeeded) /* bytes needed */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; BOOL bRet; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return FALSE; } /* Get the address of the QueryServiceConfig function, or return a failure status */ pFunc = GetProcAddress(hDll, "QueryServiceConfigA"); if (pFunc == NULL) { FreeLibrary(hDll); return FALSE; } /* Close the handle, and save the error code */ bRet = (BOOL)(*pFunc)(hService, lpServiceConfig, cbBufSize, pcbBytesNeeded); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return bRet; } /* -END- w32_query_service_config */ BOOL w32_start_service_ctrl_dispatcher( CONST LPSERVICE_TABLE_ENTRY lpServiceTable) /* service table */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; BOOL bRet; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return FALSE; } /* Get the address of the StartServiceCtrlDispatcher function, or return a failure status */ pFunc = GetProcAddress(hDll, "StartServiceCtrlDispatcherA"); if (pFunc == NULL) { FreeLibrary(hDll); return FALSE; } /* Close the handle, and save the error code */ bRet = (BOOL)(*pFunc)(lpServiceTable); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return bRet; } /* -END- w32_start_service_ctrl_dispatcher */ SERVICE_STATUS_HANDLE w32_register_service_ctrl_handler( LPCTSTR lpServiceName, /* service name */ LPHANDLER_FUNCTION lpHandlerProc) /* handler function */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; SERVICE_STATUS_HANDLE hServStat = (SERVICE_STATUS_HANDLE)0; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return hServStat; } /* Get the address of the RegisterServiceCtrlHandler function, or return a failure status */ pFunc = GetProcAddress(hDll, "RegisterServiceCtrlHandlerA"); if (pFunc == NULL) { FreeLibrary(hDll); return hServStat; } /* Close the handle, and save the error code */ hServStat = (SERVICE_STATUS_HANDLE)(*pFunc)(lpServiceName, lpHandlerProc); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return hServStat; } /* -END- w32_register_service_ctrl_handler */ BOOL w32_set_service_status( SERVICE_STATUS_HANDLE hServiceStatus, /* service status handle */ LPSERVICE_STATUS lpServiceStatus) /* status buffer */ { HMODULE hDll = NULL; FARPROC pFunc = NULL; DWORD dwLastErr = 0; BOOL bRet; /* Load the DLL with the SCM functions or return a failure status */ hDll = LoadLibrary("Advapi32.dll"); if (hDll == NULL) { return FALSE; } /* Get the address of the SetServiceStatus function, or return a failure status */ pFunc = GetProcAddress(hDll, "SetServiceStatus"); if (pFunc == NULL) { FreeLibrary(hDll); return FALSE; } /* Close the handle, and save the error code */ bRet = (BOOL)(*pFunc)(hServiceStatus, lpServiceStatus); dwLastErr = GetLastError(); /* Release the library and then restore the last error * code, in case FreeLibrary altered it. */ FreeLibrary(hDll); SetLastError(dwLastErr); return bRet; } /* -END- w32_set_service_status */ static void display_win32_msg(BOOL bIsError, char *msg) { #ifdef _WIN_CONSOLE printf("%s", msg); #else if (bIsError) { MessageBox(NULL, msg, "Privoxy Error", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); } else { MessageBox(NULL, msg, "Privoxy Information", MB_OK | MB_ICONINFORMATION | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); } #endif } /* -END- display_win32_msg */ static BOOL get_service_description(const char *pszServiceName, char *pszDisplayName, DWORD dwDispSize) { /********************************************************************* * Create a simple display name *********************************************************************/ strcpy(pszDisplayName, "Privoxy ("); strncat(pszDisplayName, pszServiceName, dwDispSize - strlen(pszDisplayName) - 2); strcat(pszDisplayName, ")"); return TRUE; } BOOL install_service(const char *service_name) { char szModule[(MAX_PATH*2)+1]; char szDisplayName[MAX_PATH+2]; SC_HANDLE hSCM; SC_HANDLE hService; /********************************************************************* * First check if this system can support a service architecture *********************************************************************/ if (!CanSystemSupportServices()) { display_win32_msg(TRUE, "This system doesn't support installing Privoxy as a service.\nWinNT/2000/XP are required for this feature.\n"); return FALSE; } /* Use a default service name if none was supplied */ if ((service_name == NULL) || (strlen(service_name) == 0)) { service_name = "privoxy"; } /********************************************************************* * Open a handle to the Service Control Manager with full access rights *********************************************************************/ hSCM = w32_open_sc_manager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCM == NULL) { display_win32_msg(TRUE, "Can't open Service Control Manager - Service install failed!\n Administrator rights are required to create a service.\n"); return FALSE; } /********************************************************************* * Work out the full image path plus command line for the service * We'll temporarily use szDisplayName as a second buffer. *********************************************************************/ GetModuleFileName(NULL, szDisplayName, MAX_PATH); sprintf(szModule, "\"%s\" --service", szDisplayName); /********************************************************************* * Get the display name for the service *********************************************************************/ get_service_description(service_name, szDisplayName, sizeof(szDisplayName)/sizeof(char)); /********************************************************************* * Create the service *********************************************************************/ hService = w32_create_service(hSCM, service_name, /* the internal service name */ szDisplayName, /* the display name */ SERVICE_ALL_ACCESS, /* get full access during creation */ SERVICE_WIN32_OWN_PROCESS /* run in our own process */ #ifndef _WIN_CONSOLE + SERVICE_INTERACTIVE_PROCESS /* GUI also wants interactive rights */ #endif , SERVICE_DEMAND_START, /* For now, only start when asked to */ SERVICE_ERROR_NORMAL, /* Normal error handling by the SCM */ szModule, /* The executable service file */ NULL, /* No load order info needed */ NULL, /* No load order info needed */ NULL, /* No dependencies */ NULL, /* Default to LocalSystem... */ NULL); /* ...which doesn't require a password */ if (hService == NULL) { display_win32_msg(TRUE, "Can't install service!\n"); w32_close_service_handle(hSCM); return FALSE; } display_win32_msg(FALSE, "Service was successfully created.\n*** IMPORTANT NOTE: You should now use the Services control panel to\n*** configure the startup type and user account details for the service.\n\n"); /* tidy up */ w32_close_service_handle(hService); w32_close_service_handle(hSCM); return TRUE; } /* -END- install_service */ BOOL uninstall_service(const char *service_name) { char szDisplayName[MAX_PATH+2]; SC_HANDLE hSCM; SC_HANDLE hService; BOOL bResult = FALSE; /********************************************************************* * First check if this system can support a service architecture *********************************************************************/ if (!CanSystemSupportServices()) { display_win32_msg(TRUE, "This system doesn't support installing Privoxy as a service.\nWinNT/2000/XP are required for this feature.\n"); return FALSE; } /* Use a default service name if none was supplied */ if ((service_name == NULL) || (strlen(service_name) == 0)) { service_name = "privoxy"; } /********************************************************************* * Open a handle to the Service Control Manager with full access rights *********************************************************************/ hSCM = w32_open_sc_manager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCM == NULL) { display_win32_msg(TRUE, "Can't open Service Control Manager - Service uninstall failed!\n Administrator rights are required to delete a service.\n"); return FALSE; } /********************************************************************* * Get the display name for the service *********************************************************************/ get_service_description(service_name, szDisplayName, sizeof(szDisplayName)/sizeof(char)); /********************************************************************* * Open and then delete the service *********************************************************************/ hService = w32_open_service(hSCM, service_name, DELETE); if (hService == NULL) { display_win32_msg(TRUE, "Can't open service for delete access rights!\n"); w32_close_service_handle(hSCM); return FALSE; } if (w32_delete_service(hService)) { display_win32_msg(FALSE, "Service was deleted successfully.\n"); bResult = TRUE; } else { display_win32_msg(TRUE, "Service could not be deleted!\n"); bResult = FALSE; } w32_close_service_handle(hService); w32_close_service_handle(hSCM); return bResult; } /* -END- uninstall_service */ /********************************************************************* * * Function : privoxy_w32_service_start * * Description : This is the entry point function for the service. * In other words, it's the ServiceMain function. * * Parameters : Defined by the Win32 API, but not used here * * Returns : void * *********************************************************************/ static void WINAPI privoxy_w32_service_start(DWORD dw, LPSTR* pszArgs) { int child_id; /* Arg zero is always the service name, and we need to * know it when we call RegisterServiceCtrlHandler. */ strcpy(szThisServiceName, pszArgs[0]); /* Tell the SCM we are running */ srv_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; srv_status.dwCurrentState = SERVICE_RUNNING; srv_status.dwCheckPoint = 0; srv_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; srv_status.dwWin32ExitCode = NO_ERROR; srv_status.dwServiceSpecificExitCode = 0; srv_status.dwWaitHint = 0; hSrv_status = w32_register_service_ctrl_handler(szThisServiceName, privoxy_w32_service_handler); if (!hSrv_status) { return; } w32_set_service_status(hSrv_status, &srv_status); #ifndef FEATURE_PTHREAD child_id = _beginthread(w32_service_listen_loop, 0, NULL); if (child_id > 0) #else #error "FIXME: Do pthread stuff here!" #endif { w32_set_service_status(hSrv_status, &srv_status); } else { srv_status.dwCurrentState = SERVICE_STOPPED; srv_status.dwCheckPoint = 0; srv_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; srv_status.dwServiceSpecificExitCode = ERROR_SERVICE_NO_THREAD; w32_set_service_status(hSrv_status, &srv_status); } } /********************************************************************* * * Function : w32_set_service_cwd * * Description : Simple function to change the current directory to * the same location as the service executable. * * Parameters : void * * Returns : void * *********************************************************************/ void w32_set_service_cwd(void) { char exe_name[MAX_PATH+1]; char dir_name[MAX_PATH+1]; char *pszFile = NULL; /* Get the exe name and path of the service */ if (GetModuleFileName(NULL, exe_name, MAX_PATH)) { /* Ask the API to tell us where the filename portion starts */ if (GetFullPathName(exe_name, MAX_PATH, dir_name, &pszFile)) { /* remove the filename from the string */ if (pszFile != NULL) { *pszFile = '\0'; /* We have just a directory path now, so make it current */ SetCurrentDirectory(dir_name); } } } } /********************************************************************* * * Function : w32_service_exit_notify * * Description : This is a simple atexit function that is called by the * C runtime after exit has been called. It allows the * service code to detect when the app is about to die and * send an quick notification to the SCM that the service * now stopped. * * Parameters : void * * Returns : void * *********************************************************************/ void w32_service_exit_notify(void) { if (hSrv_status != 0) { if (srv_status.dwCurrentState != SERVICE_STOPPED) { srv_status.dwCurrentState = SERVICE_STOPPED; srv_status.dwCheckPoint = 0; srv_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; srv_status.dwServiceSpecificExitCode = ERROR_PROCESS_ABORTED; w32_set_service_status(hSrv_status, &srv_status); } } } static void w32_mini_exit(void *p) { Sleep(100); #ifdef _WIN_CONSOLE exit(0); #else PostMessage(g_hwndLogFrame, WM_CLOSE, 0, 0); #endif /* def _WIN_CONSOLE */ } /********************************************************************* * * Function : privoxy_w32_service_handler * * Description : This is the control message handler function for * the service. * * Parameters : dwOpcode * requested control code sent by SCM * * Returns : void * *********************************************************************/ static void WINAPI privoxy_w32_service_handler(DWORD dwOpcode) { switch(dwOpcode) { case SERVICE_CONTROL_STOP: /* We've stopped */ srv_status.dwCurrentState = SERVICE_STOPPED; srv_status.dwCheckPoint = 0; srv_status.dwWin32ExitCode = NO_ERROR; srv_status.dwServiceSpecificExitCode = 0; /* Maybe there is a more friendly way to stop, but this will do for now! */ w32_set_service_status(hSrv_status, &srv_status); /* During testing, I kept getting error 109 (ERROR_BROKEN_PIPE) and * as far as the SCM was concerned the service was still stopping, * even after the process had disappeared. * * It seems that if we call exit in the ServiceMain thread, it causes * the SCM to not receive the status we sent in the line above. The * simple fix was to create a new thread to actually call exit for us * whilst this thread continues and returns to its caller. */ if (_beginthread(w32_mini_exit, 0, NULL) < 0) { /* we failed to create the exit thread, so just force an exit here * and the SCM will just have to go and whistle! */ exit(0); } break; default: break; } w32_set_service_status(hSrv_status, &srv_status); } #endif /* ifdef _WIN32 */ privoxy-3.0.21-stable/./cgiedit.h000640 001751 001751 00000012051 11630656300 015542 0ustar00fkfk000000 000000 #ifndef CGIEDIT_H_INCLUDED #define CGIEDIT_H_INCLUDED #define CGIEDIT_H_VERSION "$Id: cgiedit.h,v 1.12 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgiedit.h,v $ * * Purpose : CGI-based actionsfile editor. * * Functions declared include: * * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif /* * CGI functions */ #ifdef FEATURE_CGI_EDIT_ACTIONS extern jb_err cgi_edit_actions (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_for_url(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_list (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_submit (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_url (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_add_url(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_add_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_remove_url (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_section_remove(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_section_add (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_edit_actions_section_swap (struct client_state *csp, struct http_response *rsp, const struct map *parameters); #endif /* def FEATURE_CGI_EDIT_ACTIONS */ #ifdef FEATURE_TOGGLE extern jb_err cgi_toggle(struct client_state *csp, struct http_response *rsp, const struct map *parameters); #endif /* def FEATURE_TOGGLE */ /* Revision control strings from this header and associated .c file */ extern const char cgiedit_rcs[]; extern const char cgiedit_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef CGI_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./miscutil.c000640 001751 001751 00000147673 12054151171 015776 0ustar00fkfk000000 000000 const char miscutil_rcs[] = "$Id: miscutil.c,v 1.78 2012/11/24 13:58:17 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/miscutil.c,v $ * * Purpose : zalloc, hash_string, strcmpic, strncmpic, and * MinGW32 strdup functions. These are each too small * to deserve their own file but don't really fit in * any other file. * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * The timegm replacement function was taken from GnuPG, * Copyright (C) 2004 Free Software Foundation, Inc. * * The snprintf replacement function is written by * Mark Martinec who also holds the copyright. It can be * used under the terms of the GPL or the terms of the * "Frontier Artistic License". * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #if !defined(_WIN32) && !defined(__OS2__) #include #endif /* #if !defined(_WIN32) && !defined(__OS2__) */ #include #include #include #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) #include #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */ #include "project.h" #include "miscutil.h" #include "errlog.h" #include "jcc.h" const char miscutil_h_rcs[] = MISCUTIL_H_VERSION; /********************************************************************* * * Function : zalloc * * Description : Malloc some memory and set it to '\0'. * * Parameters : * 1 : size = Size of memory chunk to return. * * Returns : Pointer to newly malloc'd memory chunk. * *********************************************************************/ void *zalloc(size_t size) { void * ret; if ((ret = (void *)malloc(size)) != NULL) { memset(ret, 0, size); } return(ret); } /********************************************************************* * * Function : strdup_or_die * * Description : strdup wrapper that either succeeds or causes * program termination. * * Useful in situations were the string length is * "small" and strdup() failures couldn't be handled * better anyway. In case of debug builds, failures * trigger an assert(). * * Parameters : * 1 : str = String to duplicate * * Returns : Pointer to newly strdup'd copy of the string. * *********************************************************************/ char *strdup_or_die(const char *str) { char *new_str; new_str = strdup(str); if (new_str == NULL) { assert(new_str != NULL); log_error(LOG_LEVEL_FATAL, "Out of memory in strdup_or_die()."); exit(1); } return(new_str); } /********************************************************************* * * Function : malloc_or_die * * Description : malloc wrapper that either succeeds or causes * program termination. * * Useful in situations were the buffer size is "small" * and malloc() failures couldn't be handled better * anyway. In case of debug builds, failures trigger * an assert(). * * Parameters : * 1 : buffer_size = Size of the space to allocate * * Returns : Pointer to newly malloc'd memory * *********************************************************************/ void *malloc_or_die(size_t buffer_size) { char *new_buf; new_buf = malloc(buffer_size); if (new_buf == NULL) { assert(new_buf != NULL); log_error(LOG_LEVEL_FATAL, "Out of memory in malloc_or_die()."); exit(1); } return(new_buf); } #if defined(unix) /********************************************************************* * * Function : write_pid_file * * Description : Writes a pid file with the pid of the main process * * Parameters : None * * Returns : N/A * *********************************************************************/ void write_pid_file(void) { FILE *fp; /* * If no --pidfile option was given, * we can live without one. */ if (pidfile == NULL) return; if ((fp = fopen(pidfile, "w")) == NULL) { log_error(LOG_LEVEL_INFO, "can't open pidfile '%s': %E", pidfile); } else { fprintf(fp, "%u\n", (unsigned int) getpid()); fclose (fp); } return; } #endif /* def unix */ /********************************************************************* * * Function : hash_string * * Description : Take a string and compute a (hopefuly) unique numeric * integer value. This is useful to "switch" a string. * * Parameters : * 1 : s : string to be hashed. * * Returns : The string's hash * *********************************************************************/ unsigned int hash_string(const char* s) { unsigned int h = 0; for (; *s; ++s) { h = 5 * h + (unsigned int)*s; } return (h); } /********************************************************************* * * Function : strcmpic * * Description : Case insensitive string comparison * * Parameters : * 1 : s1 = string 1 to compare * 2 : s2 = string 2 to compare * * Returns : 0 if s1==s2, Negative if s1s2 * *********************************************************************/ int strcmpic(const char *s1, const char *s2) { if (!s1) s1 = ""; if (!s2) s2 = ""; while (*s1 && *s2) { if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2))) { break; } s1++, s2++; } return(privoxy_tolower(*s1) - privoxy_tolower(*s2)); } /********************************************************************* * * Function : strncmpic * * Description : Case insensitive string comparison (up to n characters) * * Parameters : * 1 : s1 = string 1 to compare * 2 : s2 = string 2 to compare * 3 : n = maximum characters to compare * * Returns : 0 if s1==s2, Negative if s1s2 * *********************************************************************/ int strncmpic(const char *s1, const char *s2, size_t n) { if (n <= (size_t)0) return(0); if (!s1) s1 = ""; if (!s2) s2 = ""; while (*s1 && *s2) { if ((*s1 != *s2) && (privoxy_tolower(*s1) != privoxy_tolower(*s2))) { break; } if (--n <= (size_t)0) break; s1++, s2++; } return(privoxy_tolower(*s1) - privoxy_tolower(*s2)); } /********************************************************************* * * Function : chomp * * Description : In-situ-eliminate all leading and trailing whitespace * from a string. * * Parameters : * 1 : s : string to be chomped. * * Returns : chomped string * *********************************************************************/ char *chomp(char *string) { char *p, *q, *r; /* * strip trailing whitespace */ p = string + strlen(string); while (p > string && privoxy_isspace(*(p-1))) { p--; } *p = '\0'; /* * find end of leading whitespace */ q = r = string; while (*q && privoxy_isspace(*q)) { q++; } /* * if there was any, move the rest forwards */ if (q != string) { while (q <= p) { *r++ = *q++; } } return(string); } /********************************************************************* * * Function : string_append * * Description : Reallocate target_string and append text to it. * This makes it easier to append to malloc'd strings. * This is similar to the (removed) strsav(), but * running out of memory isn't catastrophic. * * Programming style: * * The following style provides sufficient error * checking for this routine, with minimal clutter * in the source code. It is recommended if you * have many calls to this function: * * char * s = strdup(...); // don't check for error * string_append(&s, ...); // don't check for error * string_append(&s, ...); // don't check for error * string_append(&s, ...); // don't check for error * if (NULL == s) { ... handle error ... } * * OR, equivalently: * * char * s = strdup(...); // don't check for error * string_append(&s, ...); // don't check for error * string_append(&s, ...); // don't check for error * if (string_append(&s, ...)) {... handle error ...} * * Parameters : * 1 : target_string = Pointer to old text that is to be * extended. *target_string will be free()d by this * routine. target_string must be non-NULL. * If *target_string is NULL, this routine will * do nothing and return with an error - this allows * you to make many calls to this routine and only * check for errors after the last one. * 2 : text_to_append = Text to be appended to old. * Must not be NULL. * * Returns : JB_ERR_OK on success, and sets *target_string * to newly malloc'ed appended string. Caller * must free(*target_string). * JB_ERR_MEMORY on out-of-memory. (And free()s * *target_string and sets it to NULL). * JB_ERR_MEMORY if *target_string is NULL. * *********************************************************************/ jb_err string_append(char **target_string, const char *text_to_append) { size_t old_len; char *new_string; size_t new_size; assert(target_string); assert(text_to_append); if (*target_string == NULL) { return JB_ERR_MEMORY; } if (*text_to_append == '\0') { return JB_ERR_OK; } old_len = strlen(*target_string); new_size = strlen(text_to_append) + old_len + 1; if (NULL == (new_string = realloc(*target_string, new_size))) { free(*target_string); *target_string = NULL; return JB_ERR_MEMORY; } strlcpy(new_string + old_len, text_to_append, new_size - old_len); *target_string = new_string; return JB_ERR_OK; } /********************************************************************* * * Function : string_join * * Description : Join two strings together. Frees BOTH the original * strings. If either or both input strings are NULL, * fails as if it had run out of memory. * * For comparison, string_append requires that the * second string is non-NULL, and doesn't free it. * * Rationale: Too often, we want to do * string_append(s, html_encode(s2)). That assert()s * if s2 is NULL or if html_encode() runs out of memory. * It also leaks memory. Proper checking is cumbersome. * The solution: string_join(s, html_encode(s2)) is safe, * and will free the memory allocated by html_encode(). * * Parameters : * 1 : target_string = Pointer to old text that is to be * extended. *target_string will be free()d by this * routine. target_string must be non-NULL. * 2 : text_to_append = Text to be appended to old. * * Returns : JB_ERR_OK on success, and sets *target_string * to newly malloc'ed appended string. Caller * must free(*target_string). * JB_ERR_MEMORY on out-of-memory, or if * *target_string or text_to_append is NULL. (In * this case, frees *target_string and text_to_append, * sets *target_string to NULL). * *********************************************************************/ jb_err string_join(char **target_string, char *text_to_append) { jb_err err; assert(target_string); if (text_to_append == NULL) { freez(*target_string); return JB_ERR_MEMORY; } err = string_append(target_string, text_to_append); freez(text_to_append); return err; } /********************************************************************* * * Function : string_toupper * * Description : Produce a copy of string with all convertible * characters converted to uppercase. * * Parameters : * 1 : string = string to convert * * Returns : Uppercase copy of string if possible, * NULL on out-of-memory or if string was NULL. * *********************************************************************/ char *string_toupper(const char *string) { char *result, *p; const char *q; if (!string || ((result = (char *) zalloc(strlen(string) + 1)) == NULL)) { return NULL; } q = string; p = result; while (*q != '\0') { *p++ = (char)toupper((int) *q++); } return result; } /********************************************************************* * * Function : string_move * * Description : memmove wrapper to move the last part of a string * towards the beginning, overwriting the part in * the middle. strlcpy() can't be used here as the * strings overlap. * * Parameters : * 1 : dst = Destination to overwrite * 2 : src = Source to move. * * Returns : N/A * *********************************************************************/ void string_move(char *dst, char *src) { assert(dst < src); /* +1 to copy the terminating nul as well. */ memmove(dst, src, strlen(src)+1); } /********************************************************************* * * Function : bindup * * Description : Duplicate the first n characters of a string that may * contain '\0' characters. * * Parameters : * 1 : string = string to be duplicated * 2 : len = number of bytes to duplicate * * Returns : pointer to copy, or NULL if failiure * *********************************************************************/ char *bindup(const char *string, size_t len) { char *duplicate; duplicate = (char *)malloc(len); if (NULL != duplicate) { memcpy(duplicate, string, len); } return duplicate; } /********************************************************************* * * Function : make_path * * Description : Takes a directory name and a file name, returns * the complete path. Handles windows/unix differences. * If the file name is already an absolute path, or if * the directory name is NULL or empty, it returns * the filename. * * Parameters : * 1 : dir: Name of directory or NULL for none. * 2 : file: Name of file. Should not be NULL or empty. * * Returns : "dir/file" (Or on windows, "dir\file"). * It allocates the string on the heap. Caller frees. * Returns NULL in error (i.e. NULL file or out of * memory) * *********************************************************************/ char * make_path(const char * dir, const char * file) { #ifdef AMIGA char path[512]; if (dir) { if (dir[0] == '.') { if (dir[1] == '/') { strncpy(path,dir+2,512); } else { strncpy(path,dir+1,512); } } else { strncpy(path,dir,512); } path[511]=0; } else { path[0]=0; } if (AddPart(path,file,512)) { return strdup(path); } else { return NULL; } #else /* ndef AMIGA */ if ((file == NULL) || (*file == '\0')) { return NULL; /* Error */ } if ((dir == NULL) || (*dir == '\0') /* No directory specified */ #if defined(_WIN32) || defined(__OS2__) || (*file == '\\') || (file[1] == ':') /* Absolute path (DOS) */ #else /* ifndef _WIN32 || __OS2__ */ || (*file == '/') /* Absolute path (U*ix) */ #endif /* ifndef _WIN32 || __OS2__ */ ) { return strdup(file); } else { char * path; size_t path_size = strlen(dir) + strlen(file) + 2; /* +2 for trailing (back)slash and \0 */ #if defined(unix) if (*dir != '/' && basedir && *basedir) { /* * Relative path, so start with the base directory. */ path_size += strlen(basedir) + 1; /* +1 for the slash */ path = malloc(path_size); if (!path) log_error(LOG_LEVEL_FATAL, "malloc failed!"); strlcpy(path, basedir, path_size); strlcat(path, "/", path_size); strlcat(path, dir, path_size); } else #endif /* defined unix */ { path = malloc(path_size); if (!path) log_error(LOG_LEVEL_FATAL, "malloc failed!"); strlcpy(path, dir, path_size); } assert(NULL != path); #if defined(_WIN32) || defined(__OS2__) if (path[strlen(path)-1] != '\\') { strlcat(path, "\\", path_size); } #else /* ifndef _WIN32 || __OS2__ */ if (path[strlen(path)-1] != '/') { strlcat(path, "/", path_size); } #endif /* ifndef _WIN32 || __OS2__ */ strlcat(path, file, path_size); return path; } #endif /* ndef AMIGA */ } /********************************************************************* * * Function : pick_from_range * * Description : Pick a positive number out of a given range. * Should only be used if randomness would be nice, * but isn't really necessary. * * Parameters : * 1 : range: Highest possible number to pick. * * Returns : Picked number. * *********************************************************************/ long int pick_from_range(long int range) { long int number; #ifdef _WIN32 static unsigned long seed = 0; #endif /* def _WIN32 */ assert(range != 0); assert(range > 0); if (range <= 0) return 0; #ifdef HAVE_RANDOM number = random() % range + 1; #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&rand_mutex); #ifdef _WIN32 if (!seed) { seed = (unsigned long)(GetCurrentThreadId()+GetTickCount()); } srand(seed); seed = (unsigned long)((rand() << 16) + rand()); #endif /* def _WIN32 */ number = (unsigned long)((rand() << 16) + (rand())) % (unsigned long)(range + 1); privoxy_mutex_unlock(&rand_mutex); #else /* * XXX: Which platforms reach this and are there * better options than just using rand() and hoping * that it's safe? */ log_error(LOG_LEVEL_INFO, "No thread-safe PRNG available? Header time randomization " "might cause crashes, predictable results or even combine these fine options."); number = rand() % (long int)(range + 1); #endif /* (def HAVE_RANDOM) */ return number; } #ifdef USE_PRIVOXY_STRLCPY /********************************************************************* * * Function : privoxy_strlcpy * * Description : strlcpy(3) look-alike for those without decent libc. * * Parameters : * 1 : destination: buffer to copy into. * 2 : source: String to copy. * 3 : size: Size of destination buffer. * * Returns : The length of the string that privoxy_strlcpy() tried to create. * *********************************************************************/ size_t privoxy_strlcpy(char *destination, const char *source, const size_t size) { if (0 < size) { snprintf(destination, size, "%s", source); /* * Platforms that lack strlcpy() also tend to have * a broken snprintf implementation that doesn't * guarantee nul termination. * * XXX: the configure script should detect and reject those. */ destination[size-1] = '\0'; } return strlen(source); } #endif /* def USE_PRIVOXY_STRLCPY */ #ifndef HAVE_STRLCAT /********************************************************************* * * Function : privoxy_strlcat * * Description : strlcat(3) look-alike for those without decent libc. * * Parameters : * 1 : destination: C string. * 2 : source: String to copy. * 3 : size: Size of destination buffer. * * Returns : The length of the string that privoxy_strlcat() tried to create. * *********************************************************************/ size_t privoxy_strlcat(char *destination, const char *source, const size_t size) { const size_t old_length = strlen(destination); return old_length + strlcpy(destination + old_length, source, size - old_length); } #endif /* ndef HAVE_STRLCAT */ #if !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) /********************************************************************* * * Function : timegm * * Description : libc replacement function for the inverse of gmtime(). * Copyright (C) 2004 Free Software Foundation, Inc. * * Code originally copied from GnuPG, modifications done * for Privoxy: style changed, #ifdefs for _WIN32 added * to have it work on mingw32. * * XXX: It's very unlikely to happen, but if the malloc() * call fails the time zone will be permanently set to UTC. * * Parameters : * 1 : tm: Broken-down time struct. * * Returns : tm converted into time_t seconds. * *********************************************************************/ time_t timegm(struct tm *tm) { time_t answer; char *zone; zone = getenv("TZ"); putenv("TZ=UTC"); tzset(); answer = mktime(tm); if (zone) { char *old_zone; old_zone = malloc(3 + strlen(zone) + 1); if (old_zone) { strcpy(old_zone, "TZ="); strcat(old_zone, zone); putenv(old_zone); #ifdef _WIN32 free(old_zone); #endif /* def _WIN32 */ } } else { #ifdef HAVE_UNSETENV unsetenv("TZ"); #elif defined(_WIN32) putenv("TZ="); #else putenv("TZ"); #endif } tzset(); return answer; } #endif /* !defined(HAVE_TIMEGM) && defined(HAVE_TZSET) && defined(HAVE_PUTENV) */ #ifndef HAVE_SNPRINTF /* * What follows is a portable snprintf routine, written by Mark Martinec. * See: http://www.ijs.si/software/snprintf/ snprintf.c - a portable implementation of snprintf, including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf snprintf is a routine to convert numeric and string arguments to formatted strings. It is similar to sprintf(3) provided in a system's C library, yet it requires an additional argument - the buffer size - and it guarantees never to store anything beyond the given buffer, regardless of the format or arguments to be formatted. Some newer operating systems do provide snprintf in their C library, but many do not or do provide an inadequate (slow or idiosyncratic) version, which calls for a portable implementation of this routine. Author Mark Martinec , April 1999, June 2000 Copyright © 1999, Mark Martinec */ #define PORTABLE_SNPRINTF_VERSION_MAJOR 2 #define PORTABLE_SNPRINTF_VERSION_MINOR 2 #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) # if defined(NEED_SNPRINTF_ONLY) # undef NEED_SNPRINTF_ONLY # endif # if !defined(PREFER_PORTABLE_SNPRINTF) # define PREFER_PORTABLE_SNPRINTF # endif #endif #if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE) #define SOLARIS_COMPATIBLE #endif #if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE) #define HPUX_COMPATIBLE #endif #if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE) #define DIGITAL_UNIX_COMPATIBLE #endif #if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE) #define PERL_COMPATIBLE #endif #if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE) #define LINUX_COMPATIBLE #endif #include #include #include #include #include #include #include #ifdef isdigit #undef isdigit #endif #define isdigit(c) ((c) >= '0' && (c) <= '9') /* For copying strings longer or equal to 'breakeven_point' * it is more efficient to call memcpy() than to do it inline. * The value depends mostly on the processor architecture, * but also on the compiler and its optimization capabilities. * The value is not critical, some small value greater than zero * will be just fine if you don't care to squeeze every drop * of performance out of the code. * * Small values favor memcpy, large values favor inline code. */ #if defined(__alpha__) || defined(__alpha) # define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */ #endif #if defined(__i386__) || defined(__i386) # define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */ #endif #if defined(__hppa) # define breakeven_point 10 /* HP-PA - gcc */ #endif #if defined(__sparc__) || defined(__sparc) # define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */ #endif /* some other values of possible interest: */ /* #define breakeven_point 8 */ /* VAX 4000 - vaxc */ /* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */ #ifndef breakeven_point # define breakeven_point 6 /* some reasonable one-size-fits-all value */ #endif #define fast_memcpy(d,s,n) \ { register size_t nn = (size_t)(n); \ if (nn >= breakeven_point) memcpy((d), (s), nn); \ else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ register char *dd; register const char *ss; \ for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } } #define fast_memset(d,c,n) \ { register size_t nn = (size_t)(n); \ if (nn >= breakeven_point) memset((d), (int)(c), nn); \ else if (nn > 0) { /* proc call overhead is worth only for large strings*/\ register char *dd; register const int cc=(int)(c); \ for (dd=(d); nn>0; nn--) *dd++ = cc; } } /* prototypes */ #if defined(NEED_ASPRINTF) int asprintf (char **ptr, const char *fmt, /*args*/ ...); #endif #if defined(NEED_VASPRINTF) int vasprintf (char **ptr, const char *fmt, va_list ap); #endif #if defined(NEED_ASNPRINTF) int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); #endif #if defined(NEED_VASNPRINTF) int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap); #endif #if defined(HAVE_SNPRINTF) /* declare our portable snprintf routine under name portable_snprintf */ /* declare our portable vsnprintf routine under name portable_vsnprintf */ #else /* declare our portable routines under names snprintf and vsnprintf */ #define portable_snprintf snprintf #if !defined(NEED_SNPRINTF_ONLY) #define portable_vsnprintf vsnprintf #endif #endif #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); #if !defined(NEED_SNPRINTF_ONLY) int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); #endif #endif /* declarations */ static char credits[] = "\n\ @(#)snprintf.c, v2.2: Mark Martinec, \n\ @(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\ @(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n"; #if defined(NEED_ASPRINTF) int asprintf(char **ptr, const char *fmt, /*args*/ ...) { va_list ap; size_t str_m; int str_l; *ptr = NULL; va_start(ap, fmt); /* measure the required size */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); va_end(ap); assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ *ptr = (char *) malloc(str_m = (size_t)str_l + 1); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2; va_start(ap, fmt); str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); va_end(ap); assert(str_l2 == str_l); } return str_l; } #endif #if defined(NEED_VASPRINTF) int vasprintf(char **ptr, const char *fmt, va_list ap) { size_t str_m; int str_l; *ptr = NULL; { va_list ap2; va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ va_end(ap2); } assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ *ptr = (char *) malloc(str_m = (size_t)str_l + 1); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); assert(str_l2 == str_l); } return str_l; } #endif #if defined(NEED_ASNPRINTF) int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) { va_list ap; int str_l; *ptr = NULL; va_start(ap, fmt); /* measure the required size */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap); va_end(ap); assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ if (str_m == 0) { /* not interested in resulting string, just return size */ } else { *ptr = (char *) malloc(str_m); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2; va_start(ap, fmt); str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); va_end(ap); assert(str_l2 == str_l); } } return str_l; } #endif #if defined(NEED_VASNPRINTF) int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) { int str_l; *ptr = NULL; { va_list ap2; va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */ str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/ va_end(ap2); } assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */ if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */ /* if str_m is 0, no buffer is allocated, just set *ptr to NULL */ if (str_m == 0) { /* not interested in resulting string, just return size */ } else { *ptr = (char *) malloc(str_m); if (*ptr == NULL) { errno = ENOMEM; str_l = -1; } else { int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap); assert(str_l2 == str_l); } } return str_l; } #endif /* * If the system does have snprintf and the portable routine is not * specifically required, this module produces no code for snprintf/vsnprintf. */ #if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF) #if !defined(NEED_SNPRINTF_ONLY) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { va_list ap; int str_l; va_start(ap, fmt); str_l = portable_vsnprintf(str, str_m, fmt, ap); va_end(ap); return str_l; } #endif #if defined(NEED_SNPRINTF_ONLY) int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) { #else int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) { #endif #if defined(NEED_SNPRINTF_ONLY) va_list ap; #endif size_t str_l = 0; const char *p = fmt; /* In contrast with POSIX, the ISO C99 now says * that str can be NULL and str_m can be 0. * This is more useful than the old: if (str_m < 1) return -1; */ #if defined(NEED_SNPRINTF_ONLY) va_start(ap, fmt); #endif if (!p) p = ""; while (*p) { if (*p != '%') { /* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */ /* but the following code achieves better performance for cases * where format string is long and contains few conversions */ const char *q = strchr(p+1,'%'); size_t n = !q ? strlen(p) : (q-p); if (str_l < str_m) { size_t avail = str_m-str_l; fast_memcpy(str+str_l, p, (n>avail?avail:n)); } p += n; str_l += n; } else { const char *starting_p; size_t min_field_width = 0, precision = 0; int zero_padding = 0, precision_specified = 0, justify_left = 0; int alternate_form = 0, force_sign = 0; int space_for_positive = 1; /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored. */ char length_modifier = '\0'; /* allowed values: \0, h, l, L */ char tmp[32];/* temporary buffer for simple numeric->string conversion */ const char *str_arg; /* string address in case of string argument */ size_t str_arg_l; /* natural field width of arg without padding and sign */ unsigned char uchar_arg; /* unsigned char argument value - only defined for c conversion. N.B. standard explicitly states the char argument for the c conversion is unsigned */ size_t number_of_zeros_to_pad = 0; /* number of zeros to be inserted for numeric conversions as required by the precision or minimal field width */ size_t zero_padding_insertion_ind = 0; /* index into tmp where zero padding is to be inserted */ char fmt_spec = '\0'; /* current conversion specifier character */ str_arg = credits;/* just to make compiler happy (defined but not used)*/ str_arg = NULL; starting_p = p; p++; /* skip '%' */ /* parse flags */ while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' || *p == '#' || *p == '\'') { switch (*p) { case '0': zero_padding = 1; break; case '-': justify_left = 1; break; case '+': force_sign = 1; space_for_positive = 0; break; case ' ': force_sign = 1; /* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */ #ifdef PERL_COMPATIBLE /* ... but in Perl the last of ' ' and '+' applies */ space_for_positive = 1; #endif break; case '#': alternate_form = 1; break; case '\'': break; } p++; } /* If the '0' and '-' flags both appear, the '0' flag should be ignored. */ /* parse field width */ if (*p == '*') { int j; p++; j = va_arg(ap, int); if (j >= 0) min_field_width = j; else { min_field_width = -j; justify_left = 1; } } else if (isdigit((int)(*p))) { /* size_t could be wider than unsigned int; make sure we treat argument like common implementations do */ unsigned int uj = *p++ - '0'; while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); min_field_width = uj; } /* parse precision */ if (*p == '.') { p++; precision_specified = 1; if (*p == '*') { int j = va_arg(ap, int); p++; if (j >= 0) precision = j; else { precision_specified = 0; precision = 0; /* NOTE: * Solaris 2.6 man page claims that in this case the precision * should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page * claim that this case should be treated as unspecified precision, * which is what we do here. */ } } else if (isdigit((int)(*p))) { /* size_t could be wider than unsigned int; make sure we treat argument like common implementations do */ unsigned int uj = *p++ - '0'; while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0'); precision = uj; } } /* parse 'h', 'l' and 'll' length modifiers */ if (*p == 'h' || *p == 'l') { length_modifier = *p; p++; if (length_modifier == 'l' && *p == 'l') { /* double l = long long */ #ifdef SNPRINTF_LONGLONG_SUPPORT length_modifier = '2'; /* double l encoded as '2' */ #else length_modifier = 'l'; /* treat it as a single 'l' */ #endif p++; } } fmt_spec = *p; /* common synonyms: */ switch (fmt_spec) { case 'i': fmt_spec = 'd'; break; case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; default: break; } /* get parameter value, do initial processing */ switch (fmt_spec) { case '%': /* % behaves similar to 's' regarding flags and field widths */ case 'c': /* c behaves similar to 's' regarding flags and field widths */ case 's': length_modifier = '\0'; /* wint_t and wchar_t not supported */ /* the result of zero padding flag with non-numeric conversion specifier*/ /* is undefined. Solaris and HPUX 10 does zero padding in this case, */ /* Digital Unix and Linux does not. */ #if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE) zero_padding = 0; /* turn zero padding off for string conversions */ #endif str_arg_l = 1; switch (fmt_spec) { case '%': str_arg = p; break; case 'c': { int j = va_arg(ap, int); uchar_arg = (unsigned char) j; /* standard demands unsigned char */ str_arg = (const char *) &uchar_arg; break; } case 's': str_arg = va_arg(ap, const char *); if (!str_arg) str_arg_l = 0; /* make sure not to address string beyond the specified precision !!! */ else if (!precision_specified) str_arg_l = strlen(str_arg); /* truncate string if necessary as requested by precision */ else if (precision == 0) str_arg_l = 0; else { /* memchr on HP does not like n > 2^31 !!! */ const char *q = memchr(str_arg, '\0', precision <= 0x7fffffff ? precision : 0x7fffffff); str_arg_l = !q ? precision : (q-str_arg); } break; default: break; } break; case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': { /* NOTE: the u, o, x, X and p conversion specifiers imply the value is unsigned; d implies a signed value */ int arg_sign = 0; /* 0 if numeric argument is zero (or if pointer is NULL for 'p'), +1 if greater than zero (or nonzero for unsigned arguments), -1 if negative (unsigned argument is never negative) */ int int_arg = 0; unsigned int uint_arg = 0; /* only defined for length modifier h, or for no length modifiers */ long int long_arg = 0; unsigned long int ulong_arg = 0; /* only defined for length modifier l */ void *ptr_arg = NULL; /* pointer argument value -only defined for p conversion */ #ifdef SNPRINTF_LONGLONG_SUPPORT long long int long_long_arg = 0; unsigned long long int ulong_long_arg = 0; /* only defined for length modifier ll */ #endif if (fmt_spec == 'p') { /* HPUX 10: An l, h, ll or L before any other conversion character * (other than d, i, u, o, x, or X) is ignored. * Digital Unix: * not specified, but seems to behave as HPUX does. * Solaris: If an h, l, or L appears before any other conversion * specifier (other than d, i, u, o, x, or X), the behavior * is undefined. (Actually %hp converts only 16-bits of address * and %llp treats address as 64-bit data which is incompatible * with (void *) argument on a 32-bit system). */ #ifdef SOLARIS_COMPATIBLE # ifdef SOLARIS_BUG_COMPATIBLE /* keep length modifiers even if it represents 'll' */ # else if (length_modifier == '2') length_modifier = '\0'; # endif #else length_modifier = '\0'; #endif ptr_arg = va_arg(ap, void *); if (ptr_arg != NULL) arg_sign = 1; } else if (fmt_spec == 'd') { /* signed */ switch (length_modifier) { case '\0': case 'h': /* It is non-portable to specify a second argument of char or short * to va_arg, because arguments seen by the called function * are not char or short. C converts char and short arguments * to int before passing them to a function. */ int_arg = va_arg(ap, int); if (int_arg > 0) arg_sign = 1; else if (int_arg < 0) arg_sign = -1; break; case 'l': long_arg = va_arg(ap, long int); if (long_arg > 0) arg_sign = 1; else if (long_arg < 0) arg_sign = -1; break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': long_long_arg = va_arg(ap, long long int); if (long_long_arg > 0) arg_sign = 1; else if (long_long_arg < 0) arg_sign = -1; break; #endif } } else { /* unsigned */ switch (length_modifier) { case '\0': case 'h': uint_arg = va_arg(ap, unsigned int); if (uint_arg) arg_sign = 1; break; case 'l': ulong_arg = va_arg(ap, unsigned long int); if (ulong_arg) arg_sign = 1; break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': ulong_long_arg = va_arg(ap, unsigned long long int); if (ulong_long_arg) arg_sign = 1; break; #endif } } str_arg = tmp; str_arg_l = 0; /* NOTE: * For d, i, u, o, x, and X conversions, if precision is specified, * the '0' flag should be ignored. This is so with Solaris 2.6, * Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. */ #ifndef PERL_COMPATIBLE if (precision_specified) zero_padding = 0; #endif if (fmt_spec == 'd') { if (force_sign && arg_sign >= 0) tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; /* leave negative numbers for sprintf to handle, to avoid handling tricky cases like (short int)(-32768) */ #ifdef LINUX_COMPATIBLE } else if (fmt_spec == 'p' && force_sign && arg_sign > 0) { tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; #endif } else if (alternate_form) { if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; } /* alternate form should have no effect for p conversion, but ... */ #ifdef HPUX_COMPATIBLE else if (fmt_spec == 'p' /* HPUX 10: for an alternate form of p conversion, * a nonzero result is prefixed by 0x. */ #ifndef HPUX_BUG_COMPATIBLE /* Actually it uses 0x prefix even for a zero value. */ && arg_sign != 0 #endif ) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; } #endif } zero_padding_insertion_ind = str_arg_l; if (!precision_specified) precision = 1; /* default precision is 1 */ if (precision == 0 && arg_sign == 0 #if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE) && fmt_spec != 'p' /* HPUX 10 man page claims: With conversion character p the result of * converting a zero value with a precision of zero is a null string. * Actually HP returns all zeroes, and Linux returns "(nil)". */ #endif ) { /* converted to null string */ /* When zero value is formatted with an explicit precision 0, the resulting formatted string is empty (d, i, u, o, x, X, p). */ } else { char f[5]; int f_l = 0; f[f_l++] = '%'; /* construct a simple format string for sprintf */ if (!length_modifier) { } else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; } else f[f_l++] = length_modifier; f[f_l++] = fmt_spec; f[f_l++] = '\0'; if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg); else if (fmt_spec == 'd') { /* signed */ switch (length_modifier) { case '\0': case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break; case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break; #endif } } else { /* unsigned */ switch (length_modifier) { case '\0': case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break; case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break; #ifdef SNPRINTF_LONGLONG_SUPPORT case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break; #endif } } /* include the optional minus sign and possible "0x" in the region before the zero padding insertion point */ if (zero_padding_insertion_ind < str_arg_l && tmp[zero_padding_insertion_ind] == '-') { zero_padding_insertion_ind++; } if (zero_padding_insertion_ind+1 < str_arg_l && tmp[zero_padding_insertion_ind] == '0' && (tmp[zero_padding_insertion_ind+1] == 'x' || tmp[zero_padding_insertion_ind+1] == 'X') ) { zero_padding_insertion_ind += 2; } } { size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; if (alternate_form && fmt_spec == 'o' #ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */ && (str_arg_l > 0) #endif #ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */ #else /* unless zero is already the first character */ && !(zero_padding_insertion_ind < str_arg_l && tmp[zero_padding_insertion_ind] == '0') #endif ) { /* assure leading zero for alternate-form octal numbers */ if (!precision_specified || precision < num_of_digits+1) { /* precision is increased to force the first character to be zero, except if a zero value is formatted with an explicit precision of zero */ precision = num_of_digits+1; precision_specified = 1; } } /* zero padding to specified precision? */ if (num_of_digits < precision) number_of_zeros_to_pad = precision - num_of_digits; } /* zero padding to specified minimal field width? */ if (!justify_left && zero_padding) { int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) number_of_zeros_to_pad += n; } break; } default: /* unrecognized conversion specifier, keep format string as-is*/ zero_padding = 0; /* turn zero padding off for non-numeric convers. */ #ifndef DIGITAL_UNIX_COMPATIBLE justify_left = 1; min_field_width = 0; /* reset flags */ #endif #if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE) /* keep the entire format string unchanged */ str_arg = starting_p; str_arg_l = p - starting_p; /* well, not exactly so for Linux, which does something between, * and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */ #else /* discard the unrecognized conversion, just keep * * the unrecognized conversion character */ str_arg = p; str_arg_l = 0; #endif if (*p) str_arg_l++; /* include invalid conversion specifier unchanged if not at end-of-string */ break; } if (*p) p++; /* step over the just processed conversion specifier */ /* insert padding to the left as requested by min_field_width; this does not include the zero padding in case of numerical conversions*/ if (!justify_left) { /* left padding with blank or zero */ int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) { if (str_l < str_m) { size_t avail = str_m-str_l; fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n)); } str_l += n; } } /* zero padding as requested by the precision or by the minimal field width * for numeric conversions required? */ if (number_of_zeros_to_pad <= 0) { /* will not copy first part of numeric right now, * * force it to be copied later in its entirety */ zero_padding_insertion_ind = 0; } else { /* insert first part of numerics (sign or '0x') before zero padding */ int n = zero_padding_insertion_ind; if (n > 0) { if (str_l < str_m) { size_t avail = str_m-str_l; fast_memcpy(str+str_l, str_arg, (n>avail?avail:n)); } str_l += n; } /* insert zero padding as requested by the precision or min field width */ n = number_of_zeros_to_pad; if (n > 0) { if (str_l < str_m) { size_t avail = str_m-str_l; fast_memset(str+str_l, '0', (n>avail?avail:n)); } str_l += n; } } /* insert formatted string * (or as-is conversion specifier for unknown conversions) */ { int n = str_arg_l - zero_padding_insertion_ind; if (n > 0) { if (str_l < str_m) { size_t avail = str_m-str_l; fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind, (n>avail?avail:n)); } str_l += n; } } /* insert right padding */ if (justify_left) { /* right blank padding to the field width */ int n = min_field_width - (str_arg_l+number_of_zeros_to_pad); if (n > 0) { if (str_l < str_m) { size_t avail = str_m-str_l; fast_memset(str+str_l, ' ', (n>avail?avail:n)); } str_l += n; } } } } #if defined(NEED_SNPRINTF_ONLY) va_end(ap); #endif if (str_m > 0) { /* make sure the string is null-terminated even at the expense of overwriting the last character (shouldn't happen, but just in case) */ str[str_l <= str_m-1 ? str_l : str_m-1] = '\0'; } /* Return the number of characters formatted (excluding trailing null * character), that is, the number of characters that would have been * written to the buffer if it were large enough. * * The value of str_l should be returned, but str_l is of unsigned type * size_t, and snprintf is int, possibly leading to an undetected * integer overflow, resulting in a negative return value, which is illegal. * Both XSH5 and ISO C99 (at least the draft) are silent on this issue. * Should errno be set to EOVERFLOW and EOF returned in this case??? */ return (int) str_l; } #endif #endif /* ndef HAVE_SNPRINTF */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./tools/uagen.pl000750 001751 001751 00000047266 12076005251 016575 0ustar00fkfk000000 000000 #!/usr/bin/perl ############################################################################################## # uagen (http://www.fabiankeil.de/sourcecode/uagen/) # # $Id: uagen.pl,v 1.25 2013/01/17 14:28:57 fabiankeil Exp $ # # Generates a pseudo-random Firefox user agent and writes it into a Privoxy action file # and optionally into a Mozilla prefs file. For documentation see 'perldoc uagen(.pl)'. # # Examples (created with v1.0): # # Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8.0.2) Gecko/20060421 Firefox/1.5.0.2 # Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-CA; rv:1.8.0.2) Gecko/20060425 Firefox/1.5.0.2 # Mozilla/5.0 (X11; U; SunOS i86pc; no-NO; rv:1.8.0.2) Gecko/20060420 Firefox/1.5.0.2 # Mozilla/5.0 (X11; U; Linux x86_64; de-AT; rv:1.8.0.2) Gecko/20060422 Firefox/1.5.0.2 # Mozilla/5.0 (X11; U; NetBSD i386; en-US; rv:1.8.0.2) Gecko/20060415 Firefox/1.5.0.2 # Mozilla/5.0 (X11; U; OpenBSD sparc64; pl-PL; rv:1.8.0.2) Gecko/20060429 Firefox/1.5.0.2 # Mozilla/5.0 (X11; U; Linux i686; en-CA; rv:1.8.0.2) Gecko/20060413 Firefox/1.5.0.2 # # Copyright (c) 2006-2011 Fabian Keil # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ############################################################################################## use strict; use warnings; use Time::Local; use Getopt::Long; use constant { UAGEN_VERSION => 'uagen 1.2.1', UAGEN_LOGFILE => '/var/log/uagen.log', ACTION_FILE => '/etc/privoxy/user-agent.action', MOZILLA_PREFS_FILE => '', SILENT => 0, NO_LOGGING => 0, NO_ACTION_FILE => 0, LOOP => 0, SLEEPING_TIME => 5, # As of Firefox 4, the "Gecko token" has been frozen # http://hacks.mozilla.org/2010/09/final-user-agent-string-for-firefox-4/ RANDOMIZE_RELEASE_DATE => 0, # These variables belong together. If you only change one of them, the generated # User-Agent might be invalid. If you're not sure which values make sense, # are too lazy to check, but want to change them anyway, take the values you # see in the "Help/About Mozilla Firefox" menu. BROWSER_VERSION => "17.0", BROWSER_REVISION => '17.0', BROWSER_RELEASE_DATE => '20100101', }; use constant LANGUAGES => qw( en-AU en-GB en-CA en-NZ en-US en-ZW es-ES de-DE de-AT de-CH fr-FR sk-SK nl-NL no-NO pl-PL ); ####################################################################################### sub generate_creation_time($) { my $release_date = shift; my ($rel_year, $rel_mon, $rel_day); my ($c_day, $c_mon, $c_year); my $now = time; my (undef, undef, undef, $mday, $mon, $year, undef, undef, undef) = localtime($now); $mon += 1; $year += 1900; unless ($release_date =~ m/\d{6}/) { log_error("Invalid release date format: $release_date. Using " . BROWSER_RELEASE_DATE . " instead."); $release_date = BROWSER_RELEASE_DATE; } $rel_year = substr($release_date, 0, 4); $rel_mon = substr($release_date, 4, 2); $rel_day = substr($release_date, 6, 2); #1, 2, 3, Check. die "release year in the future" if ($year < $rel_year); die "release month in the future" if (($year == $rel_year) and ($mon < $rel_mon)); die "release day in the future" if (($year == $rel_year) and ($mon == $rel_mon) and ($mday < $rel_day)); my @c_time = (0, 0, 0, $rel_day, $rel_mon - 1, $rel_year - 1900, 0, 0, 0); my $c_seconds = timelocal(@c_time); $c_seconds = $now - (int rand ($now - $c_seconds)); @c_time = localtime($c_seconds); (undef, undef, undef, $c_day, $c_mon, $c_year, undef, undef, undef) = @c_time; $c_mon += 1; $c_year += 1900; #3, 2, 1, Test. die "Compilation year in the future" if ($year < $c_year); die "Compilation month in the future" if (($year == $c_year) and ($mon < $c_mon)); die "Compilation day in the future" if (($year == $c_year) and ($mon == $c_mon) and ($mday < $c_day)); return sprintf("%.2i%.2i%.2i", $c_year, $c_mon, $c_day); } sub generate_language_settings() { our @languages; my $language_i = int rand (@languages); my $accept_language = $languages[$language_i]; $accept_language =~ tr/[A-Z]/[a-z]/; return ($languages[$language_i], $accept_language); } sub generate_platform_and_os() { my %os_data = ( FreeBSD => { karma => 1, platform => 'X11', architectures => [ 'i386', 'amd64', 'sparc64', 'alpha' ], order_is_inversed => 0, }, OpenBSD => { karma => 1, platform => 'X11', architectures => [ 'i386', 'amd64', 'sparc64', 'alpha' ], order_is_inversed => 0, }, NetBSD => { karma => 1, platform => 'X11', architectures => [ 'i386', 'amd64', 'sparc64', 'alpha' ], order_is_inversed => 0, }, Linux => { karma => 1, platform => 'X11', architectures => [ 'i586', 'i686', 'x86_64' ], order_is_inversed => 0, }, SunOS => { karma => 1, platform => 'X11', architectures => [ 'i86pc', 'sun4u' ], order_is_inversed => 0, }, 'Mac OS X' => { karma => 1, platform => 'Macintosh', architectures => [ 'PPC', 'Intel' ], order_is_inversed => 1, }, Windows => { karma => 0, platform => 'Windows', architectures => [ 'NT 5.1' ], order_is_inversed => 0, } ); my @os_names; foreach my $os_name ( keys %os_data ) { push @os_names, ($os_name) x $os_data{$os_name}{'karma'} if $os_data{$os_name}{'karma'}; } my $os_i = int rand(@os_names); my $os = $os_names[$os_i]; my $arch_i = int rand( @{ $os_data{$os}{'architectures'} } ); my $arch = $os_data{$os}{'architectures'}[$arch_i]; my $platform = $os_data{$os}{'platform'}; my $os_or_cpu; $os_or_cpu = sprintf "%s %s", $os_data{$os}{'order_is_inversed'} ? ( $arch, $os ) : ( $os, $arch ); return $platform, $os_or_cpu; } sub generate_firefox_user_agent() { our $languages; our $browser_version; our $browser_revision; our $browser_release_date; our $randomize_release_date; my $mozillaversion = '5.0'; my $creation_time = $randomize_release_date ? generate_creation_time($browser_release_date) : $browser_release_date; my ( $locale, $accept_language ) = generate_language_settings(); my ( $platform, $os_or_cpu ) = generate_platform_and_os; my $firefox_user_agent = sprintf "Mozilla/%s (%s; %s; rv:%s) Gecko/%s Firefox/%s", $mozillaversion, $platform, $os_or_cpu, $browser_revision, $creation_time, $browser_version; return $accept_language, $firefox_user_agent; } sub log_to_file($) { my $message = shift; our $logfile; our $no_logging; my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime time; $year += 1900; $mon += 1; my $logtime = sprintf "%i/%.2i/%.2i %.2i:%.2i", $year, $mon, $mday, $hour, $min; return if $no_logging; open(my $log_fd, ">>", $logfile) || die "Writing " . $logfile . " failed"; printf $log_fd UAGEN_VERSION . " ($logtime) $message\n"; close($log_fd); } sub log_error($) { my $message = shift; $message = "Error: $message"; log_to_file($message); print "$message\n"; exit(1); } sub write_action_file() { our $action_file; our $user_agent; our $accept_language; our $no_hide_accept_language; our $action_injection; my $action_file_content = ''; if ($action_injection){ open(my $actionfile_fd, "<", $action_file) or log_error "Reading action file $action_file failed!"; while (<$actionfile_fd>) { s@(hide-accept-language\{).*?(\})@$1$accept_language$2@; s@(hide-user-agent\{).*?(\})@$1$user_agent$2@; $action_file_content .= $_; } close($actionfile_fd); } else { $action_file_content = "{"; $action_file_content .= sprintf "+hide-accept-language{%s} \\\n", $accept_language unless $no_hide_accept_language; $action_file_content .= sprintf " +hide-user-agent{%s} \\\n}\n/\n", $user_agent; } open(my $actionfile_fd, ">", $action_file) or log_error "Writing action file $action_file failed!"; print $actionfile_fd $action_file_content; close($actionfile_fd); return 0; } sub write_prefs_file() { our $mozilla_prefs_file; our $user_agent; our $accept_language; our $clean_prefs; my $prefs_file_content = ''; my $prefsfile_fd; if (open($prefsfile_fd, "<", $mozilla_prefs_file)) { while (<$prefsfile_fd>) { s@user_pref\(\"general.useragent.override\",.*\);\n?@@; s@user_pref\(\"intl.accept_languages\",.*\);\n?@@; $prefs_file_content .= $_; } close($prefsfile_fd); } else { log_error "Reading prefs file $mozilla_prefs_file failed. Creating a new file!"; } $prefs_file_content .= sprintf("user_pref(\"general.useragent.override\", \"%s\");\n", $user_agent) . sprintf("user_pref(\"intl.accept_languages\", \"%s\");\n", $accept_language) unless $clean_prefs; open($prefsfile_fd, ">", $mozilla_prefs_file) or log_error "Writing prefs file $mozilla_prefs_file failed!"; print $prefsfile_fd $prefs_file_content; close($prefsfile_fd); } sub VersionMessage() { printf UAGEN_VERSION . "\n" . 'Copyright (C) 2006-2011 Fabian Keil ' . "\nhttp://www.fabiankeil.de/sourcecode/uagen/\n"; } sub help() { our $logfile; our $action_file; our $browser_version; our $browser_revision; our $browser_release_date; our $sleeping_time; our $loop; our $mozilla_prefs_file; my $comma_separated_languages; $loop = $loop ? ' ' . $loop : ''; $mozilla_prefs_file = $mozilla_prefs_file ? ' ' . $mozilla_prefs_file : ''; foreach (LANGUAGES){ $comma_separated_languages .= $_ . ","; } chop $comma_separated_languages; VersionMessage; print << " EOF" Options and their default values if there are any: [--action-file $action_file] [--action-injection] [--browser-release-date $browser_release_date] [--browser-revision $browser_revision] [--browser-version $browser_version] [--clean-prefs-file] [--help] [--language-overwrite $comma_separated_languages] [--logfile $logfile] [--loop$loop] [--no-action-file] [--no-hide-accept-language] [--no-logfile] [--prefs-file$mozilla_prefs_file] [--randomize-release-date] [--quiet] [--silent] [--sleeping-time $sleeping_time] [--version] see "perldoc $0" for more information EOF ; exit(0); } sub main() { my $error_message; my $no_action_file = NO_ACTION_FILE; our $silent = SILENT; our $no_logging = NO_LOGGING; our $logfile = UAGEN_LOGFILE; our $action_file = ACTION_FILE; our $randomize_release_date = RANDOMIZE_RELEASE_DATE; our $browser_version = BROWSER_VERSION; our $browser_revision = BROWSER_REVISION; our $browser_release_date = BROWSER_RELEASE_DATE; our $sleeping_time = SLEEPING_TIME; our $loop = LOOP; our $no_hide_accept_language = 0; our $action_injection = 0; our @languages; our ( $accept_language, $user_agent ); our $mozilla_prefs_file = MOZILLA_PREFS_FILE; our $clean_prefs = 0; GetOptions('logfile=s' => \$logfile, 'action-file=s' => \$action_file, 'language-overwrite=s@' => \@languages, 'silent|quiet' => \$silent, 'no-hide-accept-language' => \$no_hide_accept_language, 'no-logfile' => \$no_logging, 'no-action-file' => \$no_action_file, 'randomize-release-date' => \$randomize_release_date, 'browser-version=s' => \$browser_version, 'browser-revision=s' => \$browser_revision, 'browser-release-date=s' => \$browser_release_date, 'action-injection' => \$action_injection, 'loop' => \$loop, 'sleeping-time' => \$sleeping_time, 'prefs-file=s' => \$mozilla_prefs_file, 'clean-prefs-file' => \$clean_prefs, 'help' => \&help, 'version' => sub {VersionMessage() && exit(0)} ) or exit(0); if (@languages) { @languages = split(/,/,join(',',@languages)); } else { @languages = LANGUAGES; } srand( time ^ ( $$ + ( $$ << 15 ) ) ); do { $error_message=''; ( $accept_language, $user_agent ) = generate_firefox_user_agent(); print "$user_agent\n" unless $silent; write_action_file() unless $no_action_file; write_prefs_file() if $mozilla_prefs_file; log_to_file "Generated User-Agent: $user_agent"; } while ($loop && sleep($sleeping_time * 60)); } main(); =head1 NAME B - A Firefox User-Agent generator for Privoxy and Mozilla browsers =head1 SYNOPSIS B [B<--action-file> I] [B<--action-injection>] [B<--browser-release-date> I] [B<--browser-revision> I] [B<--browser-version> I] [B<--clean-prefs-file>] [B<--help>] [B<--language-overwrite> I] [B<--logfile> I] [B<--loop>] [B<--no-action-file>] [B<--no-logfile>] [B<--prefs-file> I] [B<--randomize-release-date>] [B<--quiet>] [B<--sleeping-time> I] [B<--silent>] [B<--version>] =head1 DESCRIPTION B generates a fake Firefox User-Agent and writes it into a Privoxy action file as parameter for Privoxy's B action. Operating system, architecture, platform, language and, optionally, the build date are randomized. The generated language is also used as parameter for the B action which is understood by Privoxy since version 3.0.5 beta. Additionally the User-Agent can be written into prefs.js files which are used by many Mozilla browsers. =head1 OPTIONS B<--action-file> I Privoxy action file to write the generated actions into. Default is /etc/privoxy/user-agent.action. B<--action-injection> Don't generate a new action file from scratch, but read an old one and just replace the action values. Useful to keep custom URL patterns. For this to work, the action file has to be already present. B neither checks the syntax nor cares if all actions are present. Garbage in, garbage out. B<--browser-release-date> I Date to use. The format is YYYYMMDD. Some sanity checks are done, but you shouldn't rely on them. B<--browser-revision> I Use a custom revision. B will use it without any sanity checks. B<--browser-version> I Use a custom browser version. B will use it without any sanity checks. B<--clean-prefs-file> The I is read and the variables B and B are removed. Only effective if I is set, and only useful if you want to use the browser's defaults again. B<--help> List command line options and exit. B<--language-overwrite> I Comma separated list of language codes to overwrite the default values. B chooses one of them for the generated User-Agent, by default the chosen language in lower cases is also used as B parameter. B<--logfile> I Logfile to save error messages and the generated User-Agents. Default is /var/log/uagen.log. B<--loop> Don't exit after the generation of the action file. Sleep for a while and generate a new one instead. Useful if you don't have cron(8). B<--no-logfile> Don't log anything. B<--no-action-file> Don't write the action file. B<--no-hide-accept-language> Stay compatible with Privoxy 3.0.3 and don't generate the B action line. You should really update your Privoxy version instead. B<--prefs-file> I Use the generated User-Agent to set the B variable in the Mozilla preference file I, The B variable will be set as well. Firefox's preference file is usually located in ~/.mozilla/firefox/*.default/prefs.js. Note that Firefox doesn't reread the file once it is running. B<--randomize-release-date> Randomly pick a date between the configured release date and the actual date. Note that Firefox versions after 4.0 no longer provide the build date in the User-Agent header, so if you randomize the date anyway, it will be obvious that the generated User-Agent is fake. B<--quiet> Don't print the generated User-Agent to the console. B<--sleeping-time> I Time to sleep. Only effective if used with B<--loop>. B<--silent> Don't print the generated User-Agent to the console. B<--version> Print version and exit. The second dash is optional, options can be shortened, as long as there are no ambiguities. =head1 PRIVOXY CONFIGURATION In Privoxy's configuration file the line: actionsfile user-agent.action should be added after: actionfile default.action and before: actionfile user.action This way the user can still use custom User-Agents in I. I has to be the name of the generated action file. If you are using Privoxy 3.0.6 or earlier, don't add the ".action" extension. =head1 EXAMPLES Without any options, B creates an action file like: {+hide-accept-language{en-ca} \ +hide-user-agent{Mozilla/5.0 (X11; U; OpenBSD i386; en-CA; rv:1.8.0.4) Gecko/20060628 Firefox/1.5.0.4} \ } / with the --no-accept-language option the generated file could look like this one: {+hide-user-agent{Mozilla/5.0 (X11; U; FreeBSD i386; de-DE; rv:1.8.0.4) Gecko/20060720 Firefox/1.5.0.4} \ } / =head1 CAVEATS If the browser opens an encrypted connection, Privoxy can't inspect the content and the browser's headers reach the server unmodified. It is the user's job to use Privoxy's limit-connect action to make sure there are no encrypted connections to untrusted sites. Mozilla users can alter the browser's User-Agent with the B<--prefs-file> option. But note that the preference file is only read on startup. If the browser is already running, B changes will be ignored. Hiding the User-Agent is pointless if the browser accepts all cookies or even is configured for remote maintenance through Flash, JavaScript, Java or similar security problems. =head1 BUGS Some parameters can't be specified at the command line. =head1 SEE ALSO privoxy(1) =head1 AUTHOR Fabian Keil http://www.fabiankeil.de/sourcecode/uagen/ http://www.fabiankeil.de/blog-surrogat/2006/01/26/firefox-user-agent-generator.html (German) =cut privoxy-3.0.21-stable/./tools/privoxy-log-parser.pl000750 001751 001751 00000276442 12075552630 021276 0ustar00fkfk000000 000000 #!/usr/bin/perl ################################################################################ # privoxy-log-parser # # A parser for Privoxy log messages. For incomplete documentation run # perldoc privoxy-log-parser(.pl), for fancy screenshots see: # # http://www.fabiankeil.de/sourcecode/privoxy-log-parser/ # # $Id: privoxy-log-parser.pl,v 1.159 2013/01/16 16:30:16 fabiankeil Exp $ # # TODO: # - LOG_LEVEL_CGI, LOG_LEVEL_ERROR, LOG_LEVEL_WRITE content highlighting # - create fancy statistics # - grep through Privoxy sources to find unsupported log messages # - hunt down substitutions that match content from variables which # can contain stuff like ()?'[] # - replace $h{'foo'} with h('foo') where possible # - hunt down XXX comments instead of just creating them # - add example log lines for every regex and mark them up for # regression testing # - Handle incomplete input without Perl warning about undefined variables. # - Use generic highlighting function that takes a regex and the # hash key as input. # - Add --compress and --decompress options. # # Copyright (c) 2007-2013 Fabian Keil # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ################################################################################ use strict; use warnings; use Getopt::Long; use constant { PRIVOXY_LOG_PARSER_VERSION => '0.8', # Feel free to mess with these ... DEFAULT_BACKGROUND => 'black', # Choose registered colour (like 'black') DEFAULT_TEXT_COLOUR => 'white', # Choose registered colour (like 'black') HEADER_DEFAULT_COLOUR => 'yellow', REGISTER_HEADERS_WITH_THE_SAME_COLOUR => 1, CLI_OPTION_DEFAULT_TO_HTML_OUTPUT => 0, CLI_OPTION_TITLE => 'Privoxy-Log-Parser in da house', CLI_OPTION_NO_EMBEDDED_CSS => 0, CLI_OPTION_NO_MSECS => 0, CLI_OPTION_NO_SYNTAX_HIGHLIGHTING => 0, CLI_OPTION_SHORTEN_THREAD_IDS => 0, CLI_OPTION_SHOW_INEFFECTIVE_FILTERS => 0, CLI_OPTION_STATISTICS => 0, CLI_OPTION_STRICT_CHECKS => 0, CLI_OPTION_UNBREAK_LINES_ONLY => 0, CLI_OPTION_URL_STATISTICS_THRESHOLD => 0, CLI_OPTION_HOST_STATISTICS_THRESHOLD => 0, CLI_OPTION_SHOW_COMPLETE_REQUEST_DISTRIBUTION => 0, SUPPRESS_SUCCEEDED_FILTER_ADDITIONS => 1, SHOW_SCAN_INTRO => 0, SHOW_FILTER_READIN_IN => 0, SUPPRESS_EMPTY_LINES => 1, SUPPRESS_SUCCESSFUL_CONNECTIONS => 1, SUPPRESS_GIF_NOT_CHANGED => 1, SUPPRESS_NEED_TO_DE_CHUNK_FIRST => 1, DEBUG_HEADER_REGISTERING => 0, DEBUG_HEADER_HIGHLIGHTING => 0, DEBUG_TICKS => 0, DEBUG_PAINT_IT => 0, DEBUG_SUPPRESS_LOG_MESSAGES => 0, PUNISH_MISSING_LOG_KNOWLEDGE_WITH_DEATH => 0, PUNISH_MISSING_HIGHLIGHT_KNOWLEDGE_WITH_DEATH => 1, LOG_UNPARSED_LINES_TO_EXTRA_FILE => 0, ERROR_LOG_FILE => '/var/log/privoxy-log-parser', # You better leave these alone unless you know what you're doing. COLOUR_RESET => "\033[0;0m", ESCAPE => "\033[", }; # For performance reasons, these are global. my $t; my %req; # request data from previous lines my %h; my %thread_colours; my @all_colours; my @time_colours; my $thread_colour_index = 0; my $header_colour_index = 0; my $time_colour_index = 0; my %header_colours; my $no_special_header_highlighting; my %reason_colours; my %h_colours; my $header_highlight_regex = ''; my $html_output_mode; my $no_msecs_mode; # XXX: should probably be removed my $shorten_thread_ids; my $line_end; sub prepare_our_stuff () { # Syntax Higlight hash @all_colours = ( 'red', 'green', 'brown', 'blue', 'purple', 'cyan', 'light_gray', 'light_red', 'light_green', 'yellow', 'light_blue', 'pink', 'light_cyan', 'white' ); %h = ( # LOG_LEVEL Info => 'blue', Header => 'green', Filter => 'purple', # XXX: Used? 'Re-Filter' => 'purple', Connect => 'brown', Request => 'light_cyan', CGI => 'light_green', Redirect => 'cyan', Error => 'light_red', Crunch => 'cyan', 'Fatal error' => 'light_red', 'Gif-Deanimate' => 'blue', Force => 'red', Writing => 'light_green', Received => 'yellow', Actions => 'yellow', # ---------------------- URL => 'yellow', path => 'brown', request_ => 'brown', # host+path but no protocol 'ip-address' => 'yellow', Number => 'yellow', Standard => 'reset', Truncation => 'light_red', Status => 'brown', Timestamp => 'brown', Crunching => 'light_red', crunched => 'light_red', 'Request-Line' => 'pink', method => 'purple', destination => 'yellow', 'http-version' => 'pink', 'crunch-pattern' => 'pink', not => 'brown', file => 'brown', signal => 'yellow', version => 'green', 'program-name' => 'cyan', port => 'red', host => 'red', warning => 'light_red', debug => 'light_red', filter => 'green', tag => 'green', tagger => 'green', 'status-message' => 'light_cyan', 'status-code' => 'yellow', 'invalid-request' => 'light_red', 'hits' => 'yellow', error => 'light_red', 'rewritten-URL' => 'light_red', 'pcrs-delimiter' => 'light_red', 'ignored' => 'light_red', 'action-bits-update' => 'light_red', 'configuration-line' => 'red', 'content-type' => 'yellow', 'HOST' => HEADER_DEFAULT_COLOUR, ); %h_colours = %h; # Header colours need their own hash so the keys can be accessed properly %header_colours = ( # Prefilled with headers that should not appear with default header colours Cookie => 'light_red', 'Set-Cookie' => 'light_red', Warning => 'light_red', Default => HEADER_DEFAULT_COLOUR, ); # Crunch reasons need their own hash as well %reason_colours = ( 'Unsupported HTTP feature' => 'light_red', Blocked => 'light_red', Untrusted => 'light_red', Redirected => 'green', 'CGI Call' => 'white', 'DNS failure' => 'red', 'Forwarding failed' => 'light_red', 'Connection failure' => 'light_red', 'Out of memory (may mask other reasons)' => 'light_red', 'No reason recorded' => 'light_red', ); @time_colours = ('white', 'light_gray'); # Translate highlight strings into highlight code prepare_highlight_hash(\%header_colours); prepare_highlight_hash(\%reason_colours); prepare_highlight_hash(\%h); prepare_colour_array(\@all_colours); prepare_colour_array(\@time_colours); init_css_colours(); init_stats(); } sub paint_it ($) { ############################################################### # Takes a colour string and returns an ANSI escape sequence # (unless --no-syntax-highlighting is used). # XXX: The Rolling Stones reference has to go. ############################################################### my $colour = shift; return "" if cli_option_is_set('no-syntax-highlighting'); my %light = ( black => 0, red => 0, green => 0, brown => 0, blue => 0, purple => 0, cyan => 0, light_gray => 0, gray => 0, dark_gray => 1, light_red => 1, light_green => 1, yellow => 1, light_blue => 1, pink => 1, light_cyan => 1, white => 1, ); my %text = ( black => 30, red => 31, green => 32, brown => 33, blue => 34, purple => 35, cyan => 36, gray => 37, light_gray => 37, dark_gray => 30, light_red => 31, light_green => 32, yellow => 33, light_blue => 34, pink => 35, light_cyan => 36, white => 37, ); my $bg_code = get_background(); my $colour_code; our $default = default_colours(); if (defined($text{$colour})) { $colour_code = ESCAPE; $colour_code .= $text{$colour}; $colour_code .= ";"; $colour_code .= $light{$colour} ? "1" : "2"; $colour_code .= ";"; $colour_code .= $bg_code; $colour_code .= "m"; debug_message $colour . " is \'" . $colour_code . $colour . $default . "\'" if DEBUG_PAINT_IT; } elsif ($colour =~ /reset/) { $colour_code = default_colours(); } else { die "What's $colour supposed to mean?\n"; } return $colour_code; } sub get_semantic_html_markup ($) { ############################################################### # Takes a string and returns a span element ############################################################### my $type = shift; my $code; if ($type =~ /Standard/) { $code = ''; } else { $type = lc($type); $code = ''; } return $code; } sub cli_option_is_set ($) { our %cli_options; my $cli_option = shift; die "Unknown CLI option: $cli_option" unless defined $cli_options{$cli_option}; return $cli_options{$cli_option}; } sub get_html_title () { our %cli_options; return $cli_options{'title'}; } sub init_css_colours() { our %css_colours = ( black => "000", red => "F00", green => "0F0", brown => "C90", blue => "0F0", purple => "F06", # XXX: wrong cyan => "F09", # XXX: wrong light_gray => "999", gray => "333", dark_gray => "222", light_red => "F33", light_green => "33F", yellow => "FF0", light_blue => "30F", pink => "F0F", light_cyan => "66F", white => "FFF", ); } sub get_css_colour ($) { our %css_colours; my $colour = shift; die "What's $colour supposed to mean?\n" unless defined($css_colours{$colour}); return '#' . $css_colours{$colour}; } sub get_css_line ($) { my $class = shift; my $css_line; $css_line .= '.' . lc($class) . ' {'; # XXX: lc() shouldn't be necessary die "What's $class supposed to mean?\n" unless defined($h_colours{$class}); $css_line .= 'color:' . get_css_colour($h_colours{$class}) . ';'; $css_line .= 'background-color:' . get_css_colour(DEFAULT_BACKGROUND) . ';'; $css_line .= '}' . "\n"; return $css_line; } sub get_css_line_for_colour ($) { my $colour = shift; my $css_line; $css_line .= '.' . lc($colour) . ' {'; # XXX: lc() shouldn't be necessary $css_line .= 'color:' . get_css_colour($colour) . ';'; $css_line .= 'background-color:' . get_css_colour(DEFAULT_BACKGROUND) . ';'; $css_line .= '}' . "\n"; return $css_line; } # XXX: Wrong solution sub get_missing_css_lines () { my $css_line; $css_line .= '.' . 'default' . ' {'; $css_line .= 'color:' . HEADER_DEFAULT_COLOUR . ';'; $css_line .= 'background-color:' . get_css_colour(DEFAULT_BACKGROUND) . ';'; $css_line .= '}' . "\n"; return $css_line; } sub get_css () { our %css_colours; #XXX: Wrong solution my $css = ''; $css .= '.privoxy-log {'; $css .= 'color:' . get_css_colour(DEFAULT_TEXT_COLOUR) . ';'; $css .= 'background-color:' . get_css_colour(DEFAULT_BACKGROUND) . ';'; $css .= '}' . "\n"; foreach my $key (keys %h_colours) { next if ($h_colours{$key} =~ m/reset/); #XXX: Wrong solution. $css .= get_css_line($key); } foreach my $colour (keys %css_colours) { $css .= get_css_line_for_colour($colour); } $css .= get_missing_css_lines(); #XXX: Wrong solution return $css; } sub print_intro () { my $intro = ''; if (cli_option_is_set('html-output')) { my $title = get_html_title(); $intro .= ''; $intro .= '' . $title . ''; $intro .= '' unless cli_option_is_set('no-embedded-css'); $intro .= ''; $intro .= '

    ' . $title . '

    '; print $intro; } } sub print_outro () { my $outro = ''; if (cli_option_is_set('html-output')) { $outro = '

    '; print $outro; } } sub get_line_end () { return cli_option_is_set('html-output') ? "
    \n" : "\n"; } sub get_colour_html_markup ($) { ############################################################### # Takes a colour string a span element. XXX: WHAT? # XXX: This function shouldn't be necessary, the # markup should always be semantically correct. ############################################################### my $type = shift; my $code; if ($type =~ /Standard/) { $code = '
    '; } else { $code = ''; } return $code; } sub default_colours () { # XXX: Properly our $bg_code; return reset_colours(); } sub show_colours () { # XXX: Implement } sub reset_colours () { return ESCAPE . "0m"; } sub set_background ($){ my $colour = shift; our $bg_code; my %backgrounds = ( black => "40", red => "41", green => "42", brown => "43", blue => "44", magenta => "45", cyan => "46", white => "47", default => "49", ); if (defined($backgrounds{$colour})) { $bg_code = $backgrounds{$colour}; } else { die "Invalid background colour: " . $colour; } } sub get_background (){ return our $bg_code; } sub prepare_highlight_hash ($) { my $ref = shift; foreach my $key (keys %$ref) { $$ref{$key} = $html_output_mode ? get_semantic_html_markup($key) : paint_it($$ref{$key}); } } sub prepare_colour_array ($) { my $ref = shift; foreach my $i (0 ... @$ref - 1) { $$ref[$i] = $html_output_mode ? get_colour_html_markup($$ref[$i]) : paint_it($$ref[$i]); } } sub found_unknown_content ($) { my $unknown = shift; my $message; return unless cli_option_is_set('strict-checks'); return if ($unknown =~ /\[too long, truncated\]$/); $message = "found_unknown_content: Don't know how to highlight: "; # Break line so the log file can later be parsed as Privoxy log file again $message .= '"' . $unknown . '"' . " in:\n"; $message .= $req{$t}{'log-message'}; debug_message($message); log_parse_error($req{$t}{'log-message'}); die "Unworthy content parser" if PUNISH_MISSING_LOG_KNOWLEDGE_WITH_DEATH; } sub log_parse_error ($) { my $message = shift; if (LOG_UNPARSED_LINES_TO_EXTRA_FILE) { open(my $errorlog_fd, ">>", ERROR_LOG_FILE) || die "Writing " . ERROR_LOG_FILE . " failed"; print $errorlog_fd $message; close($errorlog_fd); } } sub debug_message (@) { my @message = @_; print $h{'debug'} . "@message" . $h{'Standard'} . "\n"; } ################################################################################ # highlighter functions that aren't loglevel-specific ################################################################################ sub h ($) { # Get highlight marker my $highlight = shift; # XXX: Stupid name; my $result = ''; my $message; if (defined($highlight)) { $result = $h{$highlight}; } else { $message = "h: Don't recognize highlighter $highlight."; debug_message($message); log_parser_error($message); die "Unworthy highlighter function" if PUNISH_MISSING_HIGHLIGHT_KNOWLEDGE_WITH_DEATH; } return $result; } sub highlight_known_headers ($) { my $content = shift; debug_message("Searching $content for things to highlight.") if DEBUG_HEADER_HIGHLIGHTING; if ($content =~ m/(?<=\s)($header_highlight_regex):/) { my $header = $1; $content =~ s@(?<=[\s|'])($header)(?=:)@$header_colours{$header}$1$h{'Standard'}@ig; debug_message("Highlighted '$header' in '$content'") if DEBUG_HEADER_HIGHLIGHTING; } return $content; } sub highlight_matched_request_line ($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; if ($result =~ m@(.*)($regex)(.*)@) { $result = $1 . highlight_request_line($2) . $3 } return $result; } sub highlight_request_line ($) { my $rl = shift; my ($method, $url, $http_version); #GET http://images.sourceforge.net/sfx/icon_warning.gif HTTP/1.1 if ($rl =~ m/Invalid request/) { $rl = h('invalid-request') . $rl . h('Standard'); } elsif ($rl =~ m/^([-\w]+) (.*) (HTTP\/\d\.\d)/) { # XXX: might not match in case of HTTP method fuzzing. # XXX: save these: ($method, $path, $http_version) = ($1, $2, $3); $rl =~ s@^(\w+)@$h{'method'}$1$h{'Standard'}@; if ($rl =~ /http:\/\//) { $rl = highlight_matched_url($rl, '[^\s]*(?=\sHTTP)'); } else { $rl = highlight_matched_pattern($rl, 'request_', '[^\s]*(?=\sHTTP)'); } $rl =~ s@(HTTP\/\d\.\d)$@$h{'http-version'}$1$h{'Standard'}@; } elsif ($rl =~ m/\.\.\. \[too long, truncated\]$/) { $rl =~ s@^(\w+)@$h{'method'}$1$h{'Standard'}@; $rl = highlight_matched_url($rl, '[^\s]*(?=\.\.\.)'); } elsif ($rl =~ m/^ $/) { $rl = h('error') . "No request line specified!" . h('Standard'); } else { debug_message ("Can't parse request line: $rl"); } return $rl; } sub highlight_response_line ($) { my $rl = shift; my ($http_version, $status_code, $status_message); #HTTP/1.1 200 OK #ICY 200 OK # TODO: Mark different status codes differently if ($rl =~ m/((?:HTTP\/\d\.\d|ICY)) (\d+) (.*)/) { ($http_version, $status_code, $status_message) = ($1, $2, $3); } else { debug_message ("Can't parse response line: $rl") and die 'Fix this'; } # Rebuild highlighted $rl= ""; $rl .= h('http-version') . $http_version . h('Standard'); $rl .= " "; $rl .= h('status-code') . $status_code . h('Standard'); $rl .= " "; $rl .= h('status-message') . $status_message . h('Standard'); return $rl; } sub highlight_matched_url ($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; #print "Got $result, regex ($regex)\n"; if ($result =~ m@(.*?)($regex)(.*)@) { $result = $1 . highlight_url($2) . $3; #print "Now the result is $result\n"; } return $result; } sub highlight_matched_host ($$) { my ($result, $regex) = @_; # XXX: result ist stupid name; if ($result =~ m@(.*?)($regex)(.*)@) { $result = $1 . $h{host} . $2 . $h{Standard} . $3; } return $result; } sub highlight_matched_pattern ($$$) { my $result = shift; # XXX: Stupid name; my $key = shift; my $regex = shift; die "Unknown key $key" unless defined $h{$key}; if ($result =~ m@(.*?)($regex)(.*)@) { $result = $1 . h($key) . $2 . h('Standard') . $3; } return $result; } sub highlight_matched_path ($$) { my $result = shift; # XXX: Stupid name; my $regex = shift; if ($result =~ m@(.*?)($regex)(.*)@) { $result = $1 . h('path') . $2 . h('Standard') . $3; } return $result; } sub highlight_url ($) { my $url = shift; if ($html_output_mode) { $url = '' . $url . ''; } else { $url = h('URL') . $url . h('Standard'); } return $url; } sub update_header_highlight_regex ($) { my $header = shift; my $headers = join ('|', keys %header_colours); $header_highlight_regex = qr/$headers/; print "Registering '$header'\n" if DEBUG_HEADER_HIGHLIGHTING; } ################################################################################ # loglevel-specific highlighter functions ################################################################################ sub handle_loglevel_header ($) { my $c = shift; if ($c =~ /^scan:/) { if ($c =~ m/^scan: ([^: ]+):/) { # Register new headers # scan: Accept: image/png,image/*;q=0.8,*/*;q=0.5 my $header = $1; if (!defined($header_colours{$header}) and $header =~ /^[\d\w-]*$/) { debug_message "Registering previously unknown header $1" if DEBUG_HEADER_REGISTERING; if (REGISTER_HEADERS_WITH_THE_SAME_COLOUR) { $header_colours{$header} = $header_colours{'Default'}; } else { $header_colours{$header} = $all_colours[$header_colour_index % @all_colours]; $header_colour_index++; } update_header_highlight_regex($header); } } elsif ($c =~ m/^(scan: )(\w+ .+ HTTP\/\d\.\d)/) { # scan: GET http://p.p/ HTTP/1.1 $c = $1 . highlight_request_line($2); } elsif ($c =~ m/^(scan: )((?:HTTP\/\d\.\d|ICY) (\d+) (.*))/) { # scan: HTTP/1.1 200 OK $req{$t}{'response_line'} = $2; $req{$t}{'status_code'} = $3; $req{$t}{'status_message'} = $4; $c = $1 . highlight_response_line($req{$t}{'response_line'}); } } elsif ($c =~ m/^Crunching (?:server|client) header: .* \(contains: ([^\)]*)\)/) { # Crunching server header: Set-Cookie: trac_form_token=d5308c34e16d15e9e301a456; (contains: Cookie:) $c =~ s@(?<=contains: )($1)@$h{'crunch-pattern'}$1$h{'Standard'}@; $c =~ s@(Crunching)@$h{$1}$1$h{'Standard'}@; } elsif ($c =~ m/^New host is: ([^\s]*)\./) { # New host is: trac.vidalia-project.net. Crunching Referer: http://www.vidalia-project.net/! $c = highlight_matched_host($c, '(?<=New host is: )[^\s]+(?=\.)'); $c = highlight_matched_url($c, '(?<=Crunching Referer: )[^\s!]+'); } elsif ($c =~ m/^Text mode enabled by force. (Take cover)!/) { # Text mode enabled by force. Take cover! $c =~ s@($1)@$h{'warning'}$1$h{'Standard'}@; } elsif ($c =~ m/^(New HTTP Request-Line: )(.*)/) { # New HTTP Request-Line: GET http://www.privoxy.org/ HTTP/1.1 $c = $1 . highlight_request_line($2); } elsif ($c =~ m/^Adjust(ed)? Content-Length to \d+/) { # Adjusted Content-Length to 2132 # Adjust Content-Length to 33533 $c =~ s@(?<=Content-Length to )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_known_headers($c); } elsif ($c =~ m/^Destination extracted from "Host:" header. New request URL:/) { # Destination extracted from "Host:" header. New request URL: http://www.cccmz.de/~ridcully/blog/ $c = highlight_matched_url($c, '(?<=New request URL: ).*'); } elsif ($c =~ m/^Couldn\'t parse:/) { # XXX: These should probable be logged with LOG_LEVEL_ERROR # Couldn't parse: If-Modified-Since: Wed, 21 Mar 2007 16:34:50 GMT (crunching!) # Couldn't parse: at, 24 Mar 2007 13:46:21 GMT in If-Modified-Since: Sat, 24 Mar 2007 13:46:21 GMT (crunching!) $c =~ s@^(Couldn\'t parse)@$h{'error'}$1$h{'Standard'}@; } elsif ($c =~ /^Tagger \'([^\']*)\' added tag \'([^\']*)\'/ or $c =~ m/^Adding tag \'([^\']*)\' created by header tagger \'([^\']*)\'/) { # Adding tag 'GET request' created by header tagger 'method-man' (XXX: no longer used) # Tagger 'revalidation' added tag 'REVALIDATION-REQUEST'. No action bit update necessary. # Tagger 'revalidation' added tag 'REVALIDATION-REQUEST'. Action bits updated accordingly. # XXX: Save tag and tagger $c =~ s@(?<=^Tagger \')([^\']*)@$h{'tagger'}$1$h{'Standard'}@; $c =~ s@(?<=added tag \')([^\']*)@$h{'tag'}$1$h{'Standard'}@; $c =~ s@(?<=Action bits )(updated)@$h{'action-bits-update'}$1$h{'Standard'}@; $no_special_header_highlighting = 1; } elsif ($c =~ /^Tagger \'([^\']*)\' didn['']t add tag \'([^\']*)\'/) { # Tagger 'revalidation' didn't add tag 'REVALIDATION-REQUEST'. Tag already present # XXX: Save tag and tagger $c =~ s@(?<=^Tagger \')([^\']*)@$h{'tag'}$1$h{'Standard'}@; $c =~ s@(?<=didn['']t add tag \')([^\']*)@$h{'tagger'}$1$h{'Standard'}@; } elsif ($c =~ m/^(?:scan:|Randomiz|addh:|Adding:|Removing:|Referer:|Modified:|Accept-Language header|[Cc]ookie)/ or $c =~ m/^(Text mode is already enabled|Denied request with NULL byte|Replaced:|add-unique:)/ or $c =~ m/^(Crunched (incoming|outgoing) cookie|Suppressed offer|Accepted the client)/ or $c =~ m/^(addh-unique|Referer forged to)/ or $c =~ m/^Downgraded answer to HTTP\/1.0/ or $c =~ m/^Parameter: \+hide-referrer\{[^\}]*\} is a bad idea, but I don\'t care./ or $c =~ m/^Referer (?:overwritten|replaced) with: Referer: / #XXX: should this be highlighted? or $c =~ m/^Referer crunched!/ or $c =~ m/^crunched x-forwarded-for!/ or $c =~ m/^crunched From!/ or $c =~ m/^ modified$/ or $c =~ m/^Content filtering is enabled. Crunching:/ or $c =~ m/^force-text-mode overruled the client/ or $c =~ m/^Server time in the future\./ or $c =~ m/^content-disposition header crunched and replaced with:/i or $c =~ m/^Reducing white space in / or $c =~ m/^Ignoring single quote in / or $c =~ m/^Converting tab to space in / or $c =~ m/A HTTP\/1\.1 response without/ or $c =~ m/Disabled filter mode on behalf of the client/ or $c =~ m/Keeping the (?:server|client) header / or $c =~ m/Content modified with no Content-Length header set/ or $c =~ m/^Appended client IP address to/ or $c =~ m/^Removing 'Connection: close' to imply keep-alive./ or $c =~ m/^keep-alive support is disabled/ or $c =~ m/^Continue hack in da house/ or $c =~ m/^Merged multiple header lines to:/ or $c =~ m/^Added header: / or $c =~ m/^Enlisting (?:sorted|left-over) header/ or $c =~ m/^Multiple Content-Type headers detected. Removing and ignoring: Content-Type:/ ) { # XXX: Some of these may need highlighting # Modified: User-Agent: Mozilla/5.0 (X11; U; SunOS i86pc; pl-PL; rv:1.8.1.1) Gecko/20070214 Firefox/2.0.0.1 # Accept-Language header crunched and replaced with: Accept-Language: pl-pl # cookie 'Set-Cookie: eZSessionCookie=07bfec287c197440d299f81580593c3d; \ # expires=Thursday, 12-Apr-07 15:16:18 GMT; path=/' send by \ # http://wirres.net/article/articleview/4265/1/6/ appears to be using time format 1 (XXX: gone with the wind) # Cookie rewritten to a temporary one: Set-Cookie: NSC_gffe-iuuq-mc-wtfswfs=8efb33a53660;path=/ # Text mode is already enabled # Denied request with NULL byte(s) turned into line break(s) # Replaced: 'Connection: Yo, home to Bel Air' with 'Connection: close' # addh-unique: Host: people.freebsd.org # Suppressed offer to compress content # Crunched incoming cookie -- yum! # Accepted the client's request to fetch without filtering. # Crunched outgoing cookie: Cookie: PREF=ID=6cf0abd347b30262:TM=1173357617:LM=1173357617:S=jZypyyJ7LPiwFi1_ # addh-unique: Host: subkeys.pgp.net:11371 # Referer forged to: Referer: http://10.0.0.1/ # Downgraded answer to HTTP/1.0 # Parameter: +hide-referrer{pille-palle} is a bad idea, but I don't care. # Referer overwritten with: Referer: pille-palle # Referer replaced with: Referer: pille-palle # crunched x-forwarded-for! # crunched From! # modified # XXX: pretty stupid log message # Content filtering is enabled. Crunching: 'Range: 1234-5678' to prevent range-mismatch problems # force-text-mode overruled the client's request to fetch without filtering! # Server time in the future. # content-disposition header crunched and replaced with: content-disposition: filename=baz # Content-Disposition header crunched and replaced with: content-disposition: filename=baz # Reducing white space in 'X-LWS-Test: "This is quoted" this is not "this is " but " this again is not' # Ignoring single quote in 'X-LWS-Test: "This is quoted" this is not "this is " but " this again is not' # Converting tab to space in 'X-LWS-Test: "This is quoted" this is not "this is " but "\ # this again is not' # A HTTP/1.1 response without Connection header implies keep-alive. # Disabled filter mode on behalf of the client. # Keeping the server header 'Connection: keep-alive' around. # Keeping the client header 'Connection: close' around. The connection will not be kept alive. # Keeping the client header 'Connection: keep-alive' around. The connection will be kept alive if possible. # Content modified with no Content-Length header set. Creating a fake one for adjustment later on. # Appended client IP address to X-Forwarded-For: 10.0.0.2, 10.0.0.1 # Removing 'Connection: close' to imply keep-alive. # keep-alive support is disabled. Crunching: Keep-Alive: 300. # Continue hack in da house. # Merged multiple header lines to: 'X-FORWARDED-PROTO: http X-HOST: 127.0.0.1' # Added header: Content-Encoding: deflate # Enlisting sorted header User-Agent: Mozilla/5.0 (X11; SunOS i86pc; rv:10.0.3) Gecko/20100101 Firefox/10.0.3 # Enlisting left-over header Connection: close # Multiple Content-Type headers detected. Removing and ignoring: Content-Type: text/html } elsif ($c =~ m/^scanning headers for:/) { return '' unless SHOW_SCAN_INTRO; } elsif ($c =~ m/^[Cc]runch(ing|ed)|crumble crunched:/) { # crunched User-Agent! # Crunching: Content-Encoding: gzip $c =~ s@(Crunching|crunched)@$h{$1}$1$h{'Standard'}@; } elsif ($c =~ m/^Offending request data with NULL bytes turned into \'°\' characters:/) { # Offending request data with NULL bytes turned into '°' characters: °°n°°(°°° $c = h('warning') . $c . h('Standard'); } elsif ($c =~ m/^(Transforming \")(.*?)(\" to \")(.*?)(\")/) { # Transforming "Proxy-Authenticate: Basic realm="Correos Proxy Server"" to\ # "Proxy-Authenticate: Basic realm="Correos Proxy Server"" $c =~ s@(?<=^Transforming \")(.*)(?=\" to)@$h{'Header'}$1$h{'Standard'}@; $c =~ s@(?<=to \")(.*)(?=\")@$h{'Header'}$1$h{'Standard'}@; } elsif ($c =~ m/^Removing empty header/) { # Removing empty header # Ignore for now } elsif ($c =~ m/^Content-Type: .* not replaced/) { # Content-Type: application/octet-stream not replaced. It doesn't look like text.\ # Enable force-text-mode if you know what you're doing. # XXX: Could highlight more here. $c =~ s@(?<=^Content-Type: )(.*)(?= not replaced)@$h{'content-type'}$1$h{'Standard'}@; } elsif ($c =~ m/^(Server|Client) keep-alive timeout is/) { # Server keep-alive timeout is 5. Sticking with 10. # Client keep-alive timeout is 20. Sticking with 10. $c =~ s@(?<=timeout is )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Sticking with )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Reducing keep-alive timeout/) { # Reducing keep-alive timeout from 60 to 10. $c =~ s@(?<= from )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<= to )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Killed all-caps Host header line: HOST:/) { # Killed all-caps Host header line: HOST: bestproxydb.com $c = highlight_matched_host($c, '(?<=HOST: )[^\s]+'); $c = highlight_matched_pattern($c, 'HOST', 'HOST'); } else { found_unknown_content($c); } # Highlight headers unless ($c =~ m/^Transforming/) { $c = highlight_known_headers($c) unless $no_special_header_highlighting; } return $c; } sub handle_loglevel_re_filter ($) { my $content = shift; my $c = $content; my $key; if ($c =~ m/^(?:re_)?filtering ([^\s]+) \(size (\d+)\) with (?:filter )?\'?([^\s]+?)\'? produced (\d+) hits \(new size (\d+)\)/) { # XXX: only the second version gets highlighted properly. # re_filtering www.lfk.de/favicon.ico (size 209) with filter untrackable-hulk produced 0 hits (new size 209). # filtering aci.blogg.de/ (size 37988) with 'blogg.de' produced 3 hits (new size 38057) $req{$t}{'content_source'} = $1; $req{$t}{'content_size'} = $2; $req{$t}{'content_filter'} = $3; $req{$t}{'content_hits'} = $4; $req{$t}{'new_content_size'} = $5; $req{$t}{'content_size_change'} = $req{$t}{'new_content_size'} - $req{$t}{'content_size'}; #return '' if ($req{$t}{'content_hits'} == 0 && !cli_option_is_set('show-ineffective-filters')); if ($req{$t}{'content_hits'} == 0 and not (cli_option_is_set('show-ineffective-filters') or ($req{$t}{'content_filter'} =~ m/^privoxy-filter-test$/))) { return ''; } $c =~ s@(?<=\(size )(\d+)\)(?= with)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=\(new size )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=produced )(\d+)(?= hits)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@([^\s]+?)(\'? produced)@$h{'filter'}$1$h{'Standard'}$2@; $c = highlight_matched_host($c, '(?<=filtering )[^\s]+'); $c =~ s@\.$@ @; $c .= "(" . $h{'Number'}; $c .= "+" if ($req{$t}{'content_size_change'} >= 0); $c .= $req{$t}{'content_size_change'} . $h{'Standard'} . ")"; $content = $c; } elsif ($c =~ /\.{3}$/ and $c =~ m/^(?:re_)?filtering \'?(.*?)\'? \(size (\d*)\) with (?:filter )?\'?([^\s]*?)\'? ?\.{3}$/) { # Used by Privoxy 3.0.5 and 3.0.6: # XXX: Fill in ... # Used by Privoxy 3.0.7: # filtering 'Connection: close' (size 17) with 'generic-content-ads' ... $req{$t}{'filtered_header'} = $1; $req{$t}{'old_header_size'} = $2; $req{$t}{'header_filter_name'} = $3; unless (cli_option_is_set('show-ineffective-filters') or $req{$t}{'header_filter_name'} =~ m/^privoxy-filter-test$/) { return ''; } $content =~ s@(?<=\(size )(\d+)@$h{'Number'}$1$h{'Standard'}@; $content =~ s@($req{$t}{'header_filter_name'})@$h{'filter'}$1$h{'Standard'}@; } elsif ($c =~ m/^ ?\.\.\. ?produced (\d*) hits \(new size (\d*)\)\./) { # ...produced 0 hits (new size 23). #... produced 1 hits (new size 54). $req{$t}{'header_filter_hits'} = $1; $req{$t}{'new_header_size'} = $2; unless (cli_option_is_set('show-ineffective-filters') or (defined($req{$t}{'header_filter_name'}) and $req{$t}{'header_filter_name'} =~ m/^privoxy-filter-test$/)) { if ($req{$t}{'header_filter_hits'} == 0 and not (defined($req{$t}{'header_filter_name'}) and $req{$t}{'header_filter_name'} =~ m/^privoxy-filter-test$/)) { return ''; } # Reformat including information from the intro $c = "'" . h('filter') . $req{$t}{'header_filter_name'} . h('Standard') . "'"; $c .= " hit "; # XXX: Hide behind constant, it may be interesting if LOG_LEVEL_HEADER isn't enabled as well. # $c .= $req{$t}{'filtered_header'} . " "; $c .= h('Number') . $req{$t}{'header_filter_hits'}. h('Standard'); $c .= ($req{$t}{'header_filter_hits'} == 1) ? " time, " : " times, "; if ($req{$t}{'old_header_size'} != $req{$t}{'new_header_size'}) { $c .= "changing size from "; $c .= h('Number') . $req{$t}{'old_header_size'} . h('Standard'); $c .= " to "; $c .= h('Number') . $req{$t}{'new_header_size'} . h('Standard'); $c .= "."; } else { $c .= "keeping the size at " . $req{$t}{'old_header_size'}; } # Highlight from last line (XXX: What?) # $c =~ s@(?<=produced )(\d+)@$h{'Number'}$1$h{'Standard'}@; # $c =~ s@($req{$t}{'header_filter_name'})@$h{'filter'}$1$h{'Standard'}@; } else { # XXX: Untested $c =~ s@(?<=produced )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=new size )(\d+)@$h{'Number'}$1$h{'Standard'}@; } $content = $c; } elsif ($c =~ m/^(Tagger|Filter) ([^\s]*) has empty joblist. Nothing to do./) { # Filter privoxy-filter-test has empty joblist. Nothing to do. # Tagger variable-test has empty joblist. Nothing to do. $content =~ s@(?<=$1 )([^\s]*)@$h{'filter'}$1$h{'Standard'}@; } elsif ($c =~ m/^De-chunking successful. Shrunk from (\d+) to (\d+)/) { $req{$t}{'chunked-size'} = $1; $req{$t}{'dechunked-size'} = $2; $req{$t}{'dechunk-change'} = $req{$t}{'dechunked-size'} - $req{$t}{'chunked-size'}; $content .= " (" . h('Number') . $req{$t}{'dechunk-change'} . h('Standard') . ")"; $content =~ s@(?<=from )($req{$t}{'chunked-size'})@$h{'Number'}$1$h{'Standard'}@; $content =~ s@(?<=to )($req{$t}{'dechunked-size'})@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Decompression successful. Old size: (\d+), new size: (\d+)./) { # Decompression successful. Old size: 670, new size: 1166. $req{$t}{'size-compressed'} = $1; $req{$t}{'size-decompressed'} = $2; $req{$t}{'decompression-gain'} = $req{$t}{'size-decompressed'} - $req{$t}{'size-compressed'}; $content =~ s@(?<=Old size: )($req{$t}{'size-compressed'})@$h{'Number'}$1$h{'Standard'}@; $content =~ s@(?<=new size: )($req{$t}{'size-decompressed'})@$h{'Number'}$1$h{'Standard'}@; # XXX: Create sub get_percentage() if ($req{$t}{'size-decompressed'}) { $req{$t}{'decompression-gain-percent'} = $req{$t}{'decompression-gain'} / $req{$t}{'size-decompressed'} * 100; $content .= " (saved: "; #$content .= h('Number') . $req{$t}{'decompression-gain'} . h('Standard'); #$content .= "/"; $content .= h('Number') . sprintf("%.2f%%", $req{$t}{'decompression-gain-percent'}) . h('Standard'); $content .= ")"; } } elsif ($c =~ m/^(Need to de-chunk first)/) { # Need to de-chunk first return '' if SUPPRESS_NEED_TO_DE_CHUNK_FIRST; } elsif ($c =~ m/^(Adding (?:dynamic )?re_filter job)/) { return '' if (SUPPRESS_SUCCEEDED_FILTER_ADDITIONS && m/succeeded/); # Adding re_filter job ... # Adding dynamic re_filter job s@^(?:\w*)\s+.*\s+HTTP/\d\.\d\s*@IP-ADDRESS: $origin@D\ # to filter client-ip-address succeeded. } elsif ($c =~ m/^Compressed content from /) { # Compressed content from 29258 to 8630 bytes. Compression level: 3 $content =~ s@(?<=from )(\d+)@$h{'Number'}$1$h{'Standard'}@; $content =~ s@(?<=to )(\d+)@$h{'Number'}$1$h{'Standard'}@; $content =~ s@(?<=level: )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Reading in filter/) { return '' unless SHOW_FILTER_READIN_IN; } else { found_unknown_content($content); } return $content; } sub handle_loglevel_redirect ($) { my $c = shift; if ($c =~ m/^Decoding "([^""]*)"/) { $req{$t}{'original-destination'} = $1; $c = highlight_matched_path($c, '(?<=Decoding ")[^"]*'); $c =~ s@\"@@g; } elsif ($c =~ m/^Checking/) { # Checking /_ylt=A0geu.Z76BRGR9k/**http://search.yahoo.com/search?p=view+odb+presentation+on+freebsd\ # &ei=UTF-8&xargs=0&pstart=1&fr=moz2&b=11 for redirects. # TODO: Change colour if really url-decoded $req{$t}{'decoded-original-destination'} = $1; $c = highlight_matched_path($c, '(?<=Checking ")[^"]*'); $c =~ s@\"@@g; } elsif ($c =~ m/^pcrs command "([^""]*)" changed /) { # pcrs command "s@&from=rss@@" changed \ # "http://it.slashdot.org/article.pl?sid=07/03/02/1657247&from=rss"\ # to "http://it.slashdot.org/article.pl?sid=07/03/02/1657247" (1 hit). $c =~ s@(?<=pcrs command )"([^""]*)"@$h{'filter'}$1$h{'Standard'}@; $c = highlight_matched_url($c, '(?<=changed ")[^""]*'); $c =~ s@(?<=changed )"([^""]*)"@$1@; # Remove quotes $c = highlight_matched_url($c, '(?<=to ")[^""]*'); $c =~ s@(?<=to )"([^""]*)"@$1@; # Remove quotes $c =~ s@(\d+)(?= hits?)@$h{'hits'}$1$h{'Standard'}@; } elsif ($c =~ m/^pcrs command "([^""]*)" didn\'t change/) { # pcrs command "s@^http://([^.]+?)/?$@http://www.bing.com/search?q=$1@" didn't \ # change "http://www.example.org/". $c =~ s@(?<=pcrs command )"([^""]*)"@$h{'filter'}$1$h{'Standard'}@; $c = highlight_matched_url($c, '(?<=change ")[^""]*'); } elsif ($c =~ m/(^New URL is: )(.*)/) { # New URL is: http://it.slashdot.org/article.pl?sid=07/03/04/1511210 # XXX: Use URL highlighter # XXX: Save? $c = $1 . h('rewritten-URL') . $2 . h('Standard'); } elsif ($c =~ m/No pcrs command recognized, assuming that/) { # No pcrs command recognized, assuming that "http://config.privoxy.org/user-manual/favicon.png"\ # is already properly formatted. # XXX: assume the same? $c = highlight_matched_url($c, '(?<=assuming that \")[^"]*'); } elsif ($c =~ m/^Percent-encoding redirect/) { # Percent-encoding redirect URL: http://www.example.org/\x02 $c = highlight_matched_url($c, '(?<=redirect URL: ).*'); } else { found_unknown_content($c); } return $c; } sub handle_loglevel_gif_deanimate ($) { my $content = shift; if ($content =~ m/Success! GIF shrunk from (\d+) bytes to (\d+)\./) { my $bytes_from = $1; my $bytes_to = $2; # Gif-Deanimate: Success! GIF shrunk from 205 bytes to 133. $content =~ s@$bytes_from@$h{'Number'}$bytes_from$h{'Standard'}@; # XXX: Do we need g in case of ($1 == $2)? $content =~ s@$bytes_to@$h{'Number'}$bytes_to$h{'Standard'}@; } elsif ($content =~ m/GIF (not) changed/) { # Gif-Deanimate: GIF not changed. return '' if SUPPRESS_GIF_NOT_CHANGED; $content =~ s@($1)@$h{'not'}$1$h{'Standard'}@; } elsif ($content =~ m/^failed! \(gif parsing\)/) { # failed! (gif parsing) # XXX: Replace this error message with something less stupid $content =~ s@(failed!)@$h{'error'}$1$h{'Standard'}@; } elsif ($content =~ m/^Need to de-chunk first/) { # Need to de-chunk first return '' if SUPPRESS_NEED_TO_DE_CHUNK_FIRST; } elsif ($content =~ m/^(?:No GIF header found|failed while parsing)/) { # No GIF header found (XXX: Did I ever commit this?) # failed while parsing 195 134747048 (XXX: never committed) # Ignore these for now } else { found_unknown_content($content); } return $content; } sub handle_loglevel_request ($) { my $content = shift; if ($content =~ m/crunch! /) { # config.privoxy.org/send-stylesheet crunch! (CGI Call) # Highlight crunch reasons foreach my $reason (keys %reason_colours) { $content =~ s@\(($reason)\)@$reason_colours{$reason}($1)$h{'Standard'}@g; } # Highlight request URL domain and ditch 'crunch!' $content = highlight_matched_pattern($content, 'request_', '[^ ]*(?= crunch!)'); $content =~ s@ crunch!@@; } elsif ($content =~ m/\[too long, truncated\]$/) { # config.privoxy.org/edit-actions-submit?f=3&v=1176116716&s=7&Submit=Submit[...]&filter... [too long, truncated] $content = highlight_matched_pattern($content, 'request_', '^.*(?=\.\.\. \[too long, truncated\]$)'); } elsif ($content =~ m/(.*)/) { # XXX: Pretty stupid # trac.vidalia-project.net/wiki/Volunteer?format=txt $content = h('request_') . $content . h('Standard'); } else { # XXX: Nop found_unknown_content($content); } return $content; } sub handle_loglevel_crunch ($) { my $content = shift; # Highlight crunch reason foreach my $reason (keys %reason_colours) { $content =~ s@($reason)@$reason_colours{$reason}$1$h{'Standard'}@g; } if ($content =~ m/\[too long, truncated\]$/) { # Blocked: config.privoxy.org/edit-actions-submit?f=3&v=1176116716&s=7&Submit=Submit\ # [...]&filter... [too long, truncated] $content = highlight_matched_pattern($content, 'request_', '^.*(?=\.\.\. \[too long, truncated\]$)'); } else { # Blocked: http://ads.example.org/ $content = highlight_matched_pattern($content, 'request_', '(?<=: ).*'); } return $content; } sub handle_loglevel_connect ($) { my $c = shift; if ($c =~ m/^via [^\s]+ to: [^\s]+/) { # Connect: via 10.0.0.1:8123 to: www.example.org.noconnect $c = highlight_matched_host($c, '(?<=via )[^\s]+'); $c = highlight_matched_host($c, '(?<=to: )[^\s]+'); } elsif ($c =~ m/^connect to: .* failed: .*/) { # connect to: www.example.org.noconnect failed: Operation not permitted $c = highlight_matched_host($c, '(?<=connect to: )[^\s]+'); $c =~ s@(?<=failed: )(.*)@$h{'error'}$1$h{'Standard'}@; } elsif ($c =~ m/^to ([^\s]*)( successful)?$/) { # Connect: to www.nzherald.co.nz successful # Connect: to archiv.radiotux.de return '' if SUPPRESS_SUCCESSFUL_CONNECTIONS; $c = highlight_matched_host($c, '(?<=to )[^\s]+'); } elsif ($c =~ m/^to ([^\s]*)$/) { # Connect: to lists.sourceforge.net:443 $c = highlight_matched_host($c, '(?<=to )[^\s]+'); } elsif ($c =~ m/^[Aa]ccepted connection from .*/ or $c =~ m/^OK/) { # Privoxy 3.0.20: # Accepted connection from 10.0.0.1 on socket 5 # Privoxy between 3.0.20 and 3.0.6: # accepted connection from 10.0.0.1( on socket 5)? # Privoxy 3.0.6 and earlier just say: # OK $c = highlight_matched_host($c, '(?<=connection from )[^ ]*'); $c = highlight_matched_pattern($c, 'Number', '(?<=socket )\d+'); } elsif ($c =~ m/^Closing client socket/) { # Closing client socket 5. Keep-alive: 0, Socket alive: 1. Data available: 0. # Privoxy 3.0.20 and later # Closing client socket 8. Keep-alive: 1. Socket alive: 0. Data available: 0. \ # Configuration file change detected: 0. Requests received: 11. $c = highlight_matched_pattern($c, 'Number', '(?<=socket )\d+'); $c = highlight_matched_pattern($c, 'Number', '(?<=Keep-alive: )\d+'); $c = highlight_matched_pattern($c, 'Number', '(?<=Socket alive: )\d+'); $c = highlight_matched_pattern($c, 'Number', '(?<=available: )\d+'); $c = highlight_matched_pattern($c, 'Number', '(?<=detected: )\d+'); $c = highlight_matched_pattern($c, 'Number', '(?<=received: )\d+'); } elsif ($c =~ m/^write header to: .* failed:/) { # write header to: 10.0.0.1 failed: Broken pipe $c = highlight_matched_host($c, '(?<=write header to: )[^\s]*'); $c =~ s@(?<=failed: )(.*)@$h{'Error'}$1$h{'Standard'}@; } elsif ($c =~ m/^write header to client failed:/) { # write header to client failed: Broken pipe # XXX: Stil in use? $c =~ s@(?<=failed: )(.*)@$h{'Error'}$1$h{'Standard'}@; } elsif ($c =~ m/^socks4_connect:/) { # socks4_connect: SOCKS request rejected or failed. $c =~ s@(?<=socks4_connect: )(.*)@$h{'Error'}$1$h{'Standard'}@; } elsif ($c =~ m/^Listening for new connections/ or $c =~ m/^accept connection/) { # XXX: Highlight? # Privoxy versions above 3.0.6 say: # Listening for new connections ... # earlier versions say: # accept connection ... return ''; } elsif ($c =~ m/^accept failed:/) { $c =~ s@(?<=accept failed: )(.*)@$h{'Error'}$1$h{'Standard'}@; } elsif ($c =~ m/^Overriding forwarding settings/) { # Overriding forwarding settings based on 'forward 10.0.0.1:8123' $c =~ s@(?<=based on \')(.*)(?=\')@$h{'configuration-line'}$1$h{'Standard'}@; } elsif ($c =~ m/^Denying suspicious CONNECT request from/) { # Denying suspicious CONNECT request from 10.0.0.1 $c = highlight_matched_host($c, '(?<=from )[^\s]+'); # XXX: not an URL } elsif ($c =~ m/^socks5_connect:/) { $c =~ s@(?<=socks5_connect: )(.*)@$h{'error'}$1$h{'Standard'}@; } elsif ($c =~ m/^Created new connection to/) { # Created new connection to www.privoxy.org:80 on socket 11. $c = highlight_matched_host($c, '(?<=connection to )[^\s]+'); $c =~ s@(?<=on socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Found reusable socket/) { # Found reusable socket 9 for www.privoxy.org:80 in slot 0. # 3.0.15 and later: # Found reusable socket 8 for www.privoxy.org:80 in slot 2.\ # Timestamp made 0 seconds ago. Timeout: 1. Latency: 0. $c =~ s@(?<=Found reusable socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=for )[^\s]+'); $c =~ s@(?<=in slot )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=made )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Timeout: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Latency: )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Marking open socket/) { # Marking open socket 9 for www.privoxy.org:80 in slot 0 as unused. $c =~ s@(?<=Marking open socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=for )[^\s]+'); $c =~ s@(?<=in slot )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^No reusable/) { # No reusable socket for addons.mozilla.org:443 found. Opening a new one. $c = highlight_matched_host($c, '(?<=for )[^\s]+'); } elsif ($c =~ m/^(Remembering|Forgetting) socket/) { # Remembering socket 13 for www.privoxy.org:80 in slot 0. # Forgetting socket 38 for www.privoxy.org:80 in slot 5. $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=for )[^\s]+'); $c =~ s@(?<=in slot )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Socket/) { # Socket 16 already forgotten or never remembered. $c =~ s@(?<=Socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^The connection to/) { # The connection to www.privoxy.org:80 in slot 6 timed out. Closing socket 19. Timeout is: 61. # 3.0.15 and later: # The connection to 1.bp.blogspot.com:80 in slot 0 timed out. Closing socket 5.\ # Timeout is: 1. Assumed latency: 4. # The connection to 10.0.0.1:80 in slot 0 is no longer usable. Closing socket 4. $c = highlight_matched_host($c, '(?<=connection to )[^\s]+'); $c =~ s@(?<=in slot )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Closing socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Timeout is: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Assumed latency: )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Stopped waiting for the request line/ or $c =~ m/^No request line on socket \d received in time/ or $c =~ m/^The client side of the connection on socket \d/) { # Stopped waiting for the request line. Timeout: 121. # Privoxy 3.0.19 and later: # No request line on socket 5 received in time. Timeout: 1. # The client side of the connection on socket 5 got closed \ # without sending a complete request line. $c =~ s@(?<=Timeout: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Waiting for \d/) { # Waiting for 1 connections to timeout. $c =~ s@(?<=^Waiting for )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Initialized/) { # Initialized 20 socket slots. $c =~ s@(?<=Initialized )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Done reading from server/) { # Done reading from server. Expected content length: 24892. \ # Actual content length: 24892. Most recently received: 4412. # 3.0.15 and later: # Done reading from server. Expected content length: 24892. \ # Actual content length: 24892. Bytes most recently read: 4412. # Done reading from server. Content length: 6018 as expected. \ # Bytes most recently read: 294. $c =~ s@(?<=ontent length: )(\d+)@$h{'Number'}$1$h{'Standard'}@g; $c =~ s@(?<=received: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=read: )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Continuing buffering (?:server )?headers/) { # Continuing buffering headers. byte_count: 19. header_offset: 517. len: 536. $c =~ s@(?<=byte_count: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=header_offset: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=len: )(\d+)@$h{'Number'}$1$h{'Standard'}@; # 3.0.15 up to 3.0.19: # Continuing buffering headers. Bytes most recently read: 498. $c =~ s@(?<=read: )(\d+)@$h{'Number'}$1$h{'Standard'}@; # 3.0.20 and later: # Continuing buffering server headers from socket 5. Bytes most recently read: 498. $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Received \d+ bytes while/) { # Received 206 bytes while expecting 12103. $c =~ s@(?<=Received )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=expecting )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^(Rejecting c|C)onnection from/) { # Connection from 81.163.28.218 dropped due to ACL # Rejecting connection from 178.63.152.227. Maximum number of connections reached. $c =~ s@(?<=onnection from )((?:\d+\.?){3}\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^(?:Reusing|Closing) server socket / or $c =~ m/^No additional client request/) { # Reusing server socket 4. Opened for 10.0.0.1. # Closing server socket 2. Opened for 10.0.0.1. # No additional client request received in time. \ # Closing server socket 4, initially opened for 10.0.0.1. # No additional client request received in time on socket 29. # Privoxy 3.0.20 and later # Reusing server socket 7 connected to www.privoxy.org. Total requests: 2. # Closing server socket 6 connected to d.asset.soup.io. Keep-alive: 0.\ # Tainted: 1. Socket alive: 1. Timeout: 60. Configuration file change detected: 0. $c =~ s@(?<= socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=for )[^\s]+(?=\.)'); $c = highlight_matched_host($c, '(?<=connected to )[^\s]+(?=\.)'); for my $number_pattern ('requests', 'Keep-alive', 'Tainted', ' alive', 'Timeout', 'detected') { $c = highlight_matched_pattern($c, 'Number', '(?<='. $number_pattern . ': )\d+'); } } elsif ($c =~ m/^Connected to /) { # Connected to tor-jail[10.0.0.2]:9050. $c = highlight_matched_host($c, '(?<=\[)[^\]]+'); $c = highlight_matched_host($c, '(?<=Connected to )[^\[\s]+'); $c =~ s@(?<=\]:)(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Could not connect to /) { # Could not connect to [10.0.0.1]:80. $c = highlight_matched_host($c, '(?<=\[)[^\]]+'); $c =~ s@(?<=\]:)(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Waiting for the next client request/ or $c =~ m/^The connection on server socket/ or $c =~ m/^Client request (?:\d+ )?(?:arrived in time|has been pipelined) /) { # Waiting for the next client request on socket 3. Keeping the server \ # socket 12 to a.fsdn.com open. # The connection on server socket 6 to upload.wikimedia.org isn't reusable. Closing. # Privoxy 3.0.20 and later: # Client request 4 arrived in time on socket 7. # Used by Privoxy 3.0.18 and 3.0.19: # Client request arrived in time on socket 21. # Used by earlier version: # Client request arrived in time or the client closed the connection on socket 12. # Client request 8 has been pipelined on socket 7 and the socket is still alive. $c =~ s@(?<=request )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=on socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=server socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=to )[^\s]+'); } elsif ($c =~ m/^Marking the server socket/) { # Marking the server socket 7 tainted. $c =~ s@(?<=server socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Reduced expected bytes to /) { # Reduced expected bytes to 0 to account for the 1542 ones we already got. $c =~ s@(?<=bytes to )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=for the )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^The client closed socket /) { # The client closed socket 2 while the server socket 4 is still open. $c =~ s@(?<=closed socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=server socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Expected client content length set /) { # Expected client content length set to 667325411 after reading 4999 bytes. $c =~ s@(?<=set to )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=reading )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Reducing expected bytes to /) { # Reducing expected bytes to 0. Marking the server socket tainted after throwing 4 bytes away. $c =~ s@(?<=bytes to )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=after throwing )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Waiting for up to /) { # Waiting for up to 4999 bytes from the client. $c =~ s@(?<=up to )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Optimistically sending /) { # Optimistically sending 318 bytes of client headers intended for www.privoxy.org $c =~ s@(?<=sending )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c = highlight_matched_host($c, '(?<=for )[^\s]+'); } elsif ($c =~ m/^Stopping to watch the client socket/) { # Stopping to watch the client socket. There's already another request waiting. # Privoxy 3.0.20 and later: # Stopping to watch the client socket 5. There's already another request waiting. $c =~ s@(?<=client socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Drained \d+ bytes before closing/) { # Drained 180 bytes before closing socket 6 $c =~ s@(?<=Drained )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Tainting client socket/ or $c =~ m/^Failed to shutdown socket/) { # Tainting client socket 7 due to unread data. # Failed to shutdown socket 11: Connection reset by peer $c =~ s@(?<=socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Shifting \d+ pipelined bytes/) { # Shifting 360 pipelined bytes by 360 bytes $c =~ s@(?<=Shifting )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=by )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Looks like we / or $c =~ m/^Unsetting keep-alive flag/ or $c =~ m/^No connections to wait/ or $c =~ m/^Complete client request received/ or $c =~ m/^Possible pipeline attempt detected./ or $c =~ m/^POST request detected. The connection will not be kept alive./ or $c =~ m/^The server still wants to talk, but the client hung up on us./ or $c =~ m/^The server didn't specify how long the connection will stay open/ or $c =~ m/^There might be a request body. The connection will not be kept alive/ or $c =~ m/^There better be a request body./ or $c =~ m/^Done reading from the client\.$/) { # Looks like we reached the end of the last chunk. We better stop reading. # Looks like we read the end of the last chunk together with the server \ # headers. We better stop reading. # Looks like we got the last chunk together with the server headers. \ # We better stop reading. # Unsetting keep-alive flag. # No connections to wait for left. # Client request arrived in time or the client closed the connection. # Complete client request received # Possible pipeline attempt detected. The connection will not be \ # kept alive and we will only serve the first request. # POST request detected. The connection will not be kept alive. # The server still wants to talk, but the client hung up on us. # The server didn't specify how long the connection will stay open. Assume it's only a second. # There might be a request body. The connection will not be kept alive. # Privoxy 3.0.20 and later # There better be a request body. # Done reading from the client. } else { found_unknown_content($c); } return $c; } sub handle_loglevel_info ($) { my $c = shift; if ($c =~ m/^Rewrite detected:/) { # Rewrite detected: GET http://10.0.0.2:88/blah.txt HTTP/1.1 $c = highlight_matched_request_line($c, '(?<=^Rewrite detected: ).*'); } elsif ($c =~ m/^Decompress(ing deflated|ion didn)/ or $c =~ m/^Compressed content detected/ or $c =~ m/^SDCH-compressed content detected/ or $c =~ m/^Tagger/ ) { # Decompressing deflated iob: 117 # Decompression didn't result in any content. # Compressed content detected, content filtering disabled. Consider recompiling Privoxy\ # with zlib support or enable the prevent-compression action. # SDCH-compressed content detected, content filtering disabled.\ # Consider suppressing SDCH offers made by the client. # Tagger 'complete-url' created empty tag. Ignored. # Ignored for now } elsif ($c =~ m/^(Re)?loading configuration file /) { # loading configuration file '/usr/local/etc/privoxy/config': # Reloading configuration file '/usr/local/etc/privoxy/config' $c =~ s@(?<=loading configuration file \')([^\']*)@$h{'file'}$1$h{'Standard'}@; } elsif ($c =~ m/^Loading (actions|filter|trust) file: /) { # Loading actions file: /usr/local/etc/privoxy/default.action # Loading filter file: /usr/local/etc/privoxy/default.filter # Loading trust file: /usr/local/etc/privoxy/trust $c =~ s@(?<= file: )(.*)$@$h{'file'}$1$h{'Standard'}@; } elsif ($c =~ m/^exiting by signal/) { # exiting by signal 15 .. bye $c =~ s@(?<=exiting by signal )(\d+)@$h{'signal'}$1$h{'Standard'}@; } elsif ($c =~ m/^Privoxy version/) { # Privoxy version 3.0.7 $c =~ s@(?<=^Privoxy version )(\d+\.\d+\.\d+)$@$h{'version'}$1$h{'Standard'}@; } elsif ($c =~ m/^Program name: /) { # Program name: /usr/local/sbin/privoxy $c =~ s@(?<=Program name: )(.*)@$h{'program-name'}$1$h{'Standard'}@; } elsif ($c =~ m/^Listening on port /) { # Listening on port 8118 on IP address 10.0.0.1 $c =~ s@(?<=Listening on port )(\d+)@$h{'port'}$1$h{'Standard'}@; $c =~ s@(?<=on IP address )(.*)@$h{'ip-address'}$1$h{'Standard'}@; } elsif ($c =~ m/^\(Re-\)Open(?:ing)? logfile/) { # (Re-)Open logfile /var/log/privoxy/privoxy.log $c =~ s@(?<=Open logfile )(.*)@$h{'file'}$1$h{'Standard'}@; } elsif ($c =~ m/^(Request from|Malformed server response detected)/) { # Request from 10.0.0.1 denied. limit-connect{,} doesn't allow CONNECT requests to port 443. # Request from 10.0.0.1 marked for blocking. limit-connect{,} doesn't allow CONNECT requests to port 443. # 3.0.18 and later: # Request from 10.0.0.1 marked for blocking. limit-connect{0} doesn't allow CONNECT requests to www.example.org:443 # Malformed server response detected. Downgrading to HTTP/1.0 impossible. $c =~ s@(?<=Request from )([^\s]*)@$h{'ip-address'}$1$h{'Standard'}@; $c =~ s@(denied|blocking)@$h{'warning'}$1$h{'Standard'}@; $c =~ s@(CONNECT)@$h{'method'}$1$h{'Standard'}@; $c =~ s@(?<=to port )(\d+)@$h{'port'}$1$h{'Standard'}@; $c =~ s@(?<=to )([^\s]+)@$h{'request_'}$1$h{'Standard'}@; } elsif ($c =~ m/^Status code/) { # Status code 304 implies no body. $c =~ s@(?<=Status code )(\d+)@$h{'status-code'}$1$h{'Standard'}@; } elsif ($c =~ m/^Method/) { # Method HEAD implies no body. $c =~ s@(?<=Method )([^\s]+)@$h{'method'}$1$h{'Standard'}@; } elsif ($c =~ m/^Buffer limit reached while extending /) { # Buffer limit reached while extending the buffer (iob). Needed: 4197470. Limit: 4194304 $c =~ s@(?<=Needed: )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=Limit: )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^File modification detected: /) { # File modification detected: /usr/local/etc/privoxy/user-agent.action $c =~ s@(?<= detected: )(.*)$@$h{'file'}$1$h{'Standard'}@; } elsif ($c =~ m/^No logfile configured/ or $c =~ m/^Malformerd HTTP headers detected and MS IIS5 hack enabled/ or $c =~ m/^Invalid \"chunked\" transfer/ or $c =~ m/^Support for/ or $c =~ m/^Flushing header and buffers/ or $c =~ m/^Can not resolve/ ) { # No logfile configured. Please enable it before reporting any problems. # Malformerd HTTP headers detected and MS IIS5 hack enabled. Expect an invalid \ # response or even no response at all. # No logfile configured. Logging disabled. # Invalid "chunked" transfer encoding detected and ignored. # Support for 'Connection: keep-alive' is experimental, incomplete and\ # known not to work properly in some situations. # Flushing header and buffers. Stepping back from filtering. # Can not resolve doesnotexist: hostname nor servname provided, or not known } else { found_unknown_content($c); } return $c; } sub handle_loglevel_cgi ($) { my $c = shift; if ($c =~ m/^Granting access to/) { #Granting access to http://config.privoxy.org/send-stylesheet, referrer http://p.p/ is trustworthy. } elsif ($c =~ m/^Substituting: s(.)/) { # Substituting: s/@else-not-FEATURE_ZLIB@.*@endif-FEATURE_ZLIB@//sigTU # XXX: prone to span several lines my $delimiter = $1; #$c =~ s@(?<=failed: )(.*)@$h{'error'}$1$h{'Standard'}@; $c =~ s@(?!<=\\)($delimiter)@$h{'pcrs-delimiter'}$1$h{'Standard'}@g; # XXX: Too aggressive #$c =~ s@(?!<=\\)($1)@$h{'pcrs-delimiter'}$1$h{'Standard'}@g; } return $c; } sub handle_loglevel_force ($) { my $c = shift; if ($c =~ m/^Ignored force prefix in request:/) { # Ignored force prefix in request: "GET http://10.0.0.1/PRIVOXY-FORCE/block HTTP/1.1" $c =~ s@^(Ignored)@$h{'ignored'}$1$h{'Standard'}@; $c = highlight_matched_request_line($c, '(?<=request: ")[^"]*'); } elsif ($c =~ m/^Enforcing request:/) { # Enforcing request: "GET http://10.0.0.1/block HTTP/1.1". $c = highlight_matched_request_line($c, '(?<=request: ")[^"]*'); } else { found_unknown_content($c); } return $c; } sub handle_loglevel_error ($) { my $c = shift; if ($c =~ m/^(?:Empty|No) server or forwarder response received on socket \d+\./) { # Empty server or forwarder response received on socket 4. # Empty server or forwarder response received on socket 3. \ # Closing client socket 15 without sending data. # Used by Privoxy 3.0.18 and later: # No server or forwarder response received on socket 8. \ # Closing client socket 10 without sending data. $c =~ s@(?<=on socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; $c =~ s@(?<=client socket )(\d+)@$h{'Number'}$1$h{'Standard'}@; } elsif ($c =~ m/^Didn't receive data in time:/) { # Didn't receive data in time: a.fsdn.com:443 $c =~ s@(?<=in time: )(.*)@$h{'destination'}$1$h{'Standard'}@; } # XXX: There are probably more messages that deserve highlighting. return $c; } sub handle_loglevel_ignore ($) { return shift; } sub gather_loglevel_request_stats ($$) { my $c = shift; my $thread = shift; our %stats; $stats{requests}++; } sub gather_loglevel_crunch_stats ($$) { my $c = shift; my $thread = shift; our %stats; $stats{requests}++; $stats{crunches}++; if ($c =~ m/^Redirected:/) { # Redirected: http://www.example.org/http://p.p/ $stats{'fast-redirections'}++; } elsif ($c =~ m/^Blocked:/) { # Blocked: blogger.googleusercontent.com:443 $stats{'blocked'}++; } } sub gather_loglevel_error_stats ($$) { my $c = shift; my $thread = shift; our %stats; our %thread_data; if ($c =~ m/^Empty server or forwarder response received on socket \d+./) { # Empty server or forwarder response received on socket 4. $stats{'empty-responses'}++; if ($thread_data{$thread}{'new_connection'}) { $stats{'empty-responses-on-new-connections'}++; } else { $stats{'empty-responses-on-reused-connections'}++; } } } sub gather_loglevel_connect_stats ($$) { my ($c, $thread) = @_; our %thread_data; our %stats; if ($c =~ m/^via ([^\s]+) to: [^\s]+/) { # Connect: via 10.0.0.1:8123 to: www.example.org.noconnect $thread_data{$thread}{'forwarder'} = $1; # XXX: is this missue? } elsif ($c =~ m/^to ([^\s]*)$/) { # Connect: to lists.sourceforge.net:443 $thread_data{$thread}{'forwarder'} = 'direct connection'; } elsif ($c =~ m/^Created new connection to/) { # Created new connection to www.privoxy.org:80 on socket 11. $thread_data{$thread}{'new_connection'} = 1; } elsif ($c =~ m/^Reusing server socket \d./ or $c =~ m/^Found reusable socket/) { # Reusing server socket 4. Opened for 10.0.0.1. # Found reusable socket 9 for www.privoxy.org:80 in slot 0. $thread_data{$thread}{'new_connection'} = 0; $stats{'reused-connections'}++; } elsif ($c =~ m/^Closing client socket \d+. .* Requests received: (\d+)\.$/) { # Closing client socket 12. Keep-alive: 1. Socket alive: 1. Data available: 0. \ # Configuration file change detected: 0. Requests received: 14. $stats{'client-requests-on-connection'}{$1}++; $stats{'closed-client-connections'}++; } } sub gather_loglevel_header_stats ($$) { my ($c, $thread) = @_; our %stats; if ($c =~ m/^A HTTP\/1\.1 response without/ or $c =~ m/^Keeping the server header 'Connection: keep-alive' around./) { # A HTTP/1.1 response without Connection header implies keep-alive. # Keeping the server header 'Connection: keep-alive' around. $stats{'server-keep-alive'}++; } elsif ($c =~ m/^scan: ((\w+) (.+) (HTTP\/\d\.\d))/) { # scan: HTTP/1.1 200 OK $stats{'method'}{$2}++; $stats{'resource'}{$3}++; $stats{'http-version'}{$4}++; } elsif ($c =~ m/^scan: Host: ([^\s]+)/) { # scan: Host: p.p $stats{'hosts'}{$1}++; } } sub init_stats () { our %stats = ( requests => 0, crunches => 0, 'server-keep-alive' => 0, 'reused-connections' => 0, 'empty-responses' => 0, 'empty-responses-on-new-connections' => 0, 'empty-responses-on-reused-connections' => 0, 'fast-redirections' => 0, 'blocked' => 0, 'reused-connections' => 0, 'server-keep-alive' => 0, 'closed-client-connections' => 0, ); $stats{'client-requests-on-connection'}{1} = 0; } sub get_percentage ($$) { my $big = shift; my $small = shift; # If small is 0 the percentage is always 0%. # Make sure it works even if big is 0 as well. return "0.00%" if ($small eq 0); # Prevent division by zero. # XXX: Is this still supposed to be reachable? return "NaN" if ($big eq 0); return sprintf("%.2f%%", $small / $big * 100); } sub print_stats () { our %stats; our %cli_options; my $new_connections = $stats{requests} - $stats{crunches} - $stats{'reused-connections'}; my $outgoing_requests = $stats{requests} - $stats{crunches}; my $client_requests_checksum = 0; if ($stats{requests} eq 0) { print "No requests yet.\n"; return; } print "Client requests total: " . $stats{requests} . "\n"; print "Crunches: " . $stats{crunches} . " (" . get_percentage($stats{requests}, $stats{crunches}) . ")\n"; print "Blocks: " . $stats{'blocked'} . " (" . get_percentage($stats{requests}, $stats{'blocked'}) . ")\n"; print "Fast redirections: " . $stats{'fast-redirections'} . " (" . get_percentage($stats{requests}, $stats{'fast-redirections'}) . ")\n"; print "Outgoing requests: " . $outgoing_requests . " (" . get_percentage($stats{requests}, $outgoing_requests) . ")\n"; print "Server keep-alive offers: " . $stats{'server-keep-alive'} . " (" . get_percentage($stats{requests}, $stats{'server-keep-alive'}) . ")\n"; print "New outgoing connections: " . $new_connections . " (" . get_percentage($stats{requests}, $new_connections) . ")\n"; print "Reused connections: " . $stats{'reused-connections'} . " (" . get_percentage($stats{requests}, $stats{'reused-connections'}) . "; server offers accepted: " . get_percentage($stats{'server-keep-alive'}, $stats{'reused-connections'}) . ")\n"; print "Empty responses: " . $stats{'empty-responses'} . " (" . get_percentage($stats{requests}, $stats{'empty-responses'}) . ")\n"; print "Empty responses on new connections: " . $stats{'empty-responses-on-new-connections'} . " (" . get_percentage($stats{requests}, $stats{'empty-responses-on-new-connections'}) . ")\n"; print "Empty responses on reused connections: " . $stats{'empty-responses-on-reused-connections'} . " (" . get_percentage($stats{requests}, $stats{'empty-responses-on-reused-connections'}) . ")\n"; print "Client connections: " . $stats{'closed-client-connections'} . "\n"; my $lines_printed = 0; print "Client requests per connection distribution:\n"; foreach my $client_requests (sort { $stats{'client-requests-on-connection'}{$b} <=> $stats{'client-requests-on-connection'}{$a}} keys %{$stats{'client-requests-on-connection'} }) { my $count = $stats{'client-requests-on-connection'}{$client_requests}; $client_requests_checksum += $count * $client_requests; if ($cli_options{'show-complete-request-distribution'} or ($lines_printed < 10)) { printf "%8d: %d\n", $count, $client_requests; $lines_printed++; } } unless ($cli_options{'show-complete-request-distribution'}) { printf "Enable --show-complete-request-distribution to get less common numbers as well.\n"; } printf "Unaccounted requests: ~%d\n", $stats{requests} - $client_requests_checksum; if ($stats{method} eq 0) { print "No response lines parsed yet yet.\n"; return; } print "Method distribution:\n"; foreach my $method (sort {$stats{'method'}{$b} <=> $stats{'method'}{$a}} keys %{$stats{'method'}}) { printf "%8d : %-8s\n", $stats{'method'}{$method}, $method; } print "Client HTTP versions:\n"; foreach my $http_version (sort {$stats{'http-version'}{$b} <=> $stats{'http-version'}{$a}} keys %{$stats{'http-version'}}) { printf "%d : %s\n", $stats{'http-version'}{$http_version}, $http_version; } if ($cli_options{'url-statistics-threshold'} == 0) { print "URL statistics are disabled. Increase --url-statistics-threshold to enable them.\n"; } else { print "Requested URLs:\n"; foreach my $resource (sort {$stats{'resource'}{$b} <=> $stats{'resource'}{$a}} keys %{$stats{'resource'}}) { if ($stats{'resource'}{$resource} < $cli_options{'url-statistics-threshold'}) { print "Skipped statistics for URLs below the treshold.\n"; last; } printf "%d : %s\n", $stats{'resource'}{$resource}, $resource; } } if ($cli_options{'host-statistics-threshold'} == 0) { print "Host statistics are disabled. Increase --host-statistics-threshold to enable them.\n"; } else { print "Requested Hosts:\n"; foreach my $host (sort {$stats{'hosts'}{$b} <=> $stats{'hosts'}{$a}} keys %{$stats{'hosts'}}) { if ($stats{'hosts'}{$host} < $cli_options{'host-statistics-threshold'}) { print "Skipped statistics for Hosts below the treshold.\n"; last; } printf "%d : %s\n", $stats{'hosts'}{$host}, $host; } } } ################################################################################ # Functions that actually print stuff ################################################################################ sub print_clf_message () { our ($ip, $timestamp, $request_line, $status_code, $size); my $output = ''; return if DEBUG_SUPPRESS_LOG_MESSAGES; # Rebuild highlighted $output .= $h{'Number'} . $ip . $h{'Standard'}; $output .= " - - "; $output .= "[" . $h{'Timestamp'} . $timestamp . $h{'Standard'} . "]"; $output .= " "; $output .= "\"" . highlight_request_line("$request_line") . "\""; $output .= " "; $output .= $h{'Status'} . $status_code . $h{'Standard'}; $output .= " "; $output .= $h{'Number'} . $size . $h{'Standard'}; $output .= $line_end; print $output; } sub print_non_clf_message ($) { my $content = shift; my $msec_string = $no_msecs_mode ? '' : '.' . $req{$t}{'msecs'}; my $line_start = $html_output_mode ? '' : $h{"Standard"}; return if DEBUG_SUPPRESS_LOG_MESSAGES; print $line_start . $time_colours[$time_colour_index % 2] . $req{$t}{'time-stamp'} . $msec_string . $h{Standard} . " " . $thread_colours{$t} . $t . $h{Standard} . " " . $h{$req{$t}{'log-level'}} . $req{$t}{'log-level'} . $h{Standard} . ": " . $content . $line_end; } sub shorten_thread_id ($) { my $thread_id = shift; our %short_thread_ids; our $max_threadid; unless (defined $short_thread_ids{$thread_id}) { $short_thread_ids{$thread_id} = sprintf "%.3d", $max_threadid++; } return $short_thread_ids{$thread_id} } sub parse_loop () { my ($day, $time_stamp, $thread, $log_level, $content, $c, $msecs); my $last_msecs = 0; my $last_thread = 0; my $last_timestamp = 0; my $filters_that_did_nothing; my $key; my $time_colour; $time_colour = paint_it('white'); my %log_level_handlers = ( 'Re-Filter' => \&handle_loglevel_re_filter, 'Header' => \&handle_loglevel_header, 'Connect' => \&handle_loglevel_connect, 'Redirect' => \&handle_loglevel_redirect, 'Request' => \&handle_loglevel_request, 'Crunch' => \&handle_loglevel_crunch, 'Gif-Deanimate' => \&handle_loglevel_gif_deanimate, 'Info' => \&handle_loglevel_info, 'CGI' => \&handle_loglevel_cgi, 'Force' => \&handle_loglevel_force, 'Error' => \&handle_loglevel_error, 'Fatal error' => \&handle_loglevel_ignore, 'Writing' => \&handle_loglevel_ignore, 'Received' => \&handle_loglevel_ignore, 'Actions' => \&handle_loglevel_ignore, 'Unknown log level' => \&handle_loglevel_ignore, ); while (<>) { if (m/^(\d{4}-\d{2}-\d{2}|\w{3} \d{2}) (\d\d:\d\d:\d\d)\.?(\d+)? (?:Privoxy\()?([^\)\s]*)[\)]? ([\w -]*): (.*?)\r?$/) { $thread = $t = ($shorten_thread_ids) ? shorten_thread_id($4) : $4; $req{$t}{'day'} = $day = $1; $req{$t}{'time-stamp'} = $time_stamp = $2; $req{$t}{'msecs'} = $msecs = $3 ? $3 : 0; # Only the cool kids have micro second resolution; $req{$t}{'log-level'} = $log_level = $5; $req{$t}{'content'} = $content = $c = $6; $req{$t}{'log-message'} = $_; $no_special_header_highlighting = 0; if (defined($log_level_handlers{$log_level})) { $content = $log_level_handlers{$log_level}($content); } else { die "No handler found for log level \"$log_level\"\n"; } # Highlight Truncations if (length($_) > 4000) { $content =~ s@(too long, truncated)]$@$h{'Truncation'}$1$h{'Standard'}]@g; } next unless $content; # Register threads to keep the colour constant if (!defined($thread_colours{$thread})) { $thread_colours{$thread} = $all_colours[$thread_colour_index % @all_colours]; $thread_colour_index++; } # Switch timestamp colour if timestamps differ if (($msecs ne $last_msecs) || ($time_stamp ne $last_timestamp)) { debug_message("Tick tack!") if DEBUG_TICKS; $time_colour = $time_colours[$time_colour_index % 2]; $time_colour_index++; $last_msecs = $msecs; $last_timestamp = $time_stamp; } $last_thread = $thread; print_non_clf_message($content); } elsif (m/^((?:\d+\.\d+\.\d+\.\d+|[:\d]+)) - - \[(.*)\] "(.*)" (\d+) (\d+)/) { # LOG_LEVEL_CLF lines look like this # 61.152.239.32 - - [04/Mar/2007:18:28:23 +0100] "GET \ # http://ad.yieldmanager.com/imp?z=1&Z=120x600&s=109339&u=http%3A%2F%2Fwww.365loan.co.uk%2F&r=1\ # HTTP/1.1" 403 1730 our ($ip, $timestamp, $request_line, $status_code, $size) = ($1, $2, $3, $4, $5); print_clf_message(); } else { # Some Privoxy log messages span more than one line, # usually to dump lots of content that doesn't need any syntax highlighting. # XXX: add mechanism to forward these lines to the right handler anyway. chomp(); unless (DEBUG_SUPPRESS_LOG_MESSAGES or (SUPPRESS_EMPTY_LINES and m/^\s+$/)) { print and print get_line_end(); # unless (SUPPRESS_EMPTY_LINES and m/^\s+$/); } } } } sub stats_loop () { my ($day, $time_stamp, $msecs, $thread, $log_level, $content); my $strict_checks = cli_option_is_set('strict-checks'); my %log_level_handlers = ( 'Connect:' => \&gather_loglevel_connect_stats, 'Crunch:' => \&gather_loglevel_crunch_stats, 'Error:' => \&gather_loglevel_error_stats, 'Header:' => \&gather_loglevel_header_stats, 'Request:' => \&gather_loglevel_request_stats, ); my %ignored_log_levels = ( 'Actions:' => \&handle_loglevel_ignore, 'CGI:' => \&handle_loglevel_ignore, 'Fatal error:' => \&handle_loglevel_ignore, 'Force:' => \&handle_loglevel_ignore, 'Gif-Deanimate:' => \&handle_loglevel_ignore, 'Info:' => \&handle_loglevel_ignore, 'Re-Filter:' => \&handle_loglevel_ignore, 'Received:' => \&handle_loglevel_ignore, 'Redirect:' => \&handle_loglevel_ignore, 'Unknown log level:' => \&handle_loglevel_ignore, 'Writing:' => \&handle_loglevel_ignore, ); while (<>) { (undef, $time_stamp, $thread, $log_level, $content) = split(/ /, $_, 5); # Skip LOG_LEVEL_CLF next if ($time_stamp eq "-" or not defined($log_level)); if (defined($log_level_handlers{$log_level})) { $content = $log_level_handlers{$log_level}($content, $thread); } elsif ($strict_checks and not defined($ignored_log_levels{$log_level})) { die "No handler found for: $_"; } } print_stats(); } sub unbreak_lines_only_loop() { my $log_messages_reached = 0; while (<>) { chomp; # Log level other than LOG_LEVEL_CLF? if (m/^(\d{4}-\d{2}-\d{2}|\w{3} \d{2}) (\d\d:\d\d:\d\d)\.?(\d+)? (?:Privoxy\()?([^\)\s]*)[\)]? ([\w -]*): (.*?)\r?$/ or # LOG_LEVEL_CLF? m/^((?:\d+\.\d+\.\d+\.\d+)) - - \[(.*)\] "(.*)" (\d+) (\d+)/) { $log_messages_reached = 1; print "\n"; } else { # Wrapped message $_ = "\n". $_ if /^(?:\d+\.\d+\.\d+\.\d+)/; $_ = " " . $_; } s@
    $@@; print; print "\n" unless $log_messages_reached; } print "\n"; } sub VersionMessage { my $version_message; $version_message .= 'Privoxy-Log-Parser ' . PRIVOXY_LOG_PARSER_VERSION . "\n"; $version_message .= 'http://www.fabiankeil.de/sourcecode/privoxy-log-parser/' . "\n"; print $version_message; } sub get_cli_options () { our %cli_options = ( 'html-output' => CLI_OPTION_DEFAULT_TO_HTML_OUTPUT, 'title' => CLI_OPTION_TITLE, 'no-syntax-highlighting' => CLI_OPTION_NO_SYNTAX_HIGHLIGHTING, 'no-embedded-css' => CLI_OPTION_NO_EMBEDDED_CSS, 'no-msecs' => CLI_OPTION_NO_MSECS, 'shorten-thread-ids' => CLI_OPTION_SHORTEN_THREAD_IDS, 'show-ineffective-filters' => CLI_OPTION_SHOW_INEFFECTIVE_FILTERS, 'statistics' => CLI_OPTION_STATISTICS, 'strict-checks' => CLI_OPTION_STRICT_CHECKS, 'url-statistics-threshold' => CLI_OPTION_URL_STATISTICS_THRESHOLD, 'unbreak-lines-only' => CLI_OPTION_UNBREAK_LINES_ONLY, 'host-statistics-threshold'=> CLI_OPTION_HOST_STATISTICS_THRESHOLD, 'show-complete-request-distribution' => CLI_OPTION_SHOW_COMPLETE_REQUEST_DISTRIBUTION, ); GetOptions ( 'html-output' => \$cli_options{'html-output'}, 'title' => \$cli_options{'title'}, 'no-syntax-highlighting' => \$cli_options{'no-syntax-highlighting'}, 'no-embedded-css' => \$cli_options{'no-embedded-css'}, 'no-msecs' => \$cli_options{'no-msecs'}, 'shorten-thread-ids' => \$cli_options{'shorten-thread-ids'}, 'show-ineffective-filters' => \$cli_options{'show-ineffective-filters'}, 'statistics' => \$cli_options{'statistics'}, 'strict-checks' => \$cli_options{'strict-checks'}, 'unbreak-lines-only' => \$cli_options{'unbreak-lines-only'}, 'url-statistics-threshold=i'=> \$cli_options{'url-statistics-threshold'}, 'host-statistics-threshold=i'=> \$cli_options{'host-statistics-threshold'}, 'show-complete-request-distribution' => \$cli_options{'show-complete-request-distribution'}, 'version' => sub { VersionMessage && exit(0) }, 'help' => \&help, ) or exit(1); $html_output_mode = cli_option_is_set('html-output'); $no_msecs_mode = cli_option_is_set('no-msecs'); $shorten_thread_ids = cli_option_is_set('shorten-thread-ids'); $line_end = get_line_end(); } sub help () { our %cli_options; VersionMessage(); print << " EOF" Options and their default values if they have any: [--host-statistics-threshold $cli_options{'host-statistics-threshold'}] [--html-output] [--no-embedded-css] [--no-msecs] [--no-syntax-highlighting] [--shorten-thread-ids] [--show-ineffective-filters] [--show-complete-request-distribution] [--statistics] [--unbreak-lines-only] [--url-statistics-threshold $cli_options{'url-statistics-threshold'}] [--title $cli_options{'title'}] [--version] see "perldoc $0" for more information EOF ; exit(0); } ################################################################################ # main ################################################################################ sub main () { get_cli_options(); set_background(DEFAULT_BACKGROUND); prepare_our_stuff(); print_intro(); # XXX: should explicitly reject incompatible argument combinations if (cli_option_is_set('unbreak-lines-only')) { unbreak_lines_only_loop(); } elsif (cli_option_is_set('statistics')) { stats_loop(); } else { parse_loop(); } print_outro(); } main(); =head1 NAME B - A parser and syntax-highlighter for Privoxy log messages =head1 SYNOPSIS B [B<--html-output>] [B<--no-msecs>] [B<--no-syntax-higlighting>] [B<--statistics>] [B<--shorten-thread-ids>] [B<--show-ineffective-filters>] [B<--url-statistics-threshold>] [B<--version>] =head1 DESCRIPTION B reads Privoxy log messages and - syntax-highlights recognized lines, - reformats some of them for easier comprehension, - filters out less useful messages, and - (in some cases) calculates additional information, like the compression ratio or how a filter affected the content size. With B you should be able to increase Privoxy's log level without getting confused by the resulting amount of output. For example for "debug 64" B will (by default) only show messages that affect the content. If a filter doesn't cause any hits, B will hide the "filter foo caused 0 hits" message. =head1 OPTIONS [B<--host-statistics-threshold>] Only show the request count for a host if it's above or equal to the given threshold. If the threshold is 0, host statistics are disabled. [B<--html-output>] Use HTML and CSS for the syntax highlighting. If this option is omitted, ANSI escape sequences are used unless B<--no-syntax-highlighting> is active. This option is only intended to make embedding log excerpts in web pages easier. It does not escape any input! [B<--no-msecs>] Don't expect milisecond resolution [B<--no-syntax-highlighting>] Disable syntax-highlighting. Useful when the filtered output is piped into less in which case the ANSI control codes don't work, or if the terminal itself doesn't support the control codes. [B<--shorten-thread-ids>] Shorten the thread ids to a three-digit decimal number. Note that the mapping from thread ids to shortened ids is created at run-time and thus varies with the input. [B<--show-ineffective-filters>] Don't suppress log lines for filters that didn't modify the content. [B<--show-complete-request-distribution>] Show the complete client request distribution in the B<--statistics> output. Without this option only the ten most common numbers are shown. [B<--statistics>] Gather various statistics instead of syntax highlighting log messages. This is an experimental feature, if the results look wrong they very well might be. Also note that the results are pretty much guaranteed to be incorrect if Privoxy and Privoxy-Log-Parser aren't in sync. [B<--strict-checks>] When generating statistics, look more careful at the input data and abort if it is unexpected, even if it doesn't affect the results. Significantly slows the parsing down and is not expected to catch any problems that matter. When highlighting, print warnings in case of unknown messages which can't be properly highlighted. [B<--unbreak-lines-only>] Tries to fix lines that got messed up by a broken or interestingly configured mail client and thus are no longer recognized properly. Only fixes some breakage, but may be good enough or at least better than nothing. Doesn't do anything else, so you probably want to pipe the output into B again. [B<--url-statistics-threshold>] Only show the request count for a resource if it's above or equal to the given threshold. If the threshold is 0, URL statistics are disabled. [B<--version>] Print version and exit. =head1 EXAMPLES To monitor a log file: tail -F /usr/jails/privoxy-jail/var/log/privoxy/privoxy.log | B Replace '-F' with '-f' if your tail implementation lacks '-F' support or if the log won't get rotated anyway. The log file location depends on your system (Doh!). To monitor Privoxy without having it write to a log file: privoxy --no-daemon /usr/jails/privoxy-jail/usr/local/etc/privoxy/config 2>&1 | B Again, the config file location depends on your system. Output redirection depends on your shell, the above works with bourne shells. To read a processed Privoxy log file from top to bottom, letting the content scroll by slightly faster than you can read: B < /usr/jails/privoxy-jail/var/log/privoxy/privoxy.log This is probably only useful to fill screens in the background of haxor movies. =head1 CAVEATS Syntax highlighting with ANSI escape sequences will look strange if your background color isn't black. Some messages aren't recognized yet and will not be fully highlighted. B is developed with Privoxy 3.0.7 or later in mind, using earlier Privoxy versions will probably result in an increased amount of unrecognized log lines. Privoxy's log files tend to be rather large. If you use HTML highlighting some browsers can't handle them, get confused and will eventually crash because of segmentation faults or unexpected exceptions. This is a problem in the browser and not B's fault. =head1 BUGS Many settings can't be controlled through command line options yet. =head1 SEE ALSO privoxy(1) =head1 AUTHOR Fabian Keil =cut privoxy-3.0.21-stable/./tools/privoxy-regression-test.pl000750 001751 001751 00000166213 12116117674 022353 0ustar00fkfk000000 000000 #!/usr/bin/perl ############################################################################ # # Privoxy-Regression-Test # # A regression test "framework" for Privoxy. For documentation see: # perldoc privoxy-regression-test.pl # # $Id: privoxy-regression-test.pl,v 1.91 2013/03/07 14:10:04 fabiankeil Exp $ # # Wish list: # # - Update documentation # - Validate HTTP times. # - Implement a HTTP_VERSION directive or allow to # specify whole request lines. # - Support filter regression tests. # - Document magic Expect Header values # - Internal fuzz support? # # Copyright (c) 2007-2013 Fabian Keil # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ############################################################################ use warnings; use strict; use Getopt::Long; use constant { PRT_VERSION => 'Privoxy-Regression-Test 0.6', CURL => 'curl', # CLI option defaults CLI_RETRIES => 1, CLI_LOOPS => 1, CLI_MAX_TIME => 5, CLI_MIN_LEVEL => 0, # XXX: why limit at all? CLI_MAX_LEVEL => 100, CLI_FORKS => 0, CLI_SLEEP_TIME => 0, PRIVOXY_CGI_URL => 'http://p.p/', FELLATIO_URL => 'http://127.0.0.1:8080/', LEADING_LOG_DATE => 1, LEADING_LOG_TIME => 1, DEBUG_LEVEL_FILE_LOADING => 0, DEBUG_LEVEL_PAGE_FETCHING => 0, DEBUG_LEVEL_VERBOSE_FAILURE => 1, # XXX: Only partly implemented and mostly useless. DEBUG_LEVEL_VERBOSE_SUCCESS => 0, DEBUG_LEVEL_STATUS => 1, # Internal use, don't modify # Available debug bits: LL_SOFT_ERROR => 1, LL_VERBOSE_FAILURE => 2, LL_PAGE_FETCHING => 4, LL_FILE_LOADING => 8, LL_VERBOSE_SUCCESS => 16, LL_STATUS => 32, CLIENT_HEADER_TEST => 1, SERVER_HEADER_TEST => 2, DUMB_FETCH_TEST => 3, METHOD_TEST => 4, STICKY_ACTIONS_TEST => 5, TRUSTED_CGI_REQUEST => 6, BLOCK_TEST => 7, REDIRECT_TEST =>108, }; sub init_our_variables () { our $leading_log_time = LEADING_LOG_TIME; our $leading_log_date = LEADING_LOG_DATE; our $privoxy_cgi_url = PRIVOXY_CGI_URL; our $log_level = get_default_log_level(); } sub get_default_log_level () { my $log_level = 0; $log_level |= LL_FILE_LOADING if DEBUG_LEVEL_FILE_LOADING; $log_level |= LL_PAGE_FETCHING if DEBUG_LEVEL_PAGE_FETCHING; $log_level |= LL_VERBOSE_FAILURE if DEBUG_LEVEL_VERBOSE_FAILURE; $log_level |= LL_VERBOSE_SUCCESS if DEBUG_LEVEL_VERBOSE_SUCCESS; $log_level |= LL_STATUS if DEBUG_LEVEL_STATUS; # This one is supposed to be always on. $log_level |= LL_SOFT_ERROR; return $log_level; } ############################################################################ # # File loading functions # ############################################################################ sub parse_tag ($) { my $tag = shift; # Remove anchors $tag =~ s@[\$\^]@@g; # Unescape brackets and dots $tag =~ s@\\(?=[{}().+])@@g; # log_message("Parsed tag: " . $tag); check_for_forbidden_characters($tag); return $tag; } sub check_for_forbidden_characters ($) { my $string = shift; my $allowed = '[-=\dA-Za-z~{}:./();\t ,+@"_%?&*^]'; unless ($string =~ m/^$allowed*$/o) { my $forbidden = $string; $forbidden =~ s@^$allowed*(.).*@$1@; log_and_die("'" . $string . "' contains character '" . $forbidden. "' which is unacceptable."); } } sub load_regression_tests() { if (cli_option_is_set('local-test-file')) { load_regression_tests_from_file(get_cli_option('local-test-file')); } else { load_regression_tests_through_privoxy(); } } # XXX: Contains a lot of code duplicated from load_action_files() # that should be factored out. sub load_regression_tests_from_file ($) { my $action_file = shift; # initialized here our %actions; our @regression_tests; my $si = 0; # Section index my $ri = -1; # Regression test index my $count = 0; my $ignored = 0; my $sticky_actions = undef; l(LL_STATUS, "Gathering regression tests from local file " . $action_file); open(my $ACTION_FILE, "<", $action_file) or log_and_die("Failed to open $action_file: $!"); while (<$ACTION_FILE>) { my $no_checks = 0; chomp; my ($token, $value) = tokenize($_); next unless defined $token; # Load regression tests if (token_starts_new_test($token)) { # Beginning of new regression test. $ri++; $count++; enlist_new_test(\@regression_tests, $token, $value, $si, $ri, $count); $no_checks = 1; # Already validated by enlist_new_test(). } if ($token =~ /level\s+(\d+)/i) { my $level = $1; register_dependency($level, $value); } if ($token eq 'sticky actions') { # Will be used by each following Sticky URL. $sticky_actions = $value; if ($sticky_actions =~ /{[^}]*\s/) { log_and_die("'Sticky Actions' with whitespace inside the " . "action parameters are currently unsupported."); } } if ($si == -1 || $ri == -1) { # No beginning of a test detected yet, # so we don't care about any other test # attributes. next; } if ($token eq 'expect header') { l(LL_FILE_LOADING, "Detected expectation: " . $value); $regression_tests[$si][$ri]{'expect-header'} = $value; } elsif ($token eq 'tag') { next if ($ri == -1); my $tag = parse_tag($value); # We already checked in parse_tag() after filtering $no_checks = 1; l(LL_FILE_LOADING, "Detected TAG: " . $tag); # Save tag for all tests in this section do { $regression_tests[$si][$ri]{'tag'} = $tag; } while ($ri-- > 0); $si++; $ri = -1; } elsif ($token eq 'ignore' && $value =~ /Yes/i) { l(LL_FILE_LOADING, "Ignoring section: " . test_content_as_string($regression_tests[$si][$ri])); $regression_tests[$si][$ri]{'ignore'} = 1; $ignored++; } elsif ($token eq 'expect status code') { l(LL_FILE_LOADING, "Expecting status code: " . $value); $regression_tests[$si][$ri]{'expected-status-code'} = $value; } elsif ($token eq 'level') { # XXX: stupid name $value =~ s@(\d+).*@$1@; l(LL_FILE_LOADING, "Level: " . $value); $regression_tests[$si][$ri]{'level'} = $value; } elsif ($token eq 'method') { l(LL_FILE_LOADING, "Method: " . $value); $regression_tests[$si][$ri]{'method'} = $value; } elsif ($token eq 'redirect destination') { l(LL_FILE_LOADING, "Redirect destination: " . $value); $regression_tests[$si][$ri]{'redirect destination'} = $value; } elsif ($token eq 'url') { if (defined $sticky_actions) { die "WTF? Attempted to overwrite Sticky Actions" if defined ($regression_tests[$si][$ri]{'sticky-actions'}); l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions); $regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions; } else { log_and_die("Sticky URL without Sticky Actions: $value"); } } else { # We don't use it, so we don't need $no_checks = 1; l(LL_STATUS, "Enabling no_checks for $token") unless $no_checks; } # XXX: Necessary? unless ($no_checks) { check_for_forbidden_characters($value); check_for_forbidden_characters($token); } } l(LL_FILE_LOADING, "Done loading " . $count . " regression tests." . " Of which " . $ignored. " will be ignored)\n"); } sub load_regression_tests_through_privoxy () { our $privoxy_cgi_url; our @privoxy_config; our %privoxy_features; my @actionfiles; my $curl_url = ''; my $file_number = 0; my $feature; my $privoxy_version = '(Unknown version!)'; $curl_url .= $privoxy_cgi_url; $curl_url .= 'show-status'; l(LL_STATUS, "Asking Privoxy for the number of action files available ..."); # Dear Privoxy, please reload the config file if necessary ... get_cgi_page_or_else($curl_url); # ... so we get the latest one here. foreach (@{get_cgi_page_or_else($curl_url)}) { chomp; if (/(.*?)<\/td>/) { my $url = $privoxy_cgi_url . 'show-status?file=actions&index=' . $2; $actionfiles[$file_number++] = $url; } elsif (m@config\.html#.*\">([^<]*)\s+(.*)
    @) { my $directive = $1 . " " . $2; push (@privoxy_config, $directive); } elsif (m@([^<]*)@) { $feature = $1; } elsif (m@ (Yes|No) @) { $privoxy_features{$feature} = $1 if defined $feature; $feature = undef; } elsif (m@This is Privoxy (\d+\.\d+\.\d+) on@) { $privoxy_version = $1; } } l(LL_STATUS, "Gathering regression tests from " . @actionfiles . " action file(s) delivered by Privoxy $privoxy_version."); load_action_files(\@actionfiles); } sub token_starts_new_test ($) { my $token = shift; my @new_test_directives = ('set header', 'fetch test', 'trusted cgi request', 'request header', 'method test', 'blocked url', 'url', 'redirected url'); foreach my $new_test_directive (@new_test_directives) { return 1 if $new_test_directive eq $token; } return 0; } sub tokenize ($) { my ($token, $value) = (undef, undef); # Remove leading and trailing white space. s@^\s*@@; s@\s*$@@; # Reverse HTML-encoding # XXX: Seriously incomplete. s@"@"@g; s@&@&@g; # Tokenize if (/^\#\s*([^=:#]*?)\s*[=]\s*([^#]+)(?:#.*)?$/) { $token = $1; $value = $2; $token =~ s@\s\s+@ @g; $token =~ tr/[A-Z]/[a-z]/; } elsif (/^TAG\s*:(.*)$/) { $token = 'tag'; $value = $1; } return ($token, $value); } sub enlist_new_test ($$$$$$) { my ($regression_tests, $token, $value, $si, $ri, $number) = @_; my $type; my $executor; if ($token eq 'set header') { l(LL_FILE_LOADING, "Header to set: " . $value); $type = CLIENT_HEADER_TEST; $executor = \&execute_client_header_regression_test; } elsif ($token eq 'request header') { l(LL_FILE_LOADING, "Header to request: " . $value); $type = SERVER_HEADER_TEST; $executor = \&execute_server_header_regression_test; $$regression_tests[$si][$ri]{'expected-status-code'} = 200; } elsif ($token eq 'trusted cgi request') { l(LL_FILE_LOADING, "CGI URL to test in a dumb way: " . $value); $type = TRUSTED_CGI_REQUEST; $executor = \&execute_dumb_fetch_test; $$regression_tests[$si][$ri]{'expected-status-code'} = 200; } elsif ($token eq 'fetch test') { l(LL_FILE_LOADING, "URL to test in a dumb way: " . $value); $type = DUMB_FETCH_TEST; $executor = \&execute_dumb_fetch_test; $$regression_tests[$si][$ri]{'expected-status-code'} = 200; } elsif ($token eq 'method test') { l(LL_FILE_LOADING, "Method to test: " . $value); $type = METHOD_TEST; $executor = \&execute_method_test; $$regression_tests[$si][$ri]{'expected-status-code'} = 200; } elsif ($token eq 'blocked url') { l(LL_FILE_LOADING, "URL to block-test: " . $value); $executor = \&execute_block_test; $type = BLOCK_TEST; } elsif ($token eq 'url') { l(LL_FILE_LOADING, "Sticky URL to test: " . $value); $type = STICKY_ACTIONS_TEST; $executor = \&execute_sticky_actions_test; } elsif ($token eq 'redirected url') { l(LL_FILE_LOADING, "Redirected URL to test: " . $value); $type = REDIRECT_TEST; $executor = \&execute_redirect_test; } else { die "Incomplete '" . $token . "' support detected."; } $$regression_tests[$si][$ri]{'type'} = $type; $$regression_tests[$si][$ri]{'level'} = $type; $$regression_tests[$si][$ri]{'executor'} = $executor; check_for_forbidden_characters($value); $$regression_tests[$si][$ri]{'data'} = $value; # For function that only get passed single tests $$regression_tests[$si][$ri]{'section-id'} = $si; $$regression_tests[$si][$ri]{'regression-test-id'} = $ri; $$regression_tests[$si][$ri]{'number'} = $number - 1; l(LL_FILE_LOADING, "Regression test " . $number . " (section:" . $si . "):"); } sub mark_matching_tests_for_skipping($) { my $overwrite_condition = shift; our @regression_tests; for (my $s = 0; $s < @regression_tests; $s++) { my $r = 0; while (defined $regression_tests[$s][$r]) { if ($regression_tests[$s][$r]{'data'} eq $overwrite_condition) { my $message = sprintf("Marking test %s for ignoring. Overwrite condition: %s.", $regression_tests[$s][$r]{'number'}, $overwrite_condition); # XXX: Should eventually be downgraded to LL_FILE_LOADING. log_message($message); # XXX: Should eventually get its own key so get_skip_reason() # can tell about the overwrite condition. $regression_tests[$s][$r]{'ignore'} = 1; } $r++; } } } # XXX: Shares a lot of code with load_regression_tests_from_file() # that should be factored out. sub load_action_files ($) { # initialized here our %actions; our @regression_tests; my $actionfiles_ref = shift; my @actionfiles = @{$actionfiles_ref}; my $si = 0; # Section index my $ri = -1; # Regression test index my $count = 0; my $ignored = 0; for my $file_number (0 .. @actionfiles - 1) { my $curl_url = quote($actionfiles[$file_number]); my $actionfile = undef; my $sticky_actions = undef; foreach (@{get_cgi_page_or_else($curl_url)}) { my $no_checks = 0; chomp; if (/

    Contents of Actions File (.*?)/); my ($token, $value) = tokenize($_); next unless defined $token; # Load regression tests if (token_starts_new_test($token)) { # Beginning of new regression test. $ri++; $count++; enlist_new_test(\@regression_tests, $token, $value, $si, $ri, $count); $no_checks = 1; # Already validated by enlist_new_test(). } if ($token =~ /level\s+(\d+)/i) { my $level = $1; register_dependency($level, $value); } if ($token eq 'sticky actions') { # Will be used by each following Sticky URL. $sticky_actions = $value; if ($sticky_actions =~ /{[^}]*\s/) { log_and_die("'Sticky Actions' with whitespace inside the " . "action parameters are currently unsupported."); } } if ($token eq 'overwrite condition') { l(LL_FILE_LOADING, "Detected overwrite condition: " . $value); # We can only skip matching tests that have already # be loaded but that is exactly what we want anyway. mark_matching_tests_for_skipping($value); next; } if ($si == -1 || $ri == -1) { # No beginning of a test detected yet, # so we don't care about any other test # attributes. next; } if ($token eq 'expect header') { l(LL_FILE_LOADING, "Detected expectation: " . $value); $regression_tests[$si][$ri]{'expect-header'} = $value; } elsif ($token eq 'tag') { next if ($ri == -1); my $tag = parse_tag($value); # We already checked in parse_tag() after filtering $no_checks = 1; l(LL_FILE_LOADING, "Detected TAG: " . $tag); # Save tag for all tests in this section do { $regression_tests[$si][$ri]{'tag'} = $tag; } while ($ri-- > 0); $si++; $ri = -1; } elsif ($token eq 'ignore' && $value =~ /Yes/i) { l(LL_FILE_LOADING, "Ignoring section: " . test_content_as_string($regression_tests[$si][$ri])); $regression_tests[$si][$ri]{'ignore'} = 1; $ignored++; } elsif ($token eq 'expect status code') { l(LL_FILE_LOADING, "Expecting status code: " . $value); $regression_tests[$si][$ri]{'expected-status-code'} = $value; } elsif ($token eq 'level') { # XXX: stupid name $value =~ s@(\d+).*@$1@; l(LL_FILE_LOADING, "Level: " . $value); $regression_tests[$si][$ri]{'level'} = $value; } elsif ($token eq 'method') { l(LL_FILE_LOADING, "Method: " . $value); $regression_tests[$si][$ri]{'method'} = $value; } elsif ($token eq 'redirect destination') { l(LL_FILE_LOADING, "Redirect destination: " . $value); $regression_tests[$si][$ri]{'redirect destination'} = $value; } elsif ($token eq 'url') { if (defined $sticky_actions) { die "WTF? Attempted to overwrite Sticky Actions" if defined ($regression_tests[$si][$ri]{'sticky-actions'}); l(LL_FILE_LOADING, "Sticky actions: " . $sticky_actions); $regression_tests[$si][$ri]{'sticky-actions'} = $sticky_actions; } else { log_and_die("Sticky URL without Sticky Actions: $value"); } } else { # We don't use it, so we don't need $no_checks = 1; l(LL_STATUS, "Enabling no_checks for $token") unless $no_checks; } # XXX: Necessary? unless ($no_checks) { check_for_forbidden_characters($value); check_for_forbidden_characters($token); } } } l(LL_FILE_LOADING, "Done loading " . $count . " regression tests." . " Of which " . $ignored. " will be ignored)\n"); } ############################################################################ # # Regression test executing functions # ############################################################################ # Fisher Yates shuffle from Perl's "How do I shuffle an array randomly?" FAQ sub fisher_yates_shuffle ($) { my $deck = shift; my $i = @$deck; while ($i--) { my $j = int rand($i+1); @$deck[$i,$j] = @$deck[$j,$i]; } } sub execute_regression_tests () { our @regression_tests; my $loops = get_cli_option('loops'); my $all_tests = 0; my $all_failures = 0; my $all_successes = 0; unless (@regression_tests) { l(LL_STATUS, "No regression tests found."); return; } l(LL_STATUS, "Executing regression tests ..."); while ($loops-- > 0) { my $successes = 0; my $tests = 0; my $failures; my $skipped = 0; if (cli_option_is_set('shuffle-tests')) { # Shuffle both the test sections and # the tests they contain. # # XXX: With the current data layout, shuffling tests # from different sections isn't possible. # Is this worth changing the layout? fisher_yates_shuffle(\@regression_tests); for (my $s = 0; $s < @regression_tests; $s++) { fisher_yates_shuffle($regression_tests[$s]); } } for (my $s = 0; $s < @regression_tests; $s++) { my $r = 0; while (defined $regression_tests[$s][$r]) { unless (cli_option_is_set('shuffle-tests')) { die "Section id mismatch" if ($s != $regression_tests[$s][$r]{'section-id'}); die "Regression test id mismatch" if ($r != $regression_tests[$s][$r]{'regression-test-id'}); } die "Internal error. Test executor missing." unless defined $regression_tests[$s][$r]{executor}; my $number = $regression_tests[$s][$r]{'number'}; my $skip_reason = get_skip_reason($regression_tests[$s][$r]); if (defined $skip_reason) { my $message = "Skipping test " . $number . ": " . $skip_reason . "."; log_message($message) if (cli_option_is_set('show-skipped-tests')); $skipped++; } else { my $result = $regression_tests[$s][$r]{executor}($regression_tests[$s][$r]); log_result($regression_tests[$s][$r], $result, $tests); $successes += $result; $tests++; sleep(get_cli_option('sleep-time')) if (cli_option_is_set('sleep-time')); } $r++; } } $failures = $tests - $successes; log_message("Executed " . $tests . " regression tests. " . 'Skipped ' . $skipped . '. ' . $successes . " successes, " . $failures . " failures."); $all_tests += $tests; $all_failures += $failures; $all_successes += $successes; } if (get_cli_option('loops') > 1) { log_message("Total: Executed " . $all_tests . " regression tests. " . $all_successes . " successes, " . $all_failures . " failures."); } } sub get_skip_reason ($) { my $test = shift; my $skip_reason = undef; if ($test->{'ignore'}) { $skip_reason = "Ignore flag is set"; } elsif (cli_option_is_set('test-number') and get_cli_option('test-number') != $test->{'number'}) { $skip_reason = "Only executing test " . get_cli_option('test-number'); } else { $skip_reason = level_is_unacceptable($test->{'level'}); } return $skip_reason; } sub level_is_unacceptable ($) { my $level = shift; my $min_level = get_cli_option('min-level'); my $max_level = get_cli_option('max-level'); my $required_level = cli_option_is_set('level') ? get_cli_option('level') : $level; my $reason = undef; if ($required_level != $level) { $reason = "Level doesn't match (" . $level . " != " . $required_level . ")" } elsif ($level < $min_level) { $reason = "Level too low (" . $level . " < " . $min_level . ")"; } elsif ($level > $max_level) { $reason = "Level too high (" . $level . " > " . $max_level . ")"; } else { $reason = dependency_unsatisfied($level); } return $reason; } sub dependency_unsatisfied ($) { my $level = shift; our %dependencies; our @privoxy_config; our %privoxy_features; my $dependency_problem = undef; if (defined ($dependencies{$level}{'config line'})) { my $dependency = $dependencies{$level}{'config line'}; $dependency_problem = "depends on config line matching: '" . $dependency . "'"; foreach (@privoxy_config) { if (/$dependency/) { $dependency_problem = undef; last; } } } if (defined ($dependencies{$level}{'feature status'}) and not defined $dependency_problem) { my $dependency = $dependencies{$level}{'feature status'}; my ($feature, $status) = $dependency =~ /([^\s]*)\s+(Yes|No)/; unless (defined($privoxy_features{$feature}) and ($privoxy_features{$feature} eq $status)) { $dependency_problem = "depends on '" . $feature . "' being set to '" . $status . "'"; } } return $dependency_problem; } sub register_dependency ($$) { my $level = shift; my $dependency = shift; our %dependencies; if ($dependency =~ /config line\s+(.*)/) { $dependencies{$level}{'config line'} = $1; } elsif ($dependency =~ /feature status\s+(.*)/) { $dependencies{$level}{'feature status'} = $1; } else { log_and_die("Didn't recognize dependency: $dependency."); } } sub execute_method_test ($) { my $test = shift; my $buffer_ref; my $status_code; my $method = $test->{'data'}; my $curl_parameters = ''; my $expected_status_code = $test->{'expected-status-code'}; $curl_parameters .= '--request ' . $method . ' '; # Don't complain about the 'missing' body $curl_parameters .= '--head ' if ($method =~ /^HEAD$/i); $curl_parameters .= PRIVOXY_CGI_URL; $buffer_ref = get_page_with_curl($curl_parameters); $status_code = get_status_code($buffer_ref); return check_status_code_result($status_code, $expected_status_code); } sub execute_redirect_test ($) { my $test = shift; my $buffer_ref; my $status_code; my $curl_parameters = ''; my $url = $test->{'data'}; my $redirect_destination; my $expected_redirect_destination = $test->{'redirect destination'}; # XXX: Check if a redirect actually applies before doing the request. # otherwise the test may hit a real server in failure cases. $curl_parameters .= '--head '; $curl_parameters .= quote($url); $buffer_ref = get_page_with_curl($curl_parameters); $status_code = get_status_code($buffer_ref); if ($status_code ne "302") { l(LL_VERBOSE_FAILURE, "Ooops. Expected redirect to: '" . $expected_redirect_destination . "' but got a response with status code: " . $status_code); return 0; } foreach (@{$buffer_ref}) { if (/^Location: (.*)\r\n/) { $redirect_destination = $1; last; } } my $success = ($redirect_destination eq $expected_redirect_destination); unless ($success) { l(LL_VERBOSE_FAILURE, "Ooops. Expected redirect to: '" . $expected_redirect_destination . "' but the redirect leads to: '" . $redirect_destination. "'"); } return $success; } sub execute_dumb_fetch_test ($) { my $test = shift; my $buffer_ref; my $status_code; my $curl_parameters = ''; my $expected_status_code = $test->{'expected-status-code'}; if (defined $test->{method}) { $curl_parameters .= '--request ' . quote($test->{method}) . ' '; } if ($test->{type} == TRUSTED_CGI_REQUEST) { $curl_parameters .= '--referer ' . quote(PRIVOXY_CGI_URL) . ' '; } $curl_parameters .= quote($test->{'data'}); $buffer_ref = get_page_with_curl($curl_parameters); $status_code = get_status_code($buffer_ref); return check_status_code_result($status_code, $expected_status_code); } sub execute_block_test ($) { my $test = shift; my $url = $test->{'data'}; my $final_results = get_final_results($url); return defined $final_results->{'+block'}; } sub execute_sticky_actions_test ($) { my $test = shift; my $url = $test->{'data'}; my $verified_actions = 0; # XXX: splitting currently doesn't work for actions whose parameters contain spaces. my @sticky_actions = split(/\s+/, $test->{'sticky-actions'}); my $final_results = get_final_results($url); foreach my $sticky_action (@sticky_actions) { if (defined $final_results->{$sticky_action}) { # Exact match $verified_actions++; } elsif ($sticky_action =~ /-.*\{/) { # Disabled multi actions aren't explicitly listed as # disabled and thus have to be checked by verifying # that they aren't enabled. $verified_actions++; } else { l(LL_VERBOSE_FAILURE, "Ooops. '$sticky_action' is not among the final results."); } } return $verified_actions == @sticky_actions; } sub get_final_results ($) { my $url = shift; my $curl_parameters = ''; my %final_results = (); my $final_results_reached = 0; die "Unacceptable characters in $url" if $url =~ m@[\\'"]@; # XXX: should be URL-encoded properly $url =~ s@%@%25@g; $url =~ s@\s@%20@g; $url =~ s@&@%26@g; $url =~ s@:@%3A@g; $url =~ s@/@%2F@g; $curl_parameters .= quote(PRIVOXY_CGI_URL . 'show-url-info?url=' . $url); foreach (@{get_cgi_page_or_else($curl_parameters)}) { $final_results_reached = 1 if (m@

    Final results:

    @); next unless ($final_results_reached); last if (m@@); # Privoxy versions before 3.0.16 add a space # between action name and parameters, therefore # the " ?". if (m@
    ([-+])([^>]*)(?: ?(\{.*\}))?@) { my $action = $1.$2; my $parameter = $3; if (defined $parameter) { # In case the caller needs to check # the action and its parameter $final_results{$action . $parameter} = 1; } # In case the action doesn't have parameters # or the caller doesn't care for the parameter. $final_results{$action} = 1; } } return \%final_results; } sub check_status_code_result ($$) { my $status_code = shift; my $expected_status_code = shift; my $result = 0; unless (defined $status_code) { # XXX: should probably be caught earlier. l(LL_VERBOSE_FAILURE, "Ooops. We expected status code " . $expected_status_code . ", but didn't get any status code at all."); } elsif ($expected_status_code == $status_code) { $result = 1; l(LL_VERBOSE_SUCCESS, "Yay. We expected status code " . $expected_status_code . ", and received: " . $status_code . '.'); } elsif (cli_option_is_set('fuzzer-feeding') and $status_code == 123) { l(LL_VERBOSE_FAILURE, "Oh well. Status code lost while fuzzing. Can't check if it was " . $expected_status_code . '.'); } else { l(LL_VERBOSE_FAILURE, "Ooops. We expected status code " . $expected_status_code . ", but received: " . $status_code . '.'); } return $result; } sub execute_client_header_regression_test ($) { my $test = shift; my $buffer_ref; my $header; $buffer_ref = get_show_request_with_curl($test); $header = get_header($buffer_ref, $test); return check_header_result($test, $header); } sub execute_server_header_regression_test ($) { my $test = shift; my $buffer_ref; my $header; $buffer_ref = get_head_with_curl($test); $header = get_server_header($buffer_ref, $test); return check_header_result($test, $header); } sub interpret_result ($) { my $success = shift; return $success ? "Success" : "Failure"; } sub check_header_result ($$) { my $test = shift; my $header = shift; my $expect_header = $test->{'expect-header'}; my $success = 0; if ($expect_header eq 'NO CHANGE') { $success = (defined($header) and $header eq $test->{'data'}); unless ($success) { $header = "REMOVAL" unless defined $header; l(LL_VERBOSE_FAILURE, "Ooops. Got: '" . $header . "' while expecting: '" . $expect_header . "'"); } } elsif ($expect_header eq 'REMOVAL') { # XXX: Use more reliable check here and make sure # the header has a different name. $success = not (defined($header) and $header eq $test->{'data'}); unless ($success) { l(LL_VERBOSE_FAILURE, "Ooops. Expected removal but: '" . $header . "' is still there."); } } elsif ($expect_header eq 'SOME CHANGE') { $success = (defined($header) and $header ne $test->{'data'}); unless ($success) { $header = "REMOVAL" unless defined $header; l(LL_VERBOSE_FAILURE, "Ooops. Got: '" . $header . "' while expecting: SOME CHANGE"); } } else { $success = (defined($header) and $header eq $expect_header); unless ($success) { $header = "No matching header" unless defined $header; # XXX: No header detected to be precise l(LL_VERBOSE_FAILURE, "Ooops. Got: '" . $header . "' while expecting: '" . $expect_header . "'"); } } return $success; } sub get_header_name ($) { my $header = shift; $header =~ s@(.*?: ).*@$1@; return $header; } sub get_header ($$) { our $filtered_request = ''; my $buffer_ref = shift; my $test = shift; my @buffer = @{$buffer_ref}; my $expect_header = $test->{'expect-header'}; die "get_header called with no expect header" unless defined $expect_header; my $line; my $processed_request_reached = 0; my $read_header = 0; my $processed_request = ''; my $header; my $header_to_get; if ($expect_header eq 'REMOVAL' or $expect_header eq 'NO CHANGE' or $expect_header eq 'SOME CHANGE') { $expect_header = $test->{'data'}; } $header_to_get = get_header_name($expect_header); foreach (@buffer) { # Skip everything before the Processed request if (/Processed Request/) { $processed_request_reached = 1; next; } next unless $processed_request_reached; # End loop after the Processed request last if (/<\/pre>/); # Ditch tags and leading/trailing white space. s@^\s*<.*?>@@g; s@\s*$@@g; # Decode characters we care about. s@"@"@g; $filtered_request .= "\n" . $_; if (/^$header_to_get/) { $read_header = 1; $header = $_; last; } } return $header; } sub get_server_header ($$) { my $buffer_ref = shift; my $test = shift; my @buffer = @{$buffer_ref}; my $expect_header = $test->{'expect-header'}; my $header; my $header_to_get; # XXX: Should be caught before starting to test. log_and_die("No expect header for test " . $test->{'number'}) unless defined $expect_header; if ($expect_header eq 'REMOVAL' or $expect_header eq 'NO CHANGE' or $expect_header eq 'SOME CHANGE') { $expect_header = $test->{'data'}; } $header_to_get = get_header_name($expect_header); foreach (@buffer) { # XXX: should probably verify that the request # was actually answered by Fellatio. if (/^$header_to_get/) { $header = $_; $header =~ s@\s*$@@g; last; } } return $header; } sub get_status_code ($) { my $buffer_ref = shift; my @buffer = @{$buffer_ref}; foreach (@buffer) { if (/^HTTP\/\d\.\d (\d{3})/) { return $1; } else { return '123' if cli_option_is_set('fuzzer-feeding'); chomp; log_and_die('Unexpected buffer line: "' . $_ . '"'); } } } sub get_test_keys () { return ('tag', 'data', 'expect-header', 'ignore'); } # XXX: incomplete sub test_content_as_string ($) { my $test = shift; my $s = "\n\t"; foreach my $key (get_test_keys()) { $test->{$key} = 'Not set' unless (defined $test->{$key}); } $s .= 'Tag: ' . $test->{'tag'}; $s .= "\n\t"; $s .= 'Set header: ' . $test->{'data'}; # XXX: adjust for other test types $s .= "\n\t"; $s .= 'Expected header: ' . $test->{'expect-header'}; $s .= "\n\t"; $s .= 'Ignore: ' . $test->{'ignore'}; return $s; } sub fuzz_header($) { my $header = shift; my $white_space = int(rand(2)) - 1 ? " " : "\t"; $white_space = $white_space x (1 + int(rand(5))); # Only fuzz white space before the first quoted token. # (Privoxy doesn't touch white space inside quoted tokens # and modifying it would cause the tests to fail). $header =~ s@(^[^"]*?)\s@$1$white_space@g; return $header; } ############################################################################ # # HTTP fetch functions # ############################################################################ sub get_cgi_page_or_else ($) { my $cgi_url = shift; my $content_ref = get_page_with_curl($cgi_url); my $status_code = get_status_code($content_ref); if (200 != $status_code) { my $log_message = "Failed to fetch Privoxy CGI Page. " . "Received status code ". $status_code . " while only 200 is acceptable."; if (cli_option_is_set('fuzzer-feeding')) { $log_message .= " Ignored due to fuzzer feeding."; l(LL_SOFT_ERROR, $log_message) } else { log_and_die($log_message); } } return $content_ref; } # XXX: misleading name sub get_show_request_with_curl ($) { our $privoxy_cgi_url; my $test = shift; my $curl_parameters = ' '; my $header = $test->{'data'}; if (cli_option_is_set('header-fuzzing')) { $header = fuzz_header($header); } # Enable the action to test $curl_parameters .= '-H \'X-Privoxy-Control: ' . $test->{'tag'} . '\' '; # The header to filter $curl_parameters .= '-H \'' . $header . '\' '; $curl_parameters .= ' '; $curl_parameters .= $privoxy_cgi_url; $curl_parameters .= 'show-request'; return get_cgi_page_or_else($curl_parameters); } sub get_head_with_curl ($) { our $fellatio_url = FELLATIO_URL; my $test = shift; my $curl_parameters = ' '; # Enable the action to test $curl_parameters .= '-H \'X-Privoxy-Control: ' . $test->{'tag'} . '\' '; # The header to filter $curl_parameters .= '-H \'X-Gimme-Head-With: ' . $test->{'data'} . '\' '; $curl_parameters .= '--head '; $curl_parameters .= ' '; $curl_parameters .= $fellatio_url; return get_page_with_curl($curl_parameters); } sub get_page_with_curl ($) { our $proxy; my $parameters = shift; my @buffer; my $curl_line = CURL; my $retries_left = get_cli_option('retries') + 1; my $failure_reason; if (defined $proxy) { $curl_line .= ' --proxy ' . quote($proxy); } # We want to see the HTTP status code $curl_line .= " --include "; # Let Privoxy emit two log messages less. $curl_line .= ' -H \'Proxy-Connection:\' ' unless $parameters =~ /Proxy-Connection:/; $curl_line .= ' -H \'Connection: close\' ' unless $parameters =~ /Connection:/; # We don't care about fetch statistic. $curl_line .= " -s "; # We do care about the failure reason if any. $curl_line .= " -S "; # We want to advertise ourselves $curl_line .= " --user-agent '" . PRT_VERSION . "' "; # We aren't too patient $curl_line .= " --max-time '" . get_cli_option('max-time') . "' "; $curl_line .= $parameters; # XXX: still necessary? $curl_line .= ' 2>&1'; l(LL_PAGE_FETCHING, "Executing: " . $curl_line); do { @buffer = `$curl_line`; if ($?) { log_and_die("Executing '$curl_line' failed.") unless @buffer; $failure_reason = array_as_string(\@buffer); chomp $failure_reason; l(LL_SOFT_ERROR, "Fetch failure: '" . $failure_reason . $! ."'"); } } while ($? && --$retries_left); unless ($retries_left) { log_and_die("Running curl failed " . get_cli_option('retries') . " times in a row. Last error: '" . $failure_reason . "'."); } return \@buffer; } ############################################################################ # # Log functions # ############################################################################ sub array_as_string ($) { my $array_ref = shift; my $string = ''; foreach (@{$array_ref}) { $string .= $_; } return $string; } sub show_test ($) { my $test = shift; log_message('Test is:' . test_content_as_string($test)); } # Conditional log sub l ($$) { our $log_level; my $this_level = shift; my $message = shift; log_message($message) if ($log_level & $this_level); } sub log_and_die ($) { my $message = shift; log_message('Oh noes. ' . $message . ' Fatal error. Exiting.'); exit; } sub log_message ($) { my $message = shift; our $logfile; our $no_logging; our $leading_log_date; our $leading_log_time; my $time_stamp = ''; my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime time; if ($leading_log_date || $leading_log_time) { if ($leading_log_date) { $year += 1900; $mon += 1; $time_stamp = sprintf("%i-%.2i-%.2i", $year, $mon, $mday); } if ($leading_log_time) { $time_stamp .= ' ' if $leading_log_date; $time_stamp.= sprintf("%.2i:%.2i:%.2i", $hour, $min, $sec); } $message = $time_stamp . ": " . $message; } printf("%s\n", $message); } sub log_result ($$) { our $filtered_request; my $test = shift; my $result = shift; my $number = shift; my $message = sprintf("%s for test %d", interpret_result($result), $test->{'number'}); if (cli_option_is_set('verbose')) { $message .= sprintf(" (%d/%d/%d)", $number, $test->{'section-id'}, $test->{'regression-test-id'}); } $message .= '. '; if ($test->{'type'} == CLIENT_HEADER_TEST) { $message .= 'Header '; $message .= quote($test->{'data'}); $message .= ' and tag '; $message .= quote($test->{'tag'}); } elsif ($test->{'type'} == SERVER_HEADER_TEST) { $message .= 'Request Header '; $message .= quote($test->{'data'}); $message .= ' and tag '; $message .= quote($test->{'tag'}); } elsif ($test->{'type'} == DUMB_FETCH_TEST) { $message .= 'URL '; $message .= quote($test->{'data'}); $message .= ' and expected status code '; $message .= quote($test->{'expected-status-code'}); } elsif ($test->{'type'} == TRUSTED_CGI_REQUEST) { $message .= 'CGI URL '; $message .= quote($test->{'data'}); $message .= ' and expected status code '; $message .= quote($test->{'expected-status-code'}); } elsif ($test->{'type'} == METHOD_TEST) { $message .= 'HTTP method '; $message .= quote($test->{'data'}); $message .= ' and expected status code '; $message .= quote($test->{'expected-status-code'}); } elsif ($test->{'type'} == BLOCK_TEST) { $message .= 'Supposedly-blocked URL: '; $message .= quote($test->{'data'}); } elsif ($test->{'type'} == STICKY_ACTIONS_TEST) { $message .= 'Sticky Actions: '; $message .= quote($test->{'sticky-actions'}); $message .= ' and URL: '; $message .= quote($test->{'data'}); } elsif ($test->{'type'} == REDIRECT_TEST) { $message .= 'Redirected URL: '; $message .= quote($test->{'data'}); $message .= ' and redirect destination: '; $message .= quote($test->{'redirect destination'}); } else { die "Incomplete support for test type " . $test->{'type'} . " detected."; } log_message($message) if (!$result or cli_option_is_set('verbose')); } sub quote ($) { my $s = shift; return '\'' . $s . '\''; } sub print_version () { printf PRT_VERSION . "\n"; } sub list_test_types () { my %test_types = ( 'Client header test' => CLIENT_HEADER_TEST, 'Server header test' => 2, 'Dumb fetch test' => 3, 'Method test' => 4, 'Sticky action test' => 5, 'Trusted CGI test' => 6, 'Block test' => 7, 'Redirect test' => 108, ); print "\nThe supported test types and their default levels are:\n"; foreach my $test_type (sort { $test_types{$a} <=> $test_types{$b} } keys %test_types) { printf " %-20s -> %3.d\n", $test_type, $test_types{$test_type}; } } sub help () { our %cli_options; print_version(); print << " EOF" Options and their default values if they have any: [--debug $cli_options{'debug'}] [--forks $cli_options{'forks'}] [--fuzzer-address] [--fuzzer-feeding] [--help] [--header-fuzzing] [--level] [--local-test-file] [--loops $cli_options{'loops'}] [--max-level $cli_options{'max-level'}] [--max-time $cli_options{'max-time'}] [--min-level $cli_options{'min-level'}] [--privoxy-address] [--retries $cli_options{'retries'}] [--show-skipped-tests] [--shuffle-tests] [--sleep-time $cli_options{'sleep-time'}] [--test-number] [--verbose] [--version] EOF ; list_test_types(); print << " EOF" Try "perldoc $0" for more information EOF ; exit(0); } sub init_cli_options () { our %cli_options; our $log_level; $cli_options{'debug'} = $log_level; $cli_options{'forks'} = CLI_FORKS; $cli_options{'loops'} = CLI_LOOPS; $cli_options{'max-level'} = CLI_MAX_LEVEL; $cli_options{'max-time'} = CLI_MAX_TIME; $cli_options{'min-level'} = CLI_MIN_LEVEL; $cli_options{'sleep-time'}= CLI_SLEEP_TIME; $cli_options{'retries'} = CLI_RETRIES; } sub parse_cli_options () { our %cli_options; our $log_level; init_cli_options(); GetOptions ( 'debug=i' => \$cli_options{'debug'}, 'forks=i' => \$cli_options{'forks'}, 'fuzzer-address=s' => \$cli_options{'fuzzer-address'}, 'fuzzer-feeding' => \$cli_options{'fuzzer-feeding'}, 'header-fuzzing' => \$cli_options{'header-fuzzing'}, 'help' => \&help, 'level=i' => \$cli_options{'level'}, 'local-test-file=s' => \$cli_options{'local-test-file'}, 'loops=i' => \$cli_options{'loops'}, 'max-level=i' => \$cli_options{'max-level'}, 'max-time=i' => \$cli_options{'max-time'}, 'min-level=i' => \$cli_options{'min-level'}, 'privoxy-address=s' => \$cli_options{'privoxy-address'}, 'retries=i' => \$cli_options{'retries'}, 'shuffle-tests' => \$cli_options{'shuffle-tests'}, 'show-skipped-tests' => \$cli_options{'show-skipped-tests'}, 'sleep-time=i' => \$cli_options{'sleep-time'}, 'test-number=i' => \$cli_options{'test-number'}, 'verbose' => \$cli_options{'verbose'}, 'version' => sub {print_version && exit(0)} ) or exit(1); $log_level |= $cli_options{'debug'}; } sub cli_option_is_set ($) { our %cli_options; my $cli_option = shift; return defined $cli_options{$cli_option}; } sub get_cli_option ($) { our %cli_options; my $cli_option = shift; die "Unknown CLI option: $cli_option" unless defined $cli_options{$cli_option}; return $cli_options{$cli_option}; } sub init_proxy_settings($) { my $choice = shift; our $proxy = undef; if (($choice eq 'fuzz-proxy') and cli_option_is_set('fuzzer-address')) { $proxy = get_cli_option('fuzzer-address'); } if ((not defined $proxy) or ($choice eq 'vanilla-proxy')) { if (cli_option_is_set('privoxy-address')) { $proxy .= get_cli_option('privoxy-address'); } } } sub start_forks($) { my $forks = shift; log_and_die("Invalid --fork value: " . $forks . ".") if ($forks < 0); foreach my $fork (1 .. $forks) { log_message("Starting fork $fork"); my $pid = fork(); if (defined $pid && !$pid) { return; } } } sub main () { init_our_variables(); parse_cli_options(); init_proxy_settings('vanilla-proxy'); load_regression_tests(); init_proxy_settings('fuzz-proxy'); start_forks(get_cli_option('forks')) if cli_option_is_set('forks'); execute_regression_tests(); } main(); =head1 NAME B - A regression test "framework" for Privoxy. =head1 SYNOPSIS B [B<--debug bitmask>] [B<--forks> forks] [B<--fuzzer-feeding>] [B<--fuzzer-feeding>] [B<--help>] [B<--level level>] [B<--local-test-file testfile>] [B<--loops count>] [B<--max-level max-level>] [B<--max-time max-time>] [B<--min-level min-level>] B<--privoxy-address proxy-address> [B<--retries retries>] [B<--test-number test-number>] [B<--show-skipped-tests>] [B<--sleep-time> seconds] [B<--verbose>] [B<--version>] =head1 DESCRIPTION Privoxy-Regression-Test is supposed to one day become a regression test suite for Privoxy. It's not quite there yet, however, and can currently only test header actions, check the returned status code for requests to arbitrary URLs and verify which actions are applied to them. Client header actions are tested by requesting B and checking whether or not Privoxy modified the original request as expected. The original request contains both the header the action-to-be-tested acts upon and an additional tagger-triggering header that enables the action to test. Applied actions are checked through B. =head1 CONFIGURATION FILE SYNTAX Privoxy-Regression-Test's configuration is embedded in Privoxy action files and loaded through Privoxy's web interface. It makes testing a Privoxy version running on a remote system easier and should prevent you from updating your tests without updating Privoxy's configuration accordingly. A client-header-action test section looks like this: # Set Header = Referer: http://www.example.org.zwiebelsuppe.exit/ # Expect Header = Referer: http://www.example.org/ {+client-header-filter{hide-tor-exit-notation} -hide-referer} TAG:^client-header-filter\{hide-tor-exit-notation\}$ The example above causes Privoxy-Regression-Test to set the header B and to expect it to be modified to B. When testing this section, Privoxy-Regression-Test will set the header B causing the B tagger to create the tag B which will finally cause Privoxy to enable the action section. Note that the actions itself are only used by Privoxy, Privoxy-Regression-Test ignores them and will be happy as long as the expectations are satisfied. A fetch test looks like this: # Fetch Test = http://p.p/user-manual # Expect Status Code = 302 It tells Privoxy-Regression-Test to request B and to expect a response with the HTTP status code B<302>. Obviously that's not a very thorough test and mainly useful to get some code coverage for Valgrind or to verify that the templates are installed correctly. If you want to test CGI pages that require a trusted referer, you can use: # Trusted CGI Request = http://p.p/edit-actions It works like ordinary fetch tests, but sets the referer header to a trusted value. If no explicit status code expectation is set, B<200> is used. To verify that a URL is blocked, use: # Blocked URL = http://www.example.com/blocked To verify that a specific set of actions is applied to an URL, use: # Sticky Actions = +block{foo} +handle-as-empty-document -handle-as-image # URL = http://www.example.org/my-first-url The sticky actions will be checked for all URLs below it until the next sticky actions directive. To verify that requests for a URL get redirected, use: # Redirected URL = http://www.example.com/redirect-me # Redirect Destination = http://www.example.org/redirected To skip a test, add the following line: # Ignore = Yes The difference between a skipped test and a removed one is that removing a test affects the numbers of the following tests, while a skipped test is still loaded and thus keeps the test numbers unchanged. Sometimes user modifications intentionally conflict with tests in the default configuration and thus cause test failures. Adding the Ignore directive to the failing tests works but is inconvenient as the directive is likely to get lost with the next update. Overwrite conditions are an alternative and can be added in any action file as long as the come after the test that is expected to fail. They causes all previous tests a matching the condition to be skipped. It is recommended to put the overwrite condition below the custom Privoxy section that causes the expected test failure and before the custom test that verifies that tests the now expected behaviour. Example: # The following section is expected to overwrite a section in # default.action, whose effect is tested. Thus also disable the # test that is now expected to fail and add a new one. # {+block{Facebook makes Firefox even more unstable. Do not want.}} # Overwrite condition = http://apps.facebook.com/onthefarm/track.php?creative=&cat=friendvisit&subcat=weeds&key=a789a971dc687bee4c20c044834fabdd&next=index.php%3Fref%3Dnotif%26visitId%3D898835505 # Blocked URL = http://apps.facebook.com/ .facebook./ =head1 TEST LEVELS All tests have test levels to let the user control which ones to execute (see I below). Test levels are either set with the B directive, or implicitly through the test type. Redirect tests default to level 108, block tests to level 7, fetch tests to level 6, "Sticky Actions" tests default to level 5, tests for trusted CGI requests to level 3 and client-header-action tests to level 1. The current redirect test level is above the default max-level value as failed tests will result in outgoing connections. Use the B<--max-level> option to run them as well. =head1 OPTIONS B<--debug bitmask> Add the bitmask provided as integer to the debug settings. B<--forks forks> Number of forks to start before executing the regression tests. This is mainly useful for stress-testing. B<--fuzzer-address> Listening address used when executing the regression tests. Useful to make sure that the requests to load the regression tests don't fail due to fuzzing. B<--fuzzer-feeding> Ignore some errors that would otherwise cause Privoxy-Regression-Test to abort the test because they shouldn't happen in normal operation. This option is intended to be used if Privoxy-Regression-Test is only used to feed a fuzzer in which case there's a high chance that Privoxy gets an invalid request and returns an error message. B<--help> Shows available command line options. B<--header-fuzzing> Modifies linear white space in headers in a way that should not affect the test result. B<--level level> Only execute tests with the specified B. B<--local-test-file test-file> Do not get the tests through Privoxy's web interface, but use a single local file. Not recommended for testing Privoxy, but can be useful to "misappropriate" Privoxy-Regression-Test to test other stuff, like webserver configurations. B<--loop count> Loop through the regression tests B times. Useful to feed a fuzzer, or when doing stress tests with several Privoxy-Regression-Test instances running at the same time. B<--max-level max-level> Only execute tests with a B below or equal to the numerical B. B<--max-time max-time> Give Privoxy B seconds to return data. Increasing the default may make sense when Privoxy is run through Valgrind, decreasing the default may make sense when Privoxy-Regression-Test is used to feed a fuzzer. B<--min-level min-level> Only execute tests with a B above or equal to the numerical B. B<--privoxy-address proxy-address> Privoxy's listening address. If it's not set, the value of the environment variable http_proxy will be used. B has to be specified in http_proxy syntax. B<--retries retries> Retry B times. B<--test-number test-number> Only run the test with the specified number. B<--show-skipped-tests> Log skipped tests even if verbose mode is off. B<--shuffle-tests> Shuffle test sections and their tests before executing them. When combined with B<--forks>, this can increase the chances of detecting race conditions. Of course some problems are easier to detect without this option. B<--sleep-time seconds> Wait B between tests. Useful when debugging issues with systems that don't log with millisecond precision. B<--verbose> Log successful tests as well. By default only the failures are logged. B<--version> Print version and exit. The second dash is optional, options can be shortened, as long as there are no ambiguities. =head1 PRIVOXY CONFIGURATION Privoxy-Regression-Test is shipped with B which aims to test all official client-header modifying actions and can be used to verify that the templates and the user manual files are installed correctly. To use it, it has to be copied in Privoxy's configuration directory, and afterwards referenced in Privoxy's configuration file with the line: actionsfile regression-tests.action In general, its tests are supposed to work without changing any other action files, unless you already added lots of taggers yourself. If you are using taggers that cause problems, you might have to temporary disable them for Privoxy's CGI pages. Some of the regression tests rely on Privoxy features that may be disabled in your configuration. Tests with a level below 7 are supposed to work with all Privoxy configurations (provided you didn't build with FEATURE_GRACEFUL_TERMINATION). Tests with level 9 require Privoxy to deliver the User Manual, tests with level 12 require the CGI editor to be enabled. =head1 CAVEATS Expect the configuration file syntax to change with future releases. =head1 LIMITATIONS As Privoxy's B page only shows client headers, Privoxy-Regression-Test can't use it to test Privoxy actions that modify server headers. As Privoxy-Regression-Test relies on Privoxy's tag feature to control the actions to test, it currently only works with Privoxy 3.0.7 or later. At the moment Privoxy-Regression-Test fetches Privoxy's configuration page through I(1), therefore you have to have I installed, otherwise you won't be able to run Privoxy-Regression-Test in a meaningful way. =head1 SEE ALSO privoxy(1) curl(1) =head1 AUTHOR Fabian Keil =cut privoxy-3.0.21-stable/./tools/url-pattern-translator.pl000750 001751 001751 00000006672 11217474274 022151 0ustar00fkfk000000 000000 #!/usr/bin/perl ############################################################################ # # url-pattern-translator # # Filters Privoxy action files and changes old-school URL patterns to # use extended regular expressions for the host as well. # # While it works good enough to satisfy the regression tests in # default.action.master, it isn't perfect and you should double-check # the output and keep backups of your old action files. # # Usage: # # url-pattern-translator.pl old.action > new.action # # Only convert your files once, or, as RoboCop used to say, # there will be... trouble. # # $Id: url-pattern-translator.pl,v 1.4 2009/06/21 18:15:24 fabiankeil Exp $ # # Copyright (c) 2008 Fabian Keil # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ############################################################################ use strict; use warnings; sub p ($) { my $message = shift; print $message . "\n"; } sub convert_host_pattern ($) { my $host_pattern = shift; my $hp = $host_pattern; $hp =~ s@\s@@g; if ($hp =~ m@^\.@) { # Not left-anchored # # XXX: This is somewhat ugly and while it's # the equivalent pattern in most cases # \. should be good enough. $hp =~ s@^\.@(^|.)@; } else { # left-anchored $hp = '^' . $hp; } # Match-all syntax has changed ... $hp =~ s@\*@[^.]*@g; # Extended host patterns are right-anchored by default $hp =~ s@\.$@(\..*)?@; # Literal dots have to be escaped $hp =~ s@((?) { chomp; if (looks_interesting($_)) { if (m@^([^/]+)(/.*)$@) { $host = $1; $path = $2; $host = convert_host_pattern($host); $_ = $host . $path; } elsif (m@^([^/]*)$@) { $host = $1; $host = convert_host_pattern($host); $_ = $host; } } p($_); } } main(); privoxy-3.0.21-stable/./TODO000640 001751 001751 00000031062 12114163742 014455 0ustar00fkfk000000 000000 $Id: TODO,v 1.79 2013/03/01 17:39:46 fabiankeil Exp $ Some Privoxy-related tasks, sorted by the time they have been added, not by priority. The latest version should be available at: http://ijbswa.cvs.sourceforge.net/viewvc/ijbswa/current/TODO 1) Add some regression tests. Filters should be tested automatically (variables too). Could probably reuse large parts of Privoxy-Filter-Test. Note that there is currently work in progress to leverage curl's test suite which could be used for this as well. 3) Fix some more XXX: comments. 6) Remove actions that aren't needed anymore: content-type-overwrite should probably stay as it's also used by some of the CGI pages (XXX: name them). crunch-client-header and crunch-server-header should probably go, their only advantage is that their search strings can be controlled through the CGI pages, other than that they only have disadvantages. crunch-if-none-match can be replaced with a header filter. prevent-compression has a misleading name and could be replaced with a header filter. 7) force-text-mode has a stupid name and should probably be renamed to force-filter-mode. 8) handle-as-empty-document and handle-as-image should be merged to something like handle-as{something} to prevent them from being activated at the same time. 10) There's a bug in the CGI editor that turns the first section's "Insert new section below" into a "Insert new section above" button. 11) CGI templates should use semantically-correct HTML and scale properly. 12) Support pipelining for outgoing connections. 14) Allow to filter POST parameters. 15) If trusted CGI pages are requested without trusted referrer, set the status code to 403 instead of 200. 16) Filter SSL encrypted content as well. At the beginning we could use a unencrypted connection between client and Privoxy, and use an encrypted connection between Privoxy and the server. This should be good enough for most of the content the user would want to filter. 19) enable-forward-fallback. Syntax? Suggested by K.R. 21) User Manual delivery doesn't accept multiple slashes. Should it? 22) Verify action files properly (Including arguments) and act accordingly (should probably intercept all requests with a "Invalid option foo detected" CGI page). 23) Do the same in case of syntax errors in the configuration file, instead of just exiting or ignoring the problem. 25) Handle multiple filters with the same name better. Reject them? 26) Let show-url-info detect clearly invalid URLs. 27) Make errno logging less thread-unsafe. Verify that it's really an improvement. 28) Don't take default ports in case of invalid forwarding ports. 31) If a string action foo is disabled csp->action->string[ACTION_STRING_FOO] doesn't necessarily contain NULL, but may contain the string of an enabled foo action in an overruled section. Is it a bug? Does it matter? 32) In case of forwarding failures with socks port == 9050, show extra info about Tor (the whole FAQ entry?). 36) Unload unused action files directly, even if they are disabled without replacement. 38) In the final results, explicitly list disabled multi actions with their parameters. Not as trivial as it sounds. 40) When running in daemon mode, Privoxy's working directory is '/' which means it may not have permissions to dump core when necessary. Figure out a way to solve this. Introduce a cwd config option? 41) Change documentation framework to one that works cross-platform. Evaluate WML. 42) Add a DTrace USDT provider. Now that FreeBSD has userland DTrace support there's no longer any reason not to. 43) Write a tool to check URL patterns against URLs in the log file. This could be included in Privoxy-Regression-Test. 44) Privoxy-Log-Parser: Consider highlighting "Connection" in: 23:13:03.506 283b6100 Header: Replaced: 'Connection: Keep-Alive' with 'Connection: close' 50) Investigate possible PCRS template speedup when searching macros with strstr() before compiling pcrs commands. Investigated, needs some restructuring but is probably worth it. 51) Make user-manual directive more generic to allow serving the FAQ and other stuff, too. Consider changing the port for "same origin policy" issues. 53) Find a more reliable hoster. Involves finding out what our requirements are and which SF alternatives fulfil them. It would probably also make sense to look into what other projects did when migrating away from SF. 54) Move away from CVS to a more modern revision control system. Find out if there are any objection against going with Git. Using Git would also have the advantage that SF now pretents to support it, so we could do it independently from 53). 55) Apply for Coverity scans: http://scan.coverity.com/ 56) Apply for the "free online access for qualified open-source software projects" for the Co-Advisor HTTP compliance tests: http://coad.measurement-factory.com/details.html#pricing 57) Allow piping into external programs to allow more powerful filters and policy decisions. Incomplete support available in Fabian's popen branch. 58) Move more template strings from the code into the actual templates. 59) Import the German template translation. 60) Ask the Russian translators for input on how to make their life easier. 61) Consider (optionally?) skipping the hostname comparison when checking if a connections that goes to a HTTP proxy can be reused. Do all HTTP proxy support that? Is it worth it? 63) Reject clearly too large requests earlier? 64) Use proper copyright attribution. "Privoxy Developers" is no legal entity. 65) Polish Website. Probably involves ditching the Docbook mess in favour of wml. There are already several threads in the mailinglist archives about this. See also #41. 66) Stop hard-coding the number of action and filter files. 67) Clean up source code directory layout. Depends on 54 so we don't lose the revision history. 68) Use standard make syntax so we don't depend on GNU make. 69) Update autoconf setup (or move away from it). 70) If the server connection is reset but the headers are received, consider passing the mess to the client instead of showing the connect-failed template. Relates to #2698674. 74) Let Privoxy-Regression-Test optionally check that action sections which disable actions actually are preceded by sections that enable said actions. 75) Create a tool that creates Privoxy action (and filter?) files out of adblock files. Could be implemented as option for url-pattern-translator.pl. 76) Cache DNS responses. Note that this has been requested several times by users, but is not a developer priority. If you care about this, feel free to submit patches. 77) Allow to configure the IP address used in outgoing connections. 78) Allow to optionally use pcre's DFA algorithm. 79) Evaluate pcre alternatives. 80) Change FEATURE_EXTENDED_HOST_PATTERNS to support both extended and vanilla host patterns at the same time. Note that the requirement is to allow the user to decide if the domain pattern should be interpreted as regex or traditional host pattern and if it's not obvious that the user made any decision, default to the latter. Possible solutions would be: 1. An always-use-regex-domain-patterns config option 2. An enable-regex-domain-patterns-for-this-action-file option 3. An enable-regex-domain-patterns-for-this-action-file-until-the-user-says-otherwise option 4. A treat-the-domain-pattern-in-this-line-as-regex(-or-not) option 5. Combinations of the options above With 2+4, 3+4 or 2+3+4 being the preferences until further discussion. 82) Detect if the system time goes back in time let the user know if it caused any connections to get closed. 84) Flesh out the user-manual delivery to serve pages from other directories, too. 85) Once #84 is done, write a script that populates a directory with various common third-party icons (stumbleupon.png, facebook.png ...) and redirect requests for them to Privoxy. 86) Add a server-body-tagger action. This is trivial as as all the functionallity required to do it already exists. 87) Add a client-body-tagger action. This is less trivial as we currently don't buffer client bodies. After 14) is implemented it would be trivial, though. 88) Investigate if there's a Perl module that Privoxy-Regression-Test could optionally use to keep connections alive, preferably while requiring less forks at the same time. 89) When multiple block actions apply, consider showing all the block reasons on the blocked page that haven't been overruled, not just the last one. 90) Implement NO-TAG: patterns that enable a section if the provided pattern doesn't match any TAG. This would make some things cleaner. 91) Add an optional limit for internal redirects. It would probably be reasonable to default to a limit of one and showing an error message if the request for the redirect URL would be redirected again. 92) The statistics currently aren't calculated correctly by Privoxy as each thread is only counted as one request which is no longer correct. This should be fixed, or the statistic code removed. Privoxy-Log-Parser's provides more detailed statistics, anyway. 93) Add a config directive to let Privoxy explicitly request either IPv4 (or IPv6) addresses, even if the system supports both. Could be useful as a workaround for misconfigured setups where the libc returns IPv6 addresses even if there's no IPv6 connectivity. 94) Add a config directive to let Privoxy prefer either IPv4 (or IPv6) addresses, instead of trusting the libc to return them in an order that makes sense. Like #93, this could be useful as a workaround for misconfigured setups. 95) Support a non-standard client header in CONNECT requests that contains the URL of the requested ressource, which is then treated like the request URL. This way the client could opt-in for path-based blocking of https requests. Given that the headers from the CONNECT request aren't forwarded to the destination server, an unencrypted URL should be acceptable if the client and Privoxy are running on the same system or in a trusted environment. 96) Enabled filters should be easier to look up. Currently most functions that work with filters spent more (duplicated) code on finding filters than on actually doing something useful with them. Dividing filters by type instead of filter file would reduce the lookup-code quite a bit. 98) When showing action section on the CGI pages, properly escape line breaks so they can be copy&pasted into action files without adjustments. 99) Figure out a mechanism through which a user can easily enable site-specific action sections that are too aggressive to be enalbled by default. This could be similiar to the presettings in default.action, but could also be just another action file that isn't used by default. 100) Create a cross-platform Privoxy control program and retire the win32 GUI. Integrate support for Privoxy-Regression-Test, Privoxy-Log-Parser, Privoxy-Filter-Test, uagen and similar tools. 102) Add an include directive to split the config file into several parts. 103) Potential performance improvement for large action files: when figuring out which actions apply, check the action bitmask before pattern matching and skip section that wouldn't modify the actions already set. To increase the impact the sections would have to be applied in reverse. 104) The code to modify global_toggle_state should be factored out into a separate function. Currently we mess with it in three different files, but only in w32log.c the tray icon is explicitly set. The logging is inconsistent as well. For details see #3525694. 105) Add support for socks authentication. 106) actionlist.h should be embedded in a way that causes less text segment bloat. 107) Support more pcrs variables, for example $destination-ip-address and $source-ip-address. 108) Allow to use a somewhat random string intead of PRIVOXY-FORCE. 109) Let log_error() support the format specifier %S which should work like %s but escape new lines like %N. This would be useful to log the result of header filters which may inject new lines. 110) Add a global-buffer-limit directive that roughly limits how much malloc'ed memory Privoxy will use and can potentionally be smaller than (buffer-limit * max-client-connections). privoxy-3.0.21-stable/./install-sh000750 001751 001751 00000012736 11217504051 015772 0ustar00fkfk000000 000000 #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 privoxy-3.0.21-stable/./encode.c000640 001751 001751 00000034576 12110657175 015407 0ustar00fkfk000000 000000 const char encode_rcs[] = "$Id: encode.c,v 1.29 2013/02/19 11:14:05 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/encode.c,v $ * * Purpose : Functions to encode and decode URLs, and also to * encode cookies and HTML text. * * Copyright : Written by and Copyright (C) 2001 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #include "miscutil.h" #include "encode.h" const char encode_h_rcs[] = ENCODE_H_VERSION; /* Maps special characters in a URL to their equivalent % codes. */ static const char url_code_map[256][4] = { "", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F", "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", "%28", "%29", "", "%2B", "%2C", "", "", "%2F", "", "", "", "", "", "", "", "", "", "", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%5B", "%5C", "%5D", "%5E", "", "%60", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F", "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F", "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7", "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF", "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7", "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF", "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7", "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF", "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF" }; /* Maps special characters in HTML to their equivalent entities. */ static const char * const html_code_map[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,""",NULL,NULL,NULL,"&","'", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "<",NULL,">",NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /********************************************************************* * * Function : html_encode * * Description : Encodes a string so it's not interpreted as * containing HTML tags or entities. * Replaces <, >, &, and " with the appropriate HTML * entities. * * Parameters : * 1 : s = String to encode. Null-terminated. * * Returns : Encoded string, newly allocated on the heap. * Caller is responsible for freeing it with free(). * If s is NULL, or on out-of memory, returns NULL. * *********************************************************************/ char * html_encode(const char *s) { char * buf; size_t buf_size; if (s == NULL) { return NULL; } /* each input char can expand to at most 6 chars */ buf_size = (strlen(s) * 6) + 1; buf = (char *) malloc(buf_size); if (buf) { char c; char * p = buf; while ((c = *s++) != '\0') { const char * replace_with = html_code_map[(unsigned char) c]; if (replace_with != NULL) { const size_t bytes_written = (size_t)(p - buf); assert(bytes_written < buf_size); p += strlcpy(p, replace_with, buf_size - bytes_written); } else { *p++ = c; } } *p = '\0'; assert(strlen(buf) < buf_size); } return(buf); } /********************************************************************* * * Function : html_encode_and_free_original * * Description : Encodes a string so it's not interpreted as * containing HTML tags or entities. * Replaces <, >, &, and " with the appropriate HTML * entities. Free()s original string. * If original string is NULL, simply returns NULL. * * Parameters : * 1 : s = String to encode. Null-terminated. * * Returns : Encoded string, newly allocated on the heap. * Caller is responsible for freeing it with free(). * If s is NULL, or on out-of memory, returns NULL. * *********************************************************************/ char * html_encode_and_free_original(char *s) { char * result; if (s == NULL) { return NULL; } result = html_encode(s); free(s); return result; } /********************************************************************* * * Function : url_encode * * Description : Encodes a string so it can be used in a URL * query string. Replaces special characters with * the appropriate %xx codes. * * XXX: url_query_encode() would be a more fitting * name. * * Parameters : * 1 : s = String to encode. Null-terminated. * * Returns : Encoded string, newly allocated on the heap. * Caller is responsible for freeing it with free(). * If s is NULL, or on out-of memory, returns NULL. * *********************************************************************/ char * url_encode(const char *s) { char * buf; size_t buf_size; if (s == NULL) { return NULL; } /* each input char can expand to at most 3 chars */ buf_size = (strlen(s) * 3) + 1; buf = (char *) malloc(buf_size); if (buf) { char c; char * p = buf; while((c = *s++) != '\0') { const char *replace_with = url_code_map[(unsigned char) c]; if (*replace_with != '\0') { const size_t bytes_written = (size_t)(p - buf); assert(bytes_written < buf_size); p += strlcpy(p, replace_with, buf_size - bytes_written); } else { *p++ = c; } } *p = '\0'; assert(strlen(buf) < buf_size); } return(buf); } /********************************************************************* * * Function : xdtoi * * Description : Converts a single hex digit to an integer. * * Parameters : * 1 : d = in the range of ['0'..'9', 'A'..'F', 'a'..'f'] * * Returns : The integer value, or -1 for non-hex characters. * *********************************************************************/ static int xdtoi(const int d) { if ((d >= '0') && (d <= '9')) { return(d - '0'); } else if ((d >= 'a') && (d <= 'f')) { return(d - 'a' + 10); } else if ((d >= 'A') && (d <= 'F')) { return(d - 'A' + 10); } else { return(-1); } } /********************************************************************* * * Function : xtoi * * Description : Hex string to integer conversion. * * Parameters : * 1 : s = a 2 digit hex string (e.g. "1f"). Only the * first two characters will be looked at. * * Returns : The integer value, or 0 for non-hex strings. * *********************************************************************/ int xtoi(const char *s) { int d1; d1 = xdtoi(*s); if (d1 >= 0) { int d2 = xdtoi(*(s+1)); if (d2 >= 0) { return (d1 << 4) + d2; } } return 0; } /********************************************************************* * * Function : url_decode * * Description : Decodes a URL query string, replacing %xx codes * with their decoded form. * * Parameters : * 1 : s = String to decode. Null-terminated. * * Returns : Decoded string, newly allocated on the heap. * Caller is responsible for freeing it with free(). * *********************************************************************/ char *url_decode(const char * s) { char *buf = malloc(strlen(s) + 1); char *q = buf; if (buf) { while (*s) { switch (*s) { case '+': s++; *q++ = ' '; break; case '%': if ((*q = (char)xtoi(s + 1)) != '\0') { s += 3; q++; } else { /* malformed, just use it */ *q++ = *s++; } break; default: *q++ = *s++; break; } } *q = '\0'; } return(buf); } /********************************************************************* * * Function : percent_encode_url * * Description : Percent-encodes a string so it no longer contains * any characters that aren't valid in an URL according * to RFC 3986. * * XXX: Do not confuse with encode_url() * * Parameters : * 1 : s = String to encode. Null-terminated. * * Returns : Encoded string, newly allocated on the heap. * Caller is responsible for freeing it with free(). * If s is NULL, or on out-of memory, returns NULL. * *********************************************************************/ char *percent_encode_url(const char *s) { static const char allowed_characters[128] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '!', '\0', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '\0', '=', '\0', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\0', ']', '\0', '_', '\0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0', '\0', '\0', '~', '\0' }; char *buf; size_t buf_size; assert(s != NULL); /* Each input char can expand to at most 3 chars. */ buf_size = (strlen(s) * 3) + 1; buf = (char *)malloc(buf_size); if (buf != NULL) { char c; char *p = buf; while ((c = *s++) != '\0') { const unsigned int i = (unsigned char)c; if (i >= sizeof(allowed_characters) || '\0' == allowed_characters[i]) { const char *replace_with = url_code_map[i]; assert(*replace_with != '\0'); if (*replace_with != '\0') { const size_t bytes_written = (size_t)(p - buf); assert(bytes_written < buf_size); p += strlcpy(p, replace_with, buf_size - bytes_written); } } else { *p++ = c; } } *p = '\0'; assert(strlen(buf) < buf_size); } return(buf); } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32taskbar.c000640 001751 001751 00000016615 11726442046 016130 0ustar00fkfk000000 000000 const char w32taskbar_rcs[] = "$Id: w32taskbar.c,v 1.14 2012/03/09 17:55:50 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32taskbar.c,v $ * * Purpose : Functions for creating, setting and destroying the * workspace tray icon * * Copyright : Written by and Copyright (C) 2001-2002 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 1999 Adam Lock * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #ifndef STRICT #define STRICT #endif #include #include "w32taskbar.h" #include "w32res.h" #include "w32log.h" const char w32taskbar_h_rcs[] = W32TASKBAR_H_VERSION; #ifndef _WIN_CONSOLE /* entire file */ #define WM_TRAYMSG WM_USER+1 static HMENU g_hmenuTray; static HWND g_hwndTrayX; static UINT g_traycreatedmsg; static LRESULT CALLBACK TrayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); /********************************************************************* * * Function : CreateTrayWindow * * Description : Creates and returns the invisible window responsible * for processing tray messages. * * Parameters : * 1 : hInstance = instance handle of this application * * Returns : Handle of the systray window. * *********************************************************************/ HWND CreateTrayWindow(HINSTANCE hInstance) { WNDCLASS wc; static const char *szWndName = "PrivoxyTrayWindow"; wc.style = 0; wc.lpfnWndProc = TrayProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = 0; wc.hCursor = 0; wc.hbrBackground = 0; wc.lpszMenuName = 0; wc.lpszClassName = szWndName; RegisterClass(&wc); /* TaskbarCreated is sent to a window when it should re-add its tray icons */ g_traycreatedmsg = RegisterWindowMessage("TaskbarCreated"); g_hwndTrayX = CreateWindow(szWndName, szWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(g_hwndTrayX, SW_HIDE); UpdateWindow(g_hwndTrayX); g_hmenuTray = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_TRAYMENU)); return g_hwndTrayX; } /********************************************************************* * * Function : TraySetIcon * * Description : Sets the tray icon to the specified shape. * * Parameters : * 1 : hwnd = handle of the systray window * 2 : uID = user message number to notify systray window * 3 : hicon = set the current icon to this handle * * Returns : Same value as `Shell_NotifyIcon'. * *********************************************************************/ BOOL TraySetIcon(HWND hwnd, UINT uID, HICON hicon) { NOTIFYICONDATA nid; memset(&nid, 0, sizeof(nid)); nid.cbSize = sizeof(nid); nid.hWnd = hwnd; nid.uID = uID; nid.uFlags = NIF_ICON; nid.uCallbackMessage = 0; nid.hIcon = hicon; return(Shell_NotifyIcon(NIM_MODIFY, &nid)); } /********************************************************************* * * Function : TrayAddIcon * * Description : Adds a tray icon. * * Parameters : * 1 : hwnd = handle of the systray window * 2 : uID = user message number to notify systray window * 3 : hicon = handle of icon to add to systray window * 4 : pszToolTip = tool tip when mouse hovers over systray window * * Returns : Same as `Shell_NotifyIcon'. * *********************************************************************/ BOOL TrayAddIcon(HWND hwnd, UINT uID, HICON hicon, const char *pszToolTip) { NOTIFYICONDATA nid; memset(&nid, 0, sizeof(nid)); nid.cbSize = sizeof(nid); nid.hWnd = hwnd; nid.uID = uID; nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; nid.uCallbackMessage = WM_TRAYMSG; nid.hIcon = hicon; if (pszToolTip) { strcpy(nid.szTip, pszToolTip); } return(Shell_NotifyIcon(NIM_ADD, &nid)); } /********************************************************************* * * Function : TrayDeleteIcon * * Description : Deletes a tray icon. * * Parameters : * 1 : hwnd = handle of the systray window * 2 : uID = user message number to notify systray window * * Returns : Same as `Shell_NotifyIcon'. * *********************************************************************/ BOOL TrayDeleteIcon(HWND hwnd, UINT uID) { NOTIFYICONDATA nid; memset(&nid, 0, sizeof(nid)); nid.cbSize = sizeof(nid); nid.hWnd = hwnd; nid.uID = uID; return(Shell_NotifyIcon(NIM_DELETE, &nid)); } /********************************************************************* * * Function : TrayProc * * Description : Call back procedure processes tray messages. * * Parameters : * 1 : hwnd = handle of the systray window * 2 : msg = message number * 3 : wParam = first param for this message * 4 : lParam = next param for this message * * Returns : Appropriate M$ window message handler codes. * *********************************************************************/ LRESULT CALLBACK TrayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: return 0; case WM_CLOSE: PostQuitMessage(0); return 0; case WM_TRAYMSG: { /* UINT uID = (UINT) wParam; */ UINT uMouseMsg = (UINT) lParam; if (uMouseMsg == WM_RBUTTONDOWN) { POINT pt; HMENU hmenu = GetSubMenu(g_hmenuTray,0); GetCursorPos(&pt); SetForegroundWindow(g_hwndLogFrame); TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, 0, g_hwndLogFrame, NULL); PostMessage(g_hwndLogFrame, WM_NULL, 0, 0); } else if (uMouseMsg == WM_LBUTTONDBLCLK) { ShowLogWindow(TRUE); } } return 0; default: if (msg == g_traycreatedmsg) { TrayAddIcon(g_hwndTrayX, 1, g_hiconApp, "Privoxy"); } break; } return DefWindowProc(hwnd, msg, wParam, lParam); } #endif /* ndef _WIN_CONSOLE - entire file */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./genclspec.sh000750 001751 001751 00000003345 11217504051 016264 0ustar00fkfk000000 000000 #!/bin/sh # # $Id: genclspec.sh,v 1.2 2002/04/27 04:49:11 morcego Exp $ # # Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # $Log: genclspec.sh,v $ # Revision 1.2 2002/04/27 04:49:11 morcego # Adding license and copyright comments. # # VERSION=`cat privoxy-rh.spec | sed -n -e 's/^Version:[ ]*//p'` RELEASE=`cat privoxy-rh.spec | sed -n -e 's/^Release:[ ]*//p'` CLTAG=${VERSION}-${RELEASE}cl PACKAGER=`rpm --eval "%{packager}"` if [ "${PACKAGER}" = "%{packager}" ]; then PACKAGER="genclspec script " fi export LC_ALL= export LANG= DATETAG=`date "+%a %b %d %Y"` if [ -r privoxy-cl.spec ]; then echo Old CL specfile found. Removing it. fi cat privoxy-rh.spec | sed -e 's/^\(Release:[ ]*[^ ]\+\)[ ]*$/\1cl/' \ -e "/^%changelog/a* ${DATETAG} ${PACKAGER}" \ -e "/^%changelog/a+ privoxy-${CLTAG}" \ -e "/^%changelog/a- Packaging for Conectiva Linux (automatic genarated specfile)" \ -e '/^%changelog/a \ ' > privoxy-cl.spec privoxy-3.0.21-stable/./deanimate.h000640 001751 001751 00000005304 11630656300 016064 0ustar00fkfk000000 000000 #ifndef DEANIMATE_H_INCLUDED #define DEANIMATE_H_INCLUDED #define DEANIMATE_H_VERSION "$Id: deanimate.h,v 1.14 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/deanimate.h,v $ * * Purpose : Declares functions to manipulate binary images on the * fly. High-level functions include: * - Deanimation of GIF images * * Functions declared include: gif_deanimate and buf_free. * * * Copyright : Written by and Copyright (C) 2001 - 2004 by the the * SourceForge Privoxy team. http://www.privoxy.org/ * * Based on ideas from the Image::DeAnim Perl module by * Ken MacFarlane, * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif /* * A struct that holds a buffer, a read/write offset, * and the buffer's capacity. */ struct binbuffer { char *buffer; size_t offset; size_t size; }; /* * Function prototypes */ extern int gif_deanimate(struct binbuffer *src, struct binbuffer *dst, int get_first_image); extern void buf_free(struct binbuffer *buf); /* * Revision control strings from this header and associated .c file */ extern const char deanimate_rcs[]; extern const char deanimate_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef DEANIMATE_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./ssplit.c000640 001751 001751 00000011536 12003243705 015446 0ustar00fkfk000000 000000 const char ssplit_rcs[] = "$Id: ssplit.c,v 1.20 2012/07/23 12:47:01 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/ssplit.c,v $ * * Purpose : A function to split a string at specified delimiters. * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include "ssplit.h" #include "miscutil.h" const char ssplit_h_rcs[] = SSPLIT_H_VERSION; /********************************************************************* * * Function : ssplit * * Description : Split a string using delimiters in `delim'. Results * go into `vec'. * * Parameters : * 1 : str = string to split. Will be split in place * (i.e. do not free until you've finished with vec, * previous contents will be trashed by the call). * 2 : delim = array of delimiters (if NULL, uses " \t"). * 3 : vec[] = results vector (aka. array) [out] * 4 : vec_len = number of usable slots in the vector (aka. array size) * * Returns : -1 => Error: vec_len is too small to hold all the * data, or str == NULL. * >=0 => the number of fields put in `vec'. * On error, vec and str may still have been overwritten. * *********************************************************************/ int ssplit(char *str, const char *delim, char *vec[], size_t vec_len) { unsigned char is_delim[256]; unsigned char char_type; int vec_count = 0; enum char_type { WANTED = 0, SEPARATOR = 1, TERMINATOR = 2, }; if (!str) { return(-1); } /* Build is_delim array */ memset(is_delim, '\0', sizeof(is_delim)); if (!delim) { delim = " \t"; /* default field separators */ } while (*delim) { is_delim[(unsigned)(unsigned char)*delim++] = SEPARATOR; } is_delim[(unsigned)(unsigned char)'\0'] = TERMINATOR; is_delim[(unsigned)(unsigned char)'\n'] = TERMINATOR; /* Parse string */ /* Skip leading separators. XXX: Why do they matter? */ while (is_delim[(unsigned)(unsigned char)*str] == SEPARATOR) { str++; } /* The first pointer is the beginning of string */ if (is_delim[(unsigned)(unsigned char)*str] == WANTED) { /* * The first character in this field is not a * delimiter or the end of string, so save it. */ if (vec_count >= vec_len) { return(-1); /* overflow */ } vec[vec_count++] = str; } while ((char_type = is_delim[(unsigned)(unsigned char)*str]) != TERMINATOR) { if (char_type == SEPARATOR) { /* the char is a separator */ /* null terminate the substring */ *str++ = '\0'; /* Check if we want to save this field */ if (is_delim[(unsigned)(unsigned char)*str] == WANTED) { /* * The first character in this field is not a * delimiter or the end of string. So save it. */ if (vec_count >= vec_len) { return(-1); /* overflow */ } vec[vec_count++] = str; } } else { str++; } } /* null terminate the substring */ /* XXX: this shouldn't be necessary, so assert that it isn't. */ assert(*str == '\0'); *str = '\0'; return(vec_count); } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./trust000640 001751 001751 00000007261 11217504052 015071 0ustar00fkfk000000 000000 ###################################################################### # # File : $Source: /cvsroot/ijbswa/current/trust,v $ # # $Id: trust,v 1.6 2007/05/14 17:19:42 fabiankeil Exp $ # # Purpose : Trustfiles are an experimental feature and can be used # to build "whitelists" (versus the usual "blacklists" # techniques). # # Copyright : Written by and Copyright # Privoxy team. http://www.privoxy.org/ # # Based on the Internet Junkbuster originally written # by and Copyright (C) 1997 Anonymous Coders and # Junkbusters Corporation. http://www.junkbusters.com # # We value your feedback. However, to provide you with the best support, # please note: # # * Use the support forum to get help: # http://sourceforge.net/tracker/?group_id=11118&atid=211118 # * Submit bugs only thru our bug forum: # http://sourceforge.net/tracker/?group_id=11118&atid=111118 # Make sure that the bug has not already been submitted. Please try # to verify that it is a Privoxy bug, and not a browser or site # bug first. If you are using your own custom configuration, please # try the stock configs to see if the problem is a configuration # related bug. And if not using the latest development snapshot, # please try the latest one. Or even better, CVS sources. # * Submit feature requests only thru our feature request tracker: # http://sourceforge.net/tracker/?atid=361118&group_id=11118&func=browse # # For any other issues, feel free to use the mailing lists: # http://sourceforge.net/mail/?group_id=11118 # # Anyone interested in actively participating in development and related # discussions can join the appropriate mailing list here: # http://sourceforge.net/mail/?group_id=11118. Archives are available # here too. # ###################################################################### # # Sample Trustfile for Privoxy # For this file to have any effect, the line in the main config file beginning # with "trustfile" must be uncommented, with the name of this file following the # word "trustfile". # Trustfiles are an experimental feature used for building "whitelists" # of "trusted" sites (versus the usual "blacklists" technique). For more # detail, see http://www.privoxy.org/user-manual/config.html#TRUSTFILE. # List trusted domains here. The default is to block any URL that is NOT # referenced. Access to trusted domains includes all paths within that # domain. # Preceding a domain with a '+' character will designate that domain # as a "trusted referrer", meaning any requests whose HTTP "Referer" headers # contain an URL from that domain will be allowed, and the previously untrusted # host will be dynamically added to this file. Thus, this builds a "white-list" # of hosts the user is allowed to visit. # Note this means that the file will grow with use! # Also note that you can only trust referrers if you control the user's # system and make sure that there are no programs available that allow # to set arbitrary headers. # Preceding the domain with '~' character allows access to that domain only # (including all paths within that domain), but does not allow access to links # to other, outside domains. Sites that are added dynamically by trusted # referrers will include the '~' character, and thus do not become trusted # referrers themselves. # Example: to allow example.com and to white-list domains that appear to # be reached through links from example.com, uncomment this line: # +example.com # The next two lines make sure that the user can access Privoxy's # CGI pages, without automatically trusting their links. ~config.privoxy.org ~p.p privoxy-3.0.21-stable/./default.action.master000640 001751 001751 00000361166 12114625660 020117 0ustar00fkfk000000 000000 #MASTER# COMMENT: #MASTER# COMMENT: Anyone adding specific rules to this file, #MASTER# COMMENT: wherever possible please include a *full* URL #MASTER# COMMENT: which can be used to verify the problem, and if #MASTER# COMMENT: the problem may not always be fully obvious, a #MASTER# COMMENT: brief explanation. Please also add tests for #MASTER# COMMENT: Privoxy-Regression-Test so we can automatically #MASTER# COMMENT: verify that your rules are effective. Thanks. #MASTER# COMMENT: ###################################################################### # # File : $Source: /cvsroot/ijbswa/current/default.action.master,v $ # # $Id: default.action.master,v 1.287 2013/03/03 10:53:36 fabiankeil Exp $ # # Requires : This version requires Privoxy v3.0.11 or later due to # syntax changes. # # Purpose : Default actions file, see # http://www.privoxy.org/user-manual/actions-file.html. # This file is subject to periodic updating. It is # not supposed to be edited by the user. Local exceptions # and enhancements are better placed in user.action, # the match-all section has been moved to match-all.action. # # Copyright : Written by and Copyright (C) 2001-2013 the # Privoxy team. http://www.privoxy.org/ # # Feedback welcome, for details please have a look at: # http://www.privoxy.org/user-manual/contact.html # # The current development version of this file is located: # http://ijbswa.cvs.sourceforge.net/*checkout*/ijbswa/current/default.action.master # ############################################################################# # Syntax ############################################################################# # # A much better explanation can be found in the user manual which is # part of the distribution and can be found at http://www.privoxy.org/user-manual # # To determine which actions apply to a request, the URL of the request is # compared to all patterns in this file. Every time it matches, the list of # applicable actions for this URL is incrementally updated. You can trace # this process by visiting http://config.privoxy.org/show-url-info # # There are 4 types of lines in this file: comments (like this line), # actions, aliases and patterns, all of which are explained below. # ############################################################################# # Pattern Syntax ############################################################################# # # 1. On Domains and Paths # ----------------------- # # Generally, a pattern has the form /, where both the # and part are optional. The pattern matching syntax is different for # each. If you only specify a domain part, the "/" can be left out, but it is # required for the path part. # # www.example.com # is a domain-only pattern and will match any request to www.example.com # # www.example.com/ # means exactly the same (but is slightly less efficient) # # www.example.com/index.html # matches only the document /index.html on www.example.com # # /index.html # matches the document /index.html, regardless of the domain # # index.html # matches nothing, since it would be interpreted as a domain name and # there is no top-level domain called ".html". # # 2. Domain Syntax # ---------------- # # The matching of the domain part offers some flexible options: If the # domain starts or ends with a dot, it becomes unanchored at that end: # # www.example.com # matches only www.example.com # # .example.com # matches any domain that ENDS in .example.com # # www. # matches any domain that STARTS with www. # # .example. # matches any domain that CONTAINS example # # # Additionally, there are wildcards that you can use in the domain names # themselves. They work pretty similar to shell wildcards: "*" stands for # zero or more arbitrary characters, "?" stands for one, and you can define # character classes in square brackets and they can be freely mixed: # # ad*.example.com # matches adserver.example.com, ads.example.com, etc but not sfads.example.com # # *ad*.example.com # matches all of the above # # .?pix.com # matches www.ipix.com, pictures.epix.com, a.b.c.d.e.upix.com etc # # www[1-9a-ez].example.com # matches www1.example.com, www4.example.com, wwwd.example.com, # wwwz.example.com etc, but not wwww.example.com # # You get the idea? # # 2. Path Syntax # -------------- # # Paths are specified as full regular expressions, and are more flexible than # the domain syntax above. A comprehensive discussion of regular expressions # wouldn't fit here. # # Perl compatible regular expressions are used. See the pcre/docs/ direcory or # man perlre (also available at http://perldoc.perl.org/perlre.html) for # details. The appendix to our User Manual also has some detail. # # Please note that matching in the path is CASE INSENSITIVE by default, but # you can switch to case sensitive by starting the pattern with the "(?-i)" # switch: # # www.example.com/(?-i)PaTtErN.* # will match only documents whose path starts with PaTtErN in exactly this # capitalization. # # Partially case-sensitive and partially case-insensitive patterns are # possible, but the rules about splitting them up are extremely complex # - see the PCRE documentation for more information. # ############################################################################# # Action Syntax ############################################################################# # # There are 3 kinds of actions: # # Boolean (e.g. "handle-as-image"): # +name # enable # -name # disable # # Parameterized (e.g. "hide-user-agent"): # +name{param} # enable and set parameter to "param" # -name # disable # # Multi-value (e.g. "add-header", "filter"): # +name{param} # enable and add parameter "param" # -name{param} # remove the parameter "param" # -name # disable totally # # The default (if you don't specify anything in this file) is not to take # any actions - i.e completely disabled, so Privoxy will just be a # normal, non-blocking, non-anonymizing proxy. You must specifically # enable the privacy and blocking features you need (although the # provided default actions file will do that for you). # # Later actions always override earlier ones. For multi-valued actions, # the actions are applied in the order they are specified. # ############################################################################# # Valid actions are: ############################################################################# # # +add-header{Name: value} # Adds the specified HTTP header, which is not checked for validity. # You may specify this many times to specify many headers. # # +block{reason} # Block this URL. Instead of forwarding the request, Privoxy will # send a "block" page containing the specified reason. # # +change-x-forwarded-for{add} # +change-x-forwarded-for{block} # Adds or blocks the "X-Forwarded-For:" HTTP header in client # requests. # # +client-header-filter{name} # All client headers to which this action applies are filtered on-the-fly # through the specified regular expression based substitutions. # # Client-header filters predefined in the supplied default.filter include: # # hide-tor-exit-notation: Removes the Tor exit node notation in Host and Referer headers. # privoxy-control: Removes X-Privoxy-Control headers. # # +client-header-tagger{string} # Tag requests based on their headers. Client headers to which this # action applies are filtered on-the-fly through the specified regular # expression based substitutions, the result is used as a tag. # Client-header taggers are the first actions that are executed and their # tags can be used to control every other action. # # Client-header taggers predefined in the supplied default.filter include: # # image-requests: Tags detected image requests as "IMAGE-REQUEST". # css-requests: Tags detected CSS requests as "CSS-REQUEST". # range-requests: Tags range requests as "RANGE-REQUEST". # client-ip-address: Tags the request with the client's IP address. # http-method: Tags the request with its HTTP method. # allow-post: Tags POST requests as "ALLOWED-POST". # complete-url: Tags the request with the whole request URL. # user-agent: Tags the request with the complete User-Agent header. # referer: Tags the request with the complete Referer header. # privoxy-control: Creates tags with the content of X-Privoxy-Control headers. # # +content-type-overwrite # Replaces the "Content-Type:" HTTP server header, so that unwanted # download menus will not pop up, or changes the browser's rendering mode. # # +crunch-client-header{string} # Deletes every header sent by the client that contains the string the # user supplied as parameter. # # +crunch-if-none-match # Deletes the "If-None-Match:" HTTP client header. # # +crunch-server-header{string} # Deletes every header sent by the server that contains the string the # user supplied as a parameter. # # +deanimate-gifs{last} # +deanimate-gifs{first} # Deanimate all animated GIF images, i.e. reduce them to their last # frame. This will also shrink the images considerably. (In bytes, # not pixels!) # If the option "first" is given, the first frame of the animation # is used as the replacement. If "last" is given, the last frame of # the animation is used instead, which propably makes more sense for # most banner animations, but also has the risk of not showing the # entire last frame (if it is only a delta to an earlier frame). # # +downgrade-http-version # Downgrade HTTP/1.1 client requests to HTTP/1.0 and downgrade the # responses as well. Use this action for servers that use HTTP/1.1 # protocol features that Privoxy currently can't handle yet. # # +fast-redirects{check-decoded-url} # +fast-redirects{simple-check} # Many sites, like yahoo.com, don't just link to other sites. # Instead, they will link to some script on their own server, # giving the destination as a parameter, which will then redirect # you to the final target. # # URLs resulting from this scheme typically look like: # http://some.place/some_script?http://some.where-else # # Sometimes, there are even multiple consecutive redirects encoded # in the URL. These redirections via scripts make your web browsing # more traceable, since the server from which you follow such a link # can see where you go to. Apart from that, valuable bandwidth and # time is wasted, while your browser asks the server for one redirect # after the other. Plus, it feeds the advertisers. # # The +fast-redirects{check-decoded-url} option enables interception of # these requests by Privoxy, who will cut off all but the last valid URL # in the request and send a local redirect back to your browser without # contacting the intermediate sites. NOTE: Syntax change as of v.3.0.4. # # +filter{name} # All files of text-based type, most notably HTML and JavaScript, to which # this action applies, can be filtered on-the-fly through the specified # regular expression based substitutions. (Note: plain text documents are # exempted from filtering, because web servers often use the text/plain # MIME type for all files whose type they don't know.) By default, # filtering works only on the raw document content itself (that which can # be seen with View Source), not the headers. Repeat for multiple filters. # Use with caution: filters can be very intrusive. # # Filters predefined in the supplied default.filter include: # # js-annoyances: Get rid of particularly annoying JavaScript abuse. # js-events: Kill JavaScript event bindings and timers (Radically destructive! Only for extra nasty sites). # html-annoyances: Get rid of particularly annoying HTML abuse. # content-cookies: Kill cookies that come in the HTML or JS content. # refresh-tags: Kill automatic refresh tags if refresh time is larger than 9 seconds. # unsolicited-popups: Disable only unsolicited pop-up windows. # all-popups: Kill all popups in JavaScript and HTML. # img-reorder: Reorder attributes in tags to make the banners-by-* filters more effective. # banners-by-size: Kill banners by size. # banners-by-link: Kill banners by their links to known clicktrackers. # webbugs: Squish WebBugs (1x1 invisible GIFs used for user tracking). # tiny-textforms: Extend those tiny textareas up to 40x80 and kill the hard wrap. # jumping-windows: Prevent windows from resizing and moving themselves. # frameset-borders: Give frames a border and make them resizable. # iframes: Removes all detected iframes. Should only be enabled for individual sites. # demoronizer: Fix MS's non-standard use of standard charsets. # shockwave-flash: Kill embedded Shockwave Flash objects. # quicktime-kioskmode: Make Quicktime movies saveable. # fun: Text replacements for subversive browsing fun! # crude-parental: Crude parental filtering. Note that this filter doesn't work reliably. # ie-exploits: Disable some known Internet Explorer bug exploits. # site-specifics: Cure for site-specific problems. Don't apply generally! # no-ping: Removes non-standard ping attributes in and tags. # google: CSS-based block for Google text ads. Also removes a width limitation and the toolbar advertisement. # yahoo: CSS-based block for Yahoo text ads. Also removes a width limitation. # msn: CSS-based block for MSN text ads. Also removes tracking URLs and a width limitation. # blogspot: Cleans up some Blogspot blogs. Read the fine print before using this. # # +force-text-mode # Declares a document as plain text, even if the "Content-Type:" isn't detected # as such. # # +forward-override{forward .} # +forward-override{forward 127.0.0.1:8123} # +forward-override{forward-socks4a 127.0.0.1:9050 .} # +forward-override{forward-socks4a 127.0.0.1:9050 proxy.example.org:8000} # +forward-override{forward-socks5 127.0.0.1:9050 .} # +forward-override{forward-socks5 127.0.0.1:9050 proxy.example.org:8000} # This action overrules the forward directives in the configuration file. # # +handle-as-empty-document # This action alone doesn't do anything noticeable. It just marks URLs. If # the block action also applies, the presence or absence of this mark # decides whether an HTML "blocked" page, or an empty document will be sent # to the client as a substitute for the blocked content. # # +handle-as-image # Treat this URL as an image. This only matters if it's also "+block"ed, # in which case a "blocked" image can be sent rather than a HTML page. # See +set-image-blocker{} for the control over what is actually sent. # # +hide-accept-language{lang} # +hide-accept-language{block} # Deletes or replaces the "Accept-Language:" HTTP header in client # requests. # # +hide-content-disposition{block} # +hide-content-disposition{string} # Deletes or replaces the "Content-Disposition:" HTTP header set by some # servers. This can be used to prevent download menus for content you # prefer to view inside the browser, for example. # # +hide-from-header{block} # +hide-from-header{spam@sittingduck.xqq} # If the browser sends a "From:" header containing your e-mail address, # either completely removes the header ("block"), or change it to the # specified e-mail address. # # +hide-if-modified-since{block} # +hide-if-modified-since{-60} # Deletes the "If-Modified-Since:" HTTP client header or modifies its # value, preventing another way to track users. # # +hide-referer{block} # +hide-referer{forge} # +hide-referer{http://nowhere.com} # Don't send the "Referer:" (sic) header to the web site. You can # block it, forge a URL to the same server as the request (which is # preferred because some sites will not send images otherwise) or # set it to a constant string. # # +hide-referrer{...} # Alternative spelling of +hide-referer. Has the same parameters, # and can be freely mixed with, "+hide-referer". ("referrer" is the # correct English spelling, however the HTTP specification has a # bug - it requires it to be spelt "referer"). # # +hide-user-agent{browser-type} # Change the "User-Agent:" header so web servers can't tell your # browser type. (Breaks many web sites). Specify the user-agent # value you want - e.g., to pretend to be using Netscape on Linux: # +hide-user-agent{Mozilla (X11; I; Linux 2.0.32 i586)} # Or to identify yourself explicitly as a Privoxy user: # +hide-user-agent{Privoxy/1.0} # (Don't change the version number from 1.0 - after all, why tell them?) # # +limit-connect{portlist} # # By default, i.e. if no limit-connect action applies, Privoxy # allows HTTP CONNECT requests to all ports. Use limit-connect # if fine-grained control is desired for some or all destinations. # The CONNECT methods exists in HTTP to allow access to secure websites # ("https://" URLs) through proxies. It works very simply: the proxy # connects to the server on the specified port, and then short-circuits # its connections to the client and to the remote server. This means # CONNECT-enabled proxies can be used as TCP relays very easily. Privoxy # relays HTTPS traffic without seeing the decoded content. Websites can # leverage this limitation to circumvent Privoxy's filters. By specifying # an invalid port range you can disable HTTPS entirely. # # +limit-connect{443} # Only port 443 is OK. # +limit-connect{80,443} # Ports 80 and 443 are OK. # +limit-connect{-3, 7, 20-100, 500-} # Ports less than 3, 7, 20 to 100 and above 500 are OK. # +limit-connect{-} # All ports are OK # +limit-connect{,} # No HTTPS/SSL traffic is allowed # # +overwrite-last-modified{block} # +overwrite-last-modified{reset-to-request-time} # +overwrite-last-modified{randomize} # Removing the "Last-Modified:" header is useful for filter testing, where # you want to force a real reload instead of getting status code "304", # which would cause the browser to reuse the old version of the page. # # The "randomize" option overwrites the value of the "Last-Modified:" # header with a randomly chosen time between the original value and the # current time. In theory the server could send each document with a # different "Last-Modified:" header to track visits without using cookies. # "Randomize" makes it impossible and the browser can still revalidate # cached documents. # # "reset-to-request-time" overwrites the value of the "Last-Modified:" # header with the current time. You could use this option together with # hide-if-modified-since to further customize your random range. # # +prevent-compression # Prevent the website from compressing the data. Some websites do # that, which is a problem for Privoxy when built without zlib support, # since +filter and +gif-deanimate will not work on compressed data. # Will slow down connections to those websites, though. # # +server-header-filter{name} # All server headers to which this action applies are filtered on-the-fly # through the specified regular expression based substitutions. # # Server-header filters predefined in the supplied default.filter include: # # x-httpd-php-to-html: Changes the Content-Type header from x-httpd-php to html. # html-to-xml: Changes the Content-Type header from html to xml. # xml-to-html: Changes the Content-Type header from xml to html. # less-download-windows: Prevent annoying download windows for content types the browser can handle itself. # privoxy-control: Removes X-Privoxy-Control headers. # # +server-header-tagger{content-type} # Server headers to which this action applies are filtered on-the-fly # through the specified regular expression based substitutions, the result # is used as a tag. Server-header taggers are executed before all other # header actions that modify server headers. Their tags can be used to # control all of the other server-header actions, the content filters and # the crunch actions (redirect and block). # # Server-header taggers predefined in the supplied default.filter include: # # content-type: Tags the request with the content type declared by the server. # privoxy-control: Creates tags with the content of X-Privoxy-Control headers. # # +session-cookies-only # If the website sets cookies, make sure they are erased when you exit # and restart your web browser. This makes profiling cookies useless, # but won't break sites which require cookies so that you can log in # or for transactions. # # +set-image-blocker{blank} # +set-image-blocker{pattern} # +set-image-blocker{} with being any valid image URL # Decides what to do with URLs that end up tagged with {+block +handle-as-image}. # There are 4 options: # * "-set-image-blocker" will send a HTML "blocked" page, usually # resulting in a "broken image" icon. # * "+set-image-blocker{blank}" will send a 1x1 transparent image # * "+set-image-blocker{pattern}" will send a 4x4 grey/white pattern # which is less intrusive than the logo but easier to recognize # than the transparent one. # * "+set-image-blocker{}" will send a HTTP temporary redirect # to the specified image URL. # # # +crunch-outgoing-cookies # Prevent the website from reading cookies # # +crunch-incoming-cookies # Prevent the website from setting cookies # # +redirect{} # +redirect{} # Convinces the browser that the requested document has been moved to # another location and the browser should get it from the specified # URL. # ############################################################################# ############################################################################# # Settings -- Don't change. ############################################################################# {{settings}} ############################################################################# #MASTER# COMMENT: The minimum Privoxy version: for-privoxy-version=3.0.11 ############################################################################# # Aliases ############################################################################# {{alias}} ############################################################################# # # You can define a short form for a list of permissions - e.g., instead # of "-crunch-incoming-cookies -crunch-outgoing-cookies -filter -fast-redirects", # you can just write "shop". This is called an alias. # # Currently, an alias can contain any character except space, tab, '=', '{' # or '}'. # But please use only 'a'-'z', '0'-'9', '+', and '-'. # # Alias names are not case sensitive. # # Aliases beginning with '+' or '-' may be used for system action names # in future releases - so try to avoid alias names like this. (e.g. # "+crunch-all-cookies" below is not a good name) # # Aliases must be defined before they are used. # # These aliases just save typing later: # +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies allow-all-cookies = -crunch-all-cookies -session-cookies-only allow-popups = -filter{all-popups} -filter{unsolicited-popups} +block-as-image = +block{Blocked image request.} +handle-as-image -block-as-image = -block # These aliases define combinations of actions # that are useful for certain types of sites: # fragile = -block -crunch-all-cookies -filter -fast-redirects -hide-referer shop = -crunch-all-cookies allow-popups # Your favourite blend of filters: # myfilters = +filter{html-annoyances} +filter{js-annoyances} +filter{all-popups}\ +filter{webbugs} +filter{banners-by-size} # Allow ads for selected useful free sites: # allow-ads = -block -filter{banners-by-size} -filter{banners-by-link} ################ # # Cautious settings -- safe for all sites, but offer little privacy protection # { \ +change-x-forwarded-for{block} \ +client-header-tagger{css-requests} \ +client-header-tagger{image-requests} \ +hide-from-header{block} \ +set-image-blocker{pattern} \ } standard.Cautious ################ # # Medium settings -- safe for most sites, with reasonable protection/damage tradeoff # { \ +change-x-forwarded-for{block} \ +client-header-tagger{css-requests} \ +client-header-tagger{image-requests} \ +deanimate-gifs{last} \ +filter{refresh-tags} \ +filter{img-reorder} \ +filter{banners-by-size} \ +filter{webbugs} \ +filter{jumping-windows} \ +filter{ie-exploits} \ +hide-from-header{block} \ +hide-referrer{conditional-block} \ +session-cookies-only \ +set-image-blocker{pattern} \ } standard.Medium ################ # # Advanced settings -- reasonable privacy protection but # require some exceptions for trusted sites, most likely # because of cookies or SSL. Also testing ground for # new options. # # CAUTION: These settings can still be subverted by a # misconfigured client that executes code from untrusted # sources. # { \ +change-x-forwarded-for{block} \ +client-header-tagger{css-requests} \ +client-header-tagger{image-requests} \ +crunch-if-none-match \ +crunch-outgoing-cookies \ +crunch-incoming-cookies \ +deanimate-gifs{last} \ +fast-redirects{check-decoded-url} \ +filter{html-annoyances} \ +filter{content-cookies} \ +filter{refresh-tags} \ +filter{img-reorder} \ +filter{banners-by-size} \ +filter{banners-by-link} \ +filter{webbugs} \ +filter{jumping-windows} \ +filter{frameset-borders} \ +filter{quicktime-kioskmode} \ +hide-if-modified-since{-60} \ +hide-from-header{block} \ +hide-referrer{conditional-block} \ +limit-connect{,} \ +overwrite-last-modified{randomize} \ +set-image-blocker{pattern} \ } standard.Advanced ############################################################################# # These extensions belong to images: ############################################################################# {+handle-as-image -filter} ############################################################################# /.*\.(gif|jpe?g|png|bmp|ico)($|\?) ############################################################################# # These don't: ############################################################################# {-handle-as-image} /.*\.(js|php|css|.?html?) ############################################################################# # These belong to multimedia files of which Firefox occasionally only # requests parts. #2816708 ############################################################################# {-filter -deanimate-gifs} # Sticky Actions = -filter -deanimate-gifs # URL = http://www.example.org/foo/bar.ogg # URL = http://www.example.net/bar.ogv /.*\.og[gv]$ ############################################################################# # Generic block patterns by host: ############################################################################# {+block{Host matches generic block pattern.}} ad*. .*ads. #MASTER# REMARKS: removed .ad. 2007-12-18 HB #MASTER# REMARKS: Modifications per Actionsfile feedback item #1807613 .ad.?. .ad.[a-ik-z][a-oq-z]. .ad.jp.*. .ad.???*. # Blocked URL = http://alternativos.iw-advertising.com/ .*advert*. *banner*. count*. *counter. #MASTER# PROBLEM URL: http://www.newegg.com promotions. #MASTER# BLOCK-REFERRER: http://tech.cybernetnews.com/ # Blocked URL = http://metrics.performancing.com/ metrics. ############################################################################# # Generic unblockers by host: ############################################################################# {-block} # Sticky Actions = -block adsl. ad[udmw]*. adbl*. adam*. adapt*. adob*. adrenaline. adtp*. adv[oia]*. adventure*. .*road*. .olympiad*. .*load*. .*[epu]ad*. county*. countr*. #MASTER# REMARKS: We still like tor # URL = http://metrics.torproject.org/consensus-graphs.html metrics.torproject.org/ # URL = http://linuxcounter.net/ linuxcounter.net/ ############################################################################# # Generic block patterns by path: ############################################################################# {+block{Path matches generic block pattern.}} /(.*/)?ad(\?|/|s|v|_?(image|se?rv|box)|cycle|rotate|mentor|click|f[ra]m|script|stream|fetch|log|space) # Blocked URL = http://www.example.org/adimage # Blocked URL = http://www.example.org/adspace /phpads(new)?/ /(.*/)?(ad|all|nn|db|promo(tion)?)?[-_]?banner /(.*/)?(publicite|werbung|rekla(me|am)|annonse|maino(kset|nta|s)?/) /.*(count|track|compteur|(? for user tracking. #MASTER# REMARKS: There is a ssl.google-analytics as well. .google-analytics./ #MASTER# REMARKS: Below Moved here from -handle-as-image 10/16/06 ########## #MASTER# BLOCK-REFERRER: http://forums2.gardenweb.com/forums/orchids/ 09/25/06 #MASTER# REMARKS: Mostly JS and plain text stuff .overture. #MASTER# PROBLEM-URL: http://www.linuxtoday.com/ #MASTER# REMARKS: /adi has HTML snipplets for use in IFRAMEs 10/15/06 .doubleclick.net/adi .doubleclick.net/(.*/)?adj/ #MASTER# PROBLEM-URL: http://maps.yahoo.com/ #MASTER# REMARKS: /AVE/iview has HTML snipplets for use in IFRAMEs 10/15/06 view.atdmt.com/(.*/)?iview/ #MASTER# REMARKS: Above Moved here from -handle-as-image 10/16/06 ########## #MASTER# REMARKS: Generic, re: tracking.foxnews.com/HG? 10/01/06 tracking. #MASTER# BLOCK-REFERRER: http://netcraft.com and many others 10/22/06 /(.*/)?adjs\.php\? #MASTER# BLOCK-REFERRER: http://groups.yahoo.com/group/epdf/ 10/08/06 .bc.yahoo.com/b\?P= #MASTER# BLOCK-REFERRER: http://www.motherboard.cz 10/30/06 x*.alexa.com #MASTER# BLOCK-REFERRER: http://mplayernetwork.com 11/07/06 #MASTER# BLOCK-REFERRER: http://eetimes.com 09/26/06 /event.ng/ # MASTER# BLOCK-REFERRER: http://www.play.com/PC/PCs/-/653/860/-/12068815/Asus-VK192S-19-Widescreen-LCD-Monitor-With-Webcam-White/Product.html # Blocked URL = http://sd.play.com/eluminate?ci=90121638&st=1296424516858&vn1=4.3.1&ec=UTF-8&vn... # Blocked URL = http://data.coremetrics.com/cm?ci=90121638&st=1296435164623&vn1=4.3.1&ec=UTF-8&vn... /(eluminate|cm)\?[tc]i=\d+&st=\d+& #MASTER# BLOCK-REFERRER: http://www.snapfiles.com/feedback/ 12/13/06 SF tracker .snapfiles.net/rotation/.*\.asp #MASTER# BLOCK-REFERRER: not provided. SF tracker #1616034 12/16/06 #MASTER# COMMENT: JS pop-ups spa.snap.com/ #MASTER# BLOCK-REFERRER: http://www.gamefaqs.com/computer/doswin/game/914819.html 12/18/06 #MASTER# COMMENT: user tracking, and run-away assorted 'junk' #MASTER# BLOCK-REFERRER: http://formwood.com 2007-11-12 .insitemetrics.com/ #MASTER# COMMENT: user tracking, and assorted 'junk' #MASTER# BLOCK-REFERRER: http://blogblog.com 2007-11-12 .extreme-dm.com/ #MASTER# COMMENT: user tracking, and assorted 'junk' #MASTER# BLOCK-REFERRER: http://www.schillmania.com 2007-11-12 stats.reinvigorate.net/ #MASTER# COMMENT: user tracking, and assorted 'junk' #MASTER# BLOCK-REFERRER: http://wordpress.com 2007-11-12 .getclicky.com/ #MASTER# COMMENT: user tracking, and assorted 'junk' #MASTER# BLOCK-REFERRER: http://infoworld.com 2007-11-12 .quantserve.com # Blocked URL = http://media.adrevolver.com/adrevolver/trace?sip=123&cpy=123 media.adrevolver.com/ #MASTER# REMARKS: Actionsfile feedback item #2975895 2010-03-24 # Blocked URL = http://static.chartbeat.com/js/chartbeat.js .chartbeat.com/(.*/)?chartbeat\.js$ # Blocked URL = http://js.adlink.net/js?lang=de&s=duesseldorf-international.de&z=home&d=1274103403564 #MASTER# BLOCK-REFERRER: http://www.duesseldorf-international.de/ js.adlink.net/ # Blocked URL = nl.sitestat.com/rdw/rdw/s?www.nl.voertuigeigenaar.voertuigeigenaar&ns__t=1274099350343 #MASTER# BLOCK-REFERRER: http://www.rdw.nl/nl/voertuigeigenaar/ .sitestat.com/ #MASTER# BLOCK-REFERRER: http://www.chip.de/artikel/c_artikelunterseite_10423683.html # Blocked URL = http://pagead.googlesyndication.example.com/foo/bar/baz.js pagead*.googlesyndication./.*\.js #MASTER# BLOCK-REFERRER: http://floodle.net 2007-01-21 SF tracker scripts.chitika.net/.*\.js #MASTER# BLOCK-REFERRER: via Yahoo groups #MASTER# REMARKS: Actionsfile tracker 1645513 2007-01-26 .adinterax.com/.*\.js #MASTER# BLOCK-REFERRER: http://dictionary.reference.com/search?q=privacy&db=* #MASTER# REMARKS: Actionsfile tracker 1650798 2007-02-02 # Blocked URL = http://partner.googleadservices.com/gampad/google_service.js # Blocked URL = http://partner.googleadservices.com/gampad/google_ads.js # Blocked URL = http://partner.googleadservices.com/gampad/slotdata.js?callback=_GA_googleAdData.setAdSlotAttributes&client=ca-gam-lexico .googleadservices.com/gampad/.*\.js # Blocked URL = http://richmedia.yimg.com/js/123/personnals_banners/PER_happy_sara1_4_425x600/ad.js?q=123 /.*/ad\.js\? # Blocked URL = http://i.cmpnet.com/shared/omniture/s_code_remote.js #MASTER# BLOCK-REFERRER: http://www.informationweek.de/ /.*omniture.*\.js # Blocked URL = http://gadk.hit.gemius.pl/*/_1274097577014/rexdot.gif?l=30&id=..DlR.vCLZGB56RmfkYNSWZVLSqB3ueYOP.Oec5WWiv.h7&fr=1&fv=WIN%2010%2C0%2C45%2C2&tz=-120&href=http%3A//www.baadgalleri.dk/&ref=&screen=1440x900&col=32 #MASTER# BLOCK-REFERRER: http://www.baadgalleri.dk/ .gemius.pl/ # Blocked URL = http://farm.plista.com/widgetdata.php?clientrev=12&domainid=4211&publickey=fdc5a7f9d15be004aa03fc4d&cb=PLISTA5_7ed57c93e0d17&requestID=5&5=widgetintegration%3A%02pictureads%03&6=pictureads%3A%1Cpictureid%1F%026716%03%1Eimgdim%1F%1Cx%1F547%1Ey%1F410%1D%1Ewidgetname%1F%02pictureads%03%1D farm.plista.com/widgetdata.php #MASTER# BLOCK-REFERRER: http://www.notebooksbilliger.de/lenovo+thinkpad+l420+business+notebook # Blocked URL = http://ib.adnxs.com/bounce?%2Fseg%3Fadd%3D279412 .adnxs.com/ #MASTER# BLOCK-REFERRER: http://www.zoover.nl/ # Blocked URL = http://service.maxymiser.net/cdn/zoover/js/mmcore.js service.maxymiser.net/ #MASTER# BLOCK-REFERRER: http://www.newyorker.com/reporting/2010/05/31/100531fa_fact_groopman # Blocked URL = http://tcr.tynt.com/javascripts/Tracer.js?user=cT9yCKGeer3PWlab7jrHtB&s=62 .tynt.com/ # Blocked URL = http://pool.sanoma.adhese.com/tag/tag.js pool.*.adhese.com/ #MASTER# BLOCK-REFERRER: http://www.canon.nl/Search/index.asp # Blocked URL = http://www.canon.nl/scripts/webtrends.js /scripts/webtrends\.js #MASTER# BLOCK-REFERRER: http://www.tradera.com/ # Blocked URL = http://oskar.tradera.com/script.js oskar.tradera.com/ {+block{Might be a web-bug.} -handle-as-empty-document +handle-as-image} #MASTER# BLOCK-REFERRER: http://versiontracker.com and many others. 10/20/06 /(.*/)?__utm.gif\? #MASTER# BLOCK-REFERRER: http://washingpost.com and others 10/25/06 /.*\.gif\?D=DM #MASTER# BLOCK-REFERRER: http://www.washingtonpost.com/ #stats.surfaid.ihost.com/(crc/)?images/(bounce/)?uc.GIF #MASTER# BLOCK-REFERRER: http://www.ibm.com 10/09/06 #MASTER# REMARKS: Similar hostname and paths appear in multiple locations. # Blocked URL = http://stats.surfaid.ihost.com/crc/images/bounce/uc.GIF # Blocked URL = http://stats.surfaid.ihost.com/rc/images/bounce/uc.GIF stats./c?rc/.*/uc.gif #MASTER# BLOCK-REFERRER: http://priceline.com 10/20/06 #MASTER# REMARKS: User tracking, webbug stuff /(.*/)?dcs.gif\?&?dcs #MASTER# BLOCK-REFERRER: http://www.msnbc.com 10/07/06 #MASTER# REMARKS: And MANY others. Webbug stuff. /(.*/)?c(lear)?\.gif\?. #MASTER# BLOCK-REFERRER: http://www.investorguide.com 10/08/06 #MASTER# BLOCK-REFERRER: http://foodnetwork.com, http://gardenweb.com 10/20/06 #MASTER# REMARK: webbug type gif used in MANY places. #MASTER# REMARK: Too many false positives #/(.*/)?(clear|(trans_?1x|blank)?1).gif #MASTER# REMARK: Let's try this way. /(.*/)?(clear|blank|(trans_?|1x)?1).gif\?. #MASTER# BLOCK-REFERRER: http://actorstheatre.org 11/02/06 stats./.*\.gif\? # Blocked URL = http://ad.yieldmanager.com/pixel?id=123456&t=2 .yieldmanager.com/pixel\? # Blocked URL = http://a.analytics.yahoo.com/p.pl?a=1000226660965&js=no # Blocked URL = http://s.analytics.yahoo.com/fpc.pl?a=1000461640983&v=4.43&enc=utf-8&f=http%3A//www.zoover.nl/nederland/limburg/maasbracht/weer%23tabs&b=Het%20Weer%20in%20Maasbracht.%20Bekijk%20Weersverwachting%20van%20Maasbracht%20%7C%20Zoover%23tabs&flv=WIN%2010%2C0%2C45%2C2&d=Mon%2C%2017%20May%202010%2014%3A09%3A26%20UTC&n=-2&g=nl&h=Y&j=1440x900&k=32&l=true&ittidx=0&fpc=uP04C7j4%7ClaDQjglKaa%7Cfses1000461640983%3D%7CkbSSgv6Jaa%7CuP04C7j4%7Cfvis1000461640983%3DZj1odHRwJTNBLy93d3cuem9vdmVyLm5sLyZiPVpvb3ZlciUyMCU3QyUyMFZha2FudGllYmVvb3JkZWxpbmdlbiUyMHZvb3IlMjBlbiUyMGRvb3IlMjByZWl6aWdlcnM%3D%7C8sHTYo10oM%7C8sHTYo10oM%7C8sHTYo10oM%7CT%7C8sHTYo10oM%7C8sHTYo10oM .analytics.yahoo.com #MASTER# BLOCK-REFERRER: http://www.aktivist.pl/ # Blocked URL = http://go.idmnet.bbelements.com/please/showit/46/1/1/1/?typkodu=img&keywords= go.idmnet.bbelements.com/please/showit/ # Blocked URL = http://gm-link.com/tm_image.asp?c=12345&x=0&u=email@address.tld&orc.gif gm-link.com/ ############################################################################# # Site-specific block patterns; ############################################################################# {+block{Domain parking site}} #MASTER# BLOCK-REFERRER: http://www.inetcat.org # Blocked URL = http://www.sedoparking.com/www.inetcat.org .sedoparking.com/ # Blocked URL = http://landing.trafficz.com/index.php?domain=www.inetcat.org landing.trafficz.com/ # Blocked URL = http://www.searchnut.com/?domain=www.inetcat.org .searchnut.com/\?domain #MASTER# REMARKS: Verizon should know better #MASTER# BLOCK-REFERRER: http://www.qwetyhjkl.com # Blocked URL = http://wwwz.websearch.verizon.net/search?qo=www.qwetyhjkl.com wwwz.websearch.verizon.net/search\?qo= {+block{Site-specific block pattern matches.}} #MASTER# BLOCK-REFERRER: http://www.brooksbrothers.com/ 10/18/06 #MASTER# BLOCK-REFERRER: http://www.autodesk.com/ # Blocked URL = http://www.hitbox.com/foobar .hitbox.com #MASTER# BLOCK-REFERRER: http://www.the-gadgeteer.com/palmos.html 10/18/06 # Blocked URL = http://www..the-gadgeteer.com/cgi-bin/getimage.cgi/ .the-gadgeteer.com/cgi-bin/getimage.cgi/ #MASTER# BLOCK-REFERRER: http://dest.travelocity.com/DestGuides/geo_frontdoor/0,,TRAVELOCITY,00.html?HPTRACK=icon_dest # Blocked URL = http://dest.travelocity.com/website/destinations/images/partner_frommers.gif # Blocked URL = http://dest.travelocity.com/website/destinations/images/travelex_logo.gif dest.travelocity.com/website/destinations/images/partner_frommers.gif dest.travelocity.com/website/destinations/images/travelex_logo.gif #MASTER# BLOCK-REFERRER: http://us.imdb.com/Title?0110912 10/18/06 #MASTER# BLOCK-REFERRER: http://www.imdb.com/help/boards/markup #MASTER# REMARKS: 2nd is for emoticons exception i.imdb.com/Photos/CMSIcons/(?!buttons|emoticons) rcm.amazon.com #MASTER# BLOCK-REFERRER: http://www.nytimes.com/ 10/18/06 # Blocked URL = http://www.nytimes.com/adx/foo .nytimes.com/adx/ #MASTER# BLOCK-REFERRER: http://www.sharereactor.com/ 10/19/06 #MASTER# BLOCK-REFERRER: http://www.popupad.net/ #www.popupad.net/ats/ .adtrak.net .elitemediagroup.net .popuptraffic.com #MASTER# BLOCK-REFERRER: http://www.famousbabes.com/gabrielleR/grpics1.htm 10/19/06 #MASTER# BLOCK-REFERRER: http://www.hit-now.com/ .hit-now.com #MASTER# BLOCK-REFERRER: http://www.pgpi.org/ 10/18/06 [a-v]*.valueclick.com #MASTER# BLOCK-REFERRER: http://astalavista.box.sk/ #MASTER# REMARKS: Yea, all these at one site! 10/19/06 .cpays.com .oxado.com .adult*finder.com #MASTER# DONT-VERIFY: Opera's list of banners to load (XML) /scripts/cms/xcms.asp #MASTER# REMARKS: Actionsfile tracker 1559740 09/16/06 See http://www.vibrantmedia.com/whatisIntelliTXT.asp #MASTER# BLOCK-REFERRER: http://www.hartware.de/news_40795.html /.*intellitxt/ .intellitxt.com #MASTER# REMARKS: per Actions File tracker: #1597893 11/17/06, similar to intellitxt .kontera.com #MASTER# REMARKS: 2007-08-17 HB, similar to intellitxt #MASTER# BLOCK-REFERRER: http://www.webhostingtalk.com/archive/index.php/t-533369.html .tribalfusion.com/ctxt #MASTER# REMARKS: Video advertizer, owned by doubleclick.net. #MASTER# BLOCK-REFERRER: http://www.ign.com/ 09/17/06 .klipmart.com #MASTER# BLOCK-REFERRER: http://gamespot.com 09/26/06 #MASTER# REMARKS: adlog.com.com and ads.com.com ad*.com.com #MASTER# REMARKS: used in redirects: dw.com.com 12/18/06 #MASTER# BLOCK-REFERRER: http://verizon.net 09/29/06 sales.liveperson.net #MASTER# BLOCK-REFERRER: www.avclub.com/ 10/14/06 .iad.liveperson.net #MASTER# BLOCK-REFERRER: http://homedepot.com 09/29/06 #MASTER# BLOCK-REFERRER: http://weather.com 11/03/06 .coremetrics.com/ #MASTER# BLOCK-REFERRER: http://wired.com 09/29/06 .realmedia.com/data/ #MASTER# REMARKS: webbugs, ads and user tracking js in many places. #MASTER# BLOCK-REFERRER: http://washingtonpost.com & http://tomshardware.com 09/29/06 .revsci.net #MASTER# BLOCK-REFERRER: http://www.time.com/time/business/article/0,8599,1073341,00.html 09/29/06 .clickability.com /.*clickability(.com)?/ #MASTER# BLOCK-REFERRER: http://washingtonpost.com 09/29/06 stats.*.ihost.com #MASTER# BLOCK-REFERRER: http://msnbc.com and many others 09/29/06 .2o7.net #MASTER# BLOCK-REFERRER: http://microsoft.com 09/29/06 .webtrends.com #MASTER# BLOCK-REFERRER: http://tomshardware.com 09/29/06 .tacoda. #MASTER# BLOCK-REFERRER: http://www.torrentazos.com 10/04/06 ad.theadhost.com #MASTER# BLOCK-REFERRER: http://www.stuff.co.nz 10/06/06 .adbureau.net #MASTER# BLOCK-REFERRER: http://drudgereport.com 10/06/06 .adgardener.com #MASTER# BLOCK-REFERRER: http://www.connected-media.com/riven/hints.htm 10/14/06 #MASTER# REMARKS: ads.kw.revenue.net/? etc .revenue.net #MASTER# BLOCK-REFERRER: http://www.geocities.com/the_sockman1/index.html 10/15/06 #MASTER# REMARKS: ..and any other page on geocities. Source of the obnoxious Geocities drop-in menu. .geocities.com/js_source #MASTER# BLOCK-REFERRER: http://www.google.com 09/28/06 .dartsearch.net #MASTER# BLOCK-REFERRER: http://wunderground.com 11/02/06 .zedo.com #MASTER# BLOCK-REFERRER: http://realtor.org 11/03/06 .trk.sodoit.com/ #MASTER# BLOCK-REFERRER: http://www.freenews.fr 11/23/06 Actionsfile feedback item #1597034 .espace.netavenir.com #MASTER# BLOCK-REFERRER: http://www.powerdvd.com/ 12/28/06 .hitfarm.com #MASTER# BLOCK-REFERRER: http://www.uk-businessdirectory.co.uk/ #MASTER# REMARKS: Action tracker 1616457. Added 2007-01-20. .topnemo.com/engine .top100categories.com/engine #MASTER# REMARKS: Actionsfile feedback item #1647852 2007-01-30 #MASTER# REMARKS: Domain squatting onload pop-ups #MASTER# BLOCK-REFERRER: http://www.memtest.com/ /(t|search)\.php\?uid=ws[a-z0-9]+\.[a-z0-9]+ #MASTER# BLOCK-REFERRER: via Yahoo groups #MASTER# REMARKS: Actionsfile tracker 1645513 2007-01-26 .adinterax.com/(?!(.*)\.(js|gif|jpg)) #MASTER# BLOCK-REFERRER: http://www.weilpod.com #MASTER# REMARKS: Actionsfile feedback item #1710951 2007-05-02 img.bluehost.com #MASTER# BLOCK-REFERRER: http://www.linuxinsider.com/story/57759.html #MASTER# REMARKS: Actionsfile feedback item #1736213 at 2007-06-12 linuxinsider.com/images/sda/ #MASTER# REMARKS: 20070711 Adam Piggott Actionsfile feedback #1700692 #MASTER# REMARKS: Tracking JavaScript #MASTER# BLOCK-REFERRER: http://www.hants.gov.uk/record-office/ [a-z].clickdensity.com #MASTER# REMARKS: Obnoxious "widget" adverts #MASTER# BLOCK-REFERRER: http://www.quickonlinetips.com/archives/2007/08/nokia-offers-free-bl-5c-battery-replacement-for-overheating/ .widgetbucks.com #MASTER# BLOCK-REFERRER: http://www.dailymail.co.uk/pages/live/articles/news/news.html?in_article_id=559547&in_page_id=1770 # Blocked URL = http://img.dailymail.co.uk/i/promo_boxes/groTime_promo.jpg # Blocked URL = http://img.dailymail.co.uk/i/promo_boxes/idealhome_promo.gif img.dailymail.co.uk/i/promo_boxes/ #MASTER# REMARKS: Flash ad, Actionsfile feedback item #2003465 2008-07-01 # Blocked URL = http://cache.opt.fimserve.com/contents/325/84/84325/LIN728x90.swf?%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20clickTag=http%3A//delb.opt.fimserve.com/lnk/%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Fk%3DODk1ODc7Mzs0MDA7ODQzMjU7Zi44LjkuaHYuaGdseHBzbG9uaCBvem0uNzYuZkBAeHp5b3ZAQGxobmxAQCs4XzlAQHhsbnN2biBoZHZ3dm1AQGh2QEBmOzEyMTQ1MTE1MjgzMzA7Mjs7MTMxfDsxOzQ7NzIxODs4ODAyODc3NQ%3D%3Dhref%3Dhttp%3A//www.myspace.com/liveinnordics&clickTarget=_new .fimserve.com #MASTER# REMARKS: Actionsfile feedback item #2004311 2008-07-01, are they all images? # Blocked URL = http://static.lycos-europe.net/lea/se/pricerunner/040608_728x90_payback_digitalkamer.gif static.lycos-europe.net #MASTER# REMARKS: Actionsfile feedback item #2005285 #MASTER# BLOCK-REFERRER: http://hitta.se # Blocked URL = http://82.99.18.195/media.1/112/9460/146016/150x175_Hitta_FV_Feb08.gif 82.99.18.195 #MASTER# REMARKS: Actionsfile feedback item #1888197 and #2975927. #MASTER# REMARKS: Have a "go there anyway" link for clk.atdmt.com and view.atdmt.com. #MASTER# BLOCK-REFERRER: http://www.networkworld.com/resourcelibrary/?tid=4&type=special%20report # Blocked URL = http://clk.atdmt.com/ # Blocked URL = http://view.atdmt.com/action/mrtiwy_FY10Office2010BetaHomeandBiz1_1 .atdmt.com/ #MASTER# REMARKS: Actionsfile feedback item #2723873 2009-04-01 #MASTER# BLOCK-REFERRER: http://www.news.software.coop/paralysed-perl-package-problem/602/ # Blocked URL = http://www.awin1.com/cread.php?s=123049&v=1983&q=80970&r=79561 .awin1.com #MASTER# BLOCK-REFERRER: http://crooksandliars.com/ # Blocked URL = http://rotator.adjuggler.com/servlet/ajrotator/616245/0/vh?z=csm&dim=616028 .adjuggler.com/servlet/ajrotator/ #MASTER# Remark: nothing but "sponsored listings" # Blocked URL = http://bcc.co.uk/ bcc.co.uk/ # Blocked URL = http://fusion.adtoma.com:80/125AFFE801/1DC59C7801.swf # Blocked URL = http://fusion.adtoma.com/1254D5CC01/1E43C76801.jpg fusion.adtoma.com/ #MASTER# Remark: Actionsfile feedback item #2975895 2010-03-24 # Blocked URL = http://ping.chartbeat.net/ping?h=uservoice.com&p=%2Fsuggestions%2Fping-chartbeat-net-sucks&u=3 .chartbeat.net/(.*/)?ping\? # Blocked URL = http://s.atemda.com/Admeta.js # Blocked URL = http://atemda.com/ClickThrough.ashx?pId=9616&mId=14484&tId=634102151426089505&opS=1&admetac=mR3sJ3%2b9yleq%2bHowITh0hw%3d%3d #MASTER# BLOCK-REFERRER: http://www.startpagina.nl .atemda.com/ #MASTER# Remark: 2o7.net, omtrdc.net and www91.intel.com are domains used by Omniture # Blocked URL = http://ciscosystemsinc.tt.omtrdc.net/m2/ciscosystemsinc/mbox/standard?mboxHost=www.cisco.com&mboxSession=12 .omtrdc.net/ # Blocked URL = http://www91.intel.com/b/ss/intelcorp,intelcorpdc/...ONDataProvider.aspx%3FDownloadType%3DDrivers&ot=A&AQE=1 www91.intel.com/ #MASTER# BLOCK-REFERRER: http://www.sport.pl/pilka/1,65080,10189388,Premier_League__Angielskie_media__Szaleni_United_zniszczyli.html # Blocked URL = http://reklamy.sfd.pl/sportpl.ashx?clickTag=http://gazeta.hit.gemius.pl/hitredir/id=ApuVHydwkYW81VSL0PZYqnXoDosBucMur1zZqGEAJa7.X7/stparam=sifgmrnlfi/url=http://reklamy.sfd.pl/sportpl_redirect.ashx reklamy.sfd.pl/ #MASTER# BLOCK-REFERRER: http://lwn.net/Articles/478657/ # Blocked URL = http://rotation.linuxnewmedia.com/www/delivery/avw.php?zoneid=26&n=aa584766 rotation.linuxnewmedia.com/ # Blocked URL = http://de17a.com/a/33039/26891.swf de17a.com/ #MASTER# BLOCK-REFERRER: http://thepiratebay.se/ # Blocked URL = http://cltomedia.info/delivery/afr.php?zoneid=7&cb=1279946132 cltomedia.info/delivery/ #MASTER# BLOCK-REFERRER: http://thepiratebay.se/ # Blocked URL = http://cdn2.adexprt.com/clkads/sky2.html .adexprt.com/ #---------------------------------------------------------------------------- # JavaScripts and Texts for ad and popup generation #---------------------------------------------------------------------------- #MASTER# REMARKS: broadening scope from a.tfag.de/js.ng/ 10/23/06 # Blocked URL = http://a.tfag.de/js.ng/ /js\.ng/ #MASTER# BLOCK-REFERRER: http://www.britannica.com/ 10/23/06 /popunder #MASTER# BLOCK-REFERRER: http://www.earthcore.com/ feedback item #1605385 12/14/06 /t\.php\?cat=.*&kw=.*&sc= #MASTER# REMARKS: Actionsfile tracker #1674363 2007-03-05, text ads #MASTER# BLOCK-REFERRER: http://www.securityfocus.com/archive/1/461489/30/0/threaded jlinks.industrybrains.com/ #MASTER# BLOCK-REFERRER: http://www.linuxworld.com/news/2007/061307-brian-aker-interview.html #MASTER# REMARKS: Actionsfile feedback item #1736794 2007-06-13 js.adsonar. #MASTER# BLOCK-REFERRER: http://news.zdnet.co.uk/software/0,1000000121,39209666,00.htm # Blocked URL = http://bwp.zdnet.com/search?dw-siteid=2&dw-ptid=2100&dw-edid=2&dw-ontid=800004 bwp. # Blocked URL = http://us.mc123.mail.yahoo.com/mc/stampNonJs .yahoo.com/mc/stampNonJs ############################################################################# # Generic block-as-image patterns: ############################################################################# {+block-as-image} # XXX: Should use "+block{Blocked image request.}", but Privoxy-Regression-Test # isn't smart enough to split that properly. # Sticky Actions = +block +handle-as-image #MASTER# BLOCK-REFERRER: http://experts-exchange.com/os2gen/ /.*ad_?image\.(php|cgi) #MASTER# BLOCK-REFERRER: http://flashhentai.com/Tgp/28-09-2002/index4.html #MASTER# BLOCK-REFERRER: http://www.thughosting.com/www/ixix/a912/912s2.html #MASTER# BLOCK-REFERRER: http://www.fantasiegirl.com/cumshots/3/spunkpatrolgirl302.htm #MASTER# BLOCK-REFERRER: http://www.asianuncut.com/asian2/sep5628.html #MASTER# BLOCK-REFERRER: http://www.tatgirls.com/gals/redhot-2/kitty-carl/lb10.html #MASTER# BLOCK-REFERRER: http://www.cream-porn.com/1/hard/29/02.html /.*recips?/ #MASTER# BLOCK-REFERRER: http://www.paroles.net/texte/10818 /bandeaux/ #MASTER# COMMENT: SF tracker 09/15/06 /.*client_?ad\.(php|cgi) #MASTER# COMMENT: SF tracker 09/15/06 /.*AIM_UAC.adp #MASTER# BLOCK-REFERRER: http://www.wunderground.com/ 2007-01-20 #MASTER# COMMENT: banner at top of page http://server2.as5000.com/AS5000/adserver/click?ID=ADST-00015&C=0&T=1169332403 /(.*/)?adserver/image #MASTER# COMMENT: Also from wunderground.com: http://icons-aa.wunderground.com/ads/images/TripAdvisor-Blinky.gif 2007-01-20 # Blocked URL = http://icons-aa.wunderground.com/ads/images/TripAdvisor-Blinky.gif # URL = http://icons-aa.wunderground.com/ads/images/TripAdvisor-Blinky.gif /(.*/)?ads/images/ # Blocked URL = http://ad.yieldmanager.com/st?ad_type=iframe&ad_size=728x90&site=123§ion_code=123 /.*\?ad_(type|size)= ############################################################################# # Site-specific block-as-image patterns: ############################################################################# #---------------------------------------------------------------------------- # Banner farms: #---------------------------------------------------------------------------- #MASTER# BLOCK-REFERRER: http://www.cnn.com/ #MASTER# BLOCK-REFERRER: http://www.aol.com/ #MASTER# COMMENT: There are at least ar.atwola and pr.atwola. 10/01/06 # Blocked URL = http://ar.atwola.com/ # Blocked URL = http://pr.atwola.com/ ?r.atwola.com #MASTER# BLOCK-REFERRER: http://www.altavista.com/ #MASTER# BLOCK-REFERRER: http://www.tecchannel.de/ #MASTER# BLOCK-REFERRER: http://www.whowhere.lycos.com/ #MASTER# REMARKS: Do NOT block /adj or /adi here since these are typically JS .[a-vx-z]*.doubleclick.net/(?!(.*/)?ad[ji]) #MASTER# BLOCK-REFERRER: http://www.joecartoon.com/ 10/17/06 .*servedby.advertising.com #MASTER# BLOCK-REFERRER: http://www.yahoo.com/ #.a.yimg.com/(?:(?!/i/).)*$ #.a[0-9].yimg.com/(?:(?!/i/).)*$ #.yimg.com/(.*/)?a/ #.yimg.com/.*/(flash|java)/promotions #.yimg.com/a/.*/flash/ #MASTER# REMARKS: The above replaced with below. Actions file tracker #1645616 2007-01-27 .yimg.com/.*\.yimg\.com/a/ #MASTER# REMARKS: Yahoo doesn't always have ".yimg.com/a/" in the URL for ads now 2010-02-28 #MASTER# BLOCK-REFERRER: various yahoo pages # Blocked URL = http://l.yimg.com/a/a/1-/flash/promotions/l3/intl/100214/300x250mfeyap.jpg # Blocked URL = http://l.yimg.com/a/a/1-/flash/promotions/l3/intl/100219/300x250mfeya.gif .yimg.com/.*/flash/promotions/.*\.(gif|jpg)$ bs*.gsanet.com bs*.einets.com .qkimg.net #MASTER# BLOCK-REFERRER: http://salon.com/ 10/19/06 #MASTER# BLOCK-REFERRER: http://maps.yahoo.com/ #MASTER# REMARKS: Banner farms; just exclude their corp. info #MASTER# REMARKS: and have a "go there anyway" link for clk.atdmt.com and view.atdmt.com #MASTER# REMARKS: (Actionsfile feedback item #1888197 and #2975927) [abd-ux-z]*.atdmt.com/ #MASTER# BLOCK-REFERRER: http://www.exactaudiocopy.de/ 09/11/06 #MASTER# BLOCK-REFERRER: http://stanford.facebook.com/home.php # URL = http://www.fastclick.net/ .fastclick.net #MASTER# BLOCK-REFERRER: http://www.math.com/school/subject2/lessons/S2U3L6DP.html 09/11/06 .casalemedia.com #MASTER# BLOCK-REFERRER: http://www.macnn.com/ 10/09/06 kermit.macnn.com/ #MASTER# BLOCK-REFERRER: http://www.globalseeker.com/freesamples/ 10/09/06 quinst.com/images valuepage.com/images #MASTER# BLOCK-REFERRER: http://www.imdb.com/ ia.imdb.com/.*\.swf #MASTER# BLOCK-REFERRER: http://www.dietngo.com/ 10/09/06 .reactivpub. #MASTER# BLOCK-REFERRER: http://freemail.web.de/ 10/17/06 #MASTER# BLOCK-REFERRER: http://www.nytimes.com/2003/11/19/politics/19DEAN.html?ex=1069822800&en=dc82dfff0502faeb&ei=5062&partner=GOOGLE .as*.falkag. #MASTER# BLOCK-REFERRER: http://www.macnn.com/news/18944 10/17/06 a.tribalfusion.com/ #MASTER# BLOCK-REFERRER: http://reviews.infosyncworld.com/palmos/featured/index.html?start=1&offset=10 10/19/06 .adserver.com/ #MASTER# BLOCK-REFERRER: http://computers.cnet.com/hardware/0-1027-404-20857400.html?tag=rev #MASTER# REMARKS: Pointdexter .ru4.com/ #MASTER# BLOCK-REFERRER: http://www.boursorama.com/infos/actualites/detail_actu_marches.phtml?news=1510287 .smartadserver.com/ #MASTER# BLOCK-REFERRER: http://www.chez.tiscali.fr/ 10/07/06 admedia. #MASTER# REMARKS: Bannerfarm used by Morpheus file sharing software jmcms.cydoor.com/ #MASTER# BLOCK-REFERRER: http://www.tech-report.com/etc/2003q2/3dmurk03/index.x?pg=7 #MASTER# REMARKS: Netshelter.com farm #MASTER# REMARKS: Not found but leaving 10/07/06 .adtrix.com #MASTER# BLOCK-REFERRER: http://discussion.brighthand.com/forumdisplay.php?s=fee44a5b2a6fc2e9e79d6472bc8fbe94&forumid=197 10/19/06 *[0-9].tribalfusion.com/ #MASTER# REMARKS: Actions file tracker 1547656 09/02/06 #MASTER# REMARKS: Update pattern: Actionsfile feedback item #1698822, was opened at 2007-04-11 to catch https://secure.img-cdn.mediaplex.com/0.... # Blocked URL = https://secure.img-cdn.mediaplex.com/0/7454/43775/YA3149_17566_728x90_FCR_07.gif .img*.mediaplex.com #MASTER# BLOCK-REFERRER: http://www.tomshardware.com/ 09/28/06 #MASTER# REMARKS: There is adfarm and altfarm.mediaplex #MASTER# REMARKS: 20070711 Actionsfile feedback #1749013 /ad/fm/ appended, as click-throughs were being blocked. Could only find adverts being served from /ad/fm/ a*farm.mediaplex.com/ad/fm/ #MASTER# REMARKS: Support request 1312362 09/08/06 #MASTER# DUPLICATED: adserver.itsfogo.com #MASTER# REMARKS: Actionsfile feedback 09/11/06 http://matrix.mediavantage.de/mx.one?p=210&pa=1060&pb=1906&pd=10944&aid=399&x=120&y=240&ts=2005.06.27.21.38.08 # URL = http://matrix.mediavantage.de/mx.one?p=210&pa=1060&pb=1906&pd=10944&aid=399&x=120&y=240&ts=2005.06.27.21.38.08 #MASTER# BLOCK-REFERRER: http://www.heise.de/newsticker/meldung/61067 matrix.mediavantage. #MASTER# REMARKS Ad generator, SF user tracker 09/11/06 .cibleclick.com #MASTER# REMARKS: Ad generator 09/11/06 http://c1.netshelter.net/campaigns/ITTTech/itttech09_728x90.gif #MASTER# BLOCK-REFERRER: http://www.osnews.com/ 09/11/06 .netracker.net #MASTER# REMARKS: ad generator domain per SF tracker 09/11/06 .interclick.com #MASTER# REMARKS: Ad generator http://c4.maxserving.com/iserver/site=5314/area=ad728x90/aamfmt=normal/aamsz=banner/PageID= #MASTER# BLOCK-REFERRER: http://www.imdb.com/name/nm0000168/bio 09/12/06 # URL = http://c4.maxserving.com/iserver/site=5314/area=ad728x90/aamfmt=normal/aamsz=banner/PageID= .maxserving.com #MASTER# REMARKS: Ad generator http://partner.gonamic.de/Affiliate/ViewCounter/index.cfm?trackingID=368232&bIsAffiliate=0 #MASTER# BLOCK-REFERRER: http://torrent.to/torrent/ 09/12/06 # URL = http://partner.gonamic.de/Affiliate/ViewCounter/index.cfm?trackingID=368232&bIsAffiliate=0 .gonamic.de # URL = http://img.webads.nl/ .webads. #MASTER# REMARKS: Ad generator http://media.adlegend.com/centrport/20060/511290/GM_emplyee_300x250.gif # URL = http://media.adlegend.com/centrport/20060/511290/GM_emplyee_300x250.gif #MASTER# BLOCK-REFERRER: http://news.yahoo.com/news?tmpl=story&cid=534&e=1&u=/ap/20050613/ap_on_he_me/cancer_research .adlegend.com #MASTER# REMARKS: Ad generator 09/12/06 http://dist.belnk.com//4/placement/1738/alt_offer/static.jpg # URL = http://dist.belnk.com//4/placement/1738/alt_offer/static.jpg #MASTER# BLOCK-REFERRER: http://groups.yahoo.com/group/louisianaandmardigra/messages/1?viscount=100 .belnk.com .euros4click. #MASTER# BLOCK-REFERRER: http://www.planet3dnow.de/cgi-bin/newspub/viewnews.cgi?id=1129904195 ads-*.quarterserver. #MASTER# BLOCK-REFERRER: http://adrian.adrian.org/ 10/07/06 searchportal.information.com/ #MASTER# BLOCK-REFERRER: http://www.nbc4.com/news/2672416/detail.html 10/17/06 images.ibsys.com/ #MASTER# BLOCK-REFERRER: http://www.rentalhouses.com/search_results.php?searchnew=1&citys_city=&citys_county=&citys_state=&ssubmit=Search&Szip=40205&keyword=&listingid=&strs_state=&strs_city=&strs_street= 11/05/06 .lduhtrp.net/image #MASTER# BLOCK-REFERRER: http://floodle.net 2007-01-21 SF tracker scripts.chitika.net/.*\.(gif|png|jpg) #MASTER# REMARKS: Actionsfile feedback item #1648478 2007-01-30 .projectwonderful.com/gen.php #MASTER# BLOCK-REFERRER: http://www.multimap.com/ (sporadic) #MASTER# REMARKS: Actionsfile feedback item #1665682 2007-02-21 .akamai.net/.*\.adtech\.de/.*\.(gif|png) #MASTER# BLOCK-REFERRER: via Yahoo groups #MASTER# REMARKS: Actionsfile tracker 1645513 2007-01-26 .adinterax.com/.*\.(gif|jpg) #MASTER# BLOCK-REFERRER: http://www.wotzon.com/profilepage.html?comp_id=1002310&CatID=2 #MASTER# REMARKS: Ad generator per Actionsfile feedback item #1749870 2007-07-08 # URL = http://img.directtrack.com img.directtrack.com #MASTER# BLOCK-REFERRER: http://www.thinkbroadband.com/news/3621-complaint-about-orange-broadband-advertising-upheld.html # URL = http://eas.apm.emediate.eu/media.5/1/1228/19193/ACT1215_120x600_v3.gif .emediate.eu/ # URL = http://feedads.googleadservices.com/~a/dPlpGU767u4D4kVO8EGuUlnf1Q0/i # URL = http://feedads.googleadservices.com/~at/EpX-FnAXxwdaBSq-GRze37-rG0M/i .googleadservices.com/~ #MASTER# REMARKS: Block yahoo email & ygroups banner ad # URL = http://ts.richmedia.yahoo.com/...hummingbird.jpg?adxq=NNN .richmedia.yahoo.com/.*\.(gif|jpe?g)\?ad # Blocked URL = http://this.content.served.by.adshuffle.com/p/a=/view.pxl .served.by.adshuffle.com/ # Blocked URL = http://newsletter.adsonar.com/nwrss/imgs/nwr_123.PNG?placementId=123&plid=123&rotation=1&type=2&&url=NA .adsonar.com/.*/imgs/ # Blocked URL = http://rtb.pclick.yahoo.com/images/nojs.gif?p=3 .pclick.yahoo.com/images/ # Blocked URL = http://rover.ebay.com/ar/1/2/3?mpt=123&adtype=1&size=728x90 # Blocked URL = http://rover.ebay.com/ar/1/711-53200-19255-0/1?mpt=CacheBuster&adtype=1&size=1x1&type=3&campid=5336328269&toolid=10001 rover.ebay./ar.*\&adtype= # Blocked URL = http://resources.parfym.se/tradedoubler/250x360.swf /tradedoubler/.*\.swf # Blocked URL = http://hstse.tradedoubler.com/file/142609/440x220.swf hstse.tradedoubler.com/.*\.swf # Blocked URL = http://www.zdnetasia.com/2007/techguide/network/sponsor/i/logmein_mpu_whitepaper.gif # Blocked URL = http://www.zdnetasia.com/2007/techguide/network/sponsor/sidebar.gif www.zdnetasia.com/.*/sponsor/.*\.gif$ # Blocked URL = http://pagead2.googlesyndication.com/pagead/imgad?id=CPjtipDs9taquQEQoAEYwgQyCIvo2PNnQywb .googlesyndication.com/.*/imgad\? #MASTER# BLOCK-REFERRER: http://textsfromlastnight.com/texts/page:19 # Blocked URL = http://optimize.indieclick.com/www/delivery/avw.php?zoneid=337501&cb=4147152&n=a530d6f1 #MASTER# BLOCK-REFERRER: http://textsfromlastnight.com/texts/page:19 optimize.indieclick.com/ # Blocked URL = http://optimized-by.rubiconproject.com/a/8327/13451/26301-2.img optimized-by.rubiconproject.com/ # Blocked URL = http://g.adspeed.net/ad.php?do=html&zid=14678&wd=728&ht=90&target=_top #MASTER# BLOCK-REFERRER: http://seclists.org/fulldisclosure/2012/Aug/4 g.adspeed.net/ # Blocked URL = http://imp.double.net/?5463;234;4505;0;39296 imp.double.net/ #---------------------------------------------------------------------------- # Cross-site user tracking #---------------------------------------------------------------------------- #MASTER# REMARKS: +block-as-image here #MASTER# BLOCK-REFERRER: http://os2.ru/ 10/07/06 .*.*.spylog.com/ #MASTER# BLOCK-REFERRER: http://www.dhtmlplanet.com/ 10/07/06 statse.webtrendslive.com #MASTER# BLOCK-REFERRER: http://www.versiontracker.com/ #MASTER# REMARKS: 1) Used on many sites 2) URLs don't _end_ in .gif, hence +imageblock spinbox.versiontracker.com/.*\.(gif|jpg) #MASTER# BLOCK-REFERRER: http://mycroft.mozdev.org/ 10/07/06 stat.onestat.com #MASTER# BLOCK-REFERRER: http://www.meparecebien.com/noticias/discograficas/sinnamon-records/sinnamon-records-libera-a-sus-artistas-nacionales-para-el-mercado-digital-401/ #MASTER# REMARKS: Actionsfile feedback item #1644583 2007-03-05 imp*.tradedoubler.com #MASTER# BLOCK-REFERRER: http://www.sharepoint.boo.pl/ #MASTER# REMARKS: Not found, but left 10/07/06 stat.webmedia. #MASTER# BLOCK-REFERRER: http://www.asp-php.net/index.php 10/07/06 log*.xiti.com/ log*.hit-parade.com/ #MASTER# BLOCK-REFERRER: http://www.msnbc.com/news/884810.asp?0si=-&cp1=1 # URL = http://www.xml.eshop.msn.com/tracksponsorimpression.asp www.xml.eshop.msn.com/tracksponsorimpression.asp #MASTER# BLOCK-REFERRER: http://www.planetgamecube.com/ 10/07/06 .imrworldwide.com #MASTER# REMARKS: Actionsfile feedback 1555719 09/10/06, and Debian Bug report #MASTER# BLOCK-REFERRER: http://www.nrc.nl/ 09/12/06 .clicktracks.com #MASTER# REMARK: Actionsfile tracker 1159072 09/12/06 .etracker. #MASTER# REMARK: Actionsfile tracker 1243494 09/12/06 #MASTER# BLOCK-REFERRER: http://www.spanked-slaves.com/movies14/bdsm14c.html .x-traceur.com #MASTER# BLOCK-REFERRER: http://www.aintitcool.com/ 10/05/06 content.ipro.com #MASTER# BLOCK-REFERRER: http://www.weatherbug.com/default.asp 10/05/06 .247realmedia.com #MASTER# BLOCK-REFERRER: http://www.samachar.com/ 10/05/06 .sify.com #MASTER# BLOCK-REFERRER: http://www.nbc4.com/news/2672416/detail.html 10/06/06 .searchignite.com #MASTER# BLOCK-REFERRER: http://www.sdtimes.com/ 10/07/06 .statcounter.com #MASTER# BLOCK-REFERRER: http://www.dn.se/ 10/07/06 .research-int.se/data #MASTER# BLOCK-REFERRER: http://www.chez.aliceadsl.fr/ 10/07/06 .cybermonitor.com #MASTER# BLOCK-REFERRER: http://disney.go.com #MASTER# BLOCK-REFERRER: http://abcnews.com 10/15/06 log.go.com/log #MASTER# BLOCK-REFERRER: http://www.care2.com 10/18/06 stats.indextools.com #MASTER# BLOCK-REFERRER: http://www.techcrunch.com/ 12/16/06 #1616497 3 urls. tra*.measuremap.com .eurekster.com/sidebar tra*.mybloglog.com #MASTER# BLOCK-REFERRER: http://www.polymervision.com/ #MASTER# REMARKS: Actionsfile feedback item #1629370 01/16/07 .guesttrace. #MASTER# BLOCK-REFERRER: http://dictionary.com #MASTER# REMARKS: Actionsfile feedback item #165078 2007-02-05 insightxe./data/ #MASTER# BLOCK-REFERRER: http://www.unitedairlines.com #MASTER# REMARKS: Actionsfile feedback item #1650797 2007-02-05 .insightfirst.com #MASTER# BLOCK-REFERRER: http://rss.slashdot.org/Slashdot/slashdot # Blocked URL = http://rss.slashdot.org/~a/Slashdot/slashdot?i=ofbWqX # URL = http://rss.slashdot.org/~a/Slashdot/slashdot?i=ofbWqX rss.slashdot.org/~a/Slashdot/slashdot\? # Blocked URL = http://rss.slashdot.org/~r/Slashdot/slashdot/~4/102113044 # URL = http://rss.slashdot.org/~r/Slashdot/slashdot/~4/102113044 rss.slashdot.org/~r/Slashdot/slashdot/~4/ #MASTER# BLOCK-REFERRER: http://www.isys.ucl.ac.be/bchi/research/Kwaresmi.htm #MASTER# REMAKRKS: Actionsfile feedback item #1849627 2007-12-12 [a-z][0-9].nedstatbasic.net/ #MASTER# BLOCK-REFERER: http://feeds.feedburner.com/dilbertdailystrip/ # Blocked URL = http://feeds.feedburner.com/~r/DilbertDailyStrip/~4/274512747 #MASTER# BLOCK-REFERER: http://feeds.feedburner.com/PCLoadLetter # Blocked URL = http://feeds.feedburner.com/~r/PCLoadLetter/~4/270448381 #MASTER# REMAKRKS: This seem to be a common pattern for web bugs in feedburner feeds. feeds.feedburner.com/~r/.*/~4/ # Blocked URL = http://feedproxy.google.com/~r/DilbertDailyStrip/~4/y_kXD1z1HO0 feedproxy.google.com/~r/.*/~4/ # Blocked URL = http://feeds.feedburner.com/~a/DilbertDailyStrip?a=Ebzxel #MASTER# REMAKRKS: This looks like a pattern as well, maybe we should block feeds.feedburner.com/~a/ here. feeds.feedburner.com/~a/DilbertDailyStrip\? #MASTER# BLOCK-REFERER: http://www.buch.de/ # URL = http://track.webtrekk.de/471497967328727/wt.pl?p=177,de.buch.show.home,1,1024x768,24,1,1218816426275,0,884x653,0&enc1=%FC&enc2=iso-8859-1&st=view&la=en-US&np=Default%20Plugi track.webtrekk.de/ #MASTER# BLOCK-REFERER: https://sourceforge.net/ # URL = http://b.scorecardresearch.com/p2?c1=2&c2=6035546&c3=&c4=&c5=&c6=&c15=&cj=1 b.scorecardresearch.com/ # URL = https://sb.scorecardresearch.com/ sb.scorecardresearch.com/ #MASTER# BLOCK-REFERRER: http://sourceforge.net/projects/ijbswa/ # Blocked URL = http://b.collective-media.net/seg/cm/cm_aa_gn1 b.collective-media.net/ #MASTER# BLOCK-REFERRER: http://www.spiegel.de/ # Blocked URL = http://spiegel.ivwbox.de/cgi-bin/ivw/CP/1001;/home/c-18/be-PB64-aG9tZXBhZ2UvY2VudGVy/szwprofil-1001 #MASTER# BLOCK-REFERRER: http://www.heise.de/ # Blocked URL = http://heise.ivwbox.de/2004/01/survey.js .ivwbox.de/ #---------------------------------------------------------------------------- # Specific counters (see above for generic patterns) #---------------------------------------------------------------------------- #MASTER# BLOCK-REFERRER: http://www.distrowatch.com/table.php?distribution=linex 10/19/06 #MASTER# BLOCK-REFERRER: http://floodle.net 2007-01-21 tracker #1641102 s*.sitemeter.com/(meter|js/counter.js) #MASTER# BLOCK-REFERRER: http://personales.mundivia.es/lbouza/ 10/19/06 # URL = http://fastcounter.bcentral.com/ fastcounter.bcentral.com/ #MASTER# BLOCK-REFERRER: http://osnews.com/ 10/19/06 # URL = http://bilbo.counted.com/ bilbo.counted.com/ #---------------------------------------------------------------------------- # On-site ads and other single sources: #---------------------------------------------------------------------------- #MASTER# BLOCK-REFERRER: http://www.travelocity.com/Vacations/0,,TRAVELOCITY||Y,00.html?HPTRACK=mpc_vac #MASTER# BLOCK-REFERRER: http://dest.travelocity.com/DestGuides/geo_frontdoor/0,,TRAVELOCITY,00.html?HPTRACK=icon_dest 10/07/06 .travelocity./Sponsor_gifs/ #MASTER# REMARKS: Referenced from HTML-Emails (not checked 10/08/06) # URL = http://foo.weather.com/creatives/ # URL = http://bar.weather.com/web/services/email/ .weather.com/creatives/ .weather.com/web/services/email/ #MASTER# BLOCK-REFERRER: http://gamespot.com/gamespot/filters/0,10850,6013548,00.html 10/08/06 /.*/topslots/topslot .contextweb.com/ .offermatica.com/ #MASTER# BLOCK-REFERRER: http://www.jpost.com/ 10/08/06 .adbrite.com #MASTER# BLOCK-REFERRER: http://www.jpost.com/servlet/Satellite?pagename=JPost/A/JPArticle/ShowFull&cid=1038889003183 .jpost.com/images/\d+/promos/ #MASTER# BLOCK-REFERRER: http://www.infoempleo.com/ 10/08/06 .infoempleo.com/(pop-up|images(/Nueva/|/motor)) #MASTER# BLOCK-REFERRER: http://www.hardocp.com/ 10/08/06 hera.hardocp.com/ #MASTER# BLOCK-REFERRER: http://people.aol.com/ 10/08/06 leadback.advertising. #MASTER# BLOCK-REFERRER: http://astalavista.box.sk/ 10/08/06 .yieldmanager.com/ .displayadsmedia.com # URL = http://astalavista.box.sk/adult.foo.jpg astalavista.box.sk/adult.*\.jpg #MASTER# BLOCK-REFERRER: http://www.bol.com.br/ smartad.*.*.* #MASTER# BLOCK-REFERRER: http://www.dinside.no/ 10/08/06 .dinside.no/annonsorer/ #MASTER# BLOCK-REFERRER: http://www.heise.de/ 10/08/06 #MASTER# BLOCK-REFERRER: http://www.spiegel.de/ /RealMedia/ads/ #MASTER# REMARKS: Variation 2007-11-12 /RealMediaAds/ #MASTER# BLOCK-REFERRER: http://www.powerdvd.com 12/28/06 per SF tracker /top\.php\?d=.*\.[a-z]{2,5} #MASTER# REMARKS: Actionsfile feedback item #1764161 2007-07-31 #MASTER# BLOCK-REFERRER: http://www.webster.com/dictionary/revering .google.com/afsonline ############################################################################# # Site-specific unblockers: ############################################################################# {-block} # Sticky Actions = -block #MASTER# UNBLOCK-REFERRER: http://www.faqs.org/ .faqs.org/banner\.html #MASTER# UNBLOCK-REFERRER: http://bannerblind.mozdev.org/ bannerblind.mozdev.org #MASTER# UNBLOCK-REFERRER: http://advogato.org/ advogato.org #MASTER# UNBLOCK-REFERRER: http://www.handelsblatt.com/ ad*.vhb.de #MASTER# UNBLOCK-REFERRER: http://www.globalintersec.com/adv/sendtemp-2001021302.txt .globalintersec.com/adv #MASTER# UNBLOCK-REFERRER: http://www.wunderground.com/geo/BannerPromo/US/NY/New_York.html 10/08/06 banners.wunderground.com/ #MASTER# UNBLOCK-REFERRER: http://www.openoffice.org/ 10/09/06 .openoffice.org/banners/ #MASTER# UNBLOCK-REFERRER: http://www.amazon.com/exec/obidos/tg/browse/-/130/ref=gw_br_dvd/102-9730978-3540926 10/09/06 #MASTER# REMARKS: Part of site decoration .amazon.com/.*/banners/ #MASTER# UNBLOCK-REFERRER: http://www.washingtonpost.com/wp-dyn/articles/A43890-2002Aug4.html #MASTER# REMARKS: Javascripts whose absence messes the page .washingtonpost.com/wp-srv/ # URL = http://www.gnome.org/images/banner-gnomeis .gnome.org #MASTER# UNBLOCK-REFERRER: http://www.nycsubway.org/ 10/09/06 .nycsubway.org/img/banner #MASTER# UNBLOCK-REFERRER: http://www.forgotten-ny.com/ADS/manhattanads/moremahnattan.html # URL = http://www.forgotten-ny.com/ADS/manhattanads/moremahnattan.html .forgotten-ny.com/ADS/ # URL = http://counter.li.org counter.li.org #MASTER# UNBLOCK-REFERRER: http://adrian.adrian.org/ 10/09/06 # URL = http://adrian.adrian.org adrian.adrian.org #MASTER# UNBLOCK-REFERRER: http://adela.karlin.mff.cuni.cz/ 10/09/06 # URL = http://adela.karlin.mff.cuni.cz adela.karlin.mff.cuni.cz #MASTER# UNBLOCK-REFERRER: http://www.swcp.com/rtoads/printmag/issue3/neg_data.html 10/09/06 .swcp.com/rtoads/ #MASTER# UNBLOCK-REFERRER: http://www.privoxy.org/actions/index.php #MASTER# REMARKS: Don't block our own feedback process, even if the #MASTER# REMARKS: parameters contain block patterns # URL = http://www.privoxy.org/actions/index.php .privoxy.org #MASTER# UNBLOCK-REFERRER: http://sourceforge.net/help/tracker.php sourceforge.net/.*tracker #MASTER# UNBLOCK-REFERRER: http://www.brawnylads.com/ # URL = http://www.brawnylads.com/ .brawnylads.com #MASTER# UNBLOCK-REFERRER: http://adzapper.sourceforge.net/ # URL = http://adzapper.sourceforge.net/ adzapper. #MASTER# UNBLOCK-REFERRER: http://de.altavista.com/web/adv # URL = http://de.altavista.com/web/adv .altavista.com/web/adv # URL = http://rads.mcafee.com/rads/scripts/RADS.dll?QueryProduct2 rads.mcafee.com/ # URL = http://linuxfromscratch.org/cgi-bin/lfscounter.cgi linuxfromscratch.org/ #MASTER# UNBLOCK-REFERRER: http://dv411.com/advc50.html # URL = http://dv411.com/advc50.html dv411.com/.*advc50 # URL = http://www.freeswan.org/freeswan_trees/freeswan-1.98b/doc/adv_config.html .freeswan.org/ # URL = http://www.arm.com/support/ads_faq?OpenDocument&ExpandSection=11 www.arm.com/.*ads # URL = http://www.anybrowser.org/campaign/ www.anybrowser.org/ # URL = http://www.tads.org/ www.tads.org/ # URL = http://www.mbe.com/redir/packtrack.asp .mbe.com/redir/packtrack.asp .iship.com/trackit/ # URL = http://www.esis.com.au/AdvSerialCards/Firewire.htm .esis.com.au/AdvSerialCards #MASTER# UNBLOCK-REFERRER: http://www.familysearch.org/ 10/11/06 .familysearch.org/.*banner #MASTER# UNBLOCK-REFERRER: http://coder.com/ 10/11/06 coder.com/creations/banner/ #MASTER# UNBLOCK-REFERRER: http://arnolds.dhs.org/static/adv_tools.html 10/11/06 # URL = http://arnolds.dhs.org/static/adv_tools.html arnolds.dhs.org/static/adv_tools.html #MASTER# UNBLOCK-REFERRER: http://www.gpl.org/ .gpl.org/ #MASTER# UNBLOCK-REFERRER: http://europa.eu.int/yourvoice/ 10/11/06 .europa.eu. #MASTER# UNBLOCK-REFERRER: http://www.schooner.com/~loverso/no-ads/ 10/11/06 # URL = http://www.schooner.com/~loverso/no-ads/ .schooner.com/~loverso/no-ads/ #MASTER# UNBLOCK-REFERRER: http://source.bungie.org/ 10/11/06 source.bungie.org/ # URL = http://adonthell.linuxgames.com/ adonthell.linuxgames.com/ #MASTER# UNBLOCK-REFERRER: http://news.bbc.co.uk/furniture/chinese/banner/bbccantonese_600.gif #MASTER# REMARKS: Banner-free site(s). .bbc.co.uk/ # URL = http://adc.netlabs.org/ adc.netlabs.org/ #MASTER# UNBLOCK-REFERRER: http://www.tela.bc.ca/tads/authoring/multimedia-tads-docs/latin2.htm 10/11/06 # URL = http://www.tela.bc.ca/tads/authoring/multimedia-tads-docs/latin2.htm .tela.bc.ca/tads/ # URL = http://adbusters.org/information/ adbusters.org/ # URL = http://www.eads.com/ # URL = http://www.eads.net/ # URL = http://www.eads.de/ .eads.*/ # URL = http://brew.qualcomm.com/brew/en/developer/resources/ad/documentation.html .qualcomm.com/brew/en/developer/resources/ad/ # URL = http://upgrade.bitdefender.com/update71/avx/Plugins/adsntfs.xmd.gzip /update\d\d/.*adsnt.* #MASTER# UNBLOCK-REFERRER: http://msdn.microsoft.com/ 09/11/06 .microsoft.com/.*masthead #MASTER# UNBLOCK-REFERRER: http://indymedia.org adfree site 09/11/06 .indymedia.org # URL = http://www.seanbaby.com/stupid/comicads05.shtml .seanbaby.com # URL = http://www.cels.org/db/keep-track.pl?cat:1 .cels.org/.*track #MASTER# UNBLOCK-REFERRER: http://www.nic.ad.jp/ See http://jprs.co.jp/en/jpdomain.html 09/11/06 #MASTER# REMARKS: 2007-10-04, increase scope per Actionsfile feedback item #1807613 #.nic.ad.jp #MASTER# REMARKS removed .ad.jp per Actionsfile feedback item #1807613 #MASTER# UNBLOCK-REFERRER: http://www.flickr.com/photo_zoom.gne?id=32594118&size=l 09/11/06 #MASTER# REMARKS: creativecommons.org worthwhile organization 09/11/06 /(.*/)?somerights20.gif .creativecommons.org # URL = http://www.ups.com/WebTracking/track?loc=en_US .ups.com/.*/track #MASTER# UNBLOCK-REFERRER: http://adju.st 09/12/06 .adju. #MASTER# REMARKS: Ad-free art site 09/12/06 .rubberslug.com .freebsd.org .fsf.org .gnu.org #MASTER# REMARKS: SF tracker 09/15/06, and #1750779 2007-07-09 #MASTER# REMARKS: New home? http://adiumx.cachefly.net/Adium_1.0.5.dmg adium*.*. #MASTER# UNBLOCK-REFERRER: http://google.com 10/01/06 #MASTER# REMARKS: This allows many (but not all) Google "Sponsored Links" to function. #MASTER# REMARKS: Presumably if someone clicks these they want to go there. .googleadservices./pagead/adclick #MASTER# UNBLOCK-REFERRER: http://www.garaget.org #MASTER# REMARKS: These are "ads" from individuals selling cars per tracker. 10/06/06 .garaget.org/annonser/ #MASTER# UNBLOCK-REFERRER: http://www.macworld.com/ 10/07/06 #MASTER# REMARKS: Without the unblock, the page layout is horribly broken 10/08/06 edge.macworld.com #MASTER# UNBLOCK-REFERRER: http:// www.discovery.de 10/19/06 #MASTER# REMARKS: These are promos relevant to the page content. .discovery./.*/topads/ #MASTER# UNBLOCK-REFERRER: http://dawn.com #MASTER# REMARKS: SF Actionsfile tracker 10/19/06. These images are not ads. .dawn.com/.*/(9690dina|aurora_award)\. #MASTER# UNBLOCK-REFERRER: http://google.com/reader/ #MASTER# REMARKS: Initial page does not load, per Support request 10/27/06 .google.com/reader/ #MASTER# REMARKS: Actionsfile Tracker 1587079 10/30/06 .parcel2go.com/track #MASTER# REMARKS: Actionsfile Tracker #1612950 12/11/06 .amazon.com/gp/gift-central/.*recip/ #MASTER# UNBLOCK-REFERRER: http://yahoo.com 2007-01-27 #MASTER# REMARKS: Actionsfile Tracker #1645501, this is a UI page element. .yimg.com/.*/themes/ad/ #MASTER# UNBLOCK-REFERRER: http://mozilla.hongo.wide.ad.jp/pub/mozilla.org//thunderbird/releases/ #MASTER# REMARKS: Actionsfile feedback item #1672918 2007-03-03 # URL = http://mozilla.hongo.wide.ad.jp/pub/mozilla.org//thunderbird/releases/ .ad.*/pub/mozilla.org/ # URL = http://lads.myspace.com/mini/mini.swf?b=NDgwNzU1ODE=&o=NjQwNzIzMA==&d=MTE3NDI4ODcwNg==&i=MA==&a=VHJ1ZQ== #MASTER# UNBLOCK-REFERRER: http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=5282733 #MASTER# UNBLOCK-REFERRER: http://lads.myspace.com/videos/vplayer.swf #MASTER# REMARKS: MySpace videos caught by .*ads. The above profile.myspace.com link grabs the vplayer.swf file (which does not work when directly fetched) # URL = http://lads.myspace.com/videos/vplayer.swf lads.myspace.com #MASTER# REMARKS: 20070402 Adam Piggott first-party tracking. 20070411 Moved from generic unblockers by path to site-specific unblockers. #MASTER# UNBLOCK-REFERRER: http://www.shockwave.com/servlet/DownloadEcommTracker?sku=fizzball-pc&promoCode=SiteShockwaveLandingPage # URL = http://www.shockwave.com/servlet/DownloadEcommTracker?sku=fizzball-pc&promoCode=SiteShockwaveLandingPage .shockwave.com/servlet/DownloadEcommTracker #MASTER# REMARKS: 20070411 Adam Piggott fish4.co.uk is a popular UK advertising site for cars, properties and jobs and uses ad/advert all over the place, understandably. # URL = http://www.fish4.co.uk/iad/lettings/advert?adId=12389712&src=nestoria .fish4.co.uk/.*ad #MASTER# REMARKS: Actionsfile feedback item #1700037 2007-04-13 HB # URL = http://www.mp3.com.au/popup/popup.asp?id=110433 .mp3.com.au/.*popup #MASTER# REMARKS Actionsfile feedback #1700915 2007-04-15 # URL = http://www.svd.se/ego/339/http://www.e24.se/dynamiskt/reklam_media/did_15092793.asp # URL = http://www.e24.se/dynamiskt/reklam_media/did_15092793.asp /(.*/)?dynamiskt/reklam_media/did_ #MASTER# REMARKS 20070710 Actionsfile feedback #1751020 switch.atdmt.com/action/ # URL = http://www.parcelforce.com/portal/pw/track?catId=7500082 .parcelforce.com/.*track #MASTER# UNBLOCK-REFERRER: redirect from http://go.microsoft.com/fwlink?linkid=51093 #MASTER# REMARKS: Actionsfile feedback item #1757121 2007-07-19 .microsoft.com/.*/adschema/ # URL = http://upload.wikimedia.org/wikipedia/en/a/ad/Picturecarnegie.jpg .wikimedia.org/ # URL = http://en.wikipedia.org/wiki/Advertisement .wikipedia.org/ #MASTER# REMARKS Actionsfile feedback item #2299717 2008-11-16 # URL = http://en.wiktionary.org/wiki/advertisement .wiktionary.org/ # URL = http://curl.haxx.se/docs/adv_20070710.html .haxx.se/docs/adv_ # URL = http://www.google.com/adsense/ www.google.com/adsense/ # URL = http://www.encyclopediadramatica.com/Advertisement # URL = http://images.encyclopediadramatica.com/images/b/b5/Advertising-Dierentuin.jpg .encyclopediadramatica.com/ #MASTER# UNBLOCK-REFERRER: http://lifehacker.com 2008-04-18 HB # URL = http://tags.gawker.com/assets/minify.php?files=/assets/base.v6/.../comments.css,/assets/base.v6/css/messages.css,/assets/base.v6/css/ui.css tags.gawker.com/.*css$ # URL = http://cgi.tnt.co.uk/TrackNTrace/quicktrack.asp .tnt.co.uk/TrackNTrace/ #MASTER# UNBLOCK-REFERRER: http://www.supermediastore.com/trackorder.html # URL = http://secure.howtoburndvd.net/ups/track.php /ups/track\.php #MASTER# REMARKS: Actionsfile feedback item #1886140 2008-02-04 #MASTER# UNBLOCK-REFERRER: http://idonthateyouall.imeem.com/video/8zH0_f9i/kiley_rilo_pull_me_in_tighter_art_video/ # URL = http://ad.doubleclick.net/crossdomain.xml ad.doubleclick.net/crossdomain\.xml #MASTER# REMARKS: Support request 2838390: 2009-08-16: nfl.com videos not working #MASTER# REMARKS: bbc.co.uk videos references ad.uk.doubleclick.net # URL = http://ad.doubleclick.net/879366/DartShell9_8.swf?adServerHost=http://ad.doubleclick.net # URL = http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml; # URL = http://ad.doubleclick.net/879366/DartShellPlayer9_8_01_00.swf # URL = http://ad.uk.doubleclick.net/879366/DartShell7_7.swf?adServerHost=http://ad.uk.doubleclick.net .doubleclick.net/.*/DartShell.*\.swf .doubleclick.net/.*/DARTSHELLCONFIGXML #MASTER# REMARKS: Actionsfile feedback item #2021509 2008-07-18 #MASTER# REMARKS: Allow realplayer site help popup windows #MASTER# UNBLOCK-REFERRER: http://real.custhelp.com/cgi-bin/real.cfg/php/enduser/std_adp.php?p_faqid=4512 # URL = http://real.custhelp.com/cgi-bin/real.cfg/php/enduser/popup_adp.php real.custhelp.com/cgi-bin/real\.cfg/php/enduser/popup_adp\.php # URL = http://fritz.fonwlan.box/cgi-bin/webcm?getpage=../html/de/help/popup.html&var:lang=de&var:pagename=hilfe_syslog&var:anker=24 fritz.fonwlan.box/ # URL = http://fritz.box/cgi-bin/webcm?getpage=../html/de/help/popup.html&var:lang=de&var:pagename=hilfe_syslog&var:anker=24 fritz.box/ #MASTER# REMARKS: Actionsfile feedback item #2043327 2008-08-08 # URL = http://kb.adobe.com/selfservice/viewContent.do?externalId=kb402747&sliceId=1 .adobe.com # URL = http://qa.debian.org/popcon.php # URL = http://qa.debian.org/popcon-png.php?packages=privoxy&show_installed=on&want_legend=on&want_ticks=on&date_fmt=%25Y-%25m&beenhere=1 qa.debian.org/popcon #MASTER# REMARKS: Support Requests item #2432535 2008-12-16 # URL = http://www.mta.info/bandt/traffic/advmain.htm .mta.info/.*advmain.htm$ #MASTER# REMARKS: We also use this as a light character class test, therefore the additional URL directives. # URL = http://www.proaurum.de/bannerA2/image/pro_master_r3_01_04.gif # URL = http://www.proaurum.de/bannerA1/image/limitorder2.gif # URL = http://www.proaurum.de/bannerA3/image/pro_master_r5_banken_01_01+.gif # URL = http://www.proaurum.de/bannerB2/image/pro_banner_mitte.gif # URL = http://www.proaurum.de/bannerB1_/image/pro_banner_links.gif # URL = http://www.proaurum.de/bannerC1/image/partner1.png .proaurum.de/banner[ABC]\d_?/ # URL = http://www.goldmoney.com/en/images/home/banner_r4_c1.gif .goldmoney.com/ #MASTER# REMARKS: Actionsfile feedback item #2017126 2008-07-13 #MASTER# REMARKS: The dutch newspaper site of Algemeen Dagblad (http://www.ad.nl) is blocked # URL = http://www.ad.nl/ .ad.nl/ #MASTER# REMARKS: yahoo groups self-promotion - and the page is uglier without it # URL = http://us.i1.yimg.com/us.yimg.com/i/yg/img/ads/bestofygroups.jpg .yimg.com/.*/ads/bestofygroups.jpg$ #MASTER# REMARKS: NYT home page is messed up because .css files are blocked #MASTER# UNBLOCK-REFERRER: http://www.nytimes.com/ # URL = http://graphics8.nytimes.com/css/0.1/screen/common/ads.css # URL = http://graphics8.nytimes.com/css/0.1/screen/homepage/ads.css .nytimes.com/.*/ads\.css$ #MASTER# REMARKS: All hosted videos seemingly require this file. #MASTER# UNBLOCK-REFERRER: http://www.cnn.com/video/#/video/showbiz/2009/04/14/dcl.boyle.british.talent.show.cnn # URL = http://i.cdn.turner.com/cnn/.element/js/2.0/video/xmp/AdServiceAdapter.swf .turner.com/cnn/.*/AdServiceAdapter.swf #MASTER# REMARKS: Tracker 2786745 : MySpace music player doesn't work #MASTER# UNBLOCK-REFERRER: www.myspace.com/bandofskulls # URL = http://lads.myspacecdn.com/videos/musicPlayerAssets.swf lads.myspacecdn.com/ #MASTER# REMARKS: AF#2789653 iTunes download blocked # URL = http://a957.phobos.apple.com/us/r1000/000/Music/ad/47/56/mzi.gnjsyarh.aac.a.m4p .phobos.apple.com/ # URL = http://eas8.emediate.eu/eas?camp=114;ty=ct;EASLink=http://www.jp.dk .emediate.eu/.*EASLink= #MASTER# REMARKS: Actionfile tracker ID: 2838501: 2009-08-16 # URL = http://new.meteo.pl/advajax.js .meteo.pl/advajax\.js # URL = http://www.adressa.no/ # URL = http://adressa.no/ adressa.no/ # URL = http://www.adresseavisen.no/ # URL = http://adresseavisen.no/ adresseavisen.no/ # URL = http://apps.facebook.com/onthefarm/track.php?creative=&cat=friendvisit&subcat=weeds&key=a789a971dc687bee4c20c044834fabdd&next=index.php%3Fref%3Dnotif%26visitId%3D898835505 .facebook.com/.*/track.php # URL = http://www.ifdb.tads.org/ # URL = http://www.tads.org/ .tads.org/ # URL = http://adtoma.com/ adtoma.com/ #MASTER# REMARKS: Actionsfile feedback 2859872 2009-09-16 09:58 # URL = http://adactio.com/ adactio.com/ # URL = http://www.peereboom.us/adsuck/ www.peereboom.us/adsuck/ # URL = http://www.svd.se/template/ver1-0/css/ads.css?v=194 .svd.se/.*\.css($|\?) #MASTER# REMARKS: [privoxy-users] Privoxy blocking Ebay item pictures Jan 31, 2010 #MASTER# REMARKS: Ebay enlarge picture function doesn't work. # URL = http://include.ebaystatic.com/v4js/en_GB/e637i/SYS-LIGER_Omniture_e637i10177164_5_en_GB.js include.ebaystatic.com/.*omniture.*\.js #MASTER# REMARKS: Allow Yahoo news and mail javascipt pages # URL = http://l.yimg.com/d/combo?news/p/common/generic/news/p/common/generic/popular-searches-min-12622.js&news/p/common/generic/ads-min-11050.js&news/p/common/generic/foundation/popup-min-12622.js .yimg.com/d/combo\? #MASTER# REMARKS: Page formatting problems when .css files are blocked # URL = http://www.networkworld.com/includes/styles/adstyles.css # URL = http://www.sj.se/common/css/pop.css # URL = http://l.yimg.com/d/combo?news/p/common/generic/ads-min-24248.css&news/p/common/generic/widgets-min-10270.css # URL = http://news.zdnet.com/css/z/ads/hs.css /.*\.css$ #MASTER# REMARKS:Actionsfile feedback item #2974204 2010-03-21 # URL = http://adesklets.sourceforge.net/ adesklets.sourceforge.net/ #MASTER# REMARKS: Mostly-french political blog # URL = http://adassier.wordpress.com/ adassier.wordpress.com/ # URL = http://adassier.files.wordpress.com/2010/05/road-to-economic-recovery2.jpg?w=630&h=451 adassier.files.wordpress.com # URL = http://adainitiative.org/about-us/ adainitiative.org/ # URL = http://adjamblog.wordpress.com/ adjamblog.wordpress.com/ # URL = http://adjamblog.files.wordpress.com/2011/12/cropped-terra.jpg adjamblog.files.wordpress.com/ # URL = http://www.urbandictionary.com/popular.php?character=C .urbandictionary.com/popular # URL = http://websupport.wdc.com/sfclickcount.asp?s1=2&s2=1&s3=2&s4=6&lang=en&url=https%3A%2F%2Fwesterndigital.secure.force.com%2F%3Flang%3Den websupport.wdc.com/ #MASTER# UNBLOCK-REFERRER: http://conradelektronik.m13.mailplus.nl/genericservice/code/servlet/React?encId=xSgAxBFNnFrne8j&actId=357685&command=openhtml # URL = http://content.conrad.se/newsletter/banners/OFFER_750987_exk.jpg .conrad.se/newsletter/banners/ #MASTER# REMARKS: Actionsfile feedback item #3413827 2011-09-25 12:11 #MASTER# REMARKS: This domain hosts JS, images and CSS upon which hotmail.com depends .wlxrs.com/ # URL = http://advrider.com/forums/ # URL = http://www.advrider.com/forums/ .advrider.com/ # URL = http://www.smugmug.com/community/ADVrider # URL = http://www.siteinfotool.com/advrider.com /.*ADVrider ############################################################################# # Site-specific special rules: ############################################################################# #---------------------------------------------------------------------------- # These sites are very complex (read: keen on your identity) and require # minimal interference. #---------------------------------------------------------------------------- {fragile} .office.microsoft.com .windowsupdate.microsoft.com #MASTER# PROBLEM URL: http://metrics.apple.com 10/11/06 # too broad: .apple.com www.apple.com store.apple.com images.apple.com #MASTER# REMARKS: Actions Tracker 1293057 09/02/06 .update.microsoft.com #MASTER# REMARKS: Various reports 09/16/06. This site also requires pop-ups. mail.google.* #---------------------------------------------------------------------------- # Shopping and banking sites - allow cookies and pop-ups #---------------------------------------------------------------------------- #MASTER# REMARKS: This section not checked 10/11/06 HB {shop} .quietpc.com .worldpay.com # for quietpc.com .jungle.com .dabs.com .overclockers.co.uk .db24.de .ebay.* .mobile.de www.fondationlejeu.com www.techtv.com .mywebgrocer.com #---------------------------------------------------------------------------- # Subscription sites (with credible privacy policy) - allow permanent cookies #---------------------------------------------------------------------------- {-session-cookies-only} #MASTER# PROBLEM-URL: http://www.nytimes.com/auth/login .nytimes.com/ #MASTER# PROBLEM-URL: http://www.volkskrant.nl/ .volkskrant.nl/ #---------------------------------------------------------------------------- # These sites require pop-ups, so don't use the unconditional filters. #---------------------------------------------------------------------------- {allow-popups} #MASTER# PROBLEM-URL: http://www.aprilbarrows.com/discography.html www.aprilbarrows.com/discography\.html$ #MASTER# PROBLEM-URL: http://www.nvidia.com/view.asp?PAGE=windows2000 .nvidia.com #MASTER# PROBLEM-URL: http://www15.chathouse.com/games/ www*.chathouse.com/games/ #MASTER# PROBLEM-URL: http://www.bild.de/ .bild.t-online.de #MASTER# PROBLEM-URL: http://www.netflix.com/ .netflix.com #MASTER# PROBLEM-URL: http://my.aol.com/ my.aol.com #MASTER# PROBLEM-URL: http://www.cnn.com/ #MASTER# REMARKS: Re-enable "Story Tools" i.e. printing, emailing etc. i.cnn.net/cnn/.*/clickability/button #MASTER# PROBLEM-URL: http://www.rosettaproject.org:8080/live/search/contribute/swadesh/view?ethnocode=SPN .rosettaproject.org #MASTER# PROBLEM-URL: http://www.quantum.com requires popups for downloads, etc. 09/11/06 .quantum.com #MASTER# PROBLEM-URL: http://www.liberation.fr 11/23/06 Actions tracker .liberation.fr #---------------------------------------------------------------------------- # Sometimes (i.e. often!) fast-redirects catches things by mistake #---------------------------------------------------------------------------- {-fast-redirects} # Sticky Actions = -fast-redirects www.ukc.ac.uk/cgi-bin/wac\.cgi\? #MASTER# PROBLEM-URL: http://www.google.com/search?q=foo # URL = http://www.google.com/search?q=foo .google.* #MASTER# PROBLEM-URL: http://de.altavista.com/q?pg=q&q=foo&kl=XX&search.x=28&search.y=8&what=web .altavista.com/(.*(like|url|link):|trans.*urltext=)http #MASTER# PROBLEM-URL: http://www.speedfind.de/cgi-bin/search?q=foo&t=STANDARD .speedfind.de #MASTER# PROBLEM-URL: http://www.nytimes.com/ .nytimes.com #MASTER# REMARKS: Disable fast-redirects for all of yahoo.com/. #MASTER# REMARKS: Apparently we can't keep up with maintaining more precise exceptions. # URL = http://login.yahoo.com/config/login?logout=1&.done=http://mail.yahoo.com&.src=ym&.intl=us #MASTER# REMARKS: Reported in support request #1635354. # URL = http://us.rd.yahoo.com/reg/login1/lisu/login/uk/ym/*http://edit.europe.yahoo.com/c onfig/login?.tries=1&.src=ym&.md5=&.hash=&.js=1&.last=&...kP=Y&.done=http://mail .yahoo.com&.pd=ym_ver=0&c=&login=XXX&passwd=XXX&.persistent =&.hash=1&.md5=1.yahoo.com/ #MASTER# REMARKS: Reported in support request #1802365. .yahoo.com/ # URL = http://validator.w3.org/check .w3.org #MASTER# PROBLEM-URL: http://www.ask.com/ .directhit.com #MASTER# PROBLEM-URL: http://www.zagats.com/ .zagats.com #MASTER# PROBLEM-URL: http://www.passport.com/Consumer/default.asp?lc=1033 #MASTER# PROBLEM-URL: http://www.msn.com/ # URL = http://www.passport.com/Consumer/default.asp?lc=1033&msppchlg=1&mspplogin= my.msn.com/passport/pp(consent|set)\.ashx\?msnru= www.passport.com/Consumer/default\.asp\?lc=[0-9]+&msppchlg=[01]&mspplogin= login.passport.com/logout\.(asp|srf)\? #MASTER# PROBLEM-URL: http://www.fileplanet.com download.com.com/redir\? www.fileplanet.com/redir\.asp\? #MASTER# PROBLEM-URL: http://cyber.law.harvard.edu/filtering/china/test/ .edu #MASTER# PROBLEM-URL: http://web.archive.org # URL = http://web.archive.org/web/19970715180251/http://www.gmd.de/ .archive.org # URL = http://www.guenstiger.de/gt/link.asp?url=http://www.edv-supermarkt.de&source=produkt=238284&USID=00086443917155&hnr=2199&pnr=238284&ppr=158,00 www.guenstiger.de # URL = http://anon.free.anonymizer.com/http://www.privoxy.org/ .anonymizer.com # URL = http://www.mailtothefuture.com/public/logon?http://www.mailtothefuture.com/ www.mailtothefuture.com #MASTER# PROBLEM-URL: http://support.microsoft.com/default.aspx?scid=KB;en-us;q219110 support.microsoft.com/ # URL = http://www.alexa.com/data/details/traffic_details?q=blogspot&url=http://www.blogalia.com .alexa.com # URL = http://www.translate.ru/url/tran_url.asp?lang=es&url=http%3A%2F%2Fos2progg.by.ru%2Findex.shtml&direction=rs&template=General&cp1=NO&cp2=NO&autotranslate=on&transliterate=on&psubmit2.x=68&psubmit2.y=12 www.translate.ru/url/ # URL = http://schneegans.de/sv/?url=http%3A%2F%2Fwww.freebsd.org%2F&schema=%28Detect+automatically%29&encoding=%28Detect+automatically%29&htmlcomp=%28Detect+automatically%29 schneegans.de/ # URL = http://config.privoxy.org/edit-actions-submit?f=user..&redirect_mode=http%3A%2F%2Fwww.privoxy.org%2F config.privoxy.org/ # URL = http://users.wsj.com/lmda/do/checkLogin?mg=evo-wsj&url=http%3A%2F%2Fonline.wsj.com%2Farticle%2FSB117313867582027623.html .wsj.com/lmda/do/checkLogin #MASTER# REMARKS: As we already have five other PROBLEM-URLs that contain '?url=', #MASTER# REMARKS: it might make sense to allow '/.*?url=' in general # URL = http://del.icio.us/url/check?url=http%3A%2F%2Fwww.privoxy.org del.icio.us/ # URL = http://calgary.ctv.ca/servlet/RTGAMArticleHTMLTemplate/B/20070615/goexpo?brand=generic&hub=&tf=CFCNPlus/generic/hubs/frontpage.html&cf=CFCNPlus/generic/hubs/frontpage.cfg&slug=goexpo&date=20070615&archive=CFCNPlus&ad_page_name=&nav=home&subnav=fullstory&site_cfcn=http://calgary.ctv.ca .ctv.ca/.*&site_cfcn=http:// # URL = http://memberservices.informit.com/checkLogin.ashx?partner=8&r=http%3a%2f%2fwww.informit.com%2farticles%2farticle.asp%3fp%3d766375%26seqNum%3d1 .informit.com/.*&r=http%3a%2f%2f # URL = http://access.adobe.com/access/getStatus.do?jobid=&srcPdfUrl=http://cups.cs.cmu.edu/soups/2007/proceedings/p41_clark.pdf&convertTo=html&visuallyImpaired=preferhtml&preferHTMLReason=&platform=&comments=&starttime=1187362172109 access.adobe.com/access/getStatus.do\?jobid=&srcPdfUrl= # URL = http://view.samurajdata.se/ps.php?url=http%3A%2F%2Fcups.cs.cmu.edu%2Fsoups%2F2007%2Fproceedings%2Fp41_clark.pdf&submit=View%21 view.samurajdata.se/ps\.php\?url= # URL = http://www.blogger.com/navbar.g?targetBlogID=8919860543765866292&blogName=Kickin%27+the+Darkness&publishMode=PUBLISH_MODE_HOSTED&navbarType=BLUE&layoutType=LAYOUTS&homepageUrl=http%3A%2F%2Fblog.kickin-the-darkness.com%2F&searchRoot=http%3A%2F%2Fblog.kickin-the-darkness.com%2Fsearch .blogger.com/navbar\.g # URL = http://editors.dmoz.org/editors/editurl.cgi?url=http%3a//www.example.de/&cat=World/Deutsch/Computer/Hardware/Speichermedien .dmoz.org/editors/editurl\.cgi # URL = http://offer.ebay.de/ws/eBayISAPI.dll?stockphotourl=http%3A%2F%2Fi16.ebayimg.com%2F02%2Fc%2F02%2F88%2F21%2F5b_6.JPG&MfcISAPICommand=BinConfirm&fb=1&co_partnerid=&item=123456789112&quantity=1&input_bin= # URL = http://offer.ebay.de/ws/eBayISAPI.dll?maxbid=15%2C01&MfcISAPICommand=MakeBid&fromPage=284&stockphotourl=http%3A%2F%2Fi14.ebayimg.com%2F02%2Fc%2F00%2Fe9%2Fe1%2F2a_6.JPG&fb=2&co_partnerid=&item=123456789112&input_bid= .ebay.de/ws/eBayISAPI\.dll\? #MASTER# REMARKS: While this is a redirect, the token isn't part of the URL redirected to. # URL = http://www.amazon.com/gp/redirect.html/ref=cm_plog_item_link/105-3659773-0844420?ie=UTF8&location=http%3A%2F%2Fjoltawards.com%2F2007%2F&token=A07736D870C02EF10CB13BCC8A33C302F689BBBA .amazon.com/gp/redirect.html/.*location.*&token # URL = http://en.groundspring.org/EmailNow/pub.php?module=WebSignup&cmd=thankyou&gotoUrl=http%3A%2F%2Fwww.freebsdfoundation.org&gotoText=Return+to+Home+Page&listNames=The+FreeBSD+Foundation+Mailing+List .groundspring.org/ # URL = http://www1.landsend.de/pp/undefined/images/error.gif?onerr=true&ts=1227969386837&file=http%3A//s7.landsend.com/is-viewers/dhtml/include/sj_textloader.js%3Fver%3Dle.1&line=0&msg=Script%20error.&sid= .landsend.de/ # URL = http://www.youtube.com/swf/l.swf?swf=http%3A//s.ytimg.com/yt/swf/cps-vfl68942.swf&video_id=2cpd6rHIfyA&rel=1&showsearch=1&eurl=&iurl=http%3A//i3.ytimg.com/vi/2cpd6rHIfyA/hqdefault.jpg&sk=5E3I2RCcOLknk1qyI_JgVVnb8FKwgpHzC&use_get_video_info=1&load_modules=1&fs=1&hl=en .youtube.com/swf/.*swf= # URL = http://redbot.org/?uri=http%3A//apache.org/ .redbot.org/ # URL = http://webcache.googleusercontent.com/custom?hl=en&domains=library.gnome.org&sitesearch=library.gnome.org&q=cache:8yGDJ1YpefcJ:http://library.gnome.org/devel//gtk/2.20/GtkLabel.html+gtk_label_set_text+escape&ct=clnk webcache.googleusercontent.com/ # URL = http://webcache.googleusercontent.com/search?q=cache:kZYcDFibjHcJ:https://grepular.com/Abusing_HTTP_Status_Codes_to_Expose_Private_Information+inurl:https://grepular.com/Abusing_HTTP_Status_Codes_to_Expose_Private_Information&hl=en&strip=1 .googleusercontent.com/.*=cache: # URL = http://maps.googleapis.com/maps/api/js/AuthenticationService.Authenticate?1shttp%3A%2F%2Fwww.wunderground.com%2Fcgi-bin%2Ffindweather%2FgetForecast%3Fbrand%3Dwxmap%26query%3D42.649601%2C-88.298500%26zoom%3D8%26theprefset%3D531051599999WS%26theprefvalue%3DME0041&2sgme-weatherunderground&3swxmap&5e1&callback=_xdc_._9er073&token=129358 .googleapis.com/ # URL = http://www.google.com.au/sorry/?continue=http://www.google.com.au/search%3Fhl%3Den%26tbo%3Dd%26output%3Dsearch%26sclient%3Dpsy-ab%26q%3Dnew%2Bcars%26btnG%3D .google./sorry/\?continue?= {+redirect{s@.*url=@http://@} -block} # Sticky Actions = +redirect -block # URL = http://go.eniro.dk/lg/ni/http:/eas8.emediate.eu/eas?camp=79;ty=ct;EASLink=http://www.bt.dk?http://redirect.metropol.dk/cgi-bin/redir.pl?url=www.bt.dk # URL = http://eas8.emediate.eu/eas?camp=79;ty=ct;EASLink=http://www.bt.dk?http://redirect.metropol.dk/cgi-bin/redir.pl?url=www.bt.dk # Redirected URL = http://go.eniro.dk/lg/ni/http:/eas8.emediate.eu/eas?camp=79;ty=ct;EASLink=http://www.bt.dk?http://redirect.metropol.dk/cgi-bin/redir.pl?url=www.bt.dk # Redirect Destination = http://www.bt.dk # Redirected URL = http://eas8.emediate.eu/eas?camp=79;ty=ct;EASLink=http://www.bt.dk?http://redirect.metropol.dk/cgi-bin/redir.pl?url=www.bt.dk # Redirect Destination = http://www.bt.dk go.eniro.dk/.*EASLink=http://.*url=(?!<=http:) .emediate.eu/.*EASLink=http://.*url=(?!<=http:) #---------------------------------------------------------------------------- # No filtering for sourcecode or other automatically parsed content #---------------------------------------------------------------------------- {-filter -prevent-compression} # Sticky Actions = -filter -prevent-compression # URL = http://ijbswa.cvs.sourceforge.net/ijbswa/current/ .cvs. /.*(cvs(view|web)|viewcvs) #MASTER# REMARKS: The same for Subversion # URL = http://svn.sourceforge.net/ .svn. .websvn. /(.*/)?svn/ #MASTER# REMARKS: Jeez, could you please stay with one of them? # URL = http://liveupdate.symantec.com/ennlu.x86 liveupdate.symantec.com liveupdate.liveupdatesymantec.com liveupdate.symantecliveupdate.com # URL = http://www.bookmarklets.com/ .bookmarklets.com # URL = http://www.squarefree.com/bookmarklets/ .squarefree.com/bookmarklets/ #MASTER# REMARKS: Used by Mac OSX's automatic software update feature swquery.apple.com swscan.apple.com #MASTER# REMARKS: These are various US DSL speed tests sites, where MIME is wrong # URL = http://atl.speakeasy.net/300k .speakeasy.net/\d+k # URL = http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=185033 .debian.org #MASTER# DONT-VERIFY #MASTER# REMARKS: Popular bug-tracking system - likely to contain code bugzilla. .tldp.org #MASTER# REMARKS: mail should not be filtered 09/18/06 webmail. #MASTER# REMARKS: all the world is wikified 09/02/06. Generic wiki un-filterers. .wiki*. .*wiki. /.*wiki/ #MASTER# REMARKS Actionsfile feedback item #2299717 2008-11-16 # URL = http://en.wiktionary.org/ .wiktionary.org/ #MASTER# REMARKS: protect some google projects from accidental JS/HTML tampering, etc maps.google. .google.com/(calendar|reader) #MASTER# REMARKS: A lot of code and docs on these sites: code. developer. .mozdev.org .mozilla.org .perl.org .cpan.org .webdeveloper.com .ibm.com/developerworks .apache.org/docs .comptechdoc.org .webmonkey.com .webreference.com docs.sun.com java.sun.com .thescripts.com .php.net .phpdeveloper.org .oreillynet.com/pub .devshed.com .htmlgoodies.com .javascript.com javascript.internet.com .w3schools.com .devguru.com javascriptkit.com .xulplanet.com .perl.com/language/newdocs # URL = http://svnweb.freebsd.org/base/head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c?revision=238391&view=markup .freebsd.org # URL = http://fxr.watson.org/fxr/source/geom/geom_event.c .watson.org .netbsd.org .openbsd.org .dragonflybsd.org .freedesktop.org .gnu.org .fedoraproject.org .userscripts.org #MASTER# REMARKS: Bug trackers like Flyspray and Mailinglist interfaces like Mailman: /(.*/)?flyspray/ /(.*/)?mail(man|archive|inglists?)/ bugs. #MASTER# REMARKS: Actionsfile tracker 1555909 09/17/06, various problems with cpu and logging in. quoka.de #---------------------------------------------------------------------------- # Innocent images in standard banner sizes found here: #---------------------------------------------------------------------------- {-filter{banners-by-size}} # Sticky Actions = -filter{banners-by-size} # URL = http://www.pricegrabber.com/search_getprod.php?masterid=580330&zip_code=92840&found=1&ut=40a6c41f2c9d1244 .pricegrabber.com/search_getprod.php #MASTER# REMARKS: URL-based filtering is enough here. 120x90 content images # URL = http://www.cnn.com/WORLD/ .cnn.com #MASTER# REMARKS: 120x90 content images # URL = http://gamespot.com/gamespot/filters/0,10850,6013054,00.html .gamespot.com/gamespot #MASTER# PROBLEM-URL: http://www.wral.com/ 10/14/06 www.wral.com #MASTER# PROBLEM-URL: http://www.cartoonnetwork.com/ 10/15/06 .cartoonnetwork.com/ # URL = http://www.anybrowser.org/campaign/ .anybrowser.org # URL = http://images.google.de/images?q=cookie+monster&svnum=10&hl=de&lr=&ie=UTF-8&oe=UTF-8&start=40&sa=N images.google. # URL = http://www.pbs.org/wgbh/pages/roadshow/series/highlights/2003/albuquerque/index.html .pbs.org/.*/roadshow/ # URL = http://objects.povworld.org/cat/Food/ objects.povworld.org/cat/ # URL = http://www.xach.com/gimp/tutorials/tiles.html www.xach.com/gimp/ #MASTER# REMARKS: The destination map at the bottom of the page. # URL = http://www.mapquest.com/directions/main.adp?go=1&do=nw&ct=NA&1y=US&1a=255+w+88+st&1p=&1c=&1s=&1z=10024&2y=US&2a=20+milltown+rd&2p=&2c=&2s=&2z=10509&lr=2 .mapquest.com/directions/ #MASTER# PROBLEM-URL: http://www.theonion.com/ 10/15/06 #MASTER# REMARKS: A nasty "premercial" ad is required to enter this site. .theonion.com/content/ # URL = http://www.pattilupone.net/gallery.html .pattilupone.net/gallery.html # URL = http://www.ambrosiasw.com/games/evn/desktops.html .ambrosiasw.com/ # URL = http://oca.microsoft.com/en/Welcome.asp .microsoft.com # URL = http://javabog.dk/ijk/ javabog.dk/ijk/ #MASTER# REMARK: Per Debian bug report #319025 09/09/06 .w3.org # URL = http://www.encyclopediadramatica.com/New_Zealand_Fail_Guy .encyclopediadramatica.com/ # URL = http://www.ikea.com/us/en/catalog/products/00103102 .ikea.com/ # URL = http://www.froscon.de/en/projects.html .froscon.de/ # URL = http://www.fsfe.org/en/supporters .fsfe.org/ # URL = http://www.couchsurfing.com/mapsurf.html .couchsurfing.com/ # URL = http://www.couchsurfing.org/mapsurf.html .couchsurfing.org/ # URL = http://www.thinkgeek.com/tshirts-apparel/unisex/generic/ .thinkgeek.com/ {-filter{banners-by-link}} # Sticky Actions = -filter{banners-by-link} # URL = http://www.encyclopediadramatica.com/Advertisement .encyclopediadramatica.com/ #---------------------------------------------------------------------------- # These don't work without the referrer information: #---------------------------------------------------------------------------- {-hide-referrer} # Sticky Actions = -hide-referrer #MASTER# REMARKS: This section NOT checked 10/18/06 HB #MASTER# REMARKS: These are movie clips, linked from http://us.imdb.com .totaleclips.com #MASTER# REMARKS: Actions Tracker 1313157 # URL = http://validator.w3.org/check?uri=referer validator.w3.org/check\?uri=referer #MASTER# REMARKS: Fixes Debian Bug #250407 # URL = http://www.petitiononline.com/mod_perl/signed.cgi .petitiononline.com/mod_perl/signed.cgi #MASTER# REMARKS: Tracker bug report 1107806 09/26/06 .telia.se #MASTER# REMARKS: XML validator that actually works. # URL = schneegans.de/sv/?url=referer schneegans.de/sv/\?url=referer #---------------------------------------------------------------------------- # These animated gifs are either useful or nice: #---------------------------------------------------------------------------- {-deanimate-gifs} # Sticky Actions = -deanimate-gifs #MASTER# REMARKS: Wanted animations on ecards #MASTER# REMARKS: Leaving 10/18/06 though most animated seem flash now. # URL = http://www.care2.com/ .care2.com .care-mail.com #MASTER# PROBLEM-URL: http://weather.chicagotribune.com/radar/station.asp?ID=LOT19&type=loop #MASTER# REMARKS: These are weather radar images. 10/18/06 # URL = http://www.wunderground.com/radar/station.asp?ID=MPX19&type=loop&clutter=1 .wunderground.com 66.28.250.180/data/ #MASTER# PROBLEM-URL: http://www.teamquest.com/html/gunther/laquiz.shtml .teamquest.com/gifs/gunther/ #MASTER# REMARKS: 09/12/06 Art site, and ad-free .rubberslug.com #MASTER# REMARKS: Actionsfile feedback item #2040467, allow animated gifs from wikipedia.org .wikipedia.org/ #---------------------------------------------------------------------------- # The "site-specifics" filter has special cures for problems found here: #---------------------------------------------------------------------------- #MASTER# REMARKS: This section NOT checked 10/15/06 HB. {+filter{site-specifics}} # Sticky Actions = +filter{site-specifics} # URL = http://www.spiegel.de/static/js/flash-plugin.js .spiegel.de/static/js/flash-plugin\.js # URL = http://www.quelle-bausparkasse.de/ .quelle-bausparkasse.de/$ # URL = http://de.groups.yahoo.com/group/die-spinner/interrupt?st=2&ln=die-spinner&m=1&done=%2Fgroup%2Fdie-spinner%2Fmessage%2F416 .groups.yahoo.com/group/ # URL = http://www.nytimes.com/ .nytimes.com/ #---------------------------------------------------------------------------- # Content under these TLDs is most probably in character sets which the # demoronizer filter would mess up #---------------------------------------------------------------------------- {-filter{demoronizer}} .jp .cn .tw .ru .kr #---------------------------------------------------------------------------- # Misc special rules: #---------------------------------------------------------------------------- {-filter{content-cookies} -filter{webbugs}} # Sticky Actions = -filter{content-cookies} -filter{webbugs} #MASTER# REMARKS: Needs content-cookies for cookie test on index page; needs webbugs for storing profile(!) # URL = http://www.friendscout24.de/ .friendscout24.de #MASTER# REMARKS: Explains how content cookies work # URL = http://www.webreference.com/js/column8/property.html .webreference.com/js/column8/property.html {-filter{fun}} # Sticky Actions = -filter{fun} #MASTER# REMARKS: Don't change the filter code with itself ;-) # URL = http://www.privoxy.org/user-manual/filter-file.html /(.*/)?user-manual/filter-file.html #{+filter{img-reorder} +filter{banners-by-link}} #MASTER# REMARKS: Temporarily decommissioning 10/15/06. Violates Cautious no filter policy. HB #MASTER# PROBLEM-URL: http://www.dn.se/ #MASTER# REMARKS: Can't catch by size or location #www.dn.se {-filter{img-reorder}} # Sticky Actions = -filter{img-reorder} #MASTER# REMARKS: Google images don't show up with img-reorder on #MASTER# REMARKS: Also images on finance.google.com 09/25/06 # URL = http://images.google.com .google. #MASTER# PROBLEM-URL: http://wired.com 09/23/06 # URL = http://wired.com /.*wired(\.com)?/ .wired.com/ {-filter{js-annoyances}} # Sticky Actions = -filter{js-annoyances} #MASTER# REMARKS: No progress past main page without js-annoyances # URL = http://www.nasa.gov .nasa.gov #MASTER# REMARKS: Exclude per Debian bug report #377843 # URL = http://www2.cnrs.fr/presse/communique/900.htm .cnrs.fr #MASTER# REMARKS: Exclude per Debian bug report #377843 # URL = http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx blogs.msdn.com {-filter{unsolicited-popups}} # Sticky Actions = -filter{unsolicited-popups} #MASTER# REMARKS: Breaks Movable Type's admin interface (http://www.movabletype.org/) /.*mt.cgi$ #MASTER# REMARKS: Exclude per Debian bug report #377843 09/17/06 # URL = http://www2.cnrs.fr/presse/communique/900.htm .cnrs.fr #MASTER# REMARKS: Exclude per Debian bug report #377843 09/17/06 # URL = http://blogs.msdn.com/wga/archive/2006/07/16/667063.aspx blogs.msdn.com {-filter{jumping-windows}} # Sticky Actions = -filter{jumping-windows} # URL = http://www.openstreetmap.org .openstreetmap.org {+fast-redirects{check-decoded-url} -block} # Sticky Actions = +fast-redirects{check-decoded-url} -block #MASTER# REMARKS: Yahoo search results. Added 2007-01-19 fk #MASTER# REDIRECT-REFERRER: http://search.yahoo.com/search?p=privoxy # URL = http://rds.yahoo.com/_ylt=A0geuryczbBF._YAEmxXNyoA;_ylu=X3oDMTB2b2gzdDdtBGNvbG8DZQRsA1dTMQRwb3MDMQRzZWMDc3IEdnRpZAM-/SIG=11b3qg40n/EXP=1169301276/**http%3a//www.privoxy.org/ rds.yahoo.com/ # Redirected URL = http://rds.yahoo.com/_ylt=A0geuryczbBF._YAEmxXNyoA;_ylu=X3oDMTB2b2gzdDdtBGNvbG8DZQRsA1dTMQRwb3MDMQRzZWMDc3IEdnRpZAM-/SIG=11b3qg40n/EXP=1169301276/**http%3a//www.privoxy.org/ # Redirect Destination = http://www.privoxy.org/ #MASTER# REDIRECT-REFERRER: http://www.gamefaqs.com/computer/doswin/game/914819.html # URL = http://dw.com.com/redir?asid=0&astid=8&siteid=19&edid=107&destCat=33862&destURL=http%3A%2F%2Fdb.gamefaqs.com%2Fcomputer%2Fdoswin%2Ffile%2Fvampire_tmb_b.txt dw.com.com/redir\? # Redirected URL = http://dw.com.com/redir?asid=0&astid=8&siteid=19&edid=107&destCat=33862&destURL=http%3A%2F%2Fdb.gamefaqs.com%2Fcomputer%2Fdoswin%2Ffile%2Fvampire_tmb_b.txt # Redirect Destination = http://db.gamefaqs.com/computer/doswin/file/vampire_tmb_b.txt #MASTER# REMARKS: Action tracker 1593393. Added 2007-01-20. # URL = http://wzus.bloglines.com/r?t=a&d=us&s=bl&c=blen&ti=1&ai=51060&l=dir&o=0&sv=z6f537f5b&ip=971AC44B&u=http%3A%2F%2Fwww.skweezer.net%2Fbloglines%2Fskweeze.aspx%3F%26i%3Dd%26l%3Den%26r%3Dhttp%253A%252F%252Fwww.bloglines.com%252Fmyblogs_display%253Fsub%253D29302699%2526site%253D5382440%26url%3Dhttp%253A%252F%252Fpermalink.gmane.org%252Fgmane.linux.debian.devel.changes.unstable%252F97340 # Redirected URL = http://wzus.bloglines.com/r?t=a&d=us&s=bl&c=blen&ti=1&ai=51060&l=dir&o=0&sv=z6f537f5b&ip=971AC44B&u=http%3A%2F%2Fwww.skweezer.net%2Fbloglines%2Fskweeze.aspx%3F%26i%3Dd%26l%3Den%26r%3Dhttp%253A%252F%252Fwww.bloglines.com%252Fmyblogs_display%253Fsub%253D29302699%2526site%253D5382440%26url%3Dhttp%253A%252F%252Fpermalink.gmane.org%252Fgmane.linux.debian.devel.changes.unstable%252F97340 # Redirect Destination = http://www.skweezer.net/bloglines/skweeze.aspx?&i=d&l=en&r=http%3A%2F%2Fwww.bloglines.com%2Fmyblogs_display%3Fsub%3D29302699%26site%3D5382440&url=http%3A%2F%2Fpermalink.gmane.org%2Fgmane.linux.debian.devel.changes.unstable%2F97340 .bloglines.com/r\? www.skweezer.net/bloglines # URL = http://media.fastclick.net/w/get.media?sid=4681&m=5&tp=6&url=http%3A//www.sciam.com/article.cfm%3FchanID%3Dsa003%26articleID%3DC7C87ECC-E7F2-99DF-39AEFF3D7D1A8CFB%26ref%3Drss # Redirected URL = http://media.fastclick.net/w/get.media?sid=4681&m=5&tp=6&url=http%3A//www.sciam.com/article.cfm%3FchanID%3Dsa003%26articleID%3DC7C87ECC-E7F2-99DF-39AEFF3D7D1A8CFB%26ref%3Drss # Redirect Destination = http://www.sciam.com/article.cfm?chanID=sa003&articleID=C7C87ECC-E7F2-99DF-39AEFF3D7D1A8CFB&ref=rss .fastclick.net/w/get\.media\? # Redirected URL = http://www.awin1.com/cread.php?awinmid=2891&awinaffid=43305&clickref=&p=http://www.groupon.co.uk/ # Redirect Destination = http://www.groupon.co.uk/ .awin1.com/.*=http:// # Redirected URL = http://tr.anp.se/track?t=c&mid=1132291&uid=328397249&&&http:%2F%2Fwww%2Eresume%2Ese%2F%2Fnyheter%2F2011%2F03%2F31%2Fexpressen%2Dkampanjen%2Danmald%2F # Redirect Destination = http://www.resume.se//nyheter/2011/03/31/expressen-kampanjen-anmald/ # Redirected URL = http://tr.anp.se/track?t=c&mid=1129528&uid=328397249&&&http:%2F%2Fwww%2Eresume%2Ese%2F%2Fnyheter%2F2011%2F03%2F29%2Fanstalt%2Dforbjod%2Dskurk%2F # Redirect Destination = http://www.resume.se//nyheter/2011/03/29/anstalt-forbjod-skurk/ tr.anp.se/ {+block{Looks like an anti-leech trigger URL.}} #MASTER# COMMENTS: This section not checked 10/17/06 HB. Still out there? #MASTER# PROBLEM-URL: http://www.anti-leech.com/theft_example.html #MASTER# REMARKS: Lame attempt at banning ad-blockers. Used by other websites as well. /antitheft\.php {+filter{tiny-textforms}} .sourceforge.net/tracker {+downgrade-http-version} #MASTER# COMMENTS: This section not checked 10/17/06 HB #MASTER# REMARKS: This is work-around for CUPS http configuration. :631 #MASTER# REMARKS: If Privoxy is disabled, requests for config.privoxy.org/ #MASTER# REMARKS: reach privoxy.org and are redirected to privoxy.org/config. #MASTER# REMARKS: The instructions tell the user to reload the page with #MASTER# REMARKS: Privoxy enabled to reach the configuration webinterface, #MASTER# REMARKS: to make this work we have to intercept the request and revert #MASTER# REMARKS: the redirection. {+redirect{http://config.privoxy.org/}} # Sticky Actions = +redirect{http://config.privoxy.org/} # URL = http://www.privoxy.org/config # Redirected URL = http://www.privoxy.org/config # Redirect Destination = http://config.privoxy.org/ .privoxy.org/config #MASTER# REMARKS: Privoxy's "unsafe" CGI pages check the referrer #MASTER# REMARKS: to make sure the user reached them intentionally. #MASTER# REMARKS: Disabling hide-referrer so there's a referrer left to check. #MASTER# REMARKS: Disabling fast-redirects because if CGI crunching gets #MASTER# REMARKS: enabled it could be leveraged to fool the referrer check. {-hide-referrer -fast-redirects} # Sticky Actions = -hide-referrer -fast-redirects # URL = http://p.p # URL = http://config.privoxy.org p.p/ config.privoxy.org/ #MASTER# REMARKS: Yahoo logout URLs need special treatment, #MASTER# REMARKS: the URL after "done=" is no fast-redirect. 2007-01-19 fk #MASTER# REMARKS: Reported in support request #1635354. {-fast-redirects +redirect{s@^.*\*(http://login\.yahoo\.com/.*)$@$1@i}} # XXX: Privoxy-Regression-Test currently doesn't allow backslashes. # Sticky Actions = -fast-redirects +redirect # URL = http://us.ard.yahoo.com/SIG=AAAAAAAAA/M=NNNNNN.NNNNNNN.NNNNNNN.NNNNNNN/D=mail/S=NNNNNNNNN:HEADR/Y=YAHOO/EXP=NNNNNNNNNN/A=NNNNNNN/R=N/SIG=AAAAAAAAA/*http://login.yahoo.com/config/login?logout=1&.done=http://mail.yahoo.com&.src=ym&.intl=us # Redirected URL = http://us.ard.yahoo.com/SIG=AAAAAAAAA/M=NNNNNN.NNNNNNN.NNNNNNN.NNNNNNN/D=mail/S=NNNNNNNNN:HEADR/Y=YAHOO/EXP=NNNNNNNNNN/A=NNNNNNN/R=N/SIG=AAAAAAAAA/*http://login.yahoo.com/config/login?logout=1&.done=http://mail.yahoo.com&.src=ym&.intl=us # Redirect Destination = http://login.yahoo.com/config/login?logout=1&.done=http://mail.yahoo.com&.src=ym&.intl=us .yahoo./.*http://login.yahoo.com/config/login.*http:// #MASTER# REMARKS: The next two sections are to get flickr's Ajax interface working #MASTER# REMARKS: with default pre-settings. For more aggressive defaults they additionally #MASTER# REMARKS: need -crunch-incoming-cookies and -crunch-outgoing-cookies. #MASTER# REMARKS: They work with +session-cookies-only, though. {-block -filter} #MASTER# PROBLEM-URL: http://www.flickr.com/ # Sticky Actions = -block -filter # URL = http://l.yimg.com/g/combo/1?event-custom/event-custom-min.js&event/event-min.js&j/.H-.K.A.vNKEa&j/.CP-.U-.DE.A.vKEJz&j/.J_.BR_.CA.A.vKYkg&j/.J_.DB.A.vPpBT&j/popup-login.A.vR53Z&dump/dump-min.js&datatype/datatype-xml-min.js&substitute/substitute-min.js&json/json-min.js&queue-promote/queue-promote-min.js&io/io-min.js&j/.J_.DS.A.vQa28&j/.FW-.FX-.GH.A.vP3XB&j/grease.A.vRktP&j/.CC.A.vNiA6&j/.C-.BL.A.vPPj2&j/.CE-.K.A.vNy32&attribute/attribute-base-min.js&base/base-min.js&anim/anim-min.js&cookie/cookie-min.js&j/.B-.C-.F.A.vQ7SZ&j/urls.A.vQtXp&j/.B-.BY.A.vQCXP&j/.H-.BY.A.vQXXx&j/.DS-value-conversions.A.vQpRt&j/.G-.BD.A.vNHSH&event/event-synthetic-min.js&j/.G-.BO.A.vNwR4&j/.CV-.CH.A.vPFSZ&j/.X-.W-.C-.F.A.vKPQa&j/.X-.W-.D.A.vQXXx&j/.Q-.BX-.K.A.vR1kt&j/.DL.A.vLPjD&j/.CF.A.vNC24&j/.CX-.CY.A.vP8ND&event-simulate/event-simulate-min.js&node/node-event-simulate-min.js&j/.B-.T-.CI-.C-.F.A.vPJPF&j/.CM/.BA_2.5.1-.D.A.vPzui&j/bo-.S-.C-.F.A.vNwWe&j/bo-.S-.D.A.vR6Hx&j/.BZ-.D.A.vNstB&j/.B-.L-.C-.F.A.vNxPX&j/.B-.L-.BH.A.vMdVB&j/.CN-.DD.A.vLjJ2&j/.B-.O-.C-.F.A.vPpcK&j/.BM.A.vKPmz&j/.B-.O.A.vQyHg&j/.B-.H-.BB-.C-.F.A.vQvrB&j/.CW-.CU.A.vQ7Rg&j/.Y-.C-.F.A.vNqGa&j/.Y.A.vLKiT&j/.B-.M-.C-.F.A.vQxDc&j/.U-.CG.A.vQ5Tt&j/.B-.M.A.vQXXx&j/.B-.Q-.BQ.A.vQvTt&j/.B-.N-.C-.F.A.vQaRp&j/.CL.A.vN4N6&j/.B-.CL-.BW.A.vPwkx&j/.DR-.DG.A.vMLJr&j/.B-.BE-.C-.F.A.vPHP4&j/.B-.BE-.D.A.vQLQH&j/.BV.A.vm3Uz&j/.Z-.DK-.D.A.vLQEe&j/.Z-.DJ-.BJ.A.vLQEe&j/.B-.I-.C-.F.A.vPKTK&stylesheet/stylesheet-min.js&j/.B-.I.A.vQvDF&j/.CM-.DO.A.vPboD&j/.B-.D.A.vRbv8&j/.B-.H-.BB.A.vQuhn&j/.B-.N.A.vR6Cn&j/.B-.L-.CZ.A.vQmzP&j/.B-.T-.CI.A.vQXXx&j/.B-.I-.CQ-.BK-.C-.F.A.vNwZF&j/.B-.I-.CQ-.BK.A.vLWQR&j/.B-.R-.C-.F.A.vPfwi&j/.B-.R.A.vRhND&j/.DN-.BB-.D-.C-.F.A.vQXZg&j/.DN-.BB-.D.A.vRcXB&j/.BF_.D-.C-.F.A.vPGYM&j/.BF_.D.A.vQxJn&plugin/plugin-min.js&cache/cache-min.js&j/.CB-.C-.F.A.vNwWe&j/.CB-.D.A.vQS6T .yimg.com/g/combo/1\?event-custom/ {-block -filter{content-cookies}} #MASTER# PROBLEM-URL: http://www.flickr.com/ {-filter{content-cookies}} # Sticky Actions = -block # URL = http://www.flickr.com/ .flickr.com/ #---------------------------------------------------------------------------- # Sections that modify the action settings based on tags. #---------------------------------------------------------------------------- ############################################################################# # Depends on +client-header-tagger{image-requests} ############################################################################# {-handle-as-empty-document \ +handle-as-image \ } TAG:^IMAGE-REQUEST$ ############################################################################# # Depends on +client-header-tagger{css-requests} ############################################################################# {+handle-as-empty-document \ -handle-as-image \ } TAG:^CSS-REQUEST$ #MASTER# set vi:nowrap privoxy-3.0.21-stable/./cgi.h000640 001751 001751 00000012776 12047157516 014722 0ustar00fkfk000000 000000 #ifndef CGI_H_INCLUDED #define CGI_H_INCLUDED #define CGI_H_VERSION "$Id: cgi.h,v 1.42 2012/11/09 10:47:42 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgi.h,v $ * * Purpose : Declares functions to intercept request, generate * html or gif answers, and to compose HTTP resonses. * * Functions declared include: * * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif /* * Main dispatch function */ extern struct http_response *dispatch_cgi(struct client_state *csp); /* Not exactly a CGI */ extern struct http_response *error_response(struct client_state *csp, const char *templatename); /* * CGI support functions */ extern struct http_response * alloc_http_response(void); extern void free_http_response(struct http_response *rsp); extern struct http_response *finish_http_response(struct client_state *csp, struct http_response *rsp); extern struct map * default_exports(const struct client_state *csp, const char *caller); extern jb_err map_block_killer (struct map *exports, const char *name); extern jb_err map_block_keep (struct map *exports, const char *name); extern jb_err map_conditional (struct map *exports, const char *name, int choose_first); extern jb_err template_load(const struct client_state *csp, char ** template_ptr, const char *templatename, int recursive); extern jb_err template_fill(char ** template_ptr, const struct map *exports); extern jb_err template_fill_for_cgi(const struct client_state *csp, const char *templatename, struct map *exports, struct http_response *rsp); extern void cgi_init_error_messages(void); extern struct http_response *cgi_error_memory(void); extern jb_err cgi_redirect (struct http_response * rsp, const char *target); extern jb_err cgi_error_no_template(const struct client_state *csp, struct http_response *rsp, const char *template_name); extern jb_err cgi_error_bad_param(const struct client_state *csp, struct http_response *rsp); extern jb_err cgi_error_disabled(const struct client_state *csp, struct http_response *rsp); extern jb_err cgi_error_unknown(const struct client_state *csp, struct http_response *rsp, jb_err error_to_report); extern jb_err get_number_param(struct client_state *csp, const struct map *parameters, char *name, unsigned *pvalue); extern jb_err get_string_param(const struct map *parameters, const char *param_name, const char **pparam); extern char get_char_param(const struct map *parameters, const char *param_name); #ifdef FEATURE_COMPRESSION /* * Minimum length which a buffer has to reach before * we bother to (re-)compress it. Completely arbitrary. */ extern const size_t LOWER_LENGTH_LIMIT_FOR_COMPRESSION; extern char *compress_buffer(char *buffer, size_t *buffer_length, int compression_level); #endif /* * Text generators */ extern void get_http_time(int time_offset, char *buf, size_t buffer_size); extern char *add_help_link(const char *item, struct configuration_spec *config); extern char *make_menu(const char *self, const unsigned feature_flags); extern char *dump_map(const struct map *the_map); /* * Ad replacement images */ extern const char image_pattern_data[]; extern const size_t image_pattern_length; extern const char image_blank_data[]; extern const size_t image_blank_length; /* Revision control strings from this header and associated .c file */ extern const char cgi_rcs[]; extern const char cgi_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef CGI_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./default.filter000640 001751 001751 00000116532 12110657247 016632 0ustar00fkfk000000 000000 # ******************************************************************** # # File : $Source: /cvsroot/ijbswa/current/default.filter,v $ # # $Id: default.filter,v 1.86 2013/02/19 11:14:47 fabiankeil Exp $ # # Purpose : Rules to process the content of web pages # # Copyright : Written by and Copyright (C) 2001-2010 the # Privoxy team. http://www.privoxy.org/ # # We value your feedback. However, to provide you with the best support, # please note: # # * Use the support forum to get help: # http://sourceforge.net/tracker/?group_id=11118&atid=211118 # * Submit bugs only thru our bug forum: # http://sourceforge.net/tracker/?group_id=11118&atid=111118 # Make sure that the bug has not already been submitted. Please try # to verify that it is a Privoxy bug, and not a browser or site # bug first. If you are using your own custom configuration, please # try the stock configs to see if the problem is a configuration # related bug. And if not using the latest development snapshot, # please try the latest one. Or even better, CVS sources. # * Submit feature requests only thru our feature request forum: # http://sourceforge.net/tracker/?atid=361118&group_id=11118&func=browse # # For any other issues, feel free to use the mailing lists: # http://sourceforge.net/mail/?group_id=11118 # # Anyone interested in actively participating in development and related # discussions can join the appropriate mailing list here: # http://sourceforge.net/mail/?group_id=11118. Archives are available # here too. # ################################################################################# # # Syntax: # # Generally filters start with a line like "FILTER: name description". # They are then referrable from the actionsfile with +filter{name} # # FILTER marks a filter as content filter, other filter # types are CLIENT-HEADER-FILTER, CLIENT-HEADER-TAGGER, # SERVER-HEADER-FILTER and SERVER-HEADER-TAGGER. # # Inside the filters, write one Perl-Style substitution (job) per line. # Jobs that precede the first FILTER: line are ignored. # # For Details see the pcrs manpage contained in this distribution. # (and the perlre, perlop and pcre manpages) # # Note that you are free to choose the delimiter as you see fit. # # Note2: In addition to the Perl options gimsx, the following nonstandard # options are supported: # # 'U' turns the default to ungreedy matching. Add ? to quantifiers to # switch back to greedy. # # 'T' (trivial) prevents parsing for backreferences in the substitute. # Use if you want to include text like '$&' in your substitute without # quoting. # # 'D' (Dynamic) allows the use of variables. Supported variables are: # $host, $origin (the IP address the request came from), $path and $url. # # Note that '$' is a bad choice as delimiter for dynamic filters as you # might end up with unintended variables if you use a variable name # directly after the delimiter. Variables will be resolved without # escaping anything, therefore you also have to be careful not to chose # delimiters that appear in the replacement text. For example '<' should # be save, while '?' will sooner or later cause conflicts with $url. # ################################################################################# ################################################################################# # # js-annoyances: Get rid of particularly annoying JavaScript abuse. # ################################################################################# FILTER: js-annoyances Get rid of particularly annoying JavaScript abuse. # Note: Most of these jobs would be safer if restricted to a # )|$1never|sigU # If we allow window.open, we want normal window features: # Test: http://www.htmlgoodies.com/beyond/notitle.html # s/(open\s*\([^\)]+resizable=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+location=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+status=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+scroll(?:ing|bars)=)(["']?)(?:no|0)\2/$1$2auto$2/sigU s/(open\s*\([^\)]+menubar=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+toolbar=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+directories=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+fullscreen=)(["']?)(?:yes|1)\2/$1$2no$2/sigU s/(open\s*\([^\)]+always(?:raised|lowered)=)(["']?)(?:yes|1)\2/$1$2no$2/sigU s/(open\s*\([^\)]+z-?lock=)(["']?)(?:yes|1)\2/$1$2no$2/sigU s/(open\s*\([^\)]+hotkeys=)(["']?)(?:yes|1)\2/$1$2no$2/sigU s/(open\s*\([^\)]+titlebar=)(["']?)(?:no|0)\2/$1$2yes$2/sigU s/(open\s*\([^\)]+always(?:raised|lowered)=)(["']?)(?:yes|1)\2/$1$2no$2/sigU ################################################################################# # # js-events: Kill JavaScript event bindings and timers (Radically destructive! Only for extra nasty sites). # ################################################################################# FILTER: js-events Kill JavaScript event bindings and timers (Radically destructive! Only for extra nasty sites). s/(on|event\.)((mouse(over|out|down|up|move))|(un)?load|contextmenu|selectstart)/never/ig # Not events, but abused on the same type of sites: s/(alert|confirm)\s*\(/concat(/ig s/set(timeout|interval)\(/concat(/ig ################################################################################# # # html-annoyances: Get rid of particularly annoying HTML abuse. # ################################################################################# FILTER: html-annoyances Get rid of particularly annoying HTML abuse. # New browser windows (if allowed -- see no-popups filter below) should be # resizeable and have a location and status bar # s/(]+resizable=)(['"]?)(?:no|0)\2/$1$2yes$2/igU s/(]+location=)(['"]?)(?:no|0)\2/$1$2yes$2/igU s/(]+status=)(['"]?)(?:no|0)\2/$1$2yes1$2/igU s/(]+scrolling=)(['"]?)(?:no|0)\2/$1$2auto$2/igU s/(]+menubar=)(['"]?)(?:no|0)\2/$1$2yes$2/igU # The and tags were crimes! # s---sigU ################################################################################# # # content-cookies: Kill cookies that come in the HTML or JS content. # ################################################################################# FILTER: content-cookies Kill cookies that come in the HTML or JS content. # JS cookies, except those used by antiadbuster.com to detect us: # s|(\w+\.)+cookie(?=[ \t\r\n]*=)(?!='aab)|ZappedCookie|ig # HTML cookies: # s|||igU ################################################################################# # # refresh-tags: Kill automatic refresh tags if refresh time is larger than 9 seconds. # ################################################################################# FILTER: refresh-tags Kill automatic refresh tags if refresh time is larger than 9 seconds. # Note: Only deactivates refreshes with more than 9 seconds delay to # preserve monster-stupid but common redirections via meta tags. # s@\2]*))?\2@)(?=\s*[^'"])+$1+isU s@([^\w\s.]\s*)((?:map)?(window|this|parent)\.?)?open\s*\(@$1PrivoxyWindowOpen(@ig s+([^'"]\s*)(?!\s*(\\n|'|"))+$1+iU ################################################################################## # # all-popups: Kill all popups in JavaScript and HTML. # ################################################################################# FILTER: all-popups Kill all popups in JavaScript and HTML. s@((\W\s*)(?:map)?(window|this|parent)\.?)open\s*\\?\(@$1concat(@ig # JavaScript #s/\starget\s*=\s*(['"]?)_?(blank|new)\1?/ notarget/ig # HTML s/\starget\s*=\s*(['"]?)_?(blank|new)\1?/ /ig # (X)HTML ################################################################################## # # img-reorder: Reorder attributes in tags to make the banners-by-* filters more effective. # ################################################################################# FILTER: img-reorder Reorder attributes in tags to make the banners-by-* filters more effective. # In the first step src is moved to the start, then width is moved to the second # place to guarantee an order of src, width, height. Also does some white-space # normalization. # # This makes banners-by-size more effective and allows both banners-by-size # and banners-by-link to preserve the original image URL in the title attribute. s|]*)\ssrc\s*=\s*(['"])([^>\\\2]+)\2|]*)\ssrc\s*=\s*([^'">\\\s]+)|]+height)\s*=\s*|$1=|sig s|\\\\2]*\2\|[^'">\\\s]+?))([^>]*)\s+width\s*=\s*((["']?)\d+?\5)(?=[\s>])|\\\1\s]+)\1)?[^>]*?(width=(['"]?)88\4)[^>]*?(height=(['"]?)31\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)120\4)[^>]*?(height=(['"]?)(?:600?|90|240)\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)125\4)[^>]*?(height=(['"]?)125\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)160\4)[^>]*?(height=(['"]?)600\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)180\4)[^>]*?(height=(['"]?)150\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)(?:234|468)\4)[^>]*?(height=(['"]?)60\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)240\4)[^>]*?(height=(['"]?)400\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)(?:250|300)\4)[^>]*?(height=(['"]?)250\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)336\4)[^>]*?(height=(['"]?)280\6)[^>]*?(?=/?>)@\ \\\1\s]+)\1)?[^>]*?(width=(['"]?)200\4)[^>]*?(height=(['"]?)50\6)[^>]*?(?=/?>)@\ # \1\s]*?(?:\ adclick # See www.dn.se \ | advert # see dict.leo.org \ | atwola\.com/(?:link|redir) # see www.cnn.com \ | doubleclick\.net/jump/ # redirs for doublecklick.net ads \ | counter # common \ | (?\1\s]*)\1[^>]*>\s*\\\3\s]+)\3)?[^>]*((?:width|height)\s*=\s*(['"]?)\d+?\6)[^>]*((?:width|height)\s*=\s*(['"]?)\d+?\8)[^>]*?(?=/?>)\ @\1\s]*?(?:ad(?:click|vert)|atwola\.com/(?:link|redir)|doubleclick\.net/jump/|(?\1\s]*)\1[^>]*>\s*\\\3\s]+)\3)?[^>]*?(?=/?>)@]*\s(?:width|height)\s*=\s*['"]?[01](?=\D)[^>]*\s(?:width|height)\s*=\s*['"]?[01](?=\D)[^>]*?>@@siUg ################################################################################# # # tiny-textforms: Extend those tiny textareas up to 40x80 and kill the hard wrap. # ################################################################################# FILTER: tiny-textforms Extend those tiny textareas up to 40x80 and kill the hard wrap. s/(]*?)(?:\s*(?:rows|cols)=(['"]?)\d+\2)+/$1 rows=$2\40$2 cols=$2\80$2/ig s/(]*?)wrap=(['"]?)hard\2/$1/ig ################################################################################# # # jumping-windows: Prevent windows from resizing and moving themselves. # ################################################################################# FILTER: jumping-windows Prevent windows from resizing and moving themselves. s/(?<=[\W])(?:window|this|self)\.(?:move|resize)(?:to|by)\(/''.concat(/ig ################################################################################# # # frameset-borders: Give frames a border, make them resizable and scrollable. # ################################################################################# FILTER: frameset-borders Give frames a border and make them resizable. s/(]*)framespacing=(['"]?)(no|0)\2/$1/igU s/(]*)frameborder=(['"]?)(no|0)\2/$1/igU s/(]*)border=(['"]?)(no|0)\2/$1/igU s/(]*)noresize/$1/igU s/(]*)frameborder=(['"]?)(no|0)\2/$1/igU s/(]*)scrolling=(['"]?)(no|0)\2/$1/igU ################################################################################# # # iframes: Remove all detected iframes. Should only be enabled for # individual sites after testing that the iframes are optional. # ################################################################################# FILTER: iframes Removes all detected iframes. Should only be enabled for individual sites. s@@@Uisg ################################################################################# # # demoronizer: Correct Microsoft's abuse of standardized character sets, which # leave the browser to (mis)-interpret unknown characters, with # sometimes bizarre results on non-MS platforms. # # credit: ripped from the demoroniser.pl script by: # John Walker -- January 1998, http://www.fourmilab.ch/webtools/demoroniser # ################################################################################# FILTER: demoronizer Fix MS's non-standard use of standard charsets. s/(&\#[0-2]\d\d)\s/$1; /g # per Robert Lynch: http://slate.msn.com//?id=2067547, just a guess. # Must come before x94 below. s/\xE2\x80\x94/ -- /g s/\x82/,/g #s-\x83-f-g s/\x84/,,/g s/\x85/.../g #s/\x88/^/g #s-\x89- °/°°-g s/\x8B/~-g #s-\x99-TM-g # per Robert Lynch. s/\x9B/>/g # 155 ################################################################################# # # shockwave-flash: Kill embedded Shockwave Flash objects. # Note: Better just block "/.*\.swf$"! # ################################################################################# FILTER: shockwave-flash Kill embedded Shockwave Flash objects. s|]*macromedia.*||sigU s|]*(application/x-shockwave-flash\|\.swf).*>(.*)?||sigU ################################################################################# # # quicktime-kioskmode: Make Quicktime movies saveable. # ################################################################################# FILTER: quicktime-kioskmode Make Quicktime movies saveable. s/(]*)kioskmode\s*=\s*(["']?)true\2/$1/ig ################################################################################# # # fun: Text replacements for subversive browsing fun! # ################################################################################# FILTER: fun Text replacements for subversive browsing fun! # SCNR # s/microsoft(?!\.[^\s])/MicroSuck/ig # Buzzword Bingo (example for extended regex syntax) # s* (?:industry|world)[ -]leading \ | cutting[ -]edge \ | customer[ -]focused \ | market[ -]driven \ | award[ -]winning # Comments are OK, too! \ | high[ -]performance \ | solutions[ -]based \ | unmatched \ | unparalleled \ | unrivalled \ *$0Bingo! \ *igx # For Germans only # s/(M|m)edien(?![^<]*>)/$1ädchen/Ug ################################################################################# # # crude-parental: Crude parental filtering. Use with a suitable blocklist. # Pages are "blocked" based on keyword matching. # ################################################################################# FILTER: crude-parental Crude parental filtering. Note that this filter doesn't work reliably. # (Note: Middlesex, Sussex and Essex are counties in the UK, not rude words) # (Note #2: Is 'sex' a rude word?!) s%^.*(?Blocked\

    Blocked by Privoxy's crude-parental filter due to possible adult content.

    %is s+^.*warez.*$+No Warez

    You're not searching for illegal stuff, are you?

    +is # Remove by description s/^.*\ (?:(suck|lick|tongue|rub|fuck|fingering|finger|chicks?)\s*)?\ (?:(her|your|my|hard|with|big|wet|tight|pink|hot|moist|young|teen)\s*)+\ (dicks?|penis|cocks?|balls?|tits?|pussy|cunt|clit|ass|mouth).*$\ /This page has been blocked by Privoxy's crude-parental content filter\ /is #Remove by link text s/^.*\ (download|broadband|view|watch|free|get|extreem)?\s*\ (sex|xxx|porn|cumshot|fuck(ing|s)?|anal|ass|asian|adult|Amateur|org(y|ies)|close ups?|hand?job|nail(ed)?)+\s*\ (movies?|pics?|videos?|dvds?|dvd's|links?).*$\ /This page has been blocked by Privoxy's crude-parental content filter\ /is #Remove by age disclaimer s/^.*\ (models?|chicks?|girls?|women|persons)\s*\ (who|are|were)+ (over|at least) (16|18|21) years (old|of age).*$\ /This page has been blocked by Privoxy's crude-parental content filter\ /is #Remove by regulations s/^.*(Section 2257|18 U.?S.?C.? 2257).*$\ /This page has been blocked by Privoxy's crude-parental content filter\ /is ################################################################################# # # IE-Exploits: Disable some known Internet Explorer bug exploits. # ################################################################################# FILTER: ie-exploits Disable some known Internet Explorer bug exploits. # Note: This is basically a demo and waits for someone more interested in IE # security (sic!) to take over. # Cross-site-scripting: # s%f\("javascript:location.replace\('mk:@MSITStore:C:'\)"\);%alert\("This page looks like it tries to use a vulnerability described here:\n http://online.securityfocus.com/archive/1/298748/2002-11-02/2002-11-08/2"\);%siU # Address bar spoofing (http://www.secunia.com/advisories/10395/): # s/(]*href[^>]*)(?:\x01|\x02|\x03|%0[012])@/$1MALICIOUS-LINK@/ig # Nimda: # s%%
    WARNING: This Server is infected with Nimda!%g ################################################################################# # # # site-specifics: Cure for site-specific problems. Don't apply generally! # # Note: The fixes contained here are so specific to the problems of the # particular web sites they are designed for that they would be a # waste of CPU cycles (or even destructive!) on 99.9% of the web # sites where they don't apply. # ################################################################################# FILTER: site-specifics Cure for site-specific problems. Don't apply generally! # www.spiegel.de excludes X11 users from viewing Flash5 objects - shame. # Apply to: www.spiegel.de/static/js/flash-plugin.js # s/indexOf\("x11"\)/indexOf("x13")/ # www.quelle-bausparkasse.de uses a very stupid redirect mechanism that # relies on a webbug being present. Can we tolerate that? No! # Apply to: www.quelle-bausparkasse.de/$ # s/mylogfunc()//g # groups.yahoo.com has splash pages that one needs to click through in # order to access the actual messages. Let the browser do that. Thanks # to Paul Jobson for this one: # s|(?:Continue to message\|Weiter zu Nachricht)||ig # monster.com has two very similar gimmicks: # s|||i s|||i # nytimes.com triggers popups through the onload handler of dummy images # to fool popup-blockers. # s|(]*)onload|$1never|sig # Pre-check all the "Discard" buttons in GNU Mailman's web interface. # (This saves a lot of mouse aiming practice when flushing spamtraps) # s|( and tags. # ################################################################################# FILTER: no-ping Removes non-standard ping attributes in and tags. s@(]*?)\sping=(['"]?)([^"'>]+)\2([>\s]?)@\ PING!\n$1$4@ig ################################################################################# # # google: CSS-based block for Google text ads. Also removes # a width limitation and the toolbar advertisement. # ################################################################################# FILTER: google CSS-based block for Google text ads. Also removes a width limitation and the toolbar advertisement. s@[^\\]@\n$0@ s@
    @
    @ s@(
    @\n\n$0\n@ s@(]*)width:545px;@$1width:70%;@isU ################################################################################# # # msn: CSS-based block for MSN text ads. Also removes tracking URLs # and a width limitation. # ################################################################################# FILTER: msn CSS-based block for MSN text ads. Also removes tracking URLs and a width limitation. s@@\n$0@ # Are these ids still in use? s@(]*) id=(["']?)ads_[^\2]*\2@$1 class="msn_ads"@Uig s@(]*) class=(["']?)sb_ads[^\2]*\2@$1 class="msn_ads"@Uig s@(]*href=\")http://g.msn.com/.*\?(http://.*)(&&DI=.*)(\")@$1$2$4@Ug s@(]*)gping=\".*\"@$1 title="URL cleaned up by Privoxy's msn filter"@Ug ################################################################################# # # blogspot: Cleans up some Blogspot blogs. Read the fine print before using this. # # This filter also intentionally removes some navigation stuff and # sets the page width to 100%. As a result, some rounded "corners" would # appear to early or not at all and as fixing this would require a browser # that understands background-size (CSS3), they are removed instead. # # When applied to feeds, it removes comment titles that # only contain the beginning of the actual comment. # ################################################################################# FILTER: blogspot Cleans up some Blogspot blogs. Read the fine print before using this. s@@\n$0@ s@|(
    ([^<]*)(?:\.\.\.)?\s*\s*\ (\s*\1)@$2@ig ################################################################################# # # x-httpd-php-to-html: Changes the Content-Type header from # x-httpd-php to html. "Content-Type: x-httpd-php" # is set by clueless PHP users and causes many # browsers do open a download menu instead of # rendering the page. # ################################################################################# SERVER-HEADER-FILTER: x-httpd-php-to-html Changes the Content-Type header from x-httpd-php to html. s@^(Content-Type:)\s*application/x-httpd-php@$1 text/html@i ################################################################################# # # html-to-xml: Changes the Content-Type header from html to xml. # ################################################################################# SERVER-HEADER-FILTER: html-to-xml Changes the Content-Type header from html to xml. s@^(Content-Type:)\s*text/html(;.*)?$@$1 application/xhtml+xml$2@i ################################################################################# # # xml-to-html: Changes the Content-Type header from xml to html. # ################################################################################# SERVER-HEADER-FILTER: xml-to-html Changes the Content-Type header from xml to html. s@^(Content-Type:)\s*(?:application|text)/(?:xhtml\+)?xml(;.*)?$@$1 text/html$2@i ################################################################################# # # hide-tor-exit-notation: Remove the Tor exit node notation in Host and Referer headers. # # Note: If Privoxy and Tor are chained and Privoxy is configured to # use socks4a, one can use http://www.example.org.foobar.exit/ # to access the host www.example.org through Tor exit node foobar. # # As the HTTP client isn't aware of this notation, it treats the # whole string "www.example.org.foobar.exit" as host and uses it # for the "Host" and "Referer" headers. From the server's point of # view the resulting headers are invalid and can cause problems. # # An invalid "Referer" header can trigger "hot-linking" protections, # an invalid "Host" header will make it impossible for the server to # find the right vhost (several domains hosted on the same IP address). # # This filter removes the "foo.exit" part in those headers # to prevent the mentioned problems. Note that it only modifies # the HTTP headers, it doesn't make it impossible for the server # to detect your Tor exit node based on the IP address the request is # coming from. # ################################################################################# CLIENT-HEADER-FILTER: hide-tor-exit-notation Removes the Tor exit node notation in Host and Referer headers. s@^((?:Referer|Host):\s*(?:https?://)?[^/]*)\.[^\./]*?\.exit@$1@i ################################################################################# # # less-download-windows: Prevents annoying download windows for content types # the browser can handle itself. # ################################################################################# SERVER-HEADER-FILTER: less-download-windows Prevent annoying download windows for content types the browser can handle itself. s@^Content-Disposition:.*filename=(["']?).*\.(png|gif|jpe?g|diff?|d?patch|c|h|pl|shar)\1.*$@@i s@^(Content-Type:)\s*(?:message/(?:news|rfc822)|text/x-.*|application/x-sh(?:\s|$))\s*@$1 text/plain@i ################################################################################# # # image-requests: Tags detected image requests as "IMAGE-REQUEST". Whether # or not the detection actually works depends on the browser. # ################################################################################# CLIENT-HEADER-TAGGER: image-requests Tags detected image requests as "IMAGE-REQUEST". s@^Accept:\s*image/.*@IMAGE-REQUEST@i ################################################################################# # # css-requests: Tags detected CSS requests as "CSS-REQUEST". Whether # or not the detection actually works depends on the browser. # ################################################################################# CLIENT-HEADER-TAGGER: css-requests Tags detected CSS requests as "CSS-REQUEST". s@^Accept:\s*text/css.*@CSS-REQUEST@i ################################################################################# # # range-requests: Tags range requests as "RANGE-REQUEST". # # By default Privoxy removes Range headers for requests to # ressources that will be filtered to make sure the filters # get the whole picture. Otherwise Range requests could be # intentionally used to circumvent filters or, less likely, # filtering a partial response may damage it because it matched # a pattern that the ressource as a whole wouldn't. # # Range requests can be useful and save bandwidth so instead # of removing Range headers for requests to ressources that # will be filtered, you may prefer to simply disable filtering # for those requests. # # That's what this tagger is all about. After enabling it, # you can disable filtering for range requests using the following # action section: # # {-filter -deanimate-gifs} # TAG:^RANGE-REQUEST # ################################################################################# CLIENT-HEADER-TAGGER: range-requests Tags range requests as "RANGE-REQUEST". s@^Range:.*@RANGE-REQUEST@i ################################################################################# # # client-ip-address: Tags the request with the client's IP address. # ################################################################################# CLIENT-HEADER-TAGGER: client-ip-address Tags the request with the client's IP address. s@^\w*\s+.*\s+HTTP/\d\.\d\s*@IP-ADDRESS: $origin@D ################################################################################# # # http-method: Tags the request with its HTTP method. # ################################################################################# CLIENT-HEADER-TAGGER: http-method Tags the request with its HTTP method. s@^(\w*).*HTTP/\d\.\d\s*$@$1@i ################################################################################# # # allow-post: Tags POST requests as "ALLOWED-POST". # ################################################################################# CLIENT-HEADER-TAGGER: allow-post Tags POST requests as "ALLOWED-POST". s@^(?:POST)\s+.*\s+HTTP/\d\.\d\s*@ALLOWED-POST@i ################################################################################# # # complete-url: Tags the request with the whole request URL. # ################################################################################# CLIENT-HEADER-TAGGER: complete-url Tags the request with the whole request URL. s@^\w*\s+(.*)\s+HTTP/\d\.\d\s*$@$1@i ################################################################################# # # user-agent: Tags the request with the complete User-Agent header. # ################################################################################# CLIENT-HEADER-TAGGER: user-agent Tags the request with the complete User-Agent header. s@^User-Agent:.*@$0@i ################################################################################# # # referer: Tags the request with the complete Referer header. # ################################################################################# CLIENT-HEADER-TAGGER: referer Tags the request with the complete Referer header. s@^Referer:.*@$0@i ################################################################################# # # content-type: Tags the request with the content type declared by the server. # ################################################################################# SERVER-HEADER-TAGGER: content-type Tags the request with the content type declared by the server. s@^Content-Type:\s*([^;]+).*@$1@i ################################################################################# # # privoxy-control: The taggers create tags with the content of X-Privoxy-Control # headers, the filters remove said headers. # ################################################################################# CLIENT-HEADER-TAGGER: privoxy-control Creates tags with the content of X-Privoxy-Control headers. s@^X-Privoxy-Control:\s*@@i CLIENT-HEADER-FILTER: privoxy-control Removes X-Privoxy-Control headers. s@^X-Privoxy-Control:.*@@i SERVER-HEADER-TAGGER: privoxy-control Creates tags with the content of X-Privoxy-Control headers. s@^X-Privoxy-Control:\s*@@i SERVER-HEADER-FILTER: privoxy-control Removes X-Privoxy-Control headers. s@^X-Privoxy-Control:.*@@i privoxy-3.0.21-stable/./LICENSE000640 001751 001751 00000043254 12113147770 015002 0ustar00fkfk000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. privoxy-3.0.21-stable/./templates/cgi-error-parse000640 001751 001751 00000011637 11630656133 020720 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy: Parse error
  • # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Parse error

    The file you're trying to edit is not valid. You need to fix it using a text editor before you can edit it using the web-based editor.

    This error should only occur if you edited the file using a text editor. If you managed to take a valid file and break it this badly using the web-based editor, please file a bug report!

    When you've fixed the problem, you can go back into the edit interface using the menu below, or by clicking here.

    Problem description:

    @parse-error@

    The line which caused the problem:

    @line-raw@

    The line which caused the problem, with comments removed

    @line-data@

    Note

    Only the first error is reported - the file may contain other errors, as well as the one reported above.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/default000640 001751 001751 00000007174 11630656133 017344 0ustar00fkfk000000 000000 ########################################################## # # Default-CGI Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy@@my-hostname@ # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Privoxy Menu:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/mod-local-help000640 001751 001751 00000001020 11661506153 020475 0ustar00fkfk000000 000000

    Local Privoxy support:

    You can consult the online documentation for more information about this Privoxy installation.

    Address e-mail questions about this Privoxy installation to @admin-address@, who will be glad to help you.

    privoxy-3.0.21-stable/./templates/cgi-error-file-read-only000640 001751 001751 00000010472 11630656133 022411 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy: Cannot write to actions file # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Cannot write to actions file

    The actions file you are trying to edit (@f@.action) could not be written to.

    You many not have permission to write to the file - check the file permissions. On Windows, right-click the file, choose Properties, and make sure it is not read-only.

    Another reason you may see this message is if you have run out of disk space. If that is the case, then the actions file has been truncated - if you get further errors, you may need to fix it using a text editor.

    Privoxy Menu:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-error-disabled000640 001751 001751 00000013011 11630656133 021341 0ustar00fkfk000000 000000 ########################################################## # # Feature disabled or referrer untrusted Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Configuration Page Disabled # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Privoxy Configuration access denied

    Access to @url@ has been denied because:

    • it requires a feature that has been disabled by the Privoxy administrator,
    • you didn't come here through one of Privoxy's CGI pages, or
    • the Referer: header is blocked.

    Note that the following features which used to be enabled in earlier releases are now off by default:

    Please refer to the documentation behind the links to learn how to enable them again and what the consequences are.

    All enabled features are accessible from the main menu, some of them are protected with a referrer check though. If you got caught by the referrer check, but are absolutely sure you know what you are doing, please try again.

    If the Referer: header is blocked, you'll have to make an exception for Privoxy's web interface first. Note that dumb referrer blocking is a bad idea anyway, as it makes it easier to fingerprint your requests. Consider using Privoxy's conditional referrer block instead.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-style.css000640 001751 001751 00000012227 11630656164 020406 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/cgi-style.css,v $ # # Purpose : Style sheet for the web-based config interface. # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## /* * CSS for Privoxy CGI and script output * * $Id: cgi-style.css,v 1.14 2011/09/04 11:09:40 fabiankeil Exp $ */ /* * General rules: Font, Color, Headings, Margins, Links */ body,td,th { font-family: arial, helvetica, helv, sans-serif; } body { background-color: #ffffff; color: #000000; } h1 { font-size: 140%; margin: 0px; } h2 { font-size: 120%; margin: 0px; } h3 { font-size: 110%; margin: 0px; } p,pre { margin-left: 15px; } li { margin: 2px 15px; } dl { margin: 2px 15px; } a:link { color: #0000dd; text-decoration: none; } a:visited { color: #330099; text-decoration: none; } a:active { color: #3333ff; text-decoration: none; } /* * Boxen as Table elements: */ td.title { border: solid black 1px; background-color: #dddddd; } td.box { border: solid black 1px; background-color: #eeeeee; } td.info { border: solid black 1px; background-color: #ccccff; } td.warning { border: solid black 1px; background-color: #ffdddd; } /* * Special Table Boxen: for nesting, naked container and for * the Status field in CGI Output: */ td.wrapbox { border: solid black 1px; padding: 5px; } td.container { padding: 0px; } td.status { border: solid black 1px; background-color: #ff0000; color: #ffffff; font-size: 300%; font-weight: bolder; } /* * Same Boxen as
    s: */ div.title { border: solid black 1px; background-color: #dddddd; margin: 20px; padding: 20px; } div.box { border: solid black 1px; background-color: #eeeeee; margin: 20px; padding: 20px; } div.info { border: solid black 1px; background-color: #ccccff; margin: 20px; padding: 20px; } div.warning { border: solid black 1px; background-color: #ffdddd; margin: 20px; padding: 20px; } div.wrapbox { border: solid black 1px; margin: 20px; padding: 5px; } /* * Bold definitions in
    s, grey BG for table headings, transparent (no-bordered) table */ dt { font-weight: bold; } th { background-color: #dddddd; } table.transparent { border-style: none} /* * Special purpose paragraphs: Small for page footers, * Important for quoting wrong or dangerous examples, * Whiteframed for the toggle?mini=y CGI */ p.small { font-size: 10px; margin: 0px; } p.important { border: solid black 1px; background-color: #ffdddd; font-weight: bold; padding: 2px; } p.whiteframed { margin: 5px; padding: 5px; border: solid black 1px; text-align: center; background-color: #eeeeee; } /* * Links as buttons: */ td.buttons { padding: 2px; } a.cmd, td.indentbuttons a, td.buttons a { white-space: nowrap; width: auto; padding: 2px; background-color: #dddddd; color: #000000; text-decoration: none; border-top: 1px solid #ffffff; border-left: 1px solid #ffffff; border-bottom: 1px solid #000000; border-right: 1px solid #000000; } a.cmd:hover, td.indentbuttons a:hover, td.buttons a:hover { background-color: #eeeeee; } a.cmd:active, td.indentbuttons a:active, td.buttons a:active { border-top: 1px solid #000000; border-left: 1px solid #000000; border-bottom: 1px solid #ffffff; border-right: 1px solid #ffffff; } /* * Special red emphasis: */ em.warning, strong.warning { color: #ff0000 } /* * In show-status we use tables directly behind headlines * and for some reason or another the headlines are set to * "margin:0" and leave the tables no air to breath. * * A proper fix would be to replace or remove the "margin:0", * but as this affects every cgi page we do it another time * and use this workaround until then. */ .box table { margin-top: 1em; } /* * Let the URL and pattern input fields scale with the browser * width and try to prevent vertical scroll bars if the width * is less than 80 characters. */ input.url, input.pattern { width: 95%; } privoxy-3.0.21-stable/./templates/connection-timeout000640 001751 001751 00000004132 11214167044 021526 0ustar00fkfk000000 000000 ########################################################## # # connection-timeout Error Output template for Privoxy. # ########################################################## 504 - Connection timeout (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    504 #include mod-title
    #include mod-unstable-warning

    Connection timeout

    Your request for @protocol@@hostport@@path@ could not be fulfilled, because the connection to @host@ (@host-ip@) timed out.

    This is often a temporary failure, so you might just try again.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-url-form000640 001751 001751 00000010400 11630656133 022026 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-url-form,v $ # # Purpose : Template used to edit a URL pattern in an actions file. # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## # # Standard support: # # This file currently produces valid HTML 4.01 Strict. # # If you change it, please save the generated page from your web browser # and then upload it to http://validator.w3.org/ for checking. # ############################################################################# # # Available variables include: # # f - filename # v - version # s - section # p - pattern # u - old value of URL # jumptarget - append to eal URL to jump to relevant section # ############################################################################# Privoxy@@my-hostname@: Edit URL Pattern # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Edit URL or TAG Pattern


        Cancel

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/mod-unstable-warning000640 001751 001751 00000000612 10751642111 021735 0ustar00fkfk000000 000000

    Warning:

    This Privoxy version is based on @code-status@ code and not intended for production systems!
    Use at your own risk. See the license for details.

    privoxy-3.0.21-stable/./templates/edit-actions-for-url000640 001751 001751 00000161135 12047716223 021665 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-for-url,v $ # # Purpose : Template used to edit the actions associated with a # particular section in an actions file. # # # Copyright : Written by and Copyright (C) 2001-2012 the # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## # # Standard support: # # This file currently produces valid HTML 4.01 Strict. # # If you change it, please save the generated page from your web browser # and then upload it to http://validator.w3.org/ for checking. # ############################################################################## # # Available variables include: # # action-name-y # action-name-n # action-name-x # # deanimate-gifs-param-first # deanimate-gifs-param-last # hide-from-param-block # hide-from-param-custom # hide-from-param # hide-referrer-param-forge # hide-referrer-param-block # hide-referrer-param-custom # hide-referrer-param # hide-user-agent-param # image-blocker-param-pattern # image-blocker-param-blank # image-blocker-param-custom # # ############################################################################## Privoxy@@my-hostname@: Edit actions
    # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Edit Actions

    Edit Actions (Section 1)

    @client-header-filter-params@ @client-header-tagger-params@
    Enable Disable No Change Action Description
    add-header Adds HTTP headers.
            Editing the settings for this option, or turning it on if it was off, is not yet supported using this web-based editor.
    block Block the request.
            Block reason to tell the user:
    change-x-forwarded-for Specifies whether to block or add X-Forwarded-For headers.
           

      client-header-filter * Filter the client headers. You can use the radio buttons on this line to disable all client-header filters applied by previous rules, and/or you can enable or disable the filters individually below.
      client-header-tagger * Create tags based on the client headers. You can use the radio buttons on this line to disable all client-header taggers applied by previous rules, and/or you can enable or disable the taggers individually below.
    content-type-overwrite Replace Content-Type header. By default it only applies to text documents, but if you know what you're doing you can enable force-text-mode to modify binary content types as well.
            New Content-Type:
    crunch-client-header Remove header(s) matching the supplied pattern.
            Header string to suppress:
    crunch-if-none-match Remove If-None-Match header. Useful for filter testing and to make sure the header can't be used to track your visits.
    crunch-incoming-cookies Prevent the website from setting HTTP cookies on your system.
    crunch-outgoing-cookies Prevent the website from reading HTTP cookies from your system.
    crunch-server-header Remove server header(s) matching the supplied pattern.
            Header string to suppress:
    deanimate-gifs Replace animated GIFs with their (first/last) frame.
            Use the   
    downgrade-http-version Change HTTP/1.1 requests to HTTP/1.0. Only change if you know what you're doing!
    fast-redirects Bypass some click-tracking URLs.
           

    Edit Actions (Section 2)

    @content-filter-params@
    Enable Disable No Change Action Description
      filter * Filter the website through regular expression filters. You can use the radio buttons on this line to disable all filters applied by previous rules, and/or you can enable or disable the filters individually below.

    Edit Actions (Section 3)

    Enable Disable No Change Action Description
    force-text-mode Enable filtering on documents whose Content-Type wasn't recognized as text. Do think twice, nothing is alright.
    forward-override Override forward directives in the configuration file. Note that the parameter syntax isn't checked until the action is used. Syntax errors will cause Privoxy to exit.
            Overriding forward directive:

    handle-as-empty-document Block with an empty document instead of an Image or HTML message. The empty document contains only a space and can safely be parsed as JavaScript or Style Sheet. Use content-type-overwrite to specify the Content-Type, default is text/html.
    handle-as-image Request is for an image (only useful in conjunction with the block and set-image-blocker actions).
    hide-accept-language Pretend to have different language settings. (Makes a fake User-Agent more believable, but you may end up with content in the language you pretended to understand.)
           


    hide-content-disposition Block or overwrite the content-disposition header. Useful to view a document inside the browser, even if you were supposed to save it first, or to change the suggested file name.
           


    hide-from-header Stop old web browsers from sending the user's e-mail address with every request.
           

    hide-if-modified-since Remove or randomize the If-Modified-Since header.
            Useful for filter testing.
    minute(s). To appreciate this option a small amount of paranoia is required, but at least in theory the If-Modified-Since header could be used to keep track of your visits.

    Edit Actions (Section 4)

    @server-header-filter-params@ @server-header-tagger-params@
    Enable Disable No Change Action Description
    hide-referrer Helps prevent tracking by not sending the URL of the previous web page. 
            (breaks images on some free web hosts).
    (fools checks for in-site links.)




    hide-user-agent Pretend to be using a different web browser.  (May cause problems with broken web sites).
            User Agent string to send:
    limit-connect Limit which ports are allowed in HTTP CONNECT requests. These requests are used to tunnel SSL and other protocols through HTTP proxies.
            Legal ports (comma separated, ranges allowed):
    limit-cookie-lifetime Limit the cookie lifetime specified in Set-Cookie headers.
    overwrite-last-modified Remove or randomize the Last-Modified header.
           

    prevent-compression Disables compression. Compressed web pages are faster to download, but cannot be filtered with filter or kill-popups if your Privoxy version was build without zlib support.
    redirect Redirect to another address.
            Static address or a single pcrs command to redirect to a rewritten version of the original URL:
      server-header-filter * Filter the server headers. You can use the radio buttons on this line to disable all server-header filters applied by previous rules, and/or you can enable or disable the filters individually below.
      server-header-tagger * Create tags based on the server headers. You can use the radio buttons on this line to disable all server-header taggers applied by previous rules, and/or you can enable or disable the taggers individually below.
    session-cookies-only HTTP cookies set by the website are changed to temporary ("per-session") ones, which only last until you close your web browser. This will allow you to use sites that require cookies, but sites will not be able to track you across sessions. For this to be useful, you should disable crunch-outgoing-cookies and crunch-incoming-cookies.
    set-image-blocker Specifies how to block images.
           


    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-error-file000640 001751 001751 00000007543 11630656133 020526 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy: Actions file not found # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Actions file not found

    The actions file you are trying to edit (index @f@) does not exist, or cannot be read.

    Privoxy Menu:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/untrusted000640 001751 001751 00000012750 11630656134 017752 0ustar00fkfk000000 000000 ########################################################## # # "Untrusted" Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # hostport: # The host and port part of the request that lead to this problem # path: # The path part of the request that lead to this problem # referrer: # The referrer of the request that lead to this problem # trusted-referrers: # An HTML-formatted list of referrers that are marked as trusted in # the trustfile # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # This is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # force-support: # Privoxy has been compiled with support for forced loading # of blocked content. In that case, the symbol "force-prefix" is # avaiable, which translates to the FORCE_PREFIX # have-trust-info: # There were URLs with info on the trust policy defined in the config # file. In this case the list of URLs is available through the # "trust-info" symbol. # # Untrusted request (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    UNTRUSTED #include mod-title
    #include mod-unstable-warning

    Request for untrusted URL

    Your request for @protocol@@hostport@@path@ was blocked, because neither the request URL itself, nor its referrer (@referrer@) were trusted.

    (You can go there anyway.)

    The following referrers are trusted:

      @trusted-referrers@

    More information on the trust policy:

    You can learn more about what this means and what you may be able to do about it by reading the following documents:

      @trust-info@

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-error-404000640 001751 001751 00000010647 11630656133 020115 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # 404 - Privoxy Configuration Page not found # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    404 #include mod-title
    #include mod-unstable-warning

    Privoxy Configuration page not found

    You typed in what looks like a URL used to configure Privoxy, but it cannot be recognised. Maybe it's for a different Privoxy version, or you typed it in wrong? Or maybe the Privoxy administrator has decided to disable the feature.

    If you got here by clicking a link in the configuration interface, please file a bug report!

    You can use the menu below to select from the available configuration options

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/no-server-data000640 001751 001751 00000005164 11214167321 020536 0ustar00fkfk000000 000000 ########################################################## # # no-server-data Error Output template for Privoxy. # ########################################################## 502 - No server or forwarder data received (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    502 #include mod-title
    #include mod-unstable-warning

    No server or forwarder data received

    Your request for @protocol@@hostport@@path@ could not be fulfilled, because the connection to @host@ (@host-ip@) has been closed before Privoxy received any data for this request.

    This is often a temporary failure, so you might just try again.

    If you get this message very often, consider disabling connection-sharing (which should be off by default). If that doesn't help, you may have to additionally disable support for connection keep-alive by setting keep-alive-timeout to 0.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-for-url-filter000640 001751 001751 00000003045 11630656133 023143 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-for-url-filter,v $ # # Purpose : Template that is included from most of Privoxy's CGI pages # to show the user how to get help or report problems. # # # Copyright : Written by and Copyright (C) 2002-2007 members of # the SourceForge Privoxy team. http://www.privoxy.org/ # # This template is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # ############################################################################## @filter-type@ @name@ @description@ privoxy-3.0.21-stable/./templates/mod-title000640 001751 001751 00000000450 10546014101 017570 0ustar00fkfk000000 000000

    This is Privoxy @version@ on @my-hostname@ (@my-ip-address@), port @my-port@, @if-enabled-display-then@enabled@else-not-enabled-display@disabled@endif-enabled-display@

    privoxy-3.0.21-stable/./templates/show-status-file000640 001751 001751 00000010021 11630656133 021117 0ustar00fkfk000000 000000 ########################################################## # # Show-Status-CGI Output template for Privoxy. # (Variant for the show-file mode) # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # file-description: # A descriptive name for the file being shown # contents: # The contents of the file being shown # filepath # The complete filename of the file being shown # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # This is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy@@my-hostname@: Contents of @file-description@ # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Contents of @file-description@ @filepath@

    @contents@

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-add-url-form000640 001751 001751 00000010242 11630656133 022560 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-add-url-form,v $ # # Purpose : Template used to add a URL pattern to the actions file. # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## # # Standard support: # # This file currently produces valid HTML 4.01 Strict. # # If you change it, please save the generated page from your web browser # and then upload it to http://validator.w3.org/ for checking. # ############################################################################# # # Available variables include: # # filename # ver # section # ############################################################################# Privoxy@@my-hostname@: Add URL Pattern # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Add URL or TAG Pattern


        Cancel

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-remove-url-form000640 001751 001751 00000007626 11630656133 023341 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-remove-url-form,v $ # # Purpose : Template used to confirm removal of a particular URL # pattern from an actions file. Only used on browsers that # don't support JavaScript. # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## # # Standard support: # # This file currently produces valid HTML 4.01 Strict. # # If you change it, please save the generated page from your web browser # and then upload it to http://validator.w3.org/ for checking. # ############################################################################# # # Available variables include: # # filename # ver # section # pattern # oldval # jumptarget - append to eal URL to jump to relevant section # ############################################################################# Privoxy@@my-hostname@: Remove URL Pattern # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Remove URL Pattern

    Are you sure you want to delete this URL pattern? The pattern is:

    @u@

    OK   Cancel

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-list000640 001751 001751 00000021660 11630656133 021250 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-list,v $ # # Purpose : Template used to edit the actions file. # # # Copyright : Written by and Copyright (C) 2001-2009 the # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## # # Browser support for the CSS on this page: # MS Internet Explorer 5.5 - Yes - everything works. # Netscape 6.2 - Yes - everything works. # Netscape 4.75 - No - CSS buttons look really bad, but they are # usable. Everything else works. # Opera 5.12 - Yes - everything works. # MS Internet Explorer 4+ - Untested # MS IE 3.x, NS3.x - Untested (Don't support CSS, so everything # should work, but will look ugly). # Mozilla >=0.6 - Yes - everything works. # # All browsers should work, you just might not get the pretty CSS buttons. # # If your favorite browser isn't listed/tested, please test and add it. # # ############################################################################# # # Standard support: # # This file currently produces valid HTML 4.01 Strict. # # If you change it, please save the generated page from your web browser # and then upload it to http://validator.w3.org/ for checking. # ############################################################################# # # Available variables include: # # filename # ver # # ############################################################################# Privoxy: Edit actions file @actions-file@ # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in @sections@
    #include mod-title
    #include mod-unstable-warning

    What is all this?

    If you haven't already done so, it is strongly recommended that you at least skim the chapter on actions files in the User Manual before making any changes. You will also find a comprehensive list of all available actions there, as well how the settings on this page work.

    Please note that the first section has special importance. It sets the default actions for all URLs. The resulting actions for a particular URL may differ from these defaults if that URL matches again further down, but this section is largely responsible for your browsing experience. Edit manually with great care, or choose from the predefined sets of actions.

    This is the default action file. Updates for it are available from Privoxy.org from time to time. It is therefore not recommended that you add your private rules here, since they will be lost if you install an update in the future. Put your rules in a separate actions file, like user.action instead.

    Editing Actions File @actions-file@

    Insert new section at top

    Actions:
    Edit @all-urls-buttons@
    @all-urls-actions@
    URL patterns:
    /   (Matches all requests)
    Advanced:
    Insert new section below

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/show-version000640 001751 001751 00000011264 11630656134 020357 0ustar00fkfk000000 000000 ########################################################## # # Show-Status-CGI Output template for Privoxy. # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # redirect-url: # The URL to a script that will redirect to the Privoxy # documentation for a given item # invocation: # The command line with whitch Privoxy was invoked # options: # The options read from the configfile, linked to their # explanations, plus warnings if parsing acl or forward # statements produced errors. # sourceversions: # A HTML-formatted list of the individual source file cvs versions # defines: # A HTML-formatted list of all conditional #defines used when # Privoxy was compiled # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # This is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # sourceversions # The versions. Privoxy@@my-hostname@: Detailed proxy version information # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Source code versions:

    (Note: This information is only relevant if you checked out Privoxy from CVS and compiled it yourself. If you downloaded a binary, .exe, RPM, or a .tgz file, then when you ask for support just mention the version number @version@ and the type of download you got.)

    @sourceversions@

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/connect-failed000640 001751 001751 00000010675 11630656133 020573 0ustar00fkfk000000 000000 ########################################################## # # Connect-Failed Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # host-ip: # The IP address of the host that could not be reached # hostport: # The host and port part of the request that lead to this problem # path: # The path part of the request that lead to this problem # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # 503 - Connect failed (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    503 #include mod-title
    #include mod-unstable-warning

    Connect failed

    Your request for @protocol@@hostport@@path@ could not be fulfilled, because the connection to @host@ (@host-ip@) could not be established.

    This is often a temporary failure, so you might just try again.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/toggle000640 001751 001751 00000015657 11630656134 017207 0ustar00fkfk000000 000000 ########################################################## # # Toggle Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@ # @if-enabled-display-then@Enabled@else-not-enabled-display@Disabled@endif-enabled-display@ - Privoxy@@my-hostname@ # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Privoxy is @if-enabled-display-then@Enabled@else-not-enabled-display@Disabled@endif-enabled-display@

    When enabled, Privoxy performs its magic - blocking adverts, filtering cookies, regex-filtering, etc.

    When disabled, Privoxy behaves as a normal HTTP proxy, and will not affect your web browsing.

    Click here to @if-enabled-display-then@disable@else-not-enabled-display@enable@endif-enabled-display@ Privoxy.

    Bookmarklets

    Here are some bookmarklets to allow you to easily access a "mini" version of this page. They are known to work with MS Internet Explorer, Netscape and Mozilla, but should work equally well in other browsers which support JavaScript. They are designed to run directly from your bookmarks - not by clicking the links below (although that will work for testing).

    To save them, right-click the link and choose "Add to Favorites" (IE) or "Add Bookmark" (Netscape). You will get a warning that the bookmark "may not be safe" - just click OK. Then you can run the Bookmarklet directly from your favourites/bookmarks. For even faster access, you can put them on the "Links" bar (IE) or the "Personal Toolbar" (Netscape), and run them with a single click.

    Credit: The site which gave us the general idea for these bookmarklets is www.bookmarklets.com. They have more information about them.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-error-modified000640 001751 001751 00000011477 11630656133 021370 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy: URL out of date # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    URL out of date - file has changed since it was generated

    The URL you're viewing is out of date. To prevent possible damage to your configuration file, this action has been ignored.

    Possible causes:

    • If you got here using your browser's "back" button, then that is deliberately disabled for this page. Please navigate around the configuration editor using the links provided.
    • Perhaps you've got more than one browser window open, and you're trying to change the same file in both? You can only have one editor window open at a time. Your other edit window should continue to function.
    • You may have modified the file some other way - perhaps by editing it with a text editor. Simply go back in to the configuration interface using the links below.

    You can go back into the edit interface using the menu below, or by clicking here.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-list-section000640 001751 001751 00000006310 11630656133 022705 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-list-section,v $ # # Purpose : Template which forms part of edit-actions-list # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################# # # Available variables include: # # filename # ver # sectionid # urls # ############################################################################# # # ** Important note: ** # # It is important to keep this file small. That's why all the # identifiers in the HTML are short and cryptic. Currently, the main # edit-actions page is ~300k. Before it was optimized, it was ~550k. # ############################################################################# @urls@
    Actions:
    Edit
    @actions@
    URL patterns:
    Add
    Advanced:
    @if-s-prev-exists-start@Move section up   @if-s-prev-exists-end@ @if-s-next-exists-start@Move section down   @if-s-next-exists-end@ Insert new section below @if-empty-section-start@   Delete whole section@if-empty-section-end@
    privoxy-3.0.21-stable/./templates/blocked000640 001751 001751 00000023222 11630656133 017313 0ustar00fkfk000000 000000 ########################################################## # # "Blocked" Error Output template for Privoxy. # # NOTE: UNLIKE THE OTHER TEMPLATES, THIS ONE USES # JavaScript write() TO GENERATE THE PAGE IN JS_AWARE # BROWSERS. SYMBOL SUBSTITUTIONS THAT RESULT IN MULTILINE # STRINGS WILL BREAK THE JavaScript SYNTAX. # USE WITH CAUTION. # # USING HTML TEMPLATES: # --------------------- # # Template files are written in plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # protocol: # The request's protocol: http:// or https:// # hostport: # The host and port part of the blocked request's URL. # path: # The path part of the blocked request's URL. # path-ue: # The path part of the blocked request's URL, url-encoded. # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # This is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # force-support: # Privoxy has been compiled with support for forced loading # of blocked content. In that case, the symbol "force-prefix" is # avaiable, which translates to the FORCE_PREFIX # Request blocked (Privoxy@@my-hostname@) # Note: The same small version is used above via JavaScript # If you make changes here, keep the other version in sync! privoxy-3.0.21-stable/./templates/show-request000640 001751 001751 00000010447 11630656133 020363 0ustar00fkfk000000 000000 ########################################################## # # Show-Request-CGI Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # client-request: # The request and headers that the client sent. # processed-request: # What we would have rewritten this request to, if this had not # been intercepted. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy@@my-hostname@ # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Show-Request

    Here you see the original headers that your client sent when requesting this page, along with the headers that Privoxy would have sent to the remote server if this request hadn't been intercepted.

    Original Client Request:

    @client-request@

    Processed Request:

    @processed-request@

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/forwarding-failed000640 001751 001751 00000011736 11630656133 021303 0ustar00fkfk000000 000000 ########################################################## # # Forwarding-failed template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written in plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # gateway # The IP or hostname of the forwarding server # hostport: # The host and port part of the request that lead to this problem # path: # The path part of the request that lead to this problem # error-message: # The failure reason. # forwarding-type: # The type of the forwarding request: "socks4-", "socks4a-" # or (in the future) "" for direct connections to the forwarder. # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # 503 - Forwarding failure (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    503 #include mod-title
    #include mod-unstable-warning

    Forwarding failure

    Privoxy was unable to @forwarding-type@forward your request @protocol@@hostport@@path@ through @gateway@: @error-message@

    Just try again to see if this is a temporary problem, or check your forwarding settings and make sure that all forwarding servers are working correctly and listening where they are supposed to be listening.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-list-url000640 001751 001751 00000004373 11630656133 022052 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-list-url,v $ # # Purpose : Template which forms part of edit-actions-list # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################# # # Available variables include: # # filename # ver # sectionid # urls # ############################################################################# # # ** Important note: ** # # It is *extremely* important to keep this file small. That's why all the # identifiers in the HTML are short and cryptic. Currently, the main # edit-actions page is ~300k. Before it was optimized, it was ~550k. # ############################################################################# Remove   Edit  @url-html@ privoxy-3.0.21-stable/./templates/no-such-domain000640 001751 001751 00000011030 11630656133 020523 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the proxy's administrator, as configured # in the 'config' file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # host: # The host part of the request that lead to this problem # hostport: # The host and port part of the request that lead to this problem # path: # The path part of the request that lead to this problem # proxy-info-url: # The URL to local online Privoxy documentation, if define in the # 'config' file # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # 404 - No such Domain (Privoxy@@my-hostname@) # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    404 #include mod-title
    #include mod-unstable-warning

    No such domain

    Your request for @protocol@@hostport@@path@ could not be fulfilled, because the domain name @host@ could not be resolved.

    This is often a temporary failure, so you might just try again.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/mod-support-and-service000640 001751 001751 00000004731 11630656133 022403 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/mod-support-and-service,v $ # # Purpose : Template that is included from most of Privoxy's CGI pages # to show the user how to get help or report problems. # # # Copyright : Written by and Copyright (C) 2002-2009 members of # the Privoxy team. http://www.privoxy.org/ # # This template is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # ##############################################################################

    Support and Service:

    The Privoxy Team values your feedback. To provide you with the best support, we ask that you:

    If you want to support the Privoxy Team, please have a look at the FAQ to learn how to participate or to donate.

    privoxy-3.0.21-stable/./templates/show-status000640 001751 001751 00000036321 12100754725 020214 0ustar00fkfk000000 000000 ########################################################## # # Show-Status-CGI Output template for Privoxy. # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach Privoxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the Privoxy administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of Privoxy # menu: # List of
  • elements linking to the other available CGIs # version: # The Privoxy version number # code-status: # The Privoxy development status: "alpha", "beta", or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # redirect-url: # The URL to a script that will redirect to the Privoxy # documentation for a given item # invocation: # The command line with which Privoxy was invoked # options: # The options read from the configfile, linked to their # explanations, plus warnings if parsing acl or forward # statements produced errors. # sourceversions: # A HTML-formatted list of the individual source file cvs versions # defines: # A HTML-formatted list of all conditional #defines used when # Privoxy was compiled # # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # This is an alpha or beta Privoxy release # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for Privoxy's online documentation has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # statistics: # Privoxy was compiled with statistics support # have-stats: # There have been previous requests and statistics have # been collected. In this case, the following symbols # are available: # requests-received: # The number of requests received so far # requests-blocked: # The number of request blocked so far # percent-blocked: # The percentage of blocked requests # have-no-stats: # There haven't any statistics been collected yet # pcrs-support: # Privoxy was compiled with pcrs support # trust-support: # Privoxy was compiled with trust support # actions-filenames: # The path to the actions files. # re-filter-filenames: # The path to the re_filter files. Only available if # pcrs-support is set # trust-filename: # The path to the trust file. Only available if # trust-support is set Privoxy@@my-hostname@: Proxy Status # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    The following files are in use:

    @actions-filenames@ @re-filter-filenames@
    Actions Files:
    Filter Files:
    Trust File:
    @trust-filename@ View

    The CGI editor is currently disabled, thus no edit buttons are shown.
    Please have a look at the enable-edit-actions documentation to learn how to enable it and what the risks are.

    Privoxy was invoked as follows:

    @invocation@

    The following options were given in the config file:

    @options@

    Blocking Statistics:

    @requests-blocked@ out of @requests-received@ requests have been blocked, which equals a block rate of @percent-blocked@%.

    Note that the statistics currently don't work properly for reused connections where only the last request gets counted. You may want to look into Privoxy-Log-Parser's --statistics option, which doesn't have this limitation. There haven't been any requests so far.

    Conditional #defines:

    #define Enabled? Effects when enabled
    FEATURE_ACCEPT_FILTER @if-FEATURE_ACCEPT_FILTER-then@ Yes @else-not-FEATURE_ACCEPT_FILTER@ No @endif-FEATURE_ACCEPT_FILTER@ Support for FreeBSD's accf_http(9) which is also available on some other BSDs.
    FEATURE_ACL @if-FEATURE_ACL-then@ Yes @else-not-FEATURE_ACL@ No @endif-FEATURE_ACL@ Allows the use of an ACL to control access to Privoxy by IP address.
    FEATURE_CGI_EDIT_ACTIONS @if-FEATURE_CGI_EDIT_ACTIONS-then@ Yes @else-not-FEATURE_CGI_EDIT_ACTIONS@ No @endif-FEATURE_CGI_EDIT_ACTIONS@ Allows the use of the @if-FEATURE_CGI_EDIT_ACTIONS-then@@else-not-FEATURE_CGI_EDIT_ACTIONS@ @endif-FEATURE_CGI_EDIT_ACTIONS@web-based actions file editor@if-FEATURE_CGI_EDIT_ACTIONS-then@@else-not-FEATURE_CGI_EDIT_ACTIONS@@endif-FEATURE_CGI_EDIT_ACTIONS@.
    FEATURE_COMPRESSION @if-FEATURE_COMPRESSION-then@ Yes @else-not-FEATURE_COMPRESSION@ No @endif-FEATURE_COMPRESSION@ Allows to compress buffered content before sending it to the client, assuming the client supports it.
    FEATURE_CONNECTION_KEEP_ALIVE @if-FEATURE_CONNECTION_KEEP_ALIVE-then@ Yes @else-not-FEATURE_CONNECTION_KEEP_ALIVE@ No @endif-FEATURE_CONNECTION_KEEP_ALIVE@ Allows to send multiple request through the same connections if the server supports it. Requires the keep-alive-timeout config directive to be set.
    FEATURE_CONNECTION_SHARING @if-FEATURE_CONNECTION_SHARING-then@ Yes @else-not-FEATURE_CONNECTION_SHARING@ No @endif-FEATURE_CONNECTION_SHARING@ Allows to share outgoing connections between incoming connections. Requires the connection-sharing config directive to be set.
    FEATURE_FAST_REDIRECTS @if-FEATURE_FAST_REDIRECTS-then@ Yes @else-not-FEATURE_FAST_REDIRECTS@ No @endif-FEATURE_FAST_REDIRECTS@ Allows the +fast-redirects action, to bypass redirect and logging scripts.
    FEATURE_FORCE_LOAD @if-FEATURE_FORCE_LOAD-then@ Yes @else-not-FEATURE_FORCE_LOAD@ No @endif-FEATURE_FORCE_LOAD@ Allows bypassing all filtering for a single page using the prefix @FORCE_PREFIX@.
    FEATURE_GRACEFUL_TERMINATION @if-FEATURE_GRACEFUL_TERMINATION-then@ Yes @else-not-FEATURE_GRACEFUL_TERMINATION@ No @endif-FEATURE_GRACEFUL_TERMINATION@ Allows to shutdown Privoxy through the web interface.
    FEATURE_IMAGE_BLOCKING @if-FEATURE_IMAGE_BLOCKING-then@ Yes @else-not-FEATURE_IMAGE_BLOCKING@ No @endif-FEATURE_IMAGE_BLOCKING@ Allows the +handle-as-image action, to send blocked images instead of HTML.
    FEATURE_IPV6_SUPPORT @if-FEATURE_IPV6_SUPPORT-then@ Yes @else-not-FEATURE_IPV6_SUPPORT@ No @endif-FEATURE_IPV6_SUPPORT@ Allows IPv6 addresses in incoming requests, when resolving domains to IP addresses and in the configuration files.
    FEATURE_IMAGE_DETECT_MSIE @if-FEATURE_IMAGE_DETECT_MSIE-then@ Yes @else-not-FEATURE_IMAGE_DETECT_MSIE@ No @endif-FEATURE_IMAGE_DETECT_MSIE@ Enables automatic detection of image and HTML requests from Microsoft Internet Explorer users, overriding the setting of +image in the actions file.
    FEATURE_NO_GIFS @if-FEATURE_NO_GIFS-then@ Yes @else-not-FEATURE_NO_GIFS@ No @endif-FEATURE_NO_GIFS@ Use PNG instead of GIF for the built-in images.
    FEATURE_PTHREAD @if-FEATURE_PTHREAD-then@ Yes @else-not-FEATURE_PTHREAD@ No @endif-FEATURE_PTHREAD@ Use POSIX threads rather than native threads
    FEATURE_STATISTICS @if-FEATURE_STATISTICS-then@ Yes @else-not-FEATURE_STATISTICS@ No @endif-FEATURE_STATISTICS@ Enables the statistics function.
    FEATURE_STRPTIME_SANITY_CHECKS @if-FEATURE_STRPTIME_SANITY_CHECKS-then@ Yes @else-not-FEATURE_STRPTIME_SANITY_CHECKS@ No @endif-FEATURE_STRPTIME_SANITY_CHECKS@ Try to work around broken strptime() implementations.
    FEATURE_TOGGLE @if-FEATURE_TOGGLE-then@ Yes @else-not-FEATURE_TOGGLE@ No @endif-FEATURE_TOGGLE@ Allow Privoxy to be disabled so it is just a normal non-blocking non-anonymizing proxy.
    FEATURE_TRUST @if-FEATURE_TRUST-then@ Yes @else-not-FEATURE_TRUST@ No @endif-FEATURE_TRUST@ Allows the use of trust files.
    FEATURE_ZLIB @if-FEATURE_ZLIB-then@ Yes @else-not-FEATURE_ZLIB@ No @endif-FEATURE_ZLIB@ Allows to decompress gzip and zlib compressed documents for filtering. Requires external zlib library and hasn't been tested on all platforms.
    STATIC_PCRE @if-STATIC_PCRE-then@ Yes @else-not-STATIC_PCRE@ No @endif-STATIC_PCRE@ Use the supplied statically-linked PCRE library. This is set automatically by ./configure if you do not have the libpcre installed. Dynamically linking to an external libpcre is recommended as the internal one is outdated and lacks various features and bug-fixes you may be interested in.
    STATIC_PCRS @if-STATIC_PCRS-then@ Yes @else-not-STATIC_PCRS@ No @endif-STATIC_PCRS@ Use the supplied statically-linked PCRS library. This is set automatically by ./configure if you do not have the libpcrs installed.

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/toggle-mini000640 001751 001751 00000006755 11630656134 020140 0ustar00fkfk000000 000000 ########################################################## # # Toggle Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@ # @if-enabled-display-then@Enabled@else-not-enabled-display@Disabled@endif-enabled-display@ - Privoxy@@my-hostname@

    Privoxy is @if-enabled-display-then@enabled@else-not-enabled-display@disabled@endif-enabled-display@.
    @if-enabled-display-then@[Disable]@else-not-enabled-display@[Enable]@endif-enabled-display@ | [Close]

    privoxy-3.0.21-stable/./templates/url-info-osd.xml000640 001751 001751 00000001271 11016570657 021031 0ustar00fkfk000000 000000 Privoxy URL Info Enter a URL to see which Privoxy actions apply. Only works while the browser is configured to use Privoxy. ISO-8859-1 ISO-8859-1 Privoxy Team ijbswa-developers@lists.sourceforge.net @default-cgi@favicon.ico privoxy-3.0.21-stable/./templates/show-url-info000640 001751 001751 00000022467 11731363577 020444 0ustar00fkfk000000 000000 ######################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/show-url-info,v $ # # Purpose : Template for Privoxy's show-url-info CGI page. # # Copyright : Written by and Copyright (C) 2001-2007 the SourceForge # Privoxy team. http://www.privoxy.org/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ######################################################################### # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach Privoxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the Privoxy administrator, as configured # in the config file # default-cgi: # The URL for Privoxy's "main menu" builtin CGI page # menu: # List of
  • elements linking to the other available CGIs # version: # Privoxy's version number # code-status: # Privoxy's development status: "alpha", "beta", or "stable". # homepage: # The Privoxy web site. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # url-given: # The CGI was called with a url parameter. In that case, the # following symbols are available: # url: # The given URL # default: # The system default for actions # matches: # The list of all matches in the actions file that this URL # produced, along with the actions that were triggered by # these matches # final: # The actions that are associated with the URL at the end of # the matching process # no-forwarder: Requests to url will be made directly. # http-forwarder: # Requests to url will be made through a HTTP proxy # forward-host: # The IP address or its hostname # forward-port. # The proxy port # socks-forwarder: # Requests to url will be made through a socks proxy # socks-type: # The socks type: socks4 or socks4a # gateway-host: # The IP address or its hostname # gateway-port: # The proxy port. # Privoxy@@my-hostname@ URL Info # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Forwarding settings:

    Requests for @url@ will be made directly, no forwarding settings apply first forwarded through @socks-type@-proxy @gateway-host@:@gateway-port@ and then forwarded through HTTP-proxy @forward-host@:@forward-port@.

    NOTE:

    This is a HTTPS URL, so the part after the "/" is ignored as Privoxy doesn't see the path for real HTTPS requests either.

    Matches for @url@:

    @matches@

    The CGI editor is currently disabled, thus no edit buttons are shown.
    Please have a look at the enable-edit-actions documentation to learn how to enable it and what the risks are.

    Warning:

    This Privoxy version has been built without zlib support, content filters will not work if the server sends compressed content. Consider enabling the prevent-compression action for this URL or rebuild Privoxy with zlib support.

    Final results:

    @final@

    Warning:

    Privoxy is currently toggled off. Matching actions will not apply unless you toggle Privoxy on first.

    Look up the actions for a new URL:

    More Privoxy:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/cgi-error-bad-param000640 001751 001751 00000011367 11630656133 021432 0ustar00fkfk000000 000000 ########################################################## # # No-Such-Domain Error Output template for Privoxy. # # # USING HTML TEMPLATES: # --------------------- # # Template files are written win plain HTML, with a few # additions: # # - Lines that start with a '#' character like this one # are ignored # # - Each item in the below list of exported symbols will # be replaced by dynamically generated text, if they # are enclosed in '@'-characters. E.g. The string @version@ # will be replaced by the version number of Privoxy. # # - One special application of this is to make whole blocks # of the HTML template disappear if the condition # is not given. Simply enclose the block between the two # strings @if-start and if--end@. The strings # should be placed in HTML comments (), so the # html structure won't be messed when the magic happens. # # USABLE SYMBOLS IN THIS TEMPLATE: # -------------------------------- # # my-ip-addr: # The IP-address that the client used to reach this proxy # my-hostname: # The hostname associated with my-ip-addr # admin-address: # The email address of the pxoxy's administrator, as configured # in the config file # default-cgi: # The URL for the "main menu" builtin CGI of this proxy # menu: # List of
  • elements linking to the other available CGIs # version: # The version number of the proxy software # code-status: # The development status of the proxy software: "alpha", "beta", # or "stable". # homepage: # The URL of the SourceForge ijbswa project, who maintains this # software. # # CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS: # ------------------------------------------------------------------ # # unstable: # this is an alpha or beta release of the proxy software # have-adminaddr-info: # An e-mail address for the local Privoxy adminstrator has # been specified and is available through the "admin-address" # symbol # have-proxy-info: # A URL for online documentation about this proxy has been # specified and is available through the "proxy-info-url" # symbol # have-help-info: # If either have-proxy-info is true or have-adminaddr-info is # true, have-help-info is true. Used to conditionally include # a grey box for any and all help info. # Privoxy: Bad parameter # This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
    #include mod-title
    #include mod-unstable-warning

    Bad parameter to Privoxy configuration page

    You've found a page used to configure Privoxy, but the parameters (the part of the web page address after the "?" mark) are wrong or missing.

    Possible causes:

    • If you just typed a URL pattern into a form, then you got something wrong. Press the "back" button on your browser once and correct what you typed.
    • If you tried to type in the URL, then you've found a page where you can't do that. You can only view this page by following links from elsewhere in the configuration interface.
    • If you got here using your browser's "back" button, then that is deliberately disabled for this page.
    • If you got here by clicking a link in the configuration interface, please file a bug report!

    You can use the menu below to select from the available configuration options

    Privoxy Menu:

    #include mod-support-and-service
    #include mod-local-help
    privoxy-3.0.21-stable/./templates/edit-actions-list-button000640 001751 001751 00000003157 11630656133 022562 0ustar00fkfk000000 000000 ############################################################################## # # File : $Source: /cvsroot/ijbswa/current/templates/edit-actions-list-button,v $ # # Purpose : Template which forms part of edit-actions-list # # # Copyright : Written by and Copyright (C) 2001 the SourceForge # Privoxy team. http://www.privoxy.org/ # # Original Author: Copyright (C) 2001 Jonathan Foster # http://www.jon-foster.co.uk/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #############################################################################   Set to @button-name@ privoxy-3.0.21-stable/./GNUmakefile.in000640 001751 001751 00000134122 12104210533 016433 0ustar00fkfk000000 000000 # Note: Makefile is built automatically from Makefile.in # # $Id: GNUmakefile.in,v 1.221 2013/02/05 14:04:11 fabiankeil Exp $ # # Written by and Copyright (C) 2001-2013 members of the # Privoxy team. http://www.privoxy.org/ # # Based on the Internet Junkbuster originally written # by and Copyright (C) 1997 Anonymous Coders and # Junkbusters Corporation. http://www.junkbusters.com # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################# # Set make command correctly ############################################################################# @SET_MAKE@ ############################################################################# # Version number (for RPM) ############################################################################# VERSION_MAJOR = @VERSION_MAJOR@ VERSION_MINOR = @VERSION_MINOR@ VERSION_POINT = @VERSION_POINT@ CODE_STATUS = @CODE_STATUS@ VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_POINT) SNAPVERSION = $(VERSION)-$(shell date "+%Y%m%d") ############################################################################# # "make install" directories and variables ############################################################################# #User Group paras USER = @USER@ GROUP = @GROUP@ datarootdir = @datarootdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ CONF_BASE = @sysconfdir@ SBIN_DEST = @sbindir@ MAN_DIR = @mandir@ MAN_DEST = $(MAN_DIR)/man1 MAN_PAGE = privoxy.1 SHARE_DEST = @datadir@ DOC_DEST = $(SHARE_DEST)/doc/privoxy VAR_DEST = @localstatedir@ LOGS_DEST = $(VAR_DEST)/log/privoxy PIDS_DEST = $(VAR_DEST)/run # if $prefix = /usr/local then the default CONFDEST change from # CONF_DEST = $(CONF_BASE) to CONF_DEST = $(CONF_BASE)/privoxy # by the target rule CONF_DEST # # also if the $prefix is /usr/local and there is no # $(SHARE_DEST)/doc, it checks for $prefix/doc and installs there # instead in this situation # # finally if $prefix=/usr/local and VAR_DEST=$prefix/var it # changes this to /var for storing the logs and pidfile # used in source dir only, the install goes to $share_dest/doc/privoxy DOK_WEB = doc/webserver/ # Install usage should be compatible with install-sh. INSTALL = @INSTALL@ # Binaries BIN_MODE = 0755 # Support files, docs, etc. RA_MODE = 0644 # Directory DIR_MODE = 0755 # Files daemon writes to. RWD_MODE = 0660 INSTALL_P = -m $(BIN_MODE) INSTALL_T = -m $(RA_MODE) INSTALL_D = -m $(DIR_MODE) -d INSTALL_R = -m $(RWD_MODE) # install options for superuser install #INSTALL_S = -g @GROUP@ -o @USER@ ############################################################################# # Build tools ############################################################################# PROGRAM = privoxy@EXEEXT@ CC = @CC@ ECHO = echo GZIP_PROG = gzip # id -u is not universal. FIXME: need to set from configure. Breaks on # Solaris. #ID = id -u ID = id LD = @CC@ RM = rm -f CP = cp -f RMDIR = rmdir MKDIR = ./mkinstalldirs STRIP_PROG = strip SED = sed GREP = grep CAT = cat MV = mv TAR = tar LN = ln TOUCH = touch KILL = kill CHMOD = chmod CHOWN = chown CHGRP = chgrp GROUPS = groups W3M_DUMP = env -u LANG LC_ALL=C @W3M@ -dump W3M_DUMP_UTF8 = @W3M@ -dump JADECAT = @JADECAT@ JADEBIN = @JADEBIN@ DB = $(JADEBIN) $(JADECAT) -ihtml -t sgml -D.. -d ldp.dsl\#html DB2HTML = @DB2HTML@ MAN2HTML = @MAN2HTML@ G2H_CMD = groff -mandoc -Thtml TARGET_OS = @host@ PERL = perl DOC_DIR = doc/source DOC_TMP = $(DOC_DIR)/tmp DOC_STATUS = @DOC_STATUS@ TIDY = tidy -modify -indent -wrap 78 --tidy-mark no # Program to do LF->CRLF # # The sed version should be the most portable, but it doesn't for for me, # the other two do. FIXME. # - Jon #DOSFILTER = $(SED) -e $$'s,$$,\r,' #DOSFILTER = gawk -v ORS='\r\n' '{print $0;}' DOSFILTER = $(PERL) -p -e 's/\n/\r\n/' CVSROOT = :pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa #TMPDIR := $(shell mktemp -d /tmp/$(PROGRAM).XXXXXX) # If your SF user name differs from your local one, # change this to "ssh -l sf-username" SSH = ssh WWW_ROOT = /home/project-web/ijbswa ############################################################################# # Setup for make distribution for now. ############################################################################# TAR_ARCH = /tmp/privoxy-$(VERSION).tar.gz ############################################################################# # We include these files in our distributions ############################################################################# CONFIGS = config trust default.action match-all.action user.action default.filter user.filter # take care that no CVS .cvsignore or other crappy files # are included here # and escape every '#' in the find. doh. CONFIG_FILES = $(CONFIGS) \ `find templates/ -type f | grep -v "CVS" | grep -v "\.\#" | grep -v ".*~" | grep -v ".cvsignore" | grep -v "TAGS"` DOC_FILES = AUTHORS LICENSE README ChangeLog INSTALL \ `find doc/webserver/ -name "*.html" | grep -v "\(webserver\|team\)\/index\.html"` \ `find doc/webserver/ -name "*.css"` \ $(MAN_PAGE) ############################################################################# # Filenames and libraries ############################################################################# C_SRC = actions.c cgi.c cgiedit.c cgisimple.c deanimate.c encode.c \ errlog.c filters.c gateway.c jbsockets.c jcc.c \ list.c loadcfg.c loaders.c miscutil.c parsers.c ssplit.c \ urlmatch.c C_OBJS = $(C_SRC:.c=.@OBJEXT@) C_HDRS = $(C_SRC:.c=.h) project.h actionlist.h W32_SRC = @WIN_ONLY@w32log.c w32taskbar.c win32.c w32svrapi.c W32_FILES = @WIN_ONLY@w32.res W32_OBJS = @WIN_ONLY@$(W32_SRC:.c=.@OBJEXT@) $(W32_FILES) W32_HDRS = @WIN_ONLY@w32log.h w32taskbar.h win32.h w32res.h w32svrapi.h W32_LIB = @WIN_ONLY@-lwsock32 -lcomctl32 W32_INIS = @WIN_ONLY@config.txt trust.txt PCRS_SRC = @STATIC_PCRS_ONLY@pcrs.c PCRS_OBJS = @STATIC_PCRS_ONLY@$(PCRS_SRC:.c=.@OBJEXT@) PCRS_HDRS = @STATIC_PCRS_ONLY@$(PCRS_SRC:.c=.h) PCRE_SRC = @STATIC_PCRE_ONLY@pcre/get.c pcre/maketables.c pcre/study.c pcre/pcre.c PCRE_OBJS = @STATIC_PCRE_ONLY@$(PCRE_SRC:.c=.@OBJEXT@) PCRE_HDRS = @STATIC_PCRE_ONLY@pcre/config.h pcre/chartables.c pcre/internal.h pcre/pcre.h # No REGEX (maybe because dynamically linked pcreposix): REGEX_SRC = @STATIC_PCRE_ONLY@REGEX_SRC = pcre/pcreposix.c REGEX_OBJS = $(REGEX_SRC:.c=.@OBJEXT@) REGEX_HDRS = $(REGEX_SRC:.c=.h) # Dependencies introduced by #include "project.h". PROJECT_H_DEPS = project.h $(REGEX_HDRS) $(PCRS_HDRS) @STATIC_PCRE_ONLY@pcre/pcre.h # Socket libraries for platforms that need them explicitly defined SOCKET_LIB = @SOCKET_LIB@ # PThreads library, if needed. PTHREAD_LIB = @PTHREAD_ONLY@@PTHREAD_LIB@ SRCS = $(C_SRC) $(W32_SRC) $(PCRS_SRC) $(PCRE_SRC) $(REGEX_SRC) OBJS = $(C_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(PCRE_OBJS) $(REGEX_OBJS) HDRS = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(PCRE_OBJS) $(REGEX_HDRS) LIBS = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB) ############################################################################# # Compiler switches ############################################################################# # The flag "-mno-win32" can be used by Cygwin to emulate a un?x type build. # The flag "-mwindows -mno-cygwin" will cause Cygwin to use MingW32 for a # Win32 GUI build. # The flag "-pthread" is required if using Pthreads under Linux (and # possibly other OSs). SPECIAL_CFLAGS = @SPECIAL_CFLAGS@ # Add your flags here OTHER_CFLAGS = CFLAGS = @CFLAGS@ @CPPFLAGS@ $(OTHER_CFLAGS) $(SPECIAL_CFLAGS) -Wall \ @STATIC_PCRE_ONLY@ -Ipcre LDFLAGS = @LDFLAGS@ $(DEBUG_CFLAGS) $(SPECIAL_CFLAGS) ############################################################################# # Build section. # # There should NOT be any targets above this line. ############################################################################# all: $(PROGRAM) default.action ############################################################################# # Phony targets ############################################################################# .PHONY: all inifiles solaris-dist \ win-dist tarball-dist dok webserver clean clobber tags \ install CONF_DEST LOG_DEST \ PID_DEST check_doc install-strip uninstall GROUP_T ############################################################################# # Define this explicitly because Solaris is broken! ############################################################################# %.o: %.c $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ ############################################################################# # Strip master copy comments from default.action: ############################################################################# default.action: default.action.master $(GREP) -v '^#MASTER#' default.action.master > $@ ############################################################################# # Win32 config files ############################################################################# inifiles: $(W32_INIS) config.txt: config $(SED) -e 's!\trustfile trust!trustfile trust.txt!' \ -e 's!\logfile logfile!logfile privoxy.log!' \ -e 's!#Win32-only: !!' \ < $< | \ $(DOSFILTER) > $@ # LF to CRLF in default.action $(DOSFILTER) default.action.txt && mv default.action.txt default.action # LF to CRLF in default.filter $(DOSFILTER) default.filter.txt && mv default.filter.txt default.filter trust.txt: trust $(DOSFILTER) < $< > $@ ############################################################################# # Pre-dist check: ############################################################################# dist-check: @if [ -d CVS ]; then \ $(ECHO) "***************************************************"; \ $(ECHO) "*** ***"; \ $(ECHO) "*** WARNING ***"; \ $(ECHO) "*** ***"; \ $(ECHO) "*** The presence of a CVS subdirectory suggests ***"; \ $(ECHO) "*** that you are trying to build a distribution ***"; \ $(ECHO) "*** package based on a checked out, not an ***"; \ $(ECHO) "*** exported copy of the source tree. Please ***"; \ $(ECHO) "*** see \"Releasing a new version\" in the ***"; \ $(ECHO) "*** developer manual. ***"; \ $(ECHO) "*** ***"; \ $(ECHO) "***************************************************"; \ $(ECHO) "Type \"yes i am sure\" if you are sure that you"; \ $(ECHO) -n "really want to proceed: "; \ read answer; \ if [ "$$answer" != "yes i am sure" ]; then exit 1; fi \ fi; ############################################################################# # create tar.gz from CVS: # This make-target is usually called through 'create-archive'. If you # run 'make create-snapshot' without setting SNAPVERSION, you'll get a # tar.gz with the current date in the name and as a releasenumber in the # spec-file. But the main usage is to run it as follows (Red Hat example): # make SNAPVERSION=1.6x create-snapshot # This creates a tar.gz. ############################################################################# create-snapshot: @tag=`cvs -d $(CVSROOT) status Makefile | awk ' /Sticky Tag/ { print $$3 } '` 2> /dev/null; \ [ x"$$tag" = x"(none)" ] && tag=HEAD; \ echo "*** Creating package from $$tag!"; \ TMPDIR=$(shell mktemp -d /tmp/$(PROGRAM).XXXXXX); \ cd $$TMPDIR ; cvs -Q -d $(CVSROOT) export -r $$tag current || echo "Um... export aborted."; \ cd $$TMPDIR/current; \ $(TAR) --exclude ".cvsignore" --exclude "CVS" \ -czf /tmp/$(PROGRAM)-$(VERSION).tar.gz .; \ $(RM) -rf $$TMPDIR @echo "Resulting file is /tmp/$(PROGRAM)-$(VERSION).tar.gz" ############################################################################# # looks at the version of Makefile and exports a corresponding source-tree # example: if the Makefile has the sticky tag v_2_9_13, you'll get # privoxy-*-2.4.13.tar.gz. ############################################################################# create-archive: make SNAPVERSION=$(SNAPVERSION) create-snapshot ############################################################################# # generic distribution ############################################################################# gen-dist: dist-check @$(ECHO) "" @$(ECHO) "You have run autoconf && autoheader && ./configure right?" @$(ECHO) "" $(MAKE) $(PROGRAM) $(STRIP_PROG) $(PROGRAM) $(LN) -s current ../privoxy-$(VERSION)-$(CODE_STATUS) # add program (cd .. && $(TAR) -cvhf --exclude "PACKAGERS" privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar privoxy-$(VERSION)-$(CODE_STATUS)/$(PROGRAM)) # add config files for foo in $(CONFIG_FILES); do \ (cd .. && $(TAR) -uvhf --exclude "PACKAGERS" privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar privoxy-$(VERSION)-$(CODE_STATUS)/$$foo;) \ done; # add documentation for foo in $(DOC_FILES); do \ (cd .. && $(TAR) -uvhf --exclude "PACKAGERS" privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar privoxy-$(VERSION)-$(CODE_STATUS)/$$foo;) \ done; # and zip the archive $(RM) ../privoxy-$(VERSION)-$(CODE_STATUS) $(GZIP_PROG) ../privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar @$(ECHO) Distribution with binary created. # anonymously ncftps the package to sourceforge gen-upload: ncftpput -u anonymous -p ijbswa-developers@lists.sourceforge.net upload.sourceforge.net /incoming ../privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar.gz @$(ECHO) ------------------------------------------------------- @$(ECHO) Now goto @$(ECHO) https://sourceforge.net/project/admin/editpackages.php?group_id=11118 @$(ECHO) ... and release the files. @$(ECHO) ------------------------------------------------------- # use with care gen-clean: $(RM) privoxy-$(TARGET_OS)-$(VERSION)-$(CODE_STATUS)-src.tar* ############################################################################# # Tarball distribution: No CVS dirs, dotfiles, debian build dir, # (FIXME:) only parts of the static / generated docs mix in doc/webserver ############################################################################# tarball-dist: dist-check clean clobber $(LN) -s current ../privoxy-$(VERSION)-$(CODE_STATUS) for i in `find . -type f -a -not \( -path "*/CVS*" -o -name ".*" \ -o -path "*/debian/*" -o -path "*/actions/*" -o -name "*.php" -o \ -name "PACKAGERS" \)`; do \ files="$$files privoxy-$(VERSION)-$(CODE_STATUS)/$$i"; \ done && \ cd .. && $(TAR) -cvhf privoxy-$(VERSION)-$(CODE_STATUS)-src.tar $$files ; \ # and zip the archive $(RM) ../privoxy-$(VERSION)-$(CODE_STATUS) $(GZIP_PROG) ../privoxy-$(VERSION)-$(CODE_STATUS)-src.tar @$(ECHO) Tarball distribution created. # anonymously ncftps the tarball to sourceforge tarball-upload: ncftpput -u anonymous -p ijbswa-developers@lists.sourceforge.net upload.sourceforge.net /incoming ../privoxy-$(VERSION)-$(CODE_STATUS)-src.tar.gz @$(ECHO) ------------------------------------------------------- @$(ECHO) Now goto @$(ECHO) https://sourceforge.net/project/admin/editpackages.php?group_id=11118 @$(ECHO) ... and release the files. @$(ECHO) ------------------------------------------------------- tarball-clean: $(RM) ../privoxy-$(VERSION)-$(CODE_STATUS)-src.tar.gz ############################################################################# # # Documentation # # converts doc/source/*.sgml into html and man pages # ############################################################################# # developer manual dok-devel: $(RM) doc/webserver/developer-manual/*.html $(RM) -r doc/source/developer-manual mkdir -p doc/source/developer-manual cd doc/source/developer-manual && $(DB) ../developer-manual.sgml && cd .. && cp developer-manual/*.html ../webserver/developer-manual/ # user manual dok-user: $(RM) doc/webserver/user-manual/*.html $(RM) -r doc/source/user-manual/ mkdir -p doc/source/user-manual cd doc/source/user-manual && $(DB) -iuser-man ../user-manual.sgml && cd .. && cp user-manual/*.html ../webserver/user-manual/ # FIXME: temp fix so same stylesheet gets in more than one place so it works # for all doc set-ups, including the 'user manual' config option in local # system where it MUST be in same directory as html. $(PERL) -pi.bak -e 's/<\/head/\n\n<\/head/i' doc/webserver/user-manual/*html # faq dok-faq: $(RM) doc/webserver/faq/*.html $(RM) -r doc/source/faq mkdir -p doc/source/faq cd doc/source/faq && $(DB) ../faq.sgml && cd .. && cp faq/*.html ../webserver/faq/ # man page, one variation. Try to use the next target, just 'make man'. dok-man: $(RM) doc/man/* doc/webserver/man-page/*.html echo MAN2HTML is $(MAN2HTML) @if [ $(MAN2HTML) != "false" ]; then \ $(ECHO) "Privoxy Man page

    NAME

    " > doc/webserver/man-page/privoxy-man-page.html; \ man ./$(MAN_PAGE) | $(MAN2HTML) -bare >> doc/webserver/man-page/privoxy-man-page.html; \ $(ECHO) "" >> doc/webserver/man-page/privoxy-man-page.html; \ else \ $(MAKE) groff2html; \ fi; # Build man page from sgml. This requires the SGMLSpm perl module. # See CPAN, or your favorite perl repository. This is the preferred # target for man page generation! man: dok-release mkdir -p doc/source/temp && cd doc/source/temp && $(RM) * ;\ nsgmls ../privoxy-man-page.sgml | sgmlspl ../../../utils/docbook2man/docbook2man-spec.pl &&\ perl -pi.bak -e 's/ //; s/\[ /\[/g' $(MAN_PAGE) ;\ perl -pi.bak -e "s/\[ /\[/g;s/á/\\\\['a]/g;s/é/\\\\['e]/g" $(MAN_PAGE); \ perl -pi.bak -e "s/ö/\\\\[:o]/g" $(MAN_PAGE); \ perl -pi.bak -e 's/([ {])-([a-z])/$$1\\-$$2/g' $(MAN_PAGE); \ perl -pi.bak -e 's/ --([a-z])/ \\-\\-$$1/g' $(MAN_PAGE); \ perl -pi.bak -e 's/\\fB--/\\fB\\-\\-/g' $(MAN_PAGE); \ $(DB) ../privoxy-man-page.sgml && $(MV) -f $(MAN_PAGE) ../../../$(MAN_PAGE) # For those with man2html ala RH7s. man2html: mkdir -p doc/webserver/man-page @if [ $(MAN2HTML) != "false" ]; then \ $(MAN2HTML) $(MAN_PAGE) |grep -v "^Content-type" > tmp.html; \ $(PERL) -pi.bak -e 's///; s//man2html/' tmp.html; \ $(PERL) -pi.bak -e 's/(<\/HEAD>)/<\/HEAD>/' tmp.html; \ $(PERL) -pi.bak -e 's/()/$$1$$2/g' tmp.html; \ $(PERL) -pi.bak -e 's,\.">,">,g' tmp.html; \ $(PERL) -pi.bak -e "s/\['a\]/\á/g;s/\['e\]/\é/g" tmp.html; \ $(SED) -e 's///g' tmp.html > doc/webserver/man-page/privoxy-man-page.html && $(RM) tmp.*; \ else \ $(MAKE) groff2html; \ fi; # Otherwise we get plain groff conversion. groff2html: $(G2H_CMD) ./$(MAN_PAGE) | $(SED) -e 's@@@' > doc/webserver/man-page/privoxy-man-page.html # readme page and INSTALL file dok-readme: dok-release cd doc/source && $(DB)-notoc -V nochunks readme.sgml > tmp.html &&\ $(W3M_DUMP) tmp.html > ../../README ;\ $(DB)-notoc -V nochunks install.sgml > tmp.html &&\ $(W3M_DUMP) tmp.html > ../../INSTALL ;\ $(RM) tmp.* # index.sgml is used to create both the Home Page, and a local index # for documentation, etc. # # index.html for webserver: dok-webserver: cd doc/source/webserver && $(DB)-notoc -ip-homepage -V nochunks index.sgml > ../../webserver/index.html $(PERL) -pi.bak -e 's/..\/p_doc.css/p_doc.css/;\ s/<\/HEAD/\n<\/HEAD/;\ s/\.\d\. //;\ s/__copy/©/'\ doc/webserver/index.html && $(RM) doc/webserver/*.bak # privoxy-index.html for local documentation: dok-index: cd doc/source/webserver && $(DB)-notoc -ip-index -V nochunks index.sgml > ../../webserver/privoxy-index.html $(PERL) -pi.bak -e 's/..\/p_doc.css/p_doc.css/;\ s/<\/HEAD/\n<\/HEAD/;\ s/\.\d\. //;\ s/__copy/©/' \ doc/webserver/privoxy-index.html && $(RM) doc/webserver/*.bak # Main documentation target. dok: dok-release dok-devel dok-user dok-faq dok-readme dok-webserver dok-authors dok-index @$(ECHO) Documentation created. ## Make AUTHORS file dok-authors: cd doc/source && $(DB) -V nochunks authors.sgml > tmp.html && $(W3M_DUMP_UTF8) \ tmp.html > ../../AUTHORS && $(RM) tmp.html # Set doc entities for VERSION and CODE_STATUS in sgml docs. Toggle content # exceptions accordingly. This needs to go before any doc building (doh). dok-release: @$(ECHO) Setting doc version and status to $(VERSION), $(CODE_STATUS) @$(PERL) -pi.bak -e 's///;\ s///' \ doc/source/*sgml doc/source/*/*sgml $(RM) -r doc/source/*bak doc/source/*/*bak @if [ $(CODE_STATUS) = "stable" ]; then \ $(ECHO) Setting docs to stable $(VERSION); \ $(PERL) -pi.bak -e 's///;\ s///' \ doc/source/*sgml doc/source/*/*sgml; \ else \ $(ECHO) Setting docs to not stable $(VERSION); \ $(PERL) -pi.bak -e 's///; \ s///' \ doc/source/*sgml doc/source/*/*sgml; \ fi; $(RM) -r doc/source/*bak doc/source/*/*bak; # Create release announcement in text and html, with short and long versions. # This is a standalone target, and must be invoked directly. # announce: dok-release # mkdir -p $(DOC_TMP) # cd $(DOC_TMP) && cp -f ../announce.sgml . && $(DB) -iannounce-big announce.sgml &&\ # mv -f index.html announce.html && $(W3M_DUMP) announce.html > announce.txt # cd $(DOC_TMP) && $(DB) announce.sgml &&\ # mv -f index.html announce-mini.html && $(W3M_DUMP) announce-mini.html > announce-mini.txt &&\ # mv -f *html *txt ../../.. # rm -fr $(DOC_TMP) # The main Privoxy config file, generated from sgml sources. # NOTE: This will require some hand editing. config-file: dok-release generate-config-file $(RM) config.bak config.html @$(ECHO) "****************************************************" @$(ECHO) "The config file has been optimistically updated" @$(ECHO) "Now -- you may need to hand edit the results!" @$(ECHO) "In particular, check the Debug levels, the" @$(ECHO) "permit-access, forward & socks examples and the" @$(ECHO) "various user-manual examples, which all" @$(ECHO) "might have gotten hammered." @$(ECHO) "****************************************************" generate-config-file: cd doc/source && $(DB)-notoc -iconfig-file -V nochunks config.sgml > ../../config.html $(W3M_DUMP) -cols 67 config.html > config $(PERL) -i.bak utils/prepare-configfile.pl config # config file, alternate version using lynx (perl stuff unfinished). Lynx # does not do so good a job. config-file-alt: cd doc/source && $(ECHO) -e ".h2 JUSTIFY\\nJUSTIFY:FALSE" > __tmp.lynx_cfg &&\ $(DB)-notoc -iconfig-file -V nochunks config.sgml > __tmp.html &&\ lynx -cfg=__tmp.lynx_cfg -width=78 -dump __tmp.html > ../../config.new && $(RM) -r __tmp.* $(PERL) -pi -e 's/^( )//;\ s/:$\/:\n/' config.new ############################################################################# # # Webserver # # moves dokumentation to webserver # ############################################################################# webserver: clean-editor-files @$(ECHO) ------------------------------------------------------- @$(ECHO) You will need to "create" a SF shell first: @$(ECHO) ssh -t SF-USER-ID,ijbswa@shell.sourceforge.net create @$(ECHO) Please make sure your documentation files are up to date. @$(ECHO) Note that this command updates the home page and copys @$(ECHO) all stuff to the webserver, it will not remove obsolete documents. @$(ECHO) Note that a botched upload can result in the documentation @$(ECHO) on the website becoming unreachable! Also the CSS files @$(ECHO) currently seem to end up at the wrong place. @$(ECHO) ------------------------------------------------------- @$(ECHO) Replacing the user-manual symlink @$(SSH) shell.sourceforge.net "cd $(WWW_ROOT)/htdocs && rm user-manual \ && mkdir -p $(VERSION)/user-manual && ln -s $(VERSION)/user-manual user-manual" @$(ECHO) Uploading html @cd doc/webserver; \ upload=`find . -type f -a -not \( -path "*/CVS*" -o -path "*/results*" \)`; \ $(TAR) cf - $$upload | $(SSH) shell.sourceforge.net 'cd $(WWW_ROOT)/htdocs/; tar xvm 2>&1 | grep -v timestamp' @$(ECHO) Fixing permissions @$(SSH) shell.sourceforge.net 'chmod -R 775 $(WWW_ROOT)/htdocs 2>/dev/null; true' @$(SSH) shell.sourceforge.net 'find $(WWW_ROOT)/htdocs/ -type f | xargs chmod 664 2>/dev/null; true' web-actions: clean-editor-files @$(ECHO) Uploading @cd doc/webserver/actions; \ upload=`find . -type f -a -not \( -path "*/CVS*" -o -path "*/results*" \)`; \ $(TAR) cf - $$upload | $(SSH) ijbswa.sourceforge.net 'cd $(WWW_ROOT)/htdocs/actions; tar xvm' @$(ECHO) Fixing permissions @$(SSH) ijbswa.sourceforge.net 'find $(WWW_ROOT)/htdocs/actions/ -type f | xargs chmod 664 2>/dev/null' @$(SSH) ijbswa.sourceforge.net 'chmod 666 $(WWW_ROOT)/htdocs/actions/results/actions-feedback.txt 2>/dev/null' ## dok-put: tar --exclude ".cvsignore" --exclude "CVS" --exclude "source" --exclude ".htaccess" \ --exclude "obsolete" --exclude "actions" --exclude "*.zip" --exclude "robots.txt"\ doc/* INSTALL LICENSE AUTHORS README \ -czf $(DOC_FILE) ;\ $(ECHO) "Uploading doc package ..." ;\ scp $(DOC_FILE) ijbswa.sourceforge.net:$(WWW_ROOT)/htdocs/docs/ @$(SSH) ijbswa.sourceforge.net 'chmod 775 $(WWW_ROOT)/htdocs/docs/*gz 2>/dev/null; true' $(RM) $(DOC_FILE) dok-get: cd /tmp ;\ $(WGET) http://www.privoxy.org/docs/$(DOC_FILE) ;\ $(TAR) -zxvf $(DOC_FILE) ############################################################################# # # Try to clean up the generated HTML files. # # The files are a such a mess that some of them require two tidy runs # in row as the first abort prematurely. The vanilla tidy output renders # poorly as it contains a bit too much white-space, so we additionally run # the files through perl to fix this again. # ############################################################################# dok-tidy: for html_file in `find doc/webserver -name "*.html"`; do \ $(TIDY) $$html_file || $(TIDY) $$html_file; \ $(PERL) -i'' -e 's@^\s*
    \s*$$@@; s@ +$$@@;' -n -p $$html_file; \ done ############################################################################# # Source file dependencies ############################################################################# actions.@OBJEXT@: actions.c actions.h config.h $(PROJECT_H_DEPS) errlog.h jcc.h list.h loaders.h miscutil.h actionlist.h ssplit.h cgi.@OBJEXT@: cgi.c cgi.h config.h $(PROJECT_H_DEPS) cgiedit.h cgisimple.h jbsockets.h list.h pcrs.h encode.h ssplit.h jcc.h filters.h actions.h errlog.h miscutil.h cgiedit.@OBJEXT@: cgiedit.c cgiedit.h config.h $(PROJECT_H_DEPS) cgi.h list.h pcrs.h encode.h ssplit.h jcc.h filters.h actionlist.h actions.h errlog.h miscutil.h cgisimple.@OBJEXT@: cgisimple.c cgisimple.h config.h $(PROJECT_H_DEPS) cgi.h list.h pcrs.h encode.h ssplit.h jcc.h filters.h actions.h errlog.h miscutil.h urlmatch.h deanimate.@OBJEXT@: deanimate.c deanimate.h config.h $(PROJECT_H_DEPS) encode.@OBJEXT@: encode.c encode.h config.h errlog.@OBJEXT@: errlog.c errlog.h config.h $(PROJECT_H_DEPS) @WIN_ONLY@w32log.h filters.@OBJEXT@: filters.c filters.h config.h $(PROJECT_H_DEPS) errlog.h encode.h gateway.h jbsockets.h jcc.h loadcfg.h parsers.h ssplit.h cgi.h deanimate.h urlmatch.h @WIN_ONLY@win32.h gateway.@OBJEXT@: gateway.c gateway.h config.h $(PROJECT_H_DEPS) errlog.h jbsockets.h jcc.h loadcfg.h jbsockets.@OBJEXT@: jbsockets.c jbsockets.h config.h $(PROJECT_H_DEPS) filters.h jcc.@OBJEXT@: jcc.c jcc.h config.h $(PROJECT_H_DEPS) errlog.h filters.h gateway.h jbsockets.h loadcfg.h loaders.h miscutil.h parsers.h @WIN_ONLY@w32log.h win32.h w32svrapi.h cgi.h list.@OBJEXT@: list.c list.h config.h $(PROJECT_H_DEPS) list.h miscutil.h loadcfg.@OBJEXT@: loadcfg.c loadcfg.h config.h $(PROJECT_H_DEPS) errlog.h filters.h gateway.h jbsockets.h jcc.h loaders.h miscutil.h parsers.h @WIN_ONLY@w32log.h win32.h loaders.@OBJEXT@: loaders.c loaders.h config.h $(PROJECT_H_DEPS) errlog.h encode.h filters.h gateway.h jcc.h loadcfg.h miscutil.h parsers.h ssplit.h miscutil.@OBJEXT@: miscutil.c miscutil.h config.h parsers.@OBJEXT@: parsers.c parsers.h config.h $(PROJECT_H_DEPS) errlog.h filters.h jbsockets.h jcc.h loadcfg.h loaders.h miscutil.h ssplit.h ssplit.@OBJEXT@: ssplit.c ssplit.h config.h miscutil.h urlmatch.@OBJEXT@: urlmatch.c urlmatch.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h ssplit.h # GNU regex gnu_regex.@OBJEXT@: gnu_regex.c gnu_regex.h config.h # PCRS pcrs.@OBJEXT@: pcrs.c pcrs.h config.h @STATIC_PCRE_ONLY@pcre/pcre.h # PCRE pcre/get.@OBJEXT@: pcre/get.c pcre/config.h pcre/internal.h pcre/pcre.h pcre/maketables.@OBJEXT@: pcre/maketables.c pcre/config.h pcre/internal.h pcre/pcre.h pcre/pcre.@OBJEXT@: pcre/pcre.c pcre/config.h pcre/internal.h pcre/pcre.h pcre/chartables.c pcre/pcreposix.@OBJEXT@: pcre/pcreposix.c pcre/config.h pcre/internal.h pcre/pcre.h pcre/pcreposix.h pcre/study.@OBJEXT@: pcre/study.c pcre/config.h pcre/internal.h pcre/pcre.h # An auxiliary program makes the PCRE default character table source pcre/chartables.c: pcre/dftables@EXEEXT@ pcre/dftables@EXEEXT@ >pcre/chartables.c pcre/dftables@EXEEXT@: pcre/dftables.c pcre/maketables.c pcre/pcre.h pcre/internal.h pcre/config.h $(CC) -o pcre/dftables@EXEEXT@ $(CFLAGS) pcre/dftables.c # Win32 w32log.@OBJEXT@: w32log.c errlog.h config.h jcc.h loadcfg.h miscutil.h pcre/pcre.h pcre/pcreposix.h pcrs.h project.h w32log.h w32taskbar.h win32.h w32taskbar.@OBJEXT@: w32taskbar.c config.h w32log.h w32taskbar.h win32.@OBJEXT@: win32.c config.h jcc.h loadcfg.h pcre/pcre.h pcre/pcreposix.h pcrs.h project.h w32log.h win32.h w32svrapi.h w32.res: w32.rc w32res.h icons/radar-01.ico icons/radar-02.ico icons/radar-03.ico icons/radar-04.ico icons/radar-05.ico icons/radar-06.ico icons/radar-07.ico icons/radar-08.ico icons/idle.ico icons/privoxy.ico config.h windres -D__MINGW32__=0.2 -O coff -i $< -o $@ # AmigaOS @AMIGAOS_ONLY@OBJS += amiga.o @AMIGAOS_ONLY@ifeq ($(shell $(CC) -dumpmachine), m68k-amigaos) @AMIGAOS_ONLY@CFLAGS += -D__AMIGAVERSION__=\"$(VERSION_MAJOR).$(VERSION_MINOR)$(VERSION_POINT)\" -D__AMIGADATE__=\"`date +%d.%m.%Y`\" -W -m68020 -noixemul -fbaserel -msmall-code @AMIGAOS_ONLY@LDFLAGS += -m68020 -noixemul -fbaserel @AMIGAOS_ONLY@LIBS = -lm /gg/lib/libb/libm020/libnix/swapstack.o @AMIGAOS_ONLY@else @AMIGAOS_ONLY@CFLAGS += -D__AMIGAVERSION__=\"$(VERSION_MAJOR).$(VERSION_MINOR)$(VERSION_POINT)\" -D__AMIGADATE__=\"`date +%d.%m.%Y`\" -Wextra -D__USE_INLINE__ -D__NO_INTUITION_RJ_MACROS @AMIGAOS_ONLY@endif @AMIGAOS_ONLY@amiga.o: amiga.c amiga.h config.h $(PROGRAM): $(OBJS) $(W32_FILES) $(LD) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) clean: $(RM) a.out $(OBJS) $(W32_FILES) $(W32_INIS) $(PROGRAM) default.action \ config.base config.tmp \ `find . \( -name TAGS -o -name tags \) -and -not -path "./.git/refs/tags"` \ `find . -name "*.orig" -a -not -name rc.privoxy.orig` clean-editor-files: $(RM) `find . -name "*~"` $(RM) `find . -name "#*#"` # Emacs backup files $(RM) `find . -name ".\#*"` clobber: clean-editor-files $(RM) GNUmakefile configure config.h.in config.h config.cache config.status config.log logfile \ privoxy.log core *.tar.gz *.tar privoxy-cl.spec doc/source/ldp.dsl config.new $(RM) -r autom4te.cache # # FIXME: What is all this? # $(RM) cscope.* *.pdb *.lib *.exp distclean: clobber tags: $(SRCS) $(HDRS) etags $(SRCS) $(HDRS) CONF_DEST:=$(shell if [ "$(prefix)" = "/usr/local" ] && [ "$(CONF_BASE)" = "$(prefix)/etc" ];then \ $(ECHO) "$(CONF_BASE)/privoxy";\ else\ $(ECHO) "$(CONF_BASE)";\ fi) LOG_DEST:=$(shell if [ "$(prefix)" = "/usr/local" ] && [ "$(LOGS_DEST)" = "$(prefix)/var/log/privoxy" ];then \ $(ECHO) "/var/log/privoxy" ;\ else\ $(ECHO) "$(LOGS_DEST)";\ fi) PID_DEST:=$(shell if [ "$(prefix)" = "/usr/local" ] && [ "$(PIDS_DEST)" = "$(prefix)/var/run" ];then \ $(ECHO) "/var/run" ;\ else\ $(ECHO) "$(PIDS_DEST)";\ fi) check_doc:=$(shell if [ ! -d "$(SHARE_DEST)/doc" ] && [ "$(prefix)" = "/usr/local" ] && [ -d "$(prefix)/doc" ];then \ $(ECHO) "1";\ else\ $(ECHO) "0";\ fi) # If USER is specified but no GROUP, assume there is a GROUP of same name. GROUP_T:=$(shell if [ x$(GROUP) = x ] && [ x$(USER) != x ];then \ $(ECHO) "$(USER)" ;\ else\ $(ECHO) "$(GROUP)";\ fi) install-strip: $(MAKE) install STRIP=-s # FIXME: Test USER and GROUP on Slack to make sure this works as # intended. # # FIXME: id handling needs help, probably via configure, since 'id -u' is not # universally reliable (eg Solaris). Group handling could be better. # Perhaps the whole user/group validation should be done here, and simplified. PROGRAM_V = Privoxy $(VERSION) $(CODE_STATUS) install: CONF_DEST LOG_DEST PID_DEST check_doc GROUP_T @# Quick test for valid USER. @if [ -n "$(USER)" ]; then \ $(ID) $(USER) >/dev/null || exit 1;\ fi @# Test for valid group. FIXME. USER does not have to belong to GROUP @# for file ownership purposes. # if [ -n "$(GROUP_T)" ] && [ -n "$(USER)" ] && ! $(GROUPS) $(USER) | $(GREP) "\<$(GROUP_T)\>" >/dev/null; then \ # $(ECHO) Group $(GROUP_T) for User $(USER) is invalid && exit 1 ;\ # fi @$(ECHO) "Creating directories, and preparing $(PROGRAM_V) installation" $(CHMOD) $(DIR_MODE) $(MKDIR) @$(MKDIR) $(DESTDIR)$(SBIN_DEST) $(DESTDIR)$(prefix) $(DESTDIR)$(CONF_DEST) \ $(DESTDIR)$(CONF_DEST)/templates $(DESTDIR)$(SHARE_DEST) \ $(DESTDIR)$(LOG_DEST) $(DESTDIR)$(PID_DEST) @# Install the executable binary, strip if invoked as install-strip @test -n "$(STRIP)" &&\ $(ECHO) Installing $(PROGRAM) stripped executable to $(SBIN_DEST) ||\ $(ECHO) Installing $(PROGRAM) executable to $(DESTDIR)$(SBIN_DEST) $(INSTALL) $(INSTALL_P) $(STRIP) $(PROGRAM) $(DESTDIR)$(SBIN_DEST) @# Install the DOCS and man page. install-sh only does one file at a time. @# FIXME: only handles jpegs. -@if [ $(check_doc) = 0 ]; then \ DOC=$(DOC_DEST) ;\ else \ DOC=$(prefix)/doc/privoxy ;\ fi;\ $(MKDIR) $(DESTDIR)$$DOC $(DESTDIR)$$DOC/user-manual $(DESTDIR)$$DOC/faq $(DESTDIR)$$DOC/developer-manual \ $(DESTDIR)$$DOC/man-page $(DESTDIR)$$DOC/images $(DESTDIR)$(MAN_DEST) ;\ if [ -d "$(DOK_WEB)" ]; then \ $(ECHO) Installing FAQ, Manual, and other docs to $(DESTDIR)$$DOC;\ for i in user-manual developer-manual faq; do \ for ii in $(DOK_WEB)/$$i/*html; do \ $(INSTALL) $(INSTALL_T) $$ii $(DESTDIR)$$DOC/$$i;\ done ;\ done ;\ for i in $(DOK_WEB)/user-manual/*jpg; do \ $(INSTALL) $(INSTALL_T) $$i $(DESTDIR)$$DOC/user-manual;\ done ;\ $(INSTALL) $(INSTALL_T) $(DOK_WEB)/man-page/*html $(DESTDIR)$$DOC/man-page;\ $(INSTALL) $(INSTALL_T) $(DOK_WEB)/privoxy-index.html $(DESTDIR)$$DOC/index.html;\ $(INSTALL) $(INSTALL_T) AUTHORS $(DESTDIR)$$DOC;\ $(INSTALL) $(INSTALL_T) LICENSE $(DESTDIR)$$DOC;\ $(INSTALL) $(INSTALL_T) README $(DESTDIR)$$DOC;\ $(INSTALL) $(INSTALL_T) ChangeLog $(DESTDIR)$$DOC;\ $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $(DESTDIR)$$DOC;\ $(INSTALL) $(INSTALL_T) $(DOK_WEB)/p_doc.css $(DESTDIR)$$DOC/user-manual;\ fi @# Not all platforms support gzipped man pages. @$(ECHO) Installing man page to $(DESTDIR)$(MAN_DEST)/$(MAN_PAGE) -$(INSTALL) $(INSTALL_T) $(MAN_PAGE) $(DESTDIR)$(MAN_DEST)/$(MAN_PAGE) @# Change the config file default directories according to the configured ones @$(ECHO) Rewriting config for this installation @if [ -f config.base ] ; then \ $(CAT) config >config~ ;\ $(MV) config.base config ;\ fi $(SED) 's+^confdir \.+confdir $(CONF_DEST)+' config | \ $(SED) 's+^logdir \.+logdir $(LOG_DEST)+' >config.tmp -@if [ $(check_doc) = 0 ]; then \ $(SED) 's+^#\?user-manual .*+user-manual $(DOC_DEST)/user-manual/+' config.tmp >config.updated ;\ else \ $(SED) 's+^#\?user-manual .*+user-manual $(prefix)/doc/privoxy/user-manual/+' config.tmp >config.updated ;\ fi;\ $(MV) config config.base $(MV) config.updated config @# Install the config support files. Test for root install, and abort @# if there is no privoxy user, and no other user was enabled during @# configure. Later, install init script if appropriate. @$(ECHO) Installing templates to $(DESTDIR)$(CONF_DEST)/templates @for i in `find templates -type f`; do \ $(INSTALL) $(INSTALL_T) $$i $(DESTDIR)$(CONF_DEST)/templates ;\ done @# FIXME: group/user validation is overly convoluted. @# If superuser install ... we require a minimum of group ownership @# of those files the daemon writes to, to be non-root owned. @if [ "`$(ID) |sed 's/(.*//' |sed 's/.*=//'`" = "0" ] ;then\ if [ x$(USER) = x ] || [ $(USER) = root ]; then \ if [ x$(GROUP) = x ] || [ $(GROUP) = root ]; then \ if [ "`$(ID) privoxy`" ] && \ $(GROUPS) privoxy | $(SED) 's/^.*://' |$(GREP) "\" >/dev/null; then \ $(ECHO) "Warning: Setting group owner to privoxy";\ GROUP_T=privoxy ;\ else \ $(ECHO) "******************************************************************" ;\ $(ECHO) " WARNING! WARNING! installing config files as root!" ;\ $(ECHO) " It is strongly recommended to run $(PROGRAM) as a non-root user," ;\ $(ECHO) " and to install the config files as that user and/or group!" ;\ $(ECHO) " Please read INSTALL, and create a privoxy user and group!" ;\ $(ECHO) "*******************************************************************" ;\ exit 1 ;\ fi ;\ else \ GROUP_T=$(GROUP) ;\ fi ;\ INSTALL_CONF="$(INSTALL_R) -g $$GROUP_T " ;\ else \ $(ECHO) "Superuser install, installing config files as $(USER):$(GROUP_T)" ;\ INSTALL_CONF="$(INSTALL_R) -o $(USER) -g $(GROUP_T)" ;\ GROUP_T=$(GROUP_T) ;\ fi ;\ else \ if [ ! "`id $(USER)`" = "`id`" ] ;then \ $(ECHO) "** WARNING ** current install user different from configured user!!" ;\ $(ECHO) "Edit may fail." ;\ fi ;\ INSTALL_CONF="$(INSTALL_R)" ;\ fi ;\ $(ECHO) Installing configuration files to $(DESTDIR)$(CONF_DEST);\ for i in $(CONFIGS); do \ if [ "$$i" = "default.action" ] || [ "$$i" = "default.filter" ] ; then \ $(RM) $(DESTDIR)$(CONF_DEST)/$$i ;\ $(ECHO) Installing fresh $$i;\ $(INSTALL) $$INSTALL_CONF $$i $(DESTDIR)$(CONF_DEST) || exit 1;\ elif [ -s "$(CONF_DEST)/$$i" ]; then \ $(ECHO) Installing $$i as $$i.new ;\ $(INSTALL) $$INSTALL_CONF $$i $(DESTDIR)$(CONF_DEST)/$$i.new || exit 1;\ NEW=1;\ else \ $(INSTALL) $$INSTALL_CONF $$i $(DESTDIR)$(CONF_DEST) || exit 1;\ fi ;\ done ;\ if [ -n "$$NEW" ]; then \ $(CHMOD) $(RWD_MODE) $(DESTDIR)$(CONF_DEST)/*.new || exit 1 ;\ $(ECHO) "Warning: Older config files are preserved. Check new versions for changes!" ;\ fi ;\ [ ! -f $(DESTDIR)$(LOG_DEST)/logfile ] && $(ECHO) Creating logfiles in $(DESTDIR)$(LOG_DEST) || \ $(ECHO) Checking logfiles in $(DESTDIR)$(LOG_DEST) ;\ $(TOUCH) $(DESTDIR)$(LOG_DEST)/logfile || exit 1 ;\ if [ x$$USER != x ]; then \ $(CHOWN) $$USER $(DESTDIR)$(LOG_DEST)/logfile || \ $(ECHO) "** WARNING ** current install user different from configured user. Logging may fail!!" ;\ fi ;\ if [ x$$GROUP_T != x ]; then \ $(CHGRP) $$GROUP_T $(DESTDIR)$(LOG_DEST)/logfile || \ $(ECHO) "** WARNING ** current install user different from configured user. Logging may fail!!" ;\ fi ;\ $(CHMOD) $(RWD_MODE) $(DESTDIR)$(LOG_DEST)/logfile || exit 1 ;\ if [ "$(prefix)" = "/usr/local" ] || [ "$(prefix)" = "/usr" ]; then \ if [ -f /etc/slackware-version ] && [ -d /etc/rc.d/ ] && [ -w /etc/rc.d/ ] ; then \ $(SED) 's+%PROGRAM%+$(PROGRAM)+' slackware/rc.privoxy.orig | \ $(SED) 's+%SBIN_DEST%+$(SBIN_DEST)+' | \ $(SED) 's+%CONF_DEST%+$(CONF_DEST)+' | \ $(SED) 's+%USER%+$(USER)+' | \ $(SED) 's+%GROUP%+$(GROUP_T)+' >slackware/rc.privoxy ;\ $(INSTALL) $(INSTALL_P) slackware/rc.privoxy $(DESTDIR)/etc/rc.d/ ;\ $(ECHO) "Installing for Slackware." ;\ $(ECHO) "Dont forget to add the rc.privoxy to rc.local if you want it started at every boot" ;\ elif [ -d $(DESTDIR)/etc/init.d ] && [ -w $(DESTDIR)/etc/init.d ] ; then \ $(ECHO) "Installing generic init script to $(DESTDIR)/etc/init.d/privoxy" ;\ $(ECHO) "Please check that the PATHs are correct, and edit if needed." ;\ $(INSTALL) $(INSTALL_P) privoxy-generic.init $(DESTDIR)/etc/init.d/privoxy ;\ fi ;\ else \ $(ECHO) "No init script installed, install it manually if needed" ;\ fi $(RM) config.base config.tmp @# mmmmm, good. @$(ECHO) "$(PROGRAM_V) installation succeeded!" @$(ECHO) "The Privoxy configuration files have been installed in $(DESTDIR)$(CONF_DEST)" # rmdir is used as a precaution since it will not remove non-empty # directories. RH init script creates lock file and pid file. uninstall: CONF_DEST LOG_DEST PID_DEST check_doc @$(ECHO) Starting Privoxy uninstallation @# KILL privoxy if running @# XXX: the chkconfig line may need a DESTDIR prefix. -@test -f $(DESTDIR)$(PID_DEST)/privoxy.pid && $(ECHO) Stopping $(PROGRAM) &&\ $(KILL) `$(CAT) $(DESTDIR)$(PID_DEST)/privoxy.pid` || : -@test -f $(DESTDIR)/var/run/privoxy.pid && $(ECHO) Stopping $(PROGRAM) &&\ $(KILL) `$(CAT) $(DESTDIR)/var/run/privoxy.pid ` || : @# Program binary @$(ECHO) Removing $(PROGRAM) binary $(RM) $(DESTDIR)$(SBIN_DEST)/$(PROGRAM) $(SBIN_DEST)/$(PROGRAM)~ @# config files and dir, and maybe old install backups -@if [ -d $(DESTDIR)$(CONF_DEST) ]; then \ $(ECHO) Saving $(PROGRAM) config files to $(DESTDIR)/tmp/$(PROGRAM)-save ;\ $(MKDIR) $(DESTDIR)/tmp/$(PROGRAM)-save ;\ cd $(DESTDIR)$(CONF_DEST) ;\ for i in $(DESTDIR)$(CONFIGS); do \ [ -f $$i ] && $(CP) $$i $(DESTDIR)/tmp/$(PROGRAM)-save ;\ done ;\ fi @$(ECHO) Removing $(PROGRAM) config files -@for i in $(DESTDIR)$(CONFIGS); do \ test -f $(CONF_DEST)/$$i && $(ECHO) Removing $$i ;\ $(RM) $(DESTDIR)$(CONF_DEST)/$$i $(DESTDIR)$(CONF_DEST)/$$i~ $(DESTDIR)$(CONF_DEST)/$$i.new ;\ done -@test -d $(DESTDIR)$(CONF_DEST)/templates && $(RM) -r $(DESTDIR)$(CONF_DEST)/templates &&\ $(ECHO) "Removing $(DESTDIR)$(CONF_DEST)/templates/*" @# man page and docs @$(ECHO) Removing $(PROGRAM) docs -$(RM) $(DESTDIR)$(MAN_DEST)/$(MAN_PAGE)* -$(RM) -r $(DESTDIR)$(DOC_DEST) || $(RM) -r $(DESTDIR)$(prefix)/doc/privoxy @# Log and pidfile @$(ECHO) Removing $(PROGRAM) logs -$(RM) $(DESTDIR)$(LOG_DEST)/logfile $(DESTDIR)$(PID_DEST)/privoxy.pid @# Final clean up of unused directories. Special handling of CONF and LOG # destinations. @$(ECHO) Removing $(PROGRAM) directories @for i in $(DESTDIR)$(LOG_DEST) $(DESTDIR)$(CONF_DEST); do \ if test -d $$i; then \ $(ECHO) Removing $$i ;\ $(RMDIR) $$i || $(ECHO) "$$i is not empty, not removed" ;\ fi;\ done @if [ ! "$(prefix)" = "/usr/local" ] ;then \ for i in $(DESTDIR)$(MAN_DEST) $(DESTDIR)$(MAN_DIR) $(DESTDIR)$(SHARE_DEST)/doc \ $(DESTDIR)$(SHARE_DEST) $(DESTDIR)$(SBIN_DEST); do \ if test -d $$i; then \ $(ECHO) Removing $$i ;\ $(RMDIR) $$i || $(ECHO) "$$i is not empty, not removed" ;\ fi;\ done;\ if test $(LOG_DEST) != /var/log/privoxy && test -d $(DESTDIR)$(prefix)/var/log; then \ $(ECHO) Removing $(DESTDIR)$(prefix)/var/log ;\ $(RMDIR) $(DESTDIR)$(prefix)/var/log || $(ECHO) "$(DESTDIR)$(prefix)/var/log is not empty, not removed";\ fi ;\ if test $(PID_DEST) != /var/run && test -d $(DESTDIR)$(prefix)/var/run; then \ $(ECHO) Removing $(DESTDIR)$(prefix)/var/run ;\ $(RMDIR) $(DESTDIR)$(prefix)/var/run || $(ECHO) "$(DESTDIR)$(prefix)/var/run is not empty, not removed";\ fi ;\ if test $(prefix)/var != /var && test -d $(DESTDIR)$(prefix)/var; then \ $(ECHO) Removing $(DESTDIR)$(prefix)/var ;\ $(RMDIR) $(DESTDIR)$(prefix)/var || $(ECHO) "$(DESTDIR)$(prefix)/var is not empty, not removed" ;\ fi ;\ if test $(prefix) != / && test $(prefix) != /usr && test -d $(DESTDIR)$(prefix); then \ $(ECHO) Removing $(DESTDIR)$(prefix) ;\ $(ECHO) Removing installation directory $(DESTDIR)$(prefix) ;\ $(RMDIR) $(DESTDIR)$(prefix) || $(ECHO) "$(DESTDIR)$(prefix) is not empty, not removed" ;\ fi;\ fi @# init scripts @if [ "$(prefix)" = "/usr/local" ] || [ "$(prefix)" = "/usr" ]; then \ $(ECHO) Removing $(PROGRAM) init script ;\ if [ -f $(DESTDIR)/etc/slackware-version ] && \ [ -d $(DESTDIR)/etc/rc.d/ ] && [ -w $(DESTDIR)/etc/rc.d/ ] ; then \ $(RM) $(DESTDIR)/etc/rc.d/rc.privoxy ;\ elif [ -d $(DESTDIR)/etc/init.d ] && [ -w $(DESTDIR)/etc/init.d ] ; then \ $(RM) $(DESTDIR)/etc/init.d/privoxy ;\ else \ $(ECHO) "Unable to remove privoxy init script, not installed or permission denied" ;\ fi ;\ fi @$(ECHO) Privoxy uninstalled, bye coffee: @perl -e 'print pack "C*", (31,139,8,8,153,63,226,60,2,3,99,111,102,102,101,' \ -e '101,0,109,143,205,13,192,32,8,133,239,78,241,110,234,1,28,160,171,' \ -e '152,208,53,26,117,247,22,165,73,137,125,9,1,62,126,2,128,169,5,243,' \ -e '143,13,139,49,164,65,100,149,152,102,73,141,88,73,178,116,205,100,' \ -e '69,253,36,102,81,49,83,236,19,225,171,131,214,172,163,73,4,168,123,' \ -e '115,71,126,247,122,94,128,178,227,95,154,12,86,215,122,197,249,146,' \ -e '187,54,220,125,193,51,228,11,1,0,0);' | zcat privoxy-3.0.21-stable/./INSTALL000640 001751 001751 00000016746 12114407630 015027 0ustar00fkfk000000 000000 /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/INSTALL,v $ * * Purpose : INSTALL file to help with installing from source. * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA * *********************************************************************/ ------------------------------------------------------------------------------- To build Privoxy from source, autoconf, GNU make (gmake), and, of course, a C compiler like gcc are required. When building from a source tarball, first unpack the source: tar xzvf privoxy-3.0.21-stable-src.tar.gz cd privoxy-3.0.21-stable For retrieving the current CVS sources, you'll need a CVS client installed. Note that sources from CVS are typically development quality, and may not be stable, or well tested. To download CVS source, check the Sourceforge documentation, which might give commands like: cvs -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa login cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co current cd current This will create a directory named current/, which will contain the source tree. You can also check out any Privoxy "branch", just exchange the current name with the wanted branch name (Example: v_3_0_branch for the 3.0 cvs tree). It is also strongly recommended to not run Privoxy as root. You should configure/install/run Privoxy as an unprivileged user, preferably by creating a "privoxy" user and group just for this purpose. See your local documentation for the correct command line to do add new users and groups (something like adduser, but the command syntax may vary from platform to platform). /etc/passwd might then look like: privoxy:*:7777:7777:privoxy proxy:/no/home:/no/shell And then /etc/group, like: privoxy:*:7777: Some binary packages may do this for you. Then, to build from either unpacked tarball or CVS source: autoheader autoconf ./configure # (--help to see options) make # (the make from GNU, sometimes called gmake) su # Possibly required make -n install # (to see where all the files will go) make -s install # (to really install, -s to silence output) Using GNU make, you can have the first four steps automatically done for you by just typing: make in the freshly downloaded or unpacked source directory. To build an executable with security enhanced features so that users cannot easily bypass the proxy (e.g. "Go There Anyway"), or alter their own configurations, configure like this: ./configure --disable-toggle --disable-editor --disable-force Then build as above. In Privoxy 3.0.7 and later, all of these options can also be disabled through the configuration file. WARNING: If installing as root, the install will fail unless a non-root user or group is specified, or a privoxy user and group already exist on the system. If a non-root user is specified, and no group, then the installation will try to also use a group of the same name as "user". If a group is specified (and no user), then the support files will be installed as writable by that group, and owned by the user running the installation. configure accepts --with-user and --with-group options for setting user and group ownership of the configuration files (which need to be writable by the daemon). The specified user must already exist. When starting Privoxy, it must be run as this same user to insure write access to configuration and log files! Alternately, you can specify user and group on the make command line, but be sure both already exist: make -s install USER=privoxy GROUP=privoxy The default installation path for make install is /usr/local. This may of course be customized with the various ./configure path options. If you are doing an install to anywhere besides /usr/local, be sure to set the appropriate paths with the correct configure options (./configure --help). Non-privileged users must of course have write access permissions to wherever the target installation is going. If you do install to /usr/local, the install will use sysconfdir=$prefix/etc/ privoxy by default. All other destinations, and the direct usage of --sysconfdir flag behave like normal, i.e. will not add the extra privoxy directory. This is for a safer install, as there may already exist another program that uses a file with the "config" name, and thus makes /usr/local/etc cleaner. If installing to /usr/local, the documentation will go by default to $prefix/ share/doc. But if this directory doesn't exist, it will then try $prefix/doc and install there before creating a new $prefix/share/doc just for Privoxy. Again, if the installs goes to /usr/local, the localstatedir (ie: var/) will default to /var instead of $prefix/var so the logs will go to /var/log/privoxy /, and the pid file will be created in /var/run/privoxy.pid. make install will attempt to set the correct values in config (main configuration file). You should check this to make sure all values are correct. If appropriate, an init script will be installed, but it is up to the user to determine how and where to start Privoxy. The init script should be checked for correct paths and values, if anything other than a default install is done. If install finds previous versions of local configuration files, most of these will not be overwritten, and the new ones will be installed with a "new" extension. default.action and default.filter will be overwritten. You will then need to manually update the other installed configuration files as needed. The default template files will be overwritten. If you have customized, local templates, these should be stored safely in a separate directory and defined in config by the "templdir" directive. It is of course wise to always back-up any important configuration files "just in case". If a previous version of Privoxy is already running, you will have to restart it manually. For more detailed instructions on how to build Redhat RPMs, Windows self-extracting installers, building on platforms with special requirements etc, please consult the developer manual. The simplest command line to start Privoxy is $path/privoxy --user=privoxy $path/etc/privoxy/config. See privoxy --usage, or the man page, for other options, and configuration. privoxy-3.0.21-stable/./loadcfg.c000640 001751 001751 00000201025 12116117561 015526 0ustar00fkfk000000 000000 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.137 2013/03/07 14:08:49 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $ * * Purpose : Loads settings from the configuration file into * global variables. This file contains both the * routine to load the configuration and the global * variables it writes to. * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 # ifndef STRICT # define STRICT # endif # include # include "win32.h" # ifndef _WIN_CONSOLE # include "w32log.h" # endif /* ndef _WIN_CONSOLE */ #else /* ifndef _WIN32 */ #ifndef __OS2__ # include # include #endif # include # include # include #endif #include "project.h" #include "loadcfg.h" #include "list.h" #include "jcc.h" #include "filters.h" #include "loaders.h" #include "miscutil.h" #include "errlog.h" #include "ssplit.h" #include "encode.h" #include "urlmatch.h" #include "cgi.h" #include "gateway.h" const char loadcfg_h_rcs[] = LOADCFG_H_VERSION; #ifdef FEATURE_TOGGLE /* Privoxy is enabled by default. */ int global_toggle_state = 1; #endif /* def FEATURE_TOGGLE */ /* The filename of the configfile */ const char *configfile = NULL; /* * CGI functions will later need access to the invocation args, * so we will make argc and argv global. */ int Argc = 0; char * const * Argv = NULL; static struct file_list *current_configfile = NULL; /* * This takes the "cryptic" hash of each keyword and aliases them to * something a little more readable. This also makes changing the * hash values easier if they should change or the hash algorthm changes. * Use the included "hash" program to find out what the hash will be * for any string supplied on the command line. (Or just put it in the * config file and read the number from the error message in the log). * * Please keep this list sorted alphabetically (but with the Windows * console and GUI specific options last). */ #define hash_actions_file 1196306641U /* "actionsfile" */ #define hash_accept_intercepted_requests 1513024973U /* "accept-intercepted-requests" */ #define hash_admin_address 4112573064U /* "admin-address" */ #define hash_allow_cgi_request_crunching 258915987U /* "allow-cgi-request-crunching" */ #define hash_buffer_limit 1881726070U /* "buffer-limit */ #define hash_client_header_order 2701453514U /* "client-header-order" */ #define hash_compression_level 2464423563U /* "compression-level" */ #define hash_confdir 1978389U /* "confdir" */ #define hash_connection_sharing 1348841265U /* "connection-sharing" */ #define hash_debug 78263U /* "debug" */ #define hash_default_server_timeout 2530089913U /* "default-server-timeout" */ #define hash_deny_access 1227333715U /* "deny-access" */ #define hash_enable_edit_actions 2517097536U /* "enable-edit-actions" */ #define hash_enable_compression 3943696946U /* "enable-compression" */ #define hash_enable_proxy_authentication_forwarding 4040610791U /* enable-proxy-authentication-forwarding */ #define hash_enable_remote_toggle 2979744683U /* "enable-remote-toggle" */ #define hash_enable_remote_http_toggle 110543988U /* "enable-remote-http-toggle" */ #define hash_enforce_blocks 1862427469U /* "enforce-blocks" */ #define hash_filterfile 250887266U /* "filterfile" */ #define hash_forward 2029845U /* "forward" */ #define hash_forward_socks4 3963965521U /* "forward-socks4" */ #define hash_forward_socks4a 2639958518U /* "forward-socks4a" */ #define hash_forward_socks5 3963965522U /* "forward-socks5" */ #define hash_forward_socks5t 2639958542U /* "forward-socks5t" */ #define hash_forwarded_connect_retries 101465292U /* "forwarded-connect-retries" */ #define hash_handle_as_empty_returns_ok 1444873247U /* "handle-as-empty-doc-returns-ok" */ #define hash_hostname 10308071U /* "hostname" */ #define hash_keep_alive_timeout 3878599515U /* "keep-alive-timeout" */ #define hash_listen_address 1255650842U /* "listen-address" */ #define hash_logdir 422889U /* "logdir" */ #define hash_logfile 2114766U /* "logfile" */ #define hash_max_client_connections 3595884446U /* "max-client-connections" */ #define hash_permit_access 3587953268U /* "permit-access" */ #define hash_proxy_info_url 3903079059U /* "proxy-info-url" */ #define hash_single_threaded 4250084780U /* "single-threaded" */ #define hash_socket_timeout 1809001761U /* "socket-timeout" */ #define hash_split_large_cgi_forms 671658948U /* "split-large-cgi-forms" */ #define hash_suppress_blocklists 1948693308U /* "suppress-blocklists" */ #define hash_templdir 11067889U /* "templdir" */ #define hash_tolerate_pipelining 1360286620U /* "tolerate-pipelining" */ #define hash_toggle 447966U /* "toggle" */ #define hash_trust_info_url 430331967U /* "trust-info-url" */ #define hash_trustfile 56494766U /* "trustfile" */ #define hash_usermanual 1416668518U /* "user-manual" */ #define hash_activity_animation 1817904738U /* "activity-animation" */ #define hash_close_button_minimizes 3651284693U /* "close-button-minimizes" */ #define hash_hide_console 2048809870U /* "hide-console" */ #define hash_log_buffer_size 2918070425U /* "log-buffer-size" */ #define hash_log_font_name 2866730124U /* "log-font-name" */ #define hash_log_font_size 2866731014U /* "log-font-size" */ #define hash_log_highlight_messages 4032101240U /* "log-highlight-messages" */ #define hash_log_max_lines 2868344173U /* "log-max-lines" */ #define hash_log_messages 2291744899U /* "log-messages" */ #define hash_show_on_task_bar 215410365U /* "show-on-task-bar" */ static void savearg(char *command, char *argument, struct configuration_spec * config); /********************************************************************* * * Function : unload_configfile * * Description : Free the config structure and all components. * * Parameters : * 1 : data: struct configuration_spec to unload * * Returns : N/A * *********************************************************************/ static void unload_configfile (void * data) { struct configuration_spec * config = (struct configuration_spec *)data; struct forward_spec *cur_fwd = config->forward; int i; #ifdef FEATURE_ACL struct access_control_list *cur_acl = config->acl; while (cur_acl != NULL) { struct access_control_list * next_acl = cur_acl->next; free(cur_acl); cur_acl = next_acl; } config->acl = NULL; #endif /* def FEATURE_ACL */ while (cur_fwd != NULL) { struct forward_spec * next_fwd = cur_fwd->next; free_url_spec(cur_fwd->url); freez(cur_fwd->gateway_host); freez(cur_fwd->forward_host); free(cur_fwd); cur_fwd = next_fwd; } config->forward = NULL; freez(config->confdir); freez(config->logdir); freez(config->templdir); freez(config->hostname); for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { freez(config->haddr[i]); } freez(config->logfile); for (i = 0; i < MAX_AF_FILES; i++) { freez(config->actions_file_short[i]); freez(config->actions_file[i]); freez(config->re_filterfile_short[i]); freez(config->re_filterfile[i]); } list_remove_all(config->ordered_client_headers); freez(config->admin_address); freez(config->proxy_info_url); freez(config->proxy_args); freez(config->usermanual); #ifdef FEATURE_TRUST freez(config->trustfile); list_remove_all(config->trust_info); #endif /* def FEATURE_TRUST */ freez(config); } #ifdef FEATURE_GRACEFUL_TERMINATION /********************************************************************* * * Function : unload_current_config_file * * Description : Unloads current config file - reset to state at * beginning of program. * * Parameters : None * * Returns : N/A * *********************************************************************/ void unload_current_config_file(void) { if (current_configfile) { current_configfile->unloader = unload_configfile; current_configfile = NULL; } } #endif /********************************************************************* * * Function : parse_toggle_value * * Description : Parse the value of a directive that can only be * enabled or disabled. Terminates with a fatal error * if the value is NULL or something other than 0 or 1. * * Parameters : * 1 : name: The name of the directive. Used for log messages. * 2 : value: The value to parse * * * Returns : The numerical toggle state * *********************************************************************/ static int parse_toggle_state(const char *name, const char *value) { int toggle_state; assert(name != NULL); assert(value != NULL); if ((value == NULL) || (*value == '\0')) { log_error(LOG_LEVEL_FATAL, "Directive %s used without argument", name); } toggle_state = atoi(value); /* * Also check the length as atoi() doesn't mind * garbage after a valid integer, but we do. */ if (((toggle_state != 0) && (toggle_state != 1)) || (strlen(value) != 1)) { log_error(LOG_LEVEL_FATAL, "Directive %s used with invalid argument '%s'. Use either '0' or '1'.", name, value); } return toggle_state; } /********************************************************************* * * Function : parse_client_header_order * * Description : Parse the value of the header-order directive * * Parameters : * 1 : ordered_header_list: List to insert the ordered * headers into. * 2 : ordered_headers: The ordered header names separated * by spaces or tabs. * * * Returns : N/A * *********************************************************************/ static void parse_client_header_order(struct list *ordered_header_list, const char *ordered_headers) { char *original_headers_copy; char **vector; size_t max_segments; int number_of_headers; int i; assert(ordered_header_list != NULL); assert(ordered_headers != NULL); if (ordered_headers == NULL) { log_error(LOG_LEVEL_FATAL, "header-order used without argument"); } /* * XXX: This estimate is guaranteed to be high enough as we * let ssplit() ignore empty fields, but also a bit wasteful. * The same hack is used in get_last_url() so it looks like * a real solution is needed. */ max_segments = strlen(ordered_headers) / 2; if (max_segments == 0) { max_segments = 1; } vector = malloc_or_die(max_segments * sizeof(char *)); original_headers_copy = strdup_or_die(ordered_headers); number_of_headers = ssplit(original_headers_copy, "\t ", vector, max_segments); if (number_of_headers == -1) { log_error(LOG_LEVEL_FATAL, "Failed to split ordered headers"); } for (i = 0; i < number_of_headers; i++) { if (JB_ERR_OK != enlist(ordered_header_list, vector[i])) { log_error(LOG_LEVEL_FATAL, "Failed to enlist ordered header: %s", vector[i]); } } freez(vector); freez(original_headers_copy); return; } /********************************************************************* * * Function : load_config * * Description : Load the config file and all parameters. * * XXX: more than thousand lines long * and thus in serious need of refactoring. * * Parameters : None * * Returns : The configuration_spec, or NULL on error. * *********************************************************************/ struct configuration_spec * load_config(void) { char *buf = NULL; char *p, *q; FILE *configfp = NULL; struct configuration_spec * config = NULL; struct client_state * fake_csp; struct file_list *fs; unsigned long linenum = 0; int i; char *logfile = NULL; if (!check_file_changed(current_configfile, configfile, &fs)) { /* No need to load */ return ((struct configuration_spec *)current_configfile->f); } if (NULL == fs) { log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s': %E", configfile); return NULL; } if (NULL != current_configfile) { log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile); } #ifdef FEATURE_TOGGLE global_toggle_state = 1; #endif /* def FEATURE_TOGGLE */ fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config)); if (NULL == config) { freez(fs->filename); freez(fs); log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); return NULL; } /* * This is backwards from how it's usually done. * Following the usual pattern, "fs" would be stored in a member * variable in "csp", and then we'd access "config" from "fs->f", * using a cast. However, "config" is used so often that a * cast each time would be very ugly, and the extra indirection * would waste CPU cycles. Therefore we store "config" in * "csp->config", and "fs" in "csp->config->config_file_list". */ config->config_file_list = fs; /* * Set to defaults */ config->multi_threaded = 1; config->buffer_limit = 4096 * 1024; config->usermanual = strdup(USER_MANUAL_URL); config->proxy_args = strdup(""); config->forwarded_connect_retries = 0; /* * 128 client sockets ought to be enough for everybody who can't * be bothered to read the documentation to figure out how to * increase the limit. */ config->max_client_connections = 128; config->socket_timeout = 300; /* XXX: Should be a macro. */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE config->default_server_timeout = 0; config->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT; config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING; #endif config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE; config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS; config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; config->feature_flags &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; #ifdef FEATURE_COMPRESSION config->feature_flags &= ~RUNTIME_FEATURE_COMPRESSION; /* * XXX: Run some benchmarks to see if there are better default values. */ config->compression_level = 1; #endif config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING; configfp = fopen(configfile, "r"); if (NULL == configfp) { log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s': %E", configfile); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } while (read_config_line(configfp, &linenum, &buf) != NULL) { char cmd[BUFFER_SIZE]; char arg[BUFFER_SIZE]; char tmp[BUFFER_SIZE]; #ifdef FEATURE_ACL struct access_control_list *cur_acl; #endif /* def FEATURE_ACL */ struct forward_spec *cur_fwd; int vec_count; char *vec[3]; unsigned int directive_hash; strlcpy(tmp, buf, sizeof(tmp)); /* Copy command (i.e. up to space or tab) into cmd */ p = buf; q = cmd; while (*p && (*p != ' ') && (*p != '\t')) { *q++ = *p++; } *q = '\0'; /* Skip over the whitespace in buf */ while (*p && ((*p == ' ') || (*p == '\t'))) { p++; } /* Copy the argument into arg */ if (strlcpy(arg, p, sizeof(arg)) >= sizeof(arg)) { log_error(LOG_LEVEL_FATAL, "Config line too long: %s", buf); } /* Should never happen, but check this anyway */ if (*cmd == '\0') { freez(buf); continue; } /* Make sure the command field is lower case */ for (p = cmd; *p; p++) { if (privoxy_isupper(*p)) { *p = (char)privoxy_tolower(*p); } } directive_hash = hash_string(cmd); switch (directive_hash) { /* ************************************************************************* * actionsfile actions-file-name * In confdir by default * *************************************************************************/ case hash_actions_file : i = 0; while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i])) { i++; } if (i >= MAX_AF_FILES) { log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n" "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).", MAX_AF_FILES); } config->actions_file_short[i] = strdup(arg); config->actions_file[i] = make_path(config->confdir, arg); break; /* ************************************************************************* * accept-intercepted-requests * *************************************************************************/ case hash_accept_intercepted_requests: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; } else { config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS; } break; /* ************************************************************************* * admin-address email-address * *************************************************************************/ case hash_admin_address : freez(config->admin_address); config->admin_address = strdup(arg); break; /* ************************************************************************* * allow-cgi-request-crunching * *************************************************************************/ case hash_allow_cgi_request_crunching: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING; } else { config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING; } break; /* ************************************************************************* * buffer-limit n * *************************************************************************/ case hash_buffer_limit : config->buffer_limit = (size_t)(1024 * atoi(arg)); break; /* ************************************************************************* * client-header-order header-1 header-2 ... header-n * *************************************************************************/ case hash_client_header_order: list_remove_all(config->ordered_client_headers); parse_client_header_order(config->ordered_client_headers, arg); break; /* ************************************************************************* * confdir directory-name * *************************************************************************/ case hash_confdir : freez(config->confdir); config->confdir = make_path(NULL, arg); break; /* ************************************************************************* * compression-level 0-9 * *************************************************************************/ #ifdef FEATURE_COMPRESSION case hash_compression_level : if (*arg != '\0') { int compression_level = atoi(arg); if (-1 <= compression_level && compression_level <= 9) { config->compression_level = compression_level;; } else { log_error(LOG_LEVEL_FATAL, "Invalid compression-level value: %s", arg); } } else { log_error(LOG_LEVEL_FATAL, "Invalid compression-level directive. Compression value missing"); } break; #endif /* ************************************************************************* * connection-sharing (0|1) * *************************************************************************/ #ifdef FEATURE_CONNECTION_SHARING case hash_connection_sharing : if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING; } else { config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING; } break; #endif /* ************************************************************************* * debug n * Specifies debug level, multiple values are ORed together. * *************************************************************************/ case hash_debug : config->debug |= atoi(arg); break; /* ************************************************************************* * default-server-timeout timeout * *************************************************************************/ #ifdef FEATURE_CONNECTION_KEEP_ALIVE case hash_default_server_timeout : if (*arg != '\0') { int timeout = atoi(arg); if (0 <= timeout) { config->default_server_timeout = (unsigned int)timeout; } else { log_error(LOG_LEVEL_FATAL, "Invalid default-server-timeout value: %s", arg); } } break; #endif /* ************************************************************************* * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]] * *************************************************************************/ #ifdef FEATURE_ACL case hash_deny_access: strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if ((vec_count != 1) && (vec_count != 2)) { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " "deny-access directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Wrong number of parameters for " "deny-access directive in configuration file.

    \n"); break; } /* allocate a new node */ cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); if (cur_acl == NULL) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ break; } cur_acl->action = ACL_DENY; if (acl_addr(vec[0], cur_acl->src) < 0) { log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask " "for deny-access directive in configuration file: \"%s\"", vec[0]); string_append(&config->proxy_args, "
    \nWARNING: Invalid source address, port or netmask " "for deny-access directive in configuration file: \""); string_append(&config->proxy_args, vec[0]); string_append(&config->proxy_args, "\"

    \n"); freez(cur_acl); break; } if (vec_count == 2) { if (acl_addr(vec[1], cur_acl->dst) < 0) { log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask " "for deny-access directive in configuration file: \"%s\"", vec[1]); string_append(&config->proxy_args, "
    \nWARNING: Invalid destination address, port or netmask " "for deny-access directive in configuration file: \""); string_append(&config->proxy_args, vec[1]); string_append(&config->proxy_args, "\"

    \n"); freez(cur_acl); break; } } #ifdef HAVE_RFC2553 else { cur_acl->wildcard_dst = 1; } #endif /* def HAVE_RFC2553 */ /* * Add it to the list. Note we reverse the list to get the * behaviour the user expects. With both the ACL and * actions file, the last match wins. However, the internal * implementations are different: The actions file is stored * in the same order as the file, and scanned completely. * With the ACL, we reverse the order as we load it, then * when we scan it we stop as soon as we get a match. */ cur_acl->next = config->acl; config->acl = cur_acl; break; #endif /* def FEATURE_ACL */ /* ************************************************************************* * enable-edit-actions 0|1 * *************************************************************************/ #ifdef FEATURE_CGI_EDIT_ACTIONS case hash_enable_edit_actions: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS; } else { config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS; } break; #endif /* def FEATURE_CGI_EDIT_ACTIONS */ /* ************************************************************************* * enable-compression 0|1 * *************************************************************************/ #ifdef FEATURE_COMPRESSION case hash_enable_compression: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_COMPRESSION; } else { config->feature_flags &= ~RUNTIME_FEATURE_COMPRESSION; } break; #endif /* def FEATURE_COMPRESSION */ /* ************************************************************************* * enable-proxy-authentication-forwarding 0|1 * *************************************************************************/ case hash_enable_proxy_authentication_forwarding: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; } else { config->feature_flags &= ~RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS; } break; /* ************************************************************************* * enable-remote-toggle 0|1 * *************************************************************************/ #ifdef FEATURE_TOGGLE case hash_enable_remote_toggle: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE; } else { config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE; } break; #endif /* def FEATURE_TOGGLE */ /* ************************************************************************* * enable-remote-http-toggle 0|1 * *************************************************************************/ case hash_enable_remote_http_toggle: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE; } else { config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE; } break; /* ************************************************************************* * enforce-blocks 0|1 * *************************************************************************/ case hash_enforce_blocks: #ifdef FEATURE_FORCE_LOAD if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS; } else { config->feature_flags &= ~RUNTIME_FEATURE_ENFORCE_BLOCKS; } #else log_error(LOG_LEVEL_ERROR, "Ignoring directive 'enforce-blocks'. " "FEATURE_FORCE_LOAD is disabled, blocks will always be enforced."); #endif /* def FEATURE_FORCE_LOAD */ break; /* ************************************************************************* * filterfile file-name * In confdir by default. * *************************************************************************/ case hash_filterfile : i = 0; while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i])) { i++; } if (i >= MAX_AF_FILES) { log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n" "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).", MAX_AF_FILES); } config->re_filterfile_short[i] = strdup(arg); config->re_filterfile[i] = make_path(config->confdir, arg); break; /* ************************************************************************* * forward url-pattern (.|http-proxy-host[:port]) * *************************************************************************/ case hash_forward: strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 2) { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward " "directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Wrong number of parameters for " "forward directive in configuration file."); break; } /* allocate a new node */ cur_fwd = zalloc(sizeof(*cur_fwd)); if (cur_fwd == NULL) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ break; } cur_fwd->type = SOCKS_NONE; /* Save the URL pattern */ if (create_url_spec(cur_fwd->url, vec[0])) { log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward " "directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Bad URL specifier for " "forward directive in configuration file."); break; } /* Parse the parent HTTP proxy host:port */ p = vec[1]; if (strcmp(p, ".") != 0) { cur_fwd->forward_port = 8000; parse_forwarder_address(p, &cur_fwd->forward_host, &cur_fwd->forward_port); } /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; break; /* ************************************************************************* * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port]) * *************************************************************************/ case hash_forward_socks4: strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 3) { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " "forward-socks4 directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Wrong number of parameters for " "forward-socks4 directive in configuration file."); break; } /* allocate a new node */ cur_fwd = zalloc(sizeof(*cur_fwd)); if (cur_fwd == NULL) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ break; } cur_fwd->type = SOCKS_4; /* Save the URL pattern */ if (create_url_spec(cur_fwd->url, vec[0])) { log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 " "directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Bad URL specifier for " "forward-socks4 directive in configuration file."); break; } /* Parse the SOCKS proxy host[:port] */ p = vec[1]; /* XXX: This check looks like a bug. */ if (strcmp(p, ".") != 0) { cur_fwd->gateway_port = 1080; parse_forwarder_address(p, &cur_fwd->gateway_host, &cur_fwd->gateway_port); } /* Parse the parent HTTP proxy host[:port] */ p = vec[2]; if (strcmp(p, ".") != 0) { cur_fwd->forward_port = 8000; parse_forwarder_address(p, &cur_fwd->forward_host, &cur_fwd->forward_port); } /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; break; /* ************************************************************************* * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port]) * *************************************************************************/ case hash_forward_socks4a: case hash_forward_socks5: case hash_forward_socks5t: strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if (vec_count != 3) { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " "forward-socks4a directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Wrong number of parameters for " "forward-socks4a directive in configuration file."); break; } /* allocate a new node */ cur_fwd = zalloc(sizeof(*cur_fwd)); if (cur_fwd == NULL) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ break; } if (directive_hash == hash_forward_socks4a) { cur_fwd->type = SOCKS_4A; } else if (directive_hash == hash_forward_socks5) { cur_fwd->type = SOCKS_5; } else { assert(directive_hash == hash_forward_socks5t); cur_fwd->type = SOCKS_5T; } /* Save the URL pattern */ if (create_url_spec(cur_fwd->url, vec[0])) { log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a " "directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Bad URL specifier for " "forward-socks4a directive in configuration file."); break; } /* Parse the SOCKS proxy host[:port] */ p = vec[1]; cur_fwd->gateway_port = 1080; parse_forwarder_address(p, &cur_fwd->gateway_host, &cur_fwd->gateway_port); /* Parse the parent HTTP proxy host[:port] */ p = vec[2]; if (strcmp(p, ".") != 0) { cur_fwd->forward_port = 8000; parse_forwarder_address(p, &cur_fwd->forward_host, &cur_fwd->forward_port); } /* Add to list. */ cur_fwd->next = config->forward; config->forward = cur_fwd; break; /* ************************************************************************* * forwarded-connect-retries n * *************************************************************************/ case hash_forwarded_connect_retries : config->forwarded_connect_retries = atoi(arg); break; /* ************************************************************************* * handle-as-empty-doc-returns-ok 0|1 * * Workaround for firefox hanging on blocked javascript pages. * Block with the "+handle-as-empty-document" flag and set the * "handle-as-empty-doc-returns-ok" run-time config flag so that * Privoxy returns a 200/OK status instead of a 403/Forbidden status * to the browser for blocked pages. ***************************************************************************/ case hash_handle_as_empty_returns_ok: if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; } else { config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK; } break; /* ************************************************************************* * hostname hostname-to-show-on-cgi-pages * *************************************************************************/ case hash_hostname : freez(config->hostname); config->hostname = strdup(arg); if (NULL == config->hostname) { log_error(LOG_LEVEL_FATAL, "Out of memory saving hostname."); } break; /* ************************************************************************* * keep-alive-timeout timeout * *************************************************************************/ #ifdef FEATURE_CONNECTION_KEEP_ALIVE case hash_keep_alive_timeout : if (*arg != '\0') { int timeout = atoi(arg); if (0 < timeout) { config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; config->keep_alive_timeout = (unsigned int)timeout; } else { config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; } } break; #endif /* ************************************************************************* * listen-address [ip][:port] * *************************************************************************/ case hash_listen_address : i = 0; while ((i < MAX_LISTENING_SOCKETS) && (NULL != config->haddr[i])) { i++; } if (i >= MAX_LISTENING_SOCKETS) { log_error(LOG_LEVEL_FATAL, "Too many 'listen-address' directives in config file - limit is %d.\n" "(You can increase this limit by changing MAX_LISTENING_SOCKETS in project.h and recompiling).", MAX_LISTENING_SOCKETS); } config->haddr[i] = strdup(arg); if (NULL == config->haddr[i]) { log_error(LOG_LEVEL_FATAL, "Out of memory while copying listening address"); } break; /* ************************************************************************* * logdir directory-name * *************************************************************************/ case hash_logdir : freez(config->logdir); config->logdir = make_path(NULL, arg); break; /* ************************************************************************* * logfile log-file-name * In logdir by default * *************************************************************************/ case hash_logfile : if (daemon_mode) { logfile = make_path(config->logdir, arg); if (NULL == logfile) { log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path"); } } break; /* ************************************************************************* * max-client-connections number * *************************************************************************/ case hash_max_client_connections : if (*arg != '\0') { int max_client_connections = atoi(arg); if (0 <= max_client_connections) { config->max_client_connections = max_client_connections; } } break; /* ************************************************************************* * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]] * *************************************************************************/ #ifdef FEATURE_ACL case hash_permit_access: strlcpy(tmp, arg, sizeof(tmp)); vec_count = ssplit(tmp, " \t", vec, SZ(vec)); if ((vec_count != 1) && (vec_count != 2)) { log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for " "permit-access directive in configuration file."); string_append(&config->proxy_args, "
    \nWARNING: Wrong number of parameters for " "permit-access directive in configuration file.

    \n"); break; } /* allocate a new node */ cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl)); if (cur_acl == NULL) { log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration"); /* Never get here - LOG_LEVEL_FATAL causes program exit */ break; } cur_acl->action = ACL_PERMIT; if (acl_addr(vec[0], cur_acl->src) < 0) { log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask " "for permit-access directive in configuration file: \"%s\"", vec[0]); string_append(&config->proxy_args, "
    \nWARNING: Invalid source address, port or netmask for " "permit-access directive in configuration file: \""); string_append(&config->proxy_args, vec[0]); string_append(&config->proxy_args, "\"

    \n"); freez(cur_acl); break; } if (vec_count == 2) { if (acl_addr(vec[1], cur_acl->dst) < 0) { log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask " "for permit-access directive in configuration file: \"%s\"", vec[1]); string_append(&config->proxy_args, "
    \nWARNING: Invalid destination address, port or netmask for " "permit-access directive in configuration file: \""); string_append(&config->proxy_args, vec[1]); string_append(&config->proxy_args, "\"

    \n"); freez(cur_acl); break; } } #ifdef HAVE_RFC2553 else { cur_acl->wildcard_dst = 1; } #endif /* def HAVE_RFC2553 */ /* * Add it to the list. Note we reverse the list to get the * behaviour the user expects. With both the ACL and * actions file, the last match wins. However, the internal * implementations are different: The actions file is stored * in the same order as the file, and scanned completely. * With the ACL, we reverse the order as we load it, then * when we scan it we stop as soon as we get a match. */ cur_acl->next = config->acl; config->acl = cur_acl; break; #endif /* def FEATURE_ACL */ /* ************************************************************************* * proxy-info-url url * *************************************************************************/ case hash_proxy_info_url : freez(config->proxy_info_url); config->proxy_info_url = strdup(arg); break; /* ************************************************************************* * single-threaded * *************************************************************************/ case hash_single_threaded : config->multi_threaded = 0; break; /* ************************************************************************* * socket-timeout numer_of_seconds * *************************************************************************/ case hash_socket_timeout : if (*arg != '\0') { int socket_timeout = atoi(arg); if (0 <= socket_timeout) { config->socket_timeout = socket_timeout; } else { log_error(LOG_LEVEL_FATAL, "Invalid socket-timeout: '%s'", arg); } } break; /* ************************************************************************* * split-large-cgi-forms * *************************************************************************/ case hash_split_large_cgi_forms : if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS; } else { config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS; } break; /* ************************************************************************* * templdir directory-name * *************************************************************************/ case hash_templdir : freez(config->templdir); config->templdir = make_path(NULL, arg); break; /* ************************************************************************* * tolerate-pipelining (0|1) * *************************************************************************/ case hash_tolerate_pipelining : if (parse_toggle_state(cmd, arg) == 1) { config->feature_flags |= RUNTIME_FEATURE_TOLERATE_PIPELINING; } else { config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING; } break; /* ************************************************************************* * toggle (0|1) * *************************************************************************/ #ifdef FEATURE_TOGGLE case hash_toggle : global_toggle_state = parse_toggle_state(cmd, arg); break; #endif /* def FEATURE_TOGGLE */ /* ************************************************************************* * trust-info-url url * *************************************************************************/ #ifdef FEATURE_TRUST case hash_trust_info_url : enlist(config->trust_info, arg); break; #endif /* def FEATURE_TRUST */ /* ************************************************************************* * trustfile filename * (In confdir by default.) * *************************************************************************/ #ifdef FEATURE_TRUST case hash_trustfile : freez(config->trustfile); config->trustfile = make_path(config->confdir, arg); break; #endif /* def FEATURE_TRUST */ /* ************************************************************************* * usermanual url * *************************************************************************/ case hash_usermanual : /* * XXX: If this isn't the first config directive, the * show-status page links to the website documentation * for the directives that were already parsed. Lame. */ freez(config->usermanual); config->usermanual = strdup(arg); break; /* ************************************************************************* * Win32 Console options: * *************************************************************************/ /* ************************************************************************* * hide-console * *************************************************************************/ #ifdef _WIN_CONSOLE case hash_hide_console : hideConsole = 1; break; #endif /*def _WIN_CONSOLE*/ /* ************************************************************************* * Win32 GUI options: * *************************************************************************/ #if defined(_WIN32) && ! defined(_WIN_CONSOLE) /* ************************************************************************* * activity-animation (0|1) * *************************************************************************/ case hash_activity_animation : g_bShowActivityAnimation = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * close-button-minimizes (0|1) * *************************************************************************/ case hash_close_button_minimizes : g_bCloseHidesWindow = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * log-buffer-size (0|1) * *************************************************************************/ case hash_log_buffer_size : g_bLimitBufferSize = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * log-font-name fontname * *************************************************************************/ case hash_log_font_name : if (strlcpy(g_szFontFaceName, arg, sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName)) { log_error(LOG_LEVEL_FATAL, "log-font-name argument '%s' is longer than %u characters.", arg, sizeof(g_szFontFaceName)-1); } break; /* ************************************************************************* * log-font-size n * *************************************************************************/ case hash_log_font_size : g_nFontSize = atoi(arg); break; /* ************************************************************************* * log-highlight-messages (0|1) * *************************************************************************/ case hash_log_highlight_messages : g_bHighlightMessages = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * log-max-lines n * *************************************************************************/ case hash_log_max_lines : g_nMaxBufferLines = atoi(arg); break; /* ************************************************************************* * log-messages (0|1) * *************************************************************************/ case hash_log_messages : g_bLogMessages = parse_toggle_state(cmd, arg); break; /* ************************************************************************* * show-on-task-bar (0|1) * *************************************************************************/ case hash_show_on_task_bar : g_bShowOnTaskBar = parse_toggle_state(cmd, arg); break; #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */ /* ************************************************************************* * Warnings about unsupported features * *************************************************************************/ #ifndef FEATURE_ACL case hash_deny_access: #endif /* ndef FEATURE_ACL */ #ifndef FEATURE_CGI_EDIT_ACTIONS case hash_enable_edit_actions: #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */ #ifndef FEATURE_TOGGLE case hash_enable_remote_toggle: #endif /* ndef FEATURE_TOGGLE */ #ifndef FEATURE_ACL case hash_permit_access: #endif /* ndef FEATURE_ACL */ #ifndef FEATURE_TOGGLE case hash_toggle : #endif /* ndef FEATURE_TOGGLE */ #ifndef FEATURE_TRUST case hash_trustfile : case hash_trust_info_url : #endif /* ndef FEATURE_TRUST */ #ifndef _WIN_CONSOLE case hash_hide_console : #endif /* ndef _WIN_CONSOLE */ #if defined(_WIN_CONSOLE) || ! defined(_WIN32) case hash_activity_animation : case hash_close_button_minimizes : case hash_log_buffer_size : case hash_log_font_name : case hash_log_font_size : case hash_log_highlight_messages : case hash_log_max_lines : case hash_log_messages : case hash_show_on_task_bar : #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */ /* These warnings are annoying - so hide them. -- Jon */ /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */ break; /* *************************************************************************/ default : /* *************************************************************************/ /* * I decided that I liked this better as a warning than an * error. To change back to an error, just change log level * to LOG_LEVEL_FATAL. */ log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive " "'%s' (%uU) in line %lu in configuration file (%s).", buf, directive_hash, linenum, configfile); string_append(&config->proxy_args, " Warning: Ignoring unrecognized directive:"); break; /* *************************************************************************/ } /* end switch(hash_string(cmd)) */ /* Save the argument for the show-status page. */ savearg(cmd, arg, config); freez(buf); } /* end while (read_config_line(...)) */ fclose(configfp); set_debug_level(config->debug); freez(config->logfile); if (daemon_mode) { if (NULL != logfile) { config->logfile = logfile; init_error_log(Argv[0], config->logfile); } else { disable_logging(); } } #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (config->default_server_timeout > config->keep_alive_timeout) { log_error(LOG_LEVEL_ERROR, "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.", config->default_server_timeout, config->keep_alive_timeout); config->default_server_timeout = config->keep_alive_timeout; } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_CONNECTION_SHARING if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) { if (config->multi_threaded) { set_keep_alive_timeout(config->keep_alive_timeout); } else { /* * While we could use keep-alive without multiple threads * if we didn't bother with enforcing the connection timeout, * that might make Tor users sad, even though they shouldn't * enable the single-threaded option anyway. * * XXX: We could still use Proxy-Connection: keep-alive. */ config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE; log_error(LOG_LEVEL_ERROR, "Config option single-threaded disables connection keep-alive."); } } else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)) { log_error(LOG_LEVEL_ERROR, "Config option connection-sharing " "has no effect if keep-alive-timeout isn't set."); config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING; } #endif /* def FEATURE_CONNECTION_SHARING */ if (NULL == config->proxy_args) { log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args"); } if (config->re_filterfile[0]) { add_loader(load_re_filterfiles, config); } if (config->actions_file[0]) { add_loader(load_action_files, config); } #ifdef FEATURE_TRUST if (config->trustfile) { add_loader(load_trustfile, config); } #endif /* def FEATURE_TRUST */ if (NULL == config->haddr[0]) { config->haddr[0] = strdup(HADDR_DEFAULT); if (NULL == config->haddr[0]) { log_error(LOG_LEVEL_FATAL, "Out of memory while copying default listening address"); } } for (i = 0; i < MAX_LISTENING_SOCKETS && NULL != config->haddr[i]; i++) { if ((*config->haddr[i] == '[') && (NULL != (p = strchr(config->haddr[i], ']'))) && (p[1] == ':') && (0 < (config->hport[i] = atoi(p + 2)))) { *p = '\0'; memmove((void *)config->haddr[i], config->haddr[i] + 1, (size_t)(p - config->haddr[i])); } else if (NULL != (p = strchr(config->haddr[i], ':')) && (0 < (config->hport[i] = atoi(p + 1)))) { *p = '\0'; } else { log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr[i]); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } if (*config->haddr[i] == '\0') { /* * Only the port specified. We stored it in config->hport[i] * and don't need its text representation anymore. * Use config->hport[i] == 0 to iterate listening addresses since * now. */ freez(config->haddr[i]); } } /* * Want to run all the loaders once now. * * Need to set up a fake csp, so they can get to the config. */ fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp)); fake_csp->config = config; if (run_loader(fake_csp)) { freez(fake_csp); log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting."); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } freez(fake_csp); /* FIXME: this is a kludge for win32 */ #if defined(_WIN32) && !defined (_WIN_CONSOLE) g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */ g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */ g_default_filterfile = config->re_filterfile[0]; /* FIXME Hope this is default.filter */ g_user_filterfile = config->re_filterfile[1]; /* FIXME Hope this is user.filter */ #ifdef FEATURE_TRUST g_trustfile = config->trustfile; #endif /* def FEATURE_TRUST */ #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */ /* FIXME: end kludge */ config->need_bind = 1; if (current_configfile) { struct configuration_spec * oldcfg = (struct configuration_spec *) current_configfile->f; /* * Check if config->haddr[i],hport[i] == oldcfg->haddr[i],hport[i] * * The following could be written more compactly as a single, * (unreadably long) if statement. */ config->need_bind = 0; for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { if (config->hport[i] != oldcfg->hport[i]) { config->need_bind = 1; } else if (config->haddr[i] == NULL) { if (oldcfg->haddr[i] != NULL) { config->need_bind = 1; } } else if (oldcfg->haddr[i] == NULL) { config->need_bind = 1; } else if (0 != strcmp(config->haddr[i], oldcfg->haddr[i])) { config->need_bind = 1; } } current_configfile->unloader = unload_configfile; } fs->next = files->next; files->next = fs; current_configfile = fs; return (config); } /********************************************************************* * * Function : savearg * * Description : Called from `load_config'. It saves each non-empty * and non-comment line from config into * config->proxy_args. This is used to create the * show-proxy-args page. On error, frees * config->proxy_args and sets it to NULL * * Parameters : * 1 : command = config setting that was found * 2 : argument = the setting's argument (if any) * 3 : config = Configuration to save into. * * Returns : N/A * *********************************************************************/ static void savearg(char *command, char *argument, struct configuration_spec * config) { char * buf; char * s; assert(command); assert(argument); /* * Add config option name embedded in * link to its section in the user-manual */ buf = strdup("\n
    usermanual, "file://", 7) || !strncmpic(config->usermanual, "http", 4)) { string_append(&buf, config->usermanual); } else { string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/"); } string_append(&buf, CONFIG_HELP_PREFIX); string_join (&buf, string_toupper(command)); string_append(&buf, "\">"); string_append(&buf, command); string_append(&buf, " "); if (NULL == buf) { freez(config->proxy_args); return; } if ((NULL != argument) && ('\0' != *argument)) { s = html_encode(argument); if (NULL == s) { freez(buf); freez(config->proxy_args); return; } if (strncmpic(argument, "http://", 7) == 0) { string_append(&buf, ""); string_join (&buf, s); string_append(&buf, ""); } else { string_join (&buf, s); } } string_append(&buf, "
    "); string_join(&config->proxy_args, buf); } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./privoxy-generic.init000750 001751 001751 00000010355 12100755411 020003 0ustar00fkfk000000 000000 #!/bin/sh ########################################################################### # # File : $Source: /cvsroot/ijbswa/current/privoxy-generic.init,v $ # # Purpose : This script takes care of starting and stopping privoxy. # It is supposed to work cross-platform and thus doesn't # do too much. When packaging Privoxy it's recommended to # write a platform-specific start script instead of using # this one. # # Copyright : Written by and Copyright (C) 2001,2002 the # Privoxy team. http://www.privoxy.org/ # # This program is free software; you can redistribute it # and/or modify it under the terms of the GNU General # Public License as published by the Free Software # Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public # License for more details. # # The GNU General Public License should be included with # this file. If not, you can view it at # http://www.gnu.org/copyleft/gpl.html # or write to the Free Software Foundation, Inc., 59 # Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ########################################################################### ### BEGIN INIT INFO # Provides: privoxy # Required-Start: # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start privoxy at boot time # Description: Start and stop the privacy-enhancing HTTP proxy privoxy. ### END INIT INFO # NOTE: This script may require editing to ensure proper location of # config file, and the privoxy executable. Care should be taken to ensure # logfile is writable by $P_USER (logfile is defined in config), and that # there is suitable write access for $P_PIDFILE. PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/xpg4/bin:/usr/bin:/sbin:/bin P_NAME=Privoxy # Path to executable. P_DAEMON=privoxy # Full path to location of Privoxy config file. P_CONF_FILE=/usr/local/etc/privoxy/config # Full path to PID file location. Location must be writable by # whoever runs this script and by Privoxy itself. P_PIDFILE=/var/run/privoxy.pid # If uncommented, this script will try to run as USER=privoxy, which # may require special handling of config, *.action, trust, logfile, # jarfile, and pidfile. P_USER=privoxy # If a privoxy user is specified, lets try that. /bin/sh does not seem to # know about $UID. if [ 0 = `id -u` ]; then if [ -n "$P_USER" ]; then id $P_USER 2>/dev/null >/dev/null if [ $? -eq 0 ]; then P_USER_SETTINGS="--user $P_USER" else echo "User $P_USER doesn't exist, exiting." exit 1 fi else # The user has sufficient rights, but $P_USER isn't set echo "Running Privoxy as root is not recommended!" P_USER_SETTINGS="" fi else # The user has insufficient rights to run Privoxy as $P_USER # and may not be able to write or delete the PID file. echo "You aren't root, expect trouble!" P_USER_SETTINGS="" fi if [ ! -f $P_CONF_FILE ]; then echo "Can't find $P_CONF_FILE, exiting." exit 1 fi case "$1" in start) if [ -f $P_PIDFILE ]; then if kill -0 `cat $P_PIDFILE`; then echo "Error: $P_NAME is already running, exiting." exit 1 else rm -f $P_PIDFILE fi fi $P_DAEMON --pidfile $P_PIDFILE $P_USER_SETTINGS $P_CONF_FILE 2>/dev/null if [ $? -eq 0 ]; then echo "Starting $P_NAME, OK." else echo "Starting $P_NAME, Failed." rm -f $P_PIDFILE fi ;; restart) $0 stop $0 start ;; stop) test ! -f $P_PIDFILE && echo "No $P_PIDFILE file found, exiting." && exit 1 kill `cat $P_PIDFILE` && rm -f $P_PIDFILE && \ echo "Stopping $P_NAME, OK." || echo "Stopping $P_NAME, failed." ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 ;; esac exit 0 privoxy-3.0.21-stable/./win32.c000640 001751 001751 00000020477 11726427226 015113 0ustar00fkfk000000 000000 const char win32_rcs[] = "$Id: win32.c,v 1.19 2012/03/09 16:23:50 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/win32.c,v $ * * Purpose : Win32 User Interface initialization and message loop * * Copyright : Written by and Copyright (C) 2001-2002 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 1999 Adam Lock * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifdef _WIN32 #include #include "project.h" #include "jcc.h" #include "miscutil.h" /* Uncomment this if you want to build Win32 as a console app */ /* #define _WIN_CONSOLE */ #ifndef STRICT #define STRICT #endif #include #include #include #if defined(_WIN32) && defined(_MSC_VER) && defined(_DEBUG) /* Visual C++ Heap debugging */ #include #endif /* defined(_WIN32) && defined(_MSC_VER) && defined(_DEBUG) */ #include "win32.h" const char win32_h_rcs[] = WIN32_H_VERSION; /** * A short introductory text about Privoxy. Used for the "About" box * or the console startup message. */ const char win32_blurb[] = "Privoxy version " VERSION " for Windows\n" "Copyright (C) 2000-2010 the Privoxy Team (" HOME_PAGE_URL ")\n" "Based on the Internet Junkbuster by Junkbusters Corp.\n" "This is free software; it may be used and copied under the\n" "GNU General Public License, version 2: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n" "This program comes with ABSOLUTELY NO WARRANTY OF ANY KIND.\n"; #ifdef _WIN_CONSOLE /** * Hide the console. If set, the program will disconnect from the * console and run in the background. This allows the command-prompt * window to close. */ int hideConsole = 0; #else /* ndef _WIN_CONSOLE */ /** * The application instance handle. */ HINSTANCE g_hInstance; /** * The command to show the window that was specified at startup. */ int g_nCmdShow; static void __cdecl UserInterfaceThread(void *); #endif /* ndef _WIN_CONSOLE */ /********************************************************************* * * Function : WinMain * * Description : M$ Windows "main" routine: * parse the `lpCmdLine' param into main's argc and argv variables, * start the user interface thread (for the systray window), and * call main (i.e. patch execution into normal startup). * * Parameters : * 1 : hInstance = instance handle of this execution * 2 : hPrevInstance = instance handle of previous execution * 3 : lpCmdLine = command line string which started us * 4 : nCmdShow = window show value (MIN, MAX, NORMAL, etc...) * * Returns : `main' never returns, so WinMain will also never return. * *********************************************************************/ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { #if 0 /* See comment about __argc & __argv below */ int i; int argc = 1; const char *argv[3]; char szModule[MAX_PATH+1]; #endif int res; #ifndef _WIN_CONSOLE HANDLE hInitCompleteEvent = NULL; #endif #if defined(_WIN32) && defined(_MSC_VER) && defined(_DEBUG) #if 0 /* Visual C++ Heap debugging */ /* Get current flag*/ int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); /* Turn on leak-checking bit */ tmpFlag |= _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF; /* Turn off CRT block checking bit */ tmpFlag &= ~(_CRTDBG_CHECK_CRT_DF | _CRTDBG_DELAY_FREE_MEM_DF); /* Set flag to the new value */ _CrtSetDbgFlag(tmpFlag); #endif #endif /* defined(_WIN32) && defined(_MSC_VER) && defined(_DEBUG) */ /************ * I couldn't figure out why the command line was being sorta parsed here * instead of using the __argc & __argv globals usually defined in stdlib.h * * From what I can tell by looking at the MinWG source, it supports these * globals, so i'd hope that the other compilers do so as well. * Obviously, if i'm wrong i'll find out soon enough! :) ************/ #if 0 /* * Cheat in parsing the command line. We only ever have at most one * paramater, which may optionally be specified inside double quotes. */ if (lpCmdLine != NULL) { /* Make writable copy */ lpCmdLine = strdup(lpCmdLine); } if (lpCmdLine != NULL) { chomp(lpCmdLine); i = strlen(lpCmdLine); if ((i >= 2) && (lpCmdLine[0] == '\"') && (lpCmdLine[i - 1] == '\"')) { lpCmdLine[i - 1] = '\0'; lpCmdLine++; } if (lpCmdLine[0] == '\0') { lpCmdLine = NULL; } } GetModuleFileName(hInstance, szModule, MAX_PATH); argv[0] = szModule; argv[1] = lpCmdLine; argv[2] = NULL; argc = ((lpCmdLine != NULL) ? 2 : 1); #endif /* -END- 0 */ #ifndef _WIN_CONSOLE /* Create a user-interface thread and wait for it to initialise */ hInitCompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); g_hInstance = hInstance; g_nCmdShow = nCmdShow; _beginthread(UserInterfaceThread, 0, &hInitCompleteEvent); WaitForSingleObject(hInitCompleteEvent, INFINITE); DeleteObject(hInitCompleteEvent); #endif #ifdef __MINGW32__ res = real_main(__argc, __argv); #else res = main(__argc, __argv); #endif return res; } #endif /********************************************************************* * * Function : InitWin32 * * Description : Initialise windows, setting up the console or windows as appropriate. * * Parameters : None * * Returns : N/A * *********************************************************************/ void InitWin32(void) { WORD wVersionRequested; WSADATA wsaData; #ifdef _WIN_CONSOLE SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY); if (hideConsole) { FreeConsole(); } #endif wVersionRequested = MAKEWORD(2, 0); if (WSAStartup(wVersionRequested, &wsaData) != 0) { #ifndef _WIN_CONSOLE MessageBox(NULL, "Cannot initialize WinSock library", "Privoxy Error", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); #endif exit(1); } } #ifndef _WIN_CONSOLE #include #include #include "win32.h" #include "w32log.h" /********************************************************************* * * Function : UserInterfaceThread * * Description : User interface thread. WinMain will wait for us to set * the hInitCompleteEvent before patching over to `main'. * This ensures the systray window is active before beginning * operations. * * Parameters : * 1 : pData = pointer to `hInitCompleteEvent'. * * Returns : N/A * *********************************************************************/ static void __cdecl UserInterfaceThread(void *pData) { MSG msg; HANDLE hInitCompleteEvent = *((HANDLE *) pData); /* Initialise */ InitLogWindow(); SetEvent(hInitCompleteEvent); /* Enter a message processing loop */ while (GetMessage(&msg, (HWND) NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } /* Cleanup */ TermLogWindow(); /* Time to die... */ exit(0); } #endif /* ndef _WIN_CONSOLE */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./cgisimple.h000640 001751 001751 00000011701 11630656300 016107 0ustar00fkfk000000 000000 #ifndef CGISIMPLE_H_INCLUDED #define CGISIMPLE_H_INCLUDED #define CGISIMPLE_H_VERSION "$Id: cgisimple.h,v 1.18 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgisimple.h,v $ * * Purpose : Declares functions to intercept request, generate * html or gif answers, and to compose HTTP resonses. * * Functions declared include: * * * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif /* * CGI functions */ extern jb_err cgi_default (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_error_404 (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_robots_txt (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_banner (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_show_status (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_show_url_info(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_show_version (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_show_request (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_transparent_image (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_error_favicon (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_default_favicon (struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_stylesheet(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_url_info_osd(struct client_state *csp, struct http_response *rsp, const struct map *parameters); extern jb_err cgi_send_user_manual(struct client_state *csp, struct http_response *rsp, const struct map *parameters); #ifdef FEATURE_GRACEFUL_TERMINATION extern jb_err cgi_die (struct client_state *csp, struct http_response *rsp, const struct map *parameters); #endif /* Revision control strings from this header and associated .c file */ extern const char cgisimple_rcs[]; extern const char cgisimple_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef CGISIMPLE_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./project.h000640 001751 001751 00000126353 12116117562 015615 0ustar00fkfk000000 000000 #ifndef PROJECT_H_INCLUDED #define PROJECT_H_INCLUDED /** Version string. */ #define PROJECT_H_VERSION "$Id: project.h,v 1.196 2013/03/07 14:08:50 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/project.h,v $ * * Purpose : Defines data structures which are widely used in the * project. Does not define any variables or functions * (though it does declare some macros). * * Copyright : Written by and Copyright (C) 2001-2012 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ /* Declare struct FILE for vars and funcs. */ #include /* Need time_t for file_list */ #include /* Needed for pcre choice */ #include "config.h" /* Need for struct sockaddr_storage */ #ifdef HAVE_RFC2553 # ifndef _WIN32 # include # include # else # include # include # include typedef unsigned short in_port_t; # endif #endif /* * Include appropriate regular expression libraries. * Note that pcrs and pcre (native) are needed for cgi * and are included anyway. */ #ifdef STATIC_PCRE # include "pcre.h" #else # ifdef PCRE_H_IN_SUBDIR # include # else # include # endif #endif #ifdef STATIC_PCRS # include "pcrs.h" #else # include #endif #ifdef STATIC_PCRE # include "pcreposix.h" #else # ifdef PCRE_H_IN_SUBDIR # include # else # include # endif #endif #ifdef AMIGA #include "amiga.h" #endif /* def AMIGA */ #ifdef _WIN32 /* * I don't want to have to #include all this just for the declaration * of SOCKET. However, it looks like we have to... */ #ifndef STRICT #define STRICT #endif #include #endif #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 typedef SOCKET jb_socket; #define JB_INVALID_SOCKET INVALID_SOCKET #else /* ndef _WIN32 */ /** * The type used by sockets. On UNIX it's an int. Microsoft decided to * make it an unsigned. */ typedef int jb_socket; /** * The error value used for variables of type jb_socket. On UNIX this * is -1, however Microsoft decided to make socket handles unsigned, so * they use a different value. */ #define JB_INVALID_SOCKET (-1) #endif /* ndef _WIN32 */ /** * A standard error code. This should be JB_ERR_OK or one of the JB_ERR_xxx * series of errors. */ typedef int jb_err; #define JB_ERR_OK 0 /**< Success, no error */ #define JB_ERR_MEMORY 1 /**< Out of memory */ #define JB_ERR_CGI_PARAMS 2 /**< Missing or corrupt CGI parameters */ #define JB_ERR_FILE 3 /**< Error opening, reading or writing a file */ #define JB_ERR_PARSE 4 /**< Error parsing file */ #define JB_ERR_MODIFIED 5 /**< File has been modified outside of the CGI actions editor. */ #define JB_ERR_COMPRESS 6 /**< Error on decompression */ /** * This macro is used to free a pointer that may be NULL. * It also sets the variable to NULL after it's been freed. * The paramater should be a simple variable without side effects. */ #define freez(X) { if(X) { free((void*)X); X = NULL ; } } /** * Macro definitions for platforms where isspace() and friends * are macros that use their argument directly as an array index * and thus better be positive. Supposedly that's the case on * some unspecified Solaris versions. * Note: Remember to #include if you use these macros. */ #define privoxy_isdigit(__X) isdigit((int)(unsigned char)(__X)) #define privoxy_isupper(__X) isupper((int)(unsigned char)(__X)) #define privoxy_toupper(__X) toupper((int)(unsigned char)(__X)) #define privoxy_tolower(__X) tolower((int)(unsigned char)(__X)) #define privoxy_isspace(__X) isspace((int)(unsigned char)(__X)) /** * Use for statically allocated buffers if you have no other choice. * Remember to check the length of what you write into the buffer * - we don't want any buffer overflows! */ #define BUFFER_SIZE 5000 /** * Max length of CGI parameters (arbitrary limit). */ #define CGI_PARAM_LEN_MAX 500U /** * Buffer size for capturing struct hostent data in the * gethostby(name|addr)_r library calls. Since we don't * loop over gethostbyname_r, the buffer must be sufficient * to accommodate multiple IN A RRs, as used in DNS round robin * load balancing. W3C's wwwlib uses 1K, so that should be * good enough for us, too. */ /** * XXX: Temporary doubled, for some configurations * 1K is still too small and we didn't get the * real fix ready for inclusion. */ #define HOSTENT_BUFFER_SIZE 2048 /** * Do not use. Originally this was so that you can * say "while (FOREVER) { ...do something... }". * However, this gives a warning with some compilers (e.g. VC++). * Instead, use "for (;;) { ...do something... }". */ #define FOREVER 1 /** * Default TCP/IP address to listen on, as a string. * Set to "127.0.0.1:8118". */ #define HADDR_DEFAULT "127.0.0.1:8118" /* Forward def for struct client_state */ struct configuration_spec; /** * Entry in a linked list of strings. */ struct list_entry { /** * The string pointer. It must point to a dynamically malloc()ed * string or be NULL for the list functions to work. In the latter * case, just be careful next time you iterate through the list in * your own code. */ char *str; /** Next entry in the linked list, or NULL if no more. */ struct list_entry *next; }; /** * A header for a linked list of strings. */ struct list { /** First entry in the list, or NULL if the list is empty. */ struct list_entry *first; /** Last entry in the list, or NULL if the list is empty. */ struct list_entry *last; }; /** * An entry in a map. This is a name=value pair. */ struct map_entry { /** The key for the map. */ const char *name; /** The value associated with that key. */ const char *value; /** The next map entry, or NULL if none. */ struct map_entry *next; }; /** * A map from a string to another string. * This is used for the paramaters passed in a HTTP GET request, and * to store the exports when the CGI interface is filling in a template. */ struct map { /** The first map entry, or NULL if the map is empty. */ struct map_entry *first; /** The last map entry, or NULL if the map is empty. */ struct map_entry *last; }; /** * A HTTP request. This includes the method (GET, POST) and * the parsed URL. * * This is also used whenever we want to match a URL against a * URL pattern. This always contains the URL to match, and never * a URL pattern. (See struct url_spec). */ struct http_request { char *cmd; /**< Whole command line: method, URL, Version */ char *ocmd; /**< Backup of original cmd for CLF logging */ char *gpc; /**< HTTP method: GET, POST, ... */ char *url; /**< The URL */ char *ver; /**< Protocol version */ int status; /**< HTTP Status */ char *host; /**< Host part of URL */ int port; /**< Port of URL or 80 (default) */ char *path; /**< Path of URL */ char *hostport; /**< host[:port] */ int ssl; /**< Flag if protocol is https */ char *host_ip_addr_str; /**< String with dotted decimal representation of host's IP. NULL before connect_to() */ #ifndef FEATURE_EXTENDED_HOST_PATTERNS char *dbuffer; /**< Buffer with '\0'-delimited domain name. */ char **dvec; /**< List of pointers to the strings in dbuffer. */ int dcount; /**< How many parts to this domain? (length of dvec) */ #endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */ }; /** * Reasons for generating a http_response instead of delivering * the requested resource. Mostly ordered the way they are checked * for in chat(). */ enum crunch_reason { UNSUPPORTED, BLOCKED, UNTRUSTED, REDIRECTED, CGI_CALL, NO_SUCH_DOMAIN, FORWARDING_FAILED, CONNECT_FAILED, OUT_OF_MEMORY, INTERNAL_ERROR, CONNECTION_TIMEOUT, NO_SERVER_DATA }; /** * Response generated by CGI, blocker, or error handler */ struct http_response { enum crunch_reason crunch_reason; /**< Why the response was generated in the first place. */ char *status; /**< HTTP status (string). */ struct list headers[1]; /**< List of header lines. */ char *head; /**< Formatted http response head. */ size_t head_length; /**< Length of http response head. */ char *body; /**< HTTP document body. */ size_t content_length; /**< Length of body, REQUIRED if binary body. */ int is_static; /**< Nonzero if the content will never change and should be cached by the browser (e.g. images). */ }; /** * A URL or a tag pattern. */ struct url_spec { /** The string which was parsed to produce this url_spec. Used for debugging or display only. */ char *spec; #ifdef FEATURE_EXTENDED_HOST_PATTERNS regex_t *host_regex;/**< Regex for host matching */ #else char *dbuffer; /**< Buffer with '\0'-delimited domain name, or NULL to match all hosts. */ char **dvec; /**< List of pointers to the strings in dbuffer. */ int dcount; /**< How many parts to this domain? (length of dvec) */ int unanchored; /**< Bitmap - flags are ANCHOR_LEFT and ANCHOR_RIGHT. */ #endif /* defined FEATURE_EXTENDED_HOST_PATTERNS */ char *port_list; /**< List of acceptable ports, or NULL to match all ports */ regex_t *preg; /**< Regex for matching path part */ regex_t *tag_regex; /**< Regex for matching tags */ }; /** * If you declare a static url_spec, this is the value to initialize it to zero. */ #ifndef FEATURE_EXTENDED_HOST_PATTERNS #define URL_SPEC_INITIALIZER { NULL, NULL, NULL, 0, 0, NULL, NULL, NULL } #else #define URL_SPEC_INITIALIZER { NULL, NULL, NULL, NULL, NULL } #endif /* def FEATURE_EXTENDED_HOST_PATTERNS */ /** * Constant for host part matching in URLs. If set, indicates that the start of * the pattern must match the start of the URL. E.g. this is not set for the * pattern ".example.com", so that it will match both "example.com" and * "www.example.com". It is set for the pattern "example.com", which makes it * match "example.com" only, not "www.example.com". */ #define ANCHOR_LEFT 1 /** * Constant for host part matching in URLs. If set, indicates that the end of * the pattern must match the end of the URL. E.g. this is not set for the * pattern "ad.", so that it will match any host called "ad", irrespective * of how many subdomains are in the fully-qualified domain name. */ #define ANCHOR_RIGHT 2 /** * An I/O buffer. Holds a string which can be appended to, and can have data * removed from the beginning. */ struct iob { char *buf; /**< Start of buffer */ char *cur; /**< Start of relevant data */ char *eod; /**< End of relevant data */ size_t size; /**< Size as malloc()ed */ }; /** * Return the number of bytes in the I/O buffer associated with the passed * I/O buffer. May be zero. */ #define IOB_PEEK(IOB) ((IOB->cur > IOB->eod) ? (IOB->eod - IOB->cur) : 0) /* Bits for csp->content_type bitmask: */ #define CT_TEXT 0x0001U /**< Suitable for pcrs filtering. */ #define CT_GIF 0x0002U /**< Suitable for GIF filtering. */ #define CT_TABOO 0x0004U /**< DO NOT filter, irrespective of other flags. */ /* Although these are not, strictly speaking, content types * (they are content encodings), it is simple to handle them * as such. */ #define CT_GZIP 0x0010U /**< gzip-compressed data. */ #define CT_DEFLATE 0x0020U /**< zlib-compressed data. */ /** * Flag to signal that the server declared the content type, * so we can differentiate between unknown and undeclared * content types. */ #define CT_DECLARED 0x0040U /** * The mask which includes all actions. */ #define ACTION_MASK_ALL (~0UL) /** * The most compatible set of actions - i.e. none. */ #define ACTION_MOST_COMPATIBLE 0x00000000UL /** Action bitmap: Block the request. */ #define ACTION_BLOCK 0x00000001UL /** Action bitmap: Deanimate if it's a GIF. */ #define ACTION_DEANIMATE 0x00000002UL /** Action bitmap: Downgrade HTTP/1.1 to 1.0. */ #define ACTION_DOWNGRADE 0x00000004UL /** Action bitmap: Fast redirects. */ #define ACTION_FAST_REDIRECTS 0x00000008UL /** Action bitmap: Remove or add "X-Forwarded-For" header. */ #define ACTION_CHANGE_X_FORWARDED_FOR 0x00000010UL /** Action bitmap: Hide "From" header. */ #define ACTION_HIDE_FROM 0x00000020UL /** Action bitmap: Hide "Referer" header. (sic - follow HTTP, not English). */ #define ACTION_HIDE_REFERER 0x00000040UL /** Action bitmap: Hide "User-Agent" and similar headers. */ #define ACTION_HIDE_USER_AGENT 0x00000080UL /** Action bitmap: This is an image. */ #define ACTION_IMAGE 0x00000100UL /** Action bitmap: Sets the image blocker. */ #define ACTION_IMAGE_BLOCKER 0x00000200UL /** Action bitmap: Prevent compression. */ #define ACTION_NO_COMPRESSION 0x00000400UL /** Action bitmap: Change cookies to session only cookies. */ #define ACTION_SESSION_COOKIES_ONLY 0x00000800UL /** Action bitmap: Block cookies coming from the client. */ #define ACTION_CRUNCH_OUTGOING_COOKIES 0x00001000UL /** Action bitmap: Block cookies coming from the server. */ #define ACTION_CRUNCH_INCOMING_COOKIES 0x00002000UL /** Action bitmap: Override the forward settings in the config file */ #define ACTION_FORWARD_OVERRIDE 0x00004000UL /** Action bitmap: Block as empty document */ #define ACTION_HANDLE_AS_EMPTY_DOCUMENT 0x00008000UL /** Action bitmap: Limit CONNECT requests to safe ports. */ #define ACTION_LIMIT_CONNECT 0x00010000UL /** Action bitmap: Redirect request. */ #define ACTION_REDIRECT 0x00020000UL /** Action bitmap: Crunch or modify "if-modified-since" header. */ #define ACTION_HIDE_IF_MODIFIED_SINCE 0x00040000UL /** Action bitmap: Overwrite Content-Type header. */ #define ACTION_CONTENT_TYPE_OVERWRITE 0x00080000UL /** Action bitmap: Crunch specified server header. */ #define ACTION_CRUNCH_SERVER_HEADER 0x00100000UL /** Action bitmap: Crunch specified client header */ #define ACTION_CRUNCH_CLIENT_HEADER 0x00200000UL /** Action bitmap: Enable text mode by force */ #define ACTION_FORCE_TEXT_MODE 0x00400000UL /** Action bitmap: Enable text mode by force */ #define ACTION_CRUNCH_IF_NONE_MATCH 0x00800000UL /** Action bitmap: Enable content-disposition crunching */ #define ACTION_HIDE_CONTENT_DISPOSITION 0x01000000UL /** Action bitmap: Replace or block Last-Modified header */ #define ACTION_OVERWRITE_LAST_MODIFIED 0x02000000UL /** Action bitmap: Replace or block Accept-Language header */ #define ACTION_HIDE_ACCEPT_LANGUAGE 0x04000000UL /** Action bitmap: Limit the cookie lifetime */ #define ACTION_LIMIT_COOKIE_LIFETIME 0x08000000UL /** Action string index: How to deanimate GIFs */ #define ACTION_STRING_DEANIMATE 0 /** Action string index: Replacement for "From:" header */ #define ACTION_STRING_FROM 1 /** Action string index: How to block images */ #define ACTION_STRING_IMAGE_BLOCKER 2 /** Action string index: Replacement for "Referer:" header */ #define ACTION_STRING_REFERER 3 /** Action string index: Replacement for "User-Agent:" header */ #define ACTION_STRING_USER_AGENT 4 /** Action string index: Legal CONNECT ports. */ #define ACTION_STRING_LIMIT_CONNECT 5 /** Action string index: Server headers containing this pattern are crunched*/ #define ACTION_STRING_SERVER_HEADER 6 /** Action string index: Client headers containing this pattern are crunched*/ #define ACTION_STRING_CLIENT_HEADER 7 /** Action string index: Replacement for the "Accept-Language:" header*/ #define ACTION_STRING_LANGUAGE 8 /** Action string index: Replacement for the "Content-Type:" header*/ #define ACTION_STRING_CONTENT_TYPE 9 /** Action string index: Replacement for the "content-disposition:" header*/ #define ACTION_STRING_CONTENT_DISPOSITION 10 /** Action string index: Replacement for the "If-Modified-Since:" header*/ #define ACTION_STRING_IF_MODIFIED_SINCE 11 /** Action string index: Replacement for the "Last-Modified:" header. */ #define ACTION_STRING_LAST_MODIFIED 12 /** Action string index: Redirect URL */ #define ACTION_STRING_REDIRECT 13 /** Action string index: Decode before redirect? */ #define ACTION_STRING_FAST_REDIRECTS 14 /** Action string index: Overriding forward rule. */ #define ACTION_STRING_FORWARD_OVERRIDE 15 /** Action string index: Reason for the block. */ #define ACTION_STRING_BLOCK 16 /** Action string index: what to do with the "X-Forwarded-For" header. */ #define ACTION_STRING_CHANGE_X_FORWARDED_FOR 17 /** Action string index: how many minutes cookies should be valid. */ #define ACTION_STRING_LIMIT_COOKIE_LIFETIME 18 /** Number of string actions. */ #define ACTION_STRING_COUNT 19 /* To make the ugly hack in sed easier to understand */ #define CHECK_EVERY_HEADER_REMAINING 0 /** Index into current_action_spec::multi[] for headers to add. */ #define ACTION_MULTI_ADD_HEADER 0 /** Index into current_action_spec::multi[] for content filters to apply. */ #define ACTION_MULTI_FILTER 1 /** Index into current_action_spec::multi[] for server-header filters to apply. */ #define ACTION_MULTI_SERVER_HEADER_FILTER 2 /** Index into current_action_spec::multi[] for client-header filters to apply. */ #define ACTION_MULTI_CLIENT_HEADER_FILTER 3 /** Index into current_action_spec::multi[] for client-header tags to apply. */ #define ACTION_MULTI_CLIENT_HEADER_TAGGER 4 /** Index into current_action_spec::multi[] for server-header tags to apply. */ #define ACTION_MULTI_SERVER_HEADER_TAGGER 5 /** Number of multi-string actions. */ #define ACTION_MULTI_COUNT 6 /** * This structure contains a list of actions to apply to a URL. * It only contains positive instructions - no "-" options. * It is not used to store the actions list itself, only for * url_actions() to return the current values. */ struct current_action_spec { /** Actions to apply. A bit set to "1" means perform the action. */ unsigned long flags; /** * Paramaters for those actions that require them. * Each entry is valid if & only if the corresponding entry in "flags" is * set. */ char * string[ACTION_STRING_COUNT]; /** Lists of strings for multi-string actions. */ struct list multi[ACTION_MULTI_COUNT][1]; }; /** * This structure contains a set of changes to actions. * It can contain both positive and negative instructions. * It is used to store an entry in the actions list. */ struct action_spec { unsigned long mask; /**< Actions to keep. A bit set to "0" means remove action. */ unsigned long add; /**< Actions to add. A bit set to "1" means add action. */ /** * Paramaters for those actions that require them. * Each entry is valid if & only if the corresponding entry in "flags" is * set. */ char * string[ACTION_STRING_COUNT]; /** Lists of strings to remove, for multi-string actions. */ struct list multi_remove[ACTION_MULTI_COUNT][1]; /** If nonzero, remove *all* strings from the multi-string action. */ int multi_remove_all[ACTION_MULTI_COUNT]; /** Lists of strings to add, for multi-string actions. */ struct list multi_add[ACTION_MULTI_COUNT][1]; }; /** * This structure is used to store action files. * * It contains an URL or tag pattern, and the changes to * the actions. It's a linked list and should only be * free'd through unload_actions_file() unless there's * only a single entry. */ struct url_actions { struct url_spec url[1]; /**< The URL or tag pattern. */ struct action_spec *action; /**< Action settings that might be shared with the list entry before or after the current one and can't be free'd willy nilly. */ struct url_actions *next; /**< Next action section in file, or NULL. */ }; enum forwarder_type { /**< Don't use a SOCKS server */ SOCKS_NONE = 0, /**< original SOCKS 4 protocol */ SOCKS_4 = 40, /**< SOCKS 4A, DNS resolution is done by the SOCKS server */ SOCKS_4A = 41, /**< SOCKS 5 with hostnames, DNS resolution is done by the SOCKS server */ SOCKS_5 = 50, /**< Like SOCKS5, but uses non-standard Tor extensions (currently only optimistic data) */ SOCKS_5T, }; /* * Structure to hold the server socket and the information * required to make sure we only reuse the connection if * the host and forwarding settings are the same. */ struct reusable_connection { jb_socket sfd; int in_use; time_t timestamp; /* XXX: rename? */ time_t request_sent; time_t response_received; /* * Number of seconds after which this * connection will no longer be reused. */ unsigned int keep_alive_timeout; /* * Number of requests that were sent to this connection. * This is currently only for debugging purposes. */ unsigned int requests_sent_total; char *host; int port; enum forwarder_type forwarder_type; char *gateway_host; int gateway_port; char *forward_host; int forward_port; }; /* * Flags for use in csp->flags */ /** * Flag for csp->flags: Set if this client is processing data. * Cleared when the thread associated with this structure dies. */ #define CSP_FLAG_ACTIVE 0x01U /** * Flag for csp->flags: Set if the server's reply is in "chunked" * transfer encoding */ #define CSP_FLAG_CHUNKED 0x02U /** * Flag for csp->flags: Set if this request was enforced, although it would * normally have been blocked. */ #define CSP_FLAG_FORCED 0x04U /** * Flag for csp->flags: Set if any modification to the body was done. */ #define CSP_FLAG_MODIFIED 0x08U /** * Flag for csp->flags: Set if request was blocked. */ #define CSP_FLAG_REJECTED 0x10U /** * Flag for csp->flags: Set if we are toggled on (FEATURE_TOGGLE). */ #define CSP_FLAG_TOGGLED_ON 0x20U /** * Flag for csp->flags: Set if we answered the request ourselve. */ #define CSP_FLAG_CRUNCHED 0x40U /** * Flag for csp->flags: Set if an acceptable Connection header * has already been set by the client. */ #define CSP_FLAG_CLIENT_CONNECTION_HEADER_SET 0x00000040U /** * Flag for csp->flags: Set if an acceptable Connection header * has already been set by the server. */ #define CSP_FLAG_SERVER_CONNECTION_HEADER_SET 0x00000080U /** * Flag for csp->flags: Signals header parsers whether they * are parsing server or client headers. */ #define CSP_FLAG_CLIENT_HEADER_PARSING_DONE 0x00000100U /** * Flag for csp->flags: Set if adding the Host: header * isn't necessary. */ #define CSP_FLAG_HOST_HEADER_IS_SET 0x00000200U /** * Flag for csp->flags: Set if filtering is disabled by X-Filter: No * XXX: As we now have tags we might as well ditch this. */ #define CSP_FLAG_NO_FILTERING 0x00000400U /** * Flag for csp->flags: Set the client IP has appended to * an already existing X-Forwarded-For header in which case * no new header has to be generated. */ #define CSP_FLAG_X_FORWARDED_FOR_APPENDED 0x00000800U /** * Flag for csp->flags: Set if the server wants to keep * the connection alive. */ #define CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE 0x00001000U /** * Flag for csp->flags: Set if the server specified the * content length. */ #define CSP_FLAG_SERVER_CONTENT_LENGTH_SET 0x00002000U /** * Flag for csp->flags: Set if we know the content length, * either because the server set it, or we figured it out * on our own. */ #define CSP_FLAG_CONTENT_LENGTH_SET 0x00004000U /** * Flag for csp->flags: Set if the client wants to keep * the connection alive. */ #define CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE 0x00008000U /** * Flag for csp->flags: Set if we think we got the whole * client request and shouldn't read any additional data * coming from the client until the current request has * been dealt with. */ #define CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ 0x00010000U /** * Flag for csp->flags: Set if the server promised us to * keep the connection open for a known number of seconds. */ #define CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET 0x00020000U /** * Flag for csp->flags: Set if we think we can't reuse * the server socket. XXX: It's also set after sabotaging * pipelining attempts which is somewhat inconsistent with * the name. */ #define CSP_FLAG_SERVER_SOCKET_TAINTED 0x00040000U /** * Flag for csp->flags: Set if the Proxy-Connection header * is among the server headers. */ #define CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET 0x00080000U /** * Flag for csp->flags: Set if the client reused its connection. */ #define CSP_FLAG_REUSED_CLIENT_CONNECTION 0x00100000U /** * Flag for csp->flags: Set if the supports deflate compression. */ #define CSP_FLAG_CLIENT_SUPPORTS_DEFLATE 0x00200000U /** * Flag for csp->flags: Set if the content has been deflated by Privoxy */ #define CSP_FLAG_BUFFERED_CONTENT_DEFLATED 0x00400000U /** * Flag for csp->flags: Set if we already read (parts of) * a pipelined request in which case the client obviously * isn't done talking. */ #define CSP_FLAG_PIPELINED_REQUEST_WAITING 0x00800000U /** * Flag for csp->flags: Set if the client body is chunk-encoded */ #define CSP_FLAG_CHUNKED_CLIENT_BODY 0x01000000U /* * Flags for use in return codes of child processes */ /** * Flag for process return code: Set if exiting porcess has been toggled * during its lifetime. */ #define RC_FLAG_TOGGLED 0x10 /** * Flag for process return code: Set if exiting porcess has blocked its * request. */ #define RC_FLAG_BLOCKED 0x20 /** * Maximum number of actions/filter files. This limit is arbitrary - it's just used * to size an array. */ #define MAX_AF_FILES 30 /** * Maximum number of sockets to listen to. This limit is arbitrary - it's just used * to size an array. */ #define MAX_LISTENING_SOCKETS 10 /** * The state of a Privoxy processing thread. */ struct client_state { /** The proxy's configuration */ struct configuration_spec * config; /** The actions to perform on the current request */ struct current_action_spec action[1]; /** socket to talk to client (web browser) */ jb_socket cfd; /** Number of requests received on the client socket. */ unsigned int requests_received_total; /** current connection to the server (may go through a proxy) */ struct reusable_connection server_connection; /** Multi-purpose flag container, see CSP_FLAG_* above */ unsigned int flags; /** Client PC's IP address, as reported by the accept() function. As a string. */ char *ip_addr_str; #ifdef HAVE_RFC2553 /** Client PC's TCP address, as reported by the accept() function. As a sockaddr. */ struct sockaddr_storage tcp_addr; #else /** Client PC's IP address, as reported by the accept() function. As a number. */ unsigned long ip_addr_long; #endif /* def HAVE_RFC2553 */ /** The URL that was requested */ struct http_request http[1]; /* * The final forwarding settings. * XXX: Currently this is only used for forward-override, * so we can free the space in sweep. */ struct forward_spec * fwd; /** An I/O buffer used for buffering data read from the server */ /* XXX: should be renamed to server_iob */ struct iob iob[1]; /** An I/O buffer used for buffering data read from the client */ struct iob client_iob[1]; /** List of all headers for this request */ struct list headers[1]; /** List of all tags that apply to this request */ struct list tags[1]; /** MIME-Type key, see CT_* above */ unsigned int content_type; /** Actions files associated with this client */ struct file_list *actions_list[MAX_AF_FILES]; /** pcrs job files. */ struct file_list *rlist[MAX_AF_FILES]; /** Length after content modification. */ unsigned long long content_length; /* XXX: is this the right location? */ /** Expected length of content after which we * should stop reading from the server socket. */ unsigned long long expected_content_length; /** Expected length of content after which we * should stop reading from the client socket. */ unsigned long long expected_client_content_length; #ifdef FEATURE_TRUST /** Trust file. */ struct file_list *tlist; #endif /* def FEATURE_TRUST */ /** * Failure reason to embedded in the CGI error page, * or NULL. Currently only used for socks errors. */ char *error_message; }; /** * List of client states so the main thread can keep * track of them and garbage collect their resources. */ struct client_states { struct client_states *next; struct client_state csp; }; /** * A function to add a header */ typedef jb_err (*add_header_func_ptr)(struct client_state *); /** * A function to process a header */ typedef jb_err (*parser_func_ptr )(struct client_state *, char **); /** * List of available CGI functions. */ struct cgi_dispatcher { /** The URL of the CGI, relative to the CGI root. */ const char * const name; /** The handler function for the CGI */ jb_err (* const handler)(struct client_state *csp, struct http_response *rsp, const struct map *parameters); /** The description of the CGI, to appear on the main menu, or NULL to hide it. */ const char * const description; /** A flag that indicates whether unintentional calls to this CGI can cause damage */ int harmless; }; /** * A data file used by Privoxy. Kept in a linked list. */ struct file_list { /** * This is a pointer to the data structures associated with the file. * Read-only once the structure has been created. */ void *f; /** * The unloader function. * Normally NULL. When we are finished with file (i.e. when we have * loaded a new one), set to a pointer to an unloader function. * Unloader will be called by sweep() (called from main loop) when * all clients using this file are done. This prevents threading * problems. */ void (*unloader)(void *); /** * Used internally by sweep(). Do not access from elsewhere. */ int active; /** * File last-modified time, so we can check if file has been changed. * Read-only once the structure has been created. */ time_t lastmodified; /** * The full filename. */ char * filename; /** * Pointer to next entry in the linked list of all "file_list"s. * This linked list is so that sweep() can navigate it. * Since sweep() can remove items from the list, we must be careful * to only access this value from main thread (when we know sweep * won't be running). */ struct file_list *next; }; #ifdef FEATURE_TRUST /** * The format of a trust file when loaded into memory. */ struct block_spec { struct url_spec url[1]; /**< The URL pattern */ int reject; /**< FIXME: Please document this! */ struct block_spec *next; /**< Next entry in linked list */ }; /** * Arbitrary limit for the number of trusted referrers. */ #define MAX_TRUSTED_REFERRERS 512 #endif /* def FEATURE_TRUST */ /** * How to forward a connection to a parent proxy. */ struct forward_spec { /** URL pattern that this forward_spec is for. */ struct url_spec url[1]; /** Connection type. Must be SOCKS_NONE, SOCKS_4, SOCKS_4A or SOCKS_5. */ enum forwarder_type type; /** SOCKS server hostname. Only valid if "type" is SOCKS_4 or SOCKS_4A. */ char *gateway_host; /** SOCKS server port. */ int gateway_port; /** Parent HTTP proxy hostname, or NULL for none. */ char *forward_host; /** Parent HTTP proxy port. */ int forward_port; /** Next entry in the linked list. */ struct forward_spec *next; }; /** * Initializer for a static struct forward_spec. */ #define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL } /* Supported filter types */ enum filter_type { FT_CONTENT_FILTER = 0, FT_CLIENT_HEADER_FILTER = 1, FT_SERVER_HEADER_FILTER = 2, FT_CLIENT_HEADER_TAGGER = 3, FT_SERVER_HEADER_TAGGER = 4, FT_INVALID_FILTER = 42, }; #define MAX_FILTER_TYPES 5 /** * This struct represents one filter (one block) from * the re_filterfile. If there is more than one filter * in the file, the file will be represented by a * chained list of re_filterfile specs. */ struct re_filterfile_spec { char *name; /**< Name from FILTER: statement in re_filterfile. */ char *description; /**< Description from FILTER: statement in re_filterfile. */ struct list patterns[1]; /**< The patterns from the re_filterfile. */ pcrs_job *joblist; /**< The resulting compiled pcrs_jobs. */ enum filter_type type; /**< Filter type (content, client-header, server-header). */ int dynamic; /**< Set to one if the pattern might contain variables and has to be recompiled for every request. */ struct re_filterfile_spec *next; /**< The pointer for chaining. */ }; #ifdef FEATURE_ACL #define ACL_PERMIT 1 /**< Accept connection request */ #define ACL_DENY 2 /**< Reject connection request */ /** * An IP address pattern. Used to specify networks in the ACL. */ struct access_control_addr { #ifdef HAVE_RFC2553 struct sockaddr_storage addr; /* # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ########################################################################## use strict; use warnings; my @entries; sub read_entries() { my $section_reached = 0; my $i = -1; while (<>) { if (/^\*{3} /) { last if $section_reached; $section_reached = 1; next; } next unless $section_reached; next if /^\s*$/; if (/^(\s*)-/) { my $indentation = length($1); if ($i > 1 and $entries[$i]{indentation} > $indentation) { $entries[$i]{last_list_item} = 1; } $i++; $entries[$i]{description} = ''; $entries[$i]{indentation} = $indentation; } if (/:\s*$/) { $entries[$i]{list_header} = 1; } s@^\s*-?\s*@@; $entries[$i]{description} .= $_; } if ($entries[$i]{indentation} != 0) { $entries[$i]{last_list_item} = 1; } print "Parsed " . @entries . " entries.\n"; } sub create_listitem_markup($) { my $entry = shift; my $description = $entry->{description}; my $markup = ''; my $default_lws = ' '; my $lws = $default_lws x ($entry->{indentation} ? 2 : 1); chomp $description; $description =~ s@\n@\n ${lws}@g; $markup .= $lws . "\n" . $lws . " \n"; $markup .= $lws . " " . $description . "\n"; if (defined $entry->{list_header}) { $markup .= $lws . " \n"; } else { if (defined $entry->{last_list_item}) { $markup .= $lws . " \n"; $markup .= $lws . " \n"; $markup .= $lws . "\n"; $lws = $default_lws; } $markup .= $lws . " \n" . $lws . "\n"; } return $markup; } sub wrap_in_para_itemlist_markup($) { my $content = shift; my $markup = "\n" . " \n" . " $content" . " \n" . "\n"; return $markup; } sub generate_markup() { my $markup = ''; foreach my $entry (@entries) { $markup .= create_listitem_markup(\%{$entry}); } print wrap_in_para_itemlist_markup($markup); } sub main () { read_entries(); generate_markup(); } main(); privoxy-3.0.21-stable/./utils/docbook2man/docbook2man-spec.pl000640 001751 001751 00000066631 10546014102 023010 0ustar00fkfk000000 000000 =head1 NAME docbook2man-spec - convert DocBook RefEntries to Unix manpages =head1 SYNOPSIS The SGMLSpm package from CPAN. This contains the sgmlspl script which is used to grok this file. Use it like this: nsgmls some-docbook-document.sgml | sgmlspl docbook2man-spec.pl =head1 DESCRIPTION This is a sgmlspl spec file that produces Unix-style manpages from RefEntry markup. See the accompanying RefEntry man page for 'plain new' documentation. :) =head1 LIMITATIONS Trying docbook2man on non-DocBook or non-conformant SGML results in undefined behavior. :-) This program is a slow, dodgy Perl script. This program does not come close to supporting all the possible markup in DocBook, and will produce wrong output in some cases with supported markup. =head1 TODO Add new element handling and fix existing handling. Be robust. Produce cleanest, readable man output as possible (unlike some other converters). Follow Linux man(7) convention. If this results in added logic in this script, that's okay. The code should still be reasonably organized. Make it faster. If Perl sucks port it to another language. =head1 COPYRIGHT Copyright (C) 1998-1999 Steve Cheng This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, please write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. =cut # $Id: docbook2man-spec.pl,v 1.4 2006/07/18 14:49:14 david__schmidt Exp $ use SGMLS; # Use the SGMLS package. use SGMLS::Output; # Use stack-based output. use SGMLS::Refs; ######################################################################## # SGMLSPL script produced automatically by the script sgmlspl.pl # # Document Type: any, but processes only RefEntries # Edited by: me :) ######################################################################## $write_manpages = 0; $blank_xrefs = 0; sgml('start', sub { push_output('nul'); $raw_cdata = 1; # Makes it a bit faster. # Links file open(LINKSFILE, ">manpage.links"); $Refs = new SGMLS::Refs("manpage.refs"); }); sgml('end', sub { close(LINKSFILE); if($blank_xrefs) { print STDERR "Warning: output contains unresolved XRefs\n"; } }); ######################################################################## # # Output helpers # ######################################################################## # Our own version of sgml() and output() to allow simple string output # to play well with roff's stupid whitespace rules. sub man_sgml { if(ref($_[1]) eq 'CODE') { return &sgml; } my $s = $_[1]; $s =~ s/\\/\\\\/g; $s =~ s/'/\\'/g; # \n at the beginning means start at beginning of line if($s =~ s/^\n//) { $sub = 'sub { output "\n" unless $newline_last++; '; if($s eq '') { sgml($_[0], eval('sub { output "\n" unless $newline_last++; }')); } elsif($s =~ /\n$/) { sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last++; output '$s'; }")); } else { sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }")); } } else { if($s =~ /\n$/) { sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }")); } else { sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }")); } } } sub man_output { $_ = shift; if(s/^\n//) { output "\n" unless $newline_last++; } return if $_ eq ''; output $_; if(@_) { output @_; $newline_last = (pop(@_) =~ /\n$/); } else { $newline_last = ($_ =~ /\n$/) } } # Fold lines into one, quote some characters sub fold_string { $_ = shift; s/\\/\\\\/g; s/"/\\\&"/g; # Change tabs to spaces tr/\t\n/ /; # Trim whitespace from beginning and end. s/^ +//; s/ +$//; return $_; } sub save_cdata() { $raw_cdata++; push_output('string'); } sub bold_on() { # If the last font is also bold, don't change anything. # Basically this is to just get more readable man output. if($fontstack[$#fontstack] ne 'bold') { if(!$raw_cdata) { output '\fB'; $newline_last = 0; } } push(@fontstack, 'bold'); } sub italic_on() { # If the last font is also italic, don't change anything. if($fontstack[$#fontstack] ne 'italic') { if(!$raw_cdata) { output '\fI'; $newline_last = 0; } } push(@fontstack, 'italic'); } sub font_off() { my $thisfont = pop(@fontstack); my $lastfont = $fontstack[$#fontstack]; # Only output font change if it is different if($thisfont ne $lastfont) { if($raw_cdata) { return; } elsif($lastfont eq 'bold') { output '\fB'; } elsif($lastfont eq 'italic') { output '\fI'; } else { output '\fR'; } $newline_last = 0; } } ######################################################################## # # Manpage management # ######################################################################## sgml('', sub { # This will be overwritten at end of REFMETA, when we know the name of the page. pop_output(); $write_manpages = 1; # Currently writing manpage. $nocollapse_whitespace = 0; # Current whitespace collapse counter. $newline_last = 1; # At beginning of line? # Just a bit of warning, you will see this variable manipulated # manually a lot. It makes the code harder to follow but it # saves you from having to worry about collapsing at the end of # parse, stopping at verbatims, etc. $raw_cdata = 0; # Instructs certain output functions to # leave CDATA alone, so we can assign # it to a string and process it, etc. @fontstack = (); # Fonts being activated. $manpage_title = ''; # Needed for indexing. $manpage_sect = ''; @manpage_names = (); $manpage_misc = ''; $list_nestlevel = 0; # Indent certain nested content. }); sgml('', sub { if(!$newline_last) { output "\n"; } $write_manpages = 0; $raw_cdata = 1; push_output('nul'); }); sgml('', sub { push_output('file', "$manpage_title.$manpage_sect"); output <<_END_BANNER; .\\" This manpage has been automatically generated by docbook2man .\\" from a DocBook document. This tool can be found at: .\\" .\\" Please send any bug reports, improvements, comments, patches, .\\" etc. to Steve Cheng . _END_BANNER my $manpage_date = `date "+%d %B %Y"`; output '.TH "'; # If the title is not mixed-case, convention says to # uppercase the whole title. (The canonical title is # lowercase.) if($manpage_title =~ /[A-Z]/) { output fold_string($manpage_title); } else { output uc(fold_string($manpage_title)); } output '" "', fold_string($manpage_sect), '" "', fold_string(`date "+%d %B %Y"`), '" "', $manpage_misc, '" "', $manpage_manual, "\"\n"; $newline_last = 1; # References to this RefEntry. my $id = $_[0]->parent->attribute('ID')->value; if($id ne '') { # The 'package name' part of the section should # not be used when citing it. my ($sectnum) = ($manpage_sect =~ /([0-9]*)/); if($_[0]->parent->attribute('XREFLABEL')->value eq '') { $Refs->put("refentry:$id", "$manpage_title($sectnum)"); } else { $Refs->put("refentry:$id", $_[0]->parent->attribute('XREFLABEL')->value . "($sectnum)"); } } }); sgml('', sub { if($_[0]->in('REFMETA')) { save_cdata(); } else { # Manpage citations are in bold. bold_on(); } }); sgml('', sub { if($_[0]->in('REFMETA')) { $raw_cdata--; $manpage_title = pop_output(); } else { font_off(); } }); sgml('', sub { if($_[0]->in('REFMETA')) { save_cdata(); } else { # Manpage citations use (). output '('; } }); sgml('', sub { if($_[0]->in('REFMETA')) { $raw_cdata--; $manpage_sect = pop_output(); } else { output ')' } }); sgml('', \&save_cdata); sgml('', sub { $raw_cdata--; $manpage_misc = fold_string(pop_output()); }); # NAME section man_sgml('', "\n.SH NAME\n"); sgml('', \&save_cdata); sgml('', sub { $raw_cdata--; push(@manpage_names, pop_output()); }); sgml('', \&save_cdata); sgml('', sub { $raw_cdata--; my $manpage_purpose = fold_string(pop_output()); for(my $i = 0; $i < $#manpage_names; $i++) { output fold_string($manpage_names[$i]), ', '; } output fold_string($manpage_names[$#manpage_names]); output " \\- $manpage_purpose\n"; $newline_last = 1; foreach(@manpage_names) { # Don't link to itself if($_ ne $manpage_title) { print LINKSFILE "$manpage_title.$manpage_sect $_.$manpage_sect\n"; } } }); man_sgml('', "\n.sp\n"); #RefDescriptor ######################################################################## # # SYNOPSIS section and synopses # ######################################################################## man_sgml('', "\n.SH SYNOPSIS\n"); man_sgml('', "\n"); ## FIXME! Must be made into block elements!! #sgml('', \&bold_on); #sgml('', \&font_off); #sgml('', \&bold_on); #sgml('', \&font_off); man_sgml('', sub { man_output("\n.sp\n"); bold_on(); }); man_sgml('', sub { font_off(); man_output("\n"); }); man_sgml('', "\n\n"); man_sgml('', "\n\n"); man_sgml('', "\n.sp\n"); # Arguments to functions. This is C convention. sub paramdef { if($_[0]->parent->ext->{'inparams'}) { output ', '; } else { output ' ('; $_[0]->parent->ext->{'inparams'} = 1; } } man_sgml('', \¶mdef); man_sgml('', ");\n"); man_sgml('', "(void"); man_sgml('', "(..."); sub group_start { if(not $_[0]->parent->in('TERM')) { if($_[0]->attribute('CHOICE')->value =~ /opt/i) { output ' ['; } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) { output ' {'; } } $_[0]->ext->{'count'} = 1; } sub group_end { if($_[0]->attribute('REP')->value =~ /^Repeat/i) { italic_on(); output ' ...'; font_off(); } if(not $_[0]->parent->in('TERM')) { if($_[0]->attribute('CHOICE')->value =~ /opt/i) { output ' ]'; } elsif($_[0]->attribute('CHOICE')->value =~ /req/i) { output ' }'; } } } sub arg_start { # my $choice = $_[0]->attribute('CHOICE')->value; # The content model for CmdSynopsis doesn't include #PCDATA, # so we won't see any of the whitespace in the source file, # so we have to add it after each component. output ' '; if($_[0]->in('GROUP')) { output '| ' if $_[0]->parent->ext->{'count'} > 1; $_[0]->parent->ext->{'count'}++; } elsif($_[0]->attribute('CHOICE')->value =~ /opt/i) { output '[ '; } bold_on(); } sub arg_end { font_off(); if($_[0]->attribute('REP')->value =~ /^Repeat/i) { italic_on(); output ' ...'; font_off(); } if($_[0]->attribute('CHOICE')->value =~ /opt/i and not $_[0]->in('GROUP')) { output ' ]'; } } sgml('', \&arg_start); sgml('', \&arg_end); sgml('', \&group_start); sgml('', \&group_end); sgml('', \&font_off); man_sgml('', "\n "); ######################################################################## # # General sections # ######################################################################## # The name of the section is handled by TITLE. This just sets # up the roff markup. man_sgml('', "\n.SH "); man_sgml('', "\n.SS "); man_sgml('', "\n.SS "); ######################################################################## # # Titles, metadata. # ######################################################################## sgml('', sub { if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) { $write_manpages = 1; } save_cdata(); }); sgml('', sub { my $title = fold_string(pop_output()); $raw_cdata--; if($_[0]->in('REFERENCE') or $_[0]->in('BOOK')) { # We use TITLE of enclosing Reference or Book as manual name $manpage_manual = $title; $write_manpages = 0; } elsif(exists $_[0]->parent->ext->{'title'}) { # By far the easiest case. Just fold the string as # above, and then set the parent element's variable. $_[0]->parent->ext->{'title'} = $title; } else { # If the parent element's handlers are lazy, # output the folded string for them :) # We assume they want uppercase and a newline. output '"', uc($title), "\"\n"; $newline_last = 1; } }); sgml('', sub { push_output('string') }); sgml('', sub { $_[0]->parent->ext->{'attribution'} = pop_output(); }); # IGNORE. sgml('', sub { push_output('nul'); }); sgml('', sub { pop_output(); }); sgml('', sub { push_output('nul'); }); sgml('', sub { pop_output(); }); sgml('', sub { push_output('nul'); }); sgml('', sub { pop_output(); }); sgml('', sub { push_output('nul'); }); sgml('', sub { pop_output(); }); sgml('', sub { push_output('nul'); }); sgml('', sub { pop_output(); }); ######################################################################## # # Set bold on enclosed content # ######################################################################## sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); # ERRORTYPE sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); # GUILABEL # GUIMENU # GUIMENUITEM # GUISUBMENU # MENUCHOICE # MOUSEBUTTON sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); # KEYCODE # KEYCOMBO # SHORTCUT sgml('', \&bold_on); sgml('', \&font_off); sgml('', \&bold_on); sgml('', \&font_off); # May need to look at the CLASS sgml('', \&bold_on); sgml('', \&font_off); ######################################################################## # # Set italic on enclosed content # ######################################################################## sgml('', \&italic_on); sgml('', \&font_off); sgml('', \&italic_on); sgml('', \&font_off); sgml('', \&italic_on); sgml('', \&font_off); sgml('', \&italic_on); sgml('', \&font_off); sgml('', sub { italic_on(); if($_[0]->in('TOKEN')) { # When tokenizing, follow more 'intuitive' convention output "<"; } }); sgml('', sub { if($_[0]->in('TOKEN')) { output ">"; } font_off(); }); sgml('', \&italic_on); sgml('', \&font_off); sgml('', \&italic_on); sgml('', \&font_off); sgml('', \&italic_on); sgml('', \&font_off); ######################################################################## # # Other 'inline' elements # ######################################################################## man_sgml('', '<'); man_sgml('', '>'); man_sgml('', '['); man_sgml('', ']'); man_sgml('', "\\u\\s-2TM\\s+2\\d"); man_sgml('', "[Comment: "); man_sgml('', "]"); man_sgml('', "``"); man_sgml('', "''"); #man_sgml('', '"'); #man_sgml('', '"'); # No special presentation: # AUTHOR # AUTHORINITIALS # ABBREV # ACTION # ACRONYM # ALT # CITATION # PHRASE # QUOTE # WORDASWORD # COMPUTEROUTPUT # MARKUP # PROMPT # RETURNVALUE # SGMLTAG # TOKEN # DATABASE # HARDWARE # INTERFACE # MEDIALABEL # There doesn't seem to be a good way to represent LITERAL in -man ######################################################################## # # Paragraph and paragraph-like elements # ######################################################################## sub para_start { output "\n" unless $newline_last++; # In lists, etc., don't start paragraph with .PP since # the indentation will be gone. if($_[0]->parent->ext->{'nobreak'}==1) { # Usually this is the FIRST element of # a hanging tag, so we MUST not do a full # paragraph break. $_[0]->parent->ext->{'nobreak'} = 2; } elsif($_[0]->parent->ext->{'nobreak'}==2) { # Usually these are the NEXT elements of # a hanging tag. If we break using a blank # line, we're okay. output "\n"; } else { # Normal case. (For indented blocks too, at least # -man isn't so braindead in this area.) output ".PP\n"; } } # Actually applies to a few other block elements as well sub para_end { output "\n" unless $newline_last++; } sgml('', \¶_start); sgml('', \¶_end); sgml('', \¶_start); sgml('', \¶_end); # Nothing special, except maybe FIXME set nobreak. sgml('', \¶_start); sgml('', \¶_end); ######################################################################## # # Blocks using SS sections # ######################################################################## # FIXME: We need to consider the effects of SS # in a hanging tag :( # Complete with the optional-title dilemma (again). sgml('', sub { $_[0]->ext->{'title'} = 'ABSTRACT'; output "\n" unless $newline_last++; push_output('string'); }); sgml('', sub { my $content = pop_output(); # As ABSTRACT is never on the same level as RefSect1, # this leaves us with only .SS in terms of -man macros. output ".SS \"", uc($_[0]->ext->{'title'}), "\"\n"; output $content; output "\n" unless $newline_last++; }); # Ah, I needed a break. Example always has a title. man_sgml('', "\n.SS "); sgml('', \¶_end); # Same with sidebar. man_sgml('', "\n.SS "); sgml('', \¶_end); # NO title. man_sgml('', "\n.SS HIGHLIGHTS\n"); sgml('', \¶_end); ######################################################################## # # Indented 'Block' elements # ######################################################################## sub indent_block_start { output "\n" unless $newline_last++; output ".sp\n.RS\n"; } sub indent_block_end { output "\n" unless $newline_last++; output ".RE\n"; } # This element is almost like an admonition (below), # only the default title is blank :) sgml('
    ', sub { $_[0]->ext->{'title'} = ''; output "\n" unless $newline_last++; push_output('string'); }); sgml('
    ', sub { my $content = pop_output(); indent_block_start(); if($_[0]->ext->{'title'}) { output ".B \"", $_[0]->ext->{'title'}, ":\"\n"; } output $content; if($_[0]->ext->{'attribution'}) { output "\n" unless $newline_last++; # One place where roff's space-sensitivity makes sense :) output "\n -- "; output $_[0]->ext->{'attribution'} . "\n"; } indent_block_end(); }); # Set off admonitions from the rest of the text by indenting. # FIXME: Need to check if this works inside paragraphs, not enclosing them. sub admonition_end { my $content = pop_output(); indent_block_start(); # When the admonition is only one paragraph, # it looks nicer if the title was inline. my $num_para; while ($content =~ /^\.PP/gm) { $num_para++ } if($num_para==1) { $content =~ s/^\.PP\n//; } output ".B \"" . $_[0]->ext->{'title'} . ":\"\n"; output $content; indent_block_end(); } sgml('', sub { # We can't see right now whether or not there is a TITLE # element, so we have to save the output now and add it back # at the end of this admonition. $_[0]->ext->{'title'} = 'Note'; # Although admonition_end's indent_block_start will do this, # we need to synchronize the output _now_ output "\n" unless $newline_last++; push_output('string'); }); sgml('', \&admonition_end); # Same as above. sgml('', sub { $_[0]->ext->{'title'} = 'Warning'; output "\n" unless $newline_last++; push_output('string'); }); sgml('', \&admonition_end); sgml('', sub { $_[0]->ext->{'title'} = 'Tip'; output "\n" unless $newline_last++; push_output('string'); }); sgml('', \&admonition_end); sgml('', sub { $_[0]->ext->{'title'} = 'Caution'; output "\n" unless $newline_last++; push_output('string'); }); sgml('', \&admonition_end); sgml('', sub { $_[0]->ext->{'title'} = 'Important'; output "\n" unless $newline_last++; push_output('string'); }); sgml('', \&admonition_end); ######################################################################## # # Verbatim displays. # ######################################################################## sub verbatim_start { output "\n" unless $newline_last++; if($_[0]->parent->ext->{'nobreak'}==1) { # Usually this is the FIRST element of # a hanging tag, so we MUST not do a full # paragraph break. $_[0]->parent->ext->{'nobreak'} = 2; } else { output "\n"; } output(".nf\n") unless $nocollapse_whitespace++; } sub verbatim_end { output "\n" unless $newline_last++; output(".fi\n") unless --$nocollapse_whitespace; } sgml('', \&verbatim_start); sgml('', \&verbatim_end); sgml('', \&verbatim_start); sgml('', \&verbatim_end); sgml('', \&verbatim_start); sgml('', \&verbatim_end); #sgml('', sub { # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) { # &verbatim_start; # } else { # roffcmd(""); # } #}); # #sgml('', sub { # if($_[0]->attribute('FORMAT')->value =~ /linespecific/i) { # &verbatim_end; # } # else { # roffcmd("");# not sure about this. # } #}); sgml('', \&verbatim_start); sgml('', \&verbatim_end); ######################################################################## # # Lists # ######################################################################## # Indent nested lists. sub indent_list_start { if($list_nestlevel++) { output "\n" unless $newline_last++; output ".RS\n"; } } sub indent_list_end { if(--$list_nestlevel) { output "\n" unless $newline_last++; output ".RE\n"; } } sgml('', \&indent_list_start); sgml('', \&indent_list_end); sgml('', \&indent_list_start); sgml('', \&indent_list_end); sgml('', sub { indent_list_start(); $_[0]->ext->{'count'} = 1; }); sgml('', \&indent_list_end); sgml('', \&indent_list_start); sgml('', \&indent_list_end); # Output content on one line, bolded. sgml('', sub { output "\n" unless $newline_last++; output ".TP\n"; bold_on(); push_output('string'); }); sgml('', sub { my $term = pop_output(); $term =~ tr/\n/ /; output $term; font_off(); output "\n"; $newline_last = 1; }); sgml('', sub { output "\n" unless $newline_last++; output ".TP\n"; bold_on(); push_output('string'); }); sgml('', sub { my $term = pop_output(); $term =~ tr/\n/ /; output $term; font_off(); output "\n"; $newline_last = 1; }); sgml('', sub { # A bulleted list. if($_[0]->in('ITEMIZEDLIST')) { output "\n" unless $newline_last++; output ".TP 0.2i\n\\(bu\n"; } # Need numbers. # Assume Arabic numeration for now. elsif($_[0]->in('ORDEREDLIST')) { output "\n" unless $newline_last++; output ".TP 3\n", $_[0]->parent->ext->{'count'}++, ". \n"; } $_[0]->ext->{'nobreak'} = 1; }); sgml('', sub { $_[0]->ext->{'nobreak'} = 1; }); sgml('', sub { $_[0]->ext->{'first_member'} = 1; }); sgml('', sub { my $parent = $_[0]->parent; if($parent->attribute('TYPE')->value =~ /Inline/i) { if($parent->ext->{'first_member'}) { # If this is the first member don't put any commas $parent->ext->{'first_member'} = 0; } else { output ", "; } } elsif($parent->attribute('TYPE')->value =~ /Vert/i) { output "\n" unless $newline_last++; output "\n"; } }); ######################################################################## # # Stuff we don't know how to handle (yet) # ######################################################################## # Address blocks: # Credit stuff: # ACKNO # ADDRESS # AFFILIATION # ARTPAGENUMS # ATTRIBUTION # AUTHORBLURB # AUTHORGROUP # OTHERCREDIT # HONORIFIC # Areas: # AREA # AREASET # AREASPEC ######################################################################## # # Linkage, cross references # ######################################################################## # Print the URL sgml('', sub { output ' attribute('URL')->value, '>'; $newline_last = 0; }); # If cross reference target is a RefEntry, # output CiteRefEntry-style references. sgml('', sub { my $id = $_[0]->attribute('LINKEND')->value; my $manref = $Refs->get("refentry:$id"); if($manref) { my ($title, $sect) = ($manref =~ /(.*)(\(.*\))/); bold_on(); output $title; font_off(); output $sect; } else { $blank_xrefs++ if $write_manpages; output "[XRef to $id]"; } $newline_last = 0; }); # Anchor ######################################################################## # # Other handlers # ######################################################################## man_sgml('|[lt ]|', '<'); man_sgml('|[gt ]|', '>'); man_sgml('|[amp ]|', '&'); # # Default handlers (uncomment these if needed). Right now, these are set # up to gag on any unrecognised elements, sdata, processing-instructions, # or entities. # # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; }); # sgml('end_element',''); # This is for weeding out and escaping certain characters. # This looks like it's inefficient since it's done on every line, but # in reality, SGMLSpm and sgmlspl parsing ESIS takes _much_ longer. sgml('cdata', sub { if(!$write_manpages) { return; } elsif($raw_cdata) { output $_[0]; return; } # Escape backslashes $_[0] =~ s/\\/\\\\/g; # In non-'pre'-type elements: if(!$nocollapse_whitespace) { # Change tabs to spaces $_[0] =~ tr/\t/ /; # Do not allow indents at beginning of line # groff chokes on that. if($newline_last) { $_[0] =~ s/^ +//; # If the line is all blank, don't do anything. if($_[0] eq '') { return; } $_[0] =~ s/^\./\\\&\./; # Argh... roff doesn't like ' either... $_[0] =~ s/^\'/\\\&\'/; } } $newline_last = 0; output $_[0]; }); # When in whitespace-collapsing mode, we disallow consecutive newlines. sgml('re', sub { if($nocollapse_whitespace || !$newline_last) { output "\n"; } $newline_last = 1; }); sgml('sdata',sub { if($_[0] =~ /\[minus \]/) { output "-"; } elsif($_[0] =~ /\[copy \]/) { output "(C)"; } elsif($_[0] =~ /\[nbsp \]/) { output " "; } else { die "Unknown SDATA: " . $_[0]; } }); sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; }); sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; }); sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; }); sgml('end_subdoc',''); sgml('conforming',''); 1; privoxy-3.0.21-stable/./utils/docbook2man/COPYING000640 001751 001751 00000043110 10546014102 020343 0ustar00fkfk000000 000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. privoxy-3.0.21-stable/./utils/docbook2man/docbook2man-spec.pl.1000640 001751 001751 00000006610 10546014102 023136 0ustar00fkfk000000 000000 .\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "DOCBOOK2MAN-SPEC.PL" "1" "27 June 2002" "" "" .SH NAME docbook2man-spec.pl \- convert DocBook RefEntries to man pages .SH SYNOPSIS \fBsgmlspl\fR \fBdocbook2man-spec.pl\fR \fBnsgmls\fR [ \fB\fIsgml document\fB\fR ]\fB| sgmlspl\fR \fBdocbook2man-spec.pl\fR .SH "DESCRIPTION" .PP \fBdocbook2man\fR is a sgmlspl spec file that produced man pages (using the -man macros) from DocBook RefEntry markup. .PP The program reads ESIS produced by nsgmls (or other SGML parsers) from standard input. Markup not found in RefEntry is discarded. .PP Its output, the converted man pages, are written to the current directory. If RefMeta information is not specified in a RefEntry, then the man page will be written to standard output. .PP The file \fImanpage.links\fR will also be created, which contains any aliases of the manpages generated. This file is in the format: .nf \fI\fR \fI\fR .fi .PP The \fImanpage.refs\fR file keeps track of XRef references. Note that if the input document has any forward references, then \fBdocbook2man\fR may have to be invoked twice (the first time updating \fImanpage.refs\fR) to resolve them. .SH "REQUIREMENTS" The SGMLSpm package from CPAN. This package includes the sgmlspl script that is also needed. .SH "LIMITATIONS" .PP Trying \fBdocbook2man\fR on non-DocBook or non-conformant SGML results in undefined behavior. :-) .PP This program is a slow, dodgy Perl script. .PP This program does not come close to supporting all the possible markup in DocBook, and may produce wrong output in some cases with supported markup. .SH "TO DO" .PP Obvious stuff: .TP 0.2i \(bu Fix \fBdocbook2man\fR breakages found in the test documents, especially \fIweird.sgml\fR. .TP 0.2i \(bu Add new element handling and fix existing handling. Be robust. .TP 0.2i \(bu Produce cleanest, readable man output as possible (unlike some other converters). Follow Linux \fBman\fR(7) convention. As conversion to man pages is usually not done very often, it is better to be slower/more complicated than to produce wrong output. Also if someone wants to give up using DocBook for whatever reason, the last-converted man pages can then be maintained manually. .TP 0.2i \(bu Make it faster. I think most of the speed problems so far is with parsing ESIS. Rewrite \fISGMLS.pm\fR with C and/or get input directly from \fBSP\fR. .TP 0.2i \(bu Support other (human) languages. But what to do with non-ASCII charsets? SGMLSpm doesn't report them and \fBroff\fR does not grok them. [Comment: text after enclosed lists (and SS blocks) will break docbook2man] If we do this, more people can use DocBook. .SH "COPYRIGHT" .PP Copyright (C) 1998-1999 Steve Cheng .PP This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. .PP You should have received a copy of the GNU General Public License along with this program; see the file \fICOPYING\fR. If not, please write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. privoxy-3.0.21-stable/./utils/filter2docs.pl000750 001751 001751 00000004452 12114407373 017710 0ustar00fkfk000000 000000 #!/usr/bin/perl # $Id: filter2docs.pl,v 1.9 2013/03/02 14:38:51 fabiankeil Exp $ # $Source: /cvsroot/ijbswa/current/utils/filter2docs.pl,v $ # Parse the filter names and descriptions from a filter file and # spit out copy&paste-ready markup for the various places in # configuration and documentation where all filters are listed. use strict; use warnings; my (%comment_lines, %action_lines, %sgml_source_1, %sgml_source_2); sub main() { die "Usage: $0 filter-file\n" unless (@ARGV == 1) ; open(INPUT, "< $ARGV[0]") or die "Couldn't open input file $ARGV[0]: $!\n"; parse_file(); print_markup(); } sub sgml_escape($) { my $text = shift; $text =~ s@<@<@g; $text =~ s@>@>@g; return $text; } sub parse_file() { while () { if (/^((?:(?:SERVER|CLIENT)-HEADER-)?(?:FILTER|TAGGER)): ([-\w]+) (.*)$/) { my $type_uc = $1; my $name = $2; my $description = $3; my $type = lc($type_uc); my $sgml_description = sgml_escape($description); my $white_space = ' ' x (($type eq 'filter' ? 20 : 27) - length($name)); $comment_lines{$type} .= "# $name:" . $white_space . "$description\n"; $action_lines{$type} .= "+$type" . "{$name} \\\n"; $sgml_source_1{$type} .= " \n \n" . " +$type" . "{$name}" . $white_space . "# $sgml_description\n \n"; $sgml_source_2{$type} .= ' -$type" . "{$name} \\\n"; } } } sub print_markup() { my @filter_types = ( 'filter', 'server-header-filter', 'client-header-filter', 'server-header-tagger', 'client-header-tagger' ); foreach my $type (@filter_types) { next unless defined $action_lines{$type}; print "=" x 90; print <<" DOCMARKUP"; Producing $type markup: Comment lines for default.action.master: $comment_lines{$type} Block of $type actions for default.action.master: $action_lines{$type} SGML Source for AF chapter in U-M: $sgml_source_1{$type} SGML Source for AF Tutorial chapter in U-M: $sgml_source_2{$type} DOCMARKUP } } main(); privoxy-3.0.21-stable/./utils/ldp_print/ldp_print000750 001751 001751 00000004075 10546014102 021034 0ustar00fkfk000000 000000 #!/usr/bin/perl -w # # usage: ldp_print # # Creates a PDF variant of a single-file HTML representation of a # DocBook SGML (or XML) instance. This simple wrapper assumes that # the file was created using {open}jade in a manner similar to: # # jade -t sgml -i html -V nochunks -d $style $fname > $fname.html # # Give this script the filename as an argument. It will then parse # the file into 'title.html' and 'body.html' and send each to # htmldoc (as the corresponding title page and body of the document). # # # CAVEATS: # # Assumes perl is in /usr/bin; adjust if necessary # # You may need to specify where the htmldoc executable resides. # The script assumes it's within your $PATH. # # If you want Postscript as an output variant, uncomment the # appropriate lines (see below). # # Relies on output from a DocBook instance created via DSSSL/{open}jade! # # Cleans up (removes) the intermediate files it creates (but not the # PDF or Postscript files, obviously!) # # Works silently; PDF (PostScript) will be created in the same directory # as was specified for the input (single-file HTML) file. # # Provided without warranty or support! # # gferg@sgi.com / Ferg (used as part of the LDP production env) # use strict; push(@INC, "./"); require 'fix_print_html.lib'; if( $ARGV[0] eq '' || !(-r $ARGV[0]) ) { die "\nusage: ldp_print \n\n"; } my($fname_wo_ext) = $ARGV[0]; $fname_wo_ext =~ s/\.[\w]+$//; # create new files from single HTML file to use for print # &fix_print_html($ARGV[0], 'body.html', 'title.html'); my($cmd) = "htmldoc --size universal --bodyfont helvetica --fontsize 8 " . "-t pdf -f ${fname_wo_ext}.pdf --firstpage p1 --titlefile title.html" . " body.html --footer c.1"; # For postscript output; append onto the above cmd string: # # "; htmldoc --size universal -t ps -f ${fname_wo_ext}.ps " . # "--firstpage p1 --titlefile title.html body.html"; # system($cmd); die "\nldp_print: could not create ${fname_wo_ext}.pdf ($!)\n" if ($?); # cleanup # system("rm -f body.html title.html"); exit(0); privoxy-3.0.21-stable/./utils/ldp_print/fix_print_html.lib000640 001751 001751 00000013314 10546014102 022626 0ustar00fkfk000000 000000 # # fix_print_html.lib # # Dan Scott / # Ferg / # # Used to prepare single-file HTML variant for PDF/Postscript creation # thru htmldoc. # # log: # 16Oct2000 - 0.1 - initial entry # 03Apr2001 - 0.2 - fix for # 05Jul2001 - 0.3 - fix for and -f # 12Oct2001 - 0.4 - fix for sections; loop thru both files (body/title) # 27Nov2001 - 0.5 - fixed bug in determining where doc-index lies # 18Jan2002 - 0.5.1 - entity fix (822*) # 02Apr2002 - 0.6 - misc fixes (bibliography/appendix, etc). # 04Apr2002 - 0.7 - fix for newer DSSSL # sub fix_print_html { my($in,$out,$ttl) = @_; open(IN_FILE, "< $in") || do { print "fix_print_html: cannot open $in: $!\n"; return 0; }; my($buf, $ttl_buf) = ''; my($indx) = -1; my($is_article) = 1; while() { if( $indx == 1 ) { # ignore everything until we see the chapter or sect # if( $_ =~ /CLASS="CHAP/i || $_ =~ /CLASS="PREF/i || $_ =~ /CLASS="SECT/i ) { $buf .= $_; $indx++; } else { next; } } elsif( $indx == 0 ) { # write out the title page file # if( $_ =~ /CLASS="TOC"/ ) { $ttl_buf .= ">
  • \n\n\n"; $ttl_buf =~ s/<\/H1\n/<\/H1\n>


    <\/DIV\n>


    /
    <\/DIV\n>/ms; &fix_html(\$ttl_buf, 1); open(TOC_FILE, "> $ttl") || do { print "fix_print_html: cannot open $ttl: $!\n"; close(IN_FILE); return 0; }; print TOC_FILE $ttl_buf; close(TOC_FILE); $ttl_buf = ''; $indx++; } else { $ttl_buf .= $_; } } elsif( $indx < 0 ) { if( $_ =~ /CLASS="BOOK"/i ) { $is_article = 0; } # up to this point, both buffers get the line # if( $_ =~ /CLASS="TITLEPAGE"/ ) { $ttl_buf .= $_ . ">\n

    \n



    \n<\/P\n"; $indx++; } else { $buf .= $_; $ttl_buf .= $_; } } else { $buf .= $_; } } close(IN_FILE); # fix body file # open(OUT_FILE, "> $out") || do { print "fix_print_html: cannot open $out: $!\n"; return 0; }; &fix_html(\$buf, $is_article); print OUT_FILE $buf; close(OUT_FILE); return 1; } sub fix_html { my($buf, $is_article) = @_; my($indx) = -1; # make corrections and write out the file # $$buf =~ s/(\n>/$1$2\n/gms; $$buf =~ s/(\n>/$1$2\n/gms; $$buf =~ s/(\n>/$1$2\n/gms; if( $is_article == 0 ) { $$buf =~ s/(\nCLASS="SECT[TION\d]+"\n>)


    ) -1 ) { $$buf = substr($$buf, 0, $indx); $$buf .= "\n<\/BODY>\n<\/HTML>\n\n"; } elsif( ($indx = rindex($$buf, " -1 ) { $$buf = substr($$buf, 0, $indx); $$buf .= "\n<\/BODY>\n<\/HTML>\n\n"; } $$buf =~ s/\&\#13;//g; $$buf =~ s/\&\#60;/\</g; $$buf =~ s/\&\#62;/\>/g; $$buf =~ s/\&\#8211;/\-/g; $$buf =~ s/\&\#8220;/\"/g; $$buf =~ s/\&\#8221;/\"/g; $$buf =~ s/WIDTH=\"\d\"//g; $$buf =~ s/><[\/]*TBODY//g; $$buf =~ s/><[\/]*THEAD//g; $$buf =~ s/TYPE=\"1\"\n//gim; $$buf =~ s/<\/P/gms; my($cnt, $j) = 0; if( $$buf !~ /

    = 0; $cnt--) { $j = $cnt + 1; if( $cnt == 0 ) { $j = 2; } $$buf =~ s/<\/DIV\n//gms; $buf =~ s/]*?>//gms; $buf =~ s/<\/SPAN\n>//gms; $$buf =~ s/(>(<\/LI\n)/$1$2$3/gms; return; } # Return true from package include # 1; privoxy-3.0.21-stable/./utils/ldp_print/VERSION000640 001751 001751 00000000022 10546014102 020150 0ustar00fkfk000000 000000 0.7.0, 2002-04-04 privoxy-3.0.21-stable/./utils/ldp_print/README000640 001751 001751 00000005503 10546014102 017771 0ustar00fkfk000000 000000 ###################################################################### ldp_print - print tool/script for DocBook SGML/XML documents ###################################################################### Copyright (C) 2002-2000 - Greg Ferguson (gferg@metalab.unc.edu) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ###################################################################### This process/script is used in the production environment for the LDP. It relies on the HTMLDOC software package (GPL'ed) which can be obtained from the Easy Software Products (c) web site: http://www.easysw.com/htmldoc/ This process creates a PDF variant from the single-file HTML representation of a DocBook SGML (or XML) instance. The simple wrapper script (ldp_print) assumes that the file was created using {open}jade in a manner similar to: jade -t sgml -i html -V nochunks -d $style $fname > $fname.html Give the script the filename as an argument. It will then parse the file into 'title.html' and 'body.html' and send each to htmldoc (as the corresponding title page and body of the document). CAVEATS ======= o Assumes perl is in /usr/bin; adjust if necessary o You may need to specify where the htmldoc executable resides. The script assumes it's within your $PATH. o If you want Postscript as an output variant, uncomment the appropriate lines (see below). o Relies on output from a DocBook instance created via DSSSL/{open}jade! o Cleans up (removes) the intermediate files it creates (but not the PDF or Postscript files, obviously!) o Works silently; PDF (PostScript) will be created in the same directory as was specified for the input (single-file HTML) file. o Provided without warranty or support! o I ran into a problem with htmldoc v1.8.8 which required a source code change (I was getting a core dump from the htmldoc process). Here is the change required: htmldoc/ps-pdf.cxx : 3662,3665d3661 < /* gjf = 11Oct2000 */ < if( temprow == NULL ) < break; < UPDATE (2001-10-10): It appears that later versions of htmldoc have this problem corrected. The patch is not required. ==== Greg Ferguson / gferg (at) metalab.unc.edu 11 Jan 2000 privoxy-3.0.21-stable/./utils/prepare-configfile.pl000750 001751 001751 00000004245 12104210622 021215 0ustar00fkfk000000 000000 #!/usr/local/bin/perl # This script is used by the config-file target in GNUMakefile. # # It removes garbage in the w3m output and separates comments # and active directives. use strict; use warnings; sub main() { my $hit_header = 0; my $hit_option = 0; my $header_len; my $unfold_mode = 0; my $unfolding_enabled = 0; my $windows_section_reached = 0; while (<>) { if (!$unfolding_enabled and m/=========/) { # We passed the table of contents # and can try to unfold unintentional # line breaks; $unfolding_enabled = 1; } if (m/specific to the Windows GUI/) { # The Windows section is formatted differently. $windows_section_reached = 1; } s/^1\. \@\@TITLE\@\@/ /i; if (m/^(\d*\.){1,3}\s/) { # Remove the first digit as it's the # config file section in the User Manual. s/^(\d\.)//; # If it's a section header, uppercase it. $_ = uc() if (/^\d\.\s+/); # Remember to underline it. $hit_header = 1; $header_len = length($_); } if ($unfold_mode) { s/^\s+/ /; $unfold_mode = 0; } else { s/^/# /; } if ($unfolding_enabled and m/(\s+#)\s*$/) { $unfold_mode = 1; chomp; } # XXX: someone should figure out what this stuff # is supposed to do (and if it really does that). s/^# #/####/ if /^# #{12,}/; s/^.*$// if $hit_option; $hit_option = 0; s/^\n//; s/^#\s*-{20,}//; s/ *$//; $hit_option = 1 if s/^#\s+@@//; if ($windows_section_reached) { # Do not drop empty lines in the Windows section s/^\s*$/#\n/; } print unless (/^\s*$/); if ($hit_header) { # The previous line was a section # header so we better underline it. die "Invalid header length" unless defined $header_len; print "# " . "=" x $header_len . "\n"; $hit_header = 0; }; } } main(); privoxy-3.0.21-stable/./user.filter000640 001751 001751 00000006406 11217504053 016153 0ustar00fkfk000000 000000 # ******************************************************************** # # File : $Source: /cvsroot/ijbswa/current/user.filter,v $ # # $Id: user.filter,v 1.3 2008/05/21 20:17:03 fabiankeil Exp $ # # Purpose : Rules to process the content of web pages # # Copyright : Written by and Copyright (C) 2006-2008 the # Privoxy team. http://www.privoxy.org/ # # We value your feedback. However, to provide you with the best support, # please note: # # * Use the support forum to get help: # http://sourceforge.net/tracker/?group_id=11118&atid=211118 # * Submit bugs only thru our bug forum: # http://sourceforge.net/tracker/?group_id=11118&atid=111118 # Make sure that the bug has not already been submitted. Please try # to verify that it is a Privoxy bug, and not a browser or site # bug first. If you are using your own custom configuration, please # try the stock configs to see if the problem is a configuration # related bug. And if not using the latest development snapshot, # please try the latest one. Or even better, CVS sources. # * Submit feature requests only thru our feature request forum: # http://sourceforge.net/tracker/?atid=361118&group_id=11118&func=browse # # For any other issues, feel free to use the mailing lists: # http://sourceforge.net/mail/?group_id=11118 # # Anyone interested in actively participating in development and related # discussions can join the appropriate mailing list here: # http://sourceforge.net/mail/?group_id=11118. Archives are available # here too. # ################################################################################# # # Syntax: # # Generally filters start with a line like "FILTER: name description". # They are then referrable from the actionsfile with +filter{name} # # FILTER marks a filter as content filter, other filter # types are CLIENT-HEADER-FILTER, CLIENT-HEADER-TAGGER, # SERVER-HEADER-FILTER and SERVER-HEADER-TAGGER. # # Inside the filters, write one Perl-Style substitution (job) per line. # Jobs that precede the first FILTER: line are ignored. # # For Details see the pcrs manpage contained in this distribution. # (and the perlre, perlop and pcre manpages) # # Note that you are free to choose the delimiter as you see fit. # # Note2: In addition to the Perl options gimsx, the following nonstandard # options are supported: # # 'U' turns the default to ungreedy matching. Add ? to quantifiers to # switch back to greedy. # # 'T' (trivial) prevents parsing for backreferences in the substitute. # Use if you want to include text like '$&' in your substitute without # quoting. # # 'D' (Dynamic) allows the use of variables. Supported variables are: # $host, $origin (the IP address the request came from), $path and $url. # # Note that '$' is a bad choice as delimiter for dynamic filters as you # might end up with unintended variables if you use a variable name # directly after the delimiter. Variables will be resolved without # escaping anything, therefore you also have to be careful not to chose # delimiters that appear in the replacement text. For example '<' should # be save, while '?' will sooner or later cause conflicts with $url. # ################################################################################# privoxy-3.0.21-stable/./list.h000640 001751 001751 00000007455 11630656300 015121 0ustar00fkfk000000 000000 #ifndef LIST_H_INCLUDED #define LIST_H_INCLUDED #define LIST_H_VERSION "$Id: list.h,v 1.18 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/list.h,v $ * * Purpose : Declares functions to handle lists. * Functions declared include: * `destroy_list', `enlist' and `list_to_text' * * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif /* * struct list * * A linked list class. */ extern void init_list (struct list *the_list); extern void destroy_list (struct list *the_list); extern jb_err enlist (struct list *the_list, const char *str); extern jb_err enlist_unique (struct list *the_list, const char *str, size_t num_significant_chars); extern jb_err enlist_unique_header (struct list *the_list, const char *name, const char *value); extern jb_err enlist_first (struct list *the_list, const char *str); extern jb_err list_append_list_unique(struct list *dest, const struct list *src); extern jb_err list_duplicate (struct list *dest, const struct list *src); extern int list_remove_item(struct list *the_list, const char *str); extern int list_remove_list(struct list *dest, const struct list *src); extern void list_remove_all (struct list *the_list); extern int list_is_empty(const struct list *the_list); extern char * list_to_text(const struct list *the_list); extern int list_contains_item(const struct list *the_list, const char *str); /* * struct map * * A class which maps names to values. * * Note: You must allocate this through new_map() and free it * through free_map(). */ extern struct map * new_map (void); extern void free_map (struct map * the_map); extern jb_err map (struct map * the_map, const char * name, int name_needs_copying, const char * value, int value_needs_copying); extern jb_err unmap (struct map *the_map, const char *name); extern const char * lookup (const struct map * the_map, const char * name); /* Revision control strings from this header and associated .c file */ extern const char list_rcs[]; extern const char list_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef LIST_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./parsers.h000640 001751 001751 00000007233 12060362213 015612 0ustar00fkfk000000 000000 #ifndef PARSERS_H_INCLUDED #define PARSERS_H_INCLUDED #define PARSERS_H_VERSION "$Id: parsers.h,v 1.55 2012/12/07 12:43:55 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.h,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * Functions declared include: * `add_to_iob', `client_cookie_adder', `client_from', * `client_referrer', `client_send_cookie', `client_ua', * `client_uagent', `client_x_forwarded', * `client_x_forwarded_adder', `client_xtra_adder', * `content_type', `crumble', `destroy_list', `enlist', * `flush_socket', `free_http_request', `get_header', * `list_to_text', `parse_http_request', `sed', * and `server_set_cookie'. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif /* Used for sed()'s second argument. */ #define FILTER_CLIENT_HEADERS 0 #define FILTER_SERVER_HEADERS 1 extern long flush_socket(jb_socket fd, struct iob *iob); extern jb_err add_to_iob(struct iob *iob, const size_t buffer_limit, char *src, long n); extern void clear_iob(struct iob *iob); extern jb_err decompress_iob(struct client_state *csp); extern char *get_header(struct iob *iob); extern char *get_header_value(const struct list *header_list, const char *header_name); extern jb_err sed(struct client_state *csp, int filter_server_headers); extern jb_err update_server_headers(struct client_state *csp); extern void get_http_time(int time_offset, char *buf, size_t buffer_size); extern jb_err get_destination_from_headers(const struct list *headers, struct http_request *http); extern unsigned long long get_expected_content_length(struct list *headers); extern jb_err client_transfer_encoding(struct client_state *csp, char **header); #ifdef FEATURE_FORCE_LOAD extern int strclean(char *string, const char *substring); #endif /* def FEATURE_FORCE_LOAD */ /* Revision control strings from this header and associated .c file */ extern const char parsers_rcs[]; extern const char parsers_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef PARSERS_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./jcc.h000640 001751 001751 00000006751 11655472007 014712 0ustar00fkfk000000 000000 #ifndef JCC_H_INCLUDED #define JCC_H_INCLUDED #define JCC_H_VERSION "$Id: jcc.h,v 1.32 2011/11/06 11:48:23 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.h,v $ * * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * * Copyright : Written by and Copyright (C) 2001-2006 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif struct client_state; struct file_list; /* Global variables */ #ifdef FEATURE_STATISTICS extern int urls_read; extern int urls_rejected; #endif /*def FEATURE_STATISTICS*/ extern struct client_states clients[1]; extern struct file_list files[1]; #ifdef unix extern const char *pidfile; #endif extern int daemon_mode; #ifdef FEATURE_GRACEFUL_TERMINATION extern int g_terminate; #endif #if defined(FEATURE_PTHREAD) || defined(_WIN32) #define MUTEX_LOCKS_AVAILABLE #ifdef FEATURE_PTHREAD #include typedef pthread_mutex_t privoxy_mutex_t; #else typedef CRITICAL_SECTION privoxy_mutex_t; #endif extern void privoxy_mutex_lock(privoxy_mutex_t *mutex); extern void privoxy_mutex_unlock(privoxy_mutex_t *mutex); extern privoxy_mutex_t log_mutex; extern privoxy_mutex_t log_init_mutex; extern privoxy_mutex_t connection_reuse_mutex; #ifndef HAVE_GMTIME_R extern privoxy_mutex_t gmtime_mutex; #endif /* ndef HAVE_GMTIME_R */ #ifndef HAVE_LOCALTIME_R extern privoxy_mutex_t localtime_mutex; #endif /* ndef HAVE_GMTIME_R */ #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) extern privoxy_mutex_t resolver_mutex; #endif /* !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) */ #ifndef HAVE_RANDOM extern privoxy_mutex_t rand_mutex; #endif /* ndef HAVE_RANDOM */ #endif /* FEATURE_PTHREAD */ /* Functions */ #ifdef __MINGW32__ int real_main(int argc, char **argv); #else int main(int argc, char **argv); #endif /* Revision control strings from this header and associated .c file */ extern const char jcc_rcs[]; extern const char jcc_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef JCC_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./actions.h000640 001751 001751 00000007741 12004551155 015602 0ustar00fkfk000000 000000 #ifndef ACTIONS_H_INCLUDED #define ACTIONS_H_INCLUDED #define ACTIONS_H_VERSION "$Id: actions.h,v 1.21 2012/07/27 17:39:57 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actions.h,v $ * * Purpose : Declares functions to work with actions files * Functions declared include: FIXME * * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif struct action_spec; struct current_action_spec; struct client_state; /* This structure is used to hold user-defined aliases */ struct action_alias { const char * name; struct action_spec action[1]; struct action_alias * next; }; extern jb_err get_actions (char *line, struct action_alias * alias_list, struct action_spec *cur_action); extern void free_alias_list(struct action_alias *alias_list); extern void init_action(struct action_spec *dest); extern void free_action(struct action_spec *src); extern jb_err merge_actions (struct action_spec *dest, const struct action_spec *src); #if 0 extern int update_action_bits_for_all_tags(struct client_state *csp); #endif extern int update_action_bits_for_tag(struct client_state *csp, const char *tag); extern jb_err copy_action (struct action_spec *dest, const struct action_spec *src); extern char * actions_to_text (const struct action_spec *action); extern char * actions_to_html (const struct client_state *csp, const struct action_spec *action); extern void init_current_action (struct current_action_spec *dest); extern void free_current_action (struct current_action_spec *src); extern jb_err merge_current_action (struct current_action_spec *dest, const struct action_spec *src); extern char * current_action_to_html(const struct client_state *csp, const struct current_action_spec *action); extern char * actions_to_line_of_text(const struct current_action_spec *action); extern jb_err get_action_token(char **line, char **name, char **value); extern void unload_actions_file(void *file_data); extern int load_action_files(struct client_state *csp); #ifdef FEATURE_GRACEFUL_TERMINATION void unload_current_actions_file(void); #endif /* Revision control strings from this header and associated .c file */ extern const char actions_rcs[]; extern const char actions_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef ACTIONS_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./config.guess000750 001751 001751 00000127045 11657466213 016325 0ustar00fkfk000000 000000 #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011 Free Software Foundation, Inc. timestamp='2011-11-11' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo hexagon-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: privoxy-3.0.21-stable/./filters.h000640 001751 001751 00000011151 11630656300 015602 0ustar00fkfk000000 000000 #ifndef FILTERS_H_INCLUDED #define FILTERS_H_INCLUDED #define FILTERS_H_VERSION "$Id: filters.h,v 1.43 2011/09/04 11:10:56 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/filters.h,v $ * * Purpose : Declares functions to parse/crunch headers and pages. * Functions declared include: * `acl_addr', `add_stats', `block_acl', `block_imageurl', * `block_url', `url_actions', `filter_popups', `forward_url' * `ij_untrusted_url', `intercept_url', `re_process_buffer', * `show_proxy_args', and `trust_url' * * Copyright : Written by and Copyright (C) 2001-2010 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif struct access_control_addr; struct client_state; struct http_request; struct http_response; struct current_action_spec; struct url_actions; struct url_spec; /* * ACL checking */ #ifdef FEATURE_ACL extern int block_acl(const struct access_control_addr *dst, const struct client_state *csp); extern int acl_addr(const char *aspec, struct access_control_addr *aca); #endif /* def FEATURE_ACL */ /* * Interceptors */ extern struct http_response *block_url(struct client_state *csp); extern struct http_response *redirect_url(struct client_state *csp); #ifdef FEATURE_TRUST extern struct http_response *trust_url(struct client_state *csp); #endif /* def FEATURE_TRUST */ /* * Request inspectors */ #ifdef FEATURE_TRUST extern int is_untrusted_url(const struct client_state *csp); #endif /* def FEATURE_TRUST */ #ifdef FEATURE_IMAGE_BLOCKING extern int is_imageurl(const struct client_state *csp); #endif /* def FEATURE_IMAGE_BLOCKING */ extern int connect_port_is_forbidden(const struct client_state *csp); /* * Determining applicable actions */ extern void get_url_actions(struct client_state *csp, struct http_request *http); extern void apply_url_actions(struct current_action_spec *action, struct http_request *http, struct url_actions *b); /* * Determining parent proxies */ extern const struct forward_spec *forward_url(struct client_state *csp, const struct http_request *http); /* * Content modification */ extern char *execute_content_filters(struct client_state *csp); extern char *execute_single_pcrs_command(char *subject, const char *pcrs_command, int *hits); extern char *rewrite_url(char *old_url, const char *pcrs_command); extern char *get_last_url(char *subject, const char *redirect_mode); extern pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const struct re_filterfile_spec *b); extern int content_requires_filtering(struct client_state *csp); extern int content_filters_enabled(const struct current_action_spec *action); extern int filters_available(const struct client_state *csp); /* * Handling Max-Forwards: */ extern struct http_response *direct_response(struct client_state *csp); /* * Revision control strings from this header and associated .c file */ extern const char filters_rcs[]; extern const char filters_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef FILTERS_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./icons/os27.ico000640 001751 001751 00000000762 10546014107 016366 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """""""""""""""""""""" """"""""""""""""""""""""ªªªª""""ªªª¢""""ªªª""""" ª¢"""" ª"""""¢""""""""""" privoxy-3.0.21-stable/./icons/os20.ico000640 001751 001751 00000000762 10546014107 016357 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """"""""""*ª"ªª"ª*¢ª*¢ "ª*¢ª*¢""ª*¢ª*¢""ª*¢ª*¢"""*¢ª*¢"""*¢ªª""""*¢ª*¢""*¢ª*¢ "*¢ª*¢"*¢ªª""""""" privoxy-3.0.21-stable/./icons/ico00002.ico000640 001751 001751 00000000476 11160754257 016744 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""""""""""""""""" """"""""""""""""""""""""""""ªªªª""""*ªªª"""""ªªª""""*ª """""ª"""""*"""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/off.ico000640 001751 001751 00000004766 11312111476 016355 0ustar00fkfk000000 000000  h&hŽ(  %³6 ÞžÖâ)Çü(ÈüÕÝÆ™B(z2""ª ã§:-¿ÿ{^}ÿ–t`ÿ–t`ÿ–t`ÿ“rcÿkSÿ* Ëþ"»œqT8 ÃôÑ[Ešÿ’p^ÿ’p^ÿ’p^ÿ’p^ÿ’p^ÿ’p^ÿ’p^ÿ’p^ÿQ>¥ÿÈÁqTT ì²gOŠÿ+ Îÿz^tÿ¬ƒoÿöâØÿn]ÿn]ÿn]ÿn]ÿn]ÿn]ÿN<¦ÿ'ºœ êKE5¬ÿ‹k[ÿ‚cfÿ)Íÿ—wŽÿþýýÿŒk\ÿ‹k[ÿ‹k[ÿ‹k[ÿ‹k[ÿ‹k[ÿ‹j[ÿ)ÊþS9r1 í´€aaÿˆgXÿˆgXÿ~_dÿ2'ÔÿÙØýÿˆgYÿˆgXÿˆgXÿˆgXÿˆgXÿˆgXÿˆgXÿ_H‰ÿ$Ä™&Ëù„dWÿ„dWÿ„dWÿ„dWÿ•txÿLLþÿŠrÿ©‹ÿ‘oaÿ„dWÿ„dWÿ„dWÿ„dWÿ‚bZÿÖÜ8+´ÿ€aTÿ€aTÿ€aTÿ€aTÿ¡qÿííÿÿF=íÿÔËíÿýùøÿÀ¬£ÿ€aTÿ€aTÿ€aTÿ€aTÿ)Æü8+±ÿ|^Sÿ|^Sÿ|^Sÿ|^Sÿž|pÿþýýÿtW_ÿ%Ëÿ„pÿøööÿ¡‰ÿ|^Sÿ|^Sÿ|^Sÿ)Çü(ÅýyZQÿyZQÿyZQÿy[Qÿ|rÿþýýÿcYÿtXaÿ$Êÿ¿¸Úÿʶ°ÿyZQÿyZQÿxZRÿØà èÃtVRÿ„ibÿŠrkÿxqÿ­”Œÿþýýÿ’|tÿ’{tÿ‡q|ÿ@=ïÿª›¼ÿ„jcÿŽwpÿbKyÿÛœö]I7ÿ’{uÿ›‡ÿ›‡ÿ³—ÿþþýÿ§…|ÿ¨ˆÿ±­ÿìêüÿ62ãÿ„r’ÿ™„ÿ-#ÂÿC+²5ÿ èÍwarÿ¥”ÿ¥”ÿ»¨¤ÿÿÿÿÿÿÿÿÿÿÿÿÿöòñÿÌÂÀÿ™‰˜ÿ1,ÝÿUH­ÿâ£þ#Øæƒoƒÿ®Ÿÿ¯ žÿ³¥£ÿ³¥£ÿ²¤¡ÿ®Ÿÿ®Ÿÿ­žœÿgZ¥ÿ òÍN:° þ# èÌTF¦ÿœŠŒÿ´¦¤ÿ¹­«ÿ¹­«ÿ³¥£ÿ“ƒ”ÿ@6»ÿ ê­H6¶ÿö\ ìÀ"Åü1&¹ÿ0%¼ÿÊö ð¯äDøàÀ€€€€Ààø( ÿC+zÿT8uÿdIFÿhLHÿtVRÿxZRÿyZQÿ|^SÿtW_ÿcYÿtXaÿ~_dÿbKyÿz^tÿ{^}ÿwarÿ€aTÿ„dWÿ‚bZÿˆgXÿ‹j[ÿŒk\ÿn]ÿn]ÿ’p^ÿ€aaÿ‚cfÿ„ibÿ„jcÿ‘oaÿŠrkÿ“rcÿ–t`ÿŽwpÿ‡q|ÿxqÿ’{tÿ’|tÿ|rÿž|pÿ•txÿ¡qÿ™„ÿ¬ƒoÿ§…|ÿ¨ˆÿ©‹ÿ%µÿ)²ÿ'»ÿ#¼ÿ8+±ÿ8+´ÿ1&¹ÿ0%¼ÿ:-¿ÿI7ÿN<¦ÿE5¬ÿM;©ÿQ>¥ÿA+°ÿB4¸ÿ@6»ÿ_H‰ÿ[EšÿgOŠÿkSÿTF¦ÿUH­ÿgZ¥ÿÆÿÉÿÊÿ ÞÿÕÿÖÿØÿÛÿØÿ!Åÿ"Åÿ%Åÿ(Æÿ)Æÿ$Êÿ%Ëÿ'Ìÿ(Èÿ)Ëÿ)Íÿ-#Âÿ* Ìÿ+ Îÿ2'Ôÿ1,Ýÿ äÿ ìÿ íÿ ìÿåÿ éÿ êÿãÿ÷ÿôÿ òÿ ðÿøÿÿÿüÿ62ãÿ@=ïÿF=íÿLLþÿƒoƒÿ„pÿŠrÿ—wŽÿ„r’ÿ›‡ÿœŠŒÿ“ƒ”ÿ™‰˜ÿ¡‰ÿ­”Œÿ¥”ÿ­žœÿ®Ÿÿ³—ÿ¯ žÿª›¼ÿ²¤¡ÿ³¥£ÿ´¦¤ÿ»¨¤ÿ¹­«ÿÀ¬£ÿ±­ÿʶ°ÿ¿¸ÚÿÌÂÀÿöâØÿÔËíÿÙØýÿìêüÿííÿÿöòñÿøööÿýùøÿþýýÿþþýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿs!!! DÿÿÿÿÿÿÿÿB,sÿÿÿÿÿs_,<ÿÿÿ<Zw— ÿÿÿs- _‘Aÿÿ)sv.G„ÿ5*“r–Šÿ?(— Wu•-D„ÿÿs) (— VŒÿÿ )~—))tr„‚sÿÿs„„w‚—-.‹’pxwOÿÿÿG||ˆ—––”„rÿÿÿÿÿ„„„…ƒ€„|Gÿÿÿÿÿÿÿs„sÿÿÿÿÿÿÿÿÿÿÿq\ÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/ico00005.ico000640 001751 001751 00000000476 11160754257 016747 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ ª" ªª""ªªª"""*ªª""""ªª""" ""*ª"""""""ª"""""""*"""""""""""""""""""""""""""""""""" """""""""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/radar-08.ico000640 001751 001751 00000004766 11312111476 017121 0ustar00fkfk000000 000000  h&hŽ(  %t0(ƒ—0 Ù3¥ ù3¥ ù0 Ù(ƒ—%t0q )…™6¯ þAÓ ÿBÕ ÿBÕ ÿBÕ ÿBÕ ÿAÓ ÿ6¯ þ)…™q  +Á=Å ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ+Á +™;À ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ+™* 05« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ* 0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿÒÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿÎÿûÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ1Ò ÿÿÿûÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —:¿ 03¤ þ^«Bÿl²Rÿ<Ó-ÿÿÿÿÿûÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0;Á ™G 'ÿGÕ:ÿÿÿÿÿÿÿûÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™8Æ #ÖÁñÿþÿÿÿÿÿûÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ ÿ ýœòþóÿúÿ üÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â þ5þ›öÜïü=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ6¡ÿ=°ÿE£#ÿG 'ÿE£$ÿG¤&ÿH¯#ÿO¨/ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿÎÿÒÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ$Öÿñÿóÿ÷ÿðÿúÿûÿûÿþÿþÿûÿûÿûÿ üÿ1Ò ÿ<Ó-ÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿGÕ:ÿ^«Bÿi±Oÿr¬^ÿk²Rÿl²Rÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿEEECCCÿÿÿÿÿÿÿÿ-AAAAAAAEEÿÿÿÿÿEEE,--------ÿÿÿÿ,+++,++,++EEÿÿÿEE++++ÿÿ++EEÿÿEEÿÿ /EEÿÿEE )6 +ÿÿA %%=6Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ,Žš)Œ 15« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ)Œ 1/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿÍÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿúÿÎÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿûÿÿÿ"ÏÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —>À 13¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿûÿÿÿÿÿ6×(ÿk²Rÿi±Oÿ7¦þ>À 1;Á šG 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿûÿÿÿÿÿÿÿ>Ú3ÿQ¥2ÿ;Á š8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿûÿÿÿÿÿýÿòÿÜÁ8Æ 8â >Ë šL°'þu®aÿ•¿†ÿžÅÿüÿúÿôÿôþþšþ CÚ1@Ì —8³ Ù<°ù ðýøÞþ›þ2øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ3¥ ÿ3¦ ÿ7§ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿE£#ÿG 'ÿE£$ÿG¤&ÿL±'ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[®>ÿ\®>ÿÎÿÍÿÝÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ"Ïÿòÿõÿôÿ ñÿúÿøÿûÿûÿýÿÿÿÿÿûÿûÿûÿüÿ6×(ÿ>Ú3ÿ@Í ÿ@Î ÿAÏ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿ[¨@ÿ^«Bÿi±Oÿk²Rÿl²Rÿu®aÿ|·gÿŒ½{ÿ½|ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHDFDÿÿÿÿÿÿÿÿ.DDDDDDDHHÿÿÿÿÿHHH-..B-....ÿÿÿÿ,,-,,,,,-,FHÿÿÿHH,,,,,ÿÿ,HHÿÿHHÿÿ) HHÿÿHH>) ,ÿÿDH'H'''880!HPHÿÿÿSOMMMM>8;@MMÿÿÿÿHPPPOO=;8?HOÿÿÿÿÿSSSSS*=888ÿÿÿÿÿÿÿÿSSS?8=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/radar-06.ico000640 001751 001751 00000004766 11312111476 017117 0ustar00fkfk000000 000000  h&hŽ(  %t0(ƒ—0 Ù3¥ ù3¥ ù0 Ù(ƒ—%t0q )…™6¯ þAÓ ÿBÕ ÿBÕ ÿBÕ ÿBÕ ÿAÓ ÿ6¯ þ)…™q ÿ ÀÁ=Å ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ+Á ý›òÿ ãÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ+™ÿ3òþþÿÿÿáÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ* 0ý™óÿÿÿÿÿÿÿÞÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—÷ÙùÿÿÿÿÿÿÿÿÿÝÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù ìúøÿùÿúÿúÿúÿúÿÖÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —:¿ 03¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0;Á ™G 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿ=°ÿE£#ÿG 'ÿE£$ÿG¤&ÿH¯#ÿO¨/ÿL±'ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿ\®>ÿÁÿÖÿÝÿÞÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ íÿáÿóÿòÿøÿøÿúÿýÿþÿ ãÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿ[¨@ÿ^«Bÿi±Oÿr¬^ÿk²Rÿl²Rÿu®aÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿGGGEEEÿÿÿÿÿÿÿÿ5CCCCCCCGGÿÿÿÿÿ=@D545555554ÿÿÿÿ>>@3433333GGÿÿÿ==>=@333ÿÿ====>0GGÿÿ@@=7=7DÿÿGGÿÿGG $$5ÿÿCCGMGMGMG&*GPGÿÿÿTOMMMMMMMMGOÿÿÿÿGPPPOPPOOPTTÿÿÿÿÿTTTTTTTTTPÿÿÿÿÿÿÿÿTTTTTTÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/os28.ico000640 001751 001751 00000000762 10546014107 016367 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """""""""""""""""""""" """""""""""""""""""""""""""*"""""""ª""""""*ª"""""ªª""" *ªª"""ªªª"""ªª"" ª" privoxy-3.0.21-stable/./icons/os2.ico000640 001751 001751 00000005630 10546014107 016276 0ustar00fkfk000000 000000 BA(xCIh @ÿÿÿCIh €€€€€€€€€€€€ÌÌÌÿÿÿÿÿÿÿÿÿÿÿÿBA(ðCI h (ÿÿÿCI  €€€€€€€€€€€€ÌÌÌÿÿÿÿÿÿÿÿÿÿÿÿBA(CIø (PÿÿÿCIx ((€€€€€€€€€€€€ÌÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿü?øðààÀÀÀ€€€€€€€€€€ÀÀÀààðøü?ÿÿÿàÿÿÿÿÿwwˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‘—ˆˆ‘ˆˆwwwq—ˆˆˆˆˆ‡ˆˆˆˆˆˆq‘ˆˆˆˆˆˆ—ˆˆ‘‘xˆˆˆ™ˆ‘—ˆˆ™‘ˆˆˆ—ˆ—ˆˆ™™ˆˆˆˆˆˆˆˆ—ˆˆˆˆˆˆˆˆˆˆˆÿÿðüðððàpÀ0À0€€€€€€€€À0À0àpððüðÿÿðˆ€ˆ€ˆˆˆˆ‘ˆˆˆˆˆˆˆˆ‰˜ˆ‘ˆ‰™ˆˆ‰˜ˆˆˆˆˆˆˆˆÿÿÿÿÿÿÿÿÿÿÿþÿÿðÿÿÀÿÿ€ÿÿÿþü?øððàààÀÀÀÀÀÀÀÀÀÀàààððøü?þÿÿÿ€ÿÿÀÿÿðÿÿþÿÿÿÿÿÿÿÿÿÿÿwwpxwxwwww‡wwwwwwww‡‡xwxwxw‘xw‡‘xxxw‡‡xw‡wwwwxxxxxxxww‡‡‡‡‡‡‡q‘‘xˆxxˆˆˆxqxˆˆˆˆˆˆˆ‘xˆˆ™‘—ˆˆ‘xˆˆxˆxˆˆ‘‘‘xˆxˆˆ™xˆxˆˆwwwˆˆxˆˆˆˆˆˆˆxˆˆˆˆˆˆˆxˆˆˆˆˆˆˆˆˆˆˆˆˆprivoxy-3.0.21-stable/./icons/os21.ico000640 001751 001751 00000000762 10546014107 016360 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """""""""""""""""""""" """"""""""""""""""""""""""""¢"""""""ª"""""""ª¢"""""ªª" """ªª¢"""ªªª""ªª"ª privoxy-3.0.21-stable/./icons/os26.ico000640 001751 001751 00000000762 10546014107 016365 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """"¢"""""ª""""" ª¢"""" ªªª"""""ªªª¢""""ªªªª"""""""""""""""""""""""""""""""""" """""""""""""""""" privoxy-3.0.21-stable/./icons/radar-07.ico000640 001751 001751 00000004766 11312111476 017120 0ustar00fkfk000000 000000  h&hŽ(  %t0(ƒ—0 Ù3¥ ù3¥ ù0 Ù(ƒ—%t0q )…™6¯ þAÓ ÿBÕ ÿBÕ ÿBÕ ÿBÕ ÿAÓ ÿ6¯ þ)…™q  +Á=Å ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ+Á +™;À ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ+™* 05« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ* 0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ùðüüÿýÿýÿüÿüÿüÿÐÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ùõÛûÿÿÿÿÿÿÿÿÿ"Ñÿ:£ÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ùý˜óÿÿÿÿÿÿÿ1Õ"ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —ù1òþþÿÿÿ9Ø+ÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0ýšñÿAÛ6ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™þ ÜÁ[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ:£ÿ<°ÿ=°ÿE£#ÿG¤&ÿH¯#ÿO¨/ÿL±'ÿQ¥2ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿÐÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ Ýÿ"Ñÿñÿñÿóÿöÿûÿüÿüÿÿÿþÿ1Õ"ÿ9Ø+ÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿAÛ6ÿ[¨@ÿi±Oÿr¬^ÿk²Rÿl²Rÿu®aÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@>><ÿÿÿÿÿÿÿÿ<<<<<<<<@@ÿÿÿÿÿ@@>++++++<++ÿÿÿÿ*))))*)*))<@ÿÿÿ@@*))ÿÿ)@@ÿÿ@@ÿÿ555555,@@ÿÿ55555?)ÿÿ555-@@C@C@$@I@ÿÿÿ55AFFFFFFF@Hÿÿÿÿ@@IIHIIHHIMMÿÿÿÿÿMMMMMMMMMIÿÿÿÿÿÿÿÿMMMMMMÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/idle.ico000640 001751 001751 00000000476 10546014107 016513 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""*¢""""*¢""""*¢""" ""*¢""""""*¢""""""*ªª¢""""*ªªª""""*¢"ª""""*¢"ª"""*ªªª" "*ªª¢""""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/ico00004.ico000640 001751 001751 00000000476 11160754257 016746 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"ª ""ªª"""ªªª"""ªª¢"""ªª" """"ª¢""""""ª"""""""¢""""""""""""""""""""""""""""""""" """""""""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/ico00003.ico000640 001751 001751 00000000476 11160754257 016745 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""""*"""""ª""""*ª """""ªªª""""*ªªª""""ªªªª"""""""""""""""""""""""""""""" """""""""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/radar-03.ico000640 001751 001751 00000004766 11312111476 017114 0ustar00fkfk000000 000000  h&hŽ(  %t0(ƒ—0 Ù3¥ ù3¥ ù0 Ù(ƒ—%t0q )…™6¯ þAÓ ÿBÕ ÿBÕ ÿBÕ ÿBÕ ÿAÓ ÿ6¯ þ)…™q  +Á=Å ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ¸À© +™;À ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ%ßÿòÿé™* 05« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ#ÛþÿÿûÿóþÔ0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ!Ùÿÿÿÿÿÿÿôÿñ—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ×ÿÿÿÿÿÿÿÿÿ÷ÿôÙ4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿÒþþÿÿÿÿÿÿÿÿÿÿÿ îù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3§ ÿ2¨ ÿ2¨ ÿ3« ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —:¿ 03¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0;Á ™G 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿŸÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ¸ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ2¨ ÿ3« ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿ=°ÿE£#ÿG 'ÿE£$ÿG¤&ÿH¯#ÿO¨/ÿL±'ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿ\®>ÿÖÿÓÿ×ÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ!Ùÿ#Üÿ%ßÿéÿ ïÿòÿòÿôÿôÿ÷ÿûÿÿÿþÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿ[¨@ÿ^«Bÿi±Oÿr¬^ÿk²Rÿl²Rÿu®aÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMMMKLKÿÿÿÿÿÿÿÿIIIIIIIMMMÿÿÿÿÿMMM88788GMÇ ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿûþÿÿÿÿÿÿ!áÿ;À ÿ+™* 05« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿûþÿÿÿÿ!Ýÿ<Á ÿ<Á ÿ5« þ* 0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿûÿÿÿ Øÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿûÿÔþ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ Ëþ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —:¿ 03¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0;Á ™G 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿ=°ÿE£#ÿG 'ÿE£$ÿG¤&ÿH¯#ÿO¨/ÿL±'ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿ\®>ÿÄÿÕÿ Ìÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ Øÿ!Ýÿ êÿòÿöÿôÿøÿûÿøÿûÿþÿüÿüÿ!áÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿ[¨@ÿ^«Bÿi±Oÿr¬^ÿk²Rÿl²Rÿu®aÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJJBBBÿÿÿÿÿÿÿÿFFJJJÿ@@@JÿÿÿÿÿJJJ4FFÿBB@C3ÿÿÿÿ4222FJÿBBGJJÿÿÿJJ222BBCJ322ÿÿ2JJCÿJJÿÿJJÿJ2ÿÿJJÿÿJJ $$4ÿÿFFJPJPJPJ&*JSJÿÿÿWRPPPPPPPPJRÿÿÿÿJSSSRSSRRSWWÿÿÿÿÿWWWWWWWWWSÿÿÿÿÿÿÿÿWWWWWWÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/privoxy.ico000640 001751 001751 00000004766 11312111476 017323 0ustar00fkfk000000 000000  h&hŽ(  w1ƒ—+ Ù¤2 ù¤2 ù+ Ùƒ—w1q „š¯9 þÔQ ÿÖR ÿÖR ÿÖR ÿÖR ÿÔQ ÿ¯9 þ„šq  ‘"ÁÆG ÿÏN ÿÏN ÿÏN ÿÏN ÿÏN ÿÏN ÿÏN ÿÏN ÿÆG ÿ‘"Á Ž"šÁD ÿÉI ÿÉI ÿÓk9ÿöâØÿÉJ ÿÉI ÿÉI ÿÉI ÿÉI ÿÉI ÿÁD ÿŽ"š‘$ 1«7 þÂE ÿÂE ÿÂE ÿÏmAÿþýýÿÂE ÿÂE ÿÂE ÿÂE ÿÂE ÿÂE ÿÂE ÿ«7 þ‘$ 1™*—º? ÿ»@ ÿ»@ ÿ»@ ÿÊj@ÿþýýÿ»A ÿ»@ ÿ»@ ÿ»@ ÿ»@ ÿ»@ ÿ»@ ÿº? ÿ™*—¤2 Ù´; ÿ´; ÿ´; ÿ´; ÿÄf@ÿÿþýÿËvTÿÉpLÿºLÿ´; ÿ´; ÿ´; ÿ´; ÿ´; ÿ¤2 Ù§4 ù­7 ÿ­7 ÿ­7 ÿ­7 ÿ¿c@ÿÿÿÿÿñߨÿôåàÿýùøÿÕ˜ÿ­7 ÿ­7 ÿ­7 ÿ­7 ÿ§4 ù¨4 ù§2 ÿ§2 ÿ§2 ÿ§2 ÿº_@ÿþýýÿ§3 ÿ§2 ÿ¸Z:ÿúôòÿ¿jMÿ§2 ÿ§2 ÿ§2 ÿ¨4 ù«6 Ù - ÿ - ÿ - ÿ - ÿ¶_Dÿþýýÿ¥8ÿ¢2ÿ - ÿຮÿ×§˜ÿ - ÿ - ÿ - ÿ«6 Ù¶< —š) ÿ¤@$ÿªL1ÿ®T;ÿÀ|hÿþýýÿ¯X?ÿ¯W>ÿ®T;ÿåÈÀÿÚ±¦ÿ¥B&ÿ¬R8ÿž1ÿ¶< —ÀC 1¤1 þ¬WBÿ³fRÿ³fRÿćxÿþþýÿ¸o]ÿ¹r`ÿП“ÿþüüÿÊ”‡ÿ³fRÿ±cPÿ¦6þÀC 1ÁE š¡@'ÿ¸vgÿ¸vgÿÈ”ˆÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ðïÿײªÿ¸ugÿ¸ugÿ¦J2ÿÁE šÆT ¿C Á©T@ÿ¾…{ÿ¿ˆ~ÿÂŽ„ÿÂŽ„ÿÁ‹‚ÿ¾†|ÿ¾†|ÿ½…zÿ©T@ÿ¿C ÁÆT âT ÍL š°K'þ®laÿÀއÿÆ—‘ÿÆ—‘ÿÀ†ÿ­h^ÿ­G#þÍL šâT ÚX1ÎM —³: Ù°>ù±>ù³: ÙÎM —ÚX1øàÀ€€€€Ààø( ÿwÿqÿÿƒÿ„ÿŽ"ÿ‘"ÿ‘$ ÿš) ÿ™*ÿ+ ÿž1ÿ - ÿ¥1 ÿ¥2 ÿ§2 ÿ¢2ÿ§6ÿ¨4 ÿ©4 ÿ«6 ÿ¬7 ÿ­7 ÿ°9 ÿ´; ÿ¶< ÿº? ÿ¥8ÿ°>ÿ±>ÿ»@ ÿ»A ÿºLÿ¡@'ÿ¤@$ÿ¥B&ÿ®G#ÿ±K'ÿ¦J2ÿªL1ÿ¬R8ÿ®T;ÿ¯W>ÿ¯X?ÿ¸Z:ÿÀC ÿÁE ÿÁD ÿÂE ÿÆG ÿÍL ÿÉI ÿÉJ ÿÎM ÿÏN ÿÆTÿÔQ ÿÖR ÿÚXÿâTÿÓk9ÿ©T@ÿ¬WBÿ¶_Dÿº_@ÿ¿c@ÿ¿jMÿ­h^ÿ±cPÿ³fRÿ¸o]ÿ®laÿ¹r`ÿ¸ugÿ¸vgÿÄf@ÿÊj@ÿÏmAÿÉpLÿËvTÿÀ|hÿ½…zÿ¾…{ÿ¾†|ÿ¿ˆ~ÿćxÿÁ‹‚ÿÀ†ÿÀއÿÂŽ„ÿÊ”‡ÿÈ”ˆÿÕ˜ÿÆ—‘ÿП“ÿ×§˜ÿÚ±¦ÿײªÿຮÿåÈÀÿñߨÿöâØÿôåàÿ÷ðïÿúôòÿýùøÿþüüÿþþýÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;;;::9ÿÿÿÿÿÿÿÿ56737777;;ÿÿÿÿÿ;<9=f5255451ÿÿÿÿ11/Nl/////9;ÿÿÿ;;.Ml  ÿÿLjPO!;<ÿÿ<:Blegj]ÿÿAl-iC9<ÿÿ<9 @j c` ÿÿ88&)Qj,,-da===ÿÿÿ]]N]iPI]i]==ÿÿÿÿ8PP]iiifc]`]ÿÿÿÿÿ]cc]]]]]]=ÿÿÿÿÿÿÿÿ]cdcccÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/ico00007.ico000640 001751 001751 00000000476 11160754257 016751 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""""""""""""""""" """"""""""""""""""""""""ªªªª""""ªªª¢""""ªªª""""" ª¢"""" ª"""""¢""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/os25.ico000640 001751 001751 00000000762 10546014107 016364 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø ª" ªª""ªªª"""*ªª""""ªª""" ""*ª"""""""ª"""""""*"""""""""""""""""""""""""""""""""" """""""""""""""""" privoxy-3.0.21-stable/./icons/os22.ico000640 001751 001751 00000000762 10546014107 016361 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """""""""""""""""""""" """"""""""""""""""""""""""""ªªªª""""*ªªª"""""ªªª""""*ª """""ª"""""*"""""" privoxy-3.0.21-stable/./icons/ico00008.ico000640 001751 001751 00000000476 11160754257 016752 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""""""""""""""""" """""""""""""""""""""""""""*"""""""ª""""""*ª"""""ªª""" *ªª"""ªªª"""ªª"" ª" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/ico00006.ico000640 001751 001751 00000000476 11160754257 016750 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """"¢"""""ª""""" ª¢"""" ªªª"""""ªªª¢""""ªªªª"""""""""""""""""""""""""""""""""" """""""""""""""""" øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/ico00001.ico000640 001751 001751 00000000476 11160754257 016743 0ustar00fkfk000000 000000 (( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"" """""""""""""""""""""" """"""""""""""""""""""""""""¢"""""""ª"""""""ª¢"""""ªª" """ªª¢"""ªªª""ªª"ª øðÀÀ€€ÀÀðøprivoxy-3.0.21-stable/./icons/radar-05.ico000640 001751 001751 00000004766 11312111476 017116 0ustar00fkfk000000 000000  h&hŽ(  é0ù—öÛóý2¨ ù0 Ù(ƒ—%t0Æ ñ™òþóÿúÿÿÿ?× ÿBÕ ÿAÓ ÿ6¯ þ)…™q  ÀÁñÿüÿÿÿÿÿÿÿ=Ñ ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ+Á +™;À ÿ!àÿÿÿÿÿÿÿÿÿ:Ì ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ+™* 05« þ<Á ÿ<Á ÿ"Ûÿÿÿÿÿÿÿ8Å ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ* 0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ"Öÿÿÿÿÿ4À ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ#Ïÿþÿ2» ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ"Éÿ0´ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4§ ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ4¨ ù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿ6¡ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ4« Ù7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿO¨/ÿE£#ÿG¤&ÿV«8ÿ7ÿ7¶ —:¿ 03¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿk²Rÿk²Rÿi±Oÿ7¦þ:¿ 0;Á ™G 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿQ¥2ÿ;Á ™8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ;¿ Á8Æ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ7ÿ¼ÿ3¥ ÿ3¦ ÿ6¡ÿ7§ÿ2© ÿ4¨ ÿ5« ÿ5¬ ÿ6° ÿ0´ ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ2» ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿ=°ÿE£#ÿG 'ÿE£$ÿG¤&ÿH¯#ÿO¨/ÿL±'ÿQ¥2ÿQ©1ÿV«8ÿY­:ÿ[¨?ÿ[®>ÿ\®>ÿÁÿ"Éÿ#Ïÿ4À ÿ8Å ÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ:Ì ÿ?Ì ÿ"Öÿ"Ûÿ=Ñ ÿ?× ÿèÿñÿñÿóÿôÿ÷ÿúÿúÿüÿÿÿþÿ!àÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿ[¨@ÿ^«Bÿi±Oÿr¬^ÿk²Rÿl²Rÿu®aÿ|·gÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿFFKQQQÿÿÿÿÿÿÿÿCIKKKQOOSSÿÿÿÿÿSSKKKK;9::O:ÿÿÿÿ98>KKK9888OSÿÿÿSS8;KK7888ÿÿ84H#SSÿÿSS##6#ÿÿ#!!!!!!!!!!!SSÿÿSS$$!((!!####:ÿÿOOSYSYSYS*.S\Sÿÿÿ`[YYYYYYYYS[ÿÿÿÿS\\\[\\[[\``ÿÿÿÿÿ`````````\ÿÿÿÿÿÿÿÿ``````ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/radar-02.ico000640 001751 001751 00000004766 11312111476 017113 0ustar00fkfk000000 000000  h&hŽ(  %t0(ƒ—0 Ù3¥ ù3¥ ù0 Ù(ƒ—%t0q )…™6¯ þAÓ ÿBÕ ÿBÕ ÿBÕ ÿBÕ ÿAÓ ÿ6¯ þ)…™q  +Á=Å ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ@Î ÿ=Å ÿ+Á +™;À ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ>Ç ÿ;À ÿ+™* 05« þ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ<Á ÿ5« þ* 0/™—9¹ ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9º ÿ9¹ ÿ/™—2¤ Ù8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ8³ ÿ2¤ Ù4§ ù5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ5¬ ÿ4® ÿ4¯ ÿ4¯ ÿ3© ù4¨ ù3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿ3¦ ÿÏÿÿÿÿÿÿÿÿÿÿÿþÿñù4« Ù1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ1Ÿ ÿ6¡ÿ;£ÿ:£ÿ6¡ÿËÿÿÿÿÿÿÿÿÿ÷ÿùÙ7¶ —/™ ÿE£$ÿQ©1ÿY­:ÿ\®>ÿ[®>ÿ[®>ÿ[®>ÿY­:ÿ3Ñ#ÿÿÿÿÿÿÿôÿû—:¿ 03¤ þ^«Bÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²Rÿl²RÿAÒ2ÿÿÿýÿóþù0;Á ™G 'ÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿ|·gÿLÔ@ÿòÿýš8Æ ;¿ Á[¨@ÿŒ½{ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿ½|ÿŒ¼zÿ[¨?ÿ&ÖÁþ 8â ?Ë ™L°'þu®aÿ•¿†ÿžÅÿžÅÿ”¿…ÿr¬^ÿH®#þ?Ë ™8â EÙ0@Ì —8³ Ù<°ù=°ù8³ Ù@Ì —EÙ0øàÀ€€€€Ààø( ÿ$vÿ%zÿ(ÿ(ƒÿ)…ÿ,Žÿ,ÿ/™ ÿ0™ ÿ0 ÿ1Ÿ ÿ3¥ ÿ3¦ ÿ6¡ÿ3ª ÿ4¨ ÿ5« ÿ5¬ ÿ4® ÿ6° ÿ8³ ÿ8´ ÿ8¶ ÿ8´ ÿ9¹ ÿ9º ÿ6¡ÿ:£ÿ;£ÿ<°ÿ=°ÿG 'ÿE£$ÿH¯#ÿL±'ÿQ©1ÿY­:ÿ[¨?ÿ[®>ÿ\®>ÿËÿÏÿ;À ÿ<À ÿ=Å ÿ>Ç ÿ?Ì ÿ&Öÿòÿôÿ÷ÿòÿ öÿùÿøÿýÿýÿüÿþÿ3Ñ#ÿ@Í ÿ@Î ÿAÎ ÿAÓ ÿBÕ ÿBÖ ÿDÚÿAÒ2ÿ[¨@ÿ^«Bÿr¬^ÿl²Rÿu®aÿ|·gÿLÔ@ÿŒ¼zÿ½|ÿ”¿…ÿ•¿†ÿžÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCCC?A?ÿÿÿÿÿÿÿÿ????????CCÿÿÿÿÿCCC..?-.?...ÿÿÿÿ,,,,,-,,,,ACÿÿÿCC,,,,,ÿÿ,CCÿÿCCÿÿ*99;99:ÿÿCC""?55::5ÿÿ?C(CHCHC(C5555ÿÿÿPJHHHHHHHC55ÿÿÿÿCLLLJLLJJPKCÿÿÿÿÿPPPPPPPPPLÿÿÿÿÿÿÿÿPPPPPPÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøàÀ€€€€Ààøprivoxy-3.0.21-stable/./icons/os23.ico000640 001751 001751 00000000762 10546014107 016362 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"" """""""""*"""""ª""""*ª """""ªªª""""*ªªª""""ªªªª"""""""""""""""""""""""""""""" """""""""""""""""" privoxy-3.0.21-stable/./icons/os24.ico000640 001751 001751 00000000762 10546014107 016363 0ustar00fkfk000000 000000 BA\CINò@ ÿÿÿCINr@€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿøðÀÀ€€ÀÀðø"ª ""ªª"""ªªª"""ªª¢"""ªª" """"ª¢""""""ª"""""""¢""""""""""""""""""""""""""""""""" """""""""""""""""" privoxy-3.0.21-stable/./errlog.h000640 001751 001751 00000006421 12004551155 015426 0ustar00fkfk000000 000000 #ifndef ERRLOG_H_INCLUDED #define ERRLOG_H_INCLUDED #define ERRLOG_H_VERSION "$Id: errlog.h,v 1.29 2012/07/27 17:39:57 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/errlog.h,v $ * * Purpose : Log errors to a designated destination in an elegant, * printf-like fashion. * * Copyright : Written by and Copyright (C) 2001-2009 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #ifdef __cplusplus extern "C" { #endif /* Debug level for errors */ /* XXX: Should be renamed. */ #define LOG_LEVEL_GPC 0x0001 #define LOG_LEVEL_CONNECT 0x0002 #define LOG_LEVEL_IO 0x0004 #define LOG_LEVEL_HEADER 0x0008 #define LOG_LEVEL_WRITING 0x0010 #ifdef FEATURE_FORCE_LOAD #define LOG_LEVEL_FORCE 0x0020 #endif /* def FEATURE_FORCE_LOAD */ #define LOG_LEVEL_RE_FILTER 0x0040 #define LOG_LEVEL_REDIRECTS 0x0080 #define LOG_LEVEL_DEANIMATE 0x0100 #define LOG_LEVEL_CLF 0x0200 /* Common Log File format */ #define LOG_LEVEL_CRUNCH 0x0400 #define LOG_LEVEL_CGI 0x0800 /* CGI / templates */ #define LOG_LEVEL_RECEIVED 0x8000 #define LOG_LEVEL_ACTIONS 0x10000 /* Following are always on: */ #define LOG_LEVEL_INFO 0x1000 #define LOG_LEVEL_ERROR 0x2000 #define LOG_LEVEL_FATAL 0x4000 /* Exits after writing log */ extern void init_error_log(const char *prog_name, const char *logfname); extern void set_debug_level(int debuglevel); extern int debug_level_is_enabled(int debuglevel); extern void disable_logging(void); extern void init_log_module(void); extern void show_version(const char *prog_name); extern void log_error(int loglevel, const char *fmt, ...); extern const char *jb_err_to_string(int jb_error); /* Revision control strings from this header and associated .c file */ extern const char errlog_rcs[]; extern const char errlog_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef ERRLOG_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./doc/pcrs.3000640 001751 001751 00000036456 11631465043 015603 0ustar00fkfk000000 000000 .\" Copyright (c) 2001-2003 Andreas S. Oesterhelt .\" .\" This is free documentation; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2 of .\" the License, or (at your option) any later version. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public .\" License along with this manual; if not, write to the Free .\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, .\" MA 02111, USA. .\" .TH PCRS 3 "2 December 2003" "pcrs-0.0.3" .SH NAME pcrs - Perl-compatible regular substitution. .SH SYNOPSIS .br .B "#include " .PP .br .BI "pcrs_job *pcrs_compile(const char *" pattern "," .ti +5n .BI "const char *" substitute ", const char *" options , .ti +5n .BI "int *" errptr ); .PP .br .BI "pcrs_job *pcrs_compile_command(const char *" command , .ti +5n .BI "int *" errptr ); .PP .br .BI "int pcrs_execute(pcrs_job *" job ", char *" subject , .ti +5n .BI "int " subject_length ", char **" result , .ti +5n .BI "int *" result_length ); .PP .br .BI "int pcrs_execute_list (pcrs_job *" joblist ", char *" subject , .ti +5n .BI "int " subject_length ", char **" result , .ti +5n .BI "int *" result_length ); .PP .br .BI "pcrs_job *pcrs_free_job(pcrs_job *" job ); .PP .br .BI "void pcrs_free_joblist(pcrs_job *" joblist ); .PP .br .BI "char *pcrs_strerror(int " err ); .PP .br .SH DESCRIPTION The .SM PCRS library is a supplement to the .SB PCRE(3) library that implements .RB "regular expression based substitution, like provided by " Perl(1) "'s 's'" operator. It uses the same syntax and semantics as Perl 5, with just a few differences (see below). In a first step, the information on a substitution, i.e. the pattern, the substitute and the options are compiled from Perl syntax to an internal form .RB "called " pcrs_job " by using either the " pcrs_compile() " or " .BR pcrs_compile_command() " functions." Once the job is compiled, it can be used on subjects, which are arbitrary memory areas containing string or binary data, by calling .BR pcrs_execute() ". Jobs can be chained to joblists and whole" .RB "joblists can be applied to a subject using " pcrs_execute_list() . There are also convenience functions for freeing the jobs and for errno-to-string .RB "conversion, namely " pcrs_free_job() ", " pcrs_free_joblist() " and " .BR pcrs_strerror() . .SH COMPILING JOBS .RB "The function " pcrs_compile() " is called to compile a " pcrs_job .RI "from a " pattern ", " substitute " and " options " string." .RB "The resulting " "pcrs_job" " structure is dynamically allocated and it" .RB "is the caller's responsibility to call " "pcrs_free_job()" " when it's no longer needed." .BR "pcrs_compile_command()" " is a convenience wrapper function that parses a Perl" .IR "command" " of the form" .BI "s/" "pattern" "/" "substitute" "/[" "options" "]" .RB "into its components and then calls " "pcrs_compile()" ". As in Perl, you" .RB "are not bound to the '" "/" "' character: Whatever" .RB "follows the '" "s" "' will be used as the delimiter. Patterns or substitutes" that contain the delimiter need to quote it: \fBs/th\\/is/th\\/at/\fR .RB "will replace " "th/is" " by " "th/at" " and can be written more simply as" .BR "s|th/is|th/at|" "." .IR "pattern" ", " "substitute" ", " "options" " and " "command" " must be" .RI "zero-terminated C strings. " "substitute" " and " "options" " may be" .BR "NULL" ", in which case they are treated like the empty string." .SS "Return value and diagnostics" On success, both functions return a pointer to the compiled job. .RB "On failure, " "NULL" .RI "is returned. In that case, the pcrs error code is written to *" "err" "." .SS Patterns .RI "For the syntax of the " "pattern" ", see the " .BR "PCRE(3)" " manual page." .SS Substitutes .RI "The " "substitute" " uses" .RB "Perl syntax as documented in the " "perlre(1)" " manual page, with" some exceptions: Most notably and evidently, since .SM PCRS is not Perl, variable interpolation or Perl command substitution won't work. Special variables that do get interpolated, are: .TP .B "$1, $2, ..., $n" Like in Perl, these variables refer to what the nth capturing subpattern in the pattern matched. .TP .B "$& and $0" .RB "refer to the whole match. Note that " "$0" " is deprecated in recent" Perl versions and now refers to the program name. .TP .B "$+" refers to what the last capturing subpattern matched. .TP .BR "$` and $'" " (backtick and tick)" .RI "refer to the areas of the " "subject" " before and after the match, respectively." .RB "Note that, like in Perl, the " "unmodified" " subject is used, even" if a global substitution previously matched. .PP Perl4-style references to subpattern matches of the form \fB\\1, \\2, ...\fR .RB "which only exist in Perl5 for backwards compatibility, are " "not" supported. Also, since the substitute is a double-quoted string in Perl, you might expect all Perl syntax for special characters to apply. In fact, only the following are supported: .TP \fB\\n\fR newline (0x0a) .TP \fB\\r\fR carriage return (0x0d) .TP \fB\\t\fR horizontal tab (0x09) .TP \fB\\f\fR form feed (0x0c) .TP \fB\\b\fR backspace (0x08) .TP \fB\\a\fR alarm, bell (0x07) .TP \fB\\e\fR escape (0x1b) .TP \fB\\0\fR binary zero (0x00) .SS "Options" .RB "The options " "gmisx" " are supported. " "e" " is not, since it would" .RB "require a Perl interpreter and neither is " o ", because the pattern is explicitly compiled, anyway. Additionally, .SM PCRS .RB "honors the options " "U" " and " "T" "." Where .SM PCRE .RB "options are mentioned below, refer to " PCRE(3) " for the subtle differences" to Perl behaviour. .TP .B g .RB "Replace " all " instances of" .IR pattern " in " subject , not just the first one. .TP .B i .RI "Match the " pattern " without respect to case. This translates to" .SM PCRE_CASELESS. .TP .B m .RI "Treat the " subject " as consisting of multiple lines, i.e." .RB ' ^ "' matches immediately after, and '" $ "' immediately before each newline." Translates to .SM PCRE_MULTILINE. .TP .B s .RI "Treat the " subject " as consisting of one single line, i.e." .RB "let the scope of the '" . "' metacharacter include newlines." Translates to .SM PCRE_DOTALL. .TP .B x .RI "Allow extended regular expression syntax in the " pattern "," .RB "enabling whitespace and comments in complex patterns." Translates to .SM PCRE_EXTENDED. .TP .B U .RB "Switch the default behaviour of the '" * "' and '" + "' quantifiers" .RB "to ungreedy. Note that appending a '" ? "' switches back to greedy(!)." .RB "The explicit in-pattern switches " (?U) " and " (?-U) " remain unaffected." Translates to .SM PCRE_UNGREEDY. .TP .B T .RI "Consider the " substitute " trivial, i.e. do not interpret any references" or special character escape sequences in the substitute. Handy for large user-supplied substitutes, which would otherwise have to be examined and properly quoted. .PP Unsupported options are silently ignored. .SH EXECUTING JOBS .RI "Calling " pcrs_execute() " produces a modified copy of the " subject ", in which" .RB "the first (or all, if the '" g "' option was given when compiling the job)" .RI "occurance(s) of the job's " pattern " in the " subject " is replaced by the job's" .IR substitute . .RI "The first " subject_length " bytes following " subject " are processed, so" .RI "a " subject_length " that exceeds the actual " subject " is dangerous." .RI "Note that for zero-terminated C strings, you should set " subject_length " to" .BI strlen( subject ) \fR, so that the dollar metacharacter matches at the end of the string, not after the string-terminating null byte. For convenience, an extra null byte is appended to the result so it can again be used as a string. .RI "The " subject " itself is left untouched, and the " *result " is dynamically" .RB "allocated, so it is the caller's responsibility to " free() " it when it's" no longer needed. .RI "The result's length (excluding the extra null byte) is written to " *result_length "." .RB "If the job matched, the " PCRS_SUCCESS " flag in" .IB job ->flags is set. .SS String subjects If your .SS Return value and diagnostics .RB "On success, " pcrs_execute() " returns the number of substitutions that" were made, which is limited to 0 or 1 for non-global searches. .RI "On failure, a negative error code is returned and " result " is set" .RB "to " NULL . .SH FREEING JOBS .RB "It is not sufficient to call " free() " on a " pcrs_job ", because it " contains pointers to other dynamically allocated structures. .RB "Use " pcrs_free_job() " instead. It is safe to pass " NULL " pointers " .RB "(or pointers to invalid " pcrs_job "s that contain " NULL " pointers" .RB "to dependant structures) to " pcrs_free_job() "." .SS Return value .RB "The value of the job's " next " pointer." .SH CHAINING JOBS .SM PCRS .RB "supports to some extent the chaining of multiple " pcrs_job " structures by" .RB "means of their " next " member." Chaining the jobs is up to you, but once you have built a linked list of jobs, .RI "you can execute a whole " joblist " on a given subject by" .RB "a single call to " pcrs_execute_list() ", which will sequentially traverse" .RB "the linked list until it reaches a " NULL " pointer, and call " pcrs_execute() .RI "for each job it encounters, feeding the " result " and " result_length " of each" .RI "call into the next as the " subject " and " subject_length ". As in the single" .RI "job case, the original " subject " remains untouched, but all interim " result "s" .RB "are of course " free() "d. The return value is the accumulated number of matches" .RI "for all jobs in the " joblist "." .RI "Note that while this is handy, it reduces the diagnostic value of " err ", since " you won't know which job failed. .RI "In analogy, you can free all jobs in a given " joblist " by calling" .BR pcrs_free_joblist() . .SH QUOTING The quote character is (surprise!) '\fB\\\fR'. It quotes the delimiter in a .IR command ", the" .RB ' $ "' in a" .IR substitute ", and, of course, itself. Note that the" .RB ' $ "' doesn't need to be quoted if it isn't followed by " [0-9+'`&] "." .RI "For quoting in the " pattern ", please refer to" .BR PCRE(3) . .SH DIAGNOSTICS .RB "When " compiling " a job either via the " pcrs_compile() " or " pcrs_compile_command() .RB "functions, you know that something went wrong when you are returned a " NULL " pointer." .RI "In that case, or in the event of non-fatal warnings, the integer pointed to by " err contains a nonzero error code, which is either a passed-through .SM PCRE error code or one generated by .SM PCRS. Under normal circumstances, it can take the following values: .TP .B PCRE_ERROR_NOMEMORY While compiling the pattern, .SM PCRE ran out of memory. .TP .B PCRS_ERR_NOMEM While compiling the job, .SM PCRS ran out of memory. .TP .B PCRS_ERR_CMDSYNTAX .BR pcrs_compile_command() " didn't find four tokens while parsing the" .IR command . .TP .B PCRS_ERR_STUDY A .SM PCRE .RB "error occured while studying the compiled pattern. Since " pcre_study() only provides textual diagnostic information, the details are lost. .TP .B PCRS_WARN_BADREF .RI "The " substitute " contains a reference to a capturing subpattern that" .RI "has a higher index than the number of capturing subpatterns in the " pattern or that exceeds the current hard limit of 33 (See LIMITATIONS below). As in Perl, this is non-fatal and results in substitutions with the empty string. .PP .RB "When " executing " jobs via " pcrs_execute() " or " pcrs_execute_list() "," .RI "a negative return code indicates an error. In that case, *" result .RB "is " NULL ". Possible error codes are:" .TP .B PCRE_ERROR_NOMEMORY While matching the pattern, .SM PCRE ran out of memory. This can only happen if there are more than 33 backrefrences .RI "in the " pattern "(!)" .BR and " memory is too tight to extend storage for more." .TP .B PCRS_ERR_NOMEM While executing the job, .SM PCRS ran out of memory. .TP .B PCRS_ERR_BADJOB .RB "The " pcrs_job "* passed to " pcrs_execute " was NULL, or the" .RB "job is bogus (it contains " NULL " pointers to the compiled pattern, extra, or substitute). .PP If you see any other .SM PCRE error code passed through, you've either messed with the compiled job or found a bug in .SM PCRS. Please send me an email. .RB "Ah, and don't look for " PCRE_ERROR_NOMATCH ", since this" is not an error in the context of .SM PCRS. .RI "Should there be no match, an exact copy of the " subject " is" .RI "found at *" result " and the return code is 0 (matches)." All error codes can be translated into human readable text by means .RB "of the " pcrs_strerror() " function." .SH EXAMPLE A trivial command-line test program for .SM PCRS might look like: .nf #include #include int main(int Argc, char **Argv) { pcrs_job *job; char *result; size_t newsize; int err; if (Argc != 3) { fprintf(stderr, "Usage: %s s/pattern/substitute/[options] subject\\n", Argv[0]); return 1; } if (NULL == (job = pcrs_compile_command(Argv[1], &err))) { fprintf(stderr, "%s: compile error: %s (%d).\\n", Argv[0], pcrs_strerror(err), err); } if (0 > (err = pcrs_execute(job, Argv[2], strlen(Argv[2]), &result, &newsize))) { fprintf(stderr, "%s: exec error: %s (%d).\\n", Argv[0], pcrs_strerror(err), err); } else { printf("Result: *%s*\\n", result); free(result); } pcrs_free_job(job); return(err < 0); } .fi .SH LIMITATIONS The number of matches that a global job can have is only limited by the available memory. An initial storage for 40 matches is reserved, which is dynamically resized by the factor 1.6 whenever it is exhausted. The number of capturing subpatterns is currently limited to 33, which is a Bad Thing[tm]. It should be dynamically expanded until it reaches the .SM PCRE limit of 99. .br This limitation is particularly embarassing since .SM PCRE 3.5 has raised the capturing subpattern limit to 65K. All of the above values can be adjusted in the "Capacity" section .RB "of " pcrs.h "." The Perl-style escape sequences for special characters \\\fInnn\fR, \\x\fInn\fR, and \\c\fIX\fR are currently unsupported. .SH BUGS This library has only been tested in the context of one application and should be considered high risk. .SH HISTORY .SM PCRS was originally written for the Privoxy project (http://www.privoxy.org/). .SH SEE ALSO .B PCRE(3), perl(1), perlre(1) .SH AUTHOR .SM PCRS is Copyright 2000 - 2003 by Andreas Oesterhelt and is licensed under the terms of the GNU Lesser General Public License (LGPL), version 2.1, which should be included in this distribution, with the exception that the permission to replace that license with the GNU General Public License (GPL) given in section 3 is restricted to version 2 of the GPL. If it is missing from this distribution, the LGPL can be obtained from http://www.gnu.org/licenses/lgpl.html or by mail: Write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. privoxy-3.0.21-stable/./doc/source/changelog.sgml000640 001751 001751 00000076205 12116121647 020655 0ustar00fkfk000000 000000 Privoxy 3.0.21 stable is a bug-fix release for Privoxy 3.0.20 beta. It also addresses two security issues that affect all previous Privoxy versions. The changes since 3.0.20 beta are: Bug fixes: On POSIX-like platforms, network sockets with file descriptor values above FD_SETSIZE are properly rejected. Previously they could cause memory corruption in configurations that allowed the limit to be reached. Proxy authentication headers are removed unless the new directive enable-proxy-authentication-forwarding is used. Forwarding the headers potentionally allows malicious sites to trick the user into providing them with login information. Reported by Chris John Riley. Compiles on OS/2 again now that unistd.h is only included on platforms that have it. General improvements: The show-status page shows the FEATURE_STRPTIME_SANITY_CHECKS status. A couple of assert()s that could theoretically dereference NULL pointers in debug builds have been relocated. Added an LSB info block to the generic start script. Based on a patch from Natxo Asenjo. The max-client-connections default has been changed to 128 which should be more than enough for most setups. Action file improvements: Block rover.ebay./ar.*\&adtype= instead of "/.*\&adtype=" which caused too man false positives. Reported by u302320 in #360284, additional feedback from Adam Piggott. Unblock '.advrider.com/' and '/.*ADVrider'. Anonymously reported in #3603636. Stop blocking '/js/slider\.js'. Reported by Adam Piggott in #3606635 and _lvm in #2791160. Filter file improvements: Added an iframes filter. Documentation improvements: The whole GPLv2 text is included in the user manual now, so Privoxy can serve it itself and the user can read it without having to wade through GPLv3 ads first. Properly numbered and underlined a couple of section titles in the config that where previously overlooked due to a flaw in the conversion script. Reported by Ralf Jungblut. Improved the support instruction to hopefully make it harder to unintentionally provide insufficient information when requesting support. Previously it wasn't obvious that the information we need in bug reports is usually also required in support requests. Removed documentation about packages that haven't been provided in years. Privoxy-Regression-Test: Only log the test number when not running in verbose mode The position of the test is rarely relevant and it previously wasn't exactly obvious which one of the numbers was useful to repeat the test with --test-number. GNUmakefile improvements: Factor generate-config-file out of config-file to make testing more convenient. The clean target now also takes care of patch leftovers. Privoxy 3.0.20 beta contained the following changes compared to the previous stable release: Bug fixes: Client sockets are now properly shutdown and drained before being closed. This fixes page truncation issues with clients that aggressively pipeline data on platforms that otherwise discard already written data. The issue mainly affected Opera users and was initially reported by Kevin in #3464439, szotsaki provided additional information to track down the cause. Fix latency calculation for shared connections (disabled by default). It was broken since their introduction in 2009. The calculated latency for most connections would be 0 in which case the timeout detection failed to account for the real latency. Reject URLs with invalid port. Previously they were parsed incorrectly and characters between the port number and the first slash were silently dropped as shown by curl test 187. The default-server-timeout and socket-timeout directives accept 0 as valid value. Fix a race condition on Windows that could cause Privoxy to become unresponsive after toggling it on or off through the taskbar icon. Reported by Tim H. in #3525694. Fix the compilation on Windows when configured without IPv6 support. Fix an assertion that could cause debug builds to abort() in case of socks5 connection failures with "debug 2" enabled. Fix an assertion that could cause debug builds to abort() if a filter contained nul bytes in the replacement text. General improvements: Significantly improved keep-alive support for both client and server connections. New debug log level 65536 which logs all actions that were applied to the request. New directive client-header-order to forward client headers in a different order than the one in which they arrived. New directive tolerate-pipelining to allow client-side pipelining. If enabled (3.0.20 beta enables it by default), Privoxy will keep pipelined client requests around to deal with them once the current request has been served. New --config-test option to let Privoxy exit after checking whether or not the configuration seems valid. The limitations noted in TODO #22 and #23 still apply. Based on a patch by Ramkumar Chinchani. New limit-cookie-lifetime{} action to let cookies expire before the end of the session. Suggested by Rick Sykes in #1049575. Increase the hard-coded maximum number of actions and filter files from 10 to 30 (each). It doesn't significantly affect Privoxy's memory usage and recompiling wasn't an option for all Privoxy users that reached the limit. Add support for chunk-encoded client request bodies. Previously chunk-encoded request bodies weren't guaranteed to be forwarded correctly, so this can also be considered a bug fix although chunk-encoded request bodies aren't commonly used in the real world. Add support for Tor's optimistic-data SOCKS extension, which can reduce the latency for requests on newly created connections. Currently only the headers are sent optimistically and only if the client request has already been read completely which rules out requests with large bodies. After preventing the client from pipelining, don't signal keep-alive intentions. When looking at the response headers alone, it previously wasn't obvious from the client's perspective that no additional responses should be expected. Stop considering client sockets tainted after receiving a request with body. It hasn't been necessary for a while now and unnecessarily causes test failures when using curl's test suite. Allow HTTP/1.0 clients to signal interest in keep-alive through the Proxy-Connection header. While such client are rare in the real world, it doesn't hurt and couple of curl tests rely on it. Only remove duplicated Content-Type headers when filters are enabled. If they are not it doesn't cause ill effects and the user might not want it. Downgrade the removal message to LOG_LEVEL_HEADER to clarify that it's not an error in Privoxy and is unlikely to cause any problems in general. Anonymously reported in #3599335. Set the socket option SO_LINGER for the client socket. Move several variable declarations to the beginning of their code block. It's required when compiling with gcc 2.95 which is still used on some platforms. Initial patch submitted by Simon South in #3564815. Optionally try to sanity-check strptime() results before trusting them. Broken strptime() implementations have caused problems in the past and the most recent offender seems to be FreeBSD's libc (standards/173421). When filtering is enabled, let Range headers pass if the range starts at the beginning. This should work around (or at least reduce) the video playback issues with various Apple clients as reported by Duc in #3426305. Do not confuse a client hanging up with a connection time out. If a client closes its side of the connection without sending a request line, do not send the CLIENT_CONNECTION_TIMEOUT_RESPONSE, but report the condition properly. Allow closing curly braces as part of action values as long as they are escaped. On Windows, the logfile is now written before showing the GUI error message which blocks until the user acknowledges it. Reported by Adriaan in #3593603. Remove an unreasonable parameter limit in the CGI interface. The new parameter limit depends on the memory available and is currently unlikely to be reachable, due to other limits in both Privoxy and common clients. Reported by Andrew on ijbswa-users@. Decrease the chances of parse failures after requests with unsupported methods were sent to the CGI interface. Action file improvements: Remove the comment that indicated that updated default.action versions are released on their own. Block 'optimize.indieclick.com/' and 'optimized-by.rubiconproject.com/' Unblock 'adjamblog.wordpress.com/' and 'adjamblog.files.wordpress.com/'. Reported by Ryan Farmer in #3496116. Unblock '/.*Bugtracker'. Reported by pwhk in #3522341. Add test URLs for '.freebsd.org' and '.watson.org'. Unblock '.urbandictionary.com/popular'. Block '.adnxs.com/'. Block 'farm.plista.com/widgetdata.php'. Block 'rotation.linuxnewmedia.com/'. Block 'reklamy.sfd.pl/'. Reported by kacperdominik in #3399948. Block 'g.adspeed.net/'. Unblock 'websupport.wdc.com/'. Reported by Adam Piggot in #3577851. Block '/openx/www/delivery/'. Disable fast-redirects for '.googleapis.com/'. Block 'imp.double.net/'. Reported by David Bo in #3070411. Block 'gm-link.com/' which is used for email tracking. Reported by David Bo in #1812733. Verify that requests to "bwp." are blocked. URL taken from #1736879 submitted by Francois Marier. Block '/.*bannerid='. Reported by Adam Piggott in #2975779. Block 'cltomedia.info/delivery/' and '.adexprt.com/'. Anonymously reported in #2965254. Block 'de17a.com/'. Reported by David Bo in #3061472. Block 'oskar.tradera.com/'. Reported by David Bo in #3060596. Block '/scripts/webtrends\.js'. Reported by johnd16 in #3002729. Block requests for 'pool.*.adhese.com/'. Reported by johnd16 in #3002716. Update path pattern for Coremetrics and add tests. Pattern and URLs submitted by Adam Piggott #3168443. Enable +fast-redirects{check-decoded-url} for 'tr.anp.se/'. Reported by David Bo in #3268832. Unblock '.conrad.se/newsletter/banners/'. Reported by David Bo in #3413824. Block '.tynt.com/'. Reported by Dan Stahlke in #3421767. Unblock '.bbci.co.uk/radio/'. Reported by Adam Piggott in #3569603. Block requests to 'service.maxymiser.net/'. Reported by johnd16 in #3118401 (with a previous URL). Disable fast-redirects for Google's "let's pretend your computer is infected" page. Unblock '/.*download' to resolve actionsfile feedback #3498129. Submitted by Steven Kolins (soundcloud.com not working). Unblock '.wlxrs.com/' which is required by hotmail.com. Fixes #3413827 submitted by David Bo. Add two unblock patterns for popup radio and TV players. Submitted by Adam Piggott in #3596089. Filter file improvements & bug fixes: Add a referer tagger. Reduce the likelihood that the google filter messes up HTML-generating JavaScript. Reported by Zeno Kugy in #3520260. Documentation improvements: Revised all OS X sections due to new packaging module (OSXPackageBuilder). Update the list of supported operating systems to clarify that all Windows versions after 95 are expected to work and note that the platform-specific code for AmigaOS and QNX currently isn't maintained. Update 'Signals' section, the only explicitly handled signals are SIGINT, SIGTERM and SIGHUP. Add Haiku to the list of operating systems on which Privoxy is known to run. Add DragonFly to the list of BSDs on which Privoxy is known to run. Removed references to redhat-specific documentation set since it no longer exists. Removed references to building PDFs since we no longer do so. Multiple listen-address directives are supported since 3.0.18, correct the documentation to say so. Remove bogus section about long and short being preferable to int. Corrected some Internet JunkBuster references to Privoxy. Removed references to www.junkbusters.com since it is no longer maintained. Reported by Angelina Matson. Various grammar and spelling corrections Add a client-header-tagger{} example for disabling filtering for range requests. Correct a URL in the "Privoxy with Tor" FAQ. Spell 'refresh-tags' correctly. Reported by Don in #3571927. Sort manpage options alphabetically. Remove an incorrect sentence in the toggle section. The toggle state doesn't affect whether or not the Windows version uses the tray icon. Reported by Zeno Kugy in #3596395. Add new contributors since 3.0.19. Log message improvements: When stopping to watch a client socket due to pipelining, additionally log the socket number. Log the client socket and its condition before closing it. This makes it more obvious that the socket actually gets closed and should help when diagnosing problems like #3464439. In case of SOCKS5 failures, do not explicitly log the server's response. It hasn't helped so far and the response can already be logged by enabling "debug 32768" anyway. This reverts v1.81 and the follow-up bug fix v1.84. Relocate the connection-accepted message from listen_loop() to serve(). This way it's printed by the thread that is actually serving the connection which is nice when grepping for thread ids in log files. Code cleanups: Remove compatibility layer for versions prior to 3.0 since it has been obsolete for more than 10 years now. Remove the ijb_isupper() and ijb_tolower() macros from parsers.c since they aren't used in this file. Removed the 'Functions declared include:' comment sections since they tend to be incomplete, incorrect and out of date and the benefit seems questionable. Various comment grammar and comprehensibility improvements. Remove a pointless fflush() call in chat(). Flushing all streams pretty much all the time for no obvious reason is ridiculous. Relocate ijb_isupper()'s definition to project.h and get the ijb_tolower() definition from there, too. Relocate ijb_isdigit()'s definition to project.h. Rename ijb_foo macros to privoxy_foo. Add malloc_or_die() which will allow to simplify code paths where malloc() failures don't need to be handled gracefully. Add strdup_or_die() which will allow to simplify code paths where strdup() failures don't need to be handled gracefully. Replace strdup() calls with strdup_or_die() calls where it's safe and simplifies the code. Fix white-space around parentheses. Add missing white-space behind if's and the following parentheses. Unwrap a memcpy() call in resolve_hostname_to_ip(). Declare pcrs_get_delimiter()'s delimiters[] static const. Various optimisations to remove dead code and merge inefficient code structures for improved clarity, performance or code compactness. Various data type corrections. Change visibility of several code segments when compiling without FEATURE_CONNECTION_KEEP_ALIVE enabled for clarity. In pcrs_get_delimiter(), do not use delimiters outside the ASCII range. Fixes a clang complaint. Fix an error message in get_last_url() nobody is supposed to see. Reported by Matthew Fischer in #3507301. Fix a typo in the no-zlib-support complaint. Patch submitted by Matthew Fischer in #3507304. Shorten ssplit()'s prototype by removing the last two arguments. We always want to skip empty fields and ignore leading delimiters, so having parameters for this only complicates the API. Use an enum for the type of the action value. Rename action_name's member takes_value to value_type as it isn't used as boolean. Turn family mismatches in match_sockaddr() into fatal errors. Let enlist_unique_header() verify that the caller didn't pass a header containing either \r or \n. Change the hashes used in load_config() to unsigned int. That's what hash_string() actually returns and using a potentially larger type is at best useless. Use privoxy_tolower() instead of vanilla tolower() with manual casting of the argument. Catch ssplit() failures in parse_cgi_parameters(). Privoxy-Regression-Test: Add an 'Overwrite condition' directive to skip any matching tests before it. As it has a global scope, using it is more convenient than clowning around with the Ignore directive. Log to STDOUT instead of STDERR. Include the Privoxy version in the output. Various grammar and spelling corrections in documentation and code. Additional tests for range requests with filtering enabled. Tests with mostly invalid range request. Add a couple of hide-if-modified-since{} tests with different date formats. Cleaned up the format of the regression-tests.action file to match the format of default.action. Remove the "Copyright" line from print_version(). When using --help, every line of screen space matters and thus shouldn't be wasted on things the user doesn't care about. Privoxy-Log-Parser: Improve the --statistics performance by skipping sanity checks for input that shouldn't affect the results anyway. Add a --strict-checks option that enables some of the checks again, just in case anybody cares. The distribution of client requests per connection is included in the --statistic output. The --accept-unknown-messages option has been removed and the behavior is now the default. Accept and (mostly) highlight new log messages introduced with Privoxy 3.0.20. uagen: Bump generated Firefox version to 17. GNUmakefile improvements: The dok-tidy target no longer taints documents with a tidy-mark Change RA_MODE from 0664 to 0644. Suggested by Markus Dittrich in #3505445. Remove tidy's clean flag as it changes the scope of attributes. Link-specific colors end up being applied to all text. Reported by Adam Piggott in #3569551. Leave it up to the user whether or not smart tags are inserted. Let w3m itself do the line wrapping for the config file. It works better than fmt as it can honour pre tags causing less unintentional line breaks. Ditch a pointless '-r' passed to rm to delete files. The config-file target now requires less manual intervention and updates the original config. Change WDUMP to generate ASCII. Add WDUMP_UTF8 to allow UTF-8 in the AUTHORS file so the names are right. Stop pretending that lynx and links are supported for the documentation. configure improvements: On Haiku, do not pass -lpthread to the compiler. Haiku's pthreads implementation is contained in its system library, libroot, so no additional library needs to be searched. Patch submitted by Simon South in #3564815. Additional Haiku-specific improvements. Disable checks intended for multi-user systems as Haiku is presently single-user. Group Haiku-specific settings in their own section, following the pattern for Solaris, OS/2 and AmigaOS. Add additional library-related settings to remove the need for providing configure with custom LDFLAGS. Submitted by Simon South in #3574538. privoxy-3.0.21-stable/./doc/source/install.sgml000640 001751 001751 00000007346 12114164370 020372 0ustar00fkfk000000 000000 ]>
    This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/doc/source/install.sgml,v $ * * Purpose : INSTALL file to help with installing from source. * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA * *********************************************************************/ &buildsource;
    privoxy-3.0.21-stable/./doc/source/p-authors.sgml000640 001751 001751 00000006441 12113435046 020641 0ustar00fkfk000000 000000 Current Privoxy Team: ]]> Fabian Keil, lead developer David Schmidt Hal Burgiss Lee Rian Roland Rosenfeld Ian Silvester Former Privoxy Team Members: Johny Agotnes Rodrigo Barbosa Moritz Barsnick Ian Cummings Brian Dessent Jon Foster Karsten Hopp Alexander Lazic Daniel Leite Gábor Lipták Adam Lock Guy Laroche Justin McMurtry Mark Miller Gerry Murphy Andreas Oesterhelt Haroon Rafique Georg Sauthoff Thomas Steudten Jörg Strohmayer Rodney Stromlund Sviatoslav Sviridov Sarantis Paskalis Stefan Waldherr ]]> Thanks to the many people who have tested Privoxy, reported bugs, provided patches, made suggestions or contributed in some way. These include (in alphabetical order): Ken Arromdee Natxo Asenjo Devin Bayer Havard Berland David Bo Gergely Bor Francois Botha Reiner Buehl Andrew J. Caines Clifford Caoile Wan-Teh Chang Ramkumar Chinchani Billy Crook Frédéric Crozat Michael T. Davis Markus Dittrich Mattes Dolak Matthias Drochner Peter E. Florian Effenberger Markus Elfring Ryan Farmer Matthew Fischer Dean Gaudet Stephen Gildea Lizik Grelier Daniel Griscom Felix Gröbert Jeff H. Tim H. Aaron Hamid Darel Henman Magnus Holmgren Eric M. Hopper Ralf Horstmann Stefan Huehner Peter Hyman Derek Jennings Andrew Jones Julien Joubert Ralf Jungblut Petr Kadlec Steven Kolins Zeno Kugy David Laight Bert van Leeuwen Don Libes Paul Lieverse Han Liu Toby Lyward Wil Mahan Jindrich Makovicka Raphael Marichez Francois Marier Angelina Matson David Mediavilla Raphael Moll Amuro Namie Adam Piggott Petr Písar Dan Price Roberto Ragusa Félix Rauch Maynard Riley Andreas Rutkauskas Bart Schelstraete Chung-chieh Shan Simon South Dan Stahlke Oliver Stoeneberg Rick Sykes Spinor S. Peter Thoenen Martin Thomas Bobby G. Vinyard Jochen Voss Glenn Washburn Song Weijia Jörg Weinmann Darren Wiebe Anduin Withers Oliver Yeoh Jamie Zawinski Privoxy is based in part on code originally developed by Junkbusters Corp. and Anonymous Coders. Privoxy heavily relies on Philip Hazel's PCRE. The code to filter compressed content makes use of zlib which is written by Jean-loup Gailly and Mark Adler. On systems that lack snprintf(), Privoxy is using a version written by Mark Martinec. On systems that lack strptime(), Privoxy is using the one from the GNU C Library written by Ulrich Drepper. ]]> privoxy-3.0.21-stable/./doc/source/supported.sgml000640 001751 001751 00000003340 12074251700 020736 0ustar00fkfk000000 000000 At present, Privoxy is known to run on Windows 95 and later versions (98, ME, 2000, XP, Vista, Windows 7 etc.), GNU/Linux (RedHat, SuSE, Debian, Fedora, Gentoo, Slackware and others), Mac OS X (10.4 and upwards on PPC and Intel processors), OS/2, Haiku, DragonFly, FreeBSD, NetBSD, OpenBSD, Solaris, and various other flavors of Unix. Privoxy used to work on AmigaOS and QNX, too, but the code currently isn't maintained and its status unknown. It might no longer compile, but getting it working again shouldn't be too hard. But any operating system that runs TCP/IP, can conceivably take advantage of Privoxy in a networked situation where Privoxy would run as a server on a LAN gateway. Then only the gateway needs to be running one of the above operating systems. Source code is freely available, so porting to other operating systems is always a possibility. ]]> privoxy-3.0.21-stable/./doc/source/temp/manpage.refs000644 001751 001751 00000000065 11147312212 021264 0ustar00fkfk000000 000000 { 'refentry:PRIVOXY' => 'privoxy(1)', '' => '' } privoxy-3.0.21-stable/./doc/source/temp/manpage.links000644 001751 001751 00000000000 11147312212 021432 0ustar00fkfk000000 000000 privoxy-3.0.21-stable/./doc/source/newfeatures.sgml000640 001751 001751 00000006342 11264020321 021237 0ustar00fkfk000000 000000 Supports "Connection: keep-alive". Outgoing connections can be kept alive independently from the client. Supports IPv6, provided the operating system does so too, and the configure script detects it. Supports tagging which allows to change the behaviour based on client and server headers. Can be run as an "intercepting" proxy, which obviates the need to configure browsers individually. Sophisticated actions and filters for manipulating both server and client headers. Can be chained with other proxies. Integrated browser-based configuration and control utility at http://config.privoxy.org/ (shortcut: http://p.p/). Browser-based tracing of rule and filter effects. Remote toggling. Web page filtering (text replacements, removes banners based on size, invisible web-bugs and HTML annoyances, etc.) Modularized configuration that allows for standard settings and user settings to reside in separate files, so that installing updated actions files won't overwrite individual user settings. Support for Perl Compatible Regular Expressions in the configuration files, and a more sophisticated and flexible configuration syntax. GIF de-animation. Bypass many click-tracking scripts (avoids script redirection). User-customizable HTML templates for most proxy-generated pages (e.g. "blocked" page). Auto-detection and re-reading of config file changes. Most features are controllable on a per-site or per-location basis. Many smaller new features added, limitations and bugs removed. privoxy-3.0.21-stable/./doc/source/config.sgml000640 001751 001751 00000002156 12114164370 020163 0ustar00fkfk000000 000000 Privoxy"> ]>
    &config;
    privoxy-3.0.21-stable/./doc/source/seealso.sgml000640 001751 001751 00000006367 11770072466 020374 0ustar00fkfk000000 000000 Other references and sites of interest to Privoxy users: http://www.privoxy.org/, the Privoxy Home page. http://www.privoxy.org/faq/, the Privoxy FAQ. http://www.privoxy.org/developer-manual/, the Privoxy developer manual. https://sourceforge.net/projects/ijbswa/, the Project Page for Privoxy on SourceForge. http://config.privoxy.org/, the web-based user interface. Privoxy must be running for this to work. Shortcut: http://p.p/ https://sourceforge.net/tracker/?group_id=11118&atid=460288, to submit misses and other configuration related suggestions to the developers. http://www.squid-cache.org/, a popular caching proxy, which is often used together with Privoxy. http://www.pps.jussieu.fr/~jch/software/polipo/, Polipo is a caching proxy with advanced features like pipelining, multiplexing and caching of partial instances. In many setups it can be used as Squid replacement. https://www.torproject.org/, Tor can help anonymize web browsing, web publishing, instant messaging, IRC, SSH, and other applications. ]]> privoxy-3.0.21-stable/./doc/source/faq.sgml000640 001751 001751 00000436525 12114164370 017500 0ustar00fkfk000000 000000 Privoxy"> ]>
    Privoxy Frequently Asked Questions Copyright &my-copy; 2001-2011 by Privoxy Developers $Id: faq.sgml,v 2.92 2013/03/01 17:44:24 fabiankeil Exp $ This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> This FAQ gives quick answers to frequently asked questions about Privoxy. It is not a substitute for the Privoxy User Manual. What is Privoxy? &p-intro; Please note that this document is a work in progress. This copy represents the state at the release of version &p-version;. You can find the latest version of the document at http://www.privoxy.org/faq/. Please see the Contact section if you want to contact the developers. General Information Who should give &my-app; a try? Anyone who is interested in security, privacy, or in finer-grained control over their web and Internet experience. Is Privoxy the best choice for me? &my-app; is certainly a good choice, especially for those who want more control and security. Those with the willingness to read the documentation and the ability to fine-tune their installation will benefit the most. One of Privoxy's strengths is that it is highly configurable giving you the ability to completely personalize your installation. Being familiar with, or at least having an interest in learning about HTTP and other networking protocols, HTML, and Regular Expressions will be a big plus and will help you get the most out of &my-app;. A new installation just includes a very basic configuration. The user should take this as a starting point only, and enhance it as he or she sees fit. In fact, the user is encouraged, and expected to, fine-tune the configuration. Much of Privoxy's configuration can be done with a Web browser. But there are areas where configuration is done using a text editor to edit configuration files. Also note that the web-based action editor doesn't use authentication and should only be enabled in environments where all clients with access to &my-app; listening port can be trusted. What is a <quote>proxy</quote>? How does Privoxy work? A web proxy is a service, based on a software such as &my-app;, that clients (i.e. browsers) can use instead of connecting to web servers directly. The clients then ask the proxy to request objects (web pages, images, movies etc) on their behalf and to forward the data to the clients. It is a go-between. For details, see Wikipedia's proxy definition. There are many reasons to use web proxies, such as security (firewalling), efficiency (caching) and others, and there are any number of proxies to accommodate those needs. &my-app; is a proxy that is primarily focused on privacy enhancement, ad and junk elimination and freeing the user from restrictions placed on his activities. Sitting between your browser(s) and the Internet, it is in a perfect position to filter outbound personal information that your browser is leaking, as well as inbound junk. It uses a variety of techniques to do this, all of which are under your complete control via the various configuration files and options. Being a proxy also makes it easier to share configurations among multiple browsers and/or users. Does Privoxy do anything more than ad blocking? Yes, ad blocking is but one possible use. There are many, many ways &my-app; can be used to sanitize and customize web browsing. What is this new version of <quote><citetitle>Junkbuster</citetitle></quote>? &history; Why <quote>Privoxy</quote>? Why change the name from Junkbuster at all? Though outdated, Junkbusters Corporation continued to offer their original version of the Internet Junkbuster for a while, so publishing our Junkbuster-derived software under the same name would have led to confusion. There were also potential legal reasons not to use the Junkbuster name, as it was (and maybe still is) a registered trademark of Junkbusters Corporation. There were, however, no objections from Junkbusters Corporation to the Privoxy project itself, and they, in fact, shared our ideals and goals. The Privoxy developers also believed that there were so many improvements over the original code, that it was time to make a clean break from the past and make a name in their own right. Privoxy is the Privacy Enhancing Proxy. Also, its content modification and junk suppression gives you, the user, more control, more freedom, and allows you to browse your personal and private edition of the web. How does Privoxy differ from the old Junkbuster? Privoxy picks up where Junkbuster left off. Privoxy still blocks ads and banners, still manages cookies, and still helps protect your privacy. But, most of these features have been enhanced, and many new ones have been added, all in the same vein. Privoxy's new features include: &newfeatures; How does Privoxy know what is an ad, and what is not? Privoxy's approach to blocking ads is twofold: First, there are certain patterns in the locations (URLs) of banner images. This applies to both the path (you wouldn't guess how many web sites serve their banners from a directory called banners!) and the host (blocking the big banner hosting services like doublecklick.net already helps a lot). Privoxy takes advantage of this fact by using URL patterns to sort out and block the requests for things that sound like they would be ads or banners. Second, banners tend to come in certain sizes. But you can't tell the size of an image by its URL without downloading it, and if you do, it's too late to save bandwidth. Therefore, Privoxy also inspects the HTML sources of web pages while they are loaded, and replaces references to images with standard banner sizes by dummy references, so that your browser doesn't request them anymore in the first place. Both of this involves a certain amount of guesswork and is, of course, freely and readily configurable. Can Privoxy make mistakes? This does not sound very scientific. Actually, it's a black art ;-) And yes, it is always possible to have a broad rule accidentally block or change something by mistake. You will almost surely run into such situations at some point. It is tricky writing rules to cover every conceivable possibility, and not occasionally get false positives. But this should not be a big concern since the Privoxy configuration is very flexible, and includes tools to help identify these types of situations so they can be addressed as needed, allowing you to customize your installation. (See the Troubleshooting section below.) Will I have to configure Privoxy before I can use it? That depends on your expectations. The default installation should give you a good starting point, and block most ads and unwanted content, but many of the more advanced features are off by default, and require you to activate them. You do have to set up your browser to use Privoxy (see the Installation section below). And you will certainly run into situations where there are false positives, or ads not being blocked that you may not want to see. In these cases, you would certainly benefit by customizing Privoxy's configuration to more closely match your individual situation. And we encourage you to do this. This is where the real power of Privoxy lies! Can Privoxy run as a server on a network? Yes, &my-app; runs as a server already, and can easily be configured to serve more than one client. See How can I set up Privoxy to act as a proxy for my LAN below. My browser does the same things as Privoxy. Why should I use Privoxy at all? Modern browsers do indeed have some of the same functionality as Privoxy. Maybe this is adequate for you. But Privoxy is very versatile and powerful, and can probably do a number of things your browser just can't. In addition, a proxy is good choice if you use multiple browsers, or have a LAN with multiple computers since &my-app; can run as a server application. This way all the configuration is in one place, and you don't have to maintain a similar configuration for possibly many browsers or users. Note, however, that it's recommended to leverage both your browser's and Privoxy's privacy enhancing features at the same time. While your browser probably lacks some features &my-app; offers, it should also be able to do some things more reliable, for example restricting and suppressing JavaScript. Why should I trust Privoxy? The most important reason is because you have access to everything, and you can control everything. You can check every line of every configuration file yourself. You can check every last bit of source code should you desire. And even if you can't read code, there should be some comfort in knowing that other people can, and do read it. You can build the software from scratch, if you want, so that you know the executable is clean, and that it is yours. In fact, we encourage this level of scrutiny. It is one reason we use &my-app; ourselves. Is there is a license or fee? What about a warranty? Registration? Privoxy is free software and licensed under the GNU General Public License (GPL) version 2. It is free to use, copy, modify or distribute as you wish under the terms of this license. Please see the Copyright section for more information on the license and copyright. Or the LICENSE file that should be included. There is no warranty of any kind, expressed, implied or otherwise. That is something that would cost real money ;-) There is no registration either. Can Privoxy remove spyware? Adware? Viruses? No, at least not reliably enough to trust it. &my-app; is not designed to be a malware removal tool and the default configuration doesn't even try to filter out any malware. &my-app; could help prevent contact from (known) sites that use such tactics with appropriate configuration rules, and thus could conceivably prevent contamination from such sites. However, keeping such a configuration up to date would require a lot of time and effort that would be better spend on keeping your software itself up to date so it doesn't have known vulnerabilities. Can I use Privoxy with other ad-blocking software? &my-app; should work fine with other proxies and other software in general. But it is probably not necessary to use &my-app; in conjunction with other ad-blocking products, and this could conceivably cause undesirable results. It might be better to choose one software or the other and work a little to tweak its configuration to your liking. Note that this is an advice specific to ad blocking. I would like to help you, what can I do? Would you like to participate? Well, we always need help. There is something for everybody who wants to help us. We welcome new developers, packagers, testers, documentation writers or really anyone with a desire to help in any way. You DO NOT need to be a programmer. There are many other tasks available. In fact, the programmers often can't spend as much time programming because of some of the other, more mundane things that need to be done, like checking the Tracker feedback sections or responding to user questions on the mailing lists. So first thing, subscribe to the Privoxy Users or the Privoxy Developers mailing list, join the discussion, help out other users, provide general feedback or report problems you noticed. If you intend to help out with the trackers, you also might want to get an account on SourceForge.net so we don't confuse you with the other name-less users. We also have a Developer's Manual. While it is partly out of date, it's still worth reading. Our TODO list may be of interest to you as well. Please let us know if you want to work on one of the items listed. Installation Which browsers are supported by Privoxy? Any browser that can be configured to use a proxy, which should be virtually all browsers, including Firefox, Internet Explorer, Opera, and Safari among others. Direct browser support is not an absolute requirement since Privoxy runs as a separate application and talks to the browser in the standardized HTTP protocol, just like a web server does. Which operating systems are supported? &supported; Can I use Privoxy with my email client? As long as there is some way to set a HTTP proxy for the client, then yes, any application can be used, whether it is strictly speaking a browser or not. Though this may not be the best approach for dealing with some of the common abuses of HTML in email. See How can I configure Privoxy with Outlook? below for more on this. Be aware that HTML email presents a number of unique security and privacy related issues, that can require advanced skills to overcome. The developers recommend using email clients that can be configured to convert HTML to plain text for these reasons. I just installed Privoxy. Is there anything special I have to do now? All browsers should be told to use Privoxy as a proxy by specifying the correct proxy address and port number in the appropriate configuration area for the browser. It's possible to combine &my-app; with a packet filter to intercept HTTP requests even if the client isn't explicitly configured to use &my-app;, but where possible, configuring the client is recommended. See the User Manual for more details. You should also flush your browser's memory and disk cache to get rid of any cached junk items, and remove any stored cookies. What is the proxy address of Privoxy? If you set up the Privoxy to run on the computer you browse from (rather than your ISP's server or some networked computer on a LAN), the proxy will be on 127.0.0.1 (sometimes referred to as localhost, which is the special name used by every computer on the Internet to refer to itself) and the port will be 8118 (unless you used the listen-address config option to tell Privoxy to run on a different port). When configuring your browser's proxy settings you typically enter the word localhost or the IP address 127.0.0.1 in the boxes next to HTTP and Secure (HTTPS) and then the number 8118 for port. This tells your browser to send all web requests to Privoxy instead of directly to the Internet. Privoxy can also be used to proxy for a Local Area Network. In this case, your would enter either the IP address of the LAN host where Privoxy is running, or the equivalent hostname, e.g. 192.168.1.1. Port assignment would be same as above. Note that Privoxy doesn't listen on any LAN interfaces by default. Privoxy does not currently handle any other protocols such as FTP, SMTP, IM, IRC, ICQ, etc. I just installed Privoxy, and nothing is happening. All the ads are there. What's wrong? Did you configure your browser to use Privoxy as a proxy? It does not sound like it. See above. You might also try flushing the browser's caches to force a full re-reading of pages. You can verify that Privoxy is running, and your browser is correctly configured by entering the special URL: http://p.p/. This should take you to a page titled This is Privoxy.. with access to Privoxy's internal configuration. If you see this, then you are good to go. If you receive a page saying Privoxy is not running, then the browser is not set up to use your Privoxy installation. If you receive anything else (probably nothing at all), it could either be that the browser is not set up correctly, or that Privoxy is not running at all. Check the log file. For instructions on starting Privoxy and browser configuration, see the chapter on starting Privoxy in the User Manual. I get a <quote>Privoxy is not being used</quote> dummy page although Privoxy is running and being used. First, make sure that Privoxy is really running and being used by visiting http://p.p/. You should see the Privoxy main page. If not, see the chapter on starting Privoxy in the User Manual. Now if http://p.p/ works for you, but other parts of Privoxy's web interface show the dummy page, your browser has cached a redirection it encountered before Privoxy was being used. You need to clear your browser's cache. Note that shift-reloading the dummy page won't help, since that'll only refresh the dummy page, not the redirection that lead you there. The procedure for clearing the cache varies from browser to browser. For example, Mozilla/Netscape users would click Edit --> Preferences --> Advanced --> Cache and then click both Clear Memory Cache and Clear Disk Cache. In some Firefox versions it's Tools --> Options --> Privacy --> Cache and then click Clear Cache Now. Configuration What exactly is an <quote>actions</quote> file? &my-app; utilizes the concept of actions that are used to manipulate and control web page data. Actions files are where these actions that Privoxy could take while processing a certain request, are configured. Typically, you would define a set of default actions that apply globally to all URLs, then add exceptions to these defaults where needed. There is a wide array of actions available that give the user a high degree of control and flexibility on how to process each and every web page. Actions can be defined on a URL pattern basis, i.e. for single URLs, whole web sites, groups or parts thereof etc. Actions can also be grouped together and then applied to requests matching one or more patterns. There are many possible actions that might apply to any given site. As an example, if you are blocking cookies as one of your default actions, but need to accept cookies from a given site, you would need to define an exception for this site in one of your actions files, preferably in user.action. The <quote>actions</quote> concept confuses me. Please list some of these <quote>actions</quote>. For a comprehensive discussion of the actions concept, please refer to the actions file chapter in the User Manual. It includes a list of all actions and an actions file tutorial to get you started. How are actions files configured? What is the easiest way to do this? Actions files are just text files in a special syntax and can be edited with a text editor. But probably the easiest way is to access Privoxy's user interface with your web browser at http://config.privoxy.org/ (Shortcut: http://p.p/) and then select View & change the current configuration from the menu. Note that this feature must be explicitly enabled in the main config file (see enable-edit-actions). There are several different <quote>actions</quote> files. What are the differences? Please have a look at the the actions chapter in the User Manual for a detailed explanation. Where can I get updated Actions Files? Based on your feedback and the continuing development, updates of default.action will be made available from time to time on the files section of our project page. If you wish to receive an email notification whenever we release updates of Privoxy or the actions file, subscribe to our announce mailing list, ijbswa-announce@lists.sourceforge.net. Can I use my old config files? The syntax and purpose of configuration files has remained roughly the same throughout the 3.x series, but backwards compatibility is not guaranteed. Also each release contains updated, improved versions and it is therefore strongly recommended to install the newer configuration files and merge back your modifications. Why is the configuration so complicated? Complicated is in the eye of the beholder. Those that are familiar with some of the underlying concepts, such as regular expression syntax, take to it like a fish takes to water. Also, software that tries hard to be user friendly, often lacks sophistication and flexibility. There is always that trade-off there between power vs. easy-of-use. Furthermore, anyone is welcome to contribute ideas and implementations to enhance &my-app;. How can I make my Yahoo/Hotmail/Gmail account work? The default configuration shouldn't impact the usability of any of these services. It may, however, make all cookies temporary, so that your browser will forget your login credentials in between browser sessions. If you would like not to have to log in manually each time you access those websites, simply turn off all cookie handling for them in the user.action file. An example for yahoo might look like: # Allow all cookies for Yahoo login: # { -crunch-incoming-cookies -crunch-outgoing-cookies -session-cookies-only } .login.yahoo.com These kinds of sites are often quite complex and heavy with Javascript and thus fragile. So if still a problem, we have an alias just for such sticky situations: # Gmail is a _fragile_ site: # { fragile } # Gmail is ... mail.google.com Be sure to flush your browser's caches whenever making these kinds of changes, just to make sure the changes take. Make sure the domain, host and path are appropriate as well. Your browser can tell you where you are specifically and you should use that information for your configuration settings. Note that above it is not referenced as gmail.com, which is a valid domain name. What's the difference between the <quote>Cautious</quote>, <quote>Medium</quote> and <quote>Advanced</quote> defaults? Configuring Privoxy is not entirely trivial. To help you get started, we provide you with three different default action profiles in the web based actions file editor at http://config.privoxy.org/show-status. See the User Manual for a list of actions, and how the default profiles are set. Where the defaults are likely to break some sites, exceptions for known popular problem sites are included, but in general, the more aggressive your default settings are, the more exceptions you will have to make later. New users are best to start off in Cautious setting. This is safest and will have the fewest problems. See the User Manual for a more detailed discussion. It should be noted that the Advanced profile (formerly known as the Adventuresome profile) is more aggressive, and will make use of some of Privoxy's advanced features. Use at your own risk! Why can I change the configuration with a browser? Does that not raise security issues? It may seem strange that regular users can edit the config files with their browsers, although the whole /etc/privoxy hierarchy belongs to the user privoxy, with only 644 permissions. When you use the browser-based editor, Privoxy itself is writing to the config files. Because Privoxy is running as the user privoxy, it can update its own config files. If you run Privoxy for multiple untrusted users (e.g. in a LAN) or aren't entirely in control of your own browser, you will probably want to make sure that the web-based editor and remote toggle features are off by setting enable-edit-actions 0 and enable-remote-toggle 0 in the main configuration file. As of &my-app; 3.0.7 these options are disabled by default. What is the <filename>default.filter</filename> file? What is a <quote>filter</quote>? The default.filter file is where filters as supplied by the developers are defined. Filters are a special subset of actions that can be used to modify or remove web page content or headers on the fly. Content filters can be applied to anything in the page source, header filters can be applied to either server or client headers. Regular expressions are used to accomplish this. There are a number of pre-defined filters to deal with common annoyances. The filters are only defined here, to invoke them, you need to use the filter action in one of the actions files. Content filtering is automatically disabled for inappropriate MIME types, but if you know better than Privoxy what should or should not be filtered you can filter any content you like. Filters should not be confused with blocks, which is a completely different action, and is more typically used to block ads and unwanted sites. If you are familiar with regular expressions, and HTML, you can look at the provided default.filter with a text editor and define your own filters. This is potentially a very powerful feature, but requires some expertise in both regular expressions and HTML/HTTP. user.filter, so they won't be overwritten during upgrades. The ability to define multiple filter files in config is a new feature as of v. 3.0.5.]]> There is no GUI editor option for this part of the configuration, but you can disable/enable the various pre-defined filters of the included default.filter file with the web-based actions file editor. Note that the custom actions editor must be explicitly enabled in the main config file (see enable-edit-actions). If you intend to develop your own filters, you might want to have a look at Privoxy-Filter-Test. How can I set up Privoxy to act as a proxy for my LAN? By default, Privoxy only responds to requests from 127.0.0.1 (localhost). To have it act as a server for a network, this needs to be changed in the main configuration file. Look for the listen-address option, which may be commented out with a # symbol. Make sure it is uncommented, and assign it the address of the LAN gateway interface, and port number to use. Assuming your LAN address is 192.168.1.1 and you wish to run Privoxy on port 8118, this line should look like: listen-address 192.168.1.1:8118 Save the file, and restart Privoxy. Configure all browsers on the network then to use this address and port number. Alternately, you can have Privoxy listen on all available interfaces: listen-address :8118 And then use Privoxy's permit-access feature to limit connections. A firewall in this situation is recommended as well. The above steps should be the same for any TCP network, regardless of operating system. If you run Privoxy on a LAN with untrusted users, we recommend that you double-check the access control and security options! Instead of ads, now I get a checkerboard pattern. I don't want to see anything. The replacement for blocked images can be controlled with the set-image-blocker action. You have the choice of a checkerboard pattern, a transparent 1x1 GIF image (aka blank), or a redirect to a custom image of your choice. Note that this choice only has effect for images which are blocked as images, i.e. whose URLs match both a handle-as-image and block action. If you want to see nothing, then change the set-image-blocker action to blank. This can be done by editing the user.action file, or through the web-based actions file editor. Why would anybody want to see a checkerboard pattern? Remember that telling which image is an ad and which isn't, is an educated guess. While we hope that the standard configuration is rather smart, it will make occasional mistakes. The checkerboard image is visually decent, and it shows you where images have been blocked, which can be very helpful in case some navigation aid or otherwise innocent image was erroneously blocked. It is recommended for new users so they can see what is happening. Some people might also enjoy seeing how many banners they don't have to see. I see some images being replaced with text instead of the checkerboard image. Why and how do I get rid of this? This happens when the banners are not embedded in the HTML code of the page itself, but in separate HTML (sub)documents that are loaded into (i)frames or (i)layers, and these external HTML documents are blocked. Being non-images they get replaced by a substitute HTML page rather than a substitute image, which wouldn't work out technically, since the browser expects and accepts only HTML when it has requested an HTML document. The substitute page adapts to the available space and shows itself as a miniature two-liner if loaded into small frames, or full-blown with a large red "BLOCKED" banner if space allows. If you prefer the banners to be blocked by images, you must see to it that the HTML documents in which they are embedded are not blocked. Clicking the See why link offered in the substitute page will show you which rule blocked the page. After changing the rule and un-blocking the HTML documents, the browser will try to load the actual banner images and the usual image blocking will (hopefully!) kick in. Can Privoxy run as a service on Win2K/NT/XP? Windows service functionality. See the User Manual for details on how to install and configure Privoxy as a service. Earlier ]]>3.x versions could run as a system service using srvany.exe. See the discussion at http://sourceforge.net/tracker/?func=detail&atid=361118&aid=485617&group_id=11118, for details, and a sample configuration. How can I make Privoxy work with other proxies? This can be done and is often useful to combine the benefits of Privoxy with those of a another proxy, for example to cache content. See the forwarding chapter in the User Manual which describes how to do this. If you intend to use Privoxy with Tor, please also have a look at How do I use Privoxy together with Tor. Can I just set Privoxy to use port 80 and thus avoid individual browser configuration? No, its more complicated than that. This only works with special kinds of proxies known as intercepting proxies (see below). Can Privoxy run as a <quote>transparent </quote> proxy? The whole idea of Privoxy is to modify client requests and server responses in all sorts of ways and therefore it's not a transparent proxy as described in RFC 2616. However, some people say transparent proxy when they mean intercepting proxy. If you are one of them, please read the next entry. Can Privoxy run as a <quote>intercepting</quote> proxy? Privoxy can't intercept traffic itself, but it can handle requests that where intercepted and redirected with a packet filter (like PF or iptables), as long as the Host header is present. As the Host header is required by HTTP/1.1 and as most web sites rely on it anyway, this limitation shouldn't be a problem. Please refer to your packet filter's documentation to learn how to intercept and redirect traffic into Privoxy. Afterward you just have to configure Privoxy to accept intercepted requests. How can I configure Privoxy for use with Outlook? Versions of Outlook prior to Office 2007, use Internet Explorer components to both render HTML, and fetch any HTTP requests that may be embedded in an HTML email. So however you have Privoxy configured to work with IE, this configuration should automatically be shared, at least with older version of Internet Explorer. Starting with Office 2007, Microsoft is instead using the MS-Word rendering engine with Outlook. It is unknown whether this can be configured to use a proxy. How can I have separate rules just for HTML mail? The short answer is, you can't. Privoxy has no way of knowing which particular application makes a request, so there is no way to distinguish between web pages and HTML mail. Privoxy just blindly proxies all requests. In the case of Outlook Express (see above), OE uses IE anyway, and there is no way for Privoxy to ever be able to distinguish between them (nor could any other proxy type application for that matter). For a good discussion of some of the issues involved (including privacy and security issues), see http://sourceforge.net/tracker/?func=detail&atid=211118&aid=629518&group_id=11118. I sometimes notice cookies sneaking through. How? Cookies can be set in several ways. The classic method is via the Set-Cookie HTTP header. This is straightforward, and an easy one to manipulate, such as the &my-app; concept of session-cookies-only. There is also the possibility of using Javascript to set cookies (&my-app; calls these content-cookies). This is trickier because the syntax can vary widely, and thus requires a certain amount of guesswork. It is not realistic to catch all of these short of disabling Javascript, which would break many sites. And lastly, if the cookies are embedded in a HTTPS/SSL secure session via Javascript, they are beyond Privoxy's reach. All in all, &my-app; can help manage cookies in general, can help minimize the loss of privacy posed by cookies, but can't realistically stop all cookies. Are all cookies bad? Why? No, in fact there are many beneficial uses of cookies. Cookies are just a method that browsers can use to store data between pages, or between browser sessions. Sometimes there is a good reason for this, and the user's life is a bit easier as a result. But there is a long history of some websites taking advantage of this layer of trust, and using the data they glean from you and your browsing habits for their own purposes, and maybe to your potential detriment. Such sites are using you and storing their data on your system. That is why the privacy conscious watch from whom those cookies come, and why they really need to be there. See the Wikipedia cookie definition for more. How can I allow permanent cookies for my trusted sites? There are several actions that relate to cookies. The default behavior is to allow only session cookies, which means the cookies only last for the current browser session. This eliminates most kinds of abuse related to cookies. But there may be cases where you want cookies to last. To disable all cookie actions, so that cookies are allowed unrestricted, both in and out, for example.com: { -crunch-incoming-cookies -crunch-outgoing-cookies -session-cookies-only -filter{content-cookies} } .example.com Place the above in user.action. Note that some of these may be off by default anyway, so this might be redundant, but there is no harm being explicit in what you want to happen. user.action includes an alias for this situation, called allow-all-cookies. Can I have separate configurations for different users? Each instance of Privoxy has its own configuration, including such attributes as the TCP port that it listens on. What you can do is run multiple instances of Privoxy, each with a unique listen-address configuration setting, and configuration path, and then each of these can have their own configurations. Think of it as per-port configuration. Simple enough for a few users, but for large installations, consider having groups of users that might share like configurations. Can I set-up Privoxy as a whitelist of <quote>good</quote> sites? Sure. There are a couple of things you can do for simple white-listing. Here's one real easy one: ############################################################ # Blacklist ############################################################ { +block } / # Block *all* URLs ############################################################ # Whitelist ############################################################ { -block } kids.example.com toys.example.com games.example.com This allows access to only those three sites by first blocking all URLs, and then subsequently allowing three specific exceptions. Another approach is Privoxy's trustfile concept, which incorporates the notion of trusted referrers. See the Trust documentation for details. These are fairly simple approaches and are not completely foolproof. There are various other configuration options that should be disabled (described elsewhere here and in the User Manual) so that users can't modify their own configuration and easily circumvent the whitelist. How can I turn off ad-blocking? Ad blocking is achieved through a complex application of various &my-app; actions. These actions are deployed against simple images, banners, flash animations, text pages, JavaScript, pop-ups and pop-unders, etc., so its not as simple as just turning one or two actions off. The various actions that make up &my-app; ad blocking are hard-coded into the default configuration files. It has been assumed that everyone using &my-app; is interested in this particular feature. If you want to do without this, there are several approaches you can take: You can manually undo the many block rules in default.action. Or even easier, just create your own default.action file from scratch without the many ad blocking rules, and corresponding exceptions. Or lastly, if you are not concerned about the additional blocks that are done for privacy reasons, you can very easily over-ride all blocking with the following very simple rule in your user.action: # Unblock everybody, everywhere { -block } / # UN-Block *all* URLs Or even a more comprehensive reversing of various ad related actions: # Unblock everybody, everywhere, and turn off appropriate filtering, etc { -block \ -filter{banners-by-size} \ -filter{banners-by-link} \ allow-popups \ } / # UN-Block *all* URLs and allow ads This last action in this compound statement, allow-popups, is an alias that disables various pop-up blocking features. How can I have custom template pages, like the <emphasis>BLOCKED</emphasis> page? &my-app; templates are specialized text files utilized by &my-app; for various purposes and can easily be modified using any text editor. All the template pages are installed in a sub-directory appropriately named: templates. Knowing something about HTML syntax will of course be helpful. Be forewarned that the default templates are subject to being overwritten during upgrades. You can, however, create completely new templates, place them in another directory and specify the alternate path in the main config. For details, have a look at the templdir option. How can I remove the <quote>Go There Anyway</quote> link from the <emphasis>BLOCKED</emphasis> page? There is more than one way to do it (although Perl is not involved). Editing the BLOCKED template page (see above) may dissuade some users, but this method is easily circumvented. Where you need this level of control, you might want to build &my-app; from source, and disable various features that are available as compile-time options. You should configure the sources as follows: ./configure --disable-toggle --disable-editor --disable-force This will create an executable with hard-coded security features so that &my-app; does not allow easy bypassing of blocked sites, or changing the current configuration via any connected user's web browser. Finally, all of these features can also be toggled on/off via options in Privoxy's main config file which means you don't have to recompile anything. Miscellaneous How much does Privoxy slow my browsing down? This has to add extra time to browsing. How much of an impact depends on many things, including the CPU of the host system, how aggressive the configuration is, which specific actions are being triggered, the size of the page, the bandwidth of the connection, etc. Overall, it should not slow you down any in real terms, and may actually help speed things up since ads, banners and other junk are not typically being retrieved and displayed. The actual processing time required by Privoxy itself for each page, is relatively small in the overall scheme of things, and happens very quickly. This is typically more than offset by time saved not downloading and rendering ad images and other junk content (if ad blocking is being used). Filtering content via the filter or deanimate-gifs actions may cause a perceived slowdown, since the entire document needs to be buffered before displaying. And on very large documents, filtering may have some measurable impact. How much depends on the page size, the actual definition of the filter(s), etc. See below. Most other actions have little to no impact on speed. Also, when filtering is enabled but zlib support isn't available, compression is often disabled (see prevent-compression). This can have an impact on speed as well, although it's probably smaller than you might think. Again, the page size, etc. will determine how much of an impact. I notice considerable delays in page requests. What's wrong? If you use any filter action, such as filtering banners by size, web-bugs etc, or the deanimate-gifs action, the entire document must be loaded into memory in order for the filtering mechanism to work, and nothing is sent to the browser during this time. The loading time typically does not really change much in real numbers, but the feeling is different, because most browsers are able to start rendering incomplete content, giving the user a feeling of "it works". This effect is more noticeable on slower dialup connections. Extremely large documents may have some impact on the time to load the page where there is filtering being done. But overall, the difference should be very minimal. If there is a big impact, then probably some other situation is contributing (like anti-virus software). Filtering is automatically disabled for inappropriate MIME types. But note that if the web server mis-reports the MIME type, then content that should not be filtered, could be. Privoxy only knows how to differentiate filterable content because of the MIME type as reported by the server, or because of some configuration setting that enables/disables filtering. What are "http://config.privoxy.org/" and "http://p.p/"? http://config.privoxy.org/ is the address of Privoxy's built-in user interface, and http://p.p/ is a shortcut for it. Since Privoxy sits between your web browser and the Internet, it can simply intercept requests for these addresses and answer them with its built-in web server. This also makes for a good test for your browser configuration: If entering the URL http://config.privoxy.org/ takes you to a page saying This is Privoxy ..., everything is OK. If you get a page saying Privoxy is not working instead, then your browser didn't use Privoxy for the request, hence it could not be intercepted, and you have accessed the real web site at config.privoxy.org. How can I submit new ads, or report problems? Please see the Contact section for various ways to interact with the developers. If I do submit missed ads, will they be included in future updates? Whether such submissions are eventually included in the default.action configuration file depends on how significant the issue is. We of course want to address any potential problem with major, high-profile sites such as Google, Yahoo, etc. Any site with global or regional reach, has a good chance of being a candidate. But at the other end of the spectrum are any number of smaller, low-profile sites such as for local clubs or schools. Since their reach and impact are much less, they are best handled by inclusion in the user's user.action, and thus would be unlikely to be included. Why doesn't anyone answer my support request? Rest assured that it has been read and considered. Why it is not answered, could be for various reasons, including no one has a good answer for it, no one has had time to yet investigate it thoroughly, it has been reported numerous times already, or because not enough information was provided to help us help you. Your efforts are not wasted, and we do appreciate them. How can I hide my IP address? If you run both the browser and &my-app; locally, you cannot hide your IP address with Privoxy or ultimately any other software alone. The server needs to know your IP address so that it knows where to send the responses back. There are many publicly usable "anonymous" proxies out there, which provide a further level of indirection between you and the web server. However, these proxies are called "anonymous" because you don't need to authenticate, not because they would offer any real anonymity. Most of them will log your IP address and make it available to the authorities in case you violate the law of the country they run in. In fact you can't even rule out that some of them only exist to *collect* information on (those suspicious) people with a more than average preference for privacy. If you want to hide your IP address from most adversaries, you should consider chaining Privoxy with Tor. The configuration details can be found in How do I use Privoxy together with Tor section just below. Can Privoxy guarantee I am anonymous? No. Your chances of remaining anonymous are improved, but unless you chain Privoxy with Tor or a similar proxy and know what you're doing when it comes to configuring the rest of your system, you should assume that everything you do on the Web can be traced back to you. Privoxy can remove various information about you, and allows you more freedom to decide which sites you can trust, and what details you want to reveal. But it neither hides your IP address, nor can it guarantee that the rest of the system behaves correctly. There are several possibilities how a web sites can find out who you are, even if you are using a strict Privoxy configuration and chained it with Tor. Most of Privoxy's privacy-enhancing features can be easily subverted by an insecure browser configuration, therefore you should use a browser that can be configured to only execute code from trusted sites, and be careful which sites you trust. For example there is no point in having Privoxy modify the User-Agent header, if websites can get all the information they want through JavaScript, ActiveX, Flash, Java etc. A few browsers disclose the user's email address in certain situations, such as when transferring a file by FTP. Privoxy does not filter FTP. If you need this feature, or are concerned about the mail handler of your browser disclosing your email address, you might consider products such as NSClean. Browsers available only as binaries could use non-standard headers to give out any information they can have access to: see the manufacturer's license agreement. It's impossible to anticipate and prevent every breach of privacy that might occur. The professionally paranoid prefer browsers available as source code, because anticipating their behavior is easier. Trust the source, Luke! A test site says I am not using a Proxy. Good! Actually, they are probably testing for some other kinds of proxies. Hiding yourself completely would require additional steps. How do I use Privoxy together with Tor? Before you configure Privoxy to use Tor, please follow the User Manual chapters 2. Installation and 5. Startup to make sure Privoxy itself is setup correctly. If it is, refer to Tor's extensive documentation to learn how to install Tor, and make sure Tor's logfile says that Tor has successfully opened a circuit and it looks like client functionality is working. If either Tor or Privoxy isn't working, their combination most likely will neither. Testing them on their own will also help you to direct problem reports to the right audience. If Privoxy isn't working, don't bother the Tor developers. If Tor isn't working, don't send bug reports to the Privoxy Team. If you verified that Privoxy and Tor are working, it is time to connect them. As far as Privoxy is concerned, Tor is just another proxy that can be reached by socks4, socks4a and socks5. Most likely you are interested in Tor to increase your anonymity level, therefore you should use socks5, to make sure DNS requests are done through Tor and thus invisible to your local network. Using socks4a would work too, but with socks5 you get more precise error messages. Since Privoxy 3.0.5, its main configuration file is already prepared for Tor, if you are using a default Tor configuration and run it on the same system as &my-app;, you just have to edit the forwarding section and uncomment the line: # forward-socks5 / 127.0.0.1:9050 . This is enough to reach the Internet, but additionally you might want to uncomment the following forward rules, to make sure your local network is still reachable through Privoxy: # forward 192.168.*.*/ . # forward 10.*.*.*/ . # forward 127.*.*.*/ . Unencrypted connections to systems in these address ranges will be as (un)secure as the local network is, but the alternative is that your browser can't reach the network at all. Then again, that may actually be desired and if you don't know for sure that your browser has to be able to reach the local network, there's no reason to allow it. If you want your browser to be able to reach servers in your local network by using their names, you will need additional exceptions that look like this: # forward localhost/ . Save the modified configuration file and open http://config.privoxy.org/show-status in your browser, confirm that Privoxy has reloaded its configuration and that there are no other forward lines, unless you know that you need them. If everything looks good, refer to Tor Faq 4.2 to learn how to verify that you are really using Tor. Afterward, please take the time to at least skim through the rest of Tor's documentation. Make sure you understand what Tor does, why it is no replacement for application level security, and why you probably don't want to use it for unencrypted logins. Might some things break because header information or content is being altered? Definitely. It is common for sites to use browser type, browser version, HTTP header content, and various other techniques in order to dynamically decide what to display and how to display it. What you see, and what I see, might be very different. There are many, many ways that this can be handled, so having hard and fast rules, is tricky. The User-Agent is sometimes used in this way to identify the browser, and adjust content accordingly. Also, different browsers use different encodings of non-English characters, certain web servers convert pages on-the-fly according to the User Agent header. Giving a User Agent with the wrong operating system or browser manufacturer causes some sites in these languages to be garbled; Surfers to Eastern European sites should change it to something closer. And then some page access counters work by looking at the Referer header; they may fail or break if unavailable. The weather maps of Intellicast have been blocked by their server when no Referer or cookie is provided, is another example. (But you can forge both headers without giving information away). There are many other ways things can go wrong when trying to fool a web server. The results of which could inadvertently cause pages to load incorrectly, partially, or even not at all. And there may be no obvious clues as to just what went wrong, or why. Nowhere will there be a message that says Turn off fast-redirects or else! Similar thoughts apply to modifying JavaScript, and, to a lesser degree, HTML elements. If you have problems with a site, you will have to adjust your configuration accordingly. Cookies are probably the most likely adjustment that may be required, but by no means the only one. Can Privoxy act as a <quote>caching</quote> proxy to speed up web browsing? No, it does not have this ability at all. You want something like Squid or Polipo for this. And, yes, before you ask, Privoxy can co-exist with other kinds of proxies like Squid. See the forwarding chapter in the user manual for details. What about as a firewall? Can Privoxy protect me? Not in the way you mean, or in the way some firewall vendors claim they can. Privoxy can help protect your privacy, but can't protect your system from intrusion attempts. It is, of course, perfectly possible to use both. I have large empty spaces / a checkerboard pattern now where ads used to be. Why? It is technically possible to eliminate banners and ads in a way that frees their allocated page space. This could easily be done by blocking with Privoxy's filters, and eliminating the entire image references from the HTML page source. But, this would consume considerably more CPU resources (IOW, slow things down), would likely destroy the layout of some web pages which rely on the banners utilizing a certain amount of page space, and might fail in other cases, where the screen space is reserved (e.g. by HTML tables for instance). Also, making ads and banners disappear without any trace complicates troubleshooting, and would sooner or later be problematic. The better alternative is to instead let them stay, and block the resulting requests for the banners themselves as is now the case. This leaves either empty space, or the familiar checkerboard pattern. So the developers won't support this in the default configuration, but you can of course define appropriate filters yourself to achieve this. How can Privoxy filter Secure (HTTPS) URLs? Since secure HTTP connections are encrypted SSL sessions between your browser and the secure site, and are meant to be reliably secure, there is little that Privoxy can do but hand the raw gibberish data though from one end to the other unprocessed. The only exception to this is blocking by host patterns, as the client needs to tell Privoxy the name of the remote server, so that Privoxy can establish the connection. If that name matches a host-only pattern, the connection will be blocked. As far as ad blocking is concerned, this is less of a restriction than it may seem, since ad sources are often identifiable by the host name, and often the banners to be placed in an encrypted page come unencrypted nonetheless for efficiency reasons, which exposes them to the full power of Privoxy's ad blocking. Content cookies (those that are embedded in the actual HTML or JS page content, see filter{content-cookies}), in an SSL transaction will be impossible to block under these conditions. Fortunately, this does not seem to be a very common scenario since most cookies come by traditional means. Privoxy runs as a <quote>server</quote>. How secure is it? Do I need to take any special precautions? On Unix-like systems, Privoxy can run as a non-privileged user, which is how we recommend it be run. Also, by default Privoxy listens to requests from localhost only. The server aspect of Privoxy is not itself directly exposed to the Internet in this configuration. If you want to have Privoxy serve as a LAN proxy, this will have to be opened up to allow for LAN requests. In this case, we'd recommend you specify only the LAN gateway address, e.g. 192.168.1.1, in the main Privoxy configuration file and check all access control and security options. All LAN hosts can then use this as their proxy address in the browser proxy configuration, but Privoxy will not listen on any external interfaces. ACLs can be defined in addition, and using a firewall is always good too. Better safe than sorry. Can I temporarily disable Privoxy? &my-app; doesn't have a transparent proxy mode, but you can toggle off blocking and content filtering. The easiest way to do that is to point your browser to the remote toggle URL: http://config.privoxy.org/toggle. See the Bookmarklets section of the User Manual for an easy way to access this feature. Note that this is a feature that may need to be enabled in the main config file. When <quote>disabled</quote> is Privoxy totally out of the picture? No, this just means all optional filtering and actions are disabled. Privoxy is still acting as a proxy, but just doing less of the things that Privoxy would normally be expected to do. It is still a middle-man in the interaction between your browser and web sites. See below to bypass the proxy. How can I tell Privoxy to totally ignore certain sites? Bypassing a proxy, or proxying based on arbitrary criteria, is purely a browser configuration issue, not a &my-app; issue. Modern browsers typically do have settings for not proxying certain sites. Check your browser's help files. My logs show Privoxy <quote>crunches</quote> ads, but also its own internal CGI pages. What is a <quote>crunch</quote>? A crunch simply means Privoxy intercepted something, nothing more. Often this is indeed ads or banners, but Privoxy uses the same mechanism for trapping requests for its own internal pages. For instance, a request for Privoxy's configuration page at: http://config.privoxy.org, is intercepted (i.e. it does not go out to the 'net), and the familiar CGI configuration is returned to the browser, and the log consequently will show a crunch. Since version 3.0.7, Privoxy will also log the crunch reason. If you are using an older version you might want to upgrade. Can Privoxy effect files that I download from a webserver? FTP server? From the webserver's perspective, there is no difference between viewing a document (i.e. a page), and downloading a file. The same is true of Privoxy. If there is a match for a block pattern, it will still be blocked, and of course this is obvious. Filtering is potentially more of a concern since the results are not always so obvious, and the effects of filtering are there whether the file is simply viewed, or downloaded. And potentially whether the content is some obnoxious advertisement, or Mr. Jimmy's latest/greatest source code jewel. Of course, one of these presumably is bad content that we don't want, and the other is good content that we do want. Privoxy is blind to the differences, and can only distinguish good from bad by the configuration parameters we give it. Privoxy knows the differences in files according to the Content Type as reported by the webserver. If this is reported accurately (e.g. application/zip for a zip archive), then Privoxy knows to ignore these where appropriate. Privoxy potentially can filter HTML as well as plain text documents, subject to configuration parameters of course. Also, documents that are of an unknown type (generally assumed to be text/plain) can be filtered, as will those that might be incorrectly reported by the webserver. If such a file is a downloaded file that is intended to be saved to disk, then any content that might have been altered by filtering, will be saved too, for these (probably rare) cases. Note that versions later than 3.0.2 do NOT filter document types reported as text/plain. Prior to this, Privoxy did filter this document type. In short, filtering is ON if a) the content type as reported by the webserver is appropriate and b) the configuration allows it (or at least does not disallow it). That's it. There is no magic cookie anywhere to say this is good and this is bad. It's the configuration that lets it all happen or not. If you download text files, you probably do not want these to be filtered, particularly if the content is source code, or other critical content. Source code sometimes might be mistaken for Javascript (i.e. the kind that might open a pop-up window). It is recommended to turn off filtering for download sites (particularly if the content may be plain text files and you are using version 3.0.2 or earlier) in your user.action file. And also, for any site or page where making any changes at all to the content is to be avoided. Privoxy does not do FTP at all, only HTTP and HTTPS (SSL) protocols. I just downloaded a Perl script, and Privoxy altered it! Yikes, what is wrong! Please read above. Should I continue to use a <quote>HOSTS</quote> file for ad-blocking? One time-tested technique to defeat common ads is to trick the local DNS system by giving a phony IP address for the ad generator in the local HOSTS file, typically using 127.0.0.1, aka localhost. This effectively blocks the ad. There is no reason to use this technique in conjunction with Privoxy. Privoxy does essentially the same thing, much more elegantly and with much more flexibility. A large HOSTS file, in fact, not only duplicates effort, but may get in the way and seriously slow down your system. It is recommended to remove such entries from your HOSTS file. If you think your hosts list is neglected by Privoxy's configuration, consider adding your list to your user.action file: { +block } www.ad.example1.com ad.example2.com ads.galore.example.com etc.example.com Where can I find more information about Privoxy and related issues? &seealso; I've noticed that Privoxy changes <quote>Microsoft</quote> to <quote>MicroSuck</quote>! Why are you manipulating my browsing? We're not. The text substitutions that you are seeing are disabled in the default configuration as shipped. You have either manually activated the fun filter which is clearly labeled Text replacements for subversive browsing fun! or you are using an older Privoxy version and have implicitly activated it by choosing the Advanced profile in the web-based editor. Please upgrade. Does Privoxy produce <quote>valid</quote> HTML (or XHTML)? Privoxy generates HTML in both its own templates, and possibly whenever there are text substitutions via a &my-app; filter. While this should always conform to the HTML 4.01 specifications, it has not been validated against this or any other standard. How did you manage to get Privoxy on my computer without my consent? We didn't. We make Privoxy available for download, but we don't go around installing it on other people's systems behind their back. If you discover Privoxy running on your system and are sure you didn't install it yourself, somebody else did. You may not even be running the real Privoxy, but maybe something else that only pretends to be Privoxy, or maybe something that is based on the real Privoxy, but has been modified. Lately there have been reports of problems with some kind of Privoxy versions that come preinstalled on some Netbooks. Some of the problems described are inconsistent with the behaviour of official Privoxy versions, which suggests that the preinstalled software may contain vendor modifications that we don't know about and thus can't debug. Privoxy's license allows vendor modifications, but the vendor has to comply with the license, which involves informing the user about the changes and to make the changes available under the same license as Privoxy itself. If you are having trouble with a modified Privoxy version, please try to talk to whoever made the modifications before reporting the problem to us. Please also try to convince whoever made the modifications to talk to us. If you think somebody gave you a modified Privoxy version without complying to the license, please let us know. Troubleshooting I cannot connect to any websites. Or, I am getting <quote>connection refused</quote> message with every web page. Why? There are several possibilities: Privoxy is not running. Solution: verify that &my-app; is installed correctly, has not crashed, and is indeed running. Turn on Privoxy's logging, and look at the logs to see what they say. Or your browser is configured for a different port than what Privoxy is using. Solution: verify that &my-app; and your browser are set to the same port (listen-address). Or if using a forwarding rule, you have a configuration problem or a problem with a host in the forwarding chain. Solution: temporarily alter your configuration and take the forwarders out of the equation. Or you have a firewall that is interfering and blocking you. Solution: try disabling or removing the firewall as a simple test. Why am I getting a 503 Error (WSAECONNREFUSED) on every page? More than likely this is a problem with your TCP/IP networking. ZoneAlarm has been reported to cause this symptom -- even if not running! The solution is to either fight the ZA configuration, or uninstall ZoneAlarm, and then find something better behaved in its place. Other personal firewall type products may cause similar type problems if not configured correctly. I just added a new rule, but the steenkin ad is still getting through. How? If the ad had been displayed before you added its URL, it will probably be held in the browser's cache for some time, so it will be displayed without the need for any request to the server, and Privoxy will not be involved. Flush the browser's caches, and then try again. If this doesn't help, you probably have an error in the rule you applied. Try pasting the full URL of the offending ad into http://config.privoxy.org/show-url-info and see if it really matches your new rule. Blocking ads is like blocking spam: a lot of tinkering is required to stay ahead of the game. And remember you need to block the URL of the ad in question, which may be entirely different from the site URL itself. Most ads are hosted on different servers than the main site itself. If you right-click on the ad, you should be able to get all the relevant information you need. Alternately, you can find the correct URL by looking at Privoxy's logs (you may need to enable logging in the main config file if its disabled). Below is a slightly modified real-life log snippet that originates with one requested URL: www.example.com (name of site was changed for this example, the number of requests is real). You can see in this the complexity of what goes into making up this one page. There are eight different domains involved here, with thirty two separate URLs requested in all, making up all manner of images, Shockwave Flash, JavaScript, CSS stylesheets, scripts, and other related content. Some of this content is obviously good or bad, but not all. Many of the more questionable looking requests, are going to outside domains that seem to be identifying themselves with suspicious looking names, making our job a little easier. &my-app; has crunched (meaning caught and BLOCKED) quite a few items in this example, but perhaps missed a few as well. Despite 12 out of 32 requests being blocked, the page looked, and seemed to behave perfectly normal (minus some ads, of course). One of my favorite sites does not work with Privoxy. What can I do? First verify that it is indeed a Privoxy problem, by toggling off Privoxy through http://config.privoxy.org/toggle (the toggle feature may need to be enabled in the main config), and then shift-reloading the problem page (i.e. holding down the shift key while clicking reload. Alternatively, flush your browser's disk and memory caches). If the problem went away, we know we have a configuration related problem. Now go to http://config.privoxy.org/show-url-info and paste the full URL of the page in question into the prompt. See which actions are being applied to the URL, and which matches in which actions files are responsible for that. It might be helpful also to look at your logs for this site too, to see what else might be happening (note: logging may need to be enabled in the main config file). Many sites are complex and require a number of related pages to help present their content. Look at what else might be used by the page in question, and what of that might be required. Now, armed with this information, go to http://config.privoxy.org/show-status and select the appropriate actions files for editing. You can now either look for a section which disables the actions that you suspect to cause the problem and add a pattern for your site there, or make up a completely new section for your site. In any case, the recommended way is to disable only the prime suspect, reload the problem page, and only if the problem persists, disable more and more actions until you have identified the culprit. You may or may not want to turn the other actions on again. Remember to flush your browser's caches in between any such changes! Alternately, if you are comfortable with a text editor, you can accomplish the same thing by editing the appropriate actions file. Probably the easiest way to deal with such problems when editing by hand is to add your site to a { fragile } section in user.action, which is an alias that turns off most dangerous actions, but is also likely to turn off more actions then needed, and thus lower your privacy and protection more than necessary, Troubleshooting actions is discussed in more detail in the User Manual appendix, Troubleshooting: the Anatomy of an Action. There is also an actions tutorial with general configuration information and examples. As a last resort, you can always see if your browser has a setting that will bypass the proxy setting for selective sites. Modern browsers can do this. After installing Privoxy, I have to log in every time I start IE. What gives? This is a quirk that effects the installation of Privoxy, in conjunction with Internet Explorer and Internet Connection Sharing on Windows 2000 and Windows XP. The symptoms may appear to be corrupted or invalid DUN settings, or passwords. When setting up an NT based Windows system with Privoxy you may find that things do not seem to be doing what you expect. When you set your system up you will probably have set up Internet Connection Sharing (ICS) with Dial up Networking (DUN) when logged in with administrator privileges. You will probably have made this DUN connection available to other accounts that you may have set-up on your system. E.g. Mum or Dad sets up the system and makes accounts suitably configured for the kids. When setting up Privoxy in this environment you will have to alter the proxy set-up of Internet Explorer (IE) for the specific DUN connection on which you wish to use Privoxy. When you do this the ICS DUN set-up becomes user specific. In this instance you will see no difference if you change the DUN connection under the account used to set-up the connection. However when you do this from another user you will notice that the DUN connection changes to make available to "Me only". You will also find that you have to store the password under each different user! The reason for this is that each user's set-up for IE is user specific. Each set-up DUN connection and each LAN connection in IE store the settings for each user individually. As such this enforces individual configurations rather than common ones. Hence the first time you use a DUN connection after re-booting your system it may not perform as you expect, and prompt you for the password. Just set and save the password again and all should be OK. [Thanks to Ray Griffith for this submission.] I cannot connect to any FTP sites. Privoxy is blocking me. Privoxy cannot act as a proxy for FTP traffic, so do not configure your browser to use Privoxy as an FTP proxy. The same is true for any protocol other than HTTP or HTTPS (SSL). Most browsers understand FTP as well as HTTP. If you connect to a site, with a URL like ftp://ftp.example.com, your browser is making an FTP connection, and not a HTTP connection. So while your browser may speak FTP, Privoxy does not, and cannot proxy such traffic. To complicate matters, some systems may have a generic proxy setting, which will enable various protocols, including both HTTP and FTP proxying! So it is possible to accidentally enable FTP proxying in these cases. And of course, if this happens, Privoxy will indeed cause problems since it does not know FTP. Just disable the FTP setting and all will be well again. Will Privoxy ever proxy FTP traffic? Unlikely. There just is not much reason, and the work to make this happen is more than it may seem. In Mac OS X, I can't configure Microsoft Internet Explorer to use Privoxy as the HTTP proxy. Microsoft Internet Explorer (in versions like 5.1) respects system-wide network settings. In order to change the HTTP proxy, open System Preferences, and click on the Network icon. In the settings pane that comes up, click on the Proxies tab. Ensure the "Web Proxy (HTTP)" checkbox is checked and enter 127.0.0.1 in the entry field. Enter 8118 in the Port field. The next time you start IE, it should reflect these values. In Mac OS X, I dragged the Privoxy folder to the trash in order to uninstall it. Now the finder tells me I don't have sufficient privileges to empty the trash. Note: This ONLY applies to privoxy 3.0.6 and earlier. Just dragging the Privoxy folder to the trash is not enough to delete it. Privoxy supplies an uninstall.command file that takes care of these details. Open the trash, drag the uninstall.command file out of the trash and double-click on it. You will be prompted for confirmation and the administration password. The trash may still appear full after this command; emptying the trash from the desktop should make it appear empty again. In Mac OS X Panther (10.3), images often fail to load and/or I experience random delays in page loading. I'm using <literal>localhost</literal> as my browser's proxy setting. We believe this is due to an IPv6-related bug in Mac OS X, but don't fully understand the issue yet. In any case, changing the proxy setting to 127.0.0.1 instead of localhost works around the problem. I get a completely blank page at one site. <quote>View Source</quote> shows only: <markup><![CDATA[<html><body></body></html>]]></markup>. Without Privoxy the page loads fine. Chances are that the site suffers from a bug in PHP, which results in empty pages being sent if the client explicitly requests an uncompressed page, like Privoxy does. This bug has been fixed in PHP 4.2.3. To find out if this is in fact the source of the problem, try adding the site to a -prevent-compression section in user.action: # Make exceptions for ill-behaved sites: # {-prevent-compression} .example.com If that works, you may also want to report the problem to the site's webmasters, telling them to use zlib.output_compression instead of ob_gzhandler in their PHP applications (workaround) or upgrade to PHP 4.2.3 or later (fix). My logs show many <quote>Unable to get my own hostname</quote> lines. Why? Privoxy tries to get the hostname of the system its running on from the IP address of the system interface it is bound to (from the config file listen-address setting). If the system cannot supply this information, Privoxy logs this condition. Typically, this would be considered a minor system configuration error. It is not a fatal error to Privoxy however, but may result in a much slower response from Privoxy on some platforms due to DNS timeouts. This can be caused by a problem with the local hosts file. If this file has been changed from the original, try reverting it to see if that helps. Make sure whatever name(s) are used for the local system, that they resolve both ways. You should also be able to work around the problem with the hostname option. When I try to launch Privoxy, I get an error message <quote>port 8118 is already in use</quote> (or similar wording). Why? Port 8118 is Privoxy's default TCP listening port. Typically this message would mean that there is already one instance of Privoxy running, and your system is actually trying to start a second Privoxy on the same port, which will not work. (You can have multiple instances but they must be assigned different ports.) How and why this might happen varies from platform to platform, but you need to check your installation and start-up procedures. Pages with UTF-8 fonts are garbled. This is caused by the demoronizer filter. You should either upgrade Privoxy, or at least upgrade to the most recent default.action file available from SourceForge. Or you can simply disable the demoronizer filter. Why are binary files (such as images) corrupted when Privoxy is used? This may also be caused by the demoronizer filter, in conjunction with a web server that is misreporting the content type. Binary files are exempted from Privoxy's filtering (unless the web server by mistake says the file is something else). Either upgrade Privoxy, or go to the most recent default.action file available from SourceForge. What is the <quote>demoronizer</quote> and why is it there? The original demoronizer was a Perl script that cleaned up HTML pages which were created with certain Microsoft products. MS has used proprietary extensions to standardized font encodings (ISO 8859-1), which has caused problems for pages that are viewed with non-Microsoft products (and are expecting to see a standard set of fonts). The demoronizer corrected these errors so the pages displayed correctly. Privoxy borrowed from this script, introducing a filter based on the original demoronizer, which in turn could correct these errors on the fly. But this is only needed in some situations, and will cause serious problems in some other situations. If you are using Microsoft products, you do not need it. If you need to view pages with UTF-8 characters (such as Cyrillic or Chinese), then it will cause corruption of the fonts, and thus should not be on. On the other hand, if you use non-Microsoft products, and you occasionally notice weird characters on pages, you might want to try it. Why do I keep seeing <quote>PrivoxyWindowOpen()</quote> in raw source code? Privoxy is attempting to disable malicious Javascript in this case, with the unsolicited-popups filter. Privoxy cannot tell very well good code snippets from bad code snippets. If you see this in HTML source, and the page displays without problems, then this is good, and likely some pop-up window was disabled. If you see this where it is causing a problem, such as a downloaded program source code file, then you should set an exception for this site or page such that the integrity of the page stays in tact by disabling all filtering. I am getting too many DNS errors like <quote>404 No Such Domain</quote>. Why can't Privoxy do this better? There are potentially several factors here. First of all, the DNS resolution is done by the underlying operating system -- not Privoxy itself. Privoxy merely initiates the process and hands it off, and then later reports whatever the outcome was and tries to give a coherent message if there seems to be a problem. In some cases, this might otherwise be mitigated by the browser itself which might try some work-arounds and alternate approaches (e.g adding www. to the URL). In other cases, if Privoxy is being chained with another proxy, this could complicate the issue, and cause undue delays and timeouts. In the case of a socks4a proxy, the socks server handles all the DNS. Privoxy would just be the messenger which is reporting whatever problem occurred downstream, and not the root cause of the error. In any case, versions newer than 3.0.3 include various improvements to help Privoxy better handle these cases. ]]> At one site Privoxy just hangs, and starts taking all CPU. Why is this? This is probably a manifestation of the 100% cpu problem that occurs on pages containing many (thousands upon thousands) of blank lines. The blank lines are in the raw HTML source of the page, and the browser just ignores them. But the pattern matching in Privoxy's page filtering mechanism is trying to match against absurdly long strings and this becomes very CPU-intensive, taking a long, long time to complete. Until a better solution comes along, disable filtering on these pages, particularly the js-annoyances and unsolicited-popups filters. If you run into this problem with a recent &my-app; version, please send a problem report. I just installed Privoxy, and all my browsing has slowed to a crawl. What gives? This should not happen, and for the overwhelming number of users world-wide, it does not happen. I would suspect some inadvertent interaction of software components such as anti-virus software, spyware protectors, personal firewalls or similar components. Try disabling (or uninstalling) these one at a time and see if that helps. Either way, if you are using a recent &my-app; version, please report the problem. Why do my filters work on some sites but not on others? It's probably due to compression. It is a common practice for web servers to send their content compressed in order to speed things up, and then let the browser uncompress them. When compiled with zlib support &my-app; can decompress content before filtering, otherwise you may want to enable prevent-compression. As of &my-app; 3.0.9, zlib support is enabled in the default builds. On some HTTPS sites my browser warns me about unauthenticated content, the URL bar doesn't get highlighted and the lock symbol appears to be broken. What's going on? Probably the browser is requesting ads through HTTPS and &my-app; is blocking the requests. Privoxy's error messages are delivered unencrypted and while it's obvious for the browser that the HTTPS request is already blocked by the proxy, some warn about unauthenticated content anyway. To work around the problem you can redirect those requests to an invalid local address instead of blocking them. While the redirects aren't encrypted either, many browsers don't care. They simply follow the redirect, fail to reach a server and display an error message instead of the ad. To do that, enable logging to figure out which requests get blocked by &my-app; and add the hosts (no path patterns) to a section like this: Additionally you have to configure your browser to contact 127.0.0.1:0 directly (instead of through &my-app;). To add a proxy exception in Mozilla Firefox open the Preferences, click the Settings button located on the Network tab in the Advanced section, and add 127.0.0.1:0 in the No Proxy for: field. I get selinux error messages. How can I fix this? Please report the problem to the creator of your selinux policies. The problem is that some selinux policy writers aren't familiar with the application they are trying to secure and thus create policies that make no sense. In Privoxy's case the problem usually is that the policy only allows outgoing connections for certain destination ports (e.g. 80 and 443). While this may cover the standard ports, websites occasionally use other ports as well. This isn't a security problem and therefore Privoxy's default configuration doesn't block these requests. If you really want to block these ports (and don't be able to load websites that don't use standard ports), you should configure Privoxy to block these ports as well, so it doesn't trigger the selinux warnings. I compiled &my-app; with Gentoo's portage and it appears to be very slow. Why? Probably you unintentionally compiled &my-app; without threading support in which case requests have to be serialized and only one can be served at the same time. Check your USE flags and make sure they include threads. If they don't, add the flag and rebuild &my-app;. If you compiled &my-app; with threading support (on POSIX-based systems), the Conditional #defines section on http://config.privoxy.org/show-status will list FEATURE_PTHREAD as enabled. Contacting the developers, Bug Reporting and Feature Requests &contacting; Privoxy Copyright, License and History ©right; Portions of this document are borrowed from the original Junkbuster (tm) FAQ, and modified as appropriate for Privoxy. License &license; History &history;
    privoxy-3.0.21-stable/./doc/source/buildsource.sgml000640 001751 001751 00000021723 11630656224 021245 0ustar00fkfk000000 000000 To build Privoxy from source, autoconf, GNU make (gmake), and, of course, a C compiler like gcc are required. When building from a source tarball, first unpack the source: tar xzvf privoxy-&p-version;-src.tar.gz cd privoxy-&p-version; For retrieving the current CVS sources, you'll need a CVS client installed. Note that sources from CVS are typically development quality, and may not be stable, or well tested. To download CVS source, check the Sourceforge documentation, which might give commands like: cvs -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa login cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co current cd current This will create a directory named current/, which will contain the source tree. You can also check out any Privoxy branch, just exchange the current name with the wanted branch name (Example: v_3_0_branch for the 3.0 cvs tree). It is also strongly recommended to not run Privoxy as root. You should configure/install/run Privoxy as an unprivileged user, preferably by creating a privoxy user and group just for this purpose. See your local documentation for the correct command line to do add new users and groups (something like adduser, but the command syntax may vary from platform to platform). /etc/passwd might then look like: privoxy:*:7777:7777:privoxy proxy:/no/home:/no/shell And then /etc/group, like: privoxy:*:7777: Some binary packages may do this for you. Then, to build from either unpacked tarball or CVS source: autoheader autoconf ./configure # (--help to see options) make # (the make from GNU, sometimes called gmake) su # Possibly required make -n install # (to see where all the files will go) make -s install # (to really install, -s to silence output) Using GNU make, you can have the first four steps automatically done for you by just typing: make in the freshly downloaded or unpacked source directory. To build an executable with security enhanced features so that users cannot easily bypass the proxy (e.g. Go There Anyway), or alter their own configurations, configure like this: ./configure --disable-toggle --disable-editor --disable-force Then build as above. In Privoxy 3.0.7 and later, all of these options can also be disabled through the configuration file. WARNING: If installing as root, the install will fail unless a non-root user or group is specified, or a privoxy user and group already exist on the system. If a non-root user is specified, and no group, then the installation will try to also use a group of the same name as user. If a group is specified (and no user), then the support files will be installed as writable by that group, and owned by the user running the installation. configure accepts --with-user and --with-group options for setting user and group ownership of the configuration files (which need to be writable by the daemon). The specified user must already exist. When starting Privoxy, it must be run as this same user to insure write access to configuration and log files! Alternately, you can specify user and group on the make command line, but be sure both already exist: make -s install USER=privoxy GROUP=privoxy The default installation path for make install is /usr/local. This may of course be customized with the various ./configure path options. If you are doing an install to anywhere besides /usr/local, be sure to set the appropriate paths with the correct configure options (./configure --help). Non-privileged users must of course have write access permissions to wherever the target installation is going. If you do install to /usr/local, the install will use sysconfdir=$prefix/etc/privoxy by default. All other destinations, and the direct usage of --sysconfdir flag behave like normal, i.e. will not add the extra privoxy directory. This is for a safer install, as there may already exist another program that uses a file with the config name, and thus makes /usr/local/etc cleaner. If installing to /usr/local, the documentation will go by default to $prefix/share/doc. But if this directory doesn't exist, it will then try $prefix/doc and install there before creating a new $prefix/share/doc just for Privoxy. Again, if the installs goes to /usr/local, the localstatedir (ie: var/) will default to /var instead of $prefix/var so the logs will go to /var/log/privoxy/, and the pid file will be created in /var/run/privoxy.pid. make install will attempt to set the correct values in config (main configuration file). You should check this to make sure all values are correct. If appropriate, an init script will be installed, but it is up to the user to determine how and where to start Privoxy. The init script should be checked for correct paths and values, if anything other than a default install is done. If install finds previous versions of local configuration files, most of these will not be overwritten, and the new ones will be installed with a new extension. default.action and default.filter will be overwritten. You will then need to manually update the other installed configuration files as needed. The default template files will be overwritten. If you have customized, local templates, these should be stored safely in a separate directory and defined in config by the templdir directive. It is of course wise to always back-up any important configuration files just in case. If a previous version of Privoxy is already running, you will have to restart it manually. For more detailed instructions on how to build Redhat RPMs, Windows self-extracting installers, building on platforms with special requirements etc, please consult the developer manual. The simplest command line to start Privoxy is $path/privoxy --user=privoxy $path/etc/privoxy/config. See privoxy --usage, or the man page, for other options, and configuration. ]]> privoxy-3.0.21-stable/./doc/source/ldp.dsl.in000640 001751 001751 00000026433 12026571552 017734 0ustar00fkfk000000 000000 ]]> ]]> ]> ;; ============================== ;; customize the print stylesheet ;; ============================== ;; ;; see http://docbook.sourceforge.net/projects/dsssl/doc/print.html ;; (define %indent-screen-lines% ;; Indent lines in a 'Screen'? #t) (define %callout-fancy-bug% ;; Use fancy callout bugs? #t) (define %chap-app-running-heads% ;; Generate running headers and footers on chapter-level elements? #t) (define %chap-app-running-head-autolabel% ;; Put chapter labels in running heads? #t) ;; this is necessary because right now jadetex does not understand ;; symbolic entities, whereas things work well with numeric entities. (declare-characteristic preserve-sdata? "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" #f) ;; put the legal notice in a separate file (define %generate-legalnotice-link% #t) ;; use graphics in admonitions, and have their path be "stylesheet-images" ;; NO: they do not yet look very good (define %admon-graphics-path% "./stylesheet-images/") (define %admon-graphics% #f) (define %funcsynopsis-decoration% ;; make funcsynopsis look pretty #t) ;;(define %shade-verbatim% ;; #t) (define %section-autolabel% #t) ;; For enumerated sections (1.1, 1.1.1, 1.2, etc.) ;; HB changed TOC depth to 3 levels. (define (toc-depth nd) 3) ;; HB added 03/20/02, see dbparam.dsl ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define %body-attr% ;; REFENTRY body-attr ;; PURP What attributes should be hung off of BODY? ;; DESC ;; A list of the BODY attributes that should be generated. ;; The format is a list of lists, each interior list contains the ;; name and value of a BODY attribute. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY (list (list "BGCOLOR" "#EEEEEE") (list "TEXT" "#000000") (list "LINK" "#0000FF") (list "VLINK" "#840084") (list "ALINK" "#0000FF"))) (define %stylesheet% ;; REFENTRY stylesheet ;; PURP Name of the stylesheet to use ;; DESC ;; The name of the stylesheet to place in the HTML LINK TAG, or '#f' to ;; suppress the stylesheet LINK. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY "../p_doc.css") (define %stylesheet-type% ;; REFENTRY stylesheet-type ;; PURP The type of the stylesheet to use ;; DESC ;; The type of the stylesheet to place in the HTML LINK TAG. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY "text/css") (define %css-liststyle-alist% ;; REFENTRY css-liststyle-alist ;; PURP Map DocBook OVERRIDE and MARK attributes to CSS ;; DESC ;; If '%css-decoration%' is turned on then the list-style-type property of ;; list items will be set to reflect the list item style selected in the ;; DocBook instance. This associative list maps the style type names used ;; in your instance to the appropriate CSS names. If no mapping exists, ;; the name from the instance will be used. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY '(("bullet" "disc") ("box" "square"))) (define %css-decoration% ;; REFENTRY css-decoration ;; PURP Enable CSS decoration of elements ;; DESC ;; If '%css-decoration%' is turned on then HTML elements produced by the ;; stylesheet may be decorated with STYLE attributes. For example, the ;; LI tags produced for list items may include a fragment of CSS in the ;; STYLE attribute which sets the CSS property "list-style-type". ;; /DESC ;; AUTHOR N/A ;; /REFENTRY #t) ;; swa1 (define %generate-part-toc% #f) (define %generate-article-toc% ;; Should a Table of Contents be produced for Articles? ;; If true, a Table of Contents will be generated for each 'Article'. #t) (define %generate-part-toc-on-titlepage% ;; Should the Part TOC appear on the Part title page? #f) ;;Do you want a separate page for the title? (define %generate-article-titlepage-on-separate-page% #t) ;;Do you want the article toc on the titlepage or separate? (define %generate-article-toc-on-titlepage% #f) ;;Titlepage Separate? ;; This is the one that makes TOC only on first page!! hal. (define (chunk-skip-first-element-list) '()) (define %body-start-indent% ;; Default indent of body text 2pi) (define %para-indent-firstpara% ;; First line start-indent for the first paragraph 0pt) ;; swa2 (define %para-indent% ;; First line start-indent for paragraphs (other than the first) 0pt) (define %block-start-indent% ;; Extra start-indent for block-elements 2pt) ;;Define distance between paragraphs (define %para-sep% (/ %bf-size% 2.0)) ;; with swa2 no effects ;; swa3 ;;Define distance between block elements (figures, tables, etc.). (define %block-sep% (* %para-sep% 1.0)) ;; (* %para-sep% 2.0)) (define %hyphenation% ;; Allow automatic hyphenation? #t) (define %left-margin% 5pi) (define %right-margin% 5pi) (define %top-margin% 5pi) (define %bottom-margin% 5pi) (define %footer-margin% 2pi) (define %header-margin% 2pi) (define %line-spacing-factor% 1.3) ;; Factor used to calculate leading ;; The leading is calculated by multiplying the current font size by the ;; '%line-spacing-factor%'. For example, if the font size is 10pt and ;; the '%line-spacing-factor%' is 1.1, then the text will be ;; printed "10-on-11". (define %head-before-factor% ;; Factor used to calculate space above a title ;; The space before a title is calculated by multiplying the font size ;; used in the title by the '%head-before-factor%'. ;; 0.75) 0.5) (define %head-after-factor% ;; Factor used to calculate space below a title ;; The space after a title is calculated by multiplying the font size used ;; in the title by the '%head-after-factor%'. 0.5) (define %input-whitespace-treatment% 'collapse) (define ($generate-article-lot-list$) ;; Which Lists of Titles should be produced for Articles? (list )) ;; this is necessary because right now jadetex does not understand ;; symbolic entities, whereas things work well with numeric entities. (declare-characteristic preserve-sdata? "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" #f) ;; put the legal notice in a separate file (define %generate-legalnotice-link% #t) ;; use graphics in admonitions, and have their path be "stylesheet-images" ;; NO: they do not yet look very good (define %admon-graphics-path% "./stylesheet-images/") (define %admon-graphics% #f) (define %funcsynopsis-decoration% ;; make funcsynopsis look pretty #t) (define %html-ext% ".html") (define %generate-article-toc% ;; Should a Table of Contents be produced for Articles? ;; If true, a Table of Contents will be generated for each 'Article'. #t) ;; HB added next three statements 05/03/02. ;;Do you want a separate page for the title? (define %generate-article-titlepage-on-separate-page% #t) ;;Do you want the article toc on the titlepage or separate? (define %generate-article-toc-on-titlepage% #t) ;;Titlepage Separate? ;; This is the one that makes TOC only on first page!! hal. (define (chunk-skip-first-element-list) '()) (define %root-filename% ;; The filename of the root HTML document (e.g, "index"). "index") (define %generate-part-toc% #t) (define %shade-verbatim% #t) (define %use-id-as-filename% ;; Use ID attributes as name for component HTML files? #t) (define %graphic-default-extension% "gif") (define %section-autolabel% #t) ;; For enumerated sections (1.1, 1.1.1, 1.2, etc.) ;; HB changed TOC depth to 3 levels. (define (toc-depth nd) 3) ;; HB added 03/20/02, see dbparam.dsl ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define %body-attr% ;; REFENTRY body-attr ;; PURP What attributes should be hung off of BODY? ;; DESC ;; A list of the the BODY attributes that should be generated. ;; The format is a list of lists, each interior list contains the ;; name and value of a BODY attribute. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY (list (list "BGCOLOR" "#EEEEEE") (list "TEXT" "#000000") (list "LINK" "#0000FF") (list "VLINK" "#840084") (list "ALINK" "#0000FF"))) (define %stylesheet% ;; REFENTRY stylesheet ;; PURP Name of the stylesheet to use ;; DESC ;; The name of the stylesheet to place in the HTML LINK TAG, or '#f' to ;; suppress the stylesheet LINK. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY "../p_doc.css") (define %stylesheet-type% ;; REFENTRY stylesheet-type ;; PURP The type of the stylesheet to use ;; DESC ;; The type of the stylesheet to place in the HTML LINK TAG. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY "text/css") (define %css-liststyle-alist% ;; REFENTRY css-liststyle-alist ;; PURP Map DocBook OVERRIDE and MARK attributes to CSS ;; DESC ;; If '%css-decoration%' is turned on then the list-style-type property of ;; list items will be set to reflect the list item style selected in the ;; DocBook instance. This associative list maps the style type names used ;; in your instance to the appropriate CSS names. If no mapping exists, ;; the name from the instance will be used. ;; /DESC ;; AUTHOR N/A ;; /REFENTRY '(("bullet" "disc") ("box" "square"))) (define %css-decoration% ;; REFENTRY css-decoration ;; PURP Enable CSS decoration of elements ;; DESC ;; If '%css-decoration%' is turned on then HTML elements produced by the ;; stylesheet may be decorated with STYLE attributes. For example, the ;; LI tags produced for list items may include a fragment of CSS in the ;; STYLE attribute which sets the CSS property "list-style-type". ;; /DESC ;; AUTHOR N/A ;; /REFENTRY #t) ;; HB added 2008-01-19 (define %html-header-tags% '(("META" ("HTTP-EQUIV" "Content-Type") ("CONTENT" "text/html; charset=ISO-8859-1")))) ;; =================================================== ;; Vairant without TOC for the Homepage --oes 24/05/02 ;; =================================================== (define %generate-article-toc% ;; Should a Table of Contents be produced for Articles? ;; If true, a Table of Contents will be generated for each 'Article'. #f) privoxy-3.0.21-stable/./doc/source/privoxy.sgml000640 001751 001751 00000003314 11630656224 020441 0ustar00fkfk000000 000000 Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks. Privoxy is Free Software and licensed under the GNU GPLv2. Privoxy is an associated project of Software in the Public Interest (SPI). Helping hands and donations are welcome: http://www.privoxy.org/faq/general.html#PARTICIPATE http://www.privoxy.org/faq/general.html#DONATE privoxy-3.0.21-stable/./doc/source/readme.sgml000640 001751 001751 00000021433 12114164370 020152 0ustar00fkfk000000 000000 ]>
    This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/doc/source/readme.sgml,v $ * * Purpose : README file to give a short intro. * * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA * *********************************************************************/ This README is included with Privoxy &p-version;. See http://www.privoxy.org/ for more information. The current code maturity level is &p-status;. &p-intro; CHANGES For a list of changes in this release, please have a look at the "ChangeLog", the "What's New" section or the "Upgrader's Notes" in the User Manual. INSTALL See the INSTALL file in this directory, for installing from raw source, and the User Manual, for all other installation types. RUN privoxy [--help] [--version] [--no-daemon] [--pidfile PIDFILE] [--user USER[.GROUP]] [--chroot] [--pre-chroot-nslookup HOSTNAME ][config_file] See the man page or User Manual for an explanation of each option, and other configuration and usage issues. If no config_file is specified on the command line, Privoxy will look for a file named 'config' in the current directory (except Win32 which will look for 'config.txt'). If no config_file is found, Privoxy will fail to start. CONFIGURATION See: 'config', 'default.action', 'user.action', 'default.filter', and 'user.filter'. 'user.action' and 'user.filter' are for personal and local configuration preferences. These are all well commented. Most of the magic is in '*.action' files. 'user.action' should be used for any actions customizations. On Unix-like systems, these files are typically installed in /etc/privoxy. On Windows, then wherever the executable itself is installed. There are many significant changes and advances from earlier versions. The User Manual has an explanation of all configuration options, and examples: http://www.privoxy.org/user-manual/. Be sure to set your browser(s) for HTTP/HTTPS Proxy at <IP>:<Port>, or whatever you specify in the config file under 'listen-address'. DEFAULT is 127.0.0.1:8118. Note that Privoxy ONLY proxies HTTP (and HTTPS) traffic. Do not try it with FTP or other protocols for the simple reason it does not work. The actions list can be configured via the web interface accessed via http://p.p/, as well other options. All configuration files are subject to unannounced changes during the development process. ]]> DOCUMENTATION There should be documentation in the 'doc' subdirectory. In particular, see the User Manual there, the FAQ, and those interested in Privoxy development, should look at developer-manual. The source and configuration files are all well commented. The main configuration files are: 'config', 'default.action', and 'default.filter'. Included documentation may vary according to platform and packager. All documentation is posted on http://www.privoxy.org, in case you don't have it, or can't find it. CONTACTING THE DEVELOPERS, BUG REPORTING AND FEATURE REQUESTS &contacting;
    privoxy-3.0.21-stable/./doc/source/webserver/index.sgml000640 001751 001751 00000015205 12114164370 022030 0ustar00fkfk000000 000000 ]>
    Privoxy - <![%p-homepage;[Home Page]]><![%p-index;[The Privacy Enhancing Proxy]]> Project Index Page v&p-version;]]> This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> &p-intro; The most recent release is &p-version; (&p-status;). ]]> Download Download recent releases Quickstart after installation Documentation User manual Frequently Asked Questions Developer Manual Classic Man Page More information Support & Service Copyright, License, History & Authors List of (new) Features The project page Related links Pictures of the Privoxy Team Privoxy is developed on: ]]> ]]> Copyright __copy 2001-2013 by Privoxy Developers
    privoxy-3.0.21-stable/./doc/source/authors.sgml000640 001751 001751 00000004200 12114164370 020373 0ustar00fkfk000000 000000 ]>
    This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> Authors of Privoxy v2.9.x and 3.x =========================================================================== &authors; If we've missed you off this list, please let us know! Privoxy team. http://www.privoxy.org/ ijbswa-developers@lists.sourceforge.net
    privoxy-3.0.21-stable/./doc/source/copyright.sgml000640 001751 001751 00000002540 12072257362 020732 0ustar00fkfk000000 000000 Copyright &my-copy; 2001-2013 by Privoxy Developers ijbswa-developers@lists.sourceforge.net Some source code is based on code Copyright &my-copy; 1997 by Anonymous Coders and Junkbusters, Inc. and licensed under the GNU General Public License. privoxy-3.0.21-stable/./doc/source/privoxy-man-page.sgml000640 001751 001751 00000032404 12114164370 022120 0ustar00fkfk000000 000000 ]> 2012-11-08 privoxy 1 Privoxy &p-version; privoxy Privacy Enhancing Proxy privoxy pidfile hostname user[.group] configfile Options Privoxy may be invoked with the following command line options: --chroot Before changing to the user ID given in the --user option, chroot to that user's home directory, i.e. make the kernel pretend to the Privoxy process that the directory tree starts there. If set up carefully, this can limit the impact of possible vulnerabilities in Privoxy to the files contained in that hierarchy. --config-test Exit after loading the configuration files before binding to the listen address. The exit code signals whether or not the configuration files have been successfully loaded. If the exit code is 1, at least one of the configuration files is invalid, if it is 0, all the configuration files have been successfully loaded (but may still contain errors that can currently only be detected at run time). This option doesn't affect the log setting, combination with "--no-daemon" is recommended if a configured log file shouldn't be used. --help Print brief usage info and exit. --no-daemon Don't become a daemon, i.e. don't fork and become process group leader, don't detach from controlling tty, and do all logging there. --pidfile pidfile On startup, write the process ID to pidfile. Delete the pidfile on exit. Failure to create or delete the pidfile is non-fatal. If no --pidfile option is given, no PID file will be used. --pre-chroot-nslookup hostname Initialize the resolver library using hostname before chroot'ing. On some systems this reduces the number of files that must be copied into the chroot tree. --user user[.group] After (optionally) writing the PID file, assume the user ID of user and the GID of group, or, if the optional group was not given, the default group of user. Exit if the privileges are not sufficient to do so. --version Print version info and exit. If the configfile is not specified on the command line, Privoxy will look for a file named config in the current directory. If no configfile is found, Privoxy will fail to start. Description &p-intro; Installation and Usage Browsers can either be individually configured to use Privoxy as a HTTP proxy (recommended), or Privoxy can be combined with a packet filter to build an intercepting proxy (see config). The default setting is for localhost, on port 8118 (configurable in the main config file). To set the HTTP proxy in Firefox, go through: Tools; Options; General; Connection Settings; Manual Proxy Configuration. For Internet Explorer, go through: Tools; Internet Properties; Connections; LAN Settings. The Secure (SSL) Proxy should also be set to the same values, otherwise https: URLs will not be proxied. Note: Privoxy can only proxy HTTP and HTTPS traffic. Do not try it with FTP or other protocols. HTTPS presents some limitations, and not all features will work with HTTPS connections. For other browsers, check the documentation. Configuration Privoxy can be configured with the various configuration files. The default configuration files are: config, default.filter, default.action and default.action. user.action should be used for locally defined exceptions to the default rules in match-all.action and default.action, and user.filter for locally defined filters. These are well commented. On Unix and Unix-like systems, these are located in /etc/privoxy/ by default. Privoxy uses the concept of actions in order to manipulate the data stream between the browser and remote sites. There are various actions available with specific functions for such things as blocking web sites, managing cookies, etc. These actions can be invoked individually or combined, and used against individual URLs, or groups of URLs that can be defined using wildcards and regular expressions. The result is that the user has greatly enhanced control and freedom. The actions list (ad blocks, etc) can also be configured with your web browser at http://config.privoxy.org/ (assuming the configuration allows it). Privoxy's configuration parameters can also be viewed at the same page. In addition, Privoxy can be toggled on/off. This is an internal page, and does not require Internet access. See the User Manual for a detailed explanation of installation, general usage, all configuration options, new features and notes on upgrading. Files /usr/sbin/privoxy /etc/privoxy/config /etc/privoxy/match-all.action /etc/privoxy/default.action /etc/privoxy/user.action /etc/privoxy/default.filter /etc/privoxy/user.filter /etc/privoxy/trust /etc/privoxy/templates/* /var/log/privoxy/logfile Various other files should be included, but may vary depending on platform and build configuration. Additional documentation should be included in the local documentation directory. Signals Privoxy terminates on the SIGINT and SIGTERM signals. Log rotation scripts may cause a re-opening of the logfile by sending a SIGHUP to Privoxy. Note that unlike other daemons, Privoxy does not need to be made aware of config file changes by SIGHUP -- it will detect them automatically. Signals other than the ones listed above aren't explicitly handled and result in the default action defined by the operating system. Notes This is a &p-status; version of Privoxy. Not all features are well tested. ]]> Please see the User Manual on how to contact the developers, for feature requests, reporting problems, and other questions. See Also &seealso; Development Team &authors; Copyright and License Copyright ©right; License &license; privoxy-3.0.21-stable/./doc/source/history.sgml000640 001751 001751 00000005150 11770072525 020423 0ustar00fkfk000000 000000 A long time ago, there was the Internet Junkbuster, by Anonymous Coders and Junkbusters Corporation. This saved many users a lot of pain in the early days of web advertising and user tracking. But the web, its protocols and standards, and with it, the techniques for forcing ads on users, give up autonomy over their browsing, and for tracking them, keeps evolving. Unfortunately, the Internet Junkbuster did not. Version 2.0.2, published in 1998, was the last official release, available from Junkbusters Corporation. Fortunately, it had been released under the GNU GPL, which allowed further development by others. So Stefan Waldherr started maintaining an improved version of the software, to which eventually a number of people contributed patches. It could already replace banners with a transparent image, and had a first version of pop-up killing, but it was still very closely based on the original, with all its limitations, such as the lack of HTTP/1.1 support, flexible per-site configuration, or content modification. The last release from this effort was version 2.0.2-10, published in 2000. Then, some developers picked up the thread, and started turning the software inside out, upside down, and then reassembled it, adding many new features along the way. The result of this is Privoxy, whose first stable version, 3.0, was released August, 2002. As of 2012 the Junkbusters Corporation's website (http://www.junkbusters.com/) has been shut down, but Privoxy is still actively maintained. privoxy-3.0.21-stable/./doc/source/p-config.sgml000640 001751 001751 00000323172 12116117750 020426 0ustar00fkfk000000 000000 The Main Configuration File By default, the main configuration file is named config, with the exception of Windows, where it is named config.txt. Configuration lines consist of an initial keyword followed by a list of values, all separated by whitespace (any number of spaces or tabs). For example: confdir /etc/privoxy Assigns the value /etc/privoxy to the option confdir and thus indicates that the configuration directory is named /etc/privoxy/. All options in the config file except for confdir and logdir are optional. Watch out in the below description for what happens if you leave them unset. The main config file controls all aspects of Privoxy's operation that are not location dependent (i.e. they apply universally, no matter where you may be surfing). Like the filter and action files, the config file is a plain text file and can be modified with a text editor like emacs, vim or notepad.exe. ]]> @@TITLE<!-- between the @@ is stripped by Makefile -->@@ Sample Configuration File for Privoxy &p-version; $Id: p-config.sgml,v 2.100 2013/03/07 14:10:48 fabiankeil Exp $ Copyright (C) 2001-2013 Privoxy Developers http://www.privoxy.org/ ################################################################# # Table of Contents # # I. INTRODUCTION # II. FORMAT OF THE CONFIGURATION FILE # # 1. LOCAL SET-UP DOCUMENTATION # 2. CONFIGURATION AND LOG FILE LOCATIONS # 3. DEBUGGING # 4. ACCESS CONTROL AND SECURITY # 5. FORWARDING # 6. MISCELLANEOUS # 7. WINDOWS GUI OPTIONS # # ################################################################# I. INTRODUCTION =============== This file holds Privoxy's main configuration. Privoxy detects configuration changes automatically, so you don't have to restart it unless you want to load a different configuration file. The configuration will be reloaded with the first request after the change was done, this request itself will still use the old configuration, though. In other words: it takes two requests before you see the result of your changes. Requests that are dropped due to ACL don't trigger reloads. When starting Privoxy on Unix systems, give the location of this file as last argument. On Windows systems, Privoxy will look for this file with the name 'config.txt' in the current working directory of the Privoxy process. II. FORMAT OF THE CONFIGURATION FILE ==================================== Configuration lines consist of an initial keyword followed by a list of values, all separated by whitespace (any number of spaces or tabs). For example, actionsfile default.action Indicates that the actionsfile is named 'default.action'. The '#' indicates a comment. Any part of a line following a '#' is ignored, except if the '#' is preceded by a '\'. Thus, by placing a # at the start of an existing configuration line, you can make it a comment and it will be treated as if it weren't there. This is called "commenting out" an option and can be useful. Removing the # again is called "uncommenting". Note that commenting out an option and leaving it at its default are two completely different things! Most options behave very differently when unset. See the "Effect if unset" explanation in each option's description for details. Long lines can be continued on the next line by using a `\' as the last character. ]]> Local Set-up Documentation If you intend to operate Privoxy for more users than just yourself, it might be a good idea to let them know how to reach you, what you block and why you do that, your policies, etc. user-manual Specifies: Location of the Privoxy User Manual. Type of value: A fully qualified URI Default value: Unset Effect if unset: http://www.privoxy.org/version/user-manual/ will be used, where version is the Privoxy version. Notes: The User Manual URI is the single best source of information on Privoxy, and is used for help links from some of the internal CGI pages. The manual itself is normally packaged with the binary distributions, so you probably want to set this to a locally installed copy. Examples: The best all purpose solution is simply to put the full local PATH to where the User Manual is located:   user-manual  /usr/share/doc/privoxy/user-manual The User Manual is then available to anyone with access to Privoxy, by following the built-in URL: http://config.privoxy.org/user-manual/ (or the shortcut: http://p.p/user-manual/). If the documentation is not on the local system, it can be accessed from a remote server, as:   user-manual  http://example.com/privoxy/user-manual/ If set, this option should be the first option in the config file, because it is used while the config file is being read on start-up. ]]> WARNING!!!
    If set, this option should be the first option in the config file, because it is used while the config file is being read.
    ]]>
    @@#user-manual http://www.privoxy.org/user-manual/
    ]]> trust-info-url Specifies: A URL to be displayed in the error page that users will see if access to an untrusted page is denied. Type of value: URL Default value: Unset Effect if unset: No links are displayed on the "untrusted" error page. Notes: The value of this option only matters if the experimental trust mechanism has been activated. (See trustfile below.) If you use the trust mechanism, it is a good idea to write up some on-line documentation about your trust policy and to specify the URL(s) here. Use multiple times for multiple URLs. The URL(s) should be added to the trustfile as well, so users don't end up locked out from the information on why they were locked out in the first place! @@#trust-info-url http://www.example.com/why_we_block.html]]> @@#trust-info-url http://www.example.com/what_we_allow.html]]> admin-address Specifies: An email address to reach the Privoxy administrator. Type of value: Email address Default value: Unset Effect if unset: No email address is displayed on error pages and the CGI user interface. Notes: If both admin-address and proxy-info-url are unset, the whole "Local Privoxy Support" box on all generated pages will not be shown. @@#admin-address privoxy-admin@example.com]]> proxy-info-url Specifies: A URL to documentation about the local Privoxy setup, configuration or policies. Type of value: URL Default value: Unset Effect if unset: No link to local documentation is displayed on error pages and the CGI user interface. Notes: If both admin-address and proxy-info-url are unset, the whole "Local Privoxy Support" box on all generated pages will not be shown. This URL shouldn't be blocked ;-) @@#proxy-info-url http://www.example.com/proxy-service.html]]> Configuration and Log File Locations Privoxy can (and normally does) use a number of other files for additional configuration, help and logging. This section of the configuration file tells Privoxy where to find those other files. The user running Privoxy, must have read permission for all configuration files, and write permission to any files that would be modified, such as log files and actions files. confdir Specifies: The directory where the other configuration files are located. Type of value: Path name Default value: /etc/privoxy (Unix) or Privoxy installation dir (Windows) Effect if unset: Mandatory Notes: No trailing /, please. @@confdir .]]> templdir Specifies: An alternative directory where the templates are loaded from. Type of value: Path name Default value: unset Effect if unset: The templates are assumed to be located in confdir/template. Notes: Privoxy's original templates are usually overwritten with each update. Use this option to relocate customized templates that should be kept. As template variables might change between updates, you shouldn't expect templates to work with Privoxy releases other than the one they were part of, though. @@#templdir .]]> logdir Specifies: The directory where all logging takes place (i.e. where the logfile is located). Type of value: Path name Default value: /var/log/privoxy (Unix) or Privoxy installation dir (Windows) Effect if unset: Mandatory Notes: No trailing /, please. @@logdir .]]> actionsfile Specifies: The actions file(s) to use Type of value: Complete file name, relative to confdir Default values: match-all.action # Actions that are applied to all sites and maybe overruled later on. default.action # Main actions file user.action # User customizations Effect if unset: No actions are taken at all. More or less neutral proxying. Notes: Multiple actionsfile lines are permitted, and are in fact recommended! The default values are default.action, which is the main actions file maintained by the developers, and user.action, where you can make your personal additions. Actions files contain all the per site and per URL configuration for ad blocking, cookie management, privacy considerations, etc. There is no point in using Privoxy without at least one actions file. Note that since Privoxy 3.0.7, the complete filename, including the .action extension has to be specified. The syntax change was necessary to be consistent with the other file options and to allow previously forbidden characters. @@actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.]]> @@actionsfile default.action # Main actions file]]> @@actionsfile user.action # User customizations]]> filterfile Specifies: The filter file(s) to use Type of value: File name, relative to confdir Default value: default.filter (Unix) or default.filter.txt (Windows) Effect if unset: No textual content filtering takes place, i.e. all +filter{name} actions in the actions files are turned neutral. Notes: Multiple filterfile lines are permitted. The filter files contain content modification rules that use regular expressions. These rules permit powerful changes on the content of Web pages, and optionally the headers as well, e.g., you could try to disable your favorite JavaScript annoyances, re-write the actual displayed text, or just have some fun playing buzzword bingo with web pages. The +filter{name} actions rely on the relevant filter (name) to be defined in a filter file! A pre-defined filter file called default.filter that contains a number of useful filters for common problems is included in the distribution. See the section on the filter action for a list. It is recommended to place any locally adapted filters into a separate file, such as user.filter. @@filterfile default.filter]]> @@filterfile user.filter # User customizations]]> logfile Specifies: The log file to use Type of value: File name, relative to logdir Default value: Unset (commented out). When activated: logfile (Unix) or privoxy.log (Windows). Effect if unset: No logfile is written. Notes: The logfile is where all logging and error messages are written. The level of detail and number of messages are set with the debug option (see below). The logfile can be useful for tracking down a problem with Privoxy (e.g., it's not blocking an ad you think it should block) and it can help you to monitor what your browser is doing. Depending on the debug options below, the logfile may be a privacy risk if third parties can get access to it. As most users will never look at it, Privoxy 3.0.7 and later only log fatal errors by default. For most troubleshooting purposes, you will have to change that, please refer to the debugging section for details. Your logfile will grow indefinitely, and you will probably want to periodically remove it. On Unix systems, you can do this with a cron job (see man cron). Any log files must be writable by whatever user Privoxy is being run as (on Unix, default user id is privoxy). @@logfile logfile]]> trustfile Specifies: The name of the trust file to use Type of value: File name, relative to confdir Default value: Unset (commented out). When activated: trust (Unix) or trust.txt (Windows) Effect if unset: The entire trust mechanism is disabled. Notes: The trust mechanism is an experimental feature for building white-lists and should be used with care. It is NOT recommended for the casual user. If you specify a trust file, Privoxy will only allow access to sites that are specified in the trustfile. Sites can be listed in one of two ways: Prepending a ~ character limits access to this site only (and any sub-paths within this site), e.g. ~www.example.com allows access to ~www.example.com/features/news.html, etc. Or, you can designate sites as trusted referrers, by prepending the name with a + character. The effect is that access to untrusted sites will be granted -- but only if a link from this trusted referrer was used to get there. The link target will then be added to the trustfile so that future, direct accesses will be granted. Sites added via this mechanism do not become trusted referrers themselves (i.e. they are added with a ~ designation). There is a limit of 512 such entries, after which new entries will not be made. If you use the + operator in the trust file, it may grow considerably over time. It is recommended that Privoxy be compiled with the --disable-force, --disable-toggle and --disable-editor options, if this feature is to be used. Possible applications include limiting Internet access for children. @@#trustfile trust]]> Debugging These options are mainly useful when tracing a problem. Note that you might also want to invoke Privoxy with the --no-daemon command line option when debugging. debug Specifies: Key values that determine what information gets logged. Type of value: Integer values Default value: 0 (i.e.: only fatal errors (that cause Privoxy to exit) are logged) Effect if unset: Default value is used (see above). Notes: The available debug levels are: debug 1 # Log the destination for each request &my-app; let through. See also debug 1024. debug 2 # show each connection status debug 4 # show I/O status debug 8 # show header parsing debug 16 # log all data written to the network debug 32 # debug force feature debug 64 # debug regular expression filters debug 128 # debug redirects debug 256 # debug GIF de-animation debug 512 # Common Log Format debug 1024 # Log the destination for requests &my-app; didn't let through, and the reason why. debug 2048 # CGI user interface debug 4096 # Startup banner and warnings. debug 8192 # Non-fatal errors debug 32768 # log all data read from the network debug 65536 # Log the applying actions To select multiple debug levels, you can either add them or use multiple debug lines. A debug level of 1 is informative because it will show you each request as it happens. 1, 1024, 4096 and 8192 are recommended so that you will notice when things go wrong. The other levels are probably only of interest if you are hunting down a specific problem. They can produce a hell of an output (especially 16). &my-app; used to ship with the debug levels recommended above enabled by default, but due to privacy concerns 3.0.7 and later are configured to only log fatal errors. If you are used to the more verbose settings, simply enable the debug lines below again. If you want to use pure CLF (Common Log Format), you should set debug 512 ONLY and not enable anything else. Privoxy has a hard-coded limit for the length of log messages. If it's reached, messages are logged truncated and marked with ... [too long, truncated]. Please don't file any support requests without trying to reproduce the problem with increased debug level first. Once you read the log messages, you may even be able to solve the problem on your own. @@#debug 1 # Log the destination for each request &my-app; let through.]]> @@#debug 1024 # Log the destination for requests &my-app; didn't let through, and the reason why.]]> @@#debug 4096 # Startup banner and warnings]]> @@#debug 8192 # Non-fatal errors]]> single-threaded Specifies: Whether to run only one server thread. Type of value: None Default value: Unset Effect if unset: Multi-threaded (or, where unavailable: forked) operation, i.e. the ability to serve multiple requests simultaneously. Notes: This option is only there for debugging purposes. It will drastically reduce performance. @@#single-threaded]]> hostname Specifies: The hostname shown on the CGI pages. Type of value: Text Default value: Unset Effect if unset: The hostname provided by the operating system is used. Notes: On some misconfigured systems resolving the hostname fails or takes too much time and slows Privoxy down. Setting a fixed hostname works around the problem. In other circumstances it might be desirable to show a hostname other than the one returned by the operating system. For example if the system has several different hostnames and you don't want to use the first one. Note that Privoxy does not validate the specified hostname value. @@#hostname hostname.example.org]]> Access Control and Security This section of the config file controls the security-relevant aspects of Privoxy's configuration. listen-address Specifies: The address and TCP port on which Privoxy will listen for client requests. Type of value: [IP-Address]:Port [Hostname]:Port Default value: 127.0.0.1:8118 Effect if unset: Bind to 127.0.0.1 (IPv4 localhost), port 8118. This is suitable and recommended for home users who run Privoxy on the same machine as their browser. Notes: You will need to configure your browser(s) to this proxy address and port. If you already have another service running on port 8118, or if you want to serve requests from other machines (e.g. on your local network) as well, you will need to override the default. You can use this statement multiple times to make Privoxy listen on more ports or more IP addresses. Suitable if your operating system does not support sharing IPv6 and IPv4 protocols on the same socket. If a hostname is used instead of an IP address, Privoxy will try to resolve it to an IP address and if there are multiple, use the first one returned. If the address for the hostname isn't already known on the system (for example because it's in /etc/hostname), this may result in DNS traffic. If the specified address isn't available on the system, or if the hostname can't be resolved, Privoxy will fail to start. IPv6 addresses containing colons have to be quoted by brackets. They can only be used if Privoxy has been compiled with IPv6 support. If you aren't sure if your version supports it, have a look at http://config.privoxy.org/show-status. Some operating systems will prefer IPv6 to IPv4 addresses even if the system has no IPv6 connectivity which is usually not expected by the user. Some even rely on DNS to resolve localhost which mean the "localhost" address used may not actually be local. It is therefore recommended to explicitly configure the intended IP address instead of relying on the operating system, unless there's a strong reason not to. If you leave out the address, Privoxy will bind to all IPv4 interfaces (addresses) on your machine and may become reachable from the Internet and/or the local network. Be aware that some GNU/Linux distributions modify that behaviour without updating the documentation. Check for non-standard patches if your Privoxy version behaves differently. If you configure Privoxy to be reachable from the network, consider using access control lists (ACL's, see below), and/or a firewall. If you open Privoxy to untrusted users, you will also want to make sure that the following actions are disabled: enable-edit-actions and enable-remote-toggle Example: Suppose you are running Privoxy on a machine which has the address 192.168.0.1 on your local private network (192.168.0.0) and has another outside connection with a different address. You want it to serve requests from inside only: listen-address 192.168.0.1:8118 Suppose you are running Privoxy on an IPv6-capable machine and you want it to listen on the IPv6 address of the loopback device: listen-address [::1]:8118 @@listen-address 127.0.0.1:8118]]> toggle Specifies: Initial state of "toggle" status Type of value: 1 or 0 Default value: 1 Effect if unset: Act as if toggled on Notes: If set to 0, Privoxy will start in toggled off mode, i.e. mostly behave like a normal, content-neutral proxy with both ad blocking and content filtering disabled. See enable-remote-toggle below. @@toggle 1]]> enable-remote-toggle Specifies: Whether or not the web-based toggle feature may be used Type of value: 0 or 1 Default value: 0 Effect if unset: The web-based toggle feature is disabled. Notes: When toggled off, Privoxy mostly acts like a normal, content-neutral proxy, i.e. doesn't block ads or filter content. Access to the toggle feature can not be controlled separately by ACLs or HTTP authentication, so that everybody who can access Privoxy (see ACLs and listen-address above) can toggle it for all users. So this option is not recommended for multi-user environments with untrusted users. Note that malicious client side code (e.g Java) is also capable of using this option. As a lot of Privoxy users don't read documentation, this feature is disabled by default. Note that you must have compiled Privoxy with support for this feature, otherwise this option has no effect. @@enable-remote-toggle 0]]> enable-remote-http-toggle Specifies: Whether or not Privoxy recognizes special HTTP headers to change its behaviour. Type of value: 0 or 1 Default value: 0 Effect if unset: Privoxy ignores special HTTP headers. Notes: When toggled on, the client can change Privoxy's behaviour by setting special HTTP headers. Currently the only supported special header is X-Filter: No, to disable filtering for the ongoing request, even if it is enabled in one of the action files. This feature is disabled by default. If you are using Privoxy in a environment with trusted clients, you may enable this feature at your discretion. Note that malicious client side code (e.g Java) is also capable of using this feature. This option will be removed in future releases as it has been obsoleted by the more general header taggers. @@enable-remote-http-toggle 0]]> enable-edit-actions Specifies: Whether or not the web-based actions file editor may be used Type of value: 0 or 1 Default value: 0 Effect if unset: The web-based actions file editor is disabled. Notes: Access to the editor can not be controlled separately by ACLs or HTTP authentication, so that everybody who can access Privoxy (see ACLs and listen-address above) can modify its configuration for all users. This option is not recommended for environments with untrusted users and as a lot of Privoxy users don't read documentation, this feature is disabled by default. Note that malicious client side code (e.g Java) is also capable of using the actions editor and you shouldn't enable this options unless you understand the consequences and are sure your browser is configured correctly. Note that you must have compiled Privoxy with support for this feature, otherwise this option has no effect. @@enable-edit-actions 0]]> enforce-blocks Specifies: Whether the user is allowed to ignore blocks and can go there anyway. Type of value: 0 or 1 Default value: 0 Effect if unset: Blocks are not enforced. Notes: Privoxy is mainly used to block and filter requests as a service to the user, for example to block ads and other junk that clogs the pipes. Privoxy's configuration isn't perfect and sometimes innocent pages are blocked. In this situation it makes sense to allow the user to enforce the request and have Privoxy ignore the block. In the default configuration Privoxy's Blocked page contains a go there anyway link to adds a special string (the force prefix) to the request URL. If that link is used, Privoxy will detect the force prefix, remove it again and let the request pass. Of course Privoxy can also be used to enforce a network policy. In that case the user obviously should not be able to bypass any blocks, and that's what the enforce-blocks option is for. If it's enabled, Privoxy hides the go there anyway link. If the user adds the force prefix by hand, it will not be accepted and the circumvention attempt is logged. Examples: enforce-blocks 1 @@enforce-blocks 0]]> ACLs: permit-access and deny-access Specifies: Who can access what. Type of value: src_addr[:port][/src_masklen] [dst_addr[:port][/dst_masklen]] Where src_addr and dst_addr are IPv4 addresses in dotted decimal notation or valid DNS names, port is a port number, and src_masklen and dst_masklen are subnet masks in CIDR notation, i.e. integer values from 2 to 30 representing the length (in bits) of the network address. The masks and the whole destination part are optional. If your system implements RFC 3493, then src_addr and dst_addr can be IPv6 addresses delimeted by brackets, port can be a number or a service name, and src_masklen and dst_masklen can be a number from 0 to 128. Default value: Unset If no port is specified, any port will match. If no src_masklen or src_masklen is given, the complete IP address has to match (i.e. 32 bits for IPv4 and 128 bits for IPv6). Effect if unset: Don't restrict access further than implied by listen-address Notes: Access controls are included at the request of ISPs and systems administrators, and are not usually needed by individual users. For a typical home user, it will normally suffice to ensure that Privoxy only listens on the localhost (127.0.0.1) or internal (home) network address by means of the listen-address option. Please see the warnings in the FAQ that Privoxy is not intended to be a substitute for a firewall or to encourage anyone to defer addressing basic security weaknesses. Multiple ACL lines are OK. If any ACLs are specified, Privoxy only talks to IP addresses that match at least one permit-access line and don't match any subsequent deny-access line. In other words, the last match wins, with the default being deny-access. If Privoxy is using a forwarder (see forward below) for a particular destination URL, the dst_addr that is examined is the address of the forwarder and NOT the address of the ultimate target. This is necessary because it may be impossible for the local Privoxy to determine the IP address of the ultimate target (that's often what gateways are used for). You should prefer using IP addresses over DNS names, because the address lookups take time. All DNS names must resolve! You can not use domain patterns like *.org or partial domain names. If a DNS name resolves to multiple IP addresses, only the first one is used. Some systems allow IPv4 clients to connect to IPv6 server sockets. Then the client's IPv4 address will be translated by the system into IPv6 address space with special prefix ::ffff:0:0/96 (so called IPv4 mapped IPv6 address). Privoxy can handle it and maps such ACL addresses automatically. Denying access to particular sites by ACL may have undesired side effects if the site in question is hosted on a machine which also hosts other sites (most sites are). Examples: Explicitly define the default behavior if no ACL and listen-address are set: localhost is OK. The absence of a dst_addr implies that all destination addresses are OK: permit-access localhost Allow any host on the same class C subnet as www.privoxy.org access to nothing but www.example.com (or other domains hosted on the same system): permit-access www.privoxy.org/24 www.example.com/32 Allow access from any host on the 26-bit subnet 192.168.45.64 to anywhere, with the exception that 192.168.45.73 may not access the IP address behind www.dirty-stuff.example.com: permit-access 192.168.45.64/26 deny-access 192.168.45.73 www.dirty-stuff.example.com Allow access from the IPv4 network 192.0.2.0/24 even if listening on an IPv6 wild card address (not supported on all platforms): permit-access 192.0.2.0/24 This is equivalent to the following line even if listening on an IPv4 address (not supported on all platforms): permit-access [::ffff:192.0.2.0]/120 buffer-limit Specifies: Maximum size of the buffer for content filtering. Type of value: Size in Kbytes Default value: 4096 Effect if unset: Use a 4MB (4096 KB) limit. Notes: For content filtering, i.e. the +filter and +deanimate-gif actions, it is necessary that Privoxy buffers the entire document body. This can be potentially dangerous, since a server could just keep sending data indefinitely and wait for your RAM to exhaust -- with nasty consequences. Hence this option. When a document buffer size reaches the buffer-limit, it is flushed to the client unfiltered and no further attempt to filter the rest of the document is made. Remember that there may be multiple threads running, which might require up to buffer-limit Kbytes each, unless you have enabled single-threaded above. @@buffer-limit 4096]]> enable-proxy-authentication-forwarding Specifies: Whether or not proxy authentication through &my-app; should work. Type of value: 0 or 1 Default value: 0 Effect if unset: Proxy authentication headers are removed. Notes: Privoxy itself does not support proxy authentication, but can allow clients to authenticate against Privoxy's parent proxy. By default Privoxy (3.0.21 and later) don't do that and remove Proxy-Authorization headers in requests and Proxy-Authenticate headers in responses to make it harder for malicious sites to trick inexperienced users into providing login information. If this option is enabled the headers are forwarded. Enabling this option is not recommended if there is no parent proxy that requires authentication or if the local network between Privoxy and the parent proxy isn't trustworthy. If proxy authentication is only required for some requests, it is recommended to use a client header filter to remove the authentication headers for requests where they aren't needed. @@enable-proxy-authentication-forwarding 0]]> Forwarding This feature allows routing of HTTP requests through a chain of multiple proxies. Forwarding can be used to chain Privoxy with a caching proxy to speed up browsing. Using a parent proxy may also be necessary if the machine that Privoxy runs on has no direct Internet access. Note that parent proxies can severely decrease your privacy level. For example a parent proxy could add your IP address to the request headers and if it's a caching proxy it may add the Etag header to revalidation requests again, even though you configured Privoxy to remove it. It may also ignore Privoxy's header time randomization and use the original values which could be used by the server as cookie replacement to track your steps between visits. Also specified here are SOCKS proxies. Privoxy supports the SOCKS 4 and SOCKS 4A protocols. forward Specifies: To which parent HTTP proxy specific requests should be routed. Type of value: target_pattern http_parent[:port] where target_pattern is a URL pattern that specifies to which requests (i.e. URLs) this forward rule shall apply. Use / to denote all URLs. http_parent[:port] is the DNS name or IP address of the parent HTTP proxy through which the requests should be forwarded, optionally followed by its listening port (default: 8000). Use a single dot (.) to denote no forwarding. Default value: Unset Effect if unset: Don't use parent HTTP proxies. Notes: If http_parent is ., then requests are not forwarded to another HTTP proxy but are made directly to the web servers. http_parent can be a numerical IPv6 address (if RFC 3493 is implemented). To prevent clashes with the port delimiter, the whole IP address has to be put into brackets. On the other hand a target_pattern containing an IPv6 address has to be put into angle brackets (normal brackets are reserved for regular expressions already). Multiple lines are OK, they are checked in sequence, and the last match wins. Examples: Everything goes to an example parent proxy, except SSL on port 443 (which it doesn't handle): forward / parent-proxy.example.org:8080 forward :443 . Everything goes to our example ISP's caching proxy, except for requests to that ISP's sites: forward / caching-proxy.isp.example.net:8000 forward .isp.example.net . Parent proxy specified by an IPv6 address: forward / [2001:DB8::1]:8000 Suppose your parent proxy doesn't support IPv6: forward / parent-proxy.example.org:8000 forward ipv6-server.example.org . forward <[2-3][0-9a-f][0-9a-f][0-9a-f]:*> . forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t Specifies: Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed. Type of value: target_pattern socks_proxy[:port] http_parent[:port] where target_pattern is a URL pattern that specifies to which requests (i.e. URLs) this forward rule shall apply. Use / to denote all URLs. http_parent and socks_proxy are IP addresses in dotted decimal notation or valid DNS names (http_parent may be . to denote no HTTP forwarding), and the optional port parameters are TCP ports, i.e. integer values from 1 to 65535 Default value: Unset Effect if unset: Don't use SOCKS proxies. Notes: Multiple lines are OK, they are checked in sequence, and the last match wins. The difference between forward-socks4 and forward-socks4a is that in the SOCKS 4A protocol, the DNS resolution of the target hostname happens on the SOCKS server, while in SOCKS 4 it happens locally. With forward-socks5 the DNS resolution will happen on the remote server as well. forward-socks5t works like vanilla forward-socks5 but lets &my-app; additionally use Tor-specific SOCKS extensions. Currently the only supported SOCKS extension is optimistic data which can reduce the latency for the first request made on a newly created connection. socks_proxy and http_parent can be a numerical IPv6 address (if RFC 3493 is implemented). To prevent clashes with the port delimiter, the whole IP address has to be put into brackets. On the other hand a target_pattern containing an IPv6 address has to be put into angle brackets (normal brackets are reserved for regular expressions already). If http_parent is ., then requests are not forwarded to another HTTP proxy but are made (HTTP-wise) directly to the web servers, albeit through a SOCKS proxy. Examples: From the company example.com, direct connections are made to all internal domains, but everything outbound goes through their ISP's proxy by way of example.com's corporate SOCKS 4A gateway to the Internet. forward-socks4a / socks-gw.example.com:1080 www-cache.isp.example.net:8080 forward .example.com . A rule that uses a SOCKS 4 gateway for all destinations but no HTTP parent looks like this: forward-socks4 / socks-gw.example.com:1080 . To chain Privoxy and Tor, both running on the same system, you would use something like: forward-socks5 / 127.0.0.1:9050 . The public Tor network can't be used to reach your local network, if you need to access local servers you therefore might want to make some exceptions: forward 192.168.*.*/ . forward 10.*.*.*/ . forward 127.*.*.*/ . Unencrypted connections to systems in these address ranges will be as (un)secure as the local network is, but the alternative is that you can't reach the local network through Privoxy at all. Of course this may actually be desired and there is no reason to make these exceptions if you aren't sure you need them. If you also want to be able to reach servers in your local network by using their names, you will need additional exceptions that look like this: forward localhost/ . Advanced Forwarding Examples If you have links to multiple ISPs that provide various special content only to their subscribers, you can configure multiple Privoxies which have connections to the respective ISPs to act as forwarders to each other, so that your users can see the internal content of all ISPs. Assume that host-a has a PPP connection to isp-a.example.net. And host-b has a PPP connection to isp-b.example.org. Both run Privoxy. Their forwarding configuration can look like this: host-a: forward / . forward .isp-b.example.net host-b:8118 host-b: forward / . forward .isp-a.example.org host-a:8118 Now, your users can set their browser's proxy to use either host-a or host-b and be able to browse the internal content of both isp-a and isp-b. If you intend to chain Privoxy and squid locally, then chaining as browser -> squid -> privoxy is the recommended way. Assuming that Privoxy and squid run on the same box, your squid configuration could then look like this: # Define Privoxy as parent proxy (without ICP) cache_peer 127.0.0.1 parent 8118 7 no-query # Define ACL for protocol FTP acl ftp proto FTP # Do not forward FTP requests to Privoxy always_direct allow ftp # Forward all the rest to Privoxy never_direct allow all You would then need to change your browser's proxy settings to squid's address and port. Squid normally uses port 3128. If unsure consult http_port in squid.conf. You could just as well decide to only forward requests you suspect of leading to Windows executables through a virus-scanning parent proxy, say, on antivir.example.com, port 8010: forward / . forward /.*\.(exe|com|dll|zip)$ antivir.example.com:8010 ]]> forwarded-connect-retries Specifies: How often Privoxy retries if a forwarded connection request fails. Type of value: Number of retries. Default value: 0 Effect if unset: Connections forwarded through other proxies are treated like direct connections and no retry attempts are made. Notes: forwarded-connect-retries is mainly interesting for socks4a connections, where Privoxy can't detect why the connections failed. The connection might have failed because of a DNS timeout in which case a retry makes sense, but it might also have failed because the server doesn't exist or isn't reachable. In this case the retry will just delay the appearance of Privoxy's error message. Note that in the context of this option, forwarded connections includes all connections that Privoxy forwards through other proxies. This option is not limited to the HTTP CONNECT method. Only use this option, if you are getting lots of forwarding-related error messages that go away when you try again manually. Start with a small value and check Privoxy's logfile from time to time, to see how many retries are usually needed. Examples: forwarded-connect-retries 1 @@forwarded-connect-retries 0]]> Miscellaneous accept-intercepted-requests Specifies: Whether intercepted requests should be treated as valid. Type of value: 0 or 1 Default value: 0 Effect if unset: Only proxy requests are accepted, intercepted requests are treated as invalid. Notes: If you don't trust your clients and want to force them to use Privoxy, enable this option and configure your packet filter to redirect outgoing HTTP connections into Privoxy. Make sure that Privoxy's own requests aren't redirected as well. Additionally take care that Privoxy can't intentionally connect to itself, otherwise you could run into redirection loops if Privoxy's listening port is reachable by the outside or an attacker has access to the pages you visit. Examples: accept-intercepted-requests 1 @@accept-intercepted-requests 0]]> allow-cgi-request-crunching Specifies: Whether requests to Privoxy's CGI pages can be blocked or redirected. Type of value: 0 or 1 Default value: 0 Effect if unset: Privoxy ignores block and redirect actions for its CGI pages. Notes: By default Privoxy ignores block or redirect actions for its CGI pages. Intercepting these requests can be useful in multi-user setups to implement fine-grained access control, but it can also render the complete web interface useless and make debugging problems painful if done without care. Don't enable this option unless you're sure that you really need it. Examples: allow-cgi-request-crunching 1 @@allow-cgi-request-crunching 0]]> split-large-forms Specifies: Whether the CGI interface should stay compatible with broken HTTP clients. Type of value: 0 or 1 Default value: 0 Effect if unset: The CGI form generate long GET URLs. Notes: Privoxy's CGI forms can lead to rather long URLs. This isn't a problem as far as the HTTP standard is concerned, but it can confuse clients with arbitrary URL length limitations. Enabling split-large-forms causes Privoxy to divide big forms into smaller ones to keep the URL length down. It makes editing a lot less convenient and you can no longer submit all changes at once, but at least it works around this browser bug. If you don't notice any editing problems, there is no reason to enable this option, but if one of the submit buttons appears to be broken, you should give it a try. Examples: split-large-forms 1 @@split-large-forms 0]]> keep-alive-timeout Specifies: Number of seconds after which an open connection will no longer be reused. Type of value: Time in seconds. Default value: None Effect if unset: Connections are not kept alive. Notes: This option allows clients to keep the connection to &my-app; alive. If the server supports it, &my-app; will keep the connection to the server alive as well. Under certain circumstances this may result in speed-ups. By default, &my-app; will close the connection to the server if the client connection gets closed, or if the specified timeout has been reached without a new request coming in. This behaviour can be changed with the connection-sharing option. This option has no effect if Privoxy has been compiled without keep-alive support. Note that a timeout of five seconds as used in the default configuration file significantly decreases the number of connections that will be reused. The value is used because some browsers limit the number of connections they open to a single host and apply the same limit to proxies. This can result in a single website grabbing all the connections the browser allows, which means connections to other websites can't be opened until the connections currently in use time out. Several users have reported this as a Privoxy bug, so the default value has been reduced. Consider increasing it to 300 seconds or even more if you think your browser can handle it. If your browser appears to be hanging, it probably can't. Examples: keep-alive-timeout 300 @@keep-alive-timeout 5]]> tolerate-pipelining Specifies: Whether or not pipelined requests should be served. Type of value: 0 or 1. Default value: None Effect if unset: If Privoxy receives more than one request at once, it terminates the client connection after serving the first one. Notes: &my-app; currently doesn't pipeline outgoing requests, thus allowing pipelining on the client connection is not guaranteed to improve the performance. By default &my-app; tries to discourage clients from pipelining by discarding aggressively pipelined requests, which forces the client to resend them through a new connection. This option lets &my-app; tolerate pipelining. Whether or not that improves performance mainly depends on the client configuration. If you are seeing problems with pages not properly loading, disabling this option could work around the problem. Examples: tolerate-pipelining 1 @@tolerate-pipelining 1]]> default-server-timeout Specifies: Assumed server-side keep-alive timeout if not specified by the server. Type of value: Time in seconds. Default value: None Effect if unset: Connections for which the server didn't specify the keep-alive timeout are not reused. Notes: Enabling this option significantly increases the number of connections that are reused, provided the keep-alive-timeout option is also enabled. While it also increases the number of connections problems when &my-app; tries to reuse a connection that already has been closed on the server side, or is closed while &my-app; is trying to reuse it, this should only be a problem if it happens for the first request sent by the client. If it happens for requests on reused client connections, &my-app; will simply close the connection and the client is supposed to retry the request without bothering the user. Enabling this option is therefore only recommended if the connection-sharing option is disabled. It is an error to specify a value larger than the keep-alive-timeout value. This option has no effect if Privoxy has been compiled without keep-alive support. Examples: default-server-timeout 60 @@#default-server-timeout 60]]> connection-sharing Specifies: Whether or not outgoing connections that have been kept alive should be shared between different incoming connections. Type of value: 0 or 1 Default value: None Effect if unset: Connections are not shared. Notes: This option has no effect if Privoxy has been compiled without keep-alive support, or if it's disabled. Notes: Note that reusing connections doesn't necessary cause speedups. There are also a few privacy implications you should be aware of. If this option is effective, outgoing connections are shared between clients (if there are more than one) and closing the browser that initiated the outgoing connection does no longer affect the connection between &my-app; and the server unless the client's request hasn't been completed yet. If the outgoing connection is idle, it will not be closed until either Privoxy's or the server's timeout is reached. While it's open, the server knows that the system running &my-app; is still there. If there are more than one client (maybe even belonging to multiple users), they will be able to reuse each others connections. This is potentially dangerous in case of authentication schemes like NTLM where only the connection is authenticated, instead of requiring authentication for each request. If there is only a single client, and if said client can keep connections alive on its own, enabling this option has next to no effect. If the client doesn't support connection keep-alive, enabling this option may make sense as it allows &my-app; to keep outgoing connections alive even if the client itself doesn't support it. You should also be aware that enabling this option increases the likelihood of getting the "No server or forwarder data" error message, especially if you are using a slow connection to the Internet. This option should only be used by experienced users who understand the risks and can weight them against the benefits. Examples: connection-sharing 1 @@#connection-sharing 1]]> socket-timeout Specifies: Number of seconds after which a socket times out if no data is received. Type of value: Time in seconds. Default value: None Effect if unset: A default value of 300 seconds is used. Notes: The default is quite high and you probably want to reduce it. If you aren't using an occasionally slow proxy like Tor, reducing it to a few seconds should be fine. Examples: socket-timeout 300 @@socket-timeout 300]]> max-client-connections Specifies: Maximum number of client connections that will be served. Type of value: Positive number. Default value: 128 Effect if unset: Connections are served until a resource limit is reached. Notes: &my-app; creates one thread (or process) for every incoming client connection that isn't rejected based on the access control settings. If the system is powerful enough, &my-app; can theoretically deal with several hundred (or thousand) connections at the same time, but some operating systems enforce resource limits by shutting down offending processes and their default limits may be below the ones &my-app; would require under heavy load. Configuring &my-app; to enforce a connection limit below the thread or process limit used by the operating system makes sure this doesn't happen. Simply increasing the operating system's limit would work too, but if &my-app; isn't the only application running on the system, you may actually want to limit the resources used by &my-app;. If &my-app; is only used by a single trusted user, limiting the number of client connections is probably unnecessary. If there are multiple possibly untrusted users you probably still want to additionally use a packet filter to limit the maximal number of incoming connections per client. Otherwise a malicious user could intentionally create a high number of connections to prevent other users from using &my-app;. Obviously using this option only makes sense if you choose a limit below the one enforced by the operating system. One most POSIX-compliant systems &my-app; can't properly deal with more than FD_SETSIZE file descriptors at the same time and has to reject connections if the limit is reached. This will likely change in a future version, but currently this limit can't be increased without recompiling &my-app; with a different FD_SETSIZE limit. Examples: max-client-connections 256 @@#max-client-connections 256]]> handle-as-empty-doc-returns-ok Specifies: The status code Privoxy returns for pages blocked with +handle-as-empty-document. Type of value: 0 or 1 Default value: 0 Effect if unset: Privoxy returns a status 403(forbidden) for all blocked pages. Effect if set: Privoxy returns a status 200(OK) for pages blocked with +handle-as-empty-document and a status 403(Forbidden) for all other blocked pages. Notes: This is a work-around for Firefox bug 492459: Websites are no longer rendered if SSL requests for JavaScripts are blocked by a proxy. (https://bugzilla.mozilla.org/show_bug.cgi?id=492459) As the bug has been fixed for quite some time this option should no longer be needed and will be removed in a future release. Please speak up if you have a reason why the option should be kept around. @@#handle-as-empty-doc-returns-ok 1]]> enable-compression Specifies: Whether or not buffered content is compressed before delivery. Type of value: 0 or 1 Default value: 0 Effect if unset: Privoxy does not compress buffered content. Effect if set: Privoxy compresses buffered content before delivering it to the client, provided the client supports it. Notes: This directive is only supported if Privoxy has been compiled with FEATURE_COMPRESSION, which should not to be confused with FEATURE_ZLIB. Compressing buffered content is mainly useful if Privoxy and the client are running on different systems. If they are running on the same system, enabling compression is likely to slow things down. If you didn't measure otherwise, you should assume that it does and keep this option disabled. Privoxy will not compress buffered content below a certain length. @@#enable-compression 1]]> compression-level Specifies: The compression level that is passed to the zlib library when compressing buffered content. Type of value: Positive number ranging from 0 to 9. Default value: 1 Notes: Compressing the data more takes usually longer than compressing it less or not compressing it at all. Which level is best depends on the connection between Privoxy and the client. If you can't be bothered to benchmark it for yourself, you should stick with the default and keep compression disabled. If compression is disabled, the compression level is irrelevant. Examples: # Best speed (compared to the other levels) compression-level 1 # Best compression compression-level 9 # No compression. Only useful for testing as the added header # slightly increases the amount of data that has to be sent. # If your benchmark shows that using this compression level # is superior to using no compression at all, the benchmark # is likely to be flawed. compression-level 0 @@#compression-level 1]]> client-header-order Specifies: The order in which client headers are sorted before forwarding them. Type of value: Client header names delimited by spaces or tabs Default value: None Notes: By default &my-app; leaves the client headers in the order they were sent by the client. Headers are modified in-place, new headers are added at the end of the already existing headers. The header order can be used to fingerprint client requests independently of other headers like the User-Agent. This directive allows to sort the headers differently to better mimic a different User-Agent. Client headers will be emitted in the order given, headers whose name isn't explicitly specified are added at the end. Note that sorting headers in an uncommon way will make fingerprinting actually easier. Encrypted headers are not affected by this directive. @@#client-header-order Host \ User-Agent \ Accept \ Accept-Language \ Accept-Encoding \ Proxy-Connection \ Referer \ Cookie \ DNT \ If-Modified-Since \ Cache-Control \ Content-Length \ Content-Type ]]> Windows GUI Options Privoxy has a number of options specific to the Windows GUI interface: @@]]> If activity-animation is set to 1, the Privoxy icon will animate when Privoxy is active. To turn off, set to 0. @@#activity-animation 1]]> activity-animation 1 ]]> @@]]> If log-messages is set to 1, Privoxy copies log messages to the console window. The log detail depends on the debug directive. @@#log-messages 1]]> log-messages 1 ]]> @@]]> If log-buffer-size is set to 1, the size of the log buffer, i.e. the amount of memory used for the log messages displayed in the console window, will be limited to log-max-lines (see below). Warning: Setting this to 0 will result in the buffer to grow infinitely and eat up all your memory! @@#log-buffer-size 1]]> log-buffer-size 1 ]]> @@]]> log-max-lines is the maximum number of lines held in the log buffer. See above. @@#log-max-lines 200]]> log-max-lines 200 ]]> @@]]> If log-highlight-messages is set to 1, Privoxy will highlight portions of the log messages with a bold-faced font: @@#log-highlight-messages 1]]> log-highlight-messages 1 ]]> @@]]> The font used in the console window: @@#log-font-name Comic Sans MS]]> log-font-name Comic Sans MS ]]> @@]]> Font size used in the console window: @@#log-font-size 8]]> log-font-size 8 ]]> @@]]> show-on-task-bar controls whether or not Privoxy will appear as a button on the Task bar when minimized: @@#show-on-task-bar 0]]> show-on-task-bar 0 ]]> @@]]> If close-button-minimizes is set to 1, the Windows close button will minimize Privoxy instead of closing the program (close with the exit option on the File menu). @@#close-button-minimizes 1]]> close-button-minimizes 1 ]]> @@]]> The hide-console option is specific to the MS-Win console version of Privoxy. If this option is used, Privoxy will disconnect from and hide the command console. @@#hide-console]]> #hide-console ]]> ]]> privoxy-3.0.21-stable/./doc/source/developer-manual.sgml000640 001751 001751 00000320730 12114164370 022157 0ustar00fkfk000000 000000 ]>
    Privoxy Developer Manual Copyright &my-copy; 2001-2013 by Privoxy Developers $Id: developer-manual.sgml,v 2.57 2013/03/01 17:44:24 fabiankeil Exp $ This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> The developer manual provides guidance on coding, testing, packaging, documentation and other issues of importance to those involved with Privoxy development. It is mandatory (and helpful!) reading for anyone who wants to join the team. Note that it's currently out of date and may not be entirely correct. As always, patches are welcome. Please note that this document is constantly evolving. This copy represents the state at the release of version &p-version;. You can find the latest version of the this manual at http://www.privoxy.org/developer-manual/. Please have a look at the contact section in the user manual if you are interested in contacting the developers. Introduction Privoxy, as an heir to Junkbuster, is a Free Software project and the code is licensed under the GNU General Public License version 2. As such, Privoxy development is potentially open to anyone who has the time, knowledge, and desire to contribute in any capacity. Our goals are simply to continue the mission, to improve Privoxy, and to make it available to as wide an audience as possible. One does not have to be a programmer to contribute. Packaging, testing, documenting and porting, are all important jobs as well. Quickstart to Privoxy Development The first step is to join the developer's mailing list. You can submit your ideas, or even better patches. Patches are best submitted to the Sourceforge tracker set up for this purpose, but can be sent to the list for review too. You will also need to have a cvs package installed, which will entail having ssh installed as well (which seems to be a requirement of SourceForge), in order to access the cvs repository. Having the GNU build tools is also going to be important (particularly, autoconf and gmake). For the time being (read, this section is under construction), you can also refer to the extensive comments in the source code. In fact, reading the code is recommended in any case. The CVS Repository If you become part of the active development team, you will eventually need write access to our holy grail, the CVS repository. One of the team members will need to set this up for you. Please read this chapter completely before accessing via CVS. Access to CVS The project's CVS repository is hosted on SourceForge. Please refer to the chapters 6 and 7 in SF's site documentation for the technical access details for your operating system. For historical reasons, the CVS server is called ijbswa.cvs.sourceforge.net, the repository is called ijbswa, and the source tree module is called current. Branches Within the CVS repository, there are modules and branches. As mentioned, the sources are in the current module. Other modules are present for platform specific issues. There is a webview of the CVS hierarchy at http://ijbswa.cvs.sourceforge.net/ijbswa/, which might help with visualizing how these pieces fit together. At one time there were two distinct branches: stable and unstable. The more drastic changes were to be in the unstable branch. These branches have now been merged to minimize time and effort of maintaining two branches. CVS Commit Guidelines The source tree is the heart of every software project. Every effort must be made to ensure that it is readable, compilable and consistent at all times. We expect anyone with CVS access to strictly adhere to the following guidelines: Basic Guidelines, for all branches: Please don't commit even a small change without testing it thoroughly first. When we're close to a public release, ask a fellow developer to review your changes. Your commit message should give a concise overview of what you changed (no big details) and why you changed it Just check previous messages for good examples. Don't use the same message on multiple files, unless it equally applies to all those files. If your changes span multiple files, and the code won't recompile unless all changes are committed (e.g. when changing the signature of a function), then commit all files one after another, without long delays in between. If necessary, prepare the commit messages in advance. Before changing things on CVS, make sure that your changes are in line with the team's general consensus on what should be done. Note that near a major public release, we get more cautious. There is always the possibility to submit a patch to the patch tracker instead. Documentation Guidelines All formal documents are maintained in Docbook SGML and located in the doc/source/* directory. You will need Docbook, the Docbook DTD's and the Docbook modular stylesheets (or comparable alternatives), and either jade or openjade (recommended) installed in order to build docs from source. Currently there is user-manual, FAQ, and, of course this, the developer-manual in this format. The README, AUTHORS, INSTALL, privoxy.1 (man page), and config files are also now maintained as Docbook SGML. These files, when built, in the top-level source directory are generated files! Also, the Privoxy index.html (and a variation on this file, privoxy-index.html, meant for inclusion with doc packages), are maintained as SGML as well. DO NOT edit these directly. Edit the SGML source, or contact someone involved in the documentation. config requires some special handling. The reason it is maintained this way is so that the extensive comments in the file mirror those in user-manual. But the conversion process requires going from SGML to HTML to text to special formatting required for the embedded comments. Some of this does not survive so well. Especially some of the examples that are longer than 80 characters. The build process for this file outputs to config.new, which should be reviewed for errors and mis-formatting. Once satisfied that it is correct, then it should be hand copied to config. Other, less formal documents (e.g. LICENSE) are maintained as plain text files in the top-level source directory. Packagers are encouraged to include this documentation. For those without the ability to build the docs locally, text versions of each are kept in CVS. HTML versions are also being kept in CVS under doc/webserver/*. Formal documents are built with the Makefile targets of make dok. The build process uses the document SGML sources in doc/source/*/* to update all text files in doc/text/ and to update all HTML documents in doc/webserver/. Documentation writers should please make sure documents build successfully before committing to CVS, if possible. How do you update the webserver (i.e. the pages on privoxy.org)? First, build the docs by running make dok. Run make webserver which copies all files from doc/webserver to the sourceforge webserver via scp. Finished docs should be occasionally submitted to CVS (doc/webserver/*/*.html) so that those without the ability to build them locally, have access to them if needed. This is especially important just prior to a new release! Please do this after the $VERSION and other release specific data in configure.in has been updated (this is done just prior to a new release). Quickstart to Docbook and SGML If you are not familiar with SGML, it is a markup language similar to HTML. Actually, not a mark up language per se, but a language used to define markup languages. In fact, HTML is an SGML application. Both will use tags to format text and other content. SGML tags can be much more varied, and flexible, but do much of the same kinds of things. The tags, or elements, are definable in SGML. There is no set standards. Since we are using Docbook, our tags are those that are defined by Docbook. Much of how the finish document is rendered is determined by the stylesheets. The stylesheets determine how each tag gets translated to HTML, or other formats. Tags in Docbook SGML need to be always closed. If not, you will likely generate errors. Example: <title>My Title</title>. They are also case-insensitive, but we strongly suggest using all lower case. This keeps compatibility with [Docbook] XML. Our documents use sections for the most part. Sections will be processed into HTML headers (e.g. h1 for sect1). The Docbook stylesheets will use these to also generate the Table of Contents for each doc. Our TOC's are set to a depth of three. Meaning sect1, sect2, and sect3 will have TOC entries, but sect4 will not. Each section requires a <title> element, and at least one <para>. There is a limit of five section levels in Docbook, but generally three should be sufficient for our purposes. Some common elements that you likely will use: <para></para>, paragraph delimiter. Most text needs to be within paragraph elements (there are some exceptions). <emphasis></emphasis>, the stylesheets make this italics. <filename></filename>, files and directories. <command></command>, command examples. <literallayout></literallayout>, like <pre>, more or less. <itemizedlist></itemizedlist>, list with bullets. <listitem></listitem>, member of the above. <screen></screen>, screen output, implies <literallayout>. <ulink url="example.com"></ulink>, like HTML <a> tag. <quote></quote>, for, doh, quoting text. Look at any of the existing docs for examples of all these and more. You might also find Writing Documentation Using DocBook - A Crash Course useful. <application>Privoxy</application> Documentation Style It will be easier if everyone follows a similar writing style. This just makes it easier to read what someone else has written if it is all done in a similar fashion. Here it is: All tags should be lower case. Tags delimiting a block of text (even small blocks) should be on their own line. Like: <para> Some text goes here. </para> Tags marking individual words, or few words, should be in-line: Just to <emphasis>emphasize</emphasis>, some text goes here. Tags should be nested and step indented for block text like: (except in-line tags) <para> <itemizedlist> <para> <listitem> Some text goes here in our list example. </listitem> </para> </itemizedlist> </para> This makes it easier to find the text amongst the tags ;-) Use white space to separate logical divisions within a document, like between sections. Running everything together consistently makes it harder to read and work on. Do not hesitate to make comments. Comments can either use the <comment> element, or the <!-- --> style comment familiar from HTML. (Note in Docbook v4.x <comment> is replaced by <remark>.) We have an international audience. Refrain from slang, or English idiosyncrasies (too many to list :). Humor also does not translate well sometimes. Try to keep overall line lengths in source files to 80 characters or less for obvious reasons. This is not always possible, with lengthy URLs for instance. Our documents are available in differing formats. Right now, they are just plain text and/or HTML, but others are always a future possibility. Be careful with URLs (<ulink>), and avoid this mistake: My favorite site is <ulink url="http://example.com">here</ulink>. This will render as My favorite site is here, which is not real helpful in a text doc. Better like this: My favorite site is <ulink url="http://example.com">example.com</ulink>. All documents should be spell checked occasionally. aspell can check SGML with the -H option. (ispell I think too.) Privoxy Custom Entities Privoxy documentation is using a number of customized entities to facilitate documentation maintenance. We are using a set of boilerplate files with generic text, that is used by multiple docs. This way we can write something once, and use it repeatedly without having to re-write the same content over and over again. If editing such a file, keep in mind that it should be generic. That is the purpose; so it can be used in varying contexts without additional modifications. We are also using what Docbook calls internal entities. These are like variables in programming. Well, sort of. For instance, we have the p-version entity that contains the current Privoxy version string. You are strongly encouraged to use these where possible. Some of these obviously require re-setting with each release (done by the Makefile). A sampling of custom entities are listed below. See any of the main docs for examples. Re- boilerplate text entities are defined like: <!entity supported SYSTEM "supported.sgml"> In this example, the contents of the file, supported.sgml is available for inclusion anywhere in the doc. To make this happen, just reference the now defined entity: &supported; (starts with an ampersand and ends with a semi-colon), and the contents will be dumped into the finished doc at that point. Commonly used internal entities: p-version: the Privoxy version string, e.g. &p-version;. p-status: the project status, either alpha, beta, or stable. p-not-stable: use to conditionally include text in not stable releases (e.g. beta). p-stable: just the opposite. p-text: this doc is only generated as text. There are others in various places that are defined for a specific purpose. Read the source! Coding Guidelines Introduction This set of standards is designed to make our lives easier. It is developed with the simple goal of helping us keep the "new and improved Privoxy" consistent and reliable. Thus making maintenance easier and increasing chances of success of the project. And that of course comes back to us as individuals. If we can increase our development and product efficiencies then we can solve more of the request for changes/improvements and in general feel good about ourselves. ;-> Using Comments Comment, Comment, Comment Explanation: Comment as much as possible without commenting the obvious. For example do not comment "variable_a is equal to variable_b". Instead explain why variable_a should be equal to the variable_b. Just because a person can read code does not mean they will understand why or what is being done. A reader may spend a lot more time figuring out what is going on when a simple comment or explanation would have prevented the extra research. Please help your fellow Privoxy developers out! The comments will also help justify the intent of the code. If the comment describes something different than what the code is doing then maybe a programming error is occurring. Example: /* if page size greater than 1k ... */ if (page_length() > 1024) { ... "block" the page up ... } /* if page size is small, send it in blocks */ if (page_length() > 1024) { ... "block" the page up ... } This demonstrates 2 cases of "what not to do". The first is a "syntax comment". The second is a comment that does not fit what is actually being done. Use blocks for comments Explanation: Comments can help or they can clutter. They help when they are differentiated from the code they describe. One line comments do not offer effective separation between the comment and the code. Block identifiers do, by surrounding the code with a clear, definable pattern. Example: /********************************************************************* * This will stand out clearly in your code! *********************************************************************/ if (this_variable == that_variable) { do_something_very_important(); } /* unfortunately, this may not */ if (this_variable == that_variable) { do_something_very_important(); } if (this_variable == that_variable) /* this may not either */ { do_something_very_important(); } Exception: If you are trying to add a small logic comment and do not wish to "disrupt" the flow of the code, feel free to use a 1 line comment which is NOT on the same line as the code. Keep Comments on their own line Explanation: It goes back to the question of readability. If the comment is on the same line as the code it will be harder to read than the comment that is on its own line. There are three exceptions to this rule, which should be violated freely and often: during the definition of variables, at the end of closing braces, when used to comment parameters. Example: /********************************************************************* * This will stand out clearly in your code, * But the second example won't. *********************************************************************/ if (this_variable == this_variable) { do_something_very_important(); } if (this_variable == this_variable) /*can you see me?*/ { do_something_very_important(); /*not easily*/ } /********************************************************************* * But, the encouraged exceptions: *********************************************************************/ int urls_read = 0; /* # of urls read + rejected */ int urls_rejected = 0; /* # of urls rejected */ if (1 == X) { do_something_very_important(); } short do_something_very_important( short firstparam, /* represents something */ short nextparam /* represents something else */ ) { ...code here... } /* -END- do_something_very_important */ Comment each logical step Explanation: Logical steps should be commented to help others follow the intent of the written code and comments will make the code more readable. If you have 25 lines of code without a comment, you should probably go back into it to see where you forgot to put one. Most "for", "while", "do", etc... loops _probably_ need a comment. After all, these are usually major logic containers. Comment All Functions Thoroughly Explanation: A reader of the code should be able to look at the comments just prior to the beginning of a function and discern the reason for its existence and the consequences of using it. The reader should not have to read through the code to determine if a given function is safe for a desired use. The proper information thoroughly presented at the introduction of a function not only saves time for subsequent maintenance or debugging, it more importantly aids in code reuse by allowing a user to determine the safety and applicability of any function for the problem at hand. As a result of such benefits, all functions should contain the information presented in the addendum section of this document. Comment at the end of braces if the content is more than one screen length Explanation: Each closing brace should be followed on the same line by a comment that describes the origination of the brace if the original brace is off of the screen, or otherwise far away from the closing brace. This will simplify the debugging, maintenance, and readability of the code. As a suggestion , use the following flags to make the comment and its brace more readable: use following a closing brace: } /* -END- if() or while () or etc... */ Example: if (1 == X) { do_something_very_important(); ...some long list of commands... } /* -END- if x is 1 */ or: if (1 == X) { do_something_very_important(); ...some long list of commands... } /* -END- if (1 == X) */ Naming Conventions Variable Names Explanation: Use all lowercase, and separate words via an underscore ('_'). Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.) Do not use identifiers which are reserved in ANSI C++. (E.g. template, class, true, false, ...). This is in case we ever decide to port Privoxy to C++. Example: int ms_iis5_hack = 0; Instead of: int msiis5hack = 0; int msIis5Hack = 0; Function Names Explanation: Use all lowercase, and separate words via an underscore ('_'). Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.) Do not use identifiers which are reserved in ANSI C++. (E.g. template, class, true, false, ...). This is in case we ever decide to port Privoxy to C++. Example: int load_some_file(struct client_state *csp) Instead of: int loadsomefile(struct client_state *csp) int loadSomeFile(struct client_state *csp) Header file prototypes Explanation: Use a descriptive parameter name in the function prototype in header files. Use the same parameter name in the header file that you use in the c file. Example: (.h) extern int load_aclfile(struct client_state *csp); (.c) int load_aclfile(struct client_state *csp) Instead of: (.h) extern int load_aclfile(struct client_state *); or (.h) extern int load_aclfile(); (.c) int load_aclfile(struct client_state *csp) Enumerations, and #defines Explanation: Use all capital letters, with underscores between words. Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.) Example: (enumeration) : enum Boolean {FALSE, TRUE}; (#define) : #define DEFAULT_SIZE 100; Note: We have a standard naming scheme for #defines that toggle a feature in the preprocessor: FEATURE_>, where > is a short (preferably 1 or 2 word) description. Example: #define FEATURE_FORCE 1 #ifdef FEATURE_FORCE #define FORCE_PREFIX blah #endif /* def FEATURE_FORCE */ Constants Explanation: Spell common words out entirely (do not remove vowels). Use only widely-known domain acronyms and abbreviations. Capitalize all letters of an acronym. Use underscore (_) to separate adjacent acronyms and abbreviations. Never terminate a name with an underscore. Example: #define USE_IMAGE_LIST 1 Instead of: #define USE_IMG_LST 1 or #define _USE_IMAGE_LIST 1 or #define USE_IMAGE_LIST_ 1 or #define use_image_list 1 or #define UseImageList 1 Using Space Put braces on a line by themselves. Explanation: The brace needs to be on a line all by itself, not at the end of the statement. Curly braces should line up with the construct that they're associated with. This practice makes it easier to identify the opening and closing braces for a block. Example: if (this == that) { ... } Instead of: if (this == that) { ... } or if (this == that) { ... } Note: In the special case that the if-statement is inside a loop, and it is trivial, i.e. it tests for a condition that is obvious from the purpose of the block, one-liners as above may optically preserve the loop structure and make it easier to read. Status: developer-discretion. Example exception: while (more lines are read) { /* Please document what is/is not a comment line here */ if (it's a comment) continue; do_something(line); } ALL control statements should have a block Explanation: Using braces to make a block will make your code more readable and less prone to error. All control statements should have a block defined. Example: if (this == that) { do_something(); do_something_else(); } Instead of: if (this == that) do_something(); do_something_else(); or if (this == that) do_something(); Note: The first example in "Instead of" will execute in a manner other than that which the developer desired (per indentation). Using code braces would have prevented this "feature". The "explanation" and "exception" from the point above also applies. Do not belabor/blow-up boolean expressions Example: structure->flag = (condition); Instead of: if (condition) { structure->flag = 1; } else { structure->flag = 0; } Note: The former is readable and concise. The later is wordy and inefficient. Please assume that any developer new to the project has at least a "good" knowledge of C/C++. (Hope I do not offend by that last comment ... 8-) Use white space freely because it is free Explanation: Make it readable. The notable exception to using white space freely is listed in the next guideline. Example: int first_value = 0; int some_value = 0; int another_value = 0; int this_variable = 0; Don't use white space around structure operators Explanation: - structure pointer operator ( "->" ) - member operator ( "." ) - functions and parentheses It is a general coding practice to put pointers, references, and function parentheses next to names. With spaces, the connection between the object and variable/function name is not as clear. Example: a_struct->a_member; a_struct.a_member; function_name(); Instead of: a_struct -> a_member; a_struct . a_member; function_name (); Make the last brace of a function stand out Example: int function1( ... ) { ...code... return(ret_code); } /* -END- function1 */ int function2( ... ) { } /* -END- function2 */ Instead of: int function1( ... ) { ...code... return(ret_code); } int function2( ... ) { } Note: Use 1 blank line before the closing brace and 2 lines afterward. This makes the end of function standout to the most casual viewer. Although function comments help separate functions, this is still a good coding practice. In fact, I follow these rules when using blocks in "for", "while", "do" loops, and long if {} statements too. After all whitespace is free! Status: developer-discretion on the number of blank lines. Enforced is the end of function comments. Use 3 character indentions Explanation: If some use 8 character TABs and some use 3 character TABs, the code can look *very* ragged. So use 3 character indentions only. If you like to use TABs, pass your code through a filter such as "expand -t3" before checking in your code. Example: static const char * const url_code_map[256] = { NULL, ... }; int function1( ... ) { if (1) { return ALWAYS_TRUE; } else { return HOW_DID_YOU_GET_HERE; } return NEVER_GETS_HERE; } Initializing Initialize all variables Explanation: Do not assume that the variables declared will not be used until after they have been assigned a value somewhere else in the code. Remove the chance of accidentally using an unassigned variable. Example: short a_short = 0; float a_float = 0; struct *ptr = NULL; Note: It is much easier to debug a SIGSEGV if the message says you are trying to access memory address 00000000 and not 129FA012; or array_ptr[20] causes a SIGSEV vs. array_ptr[0]. Status: developer-discretion if and only if the variable is assigned a value "shortly after" declaration. Functions Name functions that return a boolean as a question. Explanation: Value should be phrased as a question that would logically be answered as a true or false statement Example: should_we_block_this(); contains_an_image(); is_web_page_blank(); Always specify a return type for a function. Explanation: The default return for a function is an int. To avoid ambiguity, create a return for a function when the return has a purpose, and create a void return type if the function does not need to return anything. Minimize function calls when iterating by using variables Explanation: It is easy to write the following code, and a clear argument can be made that the code is easy to understand: Example: for (size_t cnt = 0; cnt < block_list_length(); cnt++) { .... } Note: Unfortunately, this makes a function call for each and every iteration. This increases the overhead in the program, because the compiler has to look up the function each time, call it, and return a value. Depending on what occurs in the block_list_length() call, it might even be creating and destroying structures with each iteration, even though in each case it is comparing "cnt" to the same value, over and over. Remember too - even a call to block_list_length() is a function call, with the same overhead. Instead of using a function call during the iterations, assign the value to a variable, and evaluate using the variable. Example: size_t len = block_list_length(); for (size_t cnt = 0; cnt < len; cnt++) { .... } Exceptions: if the value of block_list_length() *may* change or could *potentially* change, then you must code the function call in the for/while loop. Pass and Return by Const Reference Explanation: This allows a developer to define a const pointer and call your function. If your function does not have the const keyword, we may not be able to use your function. Consider strcmp, if it were defined as: extern int strcmp(char *s1, char *s2); I could then not use it to compare argv's in main: int main(int argc, const char *argv[]) { strcmp(argv[0], "privoxy"); } Both these pointers are *const*! If the c runtime library maintainers do it, we should too. Pass and Return by Value Explanation: Most structures cannot fit onto a normal stack entry (i.e. they are not 4 bytes or less). Aka, a function declaration like: int load_aclfile(struct client_state csp) would not work. So, to be consistent, we should declare all prototypes with "pass by value": int load_aclfile(struct client_state *csp) Names of include files Explanation: Your include statements should contain the file name without a path. The path should be listed in the Makefile, using -I as processor directive to search the indicated paths. An exception to this would be for some proprietary software that utilizes a partial path to distinguish their header files from system or other header files. Example: #include <iostream.h> /* This is not a local include */ #include "config.h" /* This IS a local include */ Exception: /* This is not a local include, but requires a path element. */ #include <sys/fileName.h> Note: Please! do not add "-I." to the Makefile without a _very_ good reason. This duplicates the #include "file.h" behavior. Provide multiple inclusion protection Explanation: Prevents compiler and linker errors resulting from redefinition of items. Wrap each header file with the following syntax to prevent multiple inclusions of the file. Of course, replace PROJECT_H with your file name, with "." Changed to "_", and make it uppercase. Example: #ifndef PROJECT_H_INCLUDED #define PROJECT_H_INCLUDED ... #endif /* ndef PROJECT_H_INCLUDED */ Use `extern "C"` when appropriate Explanation: If our headers are included from C++, they must declare our functions as `extern "C"`. This has no cost in C, but increases the potential re-usability of our code. Example: #ifdef __cplusplus extern "C" { #endif /* def __cplusplus */ ... function definitions here ... #ifdef __cplusplus } #endif /* def __cplusplus */ Where Possible, Use Forward Struct Declaration Instead of Includes Explanation: Useful in headers that include pointers to other struct's. Modifications to excess header files may cause needless compiles. Example: /********************************************************************* * We're avoiding an include statement here! *********************************************************************/ struct file_list; extern file_list *xyz; Note: If you declare "file_list xyz;" (without the pointer), then including the proper header file is necessary. If you only want to prototype a pointer, however, the header file is unnecessary. Status: Use with discretion. General Coding Practices Turn on warnings Explanation Compiler warnings are meant to help you find bugs. You should turn on as many as possible. With GCC, the switch is "-Wall". Try and fix as many warnings as possible. Provide a default case for all switch statements Explanation: What you think is guaranteed is never really guaranteed. The value that you don't think you need to check is the one that someday will be passed. So, to protect yourself from the unknown, always have a default step in a switch statement. Example: switch (hash_string(cmd)) { case hash_actions_file: ... code ... break; case hash_confdir: ... code ... break; default: log_error( ... ); ... anomaly code goes here ... continue; / break; / exit( 1 ); / etc ... } /* end switch (hash_string(cmd)) */ Note: If you already have a default condition, you are obviously exempt from this point. Of note, most of the WIN32 code calls `DefWindowProc' after the switch statement. This API call *should* be included in a default statement. Another Note: This is not so much a readability issue as a robust programming issue. The "anomaly code goes here" may be no more than a print to the STDERR stream (as in load_config). Or it may really be an abort condition. Status: Programmer discretion is advised. Try to avoid falling through cases in a switch statement. Explanation: In general, you will want to have a 'break' statement within each 'case' of a switch statement. This allows for the code to be more readable and understandable, and furthermore can prevent unwanted surprises if someone else later gets creative and moves the code around. The language allows you to plan the fall through from one case statement to another simply by omitting the break statement within the case statement. This feature does have benefits, but should only be used in rare cases. In general, use a break statement for each case statement. If you choose to allow fall through, you should comment both the fact of the fall through and reason why you felt it was necessary. Don't mix size_t and other types Explanation: The type of size_t varies across platforms. Do not make assumptions about whether it is signed or unsigned, or about how long it is. Do not compare a size_t against another variable of a different type (or even against a constant) without casting one of the values. Declare each variable and struct on its own line. Explanation: It can be tempting to declare a series of variables all on one line. Don't. Example: long a = 0; long b = 0; long c = 0; Instead of: long a, b, c; Explanation: - there is more room for comments on the individual variables - easier to add new variables without messing up the original ones - when searching on a variable to find its type, there is less clutter to "visually" eliminate Exceptions: when you want to declare a bunch of loop variables or other trivial variables; feel free to declare them on one line. You should, although, provide a good comment on their functions. Status: developer-discretion. Use malloc/zalloc sparingly Explanation: Create a local struct (on the stack) if the variable will live and die within the context of one function call. Only "malloc" a struct (on the heap) if the variable's life will extend beyond the context of one function call. Example: If a function creates a struct and stores a pointer to it in a list, then it should definitely be allocated via `malloc'. The Programmer Who Uses 'malloc' is Responsible for Ensuring 'free' Explanation: If you have to "malloc" an instance, you are responsible for insuring that the instance is `free'd, even if the deallocation event falls within some other programmer's code. You are also responsible for ensuring that deletion is timely (i.e. not too soon, not too late). This is known as "low-coupling" and is a "good thing (tm)". You may need to offer a free/unload/destructor type function to accommodate this. Example: int load_re_filterfile(struct client_state *csp) { ... } static void unload_re_filterfile(void *f) { ... } Exceptions: The developer cannot be expected to provide `free'ing functions for C run-time library functions ... such as `strdup'. Status: developer-discretion. The "main" use of this standard is for allocating and freeing data structures (complex or nested). Add loaders to the `file_list' structure and in order Explanation: I have ordered all of the "blocker" file code to be in alpha order. It is easier to add/read new blockers when you expect a certain order. Note: It may appear that the alpha order is broken in places by POPUP tests coming before PCRS tests. But since POPUPs can also be referred to as KILLPOPUPs, it is clear that it should come first. "Uncertain" new code and/or changes to existing code, use XXX Explanation: If you have enough confidence in new code or confidence in your changes, but are not *quite* sure of the repercussions, add this: /* XXX: this code has a logic error on platform XYZ, * attempting to fix */ #ifdef PLATFORM ...changed code here... #endif or: /* XXX: I think the original author really meant this... */ ...changed code here... or: /* XXX: new code that *may* break something else... */ ...new code here... Note: If you make it clear that this may or may not be a "good thing (tm)", it will be easier to identify and include in the project (or conversely exclude from the project). Addendum: Template for files and function comment blocks: Example for file comments: const char FILENAME_rcs[] = "$I<!-- Break CVS Substitution -->d$"; /********************************************************************* * * File : $S<!-- Break CVS Substitution -->ource$ * * Purpose : (Fill me in with a good description!) * * Copyright : Written by and Copyright (C) 2001-2009 * the Privoxy team. http://www.privoxy.org/ * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , * USA * *********************************************************************/ #include "config.h" ...necessary include files for us to do our work... const char FILENAME_h_rcs[] = FILENAME_H_VERSION; Note: This declares the rcs variables that should be added to the "show-proxy-args" page. If this is a brand new creation by you, you are free to change the "Copyright" section to represent the rights you wish to maintain. Note: The formfeed character that is present right after the comment flower box is handy for (X|GNU)Emacs users to skip the verbiage and get to the heart of the code (via `forward-page' and `backward-page'). Please include it if you can. Example for file header comments: #ifndef _FILENAME_H #define _FILENAME_H #define FILENAME_H_VERSION "$I<!-- Break CVS Substitution -->d$" /********************************************************************* * * File : $S<!-- Break CVS Substitution -->ource$ * * Purpose : (Fill me in with a good description!) * * Copyright : Written by and Copyright (C) 2001-2009 * the Privoxy team. http://www.privoxy.org/ * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , * USA * *********************************************************************/ #include "project.h" #ifdef __cplusplus extern "C" { #endif ... function headers here ... /* Revision control strings from this header and associated .c file */ extern const char FILENAME_rcs[]; extern const char FILENAME_h_rcs[]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef _FILENAME_H */ /* Local Variables: tab-width: 3 end: */ Example for function comments: /********************************************************************* * * Function : FUNCTION_NAME * * Description : (Fill me in with a good description!) * * parameters : * 1 : param1 = pointer to an important thing * 2 : x = pointer to something else * * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ int FUNCTION_NAME(void *param1, const char *x) { ... return 0; } Note: If we all follow this practice, we should be able to parse our code to create a "self-documenting" web page. Testing Guidelines To be filled. Testplan for releases Explain release numbers. major, minor. developer releases. etc. Remove any existing rpm with rpm -e Remove any file that was left over. This includes (but is not limited to) /var/log/privoxy /etc/privoxy /usr/sbin/privoxy /etc/init.d/privoxy /usr/doc/privoxy* Install the rpm. Any error messages? start,stop,status Privoxy with the specific script (e.g. /etc/rc.d/init/privoxy stop). Reboot your machine. Does autostart work? Start browsing. Does Privoxy work? Logfile written? Remove the rpm. Any error messages? All files removed? Test reports Please submit test reports only with the test form at sourceforge. Three simple steps: Select category: the distribution you test on. Select group: the version of Privoxy that we are about to release. Fill the Summary and Detailed Description with something intelligent (keep it short and precise). Do not mail to the mailing list (we cannot keep track on issues there). Releasing a New Version When we release versions of Privoxy, our work leaves our cozy secret lab and has to work in the cold RealWorld[tm]. Once it is released, there is no way to call it back, so it is very important that great care is taken to ensure that everything runs fine, and not to introduce problems in the very last minute. So when releasing a new version, please adhere exactly to the procedure outlined in this chapter. The following programs are required to follow this process: ncftpput (ncftp), scp, ssh (ssh), gmake (GNU's version of make), autoconf, cvs. Version numbers First you need to determine which version number the release will have. Privoxy version numbers consist of three numbers, separated by dots, like in X.Y.Z (e.g. 3.0.0), where: X, the version major, is rarely ever changed. It is increased by one if turning a development branch into stable substantially changes the functionality, user interface or configuration syntax. Majors 1 and 2 were Junkbuster, and 3 will be the first stable Privoxy release. Y, the version minor, represents the branch within the major version. At any point in time, there are two branches being maintained: The stable branch, with an even minor, say, 2N, in which no functionality is being added and only bug-fixes are made, and 2N+1, the development branch, in which the further development of Privoxy takes place. This enables us to turn the code upside down and inside out, while at the same time providing and maintaining a stable version. The minor is reset to zero (and one) when the major is incremented. When a development branch has matured to the point where it can be turned into stable, the old stable branch 2N is given up (i.e. no longer maintained), the former development branch 2N+1 becomes the new stable branch 2N+2, and a new development branch 2N+3 is opened. Z, the point or sub version, represents a release of the software within a branch. It is therefore incremented immediately before each code freeze. In development branches, only the even point versions correspond to actual releases, while the odd ones denote the evolving state of the sources on CVS in between. It follows that Z is odd on CVS in development branches most of the time. There, it gets increased to an even number immediately before a code freeze, and is increased to an odd number again immediately thereafter. This ensures that builds from CVS snapshots are easily distinguished from released versions. The point version is reset to zero when the minor changes. Stable branches work a little differently, since there should be little to no development happening in such branches. Remember, only bugfixes, which presumably should have had some testing before being committed. Stable branches will then have their version reported as 0.0.0, during that period between releases when changes are being added. This is to denote that this code is not for release. Then as the release nears, the version is bumped according: e.g. 3.0.1 -> 0.0.0 -> 3.0.2. In summary, the main CVS trunk is the development branch where new features are being worked on for the next stable series. This should almost always be where the most activity takes place. There is always at least one stable branch from the trunk, e.g now it is 3.0, which is only used to release stable versions. Once the initial *.0 release of the stable branch has been done, then as a rule, only bugfixes that have had prior testing should be committed to the stable branch. Once there are enough bugfixes to justify a new release, the version of this branch is again incremented Example: 3.0.0 -> 3.0.1 -> 3.0.2, etc are all stable releases from within the stable branch. 3.1.x is currently the main trunk, and where work on 3.2.x is taking place. If any questions, please post to the devel list before committing to a stable branch! Developers should remember too that if they commit a bugfix to the stable branch, this will more than likely require a separate submission to the main trunk, since these are separate development trees within CVS. If you are working on both, then this would require at least two separate check outs (i.e main trunk, and the stable release branch, which is v_3_0_branch at the moment). Before the Release: Freeze The following must be done by one of the developers prior to each new release. Make sure that everybody who has worked on the code in the last couple of days has had a chance to yell no! in case they have pending changes/fixes in their pipelines. Announce the freeze so that nobody will interfere with last minute changes. Increment the version number (point from odd to even in development branches!) in configure.in. (RPM spec files will need to be incremented as well.) If default.action has changed since last release (i.e. software release or standalone actions file release), bump up its version info to A.B in this line: {+add-header{X-Actions-File-Version: A.B} -filter -no-popups} Then change the version info in doc/webserver/actions/index.php, line: '$required_actions_file_version = "A.B";' All documentation should be rebuild after the version bump. Finished docs should be then be committed to CVS (for those without the ability to build these). Some docs may require rather obscure processing tools. config, the man page (and the html version of the man page) fall in this category. REAMDE, the man page, AUTHORS, and config should all also be committed to CVS for other packagers. The formal docs should be uploaded to the webserver. See the Section "Updating the webserver" in this manual for details. The User Manual is also used for context sensitive help for the CGI editor. This is version sensitive, so that the user will get appropriate help for his/her release. So with each release a fresh version should be uploaded to the webserver (this is in addition to the main User Manual link from the main page since we need to keep manuals for various versions available). The CGI pages will link to something like http://privoxy.org/$(VERSION)/user-manual/. This will need to be updated for each new release. There is no Makefile target for this at this time!!! It needs to be done manually. All developers should look at the ChangeLog and make sure noteworthy changes are referenced. Commit all files that were changed in the above steps! Tag all files in CVS with the version number with cvs tag v_X_Y_Z. Don't use vX_Y_Z, ver_X_Y_Z, v_X.Y.Z (won't work) etc. If the release was in a development branch, increase the point version from even to odd (X.Y.(Z+1)) again in configure.in and commit your change. On the webserver, copy the user manual to a new top-level directory called X.Y.Z. This ensures that help links from the CGI pages, which have the version as a prefix, will go into the right version of the manual. If this is a development branch release, also symlink X.Y.(Z-1) to X.Y.Z and X.Y.(Z+1) to . (i.e. dot). Building and Releasing the Packages Now the individual packages can be built and released. Note that for GPL reasons the first package to be released is always the source tarball. For all types of packages, including the source tarball, you must make sure that you build from clean sources by exporting the right version from CVS into an empty directory (just press return when asked for a password): mkdir dist # delete or choose different name if it already exists cd dist cvs -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa login cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa export -r v_X_Y_Z current Do NOT change a single bit, including, but not limited to version information after export from CVS. This is to make sure that all release packages, and with them, all future bug reports, are based on exactly the same code. Every significant release of Privoxy has included at least one package that either had incorrect versions of files, missing files, or incidental leftovers from a previous build process that gave unknown numbers of users headaches to try to figure out what was wrong. PLEASE, make sure you are using pristene sources, and are following the prescribed process! Please find additional instructions for the source tarball and the individual platform dependent binary packages below. And details on the Sourceforge release process below that. Note on Privoxy Packaging Please keep these general guidelines in mind when putting together your package. These apply to all platforms! Privoxy requires write access to: all *.action files, all logfiles, and the trust file. You will need to determine the best way to do this for your platform. Please include up to date documentation. At a bare minimum: LICENSE (top-level directory) README (top-level directory) AUTHORS (top-level directory) man page (top-level directory, Unix-like platforms only) The User Manual (doc/webserver/user-manual/) FAQ (doc/webserver/faq/) Also suggested: Developer Manual (doc/webserver/developer-manual) and ChangeLog (top-level directory). FAQ and the manuals are HTML docs. There are also text versions in doc/text/ which could conceivably also be included. The documentation has been designed such that the manuals are linked to each other from parallel directories, and should be packaged that way. privoxy-index.html can also be included and can serve as a focal point for docs and other links of interest (and possibly renamed to index.html). This should be one level up from the manuals. There is a link also on this page to an HTMLized version of the man page. To avoid 404 for this, it is in CVS as doc/webserver/man-page/privoxy-man-page.html, and should be included along with the manuals. There is also a css stylesheets that can be included for better presentation: p_doc.css. This should be in the same directory with privoxy-index.html, (i.e. one level up from the manual directories). user.action and user.filter are designed for local preferences. Make sure these do not get overwritten! config should not be overwritten either. This has especially important configuration data in it. trust should be left in tact as well. Other configuration files (default.action and default.filter) should be installed as the new defaults, but all previously installed configuration files should be preserved as backups. This is just good manners :-) These files are likely to change between releases and contain important new features and bug fixes. Please check platform specific notes in this doc, if you haven't done Privoxy packaging before for other platform specific issues. Conversely, please add any notes that you know are important for your platform (or contact one of the doc maintainers to do this if you can't). Packagers should do a clean install of their package after building it. So any previous installs should be removed first to ensure the integrity of the newly built package. Then run the package for a while to make sure there are no obvious problems, before uploading. Source Tarball First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then do: make tarball-dist To upload the package to Sourceforge, simply issue make tarball-upload Go to the displayed URL and release the file publicly on Sourceforge. For the change log field, use the relevant section of the ChangeLog file. SuSE, Conectiva or Red Hat RPM In following text, replace dist with either rh for Red Hat or suse for SuSE. First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). As the only exception to not changing anything after export from CVS, now examine the file privoxy-dist.spec and make sure that the version information and the RPM release number are correct. The RPM release numbers for each version start at one. Hence it must be reset to one if this is the first RPM for dist which is built from version X.Y.Z. Check the file list if unsure. Else, it must be set to the highest already available RPM release number for that version plus one. Then run: cd current autoheader && autoconf && ./configure Then do make dist-dist To upload the package to Sourceforge, simply issue make dist-upload rpm_packagerev where rpm_packagerev is the RPM release number as determined above. Go to the displayed URL and release the file publicly on Sourceforge. Use the release notes and change log from the source tarball package. OS/2 First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then get the OS/2 Setup module: cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co os2setup You will need a mix of development tools. The main compilation takes place with IBM Visual Age C++. Some ancillary work takes place with GNU tools, available from various sources like hobbes.nmsu.edu. Specificially, you will need autoheader, autoconf and sh tools. The packaging takes place with WarpIN, available from various sources, including its home page: xworkplace. Change directory to the os2setup directory. Edit the os2build.cmd file to set the final executable filename. For example, installExeName='privoxyos2_setup_X.Y.Z.exe' Next, edit the IJB.wis file so the release number matches in the PACKAGEID section: PACKAGEID="Privoxy Team\Privoxy\Privoxy Package\X\Y\Z" You're now ready to build. Run: os2build You will find the WarpIN-installable executable in the ./files directory. Upload this anonymously to uploads.sourceforge.net/incoming, create a release for it, and you're done. Use the release notes and Change Log from the source tarball package. Solaris Login to Sourceforge's compilefarm via ssh: ssh cf.sourceforge.net Choose the right operating system (not the Debian one). When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then run gmake solaris-dist which creates a gzip'ed tar archive. Sadly, you cannot use make solaris-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package. Windows You should ensure you have the latest version of Cygwin (from http://www.cygwin.com/). Run the following commands from within a Cygwin bash shell. First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then get the Windows setup module: cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co winsetup Then you can build the package. This is fully automated, and is controlled by winsetup/GNUmakefile. All you need to do is: cd winsetup make Now you can manually rename privoxy_setup.exe to privoxy_setup_X_Y_Z.exe, and upload it to SourceForge. When releasing the package on SourceForge, use the release notes and Change Log from the source tarball package. Debian First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then add a log entry to debian/changelog, if it is not already there, for example by running: debchange -v &p-version;-&p-status;-1 "New upstream version" Then, run: dpkg-buildpackage -rfakeroot -us -uc -b This will create ../privoxy_&p-version;-&p-status;-1_i386.deb which can be uploaded. To upload the package to Sourceforge, simply issue make debian-upload Mac OS X First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). There are three modules available in the CVS repository for use on Mac OS X, though technically only two of them generate a release (the other can be used to install from source). OSXPackageBuilder module The OSXPackageBuilder module generates OS X installer packages supporting all Macs running OS X 10.4 and above. Obtain it from CVS as follows into a folder parallel to the exported privoxy source: cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co OSXPackageBuilder The module contains complete instructions on its usage in the file OS X Package Builder HOWTO.txt. Once the package(s) have been generated, you can then upload them directly to the Files section of the Sourceforge project in the Macintosh (OS X) folder. Each new version release of Privoxy should have a new subfolder created in which to store its files. Please ensure that the folder contains a readme file that makes it clear which package is for whichversion of OS X. osxsetup module (DEPRECATED) This module is deprecated since the installer it generates places all Privoxy files in one folder in a non-standard location, and supports only Intel Macs running OS X 10.6 or higher. Check out the module from CVS as follows into a folder parallel to the exported privoxy source: cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co osxsetup Then run: cd osxsetup build This will run autoheader, autoconf and configure as well as make. Finally, it will copy over the necessary files to the ./osxsetup/files directory for further processing by PackageMaker. Bring up PackageMaker with the PrivoxyPackage.pmsp definition file, modify the package name to match the release, and hit the "Create package" button. If you specify ./Privoxy.pkg as the output package name, you can then create the distributable zip file with the command: zip -r privoxyosx_setup_x.y.z.zip Privoxy.pkg You can then upload this file directly to the Files section of the Sourceforge project in the Macintosh (OS X) folder. Each new version release of Privoxy should have a new subfolder created in which to store its files. Please ensure that the folder contains a readme file that makes it clear which version(s) of OS X the package supports. macsetup module The macsetup module is ideal if you wish to build and install Privoxy from source on a single machine. Check out the module from CVS as follows into a folder parallel to the exported privoxy source: cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co macsetup The module contains complete instructions on its usage in its README file. The end result will be the exported version of Privoxy installed on the build machine. FreeBSD Login to Sourceforge's compile-farm via ssh: ssh cf.sourceforge.net Choose the right operating system. When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then run: gmake freebsd-dist which creates a gzip'ed tar archive. Sadly, you cannot use make freebsd-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package. HP-UX 11 First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then do FIXME. Amiga OS First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then do FIXME. AIX Login to Sourceforge's compilefarm via ssh: ssh cf.sourceforge.net Choose the right operating system. When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run: cd current autoheader && autoconf && ./configure Then run: make aix-dist which creates a gzip'ed tar archive. Sadly, you cannot use make aix-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package. Uploading and Releasing Your Package After the package is ready, it is time to upload it to SourceForge, and go through the release steps. The upload is done via FTP: Upload to: ftp://upload.sourceforge.net/incoming user: anonymous password: ijbswa-developers@lists.sourceforge.net Or use the make targets as described above. Once this done go to https://sourceforge.net/project/admin/editpackages.php?group_id=11118, making sure you are logged in. Find your target platform in the second column, and click Add Release. You will then need to create a new release for your package, using the format of $VERSION ($CODE_STATUS), e.g. &p-version; (beta). Now just follow the prompts. Be sure to add any appropriate Release notes. You should see your freshly uploaded packages in Step 2. Add Files To This Release. Check the appropriate box(es). Remember at each step to hit the Refresh/Submit buttons! You should now see your file(s) listed in Step 3. Fill out the forms with the appropriate information for your platform, being sure to hit Update for each file. If anyone is monitoring your platform, check the email box at the very bottom to notify them of the new package. This should do it! If you have made errors, or need to make changes, you can go through essentially the same steps, but select Edit Release, instead of Add Release. After the Release When all (or: most of the) packages have been uploaded and made available, send an email to the announce mailing list, Subject: "Version X.Y.Z available for download". Be sure to include the download location, the release notes and the Changelog. Also, post an updated News item on the project page Sourceforge, and update the Home page and docs linked from the Home page (see below). Other news sites and release oriented sites, such as Freshmeat, should also be notified. Update the Webserver The webserver should be updated at least with each stable release. When updating, please follow these steps to make sure that no broken links, inconsistent contents or permission problems will occur (as it has many times in the past!): If you have changed anything in the stable-branch documentation source SGML files, do: make dok That will generate doc/webserver/user-manual, doc/webserver/developer-manual, doc/webserver/faq, doc/webserver/index.html automatically. If you changed the manual page sources, generate doc/webserver/man-page/privoxy-man-page.html by running make man. (This is a separate target due to dependencies on some obscure perl scripts [now in CVS, but not well tested]. See comments in GNUmakefile.) If you want to add new files to the webserver, create them locally in the doc/webserver/* directory (or create new directories under doc/webserver). Next, commit any changes from the above steps to CVS. All set? If these are docs in the stable branch, then do: make webserver This will do the upload to the webserver (www.privoxy.org) and ensure all files and directories there are group writable. Please do NOT use any other means of transferring files to the webserver to avoid permission problems. Also, please do not upload docs from development branches or versions. The publicly posted docs should be in sync with the last official release.
    privoxy-3.0.21-stable/./doc/source/user-manual.sgml000640 001751 001751 00001055010 12114407434 021146 0ustar00fkfk000000 000000 Privoxy"> ]>
    Privoxy &p-version; User Manual Copyright &my-copy; 2001-2013 by Privoxy Developers $Id: user-manual.sgml,v 2.174 2013/03/02 14:39:24 fabiankeil Exp $ This is here to keep vim syntax file from breaking :/ If I knew enough to fix it, I would. PLEASE DO NOT REMOVE! HB: hal@foobox.net ]]> The Privoxy User Manual gives users information on how to install, configure and use Privoxy. &p-intro; You can find the latest version of the Privoxy User Manual at http://www.privoxy.org/user-manual/. Please see the Contact section on how to contact the developers. Introduction This documentation is included with the current &p-status; version of Privoxy, &p-version;. Since this is a &p-status; version, not all new features are well tested. This documentation may be slightly out of sync as a result (especially with CVS sources). And there may be bugs, though hopefully not many! ]]> Features In addition to the core features of ad blocking and cookie management, Privoxy provides many supplemental features, that give the end-user more control, more privacy and more freedom: &newfeatures; Installation Privoxy is available both in convenient pre-compiled packages for a wide range of operating systems, and as raw source code. For most users, we recommend using the packages, which can be downloaded from our Privoxy Project Page. Note: On some platforms, the installer may remove previously installed versions, if found. (See below for your platform). In any case be sure to backup your old configuration if it is valuable to you. See the note to upgraders section below. Binary Packages How to install the binary packages depends on your operating system: Debian and Ubuntu DEBs can be installed with apt-get install privoxy, and will use /etc/privoxy for the location of configuration files. Windows Just double-click the installer, which will guide you through the installation process. You will find the configuration files in the same directory as you installed Privoxy in. Version 3.0.5 beta introduced full Windows service functionality. On Windows only, the Privoxy program has two new command line arguments to install and uninstall Privoxy as a service. Arguments: --install[:service_name] --uninstall[:service_name] After invoking Privoxy with --install, you will need to bring up the Windows service console to assign the user you want Privoxy to run under, and whether or not you want it to run whenever the system starts. You can start the Windows services console with the following command: services.msc. If you do not take the manual step of modifying Privoxy's service settings, it will not start. Note too that you will need to give Privoxy a user account that actually exists, or it will not be permitted to write to its log and configuration files. OS/2 First, make sure that no previous installations of Junkbuster and / or Privoxy are left on your system. Check that no Junkbuster or Privoxy objects are in your startup folder. Then, just double-click the WarpIN self-installing archive, which will guide you through the installation process. A shadow of the Privoxy executable will be placed in your startup folder so it will start automatically whenever OS/2 starts. The directory you choose to install Privoxy into will contain all of the configuration files. Mac OS X Installation instructions for the OS X platform depend upon whether you downloaded a ready-built installation package (.pkg or .mpkg) or have downloaded the source code. Installation from ready-built package The downloaded file will either be a .pkg (for OS X 10.5 upwards) or a bzipped .mpkg file (for OS X 10.4). The former can be double-clicked as is and the installation will start; double-clicking the latter will unzip the .mpkg file which can then be double-clicked to commence the installation. The privoxy service will automatically start after a successful installation (and thereafter every time your computer starts up) however you will need to configure your web browser(s) to use it. To do so, configure them to use a proxy for HTTP and HTTPS at the address 127.0.0.1:8118. To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the file /Library/LaunchDaemons/org.ijbswa.privoxy.plist (on OS X 10.5 and higher) or the folder named /Library/StartupItems/Privoxy (on OS X 10.4 'Tiger'). To manually start or stop the privoxy service, use the scripts startPrivoxy.sh and stopPrivoxy.sh supplied in /Applications/Privoxy. They must be run from an administrator account, using sudo. To uninstall, run /Applications/Privoxy/uninstall.command as sudo from an administrator account. Installation from source To build and install the Privoxy source code on OS X you will need to obtain the macsetup module from the Privoxy Sourceforge CVS repository (refer to Sourceforge help for details of how to set up a CVS client to have read-only access to the repository). This module contains scripts that leverage the usual open-source tools (available as part of Apple's free of charge Xcode distribution or via the usual open-source software package managers for OS X (MacPorts, Homebrew, Fink etc.) to build and then install the privoxy binary and associated files. The macsetup module's README file contains complete instructions for its use. The privoxy service will automatically start after a successful installation (and thereafter every time your computer starts up) however you will need to configure your web browser(s) to use it. To do so, configure them to use a proxy for HTTP and HTTPS at the address 127.0.0.1:8118. To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the file /Library/LaunchDaemons/org.ijbswa.privoxy.plist (on OS X 10.5 and higher) or the folder named /Library/StartupItems/Privoxy (on OS X 10.4 'Tiger'). To manually start or stop the privoxy service, use the Privoxy Utility for Mac OS X (also part of the macsetup module). This application can start and stop the privoxy service and display its log and configuration files. To uninstall, run the macsetup module's uninstall.sh as sudo from an administrator account. FreeBSD Privoxy is part of FreeBSD's Ports Collection, you can build and install it with cd /usr/ports/www/privoxy; make install clean. Building from Source The most convenient way to obtain the Privoxy sources is to download the source tarball from our project download page. If you like to live on the bleeding edge and are not afraid of using possibly unstable development versions, you can check out the up-to-the-minute version directly from the CVS repository. &buildsource; Keeping your Installation Up-to-Date If you wish to receive an email notification whenever we release updates of Privoxy or the actions file, subscribe to our announce mailing list, ijbswa-announce@lists.sourceforge.net. In order not to lose your personal changes and adjustments when updating to the latest default.action file we strongly recommend that you use user.action and user.filter for your local customizations of Privoxy. See the Chapter on actions files for details. What's New in this Release &changelog; Note to Upgraders A quick list of things to be aware of before upgrading from earlier versions of Privoxy: The recommended way to upgrade &my-app; is to backup your old configuration files, install the new ones, verify that &my-app; is working correctly and finally merge back your changes using diff and maybe patch. There are a number of new features in each &my-app; release and most of them have to be explicitly enabled in the configuration files. Old configuration files obviously don't do that and due to syntax changes using old configuration files with a new &my-app; isn't always possible anyway. Note that some installers remove earlier versions completely, including configuration files, therefore you should really save any important configuration files! On the other hand, other installers don't overwrite existing configuration files, thinking you will want to do that yourself. In the default configuration only fatal errors are logged now. You can change that in the debug section of the configuration file. You may also want to enable more verbose logging until you verified that the new &my-app; version is working as expected. Three other config file settings are now off by default: enable-remote-toggle, enable-remote-http-toggle, and enable-edit-actions. If you use or want these, you will need to explicitly enable them, and be aware of the security issues involved. Quickstart to Using Privoxy Install Privoxy. See the Installation Section below for platform specific information. Advanced users and those who want to offer Privoxy service to more than just their local machine should check the main config file, especially the security-relevant options. These are off by default. Start Privoxy, if the installation program has not done this already (may vary according to platform). See the section Starting Privoxy. Set your browser to use Privoxy as HTTP and HTTPS (SSL) proxy by setting the proxy configuration for address of 127.0.0.1 and port 8118. DO NOT activate proxying for FTP or any protocols besides HTTP and HTTPS (SSL) unless you intend to prevent your browser from using these protocols. Flush your browser's disk and memory caches, to remove any cached ad images. If using Privoxy to manage cookies, you should remove any currently stored cookies too. A default installation should provide a reasonable starting point for most. There will undoubtedly be occasions where you will want to adjust the configuration, but that can be dealt with as the need arises. Little to no initial configuration is required in most cases, you may want to enable the web-based action editor though. Be sure to read the warnings first. See the Configuration section for more configuration options, and how to customize your installation. You might also want to look at the next section for a quick introduction to how Privoxy blocks ads and banners. If you experience ads that slip through, innocent images that are blocked, or otherwise feel the need to fine-tune Privoxy's behavior, take a look at the actions files. As a quick start, you might find the richly commented examples helpful. You can also view and edit the actions files through the web-based user interface. The Appendix Troubleshooting: Anatomy of an Action has hints on how to understand and debug actions that misbehave. Please see the section Contacting the Developers on how to report bugs, problems with websites or to get help. Now enjoy surfing with enhanced control, comfort and privacy! Quickstart to Ad Blocking Ad blocking is but one of Privoxy's array of features. Many of these features are for the technically minded advanced user. But, ad and banner blocking is surely common ground for everybody. This section will provide a quick summary of ad blocking so you can get up to speed quickly without having to read the more extensive information provided below, though this is highly recommended. First a bit of a warning ... blocking ads is much like blocking SPAM: the more aggressive you are about it, the more likely you are to block things that were not intended. And the more likely that some things may not work as intended. So there is a trade off here. If you want extreme ad free browsing, be prepared to deal with more problem sites, and to spend more time adjusting the configuration to solve these unintended consequences. In short, there is not an easy way to eliminate all ads. Either take the easy way and settle for most ads blocked with the default configuration, or jump in and tweak it for your personal surfing habits and preferences. Secondly, a brief explanation of Privoxy's actions. Actions in this context, are the directives we use to tell Privoxy to perform some task relating to HTTP transactions (i.e. web browsing). We tell Privoxy to take some action. Each action has a unique name and function. While there are many potential actions in Privoxy's arsenal, only a few are used for ad blocking. Actions, and action configuration files, are explained in depth below. Actions are specified in Privoxy's configuration, followed by one or more URLs to which the action should apply. URLs can actually be URL type patterns that use wildcards so they can apply potentially to a range of similar URLs. The actions, together with the URL patterns are called a section. When you connect to a website, the full URL will either match one or more of the sections as defined in Privoxy's configuration, or not. If so, then Privoxy will perform the respective actions. If not, then nothing special happens. Furthermore, web pages may contain embedded, secondary URLs that your web browser will use to load additional components of the page, as it parses the original page's HTML content. An ad image for instance, is just an URL embedded in the page somewhere. The image itself may be on the same server, or a server somewhere else on the Internet. Complex web pages will have many such embedded URLs. &my-app; can deal with each URL individually, so, for instance, the main page text is not touched, but images from such-and-such server are blocked. The most important actions for basic ad blocking are: block, handle-as-image, handle-as-empty-document,and set-image-blocker: block - this is perhaps the single most used action, and is particularly important for ad blocking. This action stops any contact between your browser and any URL patterns that match this action's configuration. It can be used for blocking ads, but also anything that is determined to be unwanted. By itself, it simply stops any communication with the remote server and sends Privoxy's own built-in BLOCKED page instead to let you now what has happened (with some exceptions, see below). handle-as-image - tells Privoxy to treat this URL as an image. Privoxy's default configuration already does this for all common image types (e.g. GIF), but there are many situations where this is not so easy to determine. So we'll force it in these cases. This is particularly important for ad blocking, since only if we know that it's an image of some kind, can we replace it with an image of our choosing, instead of the Privoxy BLOCKED page (which would only result in a broken image icon). There are some limitations to this though. For instance, you can't just brute-force an image substitution for an entire HTML page in most situations. handle-as-empty-document - sends an empty document instead of Privoxy's normal BLOCKED HTML page. This is useful for file types that are neither HTML nor images, such as blocking JavaScript files. set-image-blocker - tells Privoxy what to display in place of an ad image that has hit a block rule. For this to come into play, the URL must match a block action somewhere in the configuration, and, it must also match an handle-as-image action. The configuration options on what to display instead of the ad are:    pattern - a checkerboard pattern, so that an ad replacement is obvious. This is the default.    blank - A very small empty GIF image is displayed. This is the so-called invisible configuration option.    http://<URL> - A redirect to any image anywhere of the user's choosing (advanced usage). Advanced users will eventually want to explore &my-app; filters as well. Filters are very different from blocks. A block blocks a site, page, or unwanted contented. Filters are a way of filtering or modifying what is actually on the page. An example filter usage: a text replacement of no-no for nasty-word. That is a very simple example. This process can be used for ad blocking, but it is more in the realm of advanced usage and has some pitfalls to be wary off. The quickest way to adjust any of these settings is with your browser through the special Privoxy editor at http://config.privoxy.org/show-status (shortcut: http://p.p/show-status). This is an internal page, and does not require Internet access. Note that as of Privoxy 3.0.7 beta the action editor is disabled by default. Check the enable-edit-actions section in the configuration file to learn why and in which cases it's safe to enable again. If you decided to enable the action editor, select the appropriate actions file, and click Edit. It is best to put personal or local preferences in user.action since this is not meant to be overwritten during upgrades, and will over-ride the settings in other files. Here you can insert new actions, and URLs for ad blocking or other purposes, and make other adjustments to the configuration. Privoxy will detect these changes automatically. A quick and simple step by step example: Right click on the ad image to be blocked, then select Copy Link Location from the pop-up menu. Set your browser to http://config.privoxy.org/show-status Find user.action in the top section, and click on Edit:
    Actions Files in Use [ Screenshot of Actions Files in Use ]
    You should have a section with only block listed under Actions:. If not, click a Insert new section below button, and in the new section that just appeared, click the Edit button right under the word Actions:. This will bring up a list of all actions. Find block near the top, and click in the Enabled column, then Submit just below the list. Now, in the block actions section, click the Add button, and paste the URL the browser got from Copy Link Location. Remove the http:// at the beginning of the URL. Then, click Submit (or OK if in a pop-up window). Now go back to the original page, and press SHIFT-Reload (or flush all browser caches). The image should be gone now.
    This is a very crude and simple example. There might be good reasons to use a wildcard pattern match to include potentially similar images from the same site. For a more extensive explanation of patterns, and the entire actions concept, see the Actions section. For advanced users who want to hand edit their config files, you might want to now go to the Actions Files Tutorial. The ideas explained therein also apply to the web-based editor. There are also various filters that can be used for ad blocking (filters are a special subset of actions). These fall into the advanced usage category, and are explained in depth in later sections.
    Starting Privoxy Before launching Privoxy for the first time, you will want to configure your browser(s) to use Privoxy as a HTTP and HTTPS (SSL) proxy. The default is 127.0.0.1 (or localhost) for the proxy address, and port 8118 (earlier versions used port 8000). This is the one configuration step that must be done ! Please note that Privoxy can only proxy HTTP and HTTPS traffic. It will not work with FTP or other protocols.
    Proxy Configuration Showing Mozilla/Netscape HTTP and HTTPS (SSL) Settings [ Screenshot of Mozilla Proxy Configuration ]
    With Firefox, this is typically set under: Tools -> Options -> Advanced -> Network ->Connection -> Settings Or optionally on some platforms: Edit -> Preferences -> General -> Connection Settings -> Manual Proxy Configuration With Netscape (and Mozilla), this can be set under: Edit -> Preferences -> Advanced -> Proxies -> HTTP Proxy For Internet Explorer v.5-7: Tools -> Internet Options -> Connections -> LAN Settings Then, check Use Proxy and fill in the appropriate info (Address: 127.0.0.1, Port: 8118). Include HTTPS (SSL), if you want HTTPS proxy support too (sometimes labeled Secure). Make sure any checkboxes like Use the same proxy server for all protocols is UNCHECKED. You want only HTTP and HTTPS (SSL)!
    Proxy Configuration Showing Internet Explorer HTTP and HTTPS (Secure) Settings [ Screenshot of IE Proxy Configuration ]
    After doing this, flush your browser's disk and memory caches to force a re-reading of all pages and to get rid of any ads that may be cached. Remove any cookies, if you want Privoxy to manage that. You are now ready to start enjoying the benefits of using Privoxy! Privoxy itself is typically started by specifying the main configuration file to be used on the command line. If no configuration file is specified on the command line, Privoxy will look for a file named config in the current directory. Except on Win32 where it will try config.txt. Debian We use a script. Note that Debian typically starts &my-app; upon booting per default. It will use the file /etc/privoxy/config as its main configuration file. # /etc/init.d/privoxy start Windows Click on the &my-app; Icon to start Privoxy. If no configuration file is specified on the command line, Privoxy will look for a file named config.txt. Note that Windows will automatically start &my-app; when the system starts if you chose that option when installing. Privoxy can run with full Windows service functionality. On Windows only, the &my-app; program has two new command line arguments to install and uninstall &my-app; as a service. See the Windows Installation instructions for details. Solaris, NetBSD, FreeBSD, HP-UX and others Example Unix startup command: # /usr/sbin/privoxy /etc/privoxy/config OS/2 During installation, Privoxy is configured to start automatically when the system restarts. You can start it manually by double-clicking on the Privoxy icon in the Privoxy folder. Mac OS X After downloading the privoxy software, unzip the downloaded file by double-clicking on the zip file icon. Then, double-click on the installer package icon and follow the installation process. The privoxy service will automatically start after a successful installation. In addition, the privoxy service will automatically start every time your computer starts up. To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the folder named /Library/StartupItems/Privoxy. A simple application named Privoxy Utility has been created which enables administrators to easily start and stop the privoxy service. In addition, the Privoxy Utility presents a simple way for administrators to edit the various privoxy config files. A method to uninstall the software is also available. An administrator username and password must be supplied in order for the Privoxy Utility to perform any of the tasks. Command Line Options Privoxy may be invoked with the following command-line options: --config-test Exit after loading the configuration files before binding to the listen address. The exit code signals whether or not the configuration files have been successfully loaded. If the exit code is 1, at least one of the configuration files is invalid, if it is 0, all the configuration files have been successfully loaded (but may still contain errors that can currently only be detected at run time). This option doesn't affect the log setting, combination with --no-daemon is recommended if a configured log file shouldn't be used. --version Print version info and exit. Unix only. --help Print short usage info and exit. Unix only. --no-daemon Don't become a daemon, i.e. don't fork and become process group leader, and don't detach from controlling tty. Unix only. --pidfile FILE On startup, write the process ID to FILE. Delete the FILE on exit. Failure to create or delete the FILE is non-fatal. If no FILE option is given, no PID file will be used. Unix only. --user USER[.GROUP] After (optionally) writing the PID file, assume the user ID of USER, and if included the GID of GROUP. Exit if the privileges are not sufficient to do so. Unix only. --chroot Before changing to the user ID given in the --user option, chroot to that user's home directory, i.e. make the kernel pretend to the &my-app; process that the directory tree starts there. If set up carefully, this can limit the impact of possible vulnerabilities in &my-app; to the files contained in that hierarchy. Unix only. --pre-chroot-nslookup hostname Specifies a hostname to look up before doing a chroot. On some systems, initializing the resolver library involves reading config files from /etc and/or loading additional shared libraries from /lib. On these systems, doing a hostname lookup before the chroot reduces the number of files that must be copied into the chroot tree. For fastest startup speed, a good value is a hostname that is not in /etc/hosts but that your local name server (listed in /etc/resolv.conf) can resolve without recursion (that is, without having to ask any other name servers). The hostname need not exist, but if it doesn't, an error message (which can be ignored) will be output. configfile If no configfile is included on the command line, Privoxy will look for a file named config in the current directory (except on Win32 where it will look for config.txt instead). Specify full path to avoid confusion. If no config file is found, Privoxy will fail to start. On MS Windows only there are two additional command-line options to allow Privoxy to install and run as a service. See the Window Installation section for details.
    Privoxy Configuration All Privoxy configuration is stored in text files. These files can be edited with a text editor. Many important aspects of Privoxy can also be controlled easily with a web browser. Controlling Privoxy with Your Web Browser Privoxy's user interface can be reached through the special URL http://config.privoxy.org/ (shortcut: http://p.p/), which is a built-in page and works without Internet access. You will see the following section:     Privoxy Menu         ▪  View & change the current configuration         ▪  View the source code version numbers         ▪  View the request headers.         ▪  Look up which actions apply to a URL and why         ▪  Toggle Privoxy on or off         ▪  Documentation This should be self-explanatory. Note the first item leads to an editor for the actions files, which is where the ad, banner, cookie, and URL blocking magic is configured as well as other advanced features of Privoxy. This is an easy way to adjust various aspects of Privoxy configuration. The actions file, and other configuration files, are explained in detail below. Toggle Privoxy On or Off is handy for sites that might have problems with your current actions and filters. You can in fact use it as a test to see whether it is Privoxy causing the problem or not. Privoxy continues to run as a proxy in this case, but all manipulation is disabled, i.e. Privoxy acts like a normal forwarding proxy. There is even a toggle Bookmarklet offered, so that you can toggle Privoxy with one click from your browser. Note that several of the features described above are disabled by default in Privoxy 3.0.7 beta and later. Check the configuration file to learn why and in which cases it's safe to enable them again. Configuration Files Overview For Unix, *BSD and Linux, all configuration files are located in /etc/privoxy/ by default. For MS Windows, OS/2, and AmigaOS these are all in the same directory as the Privoxy executable. The installed defaults provide a reasonable starting point, though some settings may be aggressive by some standards. For the time being, the principle configuration files are: The main configuration file is named config on Linux, Unix, BSD, OS/2, and AmigaOS and config.txt on Windows. This is a required file. match-all.action is used to define which actions relating to banner-blocking, images, pop-ups, content modification, cookie handling etc should be applied by default. It should be the first actions file loaded. default.action defines many exceptions (both positive and negative) from the default set of actions that's configured in match-all.action. It should be the second actions file loaded and shouldn't be edited by the user. Multiple actions files may be defined in config. These are processed in the order they are defined. Local customizations and locally preferred exceptions to the default policies as defined in match-all.action (which you will most probably want to define sooner or later) are best applied in user.action, where you can preserve them across upgrades. The file isn't installed by all installers, but you can easily create it yourself with a text editor. There is also a web based editor that can be accessed from http://config.privoxy.org/show-status (Shortcut: http://p.p/show-status) for the various actions files. Filter files (the filter file) can be used to re-write the raw page content, including viewable text as well as embedded HTML and JavaScript, and whatever else lurks on any given web page. The filtering jobs are only pre-defined here; whether to apply them or not is up to the actions files. default.filter includes various filters made available for use by the developers. Some are much more intrusive than others, and all should be used with caution. You may define additional filter files in config as you can with actions files. We suggest user.filter for any locally defined filters or customizations. The syntax of the configuration and filter files may change between different Privoxy versions, unfortunately some enhancements cost backwards compatibility. All files use the # character to denote a comment (the rest of the line will be ignored) and understand line continuation through placing a backslash ("\") as the very last character in a line. If the # is preceded by a backslash, it looses its special function. Placing a # in front of an otherwise valid configuration line to prevent it from being interpreted is called "commenting out" that line. Blank lines are ignored. The actions files and filter files can use Perl style regular expressions for maximum flexibility. After making any changes, there is no need to restart Privoxy in order for the changes to take effect. Privoxy detects such changes automatically. Note, however, that it may take one or two additional requests for the change to take effect. When changing the listening address of Privoxy, these wake up requests must obviously be sent to the old listening address. While under development, the configuration content is subject to change. The below documentation may not be accurate by the time you read this. Also, what constitutes a default setting, may change, so please check all your configuration files on important issues. ]]> &config; Actions Files The actions files are used to define what actions Privoxy takes for which URLs, and thus determines how ad images, cookies and various other aspects of HTTP content and transactions are handled, and on which sites (or even parts thereof). There are a number of such actions, with a wide range of functionality. Each action does something a little different. These actions give us a veritable arsenal of tools with which to exert our control, preferences and independence. Actions can be combined so that their effects are aggregated when applied against a given set of URLs. There are three action files included with Privoxy with differing purposes: match-all.action - is used to define which actions relating to banner-blocking, images, pop-ups, content modification, cookie handling etc should be applied by default. It should be the first actions file loaded default.action - defines many exceptions (both positive and negative) from the default set of actions that's configured in match-all.action. It is a set of rules that should work reasonably well as-is for most users. This file is only supposed to be edited by the developers. It should be the second actions file loaded. user.action - is intended to be for local site preferences and exceptions. As an example, if your ISP or your bank has specific requirements, and need special handling, this kind of thing should go here. This file will not be upgraded. Edit Set to Cautious Set to Medium Set to Advanced These have increasing levels of aggressiveness and have no influence on your browsing unless you select them explicitly in the editor. A default installation should be pre-set to Cautious. New users should try this for a while before adjusting the settings to more aggressive levels. The more aggressive the settings, then the more likelihood there is of problems such as sites not working as they should. The Edit button allows you to turn each action on/off individually for fine-tuning. The Cautious button changes the actions list to low/safe settings which will activate ad blocking and a minimal set of &my-app;'s features, and subsequently there will be less of a chance for accidental problems. The Medium button sets the list to a medium level of other features and a low level set of privacy features. The Advanced button sets the list to a high level of ad blocking and medium level of privacy. See the chart below. The latter three buttons over-ride any changes via with the Edit button. More fine-tuning can be done in the lower sections of this internal page. While the actions file editor allows to enable these settings in all actions files, they are only supposed to be enabled in the first one to make sure you don't unintentionally overrule earlier rules. The default profiles, and their associated actions, as pre-defined in default.action are: Default Configurations Feature Cautious Medium Advanced Ad-blocking Aggressiveness medium high high Ad-filtering by size no yes yes Ad-filtering by link no no yes Pop-up killing blocks only blocks only blocks only Privacy Features low medium medium/high Cookie handling none session-only kill Referer forging no yes yes GIF de-animation no yes yes Fast redirects no no yes HTML taming no no yes JavaScript taming no no yes Web-bug killing no yes yes Image tag reordering no yes yes
    The list of actions files to be used are defined in the main configuration file, and are processed in the order they are defined (e.g. default.action is typically processed before user.action). The content of these can all be viewed and edited from http://config.privoxy.org/show-status. The over-riding principle when applying actions, is that the last action that matches a given URL wins. The broadest, most general rules go first (defined in default.action), followed by any exceptions (typically also in default.action), which are then followed lastly by any local preferences (typically in user.action). Generally, user.action has the last word. An actions file typically has multiple sections. If you want to use aliases in an actions file, you have to place the (optional) alias section at the top of that file. Then comes the default set of rules which will apply universally to all sites and pages (be very careful with using such a universal set in user.action or any other actions file after default.action, because it will override the result from consulting any previous file). And then below that, exceptions to the defined universal policies. You can regard user.action as an appendix to default.action, with the advantage that it is a separate file, which makes preserving your personal settings across Privoxy upgrades easier. Actions can be used to block anything you want, including ads, banners, or just some obnoxious URL whose content you would rather not see. Cookies can be accepted or rejected, or accepted only during the current browser session (i.e. not written to disk), content can be modified, some JavaScripts tamed, user-tracking fooled, and much more. See below for a complete list of actions. Finding the Right Mix Note that some actions, like cookie suppression or script disabling, may render some sites unusable that rely on these techniques to work properly. Finding the right mix of actions is not always easy and certainly a matter of personal taste. And, things can always change, requiring refinements in the configuration. In general, it can be said that the more aggressive your default settings (in the top section of the actions file) are, the more exceptions for trusted sites you will have to make later. If, for example, you want to crunch all cookies per default, you'll have to make exceptions from that rule for sites that you regularly use and that require cookies for actually useful purposes, like maybe your bank, favorite shop, or newspaper. We have tried to provide you with reasonable rules to start from in the distribution actions files. But there is no general rule of thumb on these things. There just are too many variables, and sites are constantly changing. Sooner or later you will want to change the rules (and read this chapter again :). How to Edit The easiest way to edit the actions files is with a browser by using our browser-based editor, which can be reached from http://config.privoxy.org/show-status. Note: the config file option enable-edit-actions must be enabled for this to work. The editor allows both fine-grained control over every single feature on a per-URL basis, and easy choosing from wholesale sets of defaults like Cautious, Medium or Advanced. Warning: the Advanced setting is more aggressive, and will be more likely to cause problems for some sites. Experienced users only! If you prefer plain text editing to GUIs, you can of course also directly edit the the actions files with your favorite text editor. Look at default.action which is richly commented with many good examples. How Actions are Applied to Requests Actions files are divided into sections. There are special sections, like the alias sections which will be discussed later. For now let's concentrate on regular sections: They have a heading line (often split up to multiple lines for readability) which consist of a list of actions, separated by whitespace and enclosed in curly braces. Below that, there is a list of URL and tag patterns, each on a separate line. To determine which actions apply to a request, the URL of the request is compared to all URL patterns in each action file. Every time it matches, the list of applicable actions for the request is incrementally updated, using the heading of the section in which the pattern is located. The same is done again for tags and tag patterns later on. If multiple applying sections set the same action differently, the last match wins. If not, the effects are aggregated. E.g. a URL might match a regular section with a heading line of { +handle-as-image }, then later another one with just { +block }, resulting in both actions to apply. And there may well be cases where you will want to combine actions together. Such a section then might look like: { +handle-as-image +block{Banner ads.} } # Block these as if they were images. Send no block page. banners.example.com media.example.com/.*banners .example.com/images/ads/ You can trace this process for URL patterns and any given URL by visiting http://config.privoxy.org/show-url-info. Examples and more detail on this is provided in the Appendix, Troubleshooting: Anatomy of an Action section. Patterns As mentioned, Privoxy uses patterns to determine what actions might apply to which sites and pages your browser attempts to access. These patterns use wild card type pattern matching to achieve a high degree of flexibility. This allows one expression to be expanded and potentially match against many similar patterns. Generally, an URL pattern has the form <domain><port>/<path>, where the <domain>, the <port> and the <path> are optional. (This is why the special / pattern matches all URLs). Note that the protocol portion of the URL pattern (e.g. http://) should not be included in the pattern. This is assumed already! The pattern matching syntax is different for the domain and path parts of the URL. The domain part uses a simple globbing type matching technique, while the path part uses more flexible Regular Expressions (POSIX 1003.2). The port part of a pattern is a decimal port number preceded by a colon (:). If the domain part contains a numerical IPv6 address, it has to be put into angle brackets (<, >). www.example.com/ is a domain-only pattern and will match any request to www.example.com, regardless of which document on that server is requested. So ALL pages in this domain would be covered by the scope of this action. Note that a simple example.com is different and would NOT match. www.example.com means exactly the same. For domain-only patterns, the trailing / may be omitted. www.example.com/index.html matches all the documents on www.example.com whose name starts with /index.html. www.example.com/index.html$ matches only the single document /index.html on www.example.com. /index.html$ matches the document /index.html, regardless of the domain, i.e. on any web server anywhere. / Matches any URL because there's no requirement for either the domain or the path to match anything. :8000/ Matches any URL pointing to TCP port 8000. <2001:db8::1>/ Matches any URL with the host address 2001:db8::1. (Note that the real URL uses plain brackets, not angle brackets.) index.html matches nothing, since it would be interpreted as a domain name and there is no top-level domain called .html. So its a mistake. The Domain Pattern The matching of the domain part offers some flexible options: if the domain starts or ends with a dot, it becomes unanchored at that end. For example: .example.com matches any domain with first-level domain com and second-level domain example. For example www.example.com, example.com and foo.bar.baz.example.com. Note that it wouldn't match if the second-level domain was another-example. www. matches any domain that STARTS with www. (It also matches the domain www but most of the time that doesn't matter.) .example. matches any domain that CONTAINS .example.. And, by the way, also included would be any files or documents that exist within that domain since no path limitations are specified. (Correctly speaking: It matches any FQDN that contains example as a domain.) This might be www.example.com, news.example.de, or www.example.net/cgi/testing.pl for instance. All these cases are matched. Additionally, there are wild-cards that you can use in the domain names themselves. These work similarly to shell globbing type wild-cards: * represents zero or more arbitrary characters (this is equivalent to the Regular Expression based syntax of .*), ? represents any single character (this is equivalent to the regular expression syntax of a simple .), and you can define character classes in square brackets which is similar to the same regular expression technique. All of this can be freely mixed: ad*.example.com matches adserver.example.com, ads.example.com, etc but not sfads.example.com *ad*.example.com matches all of the above, and then some. .?pix.com matches www.ipix.com, pictures.epix.com, a.b.c.d.e.upix.com etc. www[1-9a-ez].example.c* matches www1.example.com, www4.example.cc, wwwd.example.cy, wwwz.example.com etc., but not wwww.example.com. While flexible, this is not the sophistication of full regular expression based syntax. The Path Pattern Privoxy uses modern POSIX 1003.2 Regular Expressions for matching the path portion (after the slash), and is thus more flexible. There is an Appendix with a brief quick-start into regular expressions, you also might want to have a look at your operating system's documentation on regular expressions (try man re_format). Note that the path pattern is automatically left-anchored at the /, i.e. it matches as if it would start with a ^ (regular expression speak for the beginning of a line). Please also note that matching in the path is CASE INSENSITIVE by default, but you can switch to case sensitive at any point in the pattern by using the (?-i) switch: www.example.com/(?-i)PaTtErN.* will match only documents whose path starts with PaTtErN in exactly this capitalization. .example.com/.* Is equivalent to just .example.com, since any documents within that domain are matched with or without the .* regular expression. This is redundant .example.com/.*/index.html$ Will match any page in the domain of example.com that is named index.html, and that is part of some path. For example, it matches www.example.com/testing/index.html but NOT www.example.com/index.html because the regular expression called for at least two /'s, thus the path requirement. It also would match www.example.com/testing/index_html, because of the special meta-character .. .example.com/(.*/)?index\.html$ This regular expression is conditional so it will match any page named index.html regardless of path which in this case can have one or more /'s. And this one must contain exactly .html (but does not have to end with that!). .example.com/(.*/)(ads|banners?|junk) This regular expression will match any path of example.com that contains any of the words ads, banner, banners (because of the ?) or junk. The path does not have to end in these words, just contain them. .example.com/(.*/)(ads|banners?|junk)/.*\.(jpe?g|gif|png)$ This is very much the same as above, except now it must end in either .jpg, .jpeg, .gif or .png. So this one is limited to common image formats. There are many, many good examples to be found in default.action, and more tutorials below in Appendix on regular expressions. The Tag Pattern Tag patterns are used to change the applying actions based on the request's tags. Tags can be created with either the client-header-tagger or the server-header-tagger action. Tag patterns have to start with TAG:, so &my-app; can tell them apart from URL patterns. Everything after the colon including white space, is interpreted as a regular expression with path pattern syntax, except that tag patterns aren't left-anchored automatically (&my-app; doesn't silently add a ^, you have to do it yourself if you need it). To match all requests that are tagged with foo your pattern line should be TAG:^foo$, TAG:foo would work as well, but it would also match requests whose tags contain foo somewhere. TAG: foo wouldn't work as it requires white space. Sections can contain URL and tag patterns at the same time, but tag patterns are checked after the URL patterns and thus always overrule them, even if they are located before the URL patterns. Once a new tag is added, Privoxy checks right away if it's matched by one of the tag patterns and updates the action settings accordingly. As a result tags can be used to activate other tagger actions, as long as these other taggers look for headers that haven't already be parsed. For example you could tag client requests which use the POST method, then use this tag to activate another tagger that adds a tag if cookies are sent, and then use a block action based on the cookie tag. This allows the outcome of one action, to be input into a subsequent action. However if you'd reverse the position of the described taggers, and activated the method tagger based on the cookie tagger, no method tags would be created. The method tagger would look for the request line, but at the time the cookie tag is created, the request line has already been parsed. While this is a limitation you should be aware of, this kind of indirection is seldom needed anyway and even the example doesn't make too much sense. Actions All actions are disabled by default, until they are explicitly enabled somewhere in an actions file. Actions are turned on if preceded with a +, and turned off if preceded with a -. So a +action means do that action, e.g. +block means please block URLs that match the following patterns, and -block means don't block URLs that match the following patterns, even if +block previously applied. Again, actions are invoked by placing them on a line, enclosed in curly braces and separated by whitespace, like in {+some-action -some-other-action{some-parameter}}, followed by a list of URL patterns, one per line, to which they apply. Together, the actions line and the following pattern lines make up a section of the actions file. Actions fall into three categories: Boolean, i.e the action can only be enabled or disabled. Syntax: +name # enable action name -name # disable action name Example: +handle-as-image Parameterized, where some value is required in order to enable this type of action. Syntax: +name{param} # enable action and set parameter to param, # overwriting parameter from previous match if necessary -name # disable action. The parameter can be omitted Note that if the URL matches multiple positive forms of a parameterized action, the last match wins, i.e. the params from earlier matches are simply ignored. Example: +hide-user-agent{Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.4) Gecko/20070602 Firefox/2.0.0.4} Multi-value. These look exactly like parameterized actions, but they behave differently: If the action applies multiple times to the same URL, but with different parameters, all the parameters from all matches are remembered. This is used for actions that can be executed for the same request repeatedly, like adding multiple headers, or filtering through multiple filters. Syntax: +name{param} # enable action and add param to the list of parameters -name{param} # remove the parameter param from the list of parameters # If it was the last one left, disable the action. -name # disable this action completely and remove all parameters from the list Examples: +add-header{X-Fun-Header: Some text} and +filter{html-annoyances} If nothing is specified in any actions file, no actions are taken. So in this case Privoxy would just be a normal, non-blocking, non-filtering proxy. You must specifically enable the privacy and blocking features you need (although the provided default actions files will give a good starting point). Later defined action sections always over-ride earlier ones of the same type. So exceptions to any rules you make, should come in the latter part of the file (or in a file that is processed later when using multiple actions files such as user.action). For multi-valued actions, the actions are applied in the order they are specified. Actions files are processed in the order they are defined in config (the default installation has three actions files). It also quite possible for any given URL to match more than one pattern (because of wildcards and regular expressions), and thus to trigger more than one set of actions! Last match wins. The list of valid Privoxy actions are: add-header Typical use: Confuse log analysis, custom applications Effect: Sends a user defined HTTP header to the web server. Type: Multi-value. Parameter: Any string value is possible. Validity of the defined HTTP headers is not checked. It is recommended that you use the X- prefix for custom headers. Notes: This action may be specified multiple times, in order to define multiple headers. This is rarely needed for the typical user. If you don't know what HTTP headers are, you definitely don't need to worry about this one. Headers added by this action are not modified by other actions. Example usage: +add-header{X-User-Tracking: sucks} block Typical use: Block ads or other unwanted content Effect: Requests for URLs to which this action applies are blocked, i.e. the requests are trapped by &my-app; and the requested URL is never retrieved, but is answered locally with a substitute page or image, as determined by the handle-as-image, set-image-blocker, and handle-as-empty-document actions. Type: Parameterized. Parameter: A block reason that should be given to the user. Notes: Privoxy sends a special BLOCKED page for requests to blocked pages. This page contains the block reason given as parameter, a link to find out why the block action applies, and a click-through to the blocked content (the latter only if the force feature is available and enabled). A very important exception occurs if both block and handle-as-image, apply to the same request: it will then be replaced by an image. If set-image-blocker (see below) also applies, the type of image will be determined by its parameter, if not, the standard checkerboard pattern is sent. It is important to understand this process, in order to understand how Privoxy deals with ads and other unwanted content. Blocking is a core feature, and one upon which various other features depend. The filter action can perform a very similar task, by blocking banner images and other content through rewriting the relevant URLs in the document's HTML source, so they don't get requested in the first place. Note that this is a totally different technique, and it's easy to confuse the two. Example usage (section): {+block{No nasty stuff for you.}} # Block and replace with "blocked" page .nasty-stuff.example.com {+block{Doubleclick banners.} +handle-as-image} # Block and replace with image .ad.doubleclick.net .ads.r.us/banners/ {+block{Layered ads.} +handle-as-empty-document} # Block and then ignore adserver.example.net/.*\.js$ change-x-forwarded-for Typical use: Improve privacy by not forwarding the source of the request in the HTTP headers. Effect: Deletes the X-Forwarded-For: HTTP header from the client request, or adds a new one. Type: Parameterized. Parameter: block to delete the header. add to create the header (or append the client's IP address to an already existing one). Notes: It is safe and recommended to use block. Forwarding the source address of the request may make sense in some multi-user setups but is also a privacy risk. Example usage: +change-x-forwarded-for{block} client-header-filter Typical use: Rewrite or remove single client headers. Effect: All client headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions. Type: Parameterized. Parameter: The name of a client-header filter, as defined in one of the filter files. Notes: Client-header filters are applied to each header on its own, not to all at once. This makes it easier to diagnose problems, but on the downside you can't write filters that only change header x if header y's value is z. You can do that by using tags though. Client-header filters are executed after the other header actions have finished and use their output as input. If the request URI gets changed, &my-app; will detect that and use the new one. This can be used to rewrite the request destination behind the client's back, for example to specify a Tor exit relay for certain requests. Please refer to the filter file chapter to learn which client-header filters are available by default, and how to create your own. Example usage (section): # Hide Tor exit notation in Host and Referer Headers {+client-header-filter{hide-tor-exit-notation}} / client-header-tagger Typical use: Block requests based on their headers. Effect: Client headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions, the result is used as tag. Type: Parameterized. Parameter: The name of a client-header tagger, as defined in one of the filter files. Notes: Client-header taggers are applied to each header on its own, and as the header isn't modified, each tagger sees the original. Client-header taggers are the first actions that are executed and their tags can be used to control every other action. Example usage (section): # Tag every request with the User-Agent header {+client-header-tagger{user-agent}} / # Tagging itself doesn't change the action # settings, sections with TAG patterns do: # # If it's a download agent, use a different forwarding proxy, # show the real User-Agent and make sure resume works. {+forward-override{forward-socks5 10.0.0.2:2222 .} \ -hide-if-modified-since \ -overwrite-last-modified \ -hide-user-agent \ -filter \ -deanimate-gifs \ } TAG:^User-Agent: NetBSD-ftp/ TAG:^User-Agent: Novell ZYPP Installer TAG:^User-Agent: RPM APT-HTTP/ TAG:^User-Agent: fetch libfetch/ TAG:^User-Agent: Ubuntu APT-HTTP/ TAG:^User-Agent: MPlayer/ # Tag all requests with the Range header set {+client-header-tagger{range-requests}} / # Disable filtering for the tagged requests. # # With filtering enabled Privoxy would remove the Range headers # to be able to filter the whole response. The downside is that # it prevents clients from resuming downloads or skipping over # parts of multimedia files. {-filter -deanimate-gifs} TAG:^RANGE-REQUEST$ content-type-overwrite Typical use: Stop useless download menus from popping up, or change the browser's rendering mode Effect: Replaces the Content-Type: HTTP server header. Type: Parameterized. Parameter: Any string. Notes: The Content-Type: HTTP server header is used by the browser to decide what to do with the document. The value of this header can cause the browser to open a download menu instead of displaying the document by itself, even if the document's format is supported by the browser. The declared content type can also affect which rendering mode the browser chooses. If XHTML is delivered as text/html, many browsers treat it as yet another broken HTML document. If it is send as application/xml, browsers with XHTML support will only display it, if the syntax is correct. If you see a web site that proudly uses XHTML buttons, but sets Content-Type: text/html, you can use &my-app; to overwrite it with application/xml and validate the web master's claim inside your XHTML-supporting browser. If the syntax is incorrect, the browser will complain loudly. You can also go the opposite direction: if your browser prints error messages instead of rendering a document falsely declared as XHTML, you can overwrite the content type with text/html and have it rendered as broken HTML document. By default content-type-overwrite only replaces Content-Type: headers that look like some kind of text. If you want to overwrite it unconditionally, you have to combine it with force-text-mode. This limitation exists for a reason, think twice before circumventing it. Most of the time it's easier to replace this action with a custom server-header filter. It allows you to activate it for every document of a certain site and it will still only replace the content types you aimed at. Of course you can apply content-type-overwrite to a whole site and then make URL based exceptions, but it's a lot more work to get the same precision. Example usage (sections): # Check if www.example.net/ really uses valid XHTML { +content-type-overwrite{application/xml} } www.example.net/ # but leave the content type unmodified if the URL looks like a style sheet {-content-type-overwrite} www.example.net/.*\.css$ www.example.net/.*style crunch-client-header Typical use: Remove a client header Privoxy has no dedicated action for. Effect: Deletes every header sent by the client that contains the string the user supplied as parameter. Type: Parameterized. Parameter: Any string. Notes: This action allows you to block client headers for which no dedicated Privoxy action exists. Privoxy will remove every client header that contains the string you supplied as parameter. Regular expressions are not supported and you can't use this action to block different headers in the same request, unless they contain the same string. crunch-client-header is only meant for quick tests. If you have to block several different headers, or only want to modify parts of them, you should use a client-header filter. Don't block any header without understanding the consequences. Example usage (section): # Block the non-existent "Privacy-Violation:" client header { +crunch-client-header{Privacy-Violation:} } / crunch-if-none-match Typical use: Prevent yet another way to track the user's steps between sessions. Effect: Deletes the If-None-Match: HTTP client header. Type: Boolean. Parameter: N/A Notes: Removing the If-None-Match: HTTP client header is useful for filter testing, where you want to force a real reload instead of getting status code 304 which would cause the browser to use a cached copy of the page. It is also useful to make sure the header isn't used as a cookie replacement (unlikely but possible). Blocking the If-None-Match: header shouldn't cause any caching problems, as long as the If-Modified-Since: header isn't blocked or missing as well. It is recommended to use this action together with hide-if-modified-since and overwrite-last-modified. Example usage (section): # Let the browser revalidate cached documents but don't # allow the server to use the revalidation headers for user tracking. {+hide-if-modified-since{-60} \ +overwrite-last-modified{randomize} \ +crunch-if-none-match} / crunch-incoming-cookies Typical use: Prevent the web server from setting HTTP cookies on your system Effect: Deletes any Set-Cookie: HTTP headers from server replies. Type: Boolean. Parameter: N/A Notes: This action is only concerned with incoming HTTP cookies. For outgoing HTTP cookies, use crunch-outgoing-cookies. Use both to disable HTTP cookies completely. It makes no sense at all to use this action in conjunction with the session-cookies-only action, since it would prevent the session cookies from being set. See also filter-content-cookies. Example usage: +crunch-incoming-cookies crunch-server-header Typical use: Remove a server header Privoxy has no dedicated action for. Effect: Deletes every header sent by the server that contains the string the user supplied as parameter. Type: Parameterized. Parameter: Any string. Notes: This action allows you to block server headers for which no dedicated Privoxy action exists. Privoxy will remove every server header that contains the string you supplied as parameter. Regular expressions are not supported and you can't use this action to block different headers in the same request, unless they contain the same string. crunch-server-header is only meant for quick tests. If you have to block several different headers, or only want to modify parts of them, you should use a custom server-header filter. Don't block any header without understanding the consequences. Example usage (section): # Crunch server headers that try to prevent caching { +crunch-server-header{no-cache} } / crunch-outgoing-cookies Typical use: Prevent the web server from reading any HTTP cookies from your system Effect: Deletes any Cookie: HTTP headers from client requests. Type: Boolean. Parameter: N/A Notes: This action is only concerned with outgoing HTTP cookies. For incoming HTTP cookies, use crunch-incoming-cookies. Use both to disable HTTP cookies completely. It makes no sense at all to use this action in conjunction with the session-cookies-only action, since it would prevent the session cookies from being read. Example usage: +crunch-outgoing-cookies deanimate-gifs Typical use: Stop those annoying, distracting animated GIF images. Effect: De-animate GIF animations, i.e. reduce them to their first or last image. Type: Parameterized. Parameter: last or first Notes: This will also shrink the images considerably (in bytes, not pixels!). If the option first is given, the first frame of the animation is used as the replacement. If last is given, the last frame of the animation is used instead, which probably makes more sense for most banner animations, but also has the risk of not showing the entire last frame (if it is only a delta to an earlier frame). You can safely use this action with patterns that will also match non-GIF objects, because no attempt will be made at anything that doesn't look like a GIF. Example usage: +deanimate-gifs{last} downgrade-http-version Typical use: Work around (very rare) problems with HTTP/1.1 Effect: Downgrades HTTP/1.1 client requests and server replies to HTTP/1.0. Type: Boolean. Parameter: N/A Notes: This is a left-over from the time when Privoxy didn't support important HTTP/1.1 features well. It is left here for the unlikely case that you experience HTTP/1.1-related problems with some server out there. Note that enabling this action is only a workaround. It should not be enabled for sites that work without it. While it shouldn't break any pages, it has an (usually negative) performance impact. If you come across a site where enabling this action helps, please report it, so the cause of the problem can be analyzed. If the problem turns out to be caused by a bug in Privoxy it should be fixed so the following release works without the work around. Example usage (section): {+downgrade-http-version} problem-host.example.com fast-redirects Typical use: Fool some click-tracking scripts and speed up indirect links. Effect: Detects redirection URLs and redirects the browser without contacting the redirection server first. Type: Parameterized. Parameter: simple-check to just search for the string http:// to detect redirection URLs. check-decoded-url to decode URLs (if necessary) before searching for redirection URLs. Notes: Many sites, like yahoo.com, don't just link to other sites. Instead, they will link to some script on their own servers, giving the destination as a parameter, which will then redirect you to the final target. URLs resulting from this scheme typically look like: http://www.example.org/click-tracker.cgi?target=http%3a//www.example.net/. Sometimes, there are even multiple consecutive redirects encoded in the URL. These redirections via scripts make your web browsing more traceable, since the server from which you follow such a link can see where you go to. Apart from that, valuable bandwidth and time is wasted, while your browser asks the server for one redirect after the other. Plus, it feeds the advertisers. This feature is currently not very smart and is scheduled for improvement. If it is enabled by default, you will have to create some exceptions to this action. It can lead to failures in several ways: Not every URLs with other URLs as parameters is evil. Some sites offer a real service that requires this information to work. For example a validation service needs to know, which document to validate. fast-redirects assumes that every URL parameter that looks like another URL is a redirection target, and will always redirect to the last one. Most of the time the assumption is correct, but if it isn't, the user gets redirected anyway. Another failure occurs if the URL contains other parameters after the URL parameter. The URL: http://www.example.org/?redirect=http%3a//www.example.net/&foo=bar. contains the redirection URL http://www.example.net/, followed by another parameter. fast-redirects doesn't know that and will cause a redirect to http://www.example.net/&foo=bar. Depending on the target server configuration, the parameter will be silently ignored or lead to a page not found error. You can prevent this problem by first using the redirect action to remove the last part of the URL, but it requires a little effort. To detect a redirection URL, fast-redirects only looks for the string http://, either in plain text (invalid but often used) or encoded as http%3a//. Some sites use their own URL encoding scheme, encrypt the address of the target server or replace it with a database id. In theses cases fast-redirects is fooled and the request reaches the redirection server where it probably gets logged. Example usage: { +fast-redirects{simple-check} } one.example.com { +fast-redirects{check-decoded-url} } another.example.com/testing filter Typical use: Get rid of HTML and JavaScript annoyances, banner advertisements (by size), do fun text replacements, add personalized effects, etc. Effect: All instances of text-based type, most notably HTML and JavaScript, to which this action applies, can be filtered on-the-fly through the specified regular expression based substitutions. (Note: as of version 3.0.3 plain text documents are exempted from filtering, because web servers often use the text/plain MIME type for all files whose type they don't know.) Type: Parameterized. Parameter: The name of a content filter, as defined in the filter file. Filters can be defined in one or more files as defined by the filterfile option in the config file. default.filter is the collection of filters supplied by the developers. Locally defined filters should go in their own file, such as user.filter. When used in its negative form, and without parameters, all filtering is completely disabled. Notes: For your convenience, there are a number of pre-defined filters available in the distribution filter file that you can use. See the examples below for a list. Filtering requires buffering the page content, which may appear to slow down page rendering since nothing is displayed until all content has passed the filters. (The total time until the page is completely rendered doesn't change much, but it may be perceived as slower since the page is not incrementally displayed.) This effect will be more noticeable on slower connections. Rolling your own filters requires a knowledge of Regular Expressions and HTML. This is very powerful feature, and potentially very intrusive. Filters should be used with caution, and where an equivalent action is not available. The amount of data that can be filtered is limited to the buffer-limit option in the main config file. The default is 4096 KB (4 Megs). Once this limit is exceeded, the buffered data, and all pending data, is passed through unfiltered. Inappropriate MIME types, such as zipped files, are not filtered at all. (Again, only text-based types except plain text). Encrypted SSL data (from HTTPS servers) cannot be filtered either, since this would violate the integrity of the secure transaction. In some situations it might be necessary to protect certain text, like source code, from filtering by defining appropriate -filter exceptions. Compressed content can't be filtered either, but if &my-app; is compiled with zlib support and a supported compression algorithm is used (gzip or deflate), &my-app; can first decompress the content and then filter it. If you use a &my-app; version without zlib support, but want filtering to work on as much documents as possible, even those that would normally be sent compressed, you must use the prevent-compression action in conjunction with filter. Content filtering can achieve some of the same effects as the block action, i.e. it can be used to block ads and banners. But the mechanism works quite differently. One effective use, is to block ad banners based on their size (see below), since many of these seem to be somewhat standardized. Feedback with suggestions for new or improved filters is particularly welcome! The below list has only the names and a one-line description of each predefined filter. There are more verbose explanations of what these filters do in the filter file chapter. Example usage (with filters from the distribution default.filter file). See the Predefined Filters section for more explanation on each: +filter{js-annoyances} # Get rid of particularly annoying JavaScript abuse. +filter{js-events} # Kill JavaScript event bindings and timers (Radically destructive! Only for extra nasty sites). +filter{html-annoyances} # Get rid of particularly annoying HTML abuse. +filter{content-cookies} # Kill cookies that come in the HTML or JS content. +filter{refresh-tags} # Kill automatic refresh tags if refresh time is larger than 9 seconds. +filter{unsolicited-popups} # Disable only unsolicited pop-up windows. +filter{all-popups} # Kill all popups in JavaScript and HTML. +filter{img-reorder} # Reorder attributes in <img> tags to make the banners-by-* filters more effective. +filter{banners-by-size} # Kill banners by size. +filter{banners-by-link} # Kill banners by their links to known clicktrackers. +filter{webbugs} # Squish WebBugs (1x1 invisible GIFs used for user tracking). +filter{tiny-textforms} # Extend those tiny textareas up to 40x80 and kill the hard wrap. +filter{jumping-windows} # Prevent windows from resizing and moving themselves. +filter{frameset-borders} # Give frames a border and make them resizable. +filter{iframes} # Removes all detected iframes. Should only be enabled for individual sites. +filter{demoronizer} # Fix MS's non-standard use of standard charsets. +filter{shockwave-flash} # Kill embedded Shockwave Flash objects. +filter{quicktime-kioskmode} # Make Quicktime movies saveable. +filter{fun} # Text replacements for subversive browsing fun! +filter{crude-parental} # Crude parental filtering. Note that this filter doesn't work reliably. +filter{ie-exploits} # Disable some known Internet Explorer bug exploits. +filter{site-specifics} # Cure for site-specific problems. Don't apply generally! +filter{no-ping} # Removes non-standard ping attributes in <a> and <area> tags. +filter{google} # CSS-based block for Google text ads. Also removes a width limitation and the toolbar advertisement. +filter{yahoo} # CSS-based block for Yahoo text ads. Also removes a width limitation. +filter{msn} # CSS-based block for MSN text ads. Also removes tracking URLs and a width limitation. +filter{blogspot} # Cleans up some Blogspot blogs. Read the fine print before using this. force-text-mode Typical use: Force Privoxy to treat a document as if it was in some kind of text format. Effect: Declares a document as text, even if the Content-Type: isn't detected as such. Type: Boolean. Parameter: N/A Notes: As explained above, Privoxy tries to only filter files that are in some kind of text format. The same restrictions apply to content-type-overwrite. force-text-mode declares a document as text, without looking at the Content-Type: first. Think twice before activating this action. Filtering binary data with regular expressions can cause file damage. Example usage: +force-text-mode forward-override Typical use: Change the forwarding settings based on User-Agent or request origin Effect: Overrules the forward directives in the configuration file. Type: Multi-value. Parameter: forward . to use a direct connection without any additional proxies. forward 127.0.0.1:8123 to use the HTTP proxy listening at 127.0.0.1 port 8123. forward-socks4a 127.0.0.1:9050 . to use the socks4a proxy listening at 127.0.0.1 port 9050. Replace forward-socks4a with forward-socks4 to use a socks4 connection (with local DNS resolution) instead, use forward-socks5 for socks5 connections (with remote DNS resolution). forward-socks4a 127.0.0.1:9050 proxy.example.org:8000 to use the socks4a proxy listening at 127.0.0.1 port 9050 to reach the HTTP proxy listening at proxy.example.org port 8000. Replace forward-socks4a with forward-socks4 to use a socks4 connection (with local DNS resolution) instead, use forward-socks5 for socks5 connections (with remote DNS resolution). Notes: This action takes parameters similar to the forward directives in the configuration file, but without the URL pattern. It can be used as replacement, but normally it's only used in cases where matching based on the request URL isn't sufficient. Please read the description for the forward directives before using this action. Forwarding to the wrong people will reduce your privacy and increase the chances of man-in-the-middle attacks. If the ports are missing or invalid, default values will be used. This might change in the future and you shouldn't rely on it. Otherwise incorrect syntax causes Privoxy to exit. Use the show-url-info CGI page to verify that your forward settings do what you thought the do. Example usage: # Always use direct connections for requests previously tagged as # User-Agent: fetch libfetch/2.0 and make sure # resuming downloads continues to work. # This way you can continue to use Tor for your normal browsing, # without overloading the Tor network with your FreeBSD ports updates # or downloads of bigger files like ISOs. # Note that HTTP headers are easy to fake and therefore their # values are as (un)trustworthy as your clients and users. {+forward-override{forward .} \ -hide-if-modified-since \ -overwrite-last-modified \ } TAG:^User-Agent: fetch libfetch/2\.0$ handle-as-empty-document Typical use: Mark URLs that should be replaced by empty documents if they get blocked Effect: This action alone doesn't do anything noticeable. It just marks URLs. If the block action also applies, the presence or absence of this mark decides whether an HTML BLOCKED page, or an empty document will be sent to the client as a substitute for the blocked content. The empty document isn't literally empty, but actually contains a single space. Type: Boolean. Parameter: N/A Notes: Some browsers complain about syntax errors if JavaScript documents are blocked with Privoxy's default HTML page; this option can be used to silence them. And of course this action can also be used to eliminate the &my-app; BLOCKED message in frames. The content type for the empty document can be specified with content-type-overwrite{}, but usually this isn't necessary. Example usage: # Block all documents on example.org that end with ".js", # but send an empty document instead of the usual HTML message. {+block{Blocked JavaScript} +handle-as-empty-document} example.org/.*\.js$ handle-as-image Typical use: Mark URLs as belonging to images (so they'll be replaced by images if they do get blocked, rather than HTML pages) Effect: This action alone doesn't do anything noticeable. It just marks URLs as images. If the block action also applies, the presence or absence of this mark decides whether an HTML blocked page, or a replacement image (as determined by the set-image-blocker action) will be sent to the client as a substitute for the blocked content. Type: Boolean. Parameter: N/A Notes: The below generic example section is actually part of default.action. It marks all URLs with well-known image file name extensions as images and should be left intact. Users will probably only want to use the handle-as-image action in conjunction with block, to block sources of banners, whose URLs don't reflect the file type, like in the second example section. Note that you cannot treat HTML pages as images in most cases. For instance, (in-line) ad frames require an HTML page to be sent, or they won't display properly. Forcing handle-as-image in this situation will not replace the ad frame with an image, but lead to error messages. Example usage (sections): # Generic image extensions: # {+handle-as-image} /.*\.(gif|jpg|jpeg|png|bmp|ico)$ # These don't look like images, but they're banners and should be # blocked as images: # {+block{Nasty banners.} +handle-as-image} nasty-banner-server.example.com/junk.cgi\?output=trash hide-accept-language Typical use: Pretend to use different language settings. Effect: Deletes or replaces the Accept-Language: HTTP header in client requests. Type: Parameterized. Parameter: Keyword: block, or any user defined value. Notes: Faking the browser's language settings can be useful to make a foreign User-Agent set with hide-user-agent more believable. However some sites with content in different languages check the Accept-Language: to decide which one to take by default. Sometimes it isn't possible to later switch to another language without changing the Accept-Language: header first. Therefore it's a good idea to either only change the Accept-Language: header to languages you understand, or to languages that aren't wide spread. Before setting the Accept-Language: header to a rare language, you should consider that it helps to make your requests unique and thus easier to trace. If you don't plan to change this header frequently, you should stick to a common language. Example usage (section): # Pretend to use Canadian language settings. {+hide-accept-language{en-ca} \ +hide-user-agent{Mozilla/5.0 (X11; U; OpenBSD i386; en-CA; rv:1.8.0.4) Gecko/20060628 Firefox/1.5.0.4} \ } / hide-content-disposition Typical use: Prevent download menus for content you prefer to view inside the browser. Effect: Deletes or replaces the Content-Disposition: HTTP header set by some servers. Type: Parameterized. Parameter: Keyword: block, or any user defined value. Notes: Some servers set the Content-Disposition: HTTP header for documents they assume you want to save locally before viewing them. The Content-Disposition: header contains the file name the browser is supposed to use by default. In most browsers that understand this header, it makes it impossible to just view the document, without downloading it first, even if it's just a simple text file or an image. Removing the Content-Disposition: header helps to prevent this annoyance, but some browsers additionally check the Content-Type: header, before they decide if they can display a document without saving it first. In these cases, you have to change this header as well, before the browser stops displaying download menus. It is also possible to change the server's file name suggestion to another one, but in most cases it isn't worth the time to set it up. This action will probably be removed in the future, use server-header filters instead. Example usage: # Disarm the download link in Sourceforge's patch tracker { -filter \ +content-type-overwrite{text/plain}\ +hide-content-disposition{block} } .sourceforge.net/tracker/download\.php hide-if-modified-since Typical use: Prevent yet another way to track the user's steps between sessions. Effect: Deletes the If-Modified-Since: HTTP client header or modifies its value. Type: Parameterized. Parameter: Keyword: block, or a user defined value that specifies a range of hours. Notes: Removing this header is useful for filter testing, where you want to force a real reload instead of getting status code 304, which would cause the browser to use a cached copy of the page. Instead of removing the header, hide-if-modified-since can also add or subtract a random amount of time to/from the header's value. You specify a range of minutes where the random factor should be chosen from and Privoxy does the rest. A negative value means subtracting, a positive value adding. Randomizing the value of the If-Modified-Since: makes it less likely that the server can use the time as a cookie replacement, but you will run into caching problems if the random range is too high. It is a good idea to only use a small negative value and let overwrite-last-modified handle the greater changes. It is also recommended to use this action together with crunch-if-none-match, otherwise it's more or less pointless. Example usage (section): # Let the browser revalidate but make tracking based on the time less likely. {+hide-if-modified-since{-60} \ +overwrite-last-modified{randomize} \ +crunch-if-none-match} / hide-from-header Typical use: Keep your (old and ill) browser from telling web servers your email address Effect: Deletes any existing From: HTTP header, or replaces it with the specified string. Type: Parameterized. Parameter: Keyword: block, or any user defined value. Notes: The keyword block will completely remove the header (not to be confused with the block action). Alternately, you can specify any value you prefer to be sent to the web server. If you do, it is a matter of fairness not to use any address that is actually used by a real person. This action is rarely needed, as modern web browsers don't send From: headers anymore. Example usage: +hide-from-header{block} or +hide-from-header{spam-me-senseless@sittingduck.example.com} hide-referrer Typical use: Conceal which link you followed to get to a particular site Effect: Deletes the Referer: (sic) HTTP header from the client request, or replaces it with a forged one. Type: Parameterized. Parameter: conditional-block to delete the header completely if the host has changed. conditional-forge to forge the header if the host has changed. block to delete the header unconditionally. forge to pretend to be coming from the homepage of the server we are talking to. Any other string to set a user defined referrer. Notes: conditional-block is the only parameter, that isn't easily detected in the server's log file. If it blocks the referrer, the request will look like the visitor used a bookmark or typed in the address directly. Leaving the referrer unmodified for requests on the same host allows the server owner to see the visitor's click path, but in most cases she could also get that information by comparing other parts of the log file: for example the User-Agent if it isn't a very common one, or the user's IP address if it doesn't change between different requests. Always blocking the referrer, or using a custom one, can lead to failures on servers that check the referrer before they answer any requests, in an attempt to prevent their content from being embedded or linked to elsewhere. Both conditional-block and forge will work with referrer checks, as long as content and valid referring page are on the same host. Most of the time that's the case. hide-referer is an alternate spelling of hide-referrer and the two can be can be freely substituted with each other. (referrer is the correct English spelling, however the HTTP specification has a bug - it requires it to be spelled as referer.) Example usage: +hide-referrer{forge} or +hide-referrer{http://www.yahoo.com/} hide-user-agent Typical use: Try to conceal your type of browser and client operating system Effect: Replaces the value of the User-Agent: HTTP header in client requests with the specified value. Type: Parameterized. Parameter: Any user-defined string. Notes: This can lead to problems on web sites that depend on looking at this header in order to customize their content for different browsers (which, by the way, is NOT the right thing to do: good web sites work browser-independently). Using this action in multi-user setups or wherever different types of browsers will access the same Privoxy is not recommended. In single-user, single-browser setups, you might use it to delete your OS version information from the headers, because it is an invitation to exploit known bugs for your OS. It is also occasionally useful to forge this in order to access sites that won't let you in otherwise (though there may be a good reason in some cases). More information on known user-agent strings can be found at http://www.user-agents.org/ and http://en.wikipedia.org/wiki/User_agent. Example usage: +hide-user-agent{Netscape 6.1 (X11; I; Linux 2.4.18 i686)} limit-connect Typical use: Prevent abuse of Privoxy as a TCP proxy relay or disable SSL for untrusted sites Effect: Specifies to which ports HTTP CONNECT requests are allowable. Type: Parameterized. Parameter: A comma-separated list of ports or port ranges (the latter using dashes, with the minimum defaulting to 0 and the maximum to 65K). Notes: By default, i.e. if no limit-connect action applies, Privoxy allows HTTP CONNECT requests to all ports. Use limit-connect if fine-grained control is desired for some or all destinations. The CONNECT methods exists in HTTP to allow access to secure websites (https:// URLs) through proxies. It works very simply: the proxy connects to the server on the specified port, and then short-circuits its connections to the client and to the remote server. This means CONNECT-enabled proxies can be used as TCP relays very easily. Privoxy relays HTTPS traffic without seeing the decoded content. Websites can leverage this limitation to circumvent &my-app;'s filters. By specifying an invalid port range you can disable HTTPS entirely. Example usages: +limit-connect{443} # Port 443 is OK. +limit-connect{80,443} # Ports 80 and 443 are OK. +limit-connect{-3, 7, 20-100, 500-} # Ports less than 3, 7, 20 to 100 and above 500 are OK. +limit-connect{-} # All ports are OK +limit-connect{,} # No HTTPS/SSL traffic is allowed limit-cookie-lifetime Typical use: Limit the lifetime of HTTP cookies to a couple of minutes or hours. Effect: Overwrites the expires field in Set-Cookie server headers if it's above the specified limit. Type: Parameterized. Parameter: The lifetime limit in minutes, or 0. Notes: This action reduces the lifetime of HTTP cookies coming from the server to the specified number of minutes, starting from the time the cookie passes Privoxy. Cookies with a lifetime below the limit are not modified. The lifetime of session cookies is set to the specified limit. The effect of this action depends on the server. In case of servers which refresh their cookies with each response (or at least frequently), the lifetime limit set by this action is updated as well. Thus, a session associated with the cookie continues to work with this action enabled, as long as a new request is made before the last limit set is reached. However, some servers send their cookies once, with a lifetime of several years (the year 2037 is a popular choice), and do not refresh them until a certain event in the future, for example the user logging out. In this case this action may limit the absolute lifetime of the session, even if requests are made frequently. If the parameter is 0, this action behaves like session-cookies-only. Example usages: +limit-cookie-lifetime{60} prevent-compression Typical use: Ensure that servers send the content uncompressed, so it can be passed through filters. Effect: Removes the Accept-Encoding header which can be used to ask for compressed transfer. Type: Boolean. Parameter: N/A Notes: More and more websites send their content compressed by default, which is generally a good idea and saves bandwidth. But the filter and deanimate-gifs actions need access to the uncompressed data. When compiled with zlib support (available since &my-app; 3.0.7), content that should be filtered is decompressed on-the-fly and you don't have to worry about this action. If you are using an older &my-app; version, or one that hasn't been compiled with zlib support, this action can be used to convince the server to send the content uncompressed. Most text-based instances compress very well, the size is seldom decreased by less than 50%, for markup-heavy instances like news feeds saving more than 90% of the original size isn't unusual. Not using compression will therefore slow down the transfer, and you should only enable this action if you really need it. As of &my-app; 3.0.7 it's disabled in all predefined action settings. Note that some (rare) ill-configured sites don't handle requests for uncompressed documents correctly. Broken PHP applications tend to send an empty document body, some IIS versions only send the beginning of the content. If you enable prevent-compression per default, you might want to add exceptions for those sites. See the example for how to do that. Example usage (sections): # Selectively turn off compression, and enable a filter # { +filter{tiny-textforms} +prevent-compression } # Match only these sites .google. sourceforge.net sf.net # Or instead, we could set a universal default: # { +prevent-compression } / # Match all sites # Then maybe make exceptions for broken sites: # { -prevent-compression } .compusa.com/ overwrite-last-modified Typical use: Prevent yet another way to track the user's steps between sessions. Effect: Deletes the Last-Modified: HTTP server header or modifies its value. Type: Parameterized. Parameter: One of the keywords: block, reset-to-request-time and randomize Notes: Removing the Last-Modified: header is useful for filter testing, where you want to force a real reload instead of getting status code 304, which would cause the browser to reuse the old version of the page. The randomize option overwrites the value of the Last-Modified: header with a randomly chosen time between the original value and the current time. In theory the server could send each document with a different Last-Modified: header to track visits without using cookies. Randomize makes it impossible and the browser can still revalidate cached documents. reset-to-request-time overwrites the value of the Last-Modified: header with the current time. You could use this option together with hide-if-modified-since to further customize your random range. The preferred parameter here is randomize. It is safe to use, as long as the time settings are more or less correct. If the server sets the Last-Modified: header to the time of the request, the random range becomes zero and the value stays the same. Therefore you should later randomize it a second time with hided-if-modified-since, just to be sure. It is also recommended to use this action together with crunch-if-none-match. Example usage: # Let the browser revalidate without being tracked across sessions { +hide-if-modified-since{-60} \ +overwrite-last-modified{randomize} \ +crunch-if-none-match} / redirect Typical use: Redirect requests to other sites. Effect: Convinces the browser that the requested document has been moved to another location and the browser should get it from there. Type: Parameterized Parameter: An absolute URL or a single pcrs command. Notes: Requests to which this action applies are answered with a HTTP redirect to URLs of your choosing. The new URL is either provided as parameter, or derived by applying a single pcrs command to the original URL. The syntax for pcrs commands is documented in the filter file section. This action will be ignored if you use it together with block. It can be combined with fast-redirects{check-decoded-url} to redirect to a decoded version of a rewritten URL. Use this action carefully, make sure not to create redirection loops and be aware that using your own redirects might make it possible to fingerprint your requests. In case of problems with your redirects, or simply to watch them working, enable debug 128. Example usages: # Replace example.com's style sheet with another one { +redirect{http://localhost/css-replacements/example.com.css} } example.com/stylesheet\.css # Create a short, easy to remember nickname for a favorite site # (relies on the browser accept and forward invalid URLs to &my-app;) { +redirect{http://www.privoxy.org/user-manual/actions-file.html} } a # Always use the expanded view for Undeadly.org articles # (Note the $ at the end of the URL pattern to make sure # the request for the rewritten URL isn't redirected as well) {+redirect{s@$@&mode=expanded@}} undeadly.org/cgi\?action=article&sid=\d*$ # Redirect Google search requests to MSN {+redirect{s@^http://[^/]*/search\?q=([^&]*).*@http://search.msn.com/results.aspx?q=$1@}} .google.com/search # Redirect MSN search requests to Yahoo {+redirect{s@^http://[^/]*/results\.aspx\?q=([^&]*).*@http://search.yahoo.com/search?p=$1@}} search.msn.com//results\.aspx\?q= # Redirect remote requests for this manual # to the local version delivered by Privoxy {+redirect{s@^http://www@http://config@}} www.privoxy.org/user-manual/ server-header-filter Typical use: Rewrite or remove single server headers. Effect: All server headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions. Type: Parameterized. Parameter: The name of a server-header filter, as defined in one of the filter files. Notes: Server-header filters are applied to each header on its own, not to all at once. This makes it easier to diagnose problems, but on the downside you can't write filters that only change header x if header y's value is z. You can do that by using tags though. Server-header filters are executed after the other header actions have finished and use their output as input. Please refer to the filter file chapter to learn which server-header filters are available by default, and how to create your own. Example usage (section): {+server-header-filter{html-to-xml}} example.org/xml-instance-that-is-delivered-as-html {+server-header-filter{xml-to-html}} example.org/instance-that-is-delivered-as-xml-but-is-not server-header-tagger Typical use: Enable or disable filters based on the Content-Type header. Effect: Server headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions, the result is used as tag. Type: Parameterized. Parameter: The name of a server-header tagger, as defined in one of the filter files. Notes: Server-header taggers are applied to each header on its own, and as the header isn't modified, each tagger sees the original. Server-header taggers are executed before all other header actions that modify server headers. Their tags can be used to control all of the other server-header actions, the content filters and the crunch actions (redirect and block). Obviously crunching based on tags created by server-header taggers doesn't prevent the request from showing up in the server's log file. Example usage (section): # Tag every request with the content type declared by the server {+server-header-tagger{content-type}} / session-cookies-only Typical use: Allow only temporary session cookies (for the current browser session only). Effect: Deletes the expires field from Set-Cookie: server headers. Most browsers will not store such cookies permanently and forget them in between sessions. Type: Boolean. Parameter: N/A Notes: This is less strict than crunch-incoming-cookies / crunch-outgoing-cookies and allows you to browse websites that insist or rely on setting cookies, without compromising your privacy too badly. Most browsers will not permanently store cookies that have been processed by session-cookies-only and will forget about them between sessions. This makes profiling cookies useless, but won't break sites which require cookies so that you can log in for transactions. This is generally turned on for all sites, and is the recommended setting. It makes no sense at all to use session-cookies-only together with crunch-incoming-cookies or crunch-outgoing-cookies. If you do, cookies will be plainly killed. Note that it is up to the browser how it handles such cookies without an expires field. If you use an exotic browser, you might want to try it out to be sure. This setting also has no effect on cookies that may have been stored previously by the browser before starting Privoxy. These would have to be removed manually. Privoxy also uses the content-cookies filter to block some types of cookies. Content cookies are not effected by session-cookies-only. Example usage: +session-cookies-only set-image-blocker Typical use: Choose the replacement for blocked images Effect: This action alone doesn't do anything noticeable. If both block and handle-as-image also apply, i.e. if the request is to be blocked as an image, then the parameter of this action decides what will be sent as a replacement. Type: Parameterized. Parameter: pattern to send a built-in checkerboard pattern image. The image is visually decent, scales very well, and makes it obvious where banners were busted. blank to send a built-in transparent image. This makes banners disappear completely, but makes it hard to detect where Privoxy has blocked images on a given page and complicates troubleshooting if Privoxy has blocked innocent images, like navigation icons. target-url to send a redirect to target-url. You can redirect to any image anywhere, even in your local filesystem via file:/// URL. (But note that not all browsers support redirecting to a local file system). A good application of redirects is to use special Privoxy-built-in URLs, which send the built-in images, as target-url. This has the same visual effect as specifying blank or pattern in the first place, but enables your browser to cache the replacement image, instead of requesting it over and over again. Notes: The URLs for the built-in images are http://config.privoxy.org/send-banner?type=type, where type is either blank or pattern. There is a third (advanced) type, called auto. It is NOT to be used in set-image-blocker, but meant for use from filters. Auto will select the type of image that would have applied to the referring page, had it been an image. Example usage: Built-in pattern: +set-image-blocker{pattern} Redirect to the BSD daemon: +set-image-blocker{http://www.freebsd.org/gifs/dae_up3.gif} Redirect to the built-in pattern for better caching: +set-image-blocker{http://config.privoxy.org/send-banner?type=pattern} Summary Note that many of these actions have the potential to cause a page to misbehave, possibly even not to display at all. There are many ways a site designer may choose to design his site, and what HTTP header content, and other criteria, he may depend on. There is no way to have hard and fast rules for all sites. See the Appendix for a brief example on troubleshooting actions. Aliases Custom actions, known to Privoxy as aliases, can be defined by combining other actions. These can in turn be invoked just like the built-in actions. Currently, an alias name can contain any character except space, tab, =, { and }, but we strongly recommend that you only use a to z, 0 to 9, +, and -. Alias names are not case sensitive, and are not required to start with a + or - sign, since they are merely textually expanded. Aliases can be used throughout the actions file, but they must be defined in a special section at the top of the file! And there can only be one such section per actions file. Each actions file may have its own alias section, and the aliases defined in it are only visible within that file. There are two main reasons to use aliases: One is to save typing for frequently used combinations of actions, the other one is a gain in flexibility: If you decide once how you want to handle shops by defining an alias called shop, you can later change your policy on shops in one place, and your changes will take effect everywhere in the actions file where the shop alias is used. Calling aliases by their purpose also makes your actions files more readable. Currently, there is one big drawback to using aliases, though: Privoxy's built-in web-based action file editor honors aliases when reading the actions files, but it expands them before writing. So the effects of your aliases are of course preserved, but the aliases themselves are lost when you edit sections that use aliases with it. Now let's define some aliases... # Useful custom aliases we can use later. # # Note the (required!) section header line and that this section # must be at the top of the actions file! # {{alias}} # These aliases just save typing later: # (Note that some already use other aliases!) # +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies +block-as-image = +block{Blocked image.} +handle-as-image allow-all-cookies = -crunch-all-cookies -session-cookies-only -filter{content-cookies} # These aliases define combinations of actions # that are useful for certain types of sites: # fragile = -block -filter -crunch-all-cookies -fast-redirects -hide-referrer -prevent-compression shop = -crunch-all-cookies -filter{all-popups} # Short names for other aliases, for really lazy people ;-) # c0 = +crunch-all-cookies c1 = -crunch-all-cookies ...and put them to use. These sections would appear in the lower part of an actions file and define exceptions to the default actions (as specified further up for the / pattern): # These sites are either very complex or very keen on # user data and require minimal interference to work: # {fragile} .office.microsoft.com .windowsupdate.microsoft.com # Gmail is really mail.google.com, not gmail.com mail.google.com # Shopping sites: # Allow cookies (for setting and retrieving your customer data) # {shop} .quietpc.com .worldpay.com # for quietpc.com mybank.example.com # These shops require pop-ups: # {-filter{all-popups} -filter{unsolicited-popups}} .dabs.com .overclockers.co.uk Aliases like shop and fragile are typically used for problem sites that require more than one action to be disabled in order to function properly. Actions Files Tutorial The above chapters have shown which actions files there are and how they are organized, how actions are specified and applied to URLs, how patterns work, and how to define and use aliases. Now, let's look at an example match-all.action, default.action and user.action file and see how all these pieces come together: match-all.action Remember all actions are disabled when matching starts, so we have to explicitly enable the ones we want. While the match-all.action file only contains a single section, it is probably the most important one. It has only one pattern, /, but this pattern matches all URLs. Therefore, the set of actions used in this default section will be applied to all requests as a start. It can be partly or wholly overridden by other actions files like default.action and user.action, but it will still be largely responsible for your overall browsing experience. Again, at the start of matching, all actions are disabled, so there is no need to disable any actions here. (Remember: a + preceding the action name enables the action, a - disables!). Also note how this long line has been made more readable by splitting it into multiple lines with line continuation. { \ +change-x-forwarded-for{block} \ +hide-from-header{block} \ +set-image-blocker{pattern} \ } / # Match all URLs The default behavior is now set. default.action If you aren't a developer, there's no need for you to edit the default.action file. It is maintained by the &my-app; developers and if you disagree with some of the sections, you should overrule them in your user.action. Understanding the default.action file can help you with your user.action, though. The first section in this file is a special section for internal use that prevents older &my-app; versions from reading the file: ########################################################################## # Settings -- Don't change! For internal Privoxy use ONLY. ########################################################################## {{settings}} for-privoxy-version=3.0.11 After that comes the (optional) alias section. We'll use the example section from the above chapter on aliases, that also explains why and how aliases are used: ########################################################################## # Aliases ########################################################################## {{alias}} # These aliases just save typing later: # (Note that some already use other aliases!) # +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies +block-as-image = +block{Blocked image.} +handle-as-image mercy-for-cookies = -crunch-all-cookies -session-cookies-only -filter{content-cookies} # These aliases define combinations of actions # that are useful for certain types of sites: # fragile = -block -filter -crunch-all-cookies -fast-redirects -hide-referrer shop = -crunch-all-cookies -filter{all-popups} The first of our specialized sections is concerned with fragile sites, i.e. sites that require minimum interference, because they are either very complex or very keen on tracking you (and have mechanisms in place that make them unusable for people who avoid being tracked). We will simply use our pre-defined fragile alias instead of stating the list of actions explicitly: ########################################################################## # Exceptions for sites that'll break under the default action set: ########################################################################## # "Fragile" Use a minimum set of actions for these sites (see alias above): # { fragile } .office.microsoft.com # surprise, surprise! .windowsupdate.microsoft.com mail.google.com Shopping sites are not as fragile, but they typically require cookies to log in, and pop-up windows for shopping carts or item details. Again, we'll use a pre-defined alias: # Shopping sites: # { shop } .quietpc.com .worldpay.com # for quietpc.com .jungle.com .scan.co.uk The fast-redirects action, which may have been enabled in match-all.action, breaks some sites. So disable it for popular sites where we know it misbehaves: { -fast-redirects } login.yahoo.com edit.*.yahoo.com .google.com .altavista.com/.*(like|url|link):http .altavista.com/trans.*urltext=http .nytimes.com It is important that Privoxy knows which URLs belong to images, so that if they are to be blocked, a substitute image can be sent, rather than an HTML page. Contacting the remote site to find out is not an option, since it would destroy the loading time advantage of banner blocking, and it would feed the advertisers information about you. We can mark any URL as an image with the handle-as-image action, and marking all URLs that end in a known image file extension is a good start: ########################################################################## # Images: ########################################################################## # Define which file types will be treated as images, in case they get # blocked further down this file: # { +handle-as-image } /.*\.(gif|jpe?g|png|bmp|ico)$ And then there are known banner sources. They often use scripts to generate the banners, so it won't be visible from the URL that the request is for an image. Hence we block them and mark them as images in one go, with the help of our +block-as-image alias defined above. (We could of course just as well use +block +handle-as-image here.) Remember that the type of the replacement image is chosen by the set-image-blocker action. Since all URLs have matched the default section with its +set-image-blocker{pattern} action before, it still applies and needn't be repeated: # Known ad generators: # { +block-as-image } ar.atwola.com .ad.doubleclick.net .ad.*.doubleclick.net .a.yimg.com/(?:(?!/i/).)*$ .a[0-9].yimg.com/(?:(?!/i/).)*$ bs*.gsanet.com .qkimg.net One of the most important jobs of Privoxy is to block banners. Many of these can be blocked by the filter{banners-by-size} action, which we enabled above, and which deletes the references to banner images from the pages while they are loaded, so the browser doesn't request them anymore, and hence they don't need to be blocked here. But this naturally doesn't catch all banners, and some people choose not to use filters, so we need a comprehensive list of patterns for banner URLs here, and apply the block action to them. First comes many generic patterns, which do most of the work, by matching typical domain and path name components of banners. Then comes a list of individual patterns for specific sites, which is omitted here to keep the example short: ########################################################################## # Block these fine banners: ########################################################################## { +block{Banner ads.} } # Generic patterns: # ad*. .*ads. banner?. count*. /.*count(er)?\.(pl|cgi|exe|dll|asp|php[34]?) /(?:.*/)?(publicite|werbung|rekla(ma|me|am)|annonse|maino(kset|nta|s)?)/ # Site-specific patterns (abbreviated): # .hitbox.com It's quite remarkable how many advertisers actually call their banner servers ads.company.com, or call the directory in which the banners are stored simply banners. So the above generic patterns are surprisingly effective. But being very generic, they necessarily also catch URLs that we don't want to block. The pattern .*ads. e.g. catches nasty-ads.nasty-corp.com as intended, but also downloads.sourcefroge.net or adsl.some-provider.net. So here come some well-known exceptions to the +block section above. Note that these are exceptions to exceptions from the default! Consider the URL downloads.sourcefroge.net: Initially, all actions are deactivated, so it wouldn't get blocked. Then comes the defaults section, which matches the URL, but just deactivates the block action once again. Then it matches .*ads., an exception to the general non-blocking policy, and suddenly +block applies. And now, it'll match .*loads., where -block applies, so (unless it matches again further down) it ends up with no block action applying. ########################################################################## # Save some innocent victims of the above generic block patterns: ########################################################################## # By domain: # { -block } adv[io]*. # (for advogato.org and advice.*) adsl. # (has nothing to do with ads) adobe. # (has nothing to do with ads either) ad[ud]*. # (adult.* and add.*) .edu # (universities don't host banners (yet!)) .*loads. # (downloads, uploads etc) # By path: # /.*loads/ # Site-specific: # www.globalintersec.com/adv # (adv = advanced) www.ugu.com/sui/ugu/adv Filtering source code can have nasty side effects, so make an exception for our friends at sourceforge.net, and all paths with cvs in them. Note that -filter disables all filters in one fell swoop! # Don't filter code! # { -filter } /(.*/)?cvs bugzilla. developer. wiki. .sourceforge.net The actual default.action is of course much more comprehensive, but we hope this example made clear how it works. user.action So far we are painting with a broad brush by setting general policies, which would be a reasonable starting point for many people. Now, you might want to be more specific and have customized rules that are more suitable to your personal habits and preferences. These would be for narrowly defined situations like your ISP or your bank, and should be placed in user.action, which is parsed after all other actions files and hence has the last word, over-riding any previously defined actions. user.action is also a safe place for your personal settings, since default.action is actively maintained by the Privoxy developers and you'll probably want to install updated versions from time to time. So let's look at a few examples of things that one might typically do in user.action: # My user.action file. <fred@example.com> As aliases are local to the actions file that they are defined in, you can't use the ones from default.action, unless you repeat them here: # Aliases are local to the file they are defined in. # (Re-)define aliases for this file: # {{alias}} # # These aliases just save typing later, and the alias names should # be self explanatory. # +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies allow-all-cookies = -crunch-all-cookies -session-cookies-only allow-popups = -filter{all-popups} +block-as-image = +block{Blocked as image.} +handle-as-image -block-as-image = -block # These aliases define combinations of actions that are useful for # certain types of sites: # fragile = -block -crunch-all-cookies -filter -fast-redirects -hide-referrer shop = -crunch-all-cookies allow-popups # Allow ads for selected useful free sites: # allow-ads = -block -filter{banners-by-size} -filter{banners-by-link} # Alias for specific file types that are text, but might have conflicting # MIME types. We want the browser to force these to be text documents. handle-as-text = -filter +-content-type-overwrite{text/plain} +-force-text-mode -hide-content-disposition Say you have accounts on some sites that you visit regularly, and you don't want to have to log in manually each time. So you'd like to allow persistent cookies for these sites. The allow-all-cookies alias defined above does exactly that, i.e. it disables crunching of cookies in any direction, and the processing of cookies to make them only temporary. { allow-all-cookies } sourceforge.net .yahoo.com .msdn.microsoft.com .redhat.com Your bank is allergic to some filter, but you don't know which, so you disable them all: { -filter } .your-home-banking-site.com Some file types you may not want to filter for various reasons: # Technical documentation is likely to contain strings that might # erroneously get altered by the JavaScript-oriented filters: # .tldp.org /(.*/)?selfhtml/ # And this stupid host sends streaming video with a wrong MIME type, # so that Privoxy thinks it is getting HTML and starts filtering: # stupid-server.example.com/ Example of a simple block action. Say you've seen an ad on your favourite page on example.com that you want to get rid of. You have right-clicked the image, selected copy image location and pasted the URL below while removing the leading http://, into a { +block{} } section. Note that { +handle-as-image } need not be specified, since all URLs ending in .gif will be tagged as images by the general rules as set in default.action anyway: { +block{Nasty ads.} } www.example.com/nasty-ads/sponsor\.gif another.example.net/more/junk/here/ The URLs of dynamically generated banners, especially from large banner farms, often don't use the well-known image file name extensions, which makes it impossible for Privoxy to guess the file type just by looking at the URL. You can use the +block-as-image alias defined above for these cases. Note that objects which match this rule but then turn out NOT to be an image are typically rendered as a broken image icon by the browser. Use cautiously. { +block-as-image } .doubleclick.net .fastclick.net /Realmedia/ads/ ar.atwola.com/ Now you noticed that the default configuration breaks Forbes Magazine, but you were too lazy to find out which action is the culprit, and you were again too lazy to give feedback, so you just used the fragile alias on the site, and -- whoa! -- it worked. The fragile aliases disables those actions that are most likely to break a site. Also, good for testing purposes to see if it is Privoxy that is causing the problem or not. We later find other regular sites that misbehave, and add those to our personalized list of troublemakers: { fragile } .forbes.com webmail.example.com .mybank.com You like the fun text replacements in default.filter, but it is disabled in the distributed actions file. So you'd like to turn it on in your private, update-safe config, once and for all: { +filter{fun} } / # For ALL sites! Note that the above is not really a good idea: There are exceptions to the filters in default.action for things that really shouldn't be filtered, like code on CVS->Web interfaces. Since user.action has the last word, these exceptions won't be valid for the fun filtering specified here. You might also worry about how your favourite free websites are funded, and find that they rely on displaying banner advertisements to survive. So you might want to specifically allow banners for those sites that you feel provide value to you: { allow-ads } .sourceforge.net .slashdot.org .osdn.net Note that allow-ads has been aliased to -block, -filter{banners-by-size}, and -filter{banners-by-link} above. Invoke another alias here to force an over-ride of the MIME type application/x-sh which typically would open a download type dialog. In my case, I want to look at the shell script, and then I can save it should I choose to. { handle-as-text } /.*\.sh$ user.action is generally the best place to define exceptions and additions to the default policies of default.action. Some actions are safe to have their default policies set here though. So let's set a default policy to have a blank image as opposed to the checkerboard pattern for ALL sites. / of course matches all URL paths and patterns: { +set-image-blocker{blank} } / # ALL sites
    Filter Files On-the-fly text substitutions need to be defined in a filter file. Once defined, they can then be invoked as an action. &my-app; supports three different filter actions: filter to rewrite the content that is send to the client, client-header-filter to rewrite headers that are send by the client, and server-header-filter to rewrite headers that are send by the server. &my-app; also supports two tagger actions: client-header-tagger and server-header-tagger. Taggers and filters use the same syntax in the filter files, the difference is that taggers don't modify the text they are filtering, but use a rewritten version of the filtered text as tag. The tags can then be used to change the applying actions through sections with tag-patterns. Multiple filter files can be defined through the filterfile config directive. The filters as supplied by the developers are located in default.filter. It is recommended that any locally defined or modified filters go in a separately defined file such as user.filter. Common tasks for content filters are to eliminate common annoyances in HTML and JavaScript, such as pop-up windows, exit consoles, crippled windows without navigation tools, the infamous <BLINK> tag etc, to suppress images with certain width and height attributes (standard banner sizes or web-bugs), or just to have fun. Enabled content filters are applied to any content whose Content Type header is recognised as a sign of text-based content, with the exception of text/plain. Use the force-text-mode action to also filter other content. Substitutions are made at the source level, so if you want to roll your own filters, you should first be familiar with HTML syntax, and, of course, regular expressions. Just like the actions files, the filter file is organized in sections, which are called filters here. Each filter consists of a heading line, that starts with one of the keywords FILTER:, CLIENT-HEADER-FILTER: or SERVER-HEADER-FILTER: followed by the filter's name, and a short (one line) description of what it does. Below that line come the jobs, i.e. lines that define the actual text substitutions. By convention, the name of a filter should describe what the filter eliminates. The comment is used in the web-based user interface. Once a filter called name has been defined in the filter file, it can be invoked by using an action of the form +filter{name} in any actions file. Filter definitions start with a header line that contains the filter type, the filter name and the filter description. A content filter header line for a filter called foo could look like this: FILTER: foo Replace all "foo" with "bar" Below that line, and up to the next header line, come the jobs that define what text replacements the filter executes. They are specified in a syntax that imitates Perl's s/// operator. If you are familiar with Perl, you will find this to be quite intuitive, and may want to look at the PCRS documentation for the subtle differences to Perl behaviour. Most notably, the non-standard option letter U is supported, which turns the default to ungreedy matching. If you are new to Regular Expressions, you might want to take a look at the Appendix on regular expressions, and see the Perl manual for the s/// operator's syntax and Perl-style regular expressions in general. The below examples might also help to get you started. Filter File Tutorial Now, let's complete our foo content filter. We have already defined the heading, but the jobs are still missing. Since all it does is to replace foo with bar, there is only one (trivial) job needed: s/foo/bar/ But wait! Didn't the comment say that all occurrences of foo should be replaced? Our current job will only take care of the first foo on each page. For global substitution, we'll need to add the g option: s/foo/bar/g Our complete filter now looks like this: FILTER: foo Replace all "foo" with "bar" s/foo/bar/g Let's look at some real filters for more interesting examples. Here you see a filter that protects against some common annoyances that arise from JavaScript abuse. Let's look at its jobs one after the other: FILTER: js-annoyances Get rid of particularly annoying JavaScript abuse # Get rid of JavaScript referrer tracking. Test page: http://www.randomoddness.com/untitled.htm # s|(<script.*)document\.referrer(.*</script>)|$1"Not Your Business!"$2|Usg Following the header line and a comment, you see the job. Note that it uses | as the delimiter instead of /, because the pattern contains a forward slash, which would otherwise have to be escaped by a backslash (\). Now, let's examine the pattern: it starts with the text <script.* enclosed in parentheses. Since the dot matches any character, and * means: Match an arbitrary number of the element left of myself, this matches <script, followed by any text, i.e. it matches the whole page, from the start of the first <script> tag. That's more than we want, but the pattern continues: document\.referrer matches only the exact string document.referrer. The dot needed to be escaped, i.e. preceded by a backslash, to take away its special meaning as a joker, and make it just a regular dot. So far, the meaning is: Match from the start of the first <script> tag in a the page, up to, and including, the text document.referrer, if both are present in the page (and appear in that order). But there's still more pattern to go. The next element, again enclosed in parentheses, is .*</script>. You already know what .* means, so the whole pattern translates to: Match from the start of the first <script> tag in a page to the end of the last <script> tag, provided that the text document.referrer appears somewhere in between. This is still not the whole story, since we have ignored the options and the parentheses: The portions of the page matched by sub-patterns that are enclosed in parentheses, will be remembered and be available through the variables $1, $2, ... in the substitute. The U option switches to ungreedy matching, which means that the first .* in the pattern will only eat up all text in between <script and the first occurrence of document.referrer, and that the second .* will only span the text up to the first </script> tag. Furthermore, the s option says that the match may span multiple lines in the page, and the g option again means that the substitution is global. So, to summarize, the pattern means: Match all scripts that contain the text document.referrer. Remember the parts of the script from (and including) the start tag up to (and excluding) the string document.referrer as $1, and the part following that string, up to and including the closing tag, as $2. Now the pattern is deciphered, but wasn't this about substituting things? So lets look at the substitute: $1"Not Your Business!"$2 is easy to read: The text remembered as $1, followed by "Not Your Business!" (including the quotation marks!), followed by the text remembered as $2. This produces an exact copy of the original string, with the middle part (the document.referrer) replaced by "Not Your Business!". The whole job now reads: Replace document.referrer by "Not Your Business!" wherever it appears inside a <script> tag. Note that this job won't break JavaScript syntax, since both the original and the replacement are syntactically valid string objects. The script just won't have access to the referrer information anymore. We'll show you two other jobs from the JavaScript taming department, but this time only point out the constructs of special interest: # The status bar is for displaying link targets, not pointless blahblah # s/window\.status\s*=\s*(['"]).*?\1/dUmMy=1/ig \s stands for whitespace characters (space, tab, newline, carriage return, form feed), so that \s* means: zero or more whitespace. The ? in .*? makes this matching of arbitrary text ungreedy. (Note that the U option is not set). The ['"] construct means: a single or a double quote. Finally, \1 is a back-reference to the first parenthesis just like $1 above, with the difference that in the pattern, a backslash indicates a back-reference, whereas in the substitute, it's the dollar. So what does this job do? It replaces assignments of single- or double-quoted strings to the window.status object with a dummy assignment (using a variable name that is hopefully odd enough not to conflict with real variables in scripts). Thus, it catches many cases where e.g. pointless descriptions are displayed in the status bar instead of the link target when you move your mouse over links. # Kill OnUnload popups. Yummy. Test: http://www.zdnet.com/zdsubs/yahoo/tree/yfs.html # s/(<body [^>]*)onunload(.*>)/$1never$2/iU Including the OnUnload event binding in the HTML DOM was a CRIME. When I close a browser window, I want it to close and die. Basta. This job replaces the onunload attribute in <body> tags with the dummy word never. Note that the i option makes the pattern matching case-insensitive. Also note that ungreedy matching alone doesn't always guarantee a minimal match: In the first parenthesis, we had to use [^>]* instead of .* to prevent the match from exceeding the <body> tag if it doesn't contain OnUnload, but the page's content does. The last example is from the fun department: FILTER: fun Fun text replacements # Spice the daily news: # s/microsoft(?!\.com)/MicroSuck/ig Note the (?!\.com) part (a so-called negative lookahead) in the job's pattern, which means: Don't match, if the string .com appears directly following microsoft in the page. This prevents links to microsoft.com from being trashed, while still replacing the word everywhere else. # Buzzword Bingo (example for extended regex syntax) # s* industry[ -]leading \ | cutting[ -]edge \ | customer[ -]focused \ | market[ -]driven \ | award[ -]winning # Comments are OK, too! \ | high[ -]performance \ | solutions[ -]based \ | unmatched \ | unparalleled \ | unrivalled \ *<font color="red"><b>BINGO!</b></font> \ *igx The x option in this job turns on extended syntax, and allows for e.g. the liberal use of (non-interpreted!) whitespace for nicer formatting. You get the idea? The Pre-defined Filters The distribution default.filter file contains a selection of pre-defined filters for your convenience: js-annoyances The purpose of this filter is to get rid of particularly annoying JavaScript abuse. To that end, it replaces JavaScript references to the browser's referrer information with the string "Not Your Business!". This compliments the hide-referrer action on the content level. removes the bindings to the DOM's unload event which we feel has no right to exist and is responsible for most exit consoles, i.e. nasty windows that pop up when you close another one. removes code that causes new windows to be opened with undesired properties, such as being full-screen, non-resizeable, without location, status or menu bar etc. Use with caution. This is an aggressive filter, and can break sites that rely heavily on JavaScript. js-events This is a very radical measure. It removes virtually all JavaScript event bindings, which means that scripts can not react to user actions such as mouse movements or clicks, window resizing etc, anymore. Use with caution! We strongly discourage using this filter as a default since it breaks many legitimate scripts. It is meant for use only on extra-nasty sites (should you really need to go there). html-annoyances This filter will undo many common instances of HTML based abuse. The BLINK and MARQUEE tags are neutralized (yeah baby!), and browser windows will be created as resizeable (as of course they should be!), and will have location, scroll and menu bars -- even if specified otherwise. content-cookies Most cookies are set in the HTTP dialog, where they can be intercepted by the crunch-incoming-cookies and crunch-outgoing-cookies actions. But web sites increasingly make use of HTML meta tags and JavaScript to sneak cookies to the browser on the content level. This filter disables most HTML and JavaScript code that reads or sets cookies. It cannot detect all clever uses of these types of code, so it should not be relied on as an absolute fix. Use it wherever you would also use the cookie crunch actions. refresh-tags Disable any refresh tags if the interval is greater than nine seconds (so that redirections done via refresh tags are not destroyed). This is useful for dial-on-demand setups, or for those who find this HTML feature annoying. unsolicited-popups This filter attempts to prevent only unsolicited pop-up windows from opening, yet still allow pop-up windows that the user has explicitly chosen to open. It was added in version 3.0.1, as an improvement over earlier such filters. Technical note: The filter works by redefining the window.open JavaScript function to a dummy function, PrivoxyWindowOpen(), during the loading and rendering phase of each HTML page access, and restoring the function afterward. This is recommended only for browsers that cannot perform this function reliably themselves. And be aware that some sites require such windows in order to function normally. Use with caution. all-popups Attempt to prevent all pop-up windows from opening. Note this should be used with even more discretion than the above, since it is more likely to break some sites that require pop-ups for normal usage. Use with caution. img-reorder This is a helper filter that has no value if used alone. It makes the banners-by-size and banners-by-link (see below) filters more effective and should be enabled together with them. banners-by-size This filter removes image tags purely based on what size they are. Fortunately for us, many ads and banner images tend to conform to certain standardized sizes, which makes this filter quite effective for ad stripping purposes. Occasionally this filter will cause false positives on images that are not ads, but just happen to be of one of the standard banner sizes. Recommended only for those who require extreme ad blocking. The default block rules should catch 95+% of all ads without this filter enabled. banners-by-link This is an experimental filter that attempts to kill any banners if their URLs seem to point to known or suspected click trackers. It is currently not of much value and is not recommended for use by default. webbugs Webbugs are small, invisible images (technically 1X1 GIF images), that are used to track users across websites, and collect information on them. As an HTML page is loaded by the browser, an embedded image tag causes the browser to contact a third-party site, disclosing the tracking information through the requested URL and/or cookies for that third-party domain, without the user ever becoming aware of the interaction with the third-party site. HTML-ized spam also uses a similar technique to verify email addresses. This filter removes the HTML code that loads such webbugs. tiny-textforms A rather special-purpose filter that can be used to enlarge textareas (those multi-line text boxes in web forms) and turn off hard word wrap in them. It was written for the sourceforge.net tracker system where such boxes are a nuisance, but it can be handy on other sites, too. It is not recommended to use this filter as a default. jumping-windows Many consider windows that move, or resize themselves to be abusive. This filter neutralizes the related JavaScript code. Note that some sites might not display or behave as intended when using this filter. Use with caution. frameset-borders Some web designers seem to assume that everyone in the world will view their web sites using the same browser brand and version, screen resolution etc, because only that assumption could explain why they'd use static frame sizes, yet prevent their frames from being resized by the user, should they be too small to show their whole content. This filter removes the related HTML code. It should only be applied to sites which need it. demoronizer Many Microsoft products that generate HTML use non-standard extensions (read: violations) of the ISO 8859-1 aka Latin-1 character set. This can cause those HTML documents to display with errors on standard-compliant platforms. This filter translates the MS-only characters into Latin-1 equivalents. It is not necessary when using MS products, and will cause corruption of all documents that use 8-bit character sets other than Latin-1. It's mostly worthwhile for Europeans on non-MS platforms, if weird garbage characters sometimes appear on some pages, or user agents that don't correct for this on the fly. shockwave-flash A filter for shockwave haters. As the name suggests, this filter strips code out of web pages that is used to embed shockwave flash objects. quicktime-kioskmode Change HTML code that embeds Quicktime objects so that kioskmode, which prevents saving, is disabled. fun Text replacements for subversive browsing fun. Make fun of your favorite Monopolist or play buzzword bingo. crude-parental A demonstration-only filter that shows how Privoxy can be used to delete web content on a keyword basis. ie-exploits An experimental collection of text replacements to disable malicious HTML and JavaScript code that exploits known security holes in Internet Explorer. Presently, it only protects against Nimda and a cross-site scripting bug, and would need active maintenance to provide more substantial protection. site-specifics Some web sites have very specific problems, the cure for which doesn't apply anywhere else, or could even cause damage on other sites. This is a collection of such site-specific cures which should only be applied to the sites they were intended for, which is what the supplied default.action file does. Users shouldn't need to change anything regarding this filter. google A CSS based block for Google text ads. Also removes a width limitation and the toolbar advertisement. yahoo Another CSS based block, this time for Yahoo text ads. And removes a width limitation as well. msn Another CSS based block, this time for MSN text ads. And removes tracking URLs, as well as a width limitation. blogspot Cleans up some Blogspot blogs. Read the fine print before using this one! This filter also intentionally removes some navigation stuff and sets the page width to 100%. As a result, some rounded corners would appear to early or not at all and as fixing this would require a browser that understands background-size (CSS3), they are removed instead. xml-to-html Server-header filter to change the Content-Type from xml to html. html-to-xml Server-header filter to change the Content-Type from html to xml. no-ping Removes the non-standard ping attribute from anchor and area HTML tags. hide-tor-exit-notation Client-header filter to remove the Tor exit node notation found in Host and Referer headers. If &my-app; and Tor are chained and &my-app; is configured to use socks4a, one can use http://www.example.org.foobar.exit/ to access the host www.example.org through the Tor exit node foobar. As the HTTP client isn't aware of this notation, it treats the whole string www.example.org.foobar.exit as host and uses it for the Host and Referer headers. From the server's point of view the resulting headers are invalid and can cause problems. An invalid Referer header can trigger hot-linking protections, an invalid Host header will make it impossible for the server to find the right vhost (several domains hosted on the same IP address). This client-header filter removes the foo.exit part in those headers to prevent the mentioned problems. Note that it only modifies the HTTP headers, it doesn't make it impossible for the server to detect your Tor exit node based on the IP address the request is coming from. Privoxy's Template Files All Privoxy built-in pages, i.e. error pages such as the 404 - No Such Domain error page, the BLOCKED page and all pages of its web-based user interface, are generated from templates. (Privoxy must be running for the above links to work as intended.) These templates are stored in a subdirectory of the configuration directory called templates. On Unixish platforms, this is typically /etc/privoxy/templates/. The templates are basically normal HTML files, but with place-holders (called symbols or exports), which Privoxy fills at run time. It is possible to edit the templates with a normal text editor, should you want to customize them. (Not recommended for the casual user). Should you create your own custom templates, you should use the config setting templdir to specify an alternate location, so your templates do not get overwritten during upgrades. Note that just like in configuration files, lines starting with # are ignored when the templates are filled in. The place-holders are of the form @name@, and you will find a list of available symbols, which vary from template to template, in the comments at the start of each file. Note that these comments are not always accurate, and that it's probably best to look at the existing HTML code to find out which symbols are supported and what they are filled in with. A special application of this substitution mechanism is to make whole blocks of HTML code disappear when a specific symbol is set. We use this for many purposes, one of them being to include the beta warning in all our user interface (CGI) pages when Privoxy is in an alpha or beta development stage: <!-- @if-unstable-start --> ... beta warning HTML code goes here ... <!-- if-unstable-end@ --> If the "unstable" symbol is set, everything in between and including @if-unstable-start and if-unstable-end@ will disappear, leaving nothing but an empty comment: <!-- --> There's also an if-then-else construct and an #include mechanism, but you'll sure find out if you are inclined to edit the templates ;-) All templates refer to a style located at http://config.privoxy.org/send-stylesheet. This is, of course, locally served by Privoxy and the source for it can be found and edited in the cgi-style.css template. Contacting the Developers, Bug Reporting and Feature Requests &contacting; Privoxy Copyright, License and History ©right; Privoxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation and included in the next section. License History &history; Authors &p-authors; See Also &seealso; Appendix Regular Expressions Privoxy uses Perl-style regular expressions in its actions files and filter file, through the PCRE and PCRS libraries. If you are reading this, you probably don't understand what regular expressions are, or what they can do. So this will be a very brief introduction only. A full explanation would require a book ;-) Regular expressions provide a language to describe patterns that can be run against strings of characters (letter, numbers, etc), to see if they match the string or not. The patterns are themselves (sometimes complex) strings of literal characters, combined with wild-cards, and other special characters, called meta-characters. The meta-characters have special meanings and are used to build complex patterns to be matched against. Perl Compatible Regular Expressions are an especially convenient dialect of the regular expression language. To make a simple analogy, we do something similar when we use wild-card characters when listing files with the dir command in DOS. *.* matches all filenames. The special character here is the asterisk which matches any and all characters. We can be more specific and use ? to match just individual characters. So dir file?.text would match file1.txt, file2.txt, etc. We are pattern matching, using a similar technique to regular expressions! Regular expressions do essentially the same thing, but are much, much more powerful. There are many more special characters and ways of building complex patterns however. Let's look at a few of the common ones, and then some examples: . - Matches any single character, e.g. a, A, 4, :, or @. ? - The preceding character or expression is matched ZERO or ONE times. Either/or. + - The preceding character or expression is matched ONE or MORE times. * - The preceding character or expression is matched ZERO or MORE times. \ - The escape character denotes that the following character should be taken literally. This is used where one of the special characters (e.g. .) needs to be taken literally and not as a special meta-character. Example: example\.com, makes sure the period is recognized only as a period (and not expanded to its meta-character meaning of any single character). [ ] - Characters enclosed in brackets will be matched if any of the enclosed characters are encountered. For instance, [0-9] matches any numeric digit (zero through nine). As an example, we can combine this with + to match any digit one of more times: [0-9]+. ( ) - parentheses are used to group a sub-expression, or multiple sub-expressions. | - The bar character works like an or conditional statement. A match is successful if the sub-expression on either side of | matches. As an example: /(this|that) example/ uses grouping and the bar character and would match either this example or that example, and nothing else. These are just some of the ones you are likely to use when matching URLs with Privoxy, and is a long way from a definitive list. This is enough to get us started with a few simple examples which may be more illuminating: /.*/banners/.* - A simple example that uses the common combination of . and * to denote any character, zero or more times. In other words, any string at all. So we start with a literal forward slash, then our regular expression pattern (.*) another literal forward slash, the string banners, another forward slash, and lastly another .*. We are building a directory path here. This will match any file with the path that has a directory named banners in it. The .* matches any characters, and this could conceivably be more forward slashes, so it might expand into a much longer looking path. For example, this could match: /eye/hate/spammers/banners/annoy_me_please.gif, or just /banners/annoying.html, or almost an infinite number of other possible combinations, just so it has banners in the path somewhere. And now something a little more complex: /.*/adv((er)?ts?|ertis(ing|ements?))?/ - We have several literal forward slashes again (/), so we are building another expression that is a file path statement. We have another .*, so we are matching against any conceivable sub-path, just so it matches our expression. The only true literal that must match our pattern is adv, together with the forward slashes. What comes after the adv string is the interesting part. Remember the ? means the preceding expression (either a literal character or anything grouped with (...) in this case) can exist or not, since this means either zero or one match. So ((er)?ts?|ertis(ing|ements?)) is optional, as are the individual sub-expressions: (er), (ing|ements?), and the s. The | means or. We have two of those. For instance, (ing|ements?), can expand to match either ing OR ements?. What is being done here, is an attempt at matching as many variations of advertisement, and similar, as possible. So this would expand to match just adv, or advert, or adverts, or advertising, or advertisement, or advertisements. You get the idea. But it would not match advertizements (with a z). We could fix that by changing our regular expression to: /.*/adv((er)?ts?|erti(s|z)(ing|ements?))?/, which would then match either spelling. /.*/advert[0-9]+\.(gif|jpe?g) - Again another path statement with forward slashes. Anything in the square brackets [ ] can be matched. This is using 0-9 as a shorthand expression to mean any digit one through nine. It is the same as saying 0123456789. So any digit matches. The + means one or more of the preceding expression must be included. The preceding expression here is what is in the square brackets -- in this case, any digit one through nine. Then, at the end, we have a grouping: (gif|jpe?g). This includes a |, so this needs to match the expression on either side of that bar character also. A simple gif on one side, and the other side will in turn match either jpeg or jpg, since the ? means the letter e is optional and can be matched once or not at all. So we are building an expression here to match image GIF or JPEG type image file. It must include the literal string advert, then one or more digits, and a . (which is now a literal, and not a special character, since it is escaped with \), and lastly either gif, or jpeg, or jpg. Some possible matches would include: //advert1.jpg, /nasty/ads/advert1234.gif, /banners/from/hell/advert99.jpg. It would not match advert1.gif (no leading slash), or /adverts232.jpg (the expression does not include an s), or /advert1.jsp (jsp is not in the expression anywhere). We are barely scratching the surface of regular expressions here so that you can understand the default Privoxy configuration files, and maybe use this knowledge to customize your own installation. There is much, much more that can be done with regular expressions. Now that you know enough to get started, you can learn more on your own :/ More reading on Perl Compatible Regular expressions: http://perldoc.perl.org/perlre.html For information on regular expression based substitutions and their applications in filters, please see the filter file tutorial in this manual. Privoxy's Internal Pages Since Privoxy proxies each requested web page, it is easy for Privoxy to trap certain special URLs. In this way, we can talk directly to Privoxy, and see how it is configured, see how our rules are being applied, change these rules and other configuration options, and even turn Privoxy's filtering off, all with a web browser. The URLs listed below are the special ones that allow direct access to Privoxy. Of course, Privoxy must be running to access these. If not, you will get a friendly error message. Internet access is not necessary either. Privoxy main page:
    http://config.privoxy.org/
    There is a shortcut: http://p.p/ (But it doesn't provide a fall-back to a real page, in case the request is not sent through Privoxy)
    Show information about the current configuration, including viewing and editing of actions files:
    http://config.privoxy.org/show-status
    Show the source code version numbers:
    http://config.privoxy.org/show-version
    Show the browser's request headers:
    http://config.privoxy.org/show-request
    Show which actions apply to a URL and why:
    http://config.privoxy.org/show-url-info
    Toggle Privoxy on or off. This feature can be turned off/on in the main config file. When toggled off, Privoxy continues to run, but only as a pass-through proxy, with no actions taking place:
    http://config.privoxy.org/toggle
    Short cuts. Turn off, then on:
    http://config.privoxy.org/toggle?set=disable
    http://config.privoxy.org/toggle?set=enable
    These may be bookmarked for quick reference. See next. Bookmarklets Below are some bookmarklets to allow you to easily access a mini version of some of Privoxy's special pages. They are designed for MS Internet Explorer, but should work equally well in Netscape, Mozilla, and other browsers which support JavaScript. They are designed to run directly from your bookmarks - not by clicking the links below (although that should work for testing). To save them, right-click the link and choose Add to Favorites (IE) or Add Bookmark (Netscape). You will get a warning that the bookmark may not be safe - just click OK. Then you can run the Bookmarklet directly from your favorites/bookmarks. For even faster access, you can put them on the Links bar (IE) or the Personal Toolbar (Netscape), and run them with a single click. Privoxy - Enable Privoxy - Disable Privoxy - Toggle Privoxy (Toggles between enabled and disabled) Privoxy- View Status Privoxy - Why? Credit: The site which gave us the general idea for these bookmarklets is www.bookmarklets.com. They have more information about bookmarklets.
    Chain of Events Let's take a quick look at how some of Privoxy's core features are triggered, and the ensuing sequence of events when a web page is requested by your browser: First, your web browser requests a web page. The browser knows to send the request to Privoxy, which will in turn, relay the request to the remote web server after passing the following tests: Privoxy traps any request for its own internal CGI pages (e.g http://p.p/) and sends the CGI page back to the browser. Next, Privoxy checks to see if the URL matches any +block patterns. If so, the URL is then blocked, and the remote web server will not be contacted. +handle-as-image and +handle-as-empty-document are then checked, and if there is no match, an HTML BLOCKED page is sent back to the browser. Otherwise, if it does match, an image is returned for the former, and an empty text document for the latter. The type of image would depend on the setting of +set-image-blocker (blank, checkerboard pattern, or an HTTP redirect to an image elsewhere). Untrusted URLs are blocked. If URLs are being added to the trust file, then that is done. If the URL pattern matches the +fast-redirects action, it is then processed. Unwanted parts of the requested URL are stripped. Now the rest of the client browser's request headers are processed. If any of these match any of the relevant actions (e.g. +hide-user-agent, etc.), headers are suppressed or forged as determined by these actions and their parameters. Now the web server starts sending its response back (i.e. typically a web page). First, the server headers are read and processed to determine, among other things, the MIME type (document type) and encoding. The headers are then filtered as determined by the +crunch-incoming-cookies, +session-cookies-only, and +downgrade-http-version actions. If any +filter action or +deanimate-gifs action applies (and the document type fits the action), the rest of the page is read into memory (up to a configurable limit). Then the filter rules (from default.filter and any other filter files) are processed against the buffered content. Filters are applied in the order they are specified in one of the filter files. Animated GIFs, if present, are reduced to either the first or last frame, depending on the action setting.The entire page, which is now filtered, is then sent by Privoxy back to your browser. If neither a +filter action or +deanimate-gifs matches, then Privoxy passes the raw data through to the client browser as it becomes available. As the browser receives the now (possibly filtered) page content, it reads and then requests any URLs that may be embedded within the page source, e.g. ad images, stylesheets, JavaScript, other HTML documents (e.g. frames), sounds, etc. For each of these objects, the browser issues a separate request (this is easily viewable in Privoxy's logs). And each such request is in turn processed just as above. Note that a complex web page will have many, many such embedded URLs. If these secondary requests are to a different server, then quite possibly a very differing set of actions is triggered. NOTE: This is somewhat of a simplistic overview of what happens with each URL request. For the sake of brevity and simplicity, we have focused on Privoxy's core features only. Troubleshooting: Anatomy of an Action The way Privoxy applies actions and filters to any given URL can be complex, and not always so easy to understand what is happening. And sometimes we need to be able to see just what Privoxy is doing. Especially, if something Privoxy is doing is causing us a problem inadvertently. It can be a little daunting to look at the actions and filters files themselves, since they tend to be filled with regular expressions whose consequences are not always so obvious. One quick test to see if Privoxy is causing a problem or not, is to disable it temporarily. This should be the first troubleshooting step. See the Bookmarklets section on a quick and easy way to do this (be sure to flush caches afterward!). Looking at the logs is a good idea too. (Note that both the toggle feature and logging are enabled via config file settings, and may need to be turned on.) Another easy troubleshooting step to try is if you have done any customization of your installation, revert back to the installed defaults and see if that helps. There are times the developers get complaints about one thing or another, and the problem is more related to a customized configuration issue. Privoxy also provides the http://config.privoxy.org/show-url-info page that can show us very specifically how actions are being applied to any given URL. This is a big help for troubleshooting. First, enter one URL (or partial URL) at the prompt, and then Privoxy will tell us how the current configuration will handle it. This will not help with filtering effects (i.e. the +filter action) from one of the filter files since this is handled very differently and not so easy to trap! It also will not tell you about any other URLs that may be embedded within the URL you are testing. For instance, images such as ads are expressed as URLs within the raw page source of HTML pages. So you will only get info for the actual URL that is pasted into the prompt area -- not any sub-URLs. If you want to know about embedded URLs like ads, you will have to dig those out of the HTML source. Use your browser's View Page Source option for this. Or right click on the ad, and grab the URL. Let's try an example, google.com, and look at it one section at a time in a sample configuration (your real configuration may vary): Matches for http://www.google.com: In file: default.action [ View ] [ Edit ] {+change-x-forwarded-for{block} +deanimate-gifs {last} +fast-redirects {check-decoded-url} +filter {refresh-tags} +filter {img-reorder} +filter {banners-by-size} +filter {webbugs} +filter {jumping-windows} +filter {ie-exploits} +hide-from-header {block} +hide-referrer {forge} +session-cookies-only +set-image-blocker {pattern} / { -session-cookies-only } .google.com { -fast-redirects } .google.com In file: user.action [ View ] [ Edit ] (no matches in this file) This is telling us how we have defined our actions, and which ones match for our test case, google.com. Displayed is all the actions that are available to us. Remember, the + sign denotes on. - denotes off. So some are on here, but many are off. Each example we try may provide a slightly different end result, depending on our configuration directives. The first listing is for our default.action file. The large, multi-line listing, is how the actions are set to match for all URLs, i.e. our default settings. If you look at your actions file, this would be the section just below the aliases section near the top. This will apply to all URLs as signified by the single forward slash at the end of the listing -- / . But we have defined additional actions that would be exceptions to these general rules, and then we list specific URLs (or patterns) that these exceptions would apply to. Last match wins. Just below this then are two explicit matches for .google.com. The first is negating our previous cookie setting, which was for +session-cookies-only (i.e. not persistent). So we will allow persistent cookies for google, at least that is how it is in this example. The second turns off any +fast-redirects action, allowing this to take place unmolested. Note that there is a leading dot here -- .google.com. This will match any hosts and sub-domains, in the google.com domain also, such as www.google.com or mail.google.com. But it would not match www.google.de! So, apparently, we have these two actions defined as exceptions to the general rules at the top somewhere in the lower part of our default.action file, and google.com is referenced somewhere in these latter sections. Then, for our user.action file, we again have no hits. So there is nothing google-specific that we might have added to our own, local configuration. If there was, those actions would over-rule any actions from previously processed files, such as default.action. user.action typically has the last word. This is the best place to put hard and fast exceptions, And finally we pull it all together in the bottom section and summarize how Privoxy is applying all its actions to google.com: Final results: -add-header -block +change-x-forwarded-for{block} -client-header-filter{hide-tor-exit-notation} -content-type-overwrite -crunch-client-header -crunch-if-none-match -crunch-incoming-cookies -crunch-outgoing-cookies -crunch-server-header +deanimate-gifs {last} -downgrade-http-version -fast-redirects -filter {js-events} -filter {content-cookies} -filter {all-popups} -filter {banners-by-link} -filter {tiny-textforms} -filter {frameset-borders} -filter {demoronizer} -filter {shockwave-flash} -filter {quicktime-kioskmode} -filter {fun} -filter {crude-parental} -filter {site-specifics} -filter {js-annoyances} -filter {html-annoyances} +filter {refresh-tags} -filter {unsolicited-popups} +filter {img-reorder} +filter {banners-by-size} +filter {webbugs} +filter {jumping-windows} +filter {ie-exploits} -filter {google} -filter {yahoo} -filter {msn} -filter {blogspot} -filter {no-ping} -force-text-mode -handle-as-empty-document -handle-as-image -hide-accept-language -hide-content-disposition +hide-from-header {block} -hide-if-modified-since +hide-referrer {forge} -hide-user-agent -limit-connect -overwrite-last-modified -prevent-compression -redirect -server-header-filter{xml-to-html} -server-header-filter{html-to-xml} -session-cookies-only +set-image-blocker {pattern} Notice the only difference here to the previous listing, is to fast-redirects and session-cookies-only, which are activated specifically for this site in our configuration, and thus show in the Final Results. Now another example, ad.doubleclick.net: { +block{Domains starts with "ad"} } ad*. { +block{Domain contains "ad"} } .ad. { +block{Doubleclick banner server} +handle-as-image } .[a-vx-z]*.doubleclick.net We'll just show the interesting part here - the explicit matches. It is matched three different times. Two +block{} sections, and a +block{} +handle-as-image, which is the expanded form of one of our aliases that had been defined as: +block-as-image. (Aliases are defined in the first section of the actions file and typically used to combine more than one action.) Any one of these would have done the trick and blocked this as an unwanted image. This is unnecessarily redundant since the last case effectively would also cover the first. No point in taking chances with these guys though ;-) Note that if you want an ad or obnoxious URL to be invisible, it should be defined as ad.doubleclick.net is done here -- as both a +block{} and an +handle-as-image. The custom alias +block-as-image just simplifies the process and make it more readable. One last example. Let's try http://www.example.net/adsl/HOWTO/. This one is giving us problems. We are getting a blank page. Hmmm ... Matches for http://www.example.net/adsl/HOWTO/: In file: default.action [ View ] [ Edit ] {-add-header -block +change-x-forwarded-for{block} -client-header-filter{hide-tor-exit-notation} -content-type-overwrite -crunch-client-header -crunch-if-none-match -crunch-incoming-cookies -crunch-outgoing-cookies -crunch-server-header +deanimate-gifs -downgrade-http-version +fast-redirects {check-decoded-url} -filter {js-events} -filter {content-cookies} -filter {all-popups} -filter {banners-by-link} -filter {tiny-textforms} -filter {frameset-borders} -filter {demoronizer} -filter {shockwave-flash} -filter {quicktime-kioskmode} -filter {fun} -filter {crude-parental} -filter {site-specifics} -filter {js-annoyances} -filter {html-annoyances} +filter {refresh-tags} -filter {unsolicited-popups} +filter {img-reorder} +filter {banners-by-size} +filter {webbugs} +filter {jumping-windows} +filter {ie-exploits} -filter {google} -filter {yahoo} -filter {msn} -filter {blogspot} -filter {no-ping} -force-text-mode -handle-as-empty-document -handle-as-image -hide-accept-language -hide-content-disposition +hide-from-header{block} +hide-referer{forge} -hide-user-agent -overwrite-last-modified +prevent-compression -redirect -server-header-filter{xml-to-html} -server-header-filter{html-to-xml} +session-cookies-only +set-image-blocker{blank} } / { +block{Path contains "ads".} +handle-as-image } /ads Ooops, the /adsl/ is matching /ads in our configuration! But we did not want this at all! Now we see why we get the blank page. It is actually triggering two different actions here, and the effects are aggregated so that the URL is blocked, and &my-app; is told to treat the block as if it were an image. But this is, of course, all wrong. We could now add a new action below this (or better in our own user.action file) that explicitly un blocks ( {-block}) paths with adsl in them (remember, last match in the configuration wins). There are various ways to handle such exceptions. Example: { -block } /adsl Now the page displays ;-) Remember to flush your browser's caches when making these kinds of changes to your configuration to insure that you get a freshly delivered page! Or, try using Shift+Reload. But now what about a situation where we get no explicit matches like we did with: { +block{Path starts with "ads".} +handle-as-image } /ads That actually was very helpful and pointed us quickly to where the problem was. If you don't get this kind of match, then it means one of the default rules in the first section of default.action is causing the problem. This would require some guesswork, and maybe a little trial and error to isolate the offending rule. One likely cause would be one of the +filter actions. These tend to be harder to troubleshoot. Try adding the URL for the site to one of aliases that turn off +filter: { shop } .quietpc.com .worldpay.com # for quietpc.com .jungle.com .scan.co.uk .forbes.com { shop } is an alias that expands to { -filter -session-cookies-only }. Or you could do your own exception to negate filtering: { -filter } # Disable ALL filter actions for sites in this section .forbes.com developer.ibm.com localhost This would turn off all filtering for these sites. This is best put in user.action, for local site exceptions. Note that when a simple domain pattern is used by itself (without the subsequent path portion), all sub-pages within that domain are included automatically in the scope of the action. Images that are inexplicably being blocked, may well be hitting the +filter{banners-by-size} rule, which assumes that images of certain sizes are ad banners (works well most of the time since these tend to be standardized). { fragile } is an alias that disables most actions that are the most likely to cause trouble. This can be used as a last resort for problem sites. { fragile } # Handle with care: easy to break mail.google. mybank.example.com Remember to flush caches! Note that the mail.google reference lacks the TLD portion (e.g. .com). This will effectively match any TLD with google in it, such as mail.google.de., just as an example. If this still does not work, you will have to go through the remaining actions one by one to find which one(s) is causing the problem.
    privoxy-3.0.21-stable/./doc/source/contacting.sgml000640 001751 001751 00000027760 12114407452 021060 0ustar00fkfk000000 000000 We value your feedback. In fact, we rely on it to improve Privoxy and its configuration. However, please note the following hints, so we can provide you with the best support. Please provide sufficient information A lot of support requests don't contain enough information and can't be solved without a lot of back and forth which causes unnecessary delays. Reading this section should help to prevent that. Before contacting us to report a problem, please try to verify that it is a Privoxy problem, and not a browser or site problem or documented behaviour that just happens to be different than what you expected. If unsure, try toggling off Privoxy, and see if the problem persists. If you are using your own custom configuration, please try the default configuration to see if the problem is configuration related. If you're having problems with a feature that is disabled by default, please ask around on the mailing list if others can reproduce the problem. If you aren't using the latest Privoxy version, the problem may have been found and fixed in the meantime. We would appreciate if you could take the time to upgrade to the latest version and verify that the problem still exists. Please be sure to provide the following information when reporting problems or requesting support: The exact Privoxy version you are using. The operating system and versions you run Privoxy on, e.g. Windows XP SP2. The name, platform, and version of the browser you were using (e.g. Internet Explorer v5.5 for Mac). The URL where the problem occurred, or some way for us to duplicate the problem (e.g. http://somesite.example.com/?somethingelse=123). Whether your version of Privoxy is one supplied by the Privoxy developers via SourceForge, or if you got your copy somewhere else. Whether you are using Privoxy together with another proxy such as Tor. If so, please temporary disable the other proxy to see if the symptoms change. Whether you are using a personal firewall product. If so, does Privoxy work without it? Any other pertinent information to help identify the problem such as config or log file excerpts (yes, you should have log file entries for each action taken). To get a meaningful logfile, please make sure that the logfile directive is being used and the following debug options are enabled (all of them): debug 1 # Log the destination for each request Privoxy let through. See also debug 1024. debug 2 # show each connection status debug 4 # show I/O status debug 8 # show header parsing debug 128 # debug redirects debug 256 # debug GIF de-animation debug 512 # Common Log Format debug 1024 # Log the destination for requests Privoxy didn't let through, and the reason why. debug 4096 # Startup banner and warnings. debug 8192 # Non-fatal errors If you are having trouble with a filter, please additionally enable debug 64 # debug regular expression filters If you are using Privoxy 3.0.17 or later and suspect that it interprets the request or the response incorrectly, please enable debug 32768 # log all data read from the network It's easy for us to ignore log messages that aren't relevant but missing log messages may make it impossible to investigate a problem. If you aren't sure which of the debug directives are relevant, please just enable all of them and let us worry about it. Note that Privoxy log files may contain sensitive information so please don't submit any logfiles you didn't read first. You can mask sensitive information as long as it's clear that you removed something. You don't have to tell us your actual name when filing a problem report, but if you don't, please use a nickname so we can differentiate between your messages and the ones entered by other "anonymous" users that may respond to your request if they have the same problem or already found a solution. Note that due to spam the trackers may not always allow to post without being logged into SourceForge. If that's the case, you are still free to create a login that isn't directly linked to your name, though. Please also check the status of your request a few days after submitting it, as we may request additional information. If you use a SF id, you should automatically get a mail when someone responds to your request. Please don't bother to add an email address when using the tracker. If you prefer to communicate through email, just use one of the mailing lists directly. If you are new to reporting problems, you might be interested in How to Report Bugs Effectively. The appendix of the Privoxy User Manual also has helpful information on understanding actions, and action debugging. Get Support For casual users, our support forum at SourceForge is probably best suited: http://sourceforge.net/tracker/?group_id=11118&atid=211118 All users are of course welcome to discuss their issues on the users mailing list, where the developers also hang around. Please don't send private support requests to individual Privoxy developers, either use the mailing lists or the support trackers. If you have to contact a Privoxy developer directly for other reasons, please send a real mail and do not bother with SourceForge's messaging system. Answers to SourceForge messages are usually bounced by SourceForge's mail server in which case the developer wasted time writing a response you don't get. From your point of view it will look like your message has been completely ignored, so this is frustrating for all parties involved. Note that the Privoxy mailing lists are moderated. Posts from unsubscribed addresses have to be accepted manually by a moderator. This may cause a delay of several days and if you use a subject that doesn't clearly mention Privoxy or one of its features, your message may be accidentally discarded as spam. If you aren't subscribed, you should therefore spend a few seconds to come up with a proper subject. Additionally you should make it clear that you want to get CC'd. Otherwise some responses will be directed to the mailing list only, and you won't see them. Reporting Problems Problems for our purposes, come in two forms: Configuration issues, such as ads that slip through, or sites that don't function properly due to one Privoxy action or another being turned on. Bugs in the programming code that makes up Privoxy, such as that might cause a crash. Reporting Ads or Other Configuration Problems Please send feedback on ads that slipped through, innocent images that were blocked, sites that don't work properly, and other configuration related problem of default.action file, to http://sourceforge.net/tracker/?group_id=11118&atid=460288, the Actions File Tracker. New, improved default.action files may occasionally be made available based on your feedback. These will be announced on the ijbswa-announce list and available from our the files section of our project page. Reporting Bugs Please report all bugs through our bug tracker: http://sourceforge.net/tracker/?group_id=11118&atid=111118. Before doing so, please make sure that the bug has not already been submitted and observe the additional hints at the top of the submit form. If already submitted, please feel free to add any info to the original report that might help to solve the issue. Request New Features You are welcome to submit ideas on new features or other proposals for improvement through our feature request tracker at http://sourceforge.net/tracker/?atid=361118&group_id=11118. Mailing Lists If you prefer to communicate through email, instead of using a web interface, feel free to use one of the mailing lists. To discuss issues that haven't been completely diagnosed yet, please use the Privoxy users list. Technically interested users and people who wish to contribute to the project are always welcome on the developers list. You can find an overview of all Privoxy-related mailing lists, including list archives, at: http://sourceforge.net/mail/?group_id=11118. privoxy-3.0.21-stable/./doc/source/license.sgml000640 001751 001751 00000002437 12114164170 020340 0ustar00fkfk000000 000000 Privoxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. Privoxy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for details. privoxy-3.0.21-stable/./doc/gpl.html000640 001751 001751 00000065565 10546014107 016216 0ustar00fkfk000000 000000 The GNU General Public License

    Website · Manual · FAQ · GPL

    Internet JUNKBUSTER License

    This document is out of date

    Development of Junkbuster is ongoing and this document is no longer current. However, it may provide some assistance. If you have problems, please use the Yahoo Groups mailing list (which includes an archive of mail), the SourceForge.net project page, or see the project's home page. Please also bear in mind that versions 2.9.x of Junkbuster are development releases, and are not production quality.

    The GNU General Public License

    We did not write the GPL: the Free Software Foundation did

    *  The GPL allows copying and changing of copyrighted documents

    The Free Software Foundation (FSF) is a non-profit institution that designed the GNU General Public License (GPL) to promote the publication of free software. The GPL is used by thousands of programmers who want to give others the right to copy and modify the source code of their programs. Millions of people benefit from this.

    We use the GPL to allow everyone to use, copy and modify the Internet Junkbuster as they wish. Companies can use it for commercial purposes, but they are not permitted to use it in products that they claim as their property.

    The GPL can also be used on documents written in human languages. This documentation for the Internet Junkbuster is also under the GPL. This means that you do not have to break copyright laws in order to print a page or email a screen of the text to someone, for example.

    The remainder of this page is the text of the GPL. As legal documents go it's relatively clear, but unfortunately it's fairly long because it has to cover a lot of details. The HTML formatting is ours, and should not be misinterpreted as changing the license in any way.

    --- Back to Top of Page ---

    Version 2, June 1991

    Copyright 1989, 1991
    Free Software Foundation, Inc.
    675 Mass Ave.
    Cambridge, MA 02139
    USA
    Everyone

    is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

    *  Preamble

    The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

    When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

    To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

    For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

    We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

    Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

    Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

    The precise terms and conditions for copying, distribution and modification follow.

    *  GNU General Public License: Terms and Conditions for Copying, Distribution and Modification

    O. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

    Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program).

    Whether that is true depends on what the Program does.

    1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

      You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

    2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
      1. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
      2. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
      3. If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

      These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

      Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

      In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

    3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
      1. Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
      2. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
      3. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

      The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

      If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

    4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
    5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
    6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
    7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

      If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

      It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

      This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

    8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
    9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
    10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

      NO WARRANTY

    11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
    12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

    END OF TERMS AND CONDITIONS

    *  Appendix: How to Apply These Terms to Your New Programs

    If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

    To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author>

    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    Also add information on how to contact you by electronic and paper mail.

    If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.

    The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.

    You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:

    Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989
    Ty Coon, President of Vice

    This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.

    --- Back to Top of Page ---

    Website · Manual · FAQ · GPL

    Copyright © 1996-8 Junkbusters ® Corporation. Copyright © 2001 Jon Foster. Copying and distribution permitted under the GNU General Public License. The text of the GNU GPL itself is copyrighted by the FSF, and may be copied but not modified.

    http://sourceforge.net/projects/ijbswa/

    privoxy-3.0.21-stable/./doc/webserver/faq/copyright.html000640 001751 001751 00000013307 12114164411 022177 0ustar00fkfk000000 000000 Privoxy Copyright, License and History

    7. Privoxy Copyright, License and History

    Copyright © 2001-2013 by Privoxy Developers

    Some source code is based on code Copyright © 1997 by Anonymous Coders and Junkbusters, Inc. and licensed under the GNU General Public License.

    Portions of this document are "borrowed" from the original Junkbuster (tm) FAQ, and modified as appropriate for Privoxy.

    7.1. License

    Privoxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation.

    Privoxy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for details.

    7.2. History

    A long time ago, there was the Internet Junkbuster, by Anonymous Coders and Junkbusters Corporation. This saved many users a lot of pain in the early days of web advertising and user tracking.

    But the web, its protocols and standards, and with it, the techniques for forcing ads on users, give up autonomy over their browsing, and for tracking them, keeps evolving. Unfortunately, the Internet Junkbuster did not. Version 2.0.2, published in 1998, was the last official release, available from Junkbusters Corporation. Fortunately, it had been released under the GNU GPL, which allowed further development by others.

    So Stefan Waldherr started maintaining an improved version of the software, to which eventually a number of people contributed patches. It could already replace banners with a transparent image, and had a first version of pop-up killing, but it was still very closely based on the original, with all its limitations, such as the lack of HTTP/1.1 support, flexible per-site configuration, or content modification. The last release from this effort was version 2.0.2-10, published in 2000.

    Then, some developers picked up the thread, and started turning the software inside out, upside down, and then reassembled it, adding many new features along the way.

    The result of this is Privoxy, whose first stable version, 3.0, was released August, 2002.

    As of 2012 the Junkbusters Corporation's website (http://www.junkbusters.com/) has been shut down, but Privoxy is still actively maintained.

    privoxy-3.0.21-stable/./doc/webserver/faq/misc.html000640 001751 001751 00000124063 12040771132 021126 0ustar00fkfk000000 000000 Miscellaneous

    4. Miscellaneous

    4.1. How much does Privoxy slow my browsing down? This has to add extra time to browsing.

    How much of an impact depends on many things, including the CPU of the host system, how aggressive the configuration is, which specific actions are being triggered, the size of the page, the bandwidth of the connection, etc.

    Overall, it should not slow you down any in real terms, and may actually help speed things up since ads, banners and other junk are not typically being retrieved and displayed. The actual processing time required by Privoxy itself for each page, is relatively small in the overall scheme of things, and happens very quickly. This is typically more than offset by time saved not downloading and rendering ad images and other junk content (if ad blocking is being used).

    "Filtering" content via the filter or deanimate-gifs actions may cause a perceived slowdown, since the entire document needs to be buffered before displaying. And on very large documents, filtering may have some measurable impact. How much depends on the page size, the actual definition of the filter(s), etc. See below. Most other actions have little to no impact on speed.

    Also, when filtering is enabled but zlib support isn't available, compression is often disabled (see prevent-compression). This can have an impact on speed as well, although it's probably smaller than you might think. Again, the page size, etc. will determine how much of an impact.

    4.2. I notice considerable delays in page requests. What's wrong?

    If you use any filter action, such as filtering banners by size, web-bugs etc, or the deanimate-gifs action, the entire document must be loaded into memory in order for the filtering mechanism to work, and nothing is sent to the browser during this time.

    The loading time typically does not really change much in real numbers, but the feeling is different, because most browsers are able to start rendering incomplete content, giving the user a feeling of "it works". This effect is more noticeable on slower dialup connections. Extremely large documents may have some impact on the time to load the page where there is filtering being done. But overall, the difference should be very minimal. If there is a big impact, then probably some other situation is contributing (like anti-virus software).

    Filtering is automatically disabled for inappropriate MIME types. But note that if the web server mis-reports the MIME type, then content that should not be filtered, could be. Privoxy only knows how to differentiate filterable content because of the MIME type as reported by the server, or because of some configuration setting that enables/disables filtering.

    4.3. What are "http://config.privoxy.org/" and "http://p.p/"?

    http://config.privoxy.org/ is the address of Privoxy's built-in user interface, and http://p.p/ is a shortcut for it.

    Since Privoxy sits between your web browser and the Internet, it can simply intercept requests for these addresses and answer them with its built-in "web server".

    This also makes for a good test for your browser configuration: If entering the URL http://config.privoxy.org/ takes you to a page saying "This is Privoxy ...", everything is OK. If you get a page saying "Privoxy is not working" instead, then your browser didn't use Privoxy for the request, hence it could not be intercepted, and you have accessed the real web site at config.privoxy.org.

    4.4. How can I submit new ads, or report problems?

    Please see the Contact section for various ways to interact with the developers.

    4.5. If I do submit missed ads, will they be included in future updates?

    Whether such submissions are eventually included in the default.action configuration file depends on how significant the issue is. We of course want to address any potential problem with major, high-profile sites such as Google, Yahoo, etc. Any site with global or regional reach, has a good chance of being a candidate. But at the other end of the spectrum are any number of smaller, low-profile sites such as for local clubs or schools. Since their reach and impact are much less, they are best handled by inclusion in the user's user.action, and thus would be unlikely to be included.

    4.6. Why doesn't anyone answer my support request?

    Rest assured that it has been read and considered. Why it is not answered, could be for various reasons, including no one has a good answer for it, no one has had time to yet investigate it thoroughly, it has been reported numerous times already, or because not enough information was provided to help us help you. Your efforts are not wasted, and we do appreciate them.

    4.7. How can I hide my IP address?

    If you run both the browser and Privoxy locally, you cannot hide your IP address with Privoxy or ultimately any other software alone. The server needs to know your IP address so that it knows where to send the responses back.

    There are many publicly usable "anonymous" proxies out there, which provide a further level of indirection between you and the web server.

    However, these proxies are called "anonymous" because you don't need to authenticate, not because they would offer any real anonymity. Most of them will log your IP address and make it available to the authorities in case you violate the law of the country they run in. In fact you can't even rule out that some of them only exist to *collect* information on (those suspicious) people with a more than average preference for privacy.

    If you want to hide your IP address from most adversaries, you should consider chaining Privoxy with Tor. The configuration details can be found in How do I use Privoxy together with Tor section just below.

    4.8. Can Privoxy guarantee I am anonymous?

    No. Your chances of remaining anonymous are improved, but unless you chain Privoxy with Tor or a similar proxy and know what you're doing when it comes to configuring the rest of your system, you should assume that everything you do on the Web can be traced back to you.

    Privoxy can remove various information about you, and allows you more freedom to decide which sites you can trust, and what details you want to reveal. But it neither hides your IP address, nor can it guarantee that the rest of the system behaves correctly. There are several possibilities how a web sites can find out who you are, even if you are using a strict Privoxy configuration and chained it with Tor.

    Most of Privoxy's privacy-enhancing features can be easily subverted by an insecure browser configuration, therefore you should use a browser that can be configured to only execute code from trusted sites, and be careful which sites you trust. For example there is no point in having Privoxy modify the User-Agent header, if websites can get all the information they want through JavaScript, ActiveX, Flash, Java etc.

    A few browsers disclose the user's email address in certain situations, such as when transferring a file by FTP. Privoxy does not filter FTP. If you need this feature, or are concerned about the mail handler of your browser disclosing your email address, you might consider products such as NSClean.

    Browsers available only as binaries could use non-standard headers to give out any information they can have access to: see the manufacturer's license agreement. It's impossible to anticipate and prevent every breach of privacy that might occur. The professionally paranoid prefer browsers available as source code, because anticipating their behavior is easier. Trust the source, Luke!

    4.9. A test site says I am not using a Proxy.

    Good! Actually, they are probably testing for some other kinds of proxies. Hiding yourself completely would require additional steps.

    4.10. How do I use Privoxy together with Tor?

    Before you configure Privoxy to use Tor, please follow the User Manual chapters 2. Installation and 5. Startup to make sure Privoxy itself is setup correctly.

    If it is, refer to Tor's extensive documentation to learn how to install Tor, and make sure Tor's logfile says that "Tor has successfully opened a circuit" and it "looks like client functionality is working".

    If either Tor or Privoxy isn't working, their combination most likely will neither. Testing them on their own will also help you to direct problem reports to the right audience. If Privoxy isn't working, don't bother the Tor developers. If Tor isn't working, don't send bug reports to the Privoxy Team.

    If you verified that Privoxy and Tor are working, it is time to connect them. As far as Privoxy is concerned, Tor is just another proxy that can be reached by socks4, socks4a and socks5. Most likely you are interested in Tor to increase your anonymity level, therefore you should use socks5, to make sure DNS requests are done through Tor and thus invisible to your local network. Using socks4a would work too, but with socks5 you get more precise error messages.

    Since Privoxy 3.0.5, its main configuration file is already prepared for Tor, if you are using a default Tor configuration and run it on the same system as Privoxy, you just have to edit the forwarding section and uncomment the line:

    #        forward-socks5             /     127.0.0.1:9050 .
    
    

    This is enough to reach the Internet, but additionally you might want to uncomment the following forward rules, to make sure your local network is still reachable through Privoxy:

    #        forward         192.168.*.*/     .
    #        forward            10.*.*.*/     .
    #        forward           127.*.*.*/     .
    
    

    Unencrypted connections to systems in these address ranges will be as (un)secure as the local network is, but the alternative is that your browser can't reach the network at all. Then again, that may actually be desired and if you don't know for sure that your browser has to be able to reach the local network, there's no reason to allow it.

    If you want your browser to be able to reach servers in your local network by using their names, you will need additional exceptions that look like this:

    #        forward           localhost/     .
    
    

    Save the modified configuration file and open http://config.privoxy.org/show-status in your browser, confirm that Privoxy has reloaded its configuration and that there are no other forward lines, unless you know that you need them. If everything looks good, refer to Tor Faq 4.2 to learn how to verify that you are really using Tor.

    Afterward, please take the time to at least skim through the rest of Tor's documentation. Make sure you understand what Tor does, why it is no replacement for application level security, and why you probably don't want to use it for unencrypted logins.

    4.11. Might some things break because header information or content is being altered?

    Definitely. It is common for sites to use browser type, browser version, HTTP header content, and various other techniques in order to dynamically decide what to display and how to display it. What you see, and what I see, might be very different. There are many, many ways that this can be handled, so having hard and fast rules, is tricky.

    The "User-Agent" is sometimes used in this way to identify the browser, and adjust content accordingly.

    Also, different browsers use different encodings of non-English characters, certain web servers convert pages on-the-fly according to the User Agent header. Giving a "User Agent" with the wrong operating system or browser manufacturer causes some sites in these languages to be garbled; Surfers to Eastern European sites should change it to something closer. And then some page access counters work by looking at the "Referer" header; they may fail or break if unavailable. The weather maps of Intellicast have been blocked by their server when no "Referer" or cookie is provided, is another example. (But you can forge both headers without giving information away). There are many other ways things can go wrong when trying to fool a web server. The results of which could inadvertently cause pages to load incorrectly, partially, or even not at all. And there may be no obvious clues as to just what went wrong, or why. Nowhere will there be a message that says "Turn off fast-redirects or else! "

    Similar thoughts apply to modifying JavaScript, and, to a lesser degree, HTML elements.

    If you have problems with a site, you will have to adjust your configuration accordingly. Cookies are probably the most likely adjustment that may be required, but by no means the only one.

    4.12. Can Privoxy act as a "caching" proxy to speed up web browsing?

    No, it does not have this ability at all. You want something like Squid or Polipo for this. And, yes, before you ask, Privoxy can co-exist with other kinds of proxies like Squid. See the forwarding chapter in the user manual for details.

    4.13. What about as a firewall? Can Privoxy protect me?

    Not in the way you mean, or in the way some firewall vendors claim they can. Privoxy can help protect your privacy, but can't protect your system from intrusion attempts. It is, of course, perfectly possible to use both.

    4.14. I have large empty spaces / a checkerboard pattern now where ads used to be. Why?

    It is technically possible to eliminate banners and ads in a way that frees their allocated page space. This could easily be done by blocking with Privoxy's filters, and eliminating the entire image references from the HTML page source.

    But, this would consume considerably more CPU resources (IOW, slow things down), would likely destroy the layout of some web pages which rely on the banners utilizing a certain amount of page space, and might fail in other cases, where the screen space is reserved (e.g. by HTML tables for instance). Also, making ads and banners disappear without any trace complicates troubleshooting, and would sooner or later be problematic.

    The better alternative is to instead let them stay, and block the resulting requests for the banners themselves as is now the case. This leaves either empty space, or the familiar checkerboard pattern.

    So the developers won't support this in the default configuration, but you can of course define appropriate filters yourself to achieve this.

    4.15. How can Privoxy filter Secure (HTTPS) URLs?

    Since secure HTTP connections are encrypted SSL sessions between your browser and the secure site, and are meant to be reliably secure, there is little that Privoxy can do but hand the raw gibberish data though from one end to the other unprocessed.

    The only exception to this is blocking by host patterns, as the client needs to tell Privoxy the name of the remote server, so that Privoxy can establish the connection. If that name matches a host-only pattern, the connection will be blocked.

    As far as ad blocking is concerned, this is less of a restriction than it may seem, since ad sources are often identifiable by the host name, and often the banners to be placed in an encrypted page come unencrypted nonetheless for efficiency reasons, which exposes them to the full power of Privoxy's ad blocking.

    "Content cookies" (those that are embedded in the actual HTML or JS page content, see filter{content-cookies}), in an SSL transaction will be impossible to block under these conditions. Fortunately, this does not seem to be a very common scenario since most cookies come by traditional means.

    4.16. Privoxy runs as a "server". How secure is it? Do I need to take any special precautions?

    On Unix-like systems, Privoxy can run as a non-privileged user, which is how we recommend it be run. Also, by default Privoxy listens to requests from "localhost" only.

    The server aspect of Privoxy is not itself directly exposed to the Internet in this configuration. If you want to have Privoxy serve as a LAN proxy, this will have to be opened up to allow for LAN requests. In this case, we'd recommend you specify only the LAN gateway address, e.g. 192.168.1.1, in the main Privoxy configuration file and check all access control and security options. All LAN hosts can then use this as their proxy address in the browser proxy configuration, but Privoxy will not listen on any external interfaces. ACLs can be defined in addition, and using a firewall is always good too. Better safe than sorry.

    4.17. Can I temporarily disable Privoxy?

    Privoxy doesn't have a transparent proxy mode, but you can toggle off blocking and content filtering.

    The easiest way to do that is to point your browser to the remote toggle URL: http://config.privoxy.org/toggle.

    See the Bookmarklets section of the User Manual for an easy way to access this feature. Note that this is a feature that may need to be enabled in the main config file.

    4.18. When "disabled" is Privoxy totally out of the picture?

    No, this just means all optional filtering and actions are disabled. Privoxy is still acting as a proxy, but just doing less of the things that Privoxy would normally be expected to do. It is still a "middle-man" in the interaction between your browser and web sites. See below to bypass the proxy.

    4.19. How can I tell Privoxy to totally ignore certain sites?

    Bypassing a proxy, or proxying based on arbitrary criteria, is purely a browser configuration issue, not a Privoxy issue. Modern browsers typically do have settings for not proxying certain sites. Check your browser's help files.

    4.20. My logs show Privoxy "crunches" ads, but also its own internal CGI pages. What is a "crunch"?

    A "crunch" simply means Privoxy intercepted something, nothing more. Often this is indeed ads or banners, but Privoxy uses the same mechanism for trapping requests for its own internal pages. For instance, a request for Privoxy's configuration page at: http://config.privoxy.org, is intercepted (i.e. it does not go out to the 'net), and the familiar CGI configuration is returned to the browser, and the log consequently will show a "crunch".

    Since version 3.0.7, Privoxy will also log the crunch reason. If you are using an older version you might want to upgrade.

    4.21. Can Privoxy effect files that I download from a webserver? FTP server?

    From the webserver's perspective, there is no difference between viewing a document (i.e. a page), and downloading a file. The same is true of Privoxy. If there is a match for a block pattern, it will still be blocked, and of course this is obvious.

    Filtering is potentially more of a concern since the results are not always so obvious, and the effects of filtering are there whether the file is simply viewed, or downloaded. And potentially whether the content is some obnoxious advertisement, or Mr. Jimmy's latest/greatest source code jewel. Of course, one of these presumably is "bad" content that we don't want, and the other is "good" content that we do want. Privoxy is blind to the differences, and can only distinguish "good from bad" by the configuration parameters we give it.

    Privoxy knows the differences in files according to the "Content Type" as reported by the webserver. If this is reported accurately (e.g. "application/zip" for a zip archive), then Privoxy knows to ignore these where appropriate. Privoxy potentially can filter HTML as well as plain text documents, subject to configuration parameters of course. Also, documents that are of an unknown type (generally assumed to be "text/plain") can be filtered, as will those that might be incorrectly reported by the webserver. If such a file is a downloaded file that is intended to be saved to disk, then any content that might have been altered by filtering, will be saved too, for these (probably rare) cases.

    Note that versions later than 3.0.2 do NOT filter document types reported as "text/plain". Prior to this, Privoxy did filter this document type.

    In short, filtering is "ON" if a) the content type as reported by the webserver is appropriate and b) the configuration allows it (or at least does not disallow it). That's it. There is no magic cookie anywhere to say this is "good" and this is "bad". It's the configuration that lets it all happen or not.

    If you download text files, you probably do not want these to be filtered, particularly if the content is source code, or other critical content. Source code sometimes might be mistaken for Javascript (i.e. the kind that might open a pop-up window). It is recommended to turn off filtering for download sites (particularly if the content may be plain text files and you are using version 3.0.2 or earlier) in your user.action file. And also, for any site or page where making any changes at all to the content is to be avoided.

    Privoxy does not do FTP at all, only HTTP and HTTPS (SSL) protocols.

    4.23. Should I continue to use a "HOSTS" file for ad-blocking?

    One time-tested technique to defeat common ads is to trick the local DNS system by giving a phony IP address for the ad generator in the local HOSTS file, typically using 127.0.0.1, aka localhost. This effectively blocks the ad.

    There is no reason to use this technique in conjunction with Privoxy. Privoxy does essentially the same thing, much more elegantly and with much more flexibility. A large HOSTS file, in fact, not only duplicates effort, but may get in the way and seriously slow down your system. It is recommended to remove such entries from your HOSTS file. If you think your hosts list is neglected by Privoxy's configuration, consider adding your list to your user.action file:

      { +block }
       www.ad.example1.com
       ad.example2.com
       ads.galore.example.com
       etc.example.com
    

    4.24. Where can I find more information about Privoxy and related issues?

    Other references and sites of interest to Privoxy users:

    http://www.privoxy.org/, the Privoxy Home page.
    http://www.privoxy.org/faq/, the Privoxy FAQ.
    http://www.privoxy.org/developer-manual/, the Privoxy developer manual.
    https://sourceforge.net/projects/ijbswa/, the Project Page for Privoxy on SourceForge.
    http://config.privoxy.org/, the web-based user interface. Privoxy must be running for this to work. Shortcut: http://p.p/
    https://sourceforge.net/tracker/?group_id=11118&atid=460288, to submit "misses" and other configuration related suggestions to the developers.
    http://www.squid-cache.org/, a popular caching proxy, which is often used together with Privoxy.
    http://www.pps.jussieu.fr/~jch/software/polipo/, Polipo is a caching proxy with advanced features like pipelining, multiplexing and caching of partial instances. In many setups it can be used as Squid replacement.
    https://www.torproject.org/, Tor can help anonymize web browsing, web publishing, instant messaging, IRC, SSH, and other applications.

    4.25. I've noticed that Privoxy changes "Microsoft" to "MicroSuck"! Why are you manipulating my browsing?

    We're not. The text substitutions that you are seeing are disabled in the default configuration as shipped. You have either manually activated the "fun" filter which is clearly labeled "Text replacements for subversive browsing fun!" or you are using an older Privoxy version and have implicitly activated it by choosing the "Advanced" profile in the web-based editor. Please upgrade.

    4.26. Does Privoxy produce "valid" HTML (or XHTML)?

    Privoxy generates HTML in both its own "templates", and possibly whenever there are text substitutions via a Privoxy filter. While this should always conform to the HTML 4.01 specifications, it has not been validated against this or any other standard.

    4.27. How did you manage to get Privoxy on my computer without my consent?

    We didn't. We make Privoxy available for download, but we don't go around installing it on other people's systems behind their back. If you discover Privoxy running on your system and are sure you didn't install it yourself, somebody else did. You may not even be running the real Privoxy, but maybe something else that only pretends to be Privoxy, or maybe something that is based on the real Privoxy, but has been modified.

    Lately there have been reports of problems with some kind of Privoxy versions that come preinstalled on some Netbooks. Some of the problems described are inconsistent with the behaviour of official Privoxy versions, which suggests that the preinstalled software may contain vendor modifications that we don't know about and thus can't debug.

    Privoxy's license allows vendor modifications, but the vendor has to comply with the license, which involves informing the user about the changes and to make the changes available under the same license as Privoxy itself.

    If you are having trouble with a modified Privoxy version, please try to talk to whoever made the modifications before reporting the problem to us. Please also try to convince whoever made the modifications to talk to us. If you think somebody gave you a modified Privoxy version without complying to the license, please let us know.

    privoxy-3.0.21-stable/./doc/webserver/faq/trouble.html000640 001751 001751 00000105056 12040771132 021650 0ustar00fkfk000000 000000 Troubleshooting

    5. Troubleshooting

    5.1. I cannot connect to any websites. Or, I am getting "connection refused" message with every web page. Why?

    There are several possibilities:

    • Privoxy is not running. Solution: verify that Privoxy is installed correctly, has not crashed, and is indeed running. Turn on Privoxy's logging, and look at the logs to see what they say.

    • Or your browser is configured for a different port than what Privoxy is using. Solution: verify that Privoxy and your browser are set to the same port (listen-address).

    • Or if using a forwarding rule, you have a configuration problem or a problem with a host in the forwarding chain. Solution: temporarily alter your configuration and take the forwarders out of the equation.

    • Or you have a firewall that is interfering and blocking you. Solution: try disabling or removing the firewall as a simple test.

    5.2. Why am I getting a 503 Error (WSAECONNREFUSED) on every page?

    More than likely this is a problem with your TCP/IP networking. ZoneAlarm has been reported to cause this symptom -- even if not running! The solution is to either fight the ZA configuration, or uninstall ZoneAlarm, and then find something better behaved in its place. Other personal firewall type products may cause similar type problems if not configured correctly.

    5.3. I just added a new rule, but the steenkin ad is still getting through. How?

    If the ad had been displayed before you added its URL, it will probably be held in the browser's cache for some time, so it will be displayed without the need for any request to the server, and Privoxy will not be involved. Flush the browser's caches, and then try again.

    If this doesn't help, you probably have an error in the rule you applied. Try pasting the full URL of the offending ad into http://config.privoxy.org/show-url-info and see if it really matches your new rule. Blocking ads is like blocking spam: a lot of tinkering is required to stay ahead of the game. And remember you need to block the URL of the ad in question, which may be entirely different from the site URL itself. Most ads are hosted on different servers than the main site itself. If you right-click on the ad, you should be able to get all the relevant information you need. Alternately, you can find the correct URL by looking at Privoxy's logs (you may need to enable logging in the main config file if its disabled).

    Below is a slightly modified real-life log snippet that originates with one requested URL: www.example.com (name of site was changed for this example, the number of requests is real). You can see in this the complexity of what goes into making up this one "page". There are eight different domains involved here, with thirty two separate URLs requested in all, making up all manner of images, Shockwave Flash, JavaScript, CSS stylesheets, scripts, and other related content. Some of this content is obviously "good" or "bad", but not all. Many of the more questionable looking requests, are going to outside domains that seem to be identifying themselves with suspicious looking names, making our job a little easier. Privoxy has "crunched" (meaning caught and BLOCKED) quite a few items in this example, but perhaps missed a few as well.

    Request: www.example.com/
    Request: www.example.com/favicon.ico
    Request: img.example.com/main.css
    Request: img.example.com/sr.js
    Request: example.betamarker.com/example.html
    Request: www.lik-sang.com/Banners/bestsellers/skyscraper.php?likref=BSellers
    Request: img.example.com/pb.png
    Request: www.google-analytics.com/urchin.js crunch! (Blocked)
    Request: www.advertising-department.com/ats/switch.ps.php?26856 crunch! (Blocked)
    Request: img.example.com/p.gif
    Request: www.popuptraffic.com/assign.php?l=example&mode=behind crunch! (Blocked)
    Request: www.popuptraffic.com/scripts/popup.php?hid=5c3cf&tmpl=PBa.tmpl crunch! (Blocked)
    Request: www.popuptraffic.com/assign.php?l=example crunch! (Blocked)
    Request: www.lik-sang.com/Banners/best_sellers/best_sellers.css
    Request: www.adtrak.net/adx.js crunch! (Blocked)
    Request: img.example.com/hbg.gif
    Request: img.example.com/example.jpg
    Request: img.example.com/mt.png
    Request: img.example.com/mm.png
    Request: img.example.com/mb.png
    Request: www.popuptraffic.com/scripts/popup.php?hid=a71b91fa5&tmpl=Ua.tmp crunch! (Blocked)
    Request: www.example.com/tracker.js
    Request: www.lik-sang.com/Banners/best_sellers/lsi_head.gif
    Request: www.adtrak.net/adjs.php?n=020548130&what=zone:61 crunch! (Blocked)
    Request: www.adtrak.net/adjs.php?n=463594413&what=zone:58&source=Ua crunch! (Blocked)
    Request: www.lik-sang.com/Banners/best_sellers/bottomani.swf
    Request: mmm.elitemediagroup.net/install.php?allowpop=no&popupmincook=0&allowsp2=1 crunch! (Blocked)
    Request: www.example.com/tracker.js?screen=1400x1050&win=962x693
    Request: www.adtrak.net/adlog.php?bannerid=1309&clientid=439&zoneid=61 crunch! (Blocked)
    Request: 66.70.21.80/scripts/click.php?hid=5c3cf599a9efd0320d26&si
    Request: 66.70.21.80/img/pixel.gif
    Request: www.adtrak.net/adlog.php?bannerid=1309&clientid=439&zoneid=58&source=Ua&block=86400 crunch! (Blocked)
    Request: 66.70.21.80/scripts/click.php?hid=a71b9f6504b0c5681fa5&si=Ua
    

    Despite 12 out of 32 requests being blocked, the page looked, and seemed to behave perfectly "normal" (minus some ads, of course).

    5.4. One of my favorite sites does not work with Privoxy. What can I do?

    First verify that it is indeed a Privoxy problem, by toggling off Privoxy through http://config.privoxy.org/toggle (the toggle feature may need to be enabled in the main config), and then shift-reloading the problem page (i.e. holding down the shift key while clicking reload. Alternatively, flush your browser's disk and memory caches).

    If the problem went away, we know we have a configuration related problem. Now go to http://config.privoxy.org/show-url-info and paste the full URL of the page in question into the prompt. See which actions are being applied to the URL, and which matches in which actions files are responsible for that. It might be helpful also to look at your logs for this site too, to see what else might be happening (note: logging may need to be enabled in the main config file). Many sites are complex and require a number of related pages to help present their content. Look at what else might be used by the page in question, and what of that might be required. Now, armed with this information, go to http://config.privoxy.org/show-status and select the appropriate actions files for editing.

    You can now either look for a section which disables the actions that you suspect to cause the problem and add a pattern for your site there, or make up a completely new section for your site. In any case, the recommended way is to disable only the prime suspect, reload the problem page, and only if the problem persists, disable more and more actions until you have identified the culprit. You may or may not want to turn the other actions on again. Remember to flush your browser's caches in between any such changes!

    Alternately, if you are comfortable with a text editor, you can accomplish the same thing by editing the appropriate actions file. Probably the easiest way to deal with such problems when editing by hand is to add your site to a { fragile } section in user.action, which is an alias that turns off most "dangerous" actions, but is also likely to turn off more actions then needed, and thus lower your privacy and protection more than necessary,

    Troubleshooting actions is discussed in more detail in the User Manual appendix, Troubleshooting: the Anatomy of an Action. There is also an actions tutorial with general configuration information and examples.

    As a last resort, you can always see if your browser has a setting that will bypass the proxy setting for selective sites. Modern browsers can do this.

    5.5. After installing Privoxy, I have to log in every time I start IE. What gives?

    This is a quirk that effects the installation of Privoxy, in conjunction with Internet Explorer and Internet Connection Sharing on Windows 2000 and Windows XP. The symptoms may appear to be corrupted or invalid DUN settings, or passwords.

    When setting up an NT based Windows system with Privoxy you may find that things do not seem to be doing what you expect. When you set your system up you will probably have set up Internet Connection Sharing (ICS) with Dial up Networking (DUN) when logged in with administrator privileges. You will probably have made this DUN connection available to other accounts that you may have set-up on your system. E.g. Mum or Dad sets up the system and makes accounts suitably configured for the kids.

    When setting up Privoxy in this environment you will have to alter the proxy set-up of Internet Explorer (IE) for the specific DUN connection on which you wish to use Privoxy. When you do this the ICS DUN set-up becomes user specific. In this instance you will see no difference if you change the DUN connection under the account used to set-up the connection. However when you do this from another user you will notice that the DUN connection changes to make available to "Me only". You will also find that you have to store the password under each different user!

    The reason for this is that each user's set-up for IE is user specific. Each set-up DUN connection and each LAN connection in IE store the settings for each user individually. As such this enforces individual configurations rather than common ones. Hence the first time you use a DUN connection after re-booting your system it may not perform as you expect, and prompt you for the password. Just set and save the password again and all should be OK.

    [Thanks to Ray Griffith for this submission.]

    5.6. I cannot connect to any FTP sites. Privoxy is blocking me.

    Privoxy cannot act as a proxy for FTP traffic, so do not configure your browser to use Privoxy as an FTP proxy. The same is true for any protocol other than HTTP or HTTPS (SSL).

    Most browsers understand FTP as well as HTTP. If you connect to a site, with a URL like ftp://ftp.example.com, your browser is making an FTP connection, and not a HTTP connection. So while your browser may speak FTP, Privoxy does not, and cannot proxy such traffic.

    To complicate matters, some systems may have a generic "proxy" setting, which will enable various protocols, including both HTTP and FTP proxying! So it is possible to accidentally enable FTP proxying in these cases. And of course, if this happens, Privoxy will indeed cause problems since it does not know FTP. Newer version will give a sane error message if a FTP connection is attempted. Just disable the FTP setting and all will be well again.

    Will Privoxy ever proxy FTP traffic? Unlikely. There just is not much reason, and the work to make this happen is more than it may seem.

    5.7. In Mac OS X, I can't configure Microsoft Internet Explorer to use Privoxy as the HTTP proxy.

    Microsoft Internet Explorer (in versions like 5.1) respects system-wide network settings. In order to change the HTTP proxy, open System Preferences, and click on the Network icon. In the settings pane that comes up, click on the Proxies tab. Ensure the "Web Proxy (HTTP)" checkbox is checked and enter 127.0.0.1 in the entry field. Enter 8118 in the Port field. The next time you start IE, it should reflect these values.

    5.8. In Mac OS X, I dragged the Privoxy folder to the trash in order to uninstall it. Now the finder tells me I don't have sufficient privileges to empty the trash.

    Note: This ONLY applies to privoxy 3.0.6 and earlier.

    Just dragging the Privoxy folder to the trash is not enough to delete it. Privoxy supplies an uninstall.command file that takes care of these details. Open the trash, drag the uninstall.command file out of the trash and double-click on it. You will be prompted for confirmation and the administration password.

    The trash may still appear full after this command; emptying the trash from the desktop should make it appear empty again.

    5.9. In Mac OS X Panther (10.3), images often fail to load and/or I experience random delays in page loading. I'm using localhost as my browser's proxy setting.

    We believe this is due to an IPv6-related bug in Mac OS X, but don't fully understand the issue yet. In any case, changing the proxy setting to 127.0.0.1 instead of localhost works around the problem.

    5.10. I get a completely blank page at one site. "View Source" shows only: <html><body></body></html>. Without Privoxy the page loads fine.

    Chances are that the site suffers from a bug in PHP, which results in empty pages being sent if the client explicitly requests an uncompressed page, like Privoxy does. This bug has been fixed in PHP 4.2.3.

    To find out if this is in fact the source of the problem, try adding the site to a -prevent-compression section in user.action:

       # Make exceptions for ill-behaved sites:
       #
       {-prevent-compression}
        .example.com
    

    If that works, you may also want to report the problem to the site's webmasters, telling them to use zlib.output_compression instead of ob_gzhandler in their PHP applications (workaround) or upgrade to PHP 4.2.3 or later (fix).

    5.11. My logs show many "Unable to get my own hostname" lines. Why?

    Privoxy tries to get the hostname of the system its running on from the IP address of the system interface it is bound to (from the config file listen-address setting). If the system cannot supply this information, Privoxy logs this condition.

    Typically, this would be considered a minor system configuration error. It is not a fatal error to Privoxy however, but may result in a much slower response from Privoxy on some platforms due to DNS timeouts.

    This can be caused by a problem with the local hosts file. If this file has been changed from the original, try reverting it to see if that helps. Make sure whatever name(s) are used for the local system, that they resolve both ways.

    You should also be able to work around the problem with the hostname option.

    5.12. When I try to launch Privoxy, I get an error message "port 8118 is already in use" (or similar wording). Why?

    Port 8118 is Privoxy's default TCP "listening" port. Typically this message would mean that there is already one instance of Privoxy running, and your system is actually trying to start a second Privoxy on the same port, which will not work. (You can have multiple instances but they must be assigned different ports.) How and why this might happen varies from platform to platform, but you need to check your installation and start-up procedures.

    5.13. Pages with UTF-8 fonts are garbled.

    This is caused by the "demoronizer" filter. You should either upgrade Privoxy, or at least upgrade to the most recent default.action file available from SourceForge. Or you can simply disable the demoronizer filter.

    5.14. Why are binary files (such as images) corrupted when Privoxy is used?

    This may also be caused by the "demoronizer" filter, in conjunction with a web server that is misreporting the content type. Binary files are exempted from Privoxy's filtering (unless the web server by mistake says the file is something else). Either upgrade Privoxy, or go to the most recent default.action file available from SourceForge.

    5.15. What is the "demoronizer" and why is it there?

    The original demoronizer was a Perl script that cleaned up HTML pages which were created with certain Microsoft products. MS has used proprietary extensions to standardized font encodings (ISO 8859-1), which has caused problems for pages that are viewed with non-Microsoft products (and are expecting to see a standard set of fonts). The demoronizer corrected these errors so the pages displayed correctly. Privoxy borrowed from this script, introducing a filter based on the original demoronizer, which in turn could correct these errors on the fly.

    But this is only needed in some situations, and will cause serious problems in some other situations.

    If you are using Microsoft products, you do not need it. If you need to view pages with UTF-8 characters (such as Cyrillic or Chinese), then it will cause corruption of the fonts, and thus should not be on.

    On the other hand, if you use non-Microsoft products, and you occasionally notice weird characters on pages, you might want to try it.

    5.16. Why do I keep seeing "PrivoxyWindowOpen()" in raw source code?

    Privoxy is attempting to disable malicious Javascript in this case, with the unsolicited-popups filter. Privoxy cannot tell very well "good" code snippets from "bad" code snippets.

    If you see this in HTML source, and the page displays without problems, then this is good, and likely some pop-up window was disabled. If you see this where it is causing a problem, such as a downloaded program source code file, then you should set an exception for this site or page such that the integrity of the page stays in tact by disabling all filtering.

    5.17. I am getting too many DNS errors like "404 No Such Domain". Why can't Privoxy do this better?

    There are potentially several factors here. First of all, the DNS resolution is done by the underlying operating system -- not Privoxy itself. Privoxy merely initiates the process and hands it off, and then later reports whatever the outcome was and tries to give a coherent message if there seems to be a problem. In some cases, this might otherwise be mitigated by the browser itself which might try some work-arounds and alternate approaches (e.g adding "www." to the URL).

    In other cases, if Privoxy is being chained with another proxy, this could complicate the issue, and cause undue delays and timeouts. In the case of a "socks4a" proxy, the socks server handles all the DNS. Privoxy would just be the "messenger" which is reporting whatever problem occurred downstream, and not the root cause of the error.

    In any case, versions newer than 3.0.3 include various improvements to help Privoxy better handle these cases.

    5.18. At one site Privoxy just hangs, and starts taking all CPU. Why is this?

    This is probably a manifestation of the "100% cpu" problem that occurs on pages containing many (thousands upon thousands) of blank lines. The blank lines are in the raw HTML source of the page, and the browser just ignores them. But the pattern matching in Privoxy's page filtering mechanism is trying to match against absurdly long strings and this becomes very CPU-intensive, taking a long, long time to complete.

    Until a better solution comes along, disable filtering on these pages, particularly the js-annoyances and unsolicited-popups filters. If you run into this problem with a recent Privoxy version, please send a problem report.

    5.19. I just installed Privoxy, and all my browsing has slowed to a crawl. What gives?

    This should not happen, and for the overwhelming number of users world-wide, it does not happen. I would suspect some inadvertent interaction of software components such as anti-virus software, spyware protectors, personal firewalls or similar components. Try disabling (or uninstalling) these one at a time and see if that helps. Either way, if you are using a recent Privoxy version, please report the problem.

    5.20. Why do my filters work on some sites but not on others?

    It's probably due to compression. It is a common practice for web servers to send their content "compressed" in order to speed things up, and then let the browser "uncompress" them. When compiled with zlib support Privoxy can decompress content before filtering, otherwise you may want to enable prevent-compression.

    As of Privoxy 3.0.9, zlib support is enabled in the default builds.

    5.21. On some HTTPS sites my browser warns me about unauthenticated content, the URL bar doesn't get highlighted and the lock symbol appears to be broken. What's going on?

    Probably the browser is requesting ads through HTTPS and Privoxy is blocking the requests. Privoxy's error messages are delivered unencrypted and while it's obvious for the browser that the HTTPS request is already blocked by the proxy, some warn about unauthenticated content anyway.

    To work around the problem you can redirect those requests to an invalid local address instead of blocking them. While the redirects aren't encrypted either, many browsers don't care. They simply follow the redirect, fail to reach a server and display an error message instead of the ad.

    To do that, enable logging to figure out which requests get blocked by Privoxy and add the hosts (no path patterns) to a section like this:

    {+redirect{http://127.0.0.1:0/} -block -limit-connect}
    .ivwbox.de:443/
    

    Additionally you have to configure your browser to contact "127.0.0.1:0" directly (instead of through Privoxy).

    To add a proxy exception in Mozilla Firefox open the "Preferences", click the "Settings" button located on the "Network" tab in the "Advanced" section, and add "127.0.0.1:0" in the "No Proxy for:" field.

    5.22. I get selinux error messages. How can I fix this?

    Please report the problem to the creator of your selinux policies.

    The problem is that some selinux policy writers aren't familiar with the application they are trying to "secure" and thus create policies that make no sense.

    In Privoxy's case the problem usually is that the policy only allows outgoing connections for certain destination ports (e.g. 80 and 443). While this may cover the standard ports, websites occasionally use other ports as well. This isn't a security problem and therefore Privoxy's default configuration doesn't block these requests.

    If you really want to block these ports (and don't be able to load websites that don't use standard ports), you should configure Privoxy to block these ports as well, so it doesn't trigger the selinux warnings.

    5.23. I compiled Privoxy with Gentoo's portage and it appears to be very slow. Why?

    Probably you unintentionally compiled Privoxy without threading support in which case requests have to be serialized and only one can be served at the same time.

    Check your "USE" flags and make sure they include "threads". If they don't, add the flag and rebuild Privoxy.

    If you compiled Privoxy with threading support (on POSIX-based systems), the "Conditional #defines" section on http://config.privoxy.org/show-status will list "FEATURE_PTHREAD" as "enabled".

    privoxy-3.0.21-stable/./doc/webserver/faq/general.html000640 001751 001751 00000065010 12040771132 021604 0ustar00fkfk000000 000000 General Information

    1. General Information

    1.1. Who should give Privoxy a try?

    Anyone who is interested in security, privacy, or in finer-grained control over their web and Internet experience.

    1.2. Is Privoxy the best choice for me?

    Privoxy is certainly a good choice, especially for those who want more control and security. Those with the willingness to read the documentation and the ability to fine-tune their installation will benefit the most.

    One of Privoxy's strengths is that it is highly configurable giving you the ability to completely personalize your installation. Being familiar with, or at least having an interest in learning about HTTP and other networking protocols, HTML, and "Regular Expressions" will be a big plus and will help you get the most out of Privoxy. A new installation just includes a very basic configuration. The user should take this as a starting point only, and enhance it as he or she sees fit. In fact, the user is encouraged, and expected to, fine-tune the configuration.

    Much of Privoxy's configuration can be done with a Web browser. But there are areas where configuration is done using a text editor to edit configuration files. Also note that the web-based action editor doesn't use authentication and should only be enabled in environments where all clients with access to Privoxy listening port can be trusted.

    1.3. What is a "proxy"? How does Privoxy work?

    A web proxy is a service, based on a software such as Privoxy, that clients (i.e. browsers) can use instead of connecting to web servers directly. The clients then ask the proxy to request objects (web pages, images, movies etc) on their behalf and to forward the data to the clients. It is a "go-between". For details, see Wikipedia's proxy definition.

    There are many reasons to use web proxies, such as security (firewalling), efficiency (caching) and others, and there are any number of proxies to accommodate those needs.

    Privoxy is a proxy that is primarily focused on privacy enhancement, ad and junk elimination and freeing the user from restrictions placed on his activities. Sitting between your browser(s) and the Internet, it is in a perfect position to filter outbound personal information that your browser is leaking, as well as inbound junk. It uses a variety of techniques to do this, all of which are under your complete control via the various configuration files and options. Being a proxy also makes it easier to share configurations among multiple browsers and/or users.

    1.4. Does Privoxy do anything more than ad blocking?

    Yes, ad blocking is but one possible use. There are many, many ways Privoxy can be used to sanitize and customize web browsing.

    1.5. What is this new version of "Junkbuster"?

    A long time ago, there was the Internet Junkbuster, by Anonymous Coders and Junkbusters Corporation. This saved many users a lot of pain in the early days of web advertising and user tracking.

    But the web, its protocols and standards, and with it, the techniques for forcing ads on users, give up autonomy over their browsing, and for tracking them, keeps evolving. Unfortunately, the Internet Junkbuster did not. Version 2.0.2, published in 1998, was the last official release, available from Junkbusters Corporation. Fortunately, it had been released under the GNU GPL, which allowed further development by others.

    So Stefan Waldherr started maintaining an improved version of the software, to which eventually a number of people contributed patches. It could already replace banners with a transparent image, and had a first version of pop-up killing, but it was still very closely based on the original, with all its limitations, such as the lack of HTTP/1.1 support, flexible per-site configuration, or content modification. The last release from this effort was version 2.0.2-10, published in 2000.

    Then, some developers picked up the thread, and started turning the software inside out, upside down, and then reassembled it, adding many new features along the way.

    The result of this is Privoxy, whose first stable version, 3.0, was released August, 2002.

    As of 2012 the Junkbusters Corporation's website (http://www.junkbusters.com/) has been shut down, but Privoxy is still actively maintained.

    1.6. Why "Privoxy"? Why change the name from Junkbuster at all?

    Though outdated, Junkbusters Corporation continued to offer their original version of the Internet Junkbuster for a while, so publishing our Junkbuster-derived software under the same name would have led to confusion.

    There were also potential legal reasons not to use the Junkbuster name, as it was (and maybe still is) a registered trademark of Junkbusters Corporation. There were, however, no objections from Junkbusters Corporation to the Privoxy project itself, and they, in fact, shared our ideals and goals.

    The Privoxy developers also believed that there were so many improvements over the original code, that it was time to make a clean break from the past and make a name in their own right.

    Privoxy is the "Privacy Enhancing Proxy". Also, its content modification and junk suppression gives you, the user, more control, more freedom, and allows you to browse your personal and "private edition" of the web.

    1.7. How does Privoxy differ from the old Junkbuster?

    Privoxy picks up where Junkbuster left off. Privoxy still blocks ads and banners, still manages cookies, and still helps protect your privacy. But, most of these features have been enhanced, and many new ones have been added, all in the same vein.

    Privoxy's new features include:

    • Supports "Connection: keep-alive". Outgoing connections can be kept alive independently from the client.

    • Supports IPv6, provided the operating system does so too, and the configure script detects it.

    • Supports tagging which allows to change the behaviour based on client and server headers.

    • Can be run as an "intercepting" proxy, which obviates the need to configure browsers individually.

    • Sophisticated actions and filters for manipulating both server and client headers.

    • Can be chained with other proxies.

    • Integrated browser-based configuration and control utility at http://config.privoxy.org/ (shortcut: http://p.p/). Browser-based tracing of rule and filter effects. Remote toggling.

    • Web page filtering (text replacements, removes banners based on size, invisible "web-bugs" and HTML annoyances, etc.)

    • Modularized configuration that allows for standard settings and user settings to reside in separate files, so that installing updated actions files won't overwrite individual user settings.

    • Support for Perl Compatible Regular Expressions in the configuration files, and a more sophisticated and flexible configuration syntax.

    • GIF de-animation.

    • Bypass many click-tracking scripts (avoids script redirection).

    • User-customizable HTML templates for most proxy-generated pages (e.g. "blocked" page).

    • Auto-detection and re-reading of config file changes.

    • Most features are controllable on a per-site or per-location basis.

    • Many smaller new features added, limitations and bugs removed.

    1.8. How does Privoxy know what is an ad, and what is not?

    Privoxy's approach to blocking ads is twofold:

    First, there are certain patterns in the locations (URLs) of banner images. This applies to both the path (you wouldn't guess how many web sites serve their banners from a directory called "banners"!) and the host (blocking the big banner hosting services like doublecklick.net already helps a lot). Privoxy takes advantage of this fact by using URL patterns to sort out and block the requests for things that sound like they would be ads or banners.

    Second, banners tend to come in certain sizes. But you can't tell the size of an image by its URL without downloading it, and if you do, it's too late to save bandwidth. Therefore, Privoxy also inspects the HTML sources of web pages while they are loaded, and replaces references to images with standard banner sizes by dummy references, so that your browser doesn't request them anymore in the first place.

    Both of this involves a certain amount of guesswork and is, of course, freely and readily configurable.

    1.9. Can Privoxy make mistakes? This does not sound very scientific.

    Actually, it's a black art ;-) And yes, it is always possible to have a broad rule accidentally block or change something by mistake. You will almost surely run into such situations at some point. It is tricky writing rules to cover every conceivable possibility, and not occasionally get false positives.

    But this should not be a big concern since the Privoxy configuration is very flexible, and includes tools to help identify these types of situations so they can be addressed as needed, allowing you to customize your installation. (See the Troubleshooting section below.)

    1.10. Will I have to configure Privoxy before I can use it?

    That depends on your expectations. The default installation should give you a good starting point, and block most ads and unwanted content, but many of the more advanced features are off by default, and require you to activate them.

    You do have to set up your browser to use Privoxy (see the Installation section below).

    And you will certainly run into situations where there are false positives, or ads not being blocked that you may not want to see. In these cases, you would certainly benefit by customizing Privoxy's configuration to more closely match your individual situation. And we encourage you to do this. This is where the real power of Privoxy lies!

    1.11. Can Privoxy run as a server on a network?

    Yes, Privoxy runs as a server already, and can easily be configured to "serve" more than one client. See How can I set up Privoxy to act as a proxy for my LAN below.

    1.12. My browser does the same things as Privoxy. Why should I use Privoxy at all?

    Modern browsers do indeed have some of the same functionality as Privoxy. Maybe this is adequate for you. But Privoxy is very versatile and powerful, and can probably do a number of things your browser just can't.

    In addition, a proxy is good choice if you use multiple browsers, or have a LAN with multiple computers since Privoxy can run as a server application. This way all the configuration is in one place, and you don't have to maintain a similar configuration for possibly many browsers or users.

    Note, however, that it's recommended to leverage both your browser's and Privoxy's privacy enhancing features at the same time. While your browser probably lacks some features Privoxy offers, it should also be able to do some things more reliable, for example restricting and suppressing JavaScript.

    1.13. Why should I trust Privoxy?

    The most important reason is because you have access to everything, and you can control everything. You can check every line of every configuration file yourself. You can check every last bit of source code should you desire. And even if you can't read code, there should be some comfort in knowing that other people can, and do read it. You can build the software from scratch, if you want, so that you know the executable is clean, and that it is yours. In fact, we encourage this level of scrutiny. It is one reason we use Privoxy ourselves.

    1.14. Is there is a license or fee? What about a warranty? Registration?

    Privoxy is free software and licensed under the GNU General Public License (GPL) version 2. It is free to use, copy, modify or distribute as you wish under the terms of this license. Please see the Copyright section for more information on the license and copyright. Or the LICENSE file that should be included.

    There is no warranty of any kind, expressed, implied or otherwise. That is something that would cost real money ;-) There is no registration either.

    1.15. Can Privoxy remove spyware? Adware? Viruses?

    No, at least not reliably enough to trust it. Privoxy is not designed to be a malware removal tool and the default configuration doesn't even try to filter out any malware.

    Privoxy could help prevent contact from (known) sites that use such tactics with appropriate configuration rules, and thus could conceivably prevent contamination from such sites. However, keeping such a configuration up to date would require a lot of time and effort that would be better spend on keeping your software itself up to date so it doesn't have known vulnerabilities.

    1.16. Can I use Privoxy with other ad-blocking software?

    Privoxy should work fine with other proxies and other software in general.

    But it is probably not necessary to use Privoxy in conjunction with other ad-blocking products, and this could conceivably cause undesirable results. It might be better to choose one software or the other and work a little to tweak its configuration to your liking.

    Note that this is an advice specific to ad blocking.

    1.17. I would like to help you, what can I do?

    1.17.1. Would you like to participate?

    Well, we always need help. There is something for everybody who wants to help us. We welcome new developers, packagers, testers, documentation writers or really anyone with a desire to help in any way. You DO NOT need to be a "programmer". There are many other tasks available. In fact, the programmers often can't spend as much time programming because of some of the other, more mundane things that need to be done, like checking the Tracker feedback sections or responding to user questions on the mailing lists.

    So first thing, subscribe to the Privoxy Users or the Privoxy Developers mailing list, join the discussion, help out other users, provide general feedback or report problems you noticed.

    If you intend to help out with the trackers, you also might want to get an account on SourceForge.net so we don't confuse you with the other name-less users.

    We also have a Developer's Manual. While it is partly out of date, it's still worth reading.

    Our TODO list may be of interest to you as well. Please let us know if you want to work on one of the items listed.

    Privoxy is developed by unpaid volunteers and thus our current running costs are pretty low. Nevertheless, we have plans that will cost money in the future. They include, but aren't limited to spending money on:

    • Hardware to help make sure Privoxy keeps running on platforms the developers currently can't test on and can be ported to others.

    • Technical books to educate our developers about said platforms or to improve their knowledge in general.

    • More reliable hosting,

    We would like to get this money through donations made by our users.

    Privoxy has therefore become an associated project of Software in the Public Interest (SPI), which allows us to receive donations. In the United States they are tax-deductible, in a few other western countries they might be tax-deductible in the future.

    If you read this section before you may notice that paying for the project domain privoxy.org is no longer on the list. It has been transferred to SPI is sponsored by Mythic Beasts Ltd.

    If you enjoy our software and feel like helping out with a donation, please have a look at SPI's donation page to see what the options are. If you have any questions regarding donations please mail to either the public user mailing list or, if it's a private matter, to Fabian Keil (Privoxy's SPI liason) directly.

    privoxy-3.0.21-stable/./doc/webserver/faq/contact.html000640 001751 001751 00000037445 12114407603 021636 0ustar00fkfk000000 000000 Contacting the developers, Bug Reporting and Feature Requests

    6. Contacting the developers, Bug Reporting and Feature Requests

    We value your feedback. In fact, we rely on it to improve Privoxy and its configuration. However, please note the following hints, so we can provide you with the best support.

    6.1. Please provide sufficient information

    A lot of support requests don't contain enough information and can't be solved without a lot of back and forth which causes unnecessary delays. Reading this section should help to prevent that.

    Before contacting us to report a problem, please try to verify that it is a Privoxy problem, and not a browser or site problem or documented behaviour that just happens to be different than what you expected. If unsure, try toggling off Privoxy, and see if the problem persists.

    If you are using your own custom configuration, please try the default configuration to see if the problem is configuration related. If you're having problems with a feature that is disabled by default, please ask around on the mailing list if others can reproduce the problem.

    If you aren't using the latest Privoxy version, the problem may have been found and fixed in the meantime. We would appreciate if you could take the time to upgrade to the latest version and verify that the problem still exists.

    Please be sure to provide the following information when reporting problems or requesting support:

    • The exact Privoxy version you are using.

    • The operating system and versions you run Privoxy on, e.g. Windows XP SP2.

    • The name, platform, and version of the browser you were using (e.g. Internet Explorer v5.5 for Mac).

    • The URL where the problem occurred, or some way for us to duplicate the problem (e.g. http://somesite.example.com/?somethingelse=123).

    • Whether your version of Privoxy is one supplied by the Privoxy developers via SourceForge, or if you got your copy somewhere else.

    • Whether you are using Privoxy together with another proxy such as Tor. If so, please temporary disable the other proxy to see if the symptoms change.

    • Whether you are using a personal firewall product. If so, does Privoxy work without it?

    • Any other pertinent information to help identify the problem such as config or log file excerpts (yes, you should have log file entries for each action taken). To get a meaningful logfile, please make sure that the logfile directive is being used and the following debug options are enabled (all of them):

      debug     1 # Log the destination for each request Privoxy let through. See also debug 1024.
      debug     2 # show each connection status
      debug     4 # show I/O status
      debug     8 # show header parsing
      debug   128 # debug redirects
      debug   256 # debug GIF de-animation
      debug   512 # Common Log Format
      debug  1024 # Log the destination for requests Privoxy didn't let through, and the reason why.
      debug  4096 # Startup banner and warnings.
      debug  8192 # Non-fatal errors

      If you are having trouble with a filter, please additionally enable

      debug    64 # debug regular expression filters

      If you are using Privoxy 3.0.17 or later and suspect that it interprets the request or the response incorrectly, please enable

      debug 32768 # log all data read from the network

      It's easy for us to ignore log messages that aren't relevant but missing log messages may make it impossible to investigate a problem. If you aren't sure which of the debug directives are relevant, please just enable all of them and let us worry about it.

      Note that Privoxy log files may contain sensitive information so please don't submit any logfiles you didn't read first. You can mask sensitive information as long as it's clear that you removed something.

    You don't have to tell us your actual name when filing a problem report, but if you don't, please use a nickname so we can differentiate between your messages and the ones entered by other "anonymous" users that may respond to your request if they have the same problem or already found a solution. Note that due to spam the trackers may not always allow to post without being logged into SourceForge. If that's the case, you are still free to create a login that isn't directly linked to your name, though.

    Please also check the status of your request a few days after submitting it, as we may request additional information. If you use a SF id, you should automatically get a mail when someone responds to your request. Please don't bother to add an email address when using the tracker. If you prefer to communicate through email, just use one of the mailing lists directly.

    If you are new to reporting problems, you might be interested in How to Report Bugs Effectively.

    The appendix of the Privoxy User Manual also has helpful information on understanding actions, and action debugging.

    6.2. Get Support

    For casual users, our support forum at SourceForge is probably best suited: http://sourceforge.net/tracker/?group_id=11118&atid=211118

    All users are of course welcome to discuss their issues on the users mailing list, where the developers also hang around.

    Please don't send private support requests to individual Privoxy developers, either use the mailing lists or the support trackers.

    If you have to contact a Privoxy developer directly for other reasons, please send a real mail and do not bother with SourceForge's messaging system. Answers to SourceForge messages are usually bounced by SourceForge's mail server in which case the developer wasted time writing a response you don't get. From your point of view it will look like your message has been completely ignored, so this is frustrating for all parties involved.

    Note that the Privoxy mailing lists are moderated. Posts from unsubscribed addresses have to be accepted manually by a moderator. This may cause a delay of several days and if you use a subject that doesn't clearly mention Privoxy or one of its features, your message may be accidentally discarded as spam.

    If you aren't subscribed, you should therefore spend a few seconds to come up with a proper subject. Additionally you should make it clear that you want to get CC'd. Otherwise some responses will be directed to the mailing list only, and you won't see them.

    6.3. Reporting Problems

    "Problems" for our purposes, come in two forms:

    • Configuration issues, such as ads that slip through, or sites that don't function properly due to one Privoxy "action" or another being turned "on".

    • "Bugs" in the programming code that makes up Privoxy, such as that might cause a crash.

    6.3.1. Reporting Ads or Other Configuration Problems

    Please send feedback on ads that slipped through, innocent images that were blocked, sites that don't work properly, and other configuration related problem of default.action file, to http://sourceforge.net/tracker/?group_id=11118&atid=460288, the Actions File Tracker.

    New, improved default.action files may occasionally be made available based on your feedback. These will be announced on the ijbswa-announce list and available from our the files section of our project page.

    6.3.2. Reporting Bugs

    Please report all bugs through our bug tracker: http://sourceforge.net/tracker/?group_id=11118&atid=111118.

    Before doing so, please make sure that the bug has not already been submitted and observe the additional hints at the top of the submit form. If already submitted, please feel free to add any info to the original report that might help to solve the issue.

    6.4. Request New Features

    You are welcome to submit ideas on new features or other proposals for improvement through our feature request tracker at http://sourceforge.net/tracker/?atid=361118&group_id=11118.

    6.5. Mailing Lists

    If you prefer to communicate through email, instead of using a web interface, feel free to use one of the mailing lists. To discuss issues that haven't been completely diagnosed yet, please use the Privoxy users list. Technically interested users and people who wish to contribute to the project are always welcome on the developers list. You can find an overview of all Privoxy-related mailing lists, including list archives, at: http://sourceforge.net/mail/?group_id=11118.

    privoxy-3.0.21-stable/./doc/webserver/faq/index.html000640 001751 001751 00000053522 12114407603 021304 0ustar00fkfk000000 000000 Privoxy Frequently Asked Questions

    Privoxy Frequently Asked Questions

    Copyright © 2001-2011 by Privoxy Developers

    $Id: faq.sgml,v 2.92 2013/03/01 17:44:24 fabiankeil Exp $

    This FAQ gives quick answers to frequently asked questions about Privoxy. It is not a substitute for the Privoxy User Manual.

    What is Privoxy?

    Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks.

    Privoxy is Free Software and licensed under the GNU GPLv2.

    Privoxy is an associated project of Software in the Public Interest (SPI).

    Helping hands and donations are welcome:

    Please note that this document is a work in progress. This copy represents the state at the release of version 3.0.21. You can find the latest version of the document at http://www.privoxy.org/faq/. Please see the Contact section if you want to contact the developers.


    Table of Contents
    1. General Information
    1.1. Who should give Privoxy a try?
    1.2. Is Privoxy the best choice for me?
    1.3. What is a "proxy"? How does Privoxy work?
    1.4. Does Privoxy do anything more than ad blocking?
    1.5. What is this new version of "Junkbuster"?
    1.6. Why "Privoxy"? Why change the name from Junkbuster at all?
    1.7. How does Privoxy differ from the old Junkbuster?
    1.8. How does Privoxy know what is an ad, and what is not?
    1.9. Can Privoxy make mistakes? This does not sound very scientific.
    1.10. Will I have to configure Privoxy before I can use it?
    1.11. Can Privoxy run as a server on a network?
    1.12. My browser does the same things as Privoxy. Why should I use Privoxy at all?
    1.13. Why should I trust Privoxy?
    1.14. Is there is a license or fee? What about a warranty? Registration?
    1.15. Can Privoxy remove spyware? Adware? Viruses?
    1.16. Can I use Privoxy with other ad-blocking software?
    1.17. I would like to help you, what can I do?
    1.17.1. Would you like to participate?
    1.17.2. Would you like to donate?
    2. Installation
    2.1. Which browsers are supported by Privoxy?
    2.2. Which operating systems are supported?
    2.3. Can I use Privoxy with my email client?
    2.4. I just installed Privoxy. Is there anything special I have to do now?
    2.5. What is the proxy address of Privoxy?
    2.6. I just installed Privoxy, and nothing is happening. All the ads are there. What's wrong?
    2.7. I get a "Privoxy is not being used" dummy page although Privoxy is running and being used.
    3. Configuration
    3.1. What exactly is an "actions" file?
    3.2. The "actions" concept confuses me. Please list some of these "actions".
    3.3. How are actions files configured? What is the easiest way to do this?
    3.4. There are several different "actions" files. What are the differences?
    3.5. Where can I get updated Actions Files?
    3.6. Can I use my old config files?
    3.7. Why is the configuration so complicated?
    3.8. How can I make my Yahoo/Hotmail/Gmail account work?
    3.9. What's the difference between the "Cautious", "Medium" and "Advanced" defaults?
    3.10. Why can I change the configuration with a browser? Does that not raise security issues?
    3.11. What is the default.filter file? What is a "filter"?
    3.12. How can I set up Privoxy to act as a proxy for my LAN?
    3.13. Instead of ads, now I get a checkerboard pattern. I don't want to see anything.
    3.14. Why would anybody want to see a checkerboard pattern?
    3.15. I see some images being replaced with text instead of the checkerboard image. Why and how do I get rid of this?
    3.16. Can Privoxy run as a service on Win2K/NT/XP?
    3.17. How can I make Privoxy work with other proxies?
    3.18. Can I just set Privoxy to use port 80 and thus avoid individual browser configuration?
    3.19. Can Privoxy run as a "transparent" proxy?
    3.20. Can Privoxy run as a "intercepting" proxy?
    3.21. How can I configure Privoxy for use with Outlook?
    3.22. How can I have separate rules just for HTML mail?
    3.23. I sometimes notice cookies sneaking through. How?
    3.24. Are all cookies bad? Why?
    3.25. How can I allow permanent cookies for my trusted sites?
    3.26. Can I have separate configurations for different users?
    3.27. Can I set-up Privoxy as a whitelist of "good" sites?
    3.28. How can I turn off ad-blocking?
    3.29. How can I have custom template pages, like the BLOCKED page?
    3.30. How can I remove the "Go There Anyway" link from the BLOCKED page?
    4. Miscellaneous
    4.1. How much does Privoxy slow my browsing down? This has to add extra time to browsing.
    4.2. I notice considerable delays in page requests. What's wrong?
    4.3. What are "http://config.privoxy.org/" and "http://p.p/"?
    4.4. How can I submit new ads, or report problems?
    4.5. If I do submit missed ads, will they be included in future updates?
    4.6. Why doesn't anyone answer my support request?
    4.7. How can I hide my IP address?
    4.8. Can Privoxy guarantee I am anonymous?
    4.9. A test site says I am not using a Proxy.
    4.10. How do I use Privoxy together with Tor?
    4.11. Might some things break because header information or content is being altered?
    4.12. Can Privoxy act as a "caching" proxy to speed up web browsing?
    4.13. What about as a firewall? Can Privoxy protect me?
    4.14. I have large empty spaces / a checkerboard pattern now where ads used to be. Why?
    4.15. How can Privoxy filter Secure (HTTPS) URLs?
    4.16. Privoxy runs as a "server". How secure is it? Do I need to take any special precautions?
    4.17. Can I temporarily disable Privoxy?
    4.18. When "disabled" is Privoxy totally out of the picture?
    4.19. How can I tell Privoxy to totally ignore certain sites?
    4.20. My logs show Privoxy "crunches" ads, but also its own internal CGI pages. What is a "crunch"?
    4.21. Can Privoxy effect files that I download from a webserver? FTP server?
    4.22. I just downloaded a Perl script, and Privoxy altered it! Yikes, what is wrong!
    4.23. Should I continue to use a "HOSTS" file for ad-blocking?
    4.24. Where can I find more information about Privoxy and related issues?
    4.25. I've noticed that Privoxy changes "Microsoft" to "MicroSuck"! Why are you manipulating my browsing?
    4.26. Does Privoxy produce "valid" HTML (or XHTML)?
    4.27. How did you manage to get Privoxy on my computer without my consent?
    5. Troubleshooting
    5.1. I cannot connect to any websites. Or, I am getting "connection refused" message with every web page. Why?
    5.2. Why am I getting a 503 Error (WSAECONNREFUSED) on every page?
    5.3. I just added a new rule, but the steenkin ad is still getting through. How?
    5.4. One of my favorite sites does not work with Privoxy. What can I do?
    5.5. After installing Privoxy, I have to log in every time I start IE. What gives?
    5.6. I cannot connect to any FTP sites. Privoxy is blocking me.
    5.7. In Mac OS X, I can't configure Microsoft Internet Explorer to use Privoxy as the HTTP proxy.
    5.8. In Mac OS X, I dragged the Privoxy folder to the trash in order to uninstall it. Now the finder tells me I don't have sufficient privileges to empty the trash.
    5.9. In Mac OS X Panther (10.3), images often fail to load and/or I experience random delays in page loading. I'm using localhost as my browser's proxy setting.
    5.10. I get a completely blank page at one site. "View Source" shows only: <html><body></body></html>. Without Privoxy the page loads fine.
    5.11. My logs show many "Unable to get my own hostname" lines. Why?
    5.12. When I try to launch Privoxy, I get an error message "port 8118 is already in use" (or similar wording). Why?
    5.13. Pages with UTF-8 fonts are garbled.
    5.14. Why are binary files (such as images) corrupted when Privoxy is used?
    5.15. What is the "demoronizer" and why is it there?
    5.16. Why do I keep seeing "PrivoxyWindowOpen()" in raw source code?
    5.17. I am getting too many DNS errors like "404 No Such Domain". Why can't Privoxy do this better?
    5.18. At one site Privoxy just hangs, and starts taking all CPU. Why is this?
    5.19. I just installed Privoxy, and all my browsing has slowed to a crawl. What gives?
    5.20. Why do my filters work on some sites but not on others?
    5.21. On some HTTPS sites my browser warns me about unauthenticated content, the URL bar doesn't get highlighted and the lock symbol appears to be broken. What's going on?
    5.22. I get selinux error messages. How can I fix this?
    5.23. I compiled Privoxy with Gentoo's portage and it appears to be very slow. Why?
    6. Contacting the developers, Bug Reporting and Feature Requests
    6.1. Please provide sufficient information
    6.2. Get Support
    6.3. Reporting Problems
    6.3.1. Reporting Ads or Other Configuration Problems
    6.3.2. Reporting Bugs
    6.4. Request New Features
    6.5. Mailing Lists
    7. Privoxy Copyright, License and History
    7.1. License
    7.2. History
    privoxy-3.0.21-stable/./doc/webserver/faq/configuration.html000640 001751 001751 00000121117 12040771132 023037 0ustar00fkfk000000 000000 Configuration

    3. Configuration

    3.1. What exactly is an "actions" file?

    Privoxy utilizes the concept of " actions" that are used to manipulate and control web page data. Actions files are where these actions that Privoxy could take while processing a certain request, are configured. Typically, you would define a set of default actions that apply globally to all URLs, then add exceptions to these defaults where needed. There is a wide array of actions available that give the user a high degree of control and flexibility on how to process each and every web page.

    Actions can be defined on a URL pattern basis, i.e. for single URLs, whole web sites, groups or parts thereof etc. Actions can also be grouped together and then applied to requests matching one or more patterns. There are many possible actions that might apply to any given site. As an example, if you are blocking cookies as one of your default actions, but need to accept cookies from a given site, you would need to define an exception for this site in one of your actions files, preferably in user.action.

    3.2. The "actions" concept confuses me. Please list some of these "actions".

    For a comprehensive discussion of the actions concept, please refer to the actions file chapter in the User Manual. It includes a list of all actions and an actions file tutorial to get you started.

    3.3. How are actions files configured? What is the easiest way to do this?

    Actions files are just text files in a special syntax and can be edited with a text editor. But probably the easiest way is to access Privoxy's user interface with your web browser at http://config.privoxy.org/ (Shortcut: http://p.p/) and then select "View & change the current configuration" from the menu. Note that this feature must be explicitly enabled in the main config file (see enable-edit-actions).

    3.5. Where can I get updated Actions Files?

    Based on your feedback and the continuing development, updates of default.action will be made available from time to time on the files section of our project page.

    If you wish to receive an email notification whenever we release updates of Privoxy or the actions file, subscribe to our announce mailing list, ijbswa-announce@lists.sourceforge.net.

    3.6. Can I use my old config files?

    The syntax and purpose of configuration files has remained roughly the same throughout the 3.x series, but backwards compatibility is not guaranteed. Also each release contains updated, "improved" versions and it is therefore strongly recommended to install the newer configuration files and merge back your modifications.

    3.7. Why is the configuration so complicated?

    "Complicated" is in the eye of the beholder. Those that are familiar with some of the underlying concepts, such as regular expression syntax, take to it like a fish takes to water. Also, software that tries hard to be "user friendly", often lacks sophistication and flexibility. There is always that trade-off there between power vs. easy-of-use. Furthermore, anyone is welcome to contribute ideas and implementations to enhance Privoxy.

    3.8. How can I make my Yahoo/Hotmail/Gmail account work?

    The default configuration shouldn't impact the usability of any of these services. It may, however, make all cookies temporary, so that your browser will forget your login credentials in between browser sessions. If you would like not to have to log in manually each time you access those websites, simply turn off all cookie handling for them in the user.action file. An example for yahoo might look like:

    # Allow all cookies for Yahoo login:
    #
    { -crunch-incoming-cookies -crunch-outgoing-cookies -session-cookies-only }
    .login.yahoo.com
    

    These kinds of sites are often quite complex and heavy with Javascript and thus "fragile". So if still a problem, we have an alias just for such sticky situations:

    # Gmail is a _fragile_ site:
    #
    { fragile }
     # Gmail is ...
     mail.google.com
    

    Be sure to flush your browser's caches whenever making these kinds of changes, just to make sure the changes "take".

    Make sure the domain, host and path are appropriate as well. Your browser can tell you where you are specifically and you should use that information for your configuration settings. Note that above it is not referenced as gmail.com, which is a valid domain name.

    3.9. What's the difference between the "Cautious", "Medium" and "Advanced" defaults?

    Configuring Privoxy is not entirely trivial. To help you get started, we provide you with three different default action "profiles" in the web based actions file editor at http://config.privoxy.org/show-status. See the User Manual for a list of actions, and how the default profiles are set.

    Where the defaults are likely to break some sites, exceptions for known popular "problem" sites are included, but in general, the more aggressive your default settings are, the more exceptions you will have to make later. New users are best to start off in "Cautious" setting. This is safest and will have the fewest problems. See the User Manual for a more detailed discussion.

    It should be noted that the "Advanced" profile (formerly known as the "Adventuresome" profile) is more aggressive, and will make use of some of Privoxy's advanced features. Use at your own risk!

    3.10. Why can I change the configuration with a browser? Does that not raise security issues?

    It may seem strange that regular users can edit the config files with their browsers, although the whole /etc/privoxy hierarchy belongs to the user "privoxy", with only 644 permissions.

    When you use the browser-based editor, Privoxy itself is writing to the config files. Because Privoxy is running as the user "privoxy", it can update its own config files.

    If you run Privoxy for multiple untrusted users (e.g. in a LAN) or aren't entirely in control of your own browser, you will probably want to make sure that the web-based editor and remote toggle features are "off" by setting "enable-edit-actions 0" and "enable-remote-toggle 0" in the main configuration file.

    As of Privoxy 3.0.7 these options are disabled by default.

    3.11. What is the default.filter file? What is a "filter"?

    The default.filter file is where filters as supplied by the developers are defined. Filters are a special subset of actions that can be used to modify or remove web page content or headers on the fly. Content filters can be applied to anything in the page source, header filters can be applied to either server or client headers. Regular expressions are used to accomplish this.

    There are a number of pre-defined filters to deal with common annoyances. The filters are only defined here, to invoke them, you need to use the filter action in one of the actions files. Content filtering is automatically disabled for inappropriate MIME types, but if you know better than Privoxy what should or should not be filtered you can filter any content you like.

    Filters should not be confused with blocks, which is a completely different action, and is more typically used to block ads and unwanted sites.

    If you are familiar with regular expressions, and HTML, you can look at the provided default.filter with a text editor and define your own filters. This is potentially a very powerful feature, but requires some expertise in both regular expressions and HTML/HTTP. You should place any modifications to the default filters, or any new ones you create in a separate file, such as user.filter, so they won't be overwritten during upgrades. The ability to define multiple filter files in config is a new feature as of v. 3.0.5.

    There is no GUI editor option for this part of the configuration, but you can disable/enable the various pre-defined filters of the included default.filter file with the web-based actions file editor. Note that the custom actions editor must be explicitly enabled in the main config file (see enable-edit-actions).

    If you intend to develop your own filters, you might want to have a look at Privoxy-Filter-Test.

    3.12. How can I set up Privoxy to act as a proxy for my LAN?

    By default, Privoxy only responds to requests from 127.0.0.1 (localhost). To have it act as a server for a network, this needs to be changed in the main configuration file. Look for the listen-address option, which may be commented out with a "#" symbol. Make sure it is uncommented, and assign it the address of the LAN gateway interface, and port number to use. Assuming your LAN address is 192.168.1.1 and you wish to run Privoxy on port 8118, this line should look like:

      listen-address  192.168.1.1:8118
    

    Save the file, and restart Privoxy. Configure all browsers on the network then to use this address and port number.

    Alternately, you can have Privoxy listen on all available interfaces:

      listen-address    :8118
    

    And then use Privoxy's permit-access feature to limit connections. A firewall in this situation is recommended as well.

    The above steps should be the same for any TCP network, regardless of operating system.

    If you run Privoxy on a LAN with untrusted users, we recommend that you double-check the access control and security options!

    3.13. Instead of ads, now I get a checkerboard pattern. I don't want to see anything.

    The replacement for blocked images can be controlled with the set-image-blocker action. You have the choice of a checkerboard pattern, a transparent 1x1 GIF image (aka "blank"), or a redirect to a custom image of your choice. Note that this choice only has effect for images which are blocked as images, i.e. whose URLs match both a handle-as-image and block action.

    If you want to see nothing, then change the set-image-blocker action to "blank". This can be done by editing the user.action file, or through the web-based actions file editor.

    3.14. Why would anybody want to see a checkerboard pattern?

    Remember that telling which image is an ad and which isn't, is an educated guess. While we hope that the standard configuration is rather smart, it will make occasional mistakes. The checkerboard image is visually decent, and it shows you where images have been blocked, which can be very helpful in case some navigation aid or otherwise innocent image was erroneously blocked. It is recommended for new users so they can "see" what is happening. Some people might also enjoy seeing how many banners they don't have to see.

    3.15. I see some images being replaced with text instead of the checkerboard image. Why and how do I get rid of this?

    This happens when the banners are not embedded in the HTML code of the page itself, but in separate HTML (sub)documents that are loaded into (i)frames or (i)layers, and these external HTML documents are blocked. Being non-images they get replaced by a substitute HTML page rather than a substitute image, which wouldn't work out technically, since the browser expects and accepts only HTML when it has requested an HTML document.

    The substitute page adapts to the available space and shows itself as a miniature two-liner if loaded into small frames, or full-blown with a large red "BLOCKED" banner if space allows.

    If you prefer the banners to be blocked by images, you must see to it that the HTML documents in which they are embedded are not blocked. Clicking the "See why" link offered in the substitute page will show you which rule blocked the page. After changing the rule and un-blocking the HTML documents, the browser will try to load the actual banner images and the usual image blocking will (hopefully!) kick in.

    3.16. Can Privoxy run as a service on Win2K/NT/XP?

    Yes. Version 3.0.5 introduces full Windows service functionality. See the User Manual for details on how to install and configure Privoxy as a service.

    Earlier 3.x versions could run as a system service using srvany.exe. See the discussion at http://sourceforge.net/tracker/?func=detail&atid=361118&aid=485617&group_id=11118, for details, and a sample configuration.

    3.17. How can I make Privoxy work with other proxies?

    This can be done and is often useful to combine the benefits of Privoxy with those of a another proxy, for example to cache content. See the forwarding chapter in the User Manual which describes how to do this. If you intend to use Privoxy with Tor, please also have a look at How do I use Privoxy together with Tor.

    3.18. Can I just set Privoxy to use port 80 and thus avoid individual browser configuration?

    No, its more complicated than that. This only works with special kinds of proxies known as "intercepting" proxies (see below).

    3.19. Can Privoxy run as a "transparent" proxy?

    The whole idea of Privoxy is to modify client requests and server responses in all sorts of ways and therefore it's not a transparent proxy as described in RFC 2616.

    However, some people say "transparent proxy" when they mean "intercepting proxy". If you are one of them, please read the next entry.

    3.20. Can Privoxy run as a "intercepting" proxy?

    Privoxy can't intercept traffic itself, but it can handle requests that where intercepted and redirected with a packet filter (like PF or iptables), as long as the Host header is present.

    As the Host header is required by HTTP/1.1 and as most web sites rely on it anyway, this limitation shouldn't be a problem.

    Please refer to your packet filter's documentation to learn how to intercept and redirect traffic into Privoxy. Afterward you just have to configure Privoxy to accept intercepted requests.

    3.21. How can I configure Privoxy for use with Outlook?

    Versions of Outlook prior to Office 2007, use Internet Explorer components to both render HTML, and fetch any HTTP requests that may be embedded in an HTML email. So however you have Privoxy configured to work with IE, this configuration should automatically be shared, at least with older version of Internet Explorer.

    Starting with Office 2007, Microsoft is instead using the MS-Word rendering engine with Outlook. It is unknown whether this can be configured to use a proxy.

    3.22. How can I have separate rules just for HTML mail?

    The short answer is, you can't. Privoxy has no way of knowing which particular application makes a request, so there is no way to distinguish between web pages and HTML mail. Privoxy just blindly proxies all requests. In the case of Outlook Express (see above), OE uses IE anyway, and there is no way for Privoxy to ever be able to distinguish between them (nor could any other proxy type application for that matter).

    For a good discussion of some of the issues involved (including privacy and security issues), see http://sourceforge.net/tracker/?func=detail&atid=211118&aid=629518&group_id=11118.

    3.23. I sometimes notice cookies sneaking through. How?

    Cookies can be set in several ways. The classic method is via the Set-Cookie HTTP header. This is straightforward, and an easy one to manipulate, such as the Privoxy concept of session-cookies-only. There is also the possibility of using Javascript to set cookies (Privoxy calls these content-cookies). This is trickier because the syntax can vary widely, and thus requires a certain amount of guesswork. It is not realistic to catch all of these short of disabling Javascript, which would break many sites. And lastly, if the cookies are embedded in a HTTPS/SSL secure session via Javascript, they are beyond Privoxy's reach.

    All in all, Privoxy can help manage cookies in general, can help minimize the loss of privacy posed by cookies, but can't realistically stop all cookies.

    3.24. Are all cookies bad? Why?

    No, in fact there are many beneficial uses of cookies. Cookies are just a method that browsers can use to store data between pages, or between browser sessions. Sometimes there is a good reason for this, and the user's life is a bit easier as a result. But there is a long history of some websites taking advantage of this layer of trust, and using the data they glean from you and your browsing habits for their own purposes, and maybe to your potential detriment. Such sites are using you and storing their data on your system. That is why the privacy conscious watch from whom those cookies come, and why they really need to be there.

    See the Wikipedia cookie definition for more.

    3.25. How can I allow permanent cookies for my trusted sites?

    There are several actions that relate to cookies. The default behavior is to allow only "session cookies", which means the cookies only last for the current browser session. This eliminates most kinds of abuse related to cookies. But there may be cases where you want cookies to last.

    To disable all cookie actions, so that cookies are allowed unrestricted, both in and out, for example.com:

     { -crunch-incoming-cookies -crunch-outgoing-cookies -session-cookies-only -filter{content-cookies} }
      .example.com
    

    Place the above in user.action. Note that some of these may be off by default anyway, so this might be redundant, but there is no harm being explicit in what you want to happen. user.action includes an alias for this situation, called allow-all-cookies.

    3.26. Can I have separate configurations for different users?

    Each instance of Privoxy has its own configuration, including such attributes as the TCP port that it listens on. What you can do is run multiple instances of Privoxy, each with a unique listen-address configuration setting, and configuration path, and then each of these can have their own configurations. Think of it as per-port configuration.

    Simple enough for a few users, but for large installations, consider having groups of users that might share like configurations.

    3.27. Can I set-up Privoxy as a whitelist of "good" sites?

    Sure. There are a couple of things you can do for simple white-listing. Here's one real easy one:

     ############################################################
     # Blacklist
     ############################################################
     { +block }
     / # Block *all* URLs
    
     ############################################################
     # Whitelist
     ############################################################
     { -block }
      kids.example.com
      toys.example.com
      games.example.com
    

    This allows access to only those three sites by first blocking all URLs, and then subsequently allowing three specific exceptions.

    Another approach is Privoxy's trustfile concept, which incorporates the notion of "trusted referrers". See the Trust documentation for details.

    These are fairly simple approaches and are not completely foolproof. There are various other configuration options that should be disabled (described elsewhere here and in the User Manual) so that users can't modify their own configuration and easily circumvent the whitelist.

    3.28. How can I turn off ad-blocking?

    Ad blocking is achieved through a complex application of various Privoxy actions. These actions are deployed against simple images, banners, flash animations, text pages, JavaScript, pop-ups and pop-unders, etc., so its not as simple as just turning one or two actions off. The various actions that make up Privoxy ad blocking are hard-coded into the default configuration files. It has been assumed that everyone using Privoxy is interested in this particular feature.

    If you want to do without this, there are several approaches you can take: You can manually undo the many block rules in default.action. Or even easier, just create your own default.action file from scratch without the many ad blocking rules, and corresponding exceptions. Or lastly, if you are not concerned about the additional blocks that are done for privacy reasons, you can very easily over-ride all blocking with the following very simple rule in your user.action:

     # Unblock everybody, everywhere
     { -block }
     / # UN-Block *all* URLs
    

    Or even a more comprehensive reversing of various ad related actions:

     # Unblock everybody, everywhere, and turn off appropriate filtering, etc
     { -block \
      -filter{banners-by-size} \
      -filter{banners-by-link} \
      allow-popups \
     }
     / # UN-Block *all* URLs and allow ads
    

    This last "action" in this compound statement, allow-popups, is an alias that disables various pop-up blocking features.

    3.29. How can I have custom template pages, like the BLOCKED page?

    Privoxy "templates" are specialized text files utilized by Privoxy for various purposes and can easily be modified using any text editor. All the template pages are installed in a sub-directory appropriately named: templates. Knowing something about HTML syntax will of course be helpful.

    Be forewarned that the default templates are subject to being overwritten during upgrades. You can, however, create completely new templates, place them in another directory and specify the alternate path in the main config. For details, have a look at the templdir option.

    3.30. How can I remove the "Go There Anyway" link from the BLOCKED page?

    There is more than one way to do it (although Perl is not involved).

    Editing the BLOCKED template page (see above) may dissuade some users, but this method is easily circumvented. Where you need this level of control, you might want to build Privoxy from source, and disable various features that are available as compile-time options. You should configure the sources as follows:

     ./configure  --disable-toggle  --disable-editor  --disable-force
    

    This will create an executable with hard-coded security features so that Privoxy does not allow easy bypassing of blocked sites, or changing the current configuration via any connected user's web browser.

    Finally, all of these features can also be toggled on/off via options in Privoxy's main config file which means you don't have to recompile anything.

    privoxy-3.0.21-stable/./doc/webserver/faq/installation.html000640 001751 001751 00000027773 12076236774 022727 0ustar00fkfk000000 000000 Installation

    2. Installation

    2.1. Which browsers are supported by Privoxy?

    Any browser that can be configured to use a proxy, which should be virtually all browsers, including Firefox, Internet Explorer, Opera, and Safari among others. Direct browser support is not an absolute requirement since Privoxy runs as a separate application and talks to the browser in the standardized HTTP protocol, just like a web server does.

    2.2. Which operating systems are supported?

    At present, Privoxy is known to run on Windows 95 and later versions (98, ME, 2000, XP, Vista, Windows 7 etc.), GNU/Linux (RedHat, SuSE, Debian, Fedora, Gentoo, Slackware and others), Mac OS X (10.4 and upwards on PPC and Intel processors), OS/2, Haiku, DragonFly, FreeBSD, NetBSD, OpenBSD, Solaris, and various other flavors of Unix.

    Privoxy used to work on AmigaOS and QNX, too, but the code currently isn't maintained and its status unknown. It might no longer compile, but getting it working again shouldn't be too hard.

    But any operating system that runs TCP/IP, can conceivably take advantage of Privoxy in a networked situation where Privoxy would run as a server on a LAN gateway. Then only the "gateway" needs to be running one of the above operating systems.

    Source code is freely available, so porting to other operating systems is always a possibility.

    2.3. Can I use Privoxy with my email client?

    As long as there is some way to set a HTTP proxy for the client, then yes, any application can be used, whether it is strictly speaking a "browser" or not. Though this may not be the best approach for dealing with some of the common abuses of HTML in email. See How can I configure Privoxy with Outlook? below for more on this.

    Be aware that HTML email presents a number of unique security and privacy related issues, that can require advanced skills to overcome. The developers recommend using email clients that can be configured to convert HTML to plain text for these reasons.

    2.4. I just installed Privoxy. Is there anything special I have to do now?

    All browsers should be told to use Privoxy as a proxy by specifying the correct proxy address and port number in the appropriate configuration area for the browser. It's possible to combine Privoxy with a packet filter to intercept HTTP requests even if the client isn't explicitly configured to use Privoxy, but where possible, configuring the client is recommended. See the User Manual for more details. You should also flush your browser's memory and disk cache to get rid of any cached junk items, and remove any stored cookies.

    2.5. What is the proxy address of Privoxy?

    If you set up the Privoxy to run on the computer you browse from (rather than your ISP's server or some networked computer on a LAN), the proxy will be on 127.0.0.1 (sometimes referred to as "localhost", which is the special name used by every computer on the Internet to refer to itself) and the port will be 8118 (unless you used the listen-address config option to tell Privoxy to run on a different port).

    When configuring your browser's proxy settings you typically enter the word "localhost" or the IP address "127.0.0.1" in the boxes next to "HTTP" and "Secure" (HTTPS) and then the number "8118" for "port". This tells your browser to send all web requests to Privoxy instead of directly to the Internet.

    Privoxy can also be used to proxy for a Local Area Network. In this case, your would enter either the IP address of the LAN host where Privoxy is running, or the equivalent hostname, e.g. 192.168.1.1. Port assignment would be same as above. Note that Privoxy doesn't listen on any LAN interfaces by default.

    Privoxy does not currently handle any other protocols such as FTP, SMTP, IM, IRC, ICQ, etc.

    2.6. I just installed Privoxy, and nothing is happening. All the ads are there. What's wrong?

    Did you configure your browser to use Privoxy as a proxy? It does not sound like it. See above. You might also try flushing the browser's caches to force a full re-reading of pages. You can verify that Privoxy is running, and your browser is correctly configured by entering the special URL: http://p.p/. This should take you to a page titled "This is Privoxy.." with access to Privoxy's internal configuration. If you see this, then you are good to go. If you receive a page saying "Privoxy is not running", then the browser is not set up to use your Privoxy installation. If you receive anything else (probably nothing at all), it could either be that the browser is not set up correctly, or that Privoxy is not running at all. Check the log file. For instructions on starting Privoxy and browser configuration, see the chapter on starting Privoxy in the User Manual.

    2.7. I get a "Privoxy is not being used" dummy page although Privoxy is running and being used.

    First, make sure that Privoxy is really running and being used by visiting http://p.p/. You should see the Privoxy main page. If not, see the chapter on starting Privoxy in the User Manual.

    Now if http://p.p/ works for you, but other parts of Privoxy's web interface show the dummy page, your browser has cached a redirection it encountered before Privoxy was being used. You need to clear your browser's cache. Note that shift-reloading the dummy page won't help, since that'll only refresh the dummy page, not the redirection that lead you there.

    The procedure for clearing the cache varies from browser to browser. For example, Mozilla/Netscape users would click Edit --> Preferences --> Advanced --> Cache and then click both "Clear Memory Cache" and "Clear Disk Cache". In some Firefox versions it's Tools --> Options --> Privacy --> Cache and then click "Clear Cache Now".

    privoxy-3.0.21-stable/./doc/webserver/privoxy.css000640 001751 001751 00000004520 10546014107 020764 0ustar00fkfk000000 000000 /* * CSS for Privoxy CGI and script output * * $Id: privoxy.css,v 1.2 2002/04/09 11:55:20 oes Exp $ */ /* * General rules: Font, Color, Headings, Margins, Links */ body,td,th { font-family: arial, helvetica, helv, sans-serif; } body { background-color: #ffffff; color: #000000; } h1 { font-size: 140%; margin: 0px; } h2 { font-size: 120%; margin: 0px; } h3 { font-size: 110%; margin: 0px; } p,pre { margin-left: 15px; } li { margin: 2px 15px; } dl { margin: 2px 15px; } a:link { color: #0000dd; text-decoration: none; } a:visited { color: #330099; text-decoration: none; } a:active { color: #3333ff; text-decoration: none; } /* * Boxen as Table elements: */ td.title { border: solid black 1px; background-color: #dddddd; } td.box { border: solid black 1px; background-color: #eeeeee; } td.info { border: solid black 1px; background-color: #ccccff; } td.warning { border: solid black 1px; background-color: #ffdddd; } /* * Special Table Boxen: for nesting, naked container and for * the Status field in CGI Output: */ td.wrapbox { border: solid black 1px; padding: 5px; } td.container { padding: 0px; } td.status { border: solid black 1px; background-color: #ff0000; color: #ffffff; font-size: 300%; font-weight: bolder; } /* * Same Boxen as
    s: */ div.title { border: solid black 1px; background-color: #dddddd; margin: 20px; padding: 20px; } div.box { border: solid black 1px; background-color: #eeeeee; margin: 20px; padding: 20px; } div.info { border: solid black 1px; background-color: #ccccff; margin: 20px; padding: 20px; } div.warning { border: solid black 1px; background-color: #ffdddd; margin: 20px; padding: 20px; } div.wrapbox { border: solid black 1px; margin: 20px; padding: 5px; } /* * Bold definitions in
    s, Grey BG for Table headings */ dt { font-weight: bold; } th { background-color: #dddddd; } /* * Special purpose paragraphs: Small for page footers, * Important for quoting wrong or dangerous examples, * Whiteframed for the toggle?mini=y CGI */ p.small { font-size: 10px; margin: 0px; } p.important { border: solid black 1px; background-color: #ffdddd; font-weight: bold; padding: 2px; } p.whiteframed { margin: 5px; padding: 5px; border: solid black 1px; text-align: center; background-color: #eeeeee; } /* * Special red emphasis: */ em.warning { color: #ff0000 } privoxy-3.0.21-stable/./doc/webserver/privoxy-index.html000640 001751 001751 00000010432 12113150317 022240 0ustar00fkfk000000 000000 Privoxy - The Privacy Enhancing Proxy

    Privoxy - The Privacy Enhancing Proxy

    Project Index Page v3.0.21

    Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks.

    Privoxy is Free Software and licensed under the GNU GPLv2.

    Privoxy is an associated project of Software in the Public Interest (SPI).

    Helping hands and donations are welcome:



    Copyright © 2001-2013 by Privoxy Developers

    privoxy-3.0.21-stable/./doc/webserver/man-page/privoxy-man-page.html000640 001751 001751 00000026365 12114407603 024323 0ustar00fkfk000000 000000 Man page of PRIVOXY

    PRIVOXY

    Section: (1)
    Updated: 02 March 2013
    Index
     

    NAME

    privoxy - Privacy Enhancing Proxy  

    SYNOPSIS

    privoxy [--chroot ] [--config-test ] [--help ] [--no-daemon ] [--pidfile pidfile ] [--pre-chroot-nslookup hostname ] [--user user[.group] ] [--version ] [configfile ]

     

    OPTIONS

    Privoxy may be invoked with the following command line options:

    --chroot
    Before changing to the user ID given in the --user option, chroot to that user's home directory, i.e. make the kernel pretend to the Privoxy process that the directory tree starts there. If set up carefully, this can limit the impact of possible vulnerabilities in Privoxy to the files contained in that hierarchy.
    --config-test
    Exit after loading the configuration files before binding to the listen address. The exit code signals whether or not the configuration files have been successfully loaded.

    If the exit code is 1, at least one of the configuration files is invalid, if it is 0, all the configuration files have been successfully loaded (but may still contain errors that can currently only be detected at run time).

    This option doesn't affect the log setting, combination with "--no-daemon" is recommended if a configured log file shouldn't be used.

    --help
    Print brief usage info and exit.
    --no-daemon
    Don't become a daemon, i.e. don't fork and become process group leader, don't detach from controlling tty, and do all logging there.
    --pidfile pidfile
    On startup, write the process ID to pidfile. Delete the pidfile on exit. Failure to create or delete the pidfile is non-fatal. If no --pidfile option is given, no PID file will be used.
    --pre-chroot-nslookup hostname
    Initialize the resolver library using hostname before chroot'ing. On some systems this reduces the number of files that must be copied into the chroot tree.
    --user user[.group]
    After (optionally) writing the PID file, assume the user ID of user and the GID of group, or, if the optional group was not given, the default group of user. Exit if the privileges are not sufficient to do so.
    --version
    Print version info and exit.

    If the configfile is not specified on the command line, Privoxy will look for a file named config in the current directory. If no configfile is found, Privoxy will fail to start.  

    DESCRIPTION

    Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks.

    Privoxy is Free Software and licensed under the GNU GPLv2.

    Privoxy is an associated project of Software in the Public Interest (SPI).

    Helping hands and donations are welcome:

    http://www.privoxy.org/faq/general.html#PARTICIPATE
    http://www.privoxy.org/faq/general.html#DONATE
     

    INSTALLATION AND USAGE

    Browsers can either be individually configured to use Privoxy as a HTTP proxy (recommended), or Privoxy can be combined with a packet filter to build an intercepting proxy (see config). The default setting is for localhost, on port 8118 (configurable in the main config file). To set the HTTP proxy in Firefox, go through: Tools; Options; General; Connection Settings; Manual Proxy Configuration.

    For Internet Explorer, go through: Tools; Internet Properties; Connections; LAN Settings.

    The Secure (SSL) Proxy should also be set to the same values, otherwise https: URLs will not be proxied. Note: Privoxy can only proxy HTTP and HTTPS traffic. Do not try it with FTP or other protocols. HTTPS presents some limitations, and not all features will work with HTTPS connections.

    For other browsers, check the documentation.  

    CONFIGURATION

    Privoxy can be configured with the various configuration files. The default configuration files are: config, default.filter, default.action and default.action. user.action should be used for locally defined exceptions to the default rules in match-all.action and default.action, and user.filter for locally defined filters. These are well commented. On Unix and Unix-like systems, these are located in /etc/privoxy/ by default.

    Privoxy uses the concept of actions in order to manipulate the data stream between the browser and remote sites. There are various actions available with specific functions for such things as blocking web sites, managing cookies, etc. These actions can be invoked individually or combined, and used against individual URLs, or groups of URLs that can be defined using wildcards and regular expressions. The result is that the user has greatly enhanced control and freedom.

    The actions list (ad blocks, etc) can also be configured with your web browser at http://config.privoxy.org/ (assuming the configuration allows it). Privoxy's configuration parameters can also be viewed at the same page. In addition, Privoxy can be toggled on/off. This is an internal page, and does not require Internet access.

    See the User Manual for a detailed explanation of installation, general usage, all configuration options, new features and notes on upgrading.  

    FILES

     /usr/sbin/privoxy
     /etc/privoxy/config
     /etc/privoxy/match-all.action
     /etc/privoxy/default.action
     /etc/privoxy/user.action
     /etc/privoxy/default.filter
     /etc/privoxy/user.filter
     /etc/privoxy/trust
     /etc/privoxy/templates/*
     /var/log/privoxy/logfile
    

    Various other files should be included, but may vary depending on platform and build configuration. Additional documentation should be included in the local documentation directory.  

    SIGNALS

    Privoxy terminates on the SIGINT and SIGTERM signals. Log rotation scripts may cause a re-opening of the logfile by sending a SIGHUP to Privoxy. Note that unlike other daemons, Privoxy does not need to be made aware of config file changes by SIGHUP -- it will detect them automatically. Signals other than the ones listed above aren't explicitly handled and result in the default action defined by the operating system.  

    NOTES

    Please see the User Manual on how to contact the developers, for feature requests, reporting problems, and other questions.  

    SEE ALSO

    Other references and sites of interest to Privoxy users:

    http://www.privoxy.org/, the Privoxy Home page.

    http://www.privoxy.org/faq/, the Privoxy FAQ.

    http://www.privoxy.org/developer-manual/, the Privoxy developer manual.

    https://sourceforge.net/projects/ijbswa/, the Project Page for Privoxy on SourceForge.

    http://config.privoxy.org/, the web-based user interface. Privoxy must be running for this to work. Shortcut: http://p.p/

    https://sourceforge.net/tracker/?group_id=11118&atid=460288, to submit ``misses'' and other configuration related suggestions to the developers.  

    DEVELOPMENT TEAM

     Fabian Keil, lead developer
     David Schmidt
     Hal Burgiss
     Lee Rian
     Roland Rosenfeld
     Ian Silvester
    
     

    COPYRIGHT AND LICENSE

     

    COPYRIGHT

    Copyright (C) 2001-2013 by Privoxy Developers <ijbswa-developers@lists.sourceforge.net>

    Some source code is based on code Copyright (C) 1997 by Anonymous Coders and Junkbusters, Inc. and licensed under the GNU General Public License.  

    LICENSE

    Privoxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation.

    Privoxy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for details.


     

    Index

    NAME
    SYNOPSIS
    OPTIONS
    DESCRIPTION
    INSTALLATION AND USAGE
    CONFIGURATION
    FILES
    SIGNALS
    NOTES
    SEE ALSO
    DEVELOPMENT TEAM
    COPYRIGHT AND LICENSE
    COPYRIGHT
    LICENSE

    This document was created by man2html, using the manual pages.
    Time: 14:21:31 GMT, March 02, 2013 privoxy-3.0.21-stable/./doc/webserver/robots.txt000640 001751 001751 00000000631 10546014107 020602 0ustar00fkfk000000 000000 # This is the Privoxy web site. # # If the robot is connecting through Privoxy, then the # control interface is at /config. It isn't very useful # to index it, and you're likely to break stuff. So go away! # # Even if you're not connected through Privoxy, the # one "Privoxy is not working" page there is not very # interesting. User-agent: * Disallow: /config/ Disallow: /actions/ Disallow: /submit/ privoxy-3.0.21-stable/./doc/webserver/p_doc.css000640 001751 001751 00000003170 10546014107 020330 0ustar00fkfk000000 000000 /* * CSS for Privoxy documentation * * $Id: p_doc.css,v 1.5 2006/09/09 19:13:42 hal9 Exp $ */ /* * Global fonts, colors, margins: */ body,td,th { font-family: arial, helvetica, sans-serif; } body { margin: 4%; color: #000000; background-color: #eeeeee; } /* * Headings hierarchy in terms of size and color: */ h1 { color: #4c000f; font-size: 160%; } h2 { color: #660014; font-size: 140%; } h3 { color: #820019; font-size: 120%; } h4 { color: #99001d; font-size: 110%; } /* * Make headings stand out: * Indent all content in chapters, by additional 2%, * and then pull the headings back left. */ div.sect1 { margin-left: 2%; } h1,h2,h3,h4 {margin-left: -2%; } h1.title { margin-left: 0; } h2.subtitle { margin-left: 0; } /* * Underlined links disturb the examples; * Let them get darker instead of purple after visited. */ a { text-decoration: none; } a:link { color: #0c29ff; } a:visited { color: #071899; } /* * Special highlighting: * Code examples in embedded in the text flow become half-bold, * Emphasis gets h4-red. * Warnings get the same bg as in privoxy.css */ tt.literal { font-weight: 600; } i.emphasis { color: #99001d; } table.warning { border: 0; background-color: #ffdddd;} span.guibutton { white-space: nowrap; width: auto; padding: 2px; background-color: #dddddd; color: #000000; text-decoration: none; border-top: 1px solid #ffffff; border-left: 1px solid #ffffff; border-bottom: 1px solid #000000; border-right: 1px solid #000000; } /* * Misc: */ ul { list-style-type: square; } /* Privoxy, of course */ .application {font-weight: bold; font-size:105%; color: #99001d;} privoxy-3.0.21-stable/./doc/webserver/developer-manual/index.html000640 001751 001751 00000027414 12114407603 023776 0ustar00fkfk000000 000000 Privoxy Developer Manual

    Privoxy Developer Manual

    Copyright © 2001-2013 by Privoxy Developers

    $Id: developer-manual.sgml,v 2.57 2013/03/01 17:44:24 fabiankeil Exp $

    The developer manual provides guidance on coding, testing, packaging, documentation and other issues of importance to those involved with Privoxy development. It is mandatory (and helpful!) reading for anyone who wants to join the team. Note that it's currently out of date and may not be entirely correct. As always, patches are welcome.

    Please note that this document is constantly evolving. This copy represents the state at the release of version 3.0.21. You can find the latest version of the this manual at http://www.privoxy.org/developer-manual/. Please have a look at the contact section in the user manual if you are interested in contacting the developers.


    Table of Contents
    1. Introduction
    1.1. Quickstart to Privoxy Development
    2. The CVS Repository
    2.1. Access to CVS
    2.2. Branches
    2.3. CVS Commit Guidelines
    3. Documentation Guidelines
    3.1. Quickstart to Docbook and SGML
    3.2. Privoxy Documentation Style
    3.3. Privoxy Custom Entities
    4. Coding Guidelines
    4.1. Introduction
    4.2. Using Comments
    4.2.1. Comment, Comment, Comment
    4.2.2. Use blocks for comments
    4.2.3. Keep Comments on their own line
    4.2.4. Comment each logical step
    4.2.5. Comment All Functions Thoroughly
    4.2.6. Comment at the end of braces if the content is more than one screen length
    4.3. Naming Conventions
    4.3.1. Variable Names
    4.3.2. Function Names
    4.3.3. Header file prototypes
    4.3.4. Enumerations, and #defines
    4.3.5. Constants
    4.4. Using Space
    4.4.1. Put braces on a line by themselves.
    4.4.2. ALL control statements should have a block
    4.4.3. Do not belabor/blow-up boolean expressions
    4.4.4. Use white space freely because it is free
    4.4.5. Don't use white space around structure operators
    4.4.6. Make the last brace of a function stand out
    4.4.7. Use 3 character indentions
    4.5. Initializing
    4.5.1. Initialize all variables
    4.6. Functions
    4.6.1. Name functions that return a boolean as a question.
    4.6.2. Always specify a return type for a function.
    4.6.3. Minimize function calls when iterating by using variables
    4.6.4. Pass and Return by Const Reference
    4.6.5. Pass and Return by Value
    4.6.6. Names of include files
    4.6.7. Provide multiple inclusion protection
    4.6.8. Use `extern "C"` when appropriate
    4.6.9. Where Possible, Use Forward Struct Declaration Instead of Includes
    4.7. General Coding Practices
    4.7.1. Turn on warnings
    4.7.2. Provide a default case for all switch statements
    4.7.3. Try to avoid falling through cases in a switch statement.
    4.7.4. Don't mix size_t and other types
    4.7.5. Declare each variable and struct on its own line.
    4.7.6. Use malloc/zalloc sparingly
    4.7.7. The Programmer Who Uses 'malloc' is Responsible for Ensuring 'free'
    4.7.8. Add loaders to the `file_list' structure and in order
    4.7.9. "Uncertain" new code and/or changes to existing code, use XXX
    4.8. Addendum: Template for files and function comment blocks:
    5. Testing Guidelines
    5.1. Testplan for releases
    5.2. Test reports
    6. Releasing a New Version
    6.1. Version numbers
    6.2. Before the Release: Freeze
    6.3. Building and Releasing the Packages
    6.3.1. Note on Privoxy Packaging
    6.3.2. Source Tarball
    6.3.3. SuSE, Conectiva or Red Hat RPM
    6.3.4. OS/2
    6.3.5. Solaris
    6.3.6. Windows
    6.3.7. Debian
    6.3.8. Mac OS X
    6.3.9. FreeBSD
    6.3.10. HP-UX 11
    6.3.11. Amiga OS
    6.3.12. AIX
    6.4. Uploading and Releasing Your Package
    6.5. After the Release
    7. Update the Webserver
    privoxy-3.0.21-stable/./doc/webserver/developer-manual/webserver-update.html000640 001751 001751 00000010372 12114164411 026143 0ustar00fkfk000000 000000 Update the Webserver

    7. Update the Webserver

    The webserver should be updated at least with each stable release. When updating, please follow these steps to make sure that no broken links, inconsistent contents or permission problems will occur (as it has many times in the past!):

    If you have changed anything in the stable-branch documentation source SGML files, do:

      make dok
    

    That will generate doc/webserver/user-manual, doc/webserver/developer-manual, doc/webserver/faq, doc/webserver/index.html automatically.

    If you changed the manual page sources, generate doc/webserver/man-page/privoxy-man-page.html by running "make man". (This is a separate target due to dependencies on some obscure perl scripts [now in CVS, but not well tested]. See comments in GNUmakefile.)

    If you want to add new files to the webserver, create them locally in the doc/webserver/* directory (or create new directories under doc/webserver).

    Next, commit any changes from the above steps to CVS. All set? If these are docs in the stable branch, then do:

      make webserver
    

    This will do the upload to the webserver (www.privoxy.org) and ensure all files and directories there are group writable.

    Please do NOT use any other means of transferring files to the webserver to avoid permission problems. Also, please do not upload docs from development branches or versions. The publicly posted docs should be in sync with the last official release.

    privoxy-3.0.21-stable/./doc/webserver/developer-manual/newrelease.html000640 001751 001751 00000127344 12114164411 025021 0ustar00fkfk000000 000000 Releasing a New Version

    6. Releasing a New Version

    When we release versions of Privoxy, our work leaves our cozy secret lab and has to work in the cold RealWorld[tm]. Once it is released, there is no way to call it back, so it is very important that great care is taken to ensure that everything runs fine, and not to introduce problems in the very last minute.

    So when releasing a new version, please adhere exactly to the procedure outlined in this chapter.

    The following programs are required to follow this process: ncftpput (ncftp), scp, ssh (ssh), gmake (GNU's version of make), autoconf, cvs.

    6.1. Version numbers

    First you need to determine which version number the release will have. Privoxy version numbers consist of three numbers, separated by dots, like in X.Y.Z (e.g. 3.0.0), where:

    • X, the version major, is rarely ever changed. It is increased by one if turning a development branch into stable substantially changes the functionality, user interface or configuration syntax. Majors 1 and 2 were Junkbuster, and 3 will be the first stable Privoxy release.

    • Y, the version minor, represents the branch within the major version. At any point in time, there are two branches being maintained: The stable branch, with an even minor, say, 2N, in which no functionality is being added and only bug-fixes are made, and 2N+1, the development branch, in which the further development of Privoxy takes place. This enables us to turn the code upside down and inside out, while at the same time providing and maintaining a stable version. The minor is reset to zero (and one) when the major is incremented. When a development branch has matured to the point where it can be turned into stable, the old stable branch 2N is given up (i.e. no longer maintained), the former development branch 2N+1 becomes the new stable branch 2N+2, and a new development branch 2N+3 is opened.

    • Z, the point or sub version, represents a release of the software within a branch. It is therefore incremented immediately before each code freeze. In development branches, only the even point versions correspond to actual releases, while the odd ones denote the evolving state of the sources on CVS in between. It follows that Z is odd on CVS in development branches most of the time. There, it gets increased to an even number immediately before a code freeze, and is increased to an odd number again immediately thereafter. This ensures that builds from CVS snapshots are easily distinguished from released versions. The point version is reset to zero when the minor changes.

      Stable branches work a little differently, since there should be little to no development happening in such branches. Remember, only bugfixes, which presumably should have had some testing before being committed. Stable branches will then have their version reported as 0.0.0, during that period between releases when changes are being added. This is to denote that this code is not for release. Then as the release nears, the version is bumped according: e.g. 3.0.1 -> 0.0.0 -> 3.0.2.

    In summary, the main CVS trunk is the development branch where new features are being worked on for the next stable series. This should almost always be where the most activity takes place. There is always at least one stable branch from the trunk, e.g now it is 3.0, which is only used to release stable versions. Once the initial *.0 release of the stable branch has been done, then as a rule, only bugfixes that have had prior testing should be committed to the stable branch. Once there are enough bugfixes to justify a new release, the version of this branch is again incremented Example: 3.0.0 -> 3.0.1 -> 3.0.2, etc are all stable releases from within the stable branch. 3.1.x is currently the main trunk, and where work on 3.2.x is taking place. If any questions, please post to the devel list before committing to a stable branch!

    Developers should remember too that if they commit a bugfix to the stable branch, this will more than likely require a separate submission to the main trunk, since these are separate development trees within CVS. If you are working on both, then this would require at least two separate check outs (i.e main trunk, and the stable release branch, which is v_3_0_branch at the moment).

    6.2. Before the Release: Freeze

    The following must be done by one of the developers prior to each new release.

    • Make sure that everybody who has worked on the code in the last couple of days has had a chance to yell "no!" in case they have pending changes/fixes in their pipelines. Announce the freeze so that nobody will interfere with last minute changes.

    • Increment the version number (point from odd to even in development branches!) in configure.in. (RPM spec files will need to be incremented as well.)

    • If default.action has changed since last release (i.e. software release or standalone actions file release), bump up its version info to A.B in this line:

        {+add-header{X-Actions-File-Version: A.B} -filter -no-popups}
      

      Then change the version info in doc/webserver/actions/index.php, line: '$required_actions_file_version = "A.B";'

    • All documentation should be rebuild after the version bump. Finished docs should be then be committed to CVS (for those without the ability to build these). Some docs may require rather obscure processing tools. config, the man page (and the html version of the man page) fall in this category. REAMDE, the man page, AUTHORS, and config should all also be committed to CVS for other packagers. The formal docs should be uploaded to the webserver. See the Section "Updating the webserver" in this manual for details.

    • The User Manual is also used for context sensitive help for the CGI editor. This is version sensitive, so that the user will get appropriate help for his/her release. So with each release a fresh version should be uploaded to the webserver (this is in addition to the main User Manual link from the main page since we need to keep manuals for various versions available). The CGI pages will link to something like http://privoxy.org/$(VERSION)/user-manual/. This will need to be updated for each new release. There is no Makefile target for this at this time!!! It needs to be done manually.

    • All developers should look at the ChangeLog and make sure noteworthy changes are referenced.

    • Commit all files that were changed in the above steps!

    • Tag all files in CVS with the version number with "cvs tag v_X_Y_Z". Don't use vX_Y_Z, ver_X_Y_Z, v_X.Y.Z (won't work) etc.

    • If the release was in a development branch, increase the point version from even to odd (X.Y.(Z+1)) again in configure.in and commit your change.

    • On the webserver, copy the user manual to a new top-level directory called X.Y.Z. This ensures that help links from the CGI pages, which have the version as a prefix, will go into the right version of the manual. If this is a development branch release, also symlink X.Y.(Z-1) to X.Y.Z and X.Y.(Z+1) to . (i.e. dot).

    6.3. Building and Releasing the Packages

    Now the individual packages can be built and released. Note that for GPL reasons the first package to be released is always the source tarball.

    For all types of packages, including the source tarball, you must make sure that you build from clean sources by exporting the right version from CVS into an empty directory (just press return when asked for a password):

      mkdir dist # delete or choose different name if it already exists
      cd dist
      cvs -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa login
      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa export -r v_X_Y_Z current
    

    Do NOT change a single bit, including, but not limited to version information after export from CVS. This is to make sure that all release packages, and with them, all future bug reports, are based on exactly the same code.

    Warning

    Every significant release of Privoxy has included at least one package that either had incorrect versions of files, missing files, or incidental leftovers from a previous build process that gave unknown numbers of users headaches to try to figure out what was wrong. PLEASE, make sure you are using pristene sources, and are following the prescribed process!

    Please find additional instructions for the source tarball and the individual platform dependent binary packages below. And details on the Sourceforge release process below that.

    6.3.1. Note on Privoxy Packaging

    Please keep these general guidelines in mind when putting together your package. These apply to all platforms!

    • Privoxy requires write access to: all *.action files, all logfiles, and the trust file. You will need to determine the best way to do this for your platform.

    • Please include up to date documentation. At a bare minimum:

      LICENSE (top-level directory)
      README (top-level directory)
      AUTHORS (top-level directory)
      man page (top-level directory, Unix-like platforms only)
      The User Manual (doc/webserver/user-manual/)
      FAQ (doc/webserver/faq/)

      Also suggested: Developer Manual (doc/webserver/developer-manual) and ChangeLog (top-level directory). FAQ and the manuals are HTML docs. There are also text versions in doc/text/ which could conceivably also be included.

      The documentation has been designed such that the manuals are linked to each other from parallel directories, and should be packaged that way. privoxy-index.html can also be included and can serve as a focal point for docs and other links of interest (and possibly renamed to index.html). This should be one level up from the manuals. There is a link also on this page to an HTMLized version of the man page. To avoid 404 for this, it is in CVS as doc/webserver/man-page/privoxy-man-page.html, and should be included along with the manuals. There is also a css stylesheets that can be included for better presentation: p_doc.css. This should be in the same directory with privoxy-index.html, (i.e. one level up from the manual directories).

    • user.action and user.filter are designed for local preferences. Make sure these do not get overwritten! config should not be overwritten either. This has especially important configuration data in it. trust should be left in tact as well.

    • Other configuration files (default.action and default.filter) should be installed as the new defaults, but all previously installed configuration files should be preserved as backups. This is just good manners :-) These files are likely to change between releases and contain important new features and bug fixes.

    • Please check platform specific notes in this doc, if you haven't done "Privoxy" packaging before for other platform specific issues. Conversely, please add any notes that you know are important for your platform (or contact one of the doc maintainers to do this if you can't).

    • Packagers should do a "clean" install of their package after building it. So any previous installs should be removed first to ensure the integrity of the newly built package. Then run the package for a while to make sure there are no obvious problems, before uploading.

    6.3.2. Source Tarball

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then do:

      make tarball-dist
    

    To upload the package to Sourceforge, simply issue

      make tarball-upload
    

    Go to the displayed URL and release the file publicly on Sourceforge. For the change log field, use the relevant section of the ChangeLog file.

    6.3.3. SuSE, Conectiva or Red Hat RPM

    In following text, replace dist with either "rh" for Red Hat or "suse" for SuSE.

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above).

    As the only exception to not changing anything after export from CVS, now examine the file privoxy-dist.spec and make sure that the version information and the RPM release number are correct. The RPM release numbers for each version start at one. Hence it must be reset to one if this is the first RPM for dist which is built from version X.Y.Z. Check the file list if unsure. Else, it must be set to the highest already available RPM release number for that version plus one.

    Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then do

      make dist-dist
    

    To upload the package to Sourceforge, simply issue

      make dist-upload rpm_packagerev
    

    where rpm_packagerev is the RPM release number as determined above. Go to the displayed URL and release the file publicly on Sourceforge. Use the release notes and change log from the source tarball package.

    6.3.4. OS/2

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then get the OS/2 Setup module:

      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co os2setup
    

    You will need a mix of development tools. The main compilation takes place with IBM Visual Age C++. Some ancillary work takes place with GNU tools, available from various sources like hobbes.nmsu.edu. Specificially, you will need autoheader, autoconf and sh tools. The packaging takes place with WarpIN, available from various sources, including its home page: xworkplace.

    Change directory to the os2setup directory. Edit the os2build.cmd file to set the final executable filename. For example,

      installExeName='privoxyos2_setup_X.Y.Z.exe'
    

    Next, edit the IJB.wis file so the release number matches in the PACKAGEID section:

      PACKAGEID="Privoxy Team\Privoxy\Privoxy Package\X\Y\Z"
    

    You're now ready to build. Run:

      os2build
    

    You will find the WarpIN-installable executable in the ./files directory. Upload this anonymously to uploads.sourceforge.net/incoming, create a release for it, and you're done. Use the release notes and Change Log from the source tarball package.

    6.3.5. Solaris

    Login to Sourceforge's compilefarm via ssh:

      ssh cf.sourceforge.net
    

    Choose the right operating system (not the Debian one). When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then run

      gmake solaris-dist
    

    which creates a gzip'ed tar archive. Sadly, you cannot use make solaris-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package.

    6.3.6. Windows

    You should ensure you have the latest version of Cygwin (from http://www.cygwin.com/). Run the following commands from within a Cygwin bash shell.

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then get the Windows setup module:

      cvs -z3  -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co winsetup
    

    Then you can build the package. This is fully automated, and is controlled by winsetup/GNUmakefile. All you need to do is:

      cd winsetup
      make
    

    Now you can manually rename privoxy_setup.exe to privoxy_setup_X_Y_Z.exe, and upload it to SourceForge. When releasing the package on SourceForge, use the release notes and Change Log from the source tarball package.

    6.3.7. Debian

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then add a log entry to debian/changelog, if it is not already there, for example by running:

      debchange -v 3.0.21-stable-1 "New upstream version"
    

    Then, run:

      dpkg-buildpackage -rfakeroot -us -uc -b
    

    This will create ../privoxy_3.0.21-stable-1_i386.deb which can be uploaded. To upload the package to Sourceforge, simply issue

      make debian-upload
    

    6.3.8. Mac OS X

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above).

    There are three modules available in the CVS repository for use on Mac OS X, though technically only two of them generate a release (the other can be used to install from source).

    6.3.8.1. OSXPackageBuilder module

    The OSXPackageBuilder module generates OS X installer packages supporting all Macs running OS X 10.4 and above. Obtain it from CVS as follows into a folder parallel to the exported privoxy source:

      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co OSXPackageBuilder
    

    The module contains complete instructions on its usage in the file OS X Package Builder HOWTO.txt.

    Once the package(s) have been generated, you can then upload them directly to the Files section of the Sourceforge project in the Macintosh (OS X) folder. Each new version release of Privoxy should have a new subfolder created in which to store its files. Please ensure that the folder contains a readme file that makes it clear which package is for whichversion of OS X.

    6.3.8.2. osxsetup module (DEPRECATED)

    This module is deprecated since the installer it generates places all Privoxy files in one folder in a non-standard location, and supports only Intel Macs running OS X 10.6 or higher.

    Check out the module from CVS as follows into a folder parallel to the exported privoxy source:

      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co osxsetup
    

    Then run:

      cd osxsetup
      build
    

    This will run autoheader, autoconf and configure as well as make. Finally, it will copy over the necessary files to the ./osxsetup/files directory for further processing by PackageMaker.

    Bring up PackageMaker with the PrivoxyPackage.pmsp definition file, modify the package name to match the release, and hit the "Create package" button. If you specify ./Privoxy.pkg as the output package name, you can then create the distributable zip file with the command:

      zip -r privoxyosx_setup_x.y.z.zip Privoxy.pkg
    

    You can then upload this file directly to the Files section of the Sourceforge project in the Macintosh (OS X) folder. Each new version release of Privoxy should have a new subfolder created in which to store its files. Please ensure that the folder contains a readme file that makes it clear which version(s) of OS X the package supports.

    6.3.8.3. macsetup module

    The macsetup module is ideal if you wish to build and install Privoxy from source on a single machine.

    Check out the module from CVS as follows into a folder parallel to the exported privoxy source:

      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co macsetup
    

    The module contains complete instructions on its usage in its README file. The end result will be the exported version of Privoxy installed on the build machine.

    6.3.9. FreeBSD

    Login to Sourceforge's compile-farm via ssh:

      ssh cf.sourceforge.net
    

    Choose the right operating system. When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then run:

      gmake freebsd-dist
    

    which creates a gzip'ed tar archive. Sadly, you cannot use make freebsd-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package.

    6.3.10. HP-UX 11

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then do FIXME.

    6.3.11. Amiga OS

    First, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then do FIXME.

    6.3.12. AIX

    Login to Sourceforge's compilefarm via ssh:

      ssh cf.sourceforge.net
    

    Choose the right operating system. When logged in, make sure that you have freshly exported the right version into an empty directory. (See "Building and releasing packages" above). Then run:

      cd current
      autoheader && autoconf && ./configure
    

    Then run:

      make aix-dist
    

    which creates a gzip'ed tar archive. Sadly, you cannot use make aix-upload on the Sourceforge machine (no ncftpput). You now have to manually upload the archive to Sourceforge's ftp server and release the file publicly. Use the release notes and Change Log from the source tarball package.

    6.4. Uploading and Releasing Your Package

    After the package is ready, it is time to upload it to SourceForge, and go through the release steps. The upload is done via FTP:

    Or use the make targets as described above.

    Once this done go to https://sourceforge.net/project/admin/editpackages.php?group_id=11118, making sure you are logged in. Find your target platform in the second column, and click Add Release. You will then need to create a new release for your package, using the format of $VERSION ($CODE_STATUS), e.g. 3.0.21 (beta).

    Now just follow the prompts. Be sure to add any appropriate Release notes. You should see your freshly uploaded packages in "Step 2. Add Files To This Release". Check the appropriate box(es). Remember at each step to hit the "Refresh/Submit" buttons! You should now see your file(s) listed in Step 3. Fill out the forms with the appropriate information for your platform, being sure to hit "Update" for each file. If anyone is monitoring your platform, check the "email" box at the very bottom to notify them of the new package. This should do it!

    If you have made errors, or need to make changes, you can go through essentially the same steps, but select Edit Release, instead of Add Release.

    6.5. After the Release

    When all (or: most of the) packages have been uploaded and made available, send an email to the announce mailing list, Subject: "Version X.Y.Z available for download". Be sure to include the download location, the release notes and the Changelog. Also, post an updated News item on the project page Sourceforge, and update the Home page and docs linked from the Home page (see below). Other news sites and release oriented sites, such as Freshmeat, should also be notified.

    privoxy-3.0.21-stable/./doc/webserver/developer-manual/cvs.html000640 001751 001751 00000014062 12040771132 023454 0ustar00fkfk000000 000000 The CVS Repository

    2. The CVS Repository

    If you become part of the active development team, you will eventually need write access to our holy grail, the CVS repository. One of the team members will need to set this up for you. Please read this chapter completely before accessing via CVS.

    2.1. Access to CVS

    The project's CVS repository is hosted on SourceForge. Please refer to the chapters 6 and 7 in SF's site documentation for the technical access details for your operating system. For historical reasons, the CVS server is called ijbswa.cvs.sourceforge.net, the repository is called ijbswa, and the source tree module is called current.

    2.2. Branches

    Within the CVS repository, there are modules and branches. As mentioned, the sources are in the current "module". Other modules are present for platform specific issues. There is a webview of the CVS hierarchy at http://ijbswa.cvs.sourceforge.net/ijbswa/, which might help with visualizing how these pieces fit together.

    At one time there were two distinct branches: stable and unstable. The more drastic changes were to be in the unstable branch. These branches have now been merged to minimize time and effort of maintaining two branches.

    2.3. CVS Commit Guidelines

    The source tree is the heart of every software project. Every effort must be made to ensure that it is readable, compilable and consistent at all times. We expect anyone with CVS access to strictly adhere to the following guidelines:

    Basic Guidelines, for all branches:

    • Please don't commit even a small change without testing it thoroughly first. When we're close to a public release, ask a fellow developer to review your changes.

    • Your commit message should give a concise overview of what you changed (no big details) and why you changed it Just check previous messages for good examples.

    • Don't use the same message on multiple files, unless it equally applies to all those files.

    • If your changes span multiple files, and the code won't recompile unless all changes are committed (e.g. when changing the signature of a function), then commit all files one after another, without long delays in between. If necessary, prepare the commit messages in advance.

    • Before changing things on CVS, make sure that your changes are in line with the team's general consensus on what should be done.

    • Note that near a major public release, we get more cautious. There is always the possibility to submit a patch to the patch tracker instead.

    privoxy-3.0.21-stable/./doc/webserver/developer-manual/testing.html000640 001751 001751 00000010655 12026576114 024351 0ustar00fkfk000000 000000 Testing Guidelines

    5. Testing Guidelines

    To be filled.

    5.1. Testplan for releases

    Explain release numbers. major, minor. developer releases. etc.

    1. Remove any existing rpm with rpm -e

    2. Remove any file that was left over. This includes (but is not limited to)

      • /var/log/privoxy

      • /etc/privoxy

      • /usr/sbin/privoxy

      • /etc/init.d/privoxy

      • /usr/doc/privoxy*

    3. Install the rpm. Any error messages?

    4. start,stop,status Privoxy with the specific script (e.g. /etc/rc.d/init/privoxy stop). Reboot your machine. Does autostart work?

    5. Start browsing. Does Privoxy work? Logfile written?

    6. Remove the rpm. Any error messages? All files removed?

    5.2. Test reports

    Please submit test reports only with the test form at sourceforge. Three simple steps:

    • Select category: the distribution you test on.

    • Select group: the version of Privoxy that we are about to release.

    • Fill the Summary and Detailed Description with something intelligent (keep it short and precise).

    Do not mail to the mailing list (we cannot keep track on issues there).
    privoxy-3.0.21-stable/./doc/webserver/developer-manual/introduction.html000640 001751 001751 00000007550 12026576114 025415 0ustar00fkfk000000 000000 Introduction

    1. Introduction

    Privoxy, as an heir to Junkbuster, is a Free Software project and the code is licensed under the GNU General Public License version 2. As such, Privoxy development is potentially open to anyone who has the time, knowledge, and desire to contribute in any capacity. Our goals are simply to continue the mission, to improve Privoxy, and to make it available to as wide an audience as possible.

    One does not have to be a programmer to contribute. Packaging, testing, documenting and porting, are all important jobs as well.

    1.1. Quickstart to Privoxy Development

    The first step is to join the developer's mailing list. You can submit your ideas, or even better patches. Patches are best submitted to the Sourceforge tracker set up for this purpose, but can be sent to the list for review too.

    You will also need to have a cvs package installed, which will entail having ssh installed as well (which seems to be a requirement of SourceForge), in order to access the cvs repository. Having the GNU build tools is also going to be important (particularly, autoconf and gmake).

    For the time being (read, this section is under construction), you can also refer to the extensive comments in the source code. In fact, reading the code is recommended in any case.

    privoxy-3.0.21-stable/./doc/webserver/developer-manual/coding.html000640 001751 001751 00000147171 12040771132 024134 0ustar00fkfk000000 000000 Coding Guidelines

    4. Coding Guidelines

    4.1. Introduction

    This set of standards is designed to make our lives easier. It is developed with the simple goal of helping us keep the "new and improved Privoxy" consistent and reliable. Thus making maintenance easier and increasing chances of success of the project.

    And that of course comes back to us as individuals. If we can increase our development and product efficiencies then we can solve more of the request for changes/improvements and in general feel good about ourselves. ;->

    4.2. Using Comments

    4.2.1. Comment, Comment, Comment

    Explanation:

    Comment as much as possible without commenting the obvious. For example do not comment "variable_a is equal to variable_b". Instead explain why variable_a should be equal to the variable_b. Just because a person can read code does not mean they will understand why or what is being done. A reader may spend a lot more time figuring out what is going on when a simple comment or explanation would have prevented the extra research. Please help your fellow Privoxy developers out!

    The comments will also help justify the intent of the code. If the comment describes something different than what the code is doing then maybe a programming error is occurring.

    Example:

    /* if page size greater than 1k ... */
    if (page_length() > 1024)
    {
        ... "block" the page up ...
    }
    
    /* if page size is small, send it in blocks */
    if (page_length() > 1024)
    {
        ... "block" the page up ...
    }
    
    This demonstrates 2 cases of "what not to do".  The first is a
    "syntax comment".  The second is a comment that does not fit what
    is actually being done.
    

    4.2.2. Use blocks for comments

    Explanation:

    Comments can help or they can clutter. They help when they are differentiated from the code they describe. One line comments do not offer effective separation between the comment and the code. Block identifiers do, by surrounding the code with a clear, definable pattern.

    Example:

    /*********************************************************************
     * This will stand out clearly in your code!
     *********************************************************************/
    if (this_variable == that_variable)
    {
       do_something_very_important();
    }
    
    
    /* unfortunately, this may not */
    if (this_variable == that_variable)
    {
       do_something_very_important();
    }
    
    
    if (this_variable == that_variable) /* this may not either */
    {
       do_something_very_important();
    }
    

    Exception:

    If you are trying to add a small logic comment and do not wish to "disrupt" the flow of the code, feel free to use a 1 line comment which is NOT on the same line as the code.

    4.2.3. Keep Comments on their own line

    Explanation:

    It goes back to the question of readability. If the comment is on the same line as the code it will be harder to read than the comment that is on its own line.

    There are three exceptions to this rule, which should be violated freely and often: during the definition of variables, at the end of closing braces, when used to comment parameters.

    Example:

    /*********************************************************************
     * This will stand out clearly in your code,
     * But the second example won't.
     *********************************************************************/
    if (this_variable == this_variable)
    {
       do_something_very_important();
    }
    
    if (this_variable == this_variable) /*can you see me?*/
    {
       do_something_very_important(); /*not easily*/
    }
    
    
    /*********************************************************************
     * But, the encouraged exceptions:
     *********************************************************************/
    int urls_read     = 0;     /* # of urls read + rejected */
    int urls_rejected = 0;     /* # of urls rejected */
    
    if (1 == X)
    {
       do_something_very_important();
    }
    
    
    short do_something_very_important(
       short firstparam,   /* represents something */
       short nextparam     /* represents something else */ )
    {
       ...code here...
    
    }   /* -END- do_something_very_important */
    

    4.2.4. Comment each logical step

    Explanation:

    Logical steps should be commented to help others follow the intent of the written code and comments will make the code more readable.

    If you have 25 lines of code without a comment, you should probably go back into it to see where you forgot to put one.

    Most "for", "while", "do", etc... loops _probably_ need a comment. After all, these are usually major logic containers.

    4.2.5. Comment All Functions Thoroughly

    Explanation:

    A reader of the code should be able to look at the comments just prior to the beginning of a function and discern the reason for its existence and the consequences of using it. The reader should not have to read through the code to determine if a given function is safe for a desired use. The proper information thoroughly presented at the introduction of a function not only saves time for subsequent maintenance or debugging, it more importantly aids in code reuse by allowing a user to determine the safety and applicability of any function for the problem at hand. As a result of such benefits, all functions should contain the information presented in the addendum section of this document.

    4.2.6. Comment at the end of braces if the content is more than one screen length

    Explanation:

    Each closing brace should be followed on the same line by a comment that describes the origination of the brace if the original brace is off of the screen, or otherwise far away from the closing brace. This will simplify the debugging, maintenance, and readability of the code.

    As a suggestion , use the following flags to make the comment and its brace more readable:

    use following a closing brace: } /* -END- if() or while () or etc... */

    Example:

    if (1 == X)
    {
       do_something_very_important();
       ...some long list of commands...
    } /* -END- if x is 1 */
    
    or:
    
    if (1 == X)
    {
       do_something_very_important();
       ...some long list of commands...
    } /* -END- if (1 == X) */
    

    4.3. Naming Conventions

    4.3.1. Variable Names

    Explanation:

    Use all lowercase, and separate words via an underscore ('_'). Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.) Do not use identifiers which are reserved in ANSI C++. (E.g. template, class, true, false, ...). This is in case we ever decide to port Privoxy to C++.

    Example:

    int ms_iis5_hack = 0;
    

    Instead of:

    int msiis5hack = 0; int msIis5Hack = 0;
    

    4.3.2. Function Names

    Explanation:

    Use all lowercase, and separate words via an underscore ('_'). Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.) Do not use identifiers which are reserved in ANSI C++. (E.g. template, class, true, false, ...). This is in case we ever decide to port Privoxy to C++.

    Example:

    int load_some_file(struct client_state *csp)
    

    Instead of:

    int loadsomefile(struct client_state *csp)
    int loadSomeFile(struct client_state *csp)
    

    4.3.3. Header file prototypes

    Explanation:

    Use a descriptive parameter name in the function prototype in header files. Use the same parameter name in the header file that you use in the c file.

    Example:

    (.h) extern int load_aclfile(struct client_state *csp);
    (.c) int load_aclfile(struct client_state *csp)
    

    Instead of:

    (.h) extern int load_aclfile(struct client_state *); or
    (.h) extern int load_aclfile();
    (.c) int load_aclfile(struct client_state *csp)
    

    4.3.4. Enumerations, and #defines

    Explanation:

    Use all capital letters, with underscores between words. Do not start an identifier with an underscore. (ANSI C reserves these for use by the compiler and system headers.)

    Example:

    (enumeration) : enum Boolean {FALSE, TRUE};
    (#define) : #define DEFAULT_SIZE 100;
    

    Note: We have a standard naming scheme for #defines that toggle a feature in the preprocessor: FEATURE_>, where > is a short (preferably 1 or 2 word) description.

    Example:

    #define FEATURE_FORCE 1
    
    #ifdef FEATURE_FORCE
    #define FORCE_PREFIX blah
    #endif /* def FEATURE_FORCE */
    

    4.3.5. Constants

    Explanation:

    Spell common words out entirely (do not remove vowels).

    Use only widely-known domain acronyms and abbreviations. Capitalize all letters of an acronym.

    Use underscore (_) to separate adjacent acronyms and abbreviations. Never terminate a name with an underscore.

    Example:

    #define USE_IMAGE_LIST 1
    

    Instead of:

    #define USE_IMG_LST 1 or
    #define _USE_IMAGE_LIST 1 or
    #define USE_IMAGE_LIST_ 1 or
    #define use_image_list 1 or
    #define UseImageList 1
    

    4.4. Using Space

    4.4.1. Put braces on a line by themselves.

    Explanation:

    The brace needs to be on a line all by itself, not at the end of the statement. Curly braces should line up with the construct that they're associated with. This practice makes it easier to identify the opening and closing braces for a block.

    Example:

    if (this == that)
    {
       ...
    }
    

    Instead of:

    if (this == that) { ... }

    or

    if (this == that) { ... }

    Note: In the special case that the if-statement is inside a loop, and it is trivial, i.e. it tests for a condition that is obvious from the purpose of the block, one-liners as above may optically preserve the loop structure and make it easier to read.

    Status: developer-discretion.

    Example exception:

    while (more lines are read)
    {
       /* Please document what is/is not a comment line here */
       if (it's a comment) continue;
    
       do_something(line);
    }
    

    4.4.2. ALL control statements should have a block

    Explanation:

    Using braces to make a block will make your code more readable and less prone to error. All control statements should have a block defined.

    Example:

    if (this == that)
    {
       do_something();
       do_something_else();
    }
    

    Instead of:

    if (this == that) do_something(); do_something_else();

    or

    if (this == that) do_something();

    Note: The first example in "Instead of" will execute in a manner other than that which the developer desired (per indentation). Using code braces would have prevented this "feature". The "explanation" and "exception" from the point above also applies.

    4.4.3. Do not belabor/blow-up boolean expressions

    Example:

    structure->flag = (condition);
    

    Instead of:

    if (condition) { structure->flag = 1; } else { structure->flag = 0; }

    Note: The former is readable and concise. The later is wordy and inefficient. Please assume that any developer new to the project has at least a "good" knowledge of C/C++. (Hope I do not offend by that last comment ... 8-)

    4.4.4. Use white space freely because it is free

    Explanation:

    Make it readable. The notable exception to using white space freely is listed in the next guideline.

    Example:

    int first_value   = 0;
    int some_value    = 0;
    int another_value = 0;
    int this_variable = 0;
    

    4.4.5. Don't use white space around structure operators

    Explanation:

    - structure pointer operator ( "->" ) - member operator ( "." ) - functions and parentheses

    It is a general coding practice to put pointers, references, and function parentheses next to names. With spaces, the connection between the object and variable/function name is not as clear.

    Example:

    a_struct->a_member;
    a_struct.a_member;
    function_name();
    

    Instead of: a_struct -> a_member; a_struct . a_member; function_name ();

    4.4.6. Make the last brace of a function stand out

    Example:

    int function1( ... )
    {
       ...code...
       return(ret_code);
    
    } /* -END- function1 */
    
    
    int function2( ... )
    {
    } /* -END- function2 */
    

    Instead of:

    int function1( ... ) { ...code... return(ret_code); } int function2( ... ) { }

    Note: Use 1 blank line before the closing brace and 2 lines afterward. This makes the end of function standout to the most casual viewer. Although function comments help separate functions, this is still a good coding practice. In fact, I follow these rules when using blocks in "for", "while", "do" loops, and long if {} statements too. After all whitespace is free!

    Status: developer-discretion on the number of blank lines. Enforced is the end of function comments.

    4.4.7. Use 3 character indentions

    Explanation:

    If some use 8 character TABs and some use 3 character TABs, the code can look *very* ragged. So use 3 character indentions only. If you like to use TABs, pass your code through a filter such as "expand -t3" before checking in your code.

    Example:

    static const char * const url_code_map[256] =
    {
       NULL, ...
    };
    
    
    int function1( ... )
    {
       if (1)
       {
          return ALWAYS_TRUE;
       }
       else
       {
          return HOW_DID_YOU_GET_HERE;
       }
    
       return NEVER_GETS_HERE;
    
    }
    

    4.5. Initializing

    4.5.1. Initialize all variables

    Explanation:

    Do not assume that the variables declared will not be used until after they have been assigned a value somewhere else in the code. Remove the chance of accidentally using an unassigned variable.

    Example:

    short a_short = 0;
    float a_float  = 0;
    struct *ptr = NULL;
    

    Note: It is much easier to debug a SIGSEGV if the message says you are trying to access memory address 00000000 and not 129FA012; or array_ptr[20] causes a SIGSEV vs. array_ptr[0].

    Status: developer-discretion if and only if the variable is assigned a value "shortly after" declaration.

    4.6. Functions

    4.6.1. Name functions that return a boolean as a question.

    Explanation:

    Value should be phrased as a question that would logically be answered as a true or false statement

    Example:

    should_we_block_this();
    contains_an_image();
    is_web_page_blank();
    

    4.6.2. Always specify a return type for a function.

    Explanation:

    The default return for a function is an int. To avoid ambiguity, create a return for a function when the return has a purpose, and create a void return type if the function does not need to return anything.

    4.6.3. Minimize function calls when iterating by using variables

    Explanation:

    It is easy to write the following code, and a clear argument can be made that the code is easy to understand:

    Example:

    for (size_t cnt = 0; cnt < block_list_length(); cnt++)
    {
       ....
    }
    

    Note: Unfortunately, this makes a function call for each and every iteration. This increases the overhead in the program, because the compiler has to look up the function each time, call it, and return a value. Depending on what occurs in the block_list_length() call, it might even be creating and destroying structures with each iteration, even though in each case it is comparing "cnt" to the same value, over and over. Remember too - even a call to block_list_length() is a function call, with the same overhead.

    Instead of using a function call during the iterations, assign the value to a variable, and evaluate using the variable.

    Example:

    size_t len = block_list_length();
    
    for (size_t cnt = 0; cnt < len; cnt++)
    {
       ....
    }
    

    Exceptions: if the value of block_list_length() *may* change or could *potentially* change, then you must code the function call in the for/while loop.

    4.6.4. Pass and Return by Const Reference

    Explanation:

    This allows a developer to define a const pointer and call your function. If your function does not have the const keyword, we may not be able to use your function. Consider strcmp, if it were defined as: extern int strcmp(char *s1, char *s2);

    I could then not use it to compare argv's in main: int main(int argc, const char *argv[]) { strcmp(argv[0], "privoxy"); }

    Both these pointers are *const*! If the c runtime library maintainers do it, we should too.

    4.6.5. Pass and Return by Value

    Explanation:

    Most structures cannot fit onto a normal stack entry (i.e. they are not 4 bytes or less). Aka, a function declaration like: int load_aclfile(struct client_state csp)

    would not work. So, to be consistent, we should declare all prototypes with "pass by value": int load_aclfile(struct client_state *csp)

    4.6.6. Names of include files

    Explanation:

    Your include statements should contain the file name without a path. The path should be listed in the Makefile, using -I as processor directive to search the indicated paths. An exception to this would be for some proprietary software that utilizes a partial path to distinguish their header files from system or other header files.

    Example:

    #include <iostream.h>     /* This is not a local include */
    #include "config.h"       /* This IS a local include */
    

    Exception:

    /* This is not a local include, but requires a path element. */
    #include <sys/fileName.h>
    

    Note: Please! do not add "-I." to the Makefile without a _very_ good reason. This duplicates the #include "file.h" behavior.

    4.6.7. Provide multiple inclusion protection

    Explanation:

    Prevents compiler and linker errors resulting from redefinition of items.

    Wrap each header file with the following syntax to prevent multiple inclusions of the file. Of course, replace PROJECT_H with your file name, with "." Changed to "_", and make it uppercase.

    Example:

    #ifndef PROJECT_H_INCLUDED
    #define PROJECT_H_INCLUDED
     ...
    #endif /* ndef PROJECT_H_INCLUDED */
    

    4.6.8. Use `extern "C"` when appropriate

    Explanation:

    If our headers are included from C++, they must declare our functions as `extern "C"`. This has no cost in C, but increases the potential re-usability of our code.

    Example:

    #ifdef __cplusplus
    extern "C"
    {
    #endif /* def __cplusplus */
    
    ... function definitions here ...
    
    #ifdef __cplusplus
    }
    #endif /* def __cplusplus */
    

    4.6.9. Where Possible, Use Forward Struct Declaration Instead of Includes

    Explanation:

    Useful in headers that include pointers to other struct's. Modifications to excess header files may cause needless compiles.

    Example:

    /*********************************************************************
     * We're avoiding an include statement here!
     *********************************************************************/
    struct file_list;
    extern file_list *xyz;
    

    Note: If you declare "file_list xyz;" (without the pointer), then including the proper header file is necessary. If you only want to prototype a pointer, however, the header file is unnecessary.

    Status: Use with discretion.

    4.7. General Coding Practices

    4.7.1. Turn on warnings

    Explanation

    Compiler warnings are meant to help you find bugs. You should turn on as many as possible. With GCC, the switch is "-Wall". Try and fix as many warnings as possible.

    4.7.2. Provide a default case for all switch statements

    Explanation:

    What you think is guaranteed is never really guaranteed. The value that you don't think you need to check is the one that someday will be passed. So, to protect yourself from the unknown, always have a default step in a switch statement.

    Example:

    switch (hash_string(cmd))
    {
       case hash_actions_file:
          ... code ...
          break;
    
       case hash_confdir:
          ... code ...
          break;
    
       default:
          log_error( ... );
          ... anomaly code goes here ...
          continue; / break; / exit( 1 ); / etc ...
    
    } /* end switch (hash_string(cmd)) */
    

    Note: If you already have a default condition, you are obviously exempt from this point. Of note, most of the WIN32 code calls `DefWindowProc' after the switch statement. This API call *should* be included in a default statement.

    Another Note: This is not so much a readability issue as a robust programming issue. The "anomaly code goes here" may be no more than a print to the STDERR stream (as in load_config). Or it may really be an abort condition.

    Status: Programmer discretion is advised.

    4.7.3. Try to avoid falling through cases in a switch statement.

    Explanation:

    In general, you will want to have a 'break' statement within each 'case' of a switch statement. This allows for the code to be more readable and understandable, and furthermore can prevent unwanted surprises if someone else later gets creative and moves the code around.

    The language allows you to plan the fall through from one case statement to another simply by omitting the break statement within the case statement. This feature does have benefits, but should only be used in rare cases. In general, use a break statement for each case statement.

    If you choose to allow fall through, you should comment both the fact of the fall through and reason why you felt it was necessary.

    4.7.4. Don't mix size_t and other types

    Explanation:

    The type of size_t varies across platforms. Do not make assumptions about whether it is signed or unsigned, or about how long it is. Do not compare a size_t against another variable of a different type (or even against a constant) without casting one of the values.

    4.7.5. Declare each variable and struct on its own line.

    Explanation:

    It can be tempting to declare a series of variables all on one line. Don't.

    Example:

    long a = 0;
    long b = 0;
    long c = 0;
    

    Instead of:

    long a, b, c;

    Explanation: - there is more room for comments on the individual variables - easier to add new variables without messing up the original ones - when searching on a variable to find its type, there is less clutter to "visually" eliminate

    Exceptions: when you want to declare a bunch of loop variables or other trivial variables; feel free to declare them on one line. You should, although, provide a good comment on their functions.

    Status: developer-discretion.

    4.7.6. Use malloc/zalloc sparingly

    Explanation:

    Create a local struct (on the stack) if the variable will live and die within the context of one function call.

    Only "malloc" a struct (on the heap) if the variable's life will extend beyond the context of one function call.

    Example:

    If a function creates a struct and stores a pointer to it in a
    list, then it should definitely be allocated via `malloc'.
    

    4.7.7. The Programmer Who Uses 'malloc' is Responsible for Ensuring 'free'

    Explanation:

    If you have to "malloc" an instance, you are responsible for insuring that the instance is `free'd, even if the deallocation event falls within some other programmer's code. You are also responsible for ensuring that deletion is timely (i.e. not too soon, not too late). This is known as "low-coupling" and is a "good thing (tm)". You may need to offer a free/unload/destructor type function to accommodate this.

    Example:

    int load_re_filterfile(struct client_state *csp) { ... }
    static void unload_re_filterfile(void *f) { ... }
    

    Exceptions:

    The developer cannot be expected to provide `free'ing functions for C run-time library functions ... such as `strdup'.

    Status: developer-discretion. The "main" use of this standard is for allocating and freeing data structures (complex or nested).

    4.7.8. Add loaders to the `file_list' structure and in order

    Explanation:

    I have ordered all of the "blocker" file code to be in alpha order. It is easier to add/read new blockers when you expect a certain order.

    Note: It may appear that the alpha order is broken in places by POPUP tests coming before PCRS tests. But since POPUPs can also be referred to as KILLPOPUPs, it is clear that it should come first.

    4.7.9. "Uncertain" new code and/or changes to existing code, use XXX

    Explanation:

    If you have enough confidence in new code or confidence in your changes, but are not *quite* sure of the repercussions, add this:

    /* XXX: this code has a logic error on platform XYZ, * attempting to fix */ #ifdef PLATFORM ...changed code here... #endif

    or:

    /* XXX: I think the original author really meant this... */ ...changed code here...

    or:

    /* XXX: new code that *may* break something else... */ ...new code here...

    Note: If you make it clear that this may or may not be a "good thing (tm)", it will be easier to identify and include in the project (or conversely exclude from the project).

    4.8. Addendum: Template for files and function comment blocks:

    Example for file comments:

    const char FILENAME_rcs[] = "$I<!-- Break CVS Substitution -->d$";
    /*********************************************************************
     *
     * File        :  $S<!-- Break CVS Substitution -->ource$
     *
     * Purpose     :  (Fill me in with a good description!)
     *
     * Copyright   :  Written by and Copyright (C) 2001-2009
     *                the Privoxy team. http://www.privoxy.org/
     *
     *                This program is free software; you can redistribute it
     *                and/or modify it under the terms of the GNU General
     *                Public License as published by the Free Software
     *                Foundation; either version 2 of the License, or (at
     *                your option) any later version.
     *
     *                This program is distributed in the hope that it will
     *                be useful, but WITHOUT ANY WARRANTY; without even the
     *                implied warranty of MERCHANTABILITY or FITNESS FOR A
     *                PARTICULAR PURPOSE.  See the GNU General Public
     *                License for more details.
     *
     *                The GNU General Public License should be included with
     *                this file.  If not, you can view it at
     *                http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
     *                or write to the Free Software Foundation, Inc.,
     *                51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 ,
     *                USA
     *
     *********************************************************************/
    
    
    #include "config.h"
    
       ...necessary include files for us to do our work...
    
    const char FILENAME_h_rcs[] = FILENAME_H_VERSION;
    

    Note: This declares the rcs variables that should be added to the "show-proxy-args" page. If this is a brand new creation by you, you are free to change the "Copyright" section to represent the rights you wish to maintain.

    Note: The formfeed character that is present right after the comment flower box is handy for (X|GNU)Emacs users to skip the verbiage and get to the heart of the code (via `forward-page' and `backward-page'). Please include it if you can.

    Example for file header comments:

    #ifndef _FILENAME_H
    #define _FILENAME_H
    #define FILENAME_H_VERSION "$I<!-- Break CVS Substitution -->d$"
    /*********************************************************************
     *
     * File        :  $S<!-- Break CVS Substitution -->ource$
     *
     * Purpose     :  (Fill me in with a good description!)
     *
     * Copyright   :  Written by and Copyright (C) 2001-2009
     *                the Privoxy team. http://www.privoxy.org/
     *
     *                This program is free software; you can redistribute it
     *                and/or modify it under the terms of the GNU General
     *                Public License as published by the Free Software
     *                Foundation; either version 2 of the License, or (at
     *                your option) any later version.
     *
     *                This program is distributed in the hope that it will
     *                be useful, but WITHOUT ANY WARRANTY; without even the
     *                implied warranty of MERCHANTABILITY or FITNESS FOR A
     *                PARTICULAR PURPOSE.  See the GNU General Public
     *                License for more details.
     *
     *                The GNU General Public License should be included with
     *                this file.  If not, you can view it at
     *                http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
     *                or write to the Free Software Foundation, Inc.,
     *                51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 ,
     *                USA
     *
     *********************************************************************/
    
    
    #include "project.h"
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
       ... function headers here ...
    
    
    /* Revision control strings from this header and associated .c file */
    extern const char FILENAME_rcs[];
    extern const char FILENAME_h_rcs[];
    
    
    #ifdef __cplusplus
    } /* extern "C" */
    #endif
    
    #endif /* ndef _FILENAME_H */
    
    /*
      Local Variables:
      tab-width: 3
      end:
    */
    

    Example for function comments:

    /*********************************************************************
     *
     * Function    :  FUNCTION_NAME
     *
     * Description :  (Fill me in with a good description!)
     *
     * parameters  :
     *          1  :  param1 = pointer to an important thing
     *          2  :  x      = pointer to something else
     *
     * Returns     :  0 => Ok, everything else is an error.
     *
     *********************************************************************/
    int FUNCTION_NAME(void *param1, const char *x)
    {
       ...
       return 0;
    
    }
    

    Note: If we all follow this practice, we should be able to parse our code to create a "self-documenting" web page.

    privoxy-3.0.21-stable/./doc/webserver/developer-manual/documentation.html000640 001751 001751 00000044777 12113150317 025547 0ustar00fkfk000000 000000 Documentation Guidelines

    3. Documentation Guidelines

    All formal documents are maintained in Docbook SGML and located in the doc/source/* directory. You will need Docbook, the Docbook DTD's and the Docbook modular stylesheets (or comparable alternatives), and either jade or openjade (recommended) installed in order to build docs from source. Currently there is user-manual, FAQ, and, of course this, the developer-manual in this format. The README, AUTHORS, INSTALL, privoxy.1 (man page), and config files are also now maintained as Docbook SGML. These files, when built, in the top-level source directory are generated files! Also, the Privoxy index.html (and a variation on this file, privoxy-index.html, meant for inclusion with doc packages), are maintained as SGML as well. DO NOT edit these directly. Edit the SGML source, or contact someone involved in the documentation.

    config requires some special handling. The reason it is maintained this way is so that the extensive comments in the file mirror those in user-manual. But the conversion process requires going from SGML to HTML to text to special formatting required for the embedded comments. Some of this does not survive so well. Especially some of the examples that are longer than 80 characters. The build process for this file outputs to config.new, which should be reviewed for errors and mis-formatting. Once satisfied that it is correct, then it should be hand copied to config.

    Other, less formal documents (e.g. LICENSE) are maintained as plain text files in the top-level source directory.

    Packagers are encouraged to include this documentation. For those without the ability to build the docs locally, text versions of each are kept in CVS. HTML versions are also being kept in CVS under doc/webserver/*.

    Formal documents are built with the Makefile targets of make dok. The build process uses the document SGML sources in doc/source/*/* to update all text files in doc/text/ and to update all HTML documents in doc/webserver/.

    Documentation writers should please make sure documents build successfully before committing to CVS, if possible.

    How do you update the webserver (i.e. the pages on privoxy.org)?

    1. First, build the docs by running make dok.

    2. Run make webserver which copies all files from doc/webserver to the sourceforge webserver via scp.

    Finished docs should be occasionally submitted to CVS (doc/webserver/*/*.html) so that those without the ability to build them locally, have access to them if needed. This is especially important just prior to a new release! Please do this after the $VERSION and other release specific data in configure.in has been updated (this is done just prior to a new release).

    3.1. Quickstart to Docbook and SGML

    If you are not familiar with SGML, it is a markup language similar to HTML. Actually, not a mark up language per se, but a language used to define markup languages. In fact, HTML is an SGML application. Both will use "tags" to format text and other content. SGML tags can be much more varied, and flexible, but do much of the same kinds of things. The tags, or "elements", are definable in SGML. There is no set "standards". Since we are using Docbook, our tags are those that are defined by Docbook. Much of how the finish document is rendered is determined by the "stylesheets". The stylesheets determine how each tag gets translated to HTML, or other formats.

    Tags in Docbook SGML need to be always "closed". If not, you will likely generate errors. Example: <title>My Title</title>. They are also case-insensitive, but we strongly suggest using all lower case. This keeps compatibility with [Docbook] XML.

    Our documents use "sections" for the most part. Sections will be processed into HTML headers (e.g. h1 for sect1). The Docbook stylesheets will use these to also generate the Table of Contents for each doc. Our TOC's are set to a depth of three. Meaning sect1, sect2, and sect3 will have TOC entries, but sect4 will not. Each section requires a <title> element, and at least one <para>. There is a limit of five section levels in Docbook, but generally three should be sufficient for our purposes.

    Some common elements that you likely will use:

    <para></para>, paragraph delimiter. Most text needs to be within paragraph elements (there are some exceptions).
    <emphasis></emphasis>, the stylesheets make this italics.
    <filename></filename>, files and directories.
    <command></command>, command examples.
    <literallayout></literallayout>, like <pre>, more or less.
    <itemizedlist></itemizedlist>, list with bullets.
    <listitem></listitem>, member of the above.
    <screen></screen>, screen output, implies <literallayout>.
    <ulink url="example.com"></ulink>, like HTML <a> tag.
    <quote></quote>, for, doh, quoting text.

    Look at any of the existing docs for examples of all these and more.

    You might also find "Writing Documentation Using DocBook - A Crash Course" useful.

    3.2. Privoxy Documentation Style

    It will be easier if everyone follows a similar writing style. This just makes it easier to read what someone else has written if it is all done in a similar fashion.

    Here it is:

    • All tags should be lower case.

    • Tags delimiting a block of text (even small blocks) should be on their own line. Like:

       <para>
        Some text goes here.
       </para>
             

      Tags marking individual words, or few words, should be in-line:

        Just to <emphasis>emphasize</emphasis>, some text goes here.
             

    • Tags should be nested and step indented for block text like: (except in-line tags)

       <para>
        <itemizedlist>
         <para>
          <listitem>
            Some text goes here in our list example.
           </listitem>
         </para>
        </itemizedlist>
       </para>
             

      This makes it easier to find the text amongst the tags ;-)
    • Use white space to separate logical divisions within a document, like between sections. Running everything together consistently makes it harder to read and work on.

    • Do not hesitate to make comments. Comments can either use the <comment> element, or the <!-- --> style comment familiar from HTML. (Note in Docbook v4.x <comment> is replaced by <remark>.)

    • We have an international audience. Refrain from slang, or English idiosyncrasies (too many to list :). Humor also does not translate well sometimes.

    • Try to keep overall line lengths in source files to 80 characters or less for obvious reasons. This is not always possible, with lengthy URLs for instance.

    • Our documents are available in differing formats. Right now, they are just plain text and/or HTML, but others are always a future possibility. Be careful with URLs (<ulink>), and avoid this mistake:

      My favorite site is <ulink url="http://example.com">here</ulink>.

      This will render as "My favorite site is here", which is not real helpful in a text doc. Better like this:

      My favorite site is <ulink url="http://example.com">example.com</ulink>.

    • All documents should be spell checked occasionally. aspell can check SGML with the -H option. (ispell I think too.)

    3.3. Privoxy Custom Entities

    Privoxy documentation is using a number of customized "entities" to facilitate documentation maintenance.

    We are using a set of "boilerplate" files with generic text, that is used by multiple docs. This way we can write something once, and use it repeatedly without having to re-write the same content over and over again. If editing such a file, keep in mind that it should be generic. That is the purpose; so it can be used in varying contexts without additional modifications.

    We are also using what Docbook calls "internal entities". These are like variables in programming. Well, sort of. For instance, we have the p-version entity that contains the current Privoxy version string. You are strongly encouraged to use these where possible. Some of these obviously require re-setting with each release (done by the Makefile). A sampling of custom entities are listed below. See any of the main docs for examples.

    • Re- "boilerplate" text entities are defined like:

      <!entity supported SYSTEM "supported.sgml">

      In this example, the contents of the file, supported.sgml is available for inclusion anywhere in the doc. To make this happen, just reference the now defined entity: &supported; (starts with an ampersand and ends with a semi-colon), and the contents will be dumped into the finished doc at that point.

    • Commonly used "internal entities":

      p-version: the Privoxy version string, e.g. "3.0.21".
      p-status: the project status, either "alpha", "beta", or "stable".
      p-not-stable: use to conditionally include text in "not stable" releases (e.g. "beta").
      p-stable: just the opposite.
      p-text: this doc is only generated as text.

    There are others in various places that are defined for a specific purpose. Read the source!

    privoxy-3.0.21-stable/./doc/webserver/favicon.ico000640 001751 001751 00000000306 07122664100 020651 0ustar00fkfk000000 000000 °( @ÿÿÿÿ*ð?üqþqþñÿñÿððñÇñÇñÇðpþ?üððÀ€€€€Àðprivoxy-3.0.21-stable/./doc/webserver/user-manual/copyright.html000640 001751 001751 00000070126 12114164411 023663 0ustar00fkfk000000 000000 Privoxy Copyright, License and History

    12. Privoxy Copyright, License and History

    Copyright © 2001-2013 by Privoxy Developers

    Some source code is based on code Copyright © 1997 by Anonymous Coders and Junkbusters, Inc. and licensed under the GNU General Public License.

    Privoxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation and included in the next section.

    12.1. License

                         GNU GENERAL PUBLIC LICENSE
                           Version 2, June 1991
    
     Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.
    
                                Preamble
    
      The licenses for most software are designed to take away your
    freedom to share and change it.  By contrast, the GNU General Public
    License is intended to guarantee your freedom to share and change free
    software--to make sure the software is free for all its users.  This
    General Public License applies to most of the Free Software
    Foundation's software and to any other program whose authors commit to
    using it.  (Some other Free Software Foundation software is covered by
    the GNU Lesser General Public License instead.)  You can apply it to
    your programs, too.
    
      When we speak of free software, we are referring to freedom, not
    price.  Our General Public Licenses are designed to make sure that you
    have the freedom to distribute copies of free software (and charge for
    this service if you wish), that you receive source code or can get it
    if you want it, that you can change the software or use pieces of it
    in new free programs; and that you know you can do these things.
    
      To protect your rights, we need to make restrictions that forbid
    anyone to deny you these rights or to ask you to surrender the rights.
    These restrictions translate to certain responsibilities for you if you
    distribute copies of the software, or if you modify it.
    
      For example, if you distribute copies of such a program, whether
    gratis or for a fee, you must give the recipients all the rights that
    you have.  You must make sure that they, too, receive or can get the
    source code.  And you must show them these terms so they know their
    rights.
    
      We protect your rights with two steps: (1) copyright the software, and
    (2) offer you this license which gives you legal permission to copy,
    distribute and/or modify the software.
    
      Also, for each author's protection and ours, we want to make certain
    that everyone understands that there is no warranty for this free
    software.  If the software is modified by someone else and passed on, we
    want its recipients to know that what they have is not the original, so
    that any problems introduced by others will not reflect on the original
    authors' reputations.
    
      Finally, any free program is threatened constantly by software
    patents.  We wish to avoid the danger that redistributors of a free
    program will individually obtain patent licenses, in effect making the
    program proprietary.  To prevent this, we have made it clear that any
    patent must be licensed for everyone's free use or not licensed at all.
    
      The precise terms and conditions for copying, distribution and
    modification follow.
    
                        GNU GENERAL PUBLIC LICENSE
       TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    
      0. This License applies to any program or other work which contains
    a notice placed by the copyright holder saying it may be distributed
    under the terms of this General Public License.  The "Program", below,
    refers to any such program or work, and a "work based on the Program"
    means either the Program or any derivative work under copyright law:
    that is to say, a work containing the Program or a portion of it,
    either verbatim or with modifications and/or translated into another
    language.  (Hereinafter, translation is included without limitation in
    the term "modification".)  Each licensee is addressed as "you".
    
    Activities other than copying, distribution and modification are not
    covered by this License; they are outside its scope.  The act of
    running the Program is not restricted, and the output from the Program
    is covered only if its contents constitute a work based on the
    Program (independent of having been made by running the Program).
    Whether that is true depends on what the Program does.
    
      1. You may copy and distribute verbatim copies of the Program's
    source code as you receive it, in any medium, provided that you
    conspicuously and appropriately publish on each copy an appropriate
    copyright notice and disclaimer of warranty; keep intact all the
    notices that refer to this License and to the absence of any warranty;
    and give any other recipients of the Program a copy of this License
    along with the Program.
    
    You may charge a fee for the physical act of transferring a copy, and
    you may at your option offer warranty protection in exchange for a fee.
    
      2. You may modify your copy or copies of the Program or any portion
    of it, thus forming a work based on the Program, and copy and
    distribute such modifications or work under the terms of Section 1
    above, provided that you also meet all of these conditions:
    
        a) You must cause the modified files to carry prominent notices
        stating that you changed the files and the date of any change.
    
        b) You must cause any work that you distribute or publish, that in
        whole or in part contains or is derived from the Program or any
        part thereof, to be licensed as a whole at no charge to all third
        parties under the terms of this License.
    
        c) If the modified program normally reads commands interactively
        when run, you must cause it, when started running for such
        interactive use in the most ordinary way, to print or display an
        announcement including an appropriate copyright notice and a
        notice that there is no warranty (or else, saying that you provide
        a warranty) and that users may redistribute the program under
        these conditions, and telling the user how to view a copy of this
        License.  (Exception: if the Program itself is interactive but
        does not normally print such an announcement, your work based on
        the Program is not required to print an announcement.)
    
    These requirements apply to the modified work as a whole.  If
    identifiable sections of that work are not derived from the Program,
    and can be reasonably considered independent and separate works in
    themselves, then this License, and its terms, do not apply to those
    sections when you distribute them as separate works.  But when you
    distribute the same sections as part of a whole which is a work based
    on the Program, the distribution of the whole must be on the terms of
    this License, whose permissions for other licensees extend to the
    entire whole, and thus to each and every part regardless of who wrote it.
    
    Thus, it is not the intent of this section to claim rights or contest
    your rights to work written entirely by you; rather, the intent is to
    exercise the right to control the distribution of derivative or
    collective works based on the Program.
    
    In addition, mere aggregation of another work not based on the Program
    with the Program (or with a work based on the Program) on a volume of
    a storage or distribution medium does not bring the other work under
    the scope of this License.
    
      3. You may copy and distribute the Program (or a work based on it,
    under Section 2) in object code or executable form under the terms of
    Sections 1 and 2 above provided that you also do one of the following:
    
        a) Accompany it with the complete corresponding machine-readable
        source code, which must be distributed under the terms of Sections
        1 and 2 above on a medium customarily used for software interchange; or,
    
        b) Accompany it with a written offer, valid for at least three
        years, to give any third party, for a charge no more than your
        cost of physically performing source distribution, a complete
        machine-readable copy of the corresponding source code, to be
        distributed under the terms of Sections 1 and 2 above on a medium
        customarily used for software interchange; or,
    
        c) Accompany it with the information you received as to the offer
        to distribute corresponding source code.  (This alternative is
        allowed only for noncommercial distribution and only if you
        received the program in object code or executable form with such
        an offer, in accord with Subsection b above.)
    
    The source code for a work means the preferred form of the work for
    making modifications to it.  For an executable work, complete source
    code means all the source code for all modules it contains, plus any
    associated interface definition files, plus the scripts used to
    control compilation and installation of the executable.  However, as a
    special exception, the source code distributed need not include
    anything that is normally distributed (in either source or binary
    form) with the major components (compiler, kernel, and so on) of the
    operating system on which the executable runs, unless that component
    itself accompanies the executable.
    
    If distribution of executable or object code is made by offering
    access to copy from a designated place, then offering equivalent
    access to copy the source code from the same place counts as
    distribution of the source code, even though third parties are not
    compelled to copy the source along with the object code.
    
      4. You may not copy, modify, sublicense, or distribute the Program
    except as expressly provided under this License.  Any attempt
    otherwise to copy, modify, sublicense or distribute the Program is
    void, and will automatically terminate your rights under this License.
    However, parties who have received copies, or rights, from you under
    this License will not have their licenses terminated so long as such
    parties remain in full compliance.
    
      5. You are not required to accept this License, since you have not
    signed it.  However, nothing else grants you permission to modify or
    distribute the Program or its derivative works.  These actions are
    prohibited by law if you do not accept this License.  Therefore, by
    modifying or distributing the Program (or any work based on the
    Program), you indicate your acceptance of this License to do so, and
    all its terms and conditions for copying, distributing or modifying
    the Program or works based on it.
    
      6. Each time you redistribute the Program (or any work based on the
    Program), the recipient automatically receives a license from the
    original licensor to copy, distribute or modify the Program subject to
    these terms and conditions.  You may not impose any further
    restrictions on the recipients' exercise of the rights granted herein.
    You are not responsible for enforcing compliance by third parties to
    this License.
    
      7. If, as a consequence of a court judgment or allegation of patent
    infringement or for any other reason (not limited to patent issues),
    conditions are imposed on you (whether by court order, agreement or
    otherwise) that contradict the conditions of this License, they do not
    excuse you from the conditions of this License.  If you cannot
    distribute so as to satisfy simultaneously your obligations under this
    License and any other pertinent obligations, then as a consequence you
    may not distribute the Program at all.  For example, if a patent
    license would not permit royalty-free redistribution of the Program by
    all those who receive copies directly or indirectly through you, then
    the only way you could satisfy both it and this License would be to
    refrain entirely from distribution of the Program.
    
    If any portion of this section is held invalid or unenforceable under
    any particular circumstance, the balance of the section is intended to
    apply and the section as a whole is intended to apply in other
    circumstances.
    
    It is not the purpose of this section to induce you to infringe any
    patents or other property right claims or to contest validity of any
    such claims; this section has the sole purpose of protecting the
    integrity of the free software distribution system, which is
    implemented by public license practices.  Many people have made
    generous contributions to the wide range of software distributed
    through that system in reliance on consistent application of that
    system; it is up to the author/donor to decide if he or she is willing
    to distribute software through any other system and a licensee cannot
    impose that choice.
    
    This section is intended to make thoroughly clear what is believed to
    be a consequence of the rest of this License.
    
      8. If the distribution and/or use of the Program is restricted in
    certain countries either by patents or by copyrighted interfaces, the
    original copyright holder who places the Program under this License
    may add an explicit geographical distribution limitation excluding
    those countries, so that distribution is permitted only in or among
    countries not thus excluded.  In such case, this License incorporates
    the limitation as if written in the body of this License.
    
      9. The Free Software Foundation may publish revised and/or new versions
    of the General Public License from time to time.  Such new versions will
    be similar in spirit to the present version, but may differ in detail to
    address new problems or concerns.
    
    Each version is given a distinguishing version number.  If the Program
    specifies a version number of this License which applies to it and "any
    later version", you have the option of following the terms and conditions
    either of that version or of any later version published by the Free
    Software Foundation.  If the Program does not specify a version number of
    this License, you may choose any version ever published by the Free Software
    Foundation.
    
      10. If you wish to incorporate parts of the Program into other free
    programs whose distribution conditions are different, write to the author
    to ask for permission.  For software which is copyrighted by the Free
    Software Foundation, write to the Free Software Foundation; we sometimes
    make exceptions for this.  Our decision will be guided by the two goals
    of preserving the free status of all derivatives of our free software and
    of promoting the sharing and reuse of software generally.
    
                                NO WARRANTY
    
      11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
    OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
    TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
    PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
    REPAIR OR CORRECTION.
    
      12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
    OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
    TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
    YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
    PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGES.
    
                         END OF TERMS AND CONDITIONS
    
                How to Apply These Terms to Your New Programs
    
      If you develop a new program, and you want it to be of the greatest
    possible use to the public, the best way to achieve this is to make it
    free software which everyone can redistribute and change under these terms.
    
      To do so, attach the following notices to the program.  It is safest
    to attach them to the start of each source file to most effectively
    convey the exclusion of warranty; and each file should have at least
    the "copyright" line and a pointer to where the full notice is found.
    
        <one line to give the program's name and a brief idea of what it does.>
        Copyright (C) <year>  <name of author>
    
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License along
        with this program; if not, write to the Free Software Foundation, Inc.,
        51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    
    Also add information on how to contact you by electronic and paper mail.
    
    If the program is interactive, make it output a short notice like this
    when it starts in an interactive mode:
    
        Gnomovision version 69, Copyright (C) year name of author
        Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
        This is free software, and you are welcome to redistribute it
        under certain conditions; type `show c' for details.
    
    The hypothetical commands `show w' and `show c' should show the appropriate
    parts of the General Public License.  Of course, the commands you use may
    be called something other than `show w' and `show c'; they could even be
    mouse-clicks or menu items--whatever suits your program.
    
    You should also get your employer (if you work as a programmer) or your
    school, if any, to sign a "copyright disclaimer" for the program, if
    necessary.  Here is a sample; alter the names:
    
      Yoyodyne, Inc., hereby disclaims all copyright interest in the program
      `Gnomovision' (which makes passes at compilers) written by James Hacker.
    
      <signature of Ty Coon>, 1 April 1989
      Ty Coon, President of Vice
    
    This General Public License does not permit incorporating your program into
    proprietary programs.  If your program is a subroutine library, you may
    consider it more useful to permit linking proprietary applications with the
    library.  If this is what you want to do, use the GNU Lesser General
    Public License instead of this License.
    
    

    12.2. History

    A long time ago, there was the Internet Junkbuster, by Anonymous Coders and Junkbusters Corporation. This saved many users a lot of pain in the early days of web advertising and user tracking.

    But the web, its protocols and standards, and with it, the techniques for forcing ads on users, give up autonomy over their browsing, and for tracking them, keeps evolving. Unfortunately, the Internet Junkbuster did not. Version 2.0.2, published in 1998, was the last official release, available from Junkbusters Corporation. Fortunately, it had been released under the GNU GPL, which allowed further development by others.

    So Stefan Waldherr started maintaining an improved version of the software, to which eventually a number of people contributed patches. It could already replace banners with a transparent image, and had a first version of pop-up killing, but it was still very closely based on the original, with all its limitations, such as the lack of HTTP/1.1 support, flexible per-site configuration, or content modification. The last release from this effort was version 2.0.2-10, published in 2000.

    Then, some developers picked up the thread, and started turning the software inside out, upside down, and then reassembled it, adding many new features along the way.

    The result of this is Privoxy, whose first stable version, 3.0, was released August, 2002.

    As of 2012 the Junkbusters Corporation's website (http://www.junkbusters.com/) has been shut down, but Privoxy is still actively maintained.

    12.3. Authors

    Current Privoxy Team:

     Fabian Keil, lead developer
     David Schmidt
     Hal Burgiss
     Lee Rian
     Roland Rosenfeld
     Ian Silvester

    Former Privoxy Team Members:

     Johny Agotnes
     Rodrigo Barbosa
     Moritz Barsnick
     Ian Cummings
     Brian Dessent
     Jon Foster
     Karsten Hopp
     Alexander Lazic
     Daniel Leite
     Gábor Lipták
     Adam Lock
     Guy Laroche
     Justin McMurtry
     Mark Miller
     Gerry Murphy
     Andreas Oesterhelt
     Haroon Rafique
     Georg Sauthoff
     Thomas Steudten
     Jörg Strohmayer
     Rodney Stromlund
     Sviatoslav Sviridov
     Sarantis Paskalis
     Stefan Waldherr

    Thanks to the many people who have tested Privoxy, reported bugs, provided patches, made suggestions or contributed in some way. These include (in alphabetical order):

     Ken Arromdee
     Natxo Asenjo
     Devin Bayer
     Havard Berland
     David Bo
     Gergely Bor
     Francois Botha
     Reiner Buehl
     Andrew J. Caines
     Clifford Caoile
     Wan-Teh Chang
     Ramkumar Chinchani
     Billy Crook
     Frédéric Crozat
     Michael T. Davis
     Markus Dittrich
     Mattes Dolak
     Matthias Drochner
     Peter E.
     Florian Effenberger
     Markus Elfring
     Ryan Farmer
     Matthew Fischer
     Dean Gaudet
     Stephen Gildea
     Lizik Grelier
     Daniel Griscom
     Felix Gröbert
     Jeff H.
     Tim H.
     Aaron Hamid
     Darel Henman
     Magnus Holmgren
     Eric M. Hopper
     Ralf Horstmann
     Stefan Huehner
     Peter Hyman
     Derek Jennings
     Andrew Jones
     Julien Joubert
     Ralf Jungblut
     Petr Kadlec
     Steven Kolins
     Zeno Kugy
     David Laight
     Bert van Leeuwen
     Don Libes
     Paul Lieverse
     Han Liu
     Toby Lyward
     Wil Mahan
     Jindrich Makovicka
     Raphael Marichez
     Francois Marier
     Angelina Matson
     David Mediavilla
     Raphael Moll
     Amuro Namie
     Adam Piggott
     Petr Písar
     Dan Price
     Roberto Ragusa
     Félix Rauch
     Maynard Riley
     Andreas Rutkauskas
     Bart Schelstraete
     Chung-chieh Shan
     Simon South
     Dan Stahlke
     Oliver Stoeneberg
     Rick Sykes
     Spinor S.
     Peter Thoenen
     Martin Thomas
     Bobby G. Vinyard
     Jochen Voss
     Glenn Washburn
     Song Weijia
     Jörg Weinmann
     Darren Wiebe
     Anduin Withers
     Oliver Yeoh
     Jamie Zawinski

    Privoxy is based in part on code originally developed by Junkbusters Corp. and Anonymous Coders.

    Privoxy heavily relies on Philip Hazel's PCRE.

    The code to filter compressed content makes use of zlib which is written by Jean-loup Gailly and Mark Adler.

    On systems that lack snprintf(), Privoxy is using a version written by Mark Martinec. On systems that lack strptime(), Privoxy is using the one from the GNU C Library written by Ulrich Drepper.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/actions-file.html000640 001751 001751 00000565410 12116120072 024232 0ustar00fkfk000000 000000 Actions Files

    8. Actions Files

    The actions files are used to define what actions Privoxy takes for which URLs, and thus determines how ad images, cookies and various other aspects of HTTP content and transactions are handled, and on which sites (or even parts thereof). There are a number of such actions, with a wide range of functionality. Each action does something a little different. These actions give us a veritable arsenal of tools with which to exert our control, preferences and independence. Actions can be combined so that their effects are aggregated when applied against a given set of URLs.

    There are three action files included with Privoxy with differing purposes:

    • match-all.action - is used to define which "actions" relating to banner-blocking, images, pop-ups, content modification, cookie handling etc should be applied by default. It should be the first actions file loaded

    • default.action - defines many exceptions (both positive and negative) from the default set of actions that's configured in match-all.action. It is a set of rules that should work reasonably well as-is for most users. This file is only supposed to be edited by the developers. It should be the second actions file loaded.

    • user.action - is intended to be for local site preferences and exceptions. As an example, if your ISP or your bank has specific requirements, and need special handling, this kind of thing should go here. This file will not be upgraded.

    • Edit Set to Cautious Set to Medium Set to Advanced

      These have increasing levels of aggressiveness and have no influence on your browsing unless you select them explicitly in the editor. A default installation should be pre-set to Cautious. New users should try this for a while before adjusting the settings to more aggressive levels. The more aggressive the settings, then the more likelihood there is of problems such as sites not working as they should.

      The Edit button allows you to turn each action on/off individually for fine-tuning. The Cautious button changes the actions list to low/safe settings which will activate ad blocking and a minimal set of Privoxy's features, and subsequently there will be less of a chance for accidental problems. The Medium button sets the list to a medium level of other features and a low level set of privacy features. The Advanced button sets the list to a high level of ad blocking and medium level of privacy. See the chart below. The latter three buttons over-ride any changes via with the Edit button. More fine-tuning can be done in the lower sections of this internal page.

      While the actions file editor allows to enable these settings in all actions files, they are only supposed to be enabled in the first one to make sure you don't unintentionally overrule earlier rules.

      The default profiles, and their associated actions, as pre-defined in default.action are:

      Table 1. Default Configurations

      Feature Cautious Medium Advanced
      Ad-blocking Aggressiveness medium high high
      Ad-filtering by size no yes yes
      Ad-filtering by link no no yes
      Pop-up killing blocks only blocks only blocks only
      Privacy Features low medium medium/high
      Cookie handling none session-only kill
      Referer forging no yes yes
      GIF de-animation no yes yes
      Fast redirects no no yes
      HTML taming no no yes
      JavaScript taming no no yes
      Web-bug killing no yes yes
      Image tag reordering no yes yes

    The list of actions files to be used are defined in the main configuration file, and are processed in the order they are defined (e.g. default.action is typically processed before user.action). The content of these can all be viewed and edited from http://config.privoxy.org/show-status. The over-riding principle when applying actions, is that the last action that matches a given URL wins. The broadest, most general rules go first (defined in default.action), followed by any exceptions (typically also in default.action), which are then followed lastly by any local preferences (typically in user.action). Generally, user.action has the last word.

    An actions file typically has multiple sections. If you want to use "aliases" in an actions file, you have to place the (optional) alias section at the top of that file. Then comes the default set of rules which will apply universally to all sites and pages (be very careful with using such a universal set in user.action or any other actions file after default.action, because it will override the result from consulting any previous file). And then below that, exceptions to the defined universal policies. You can regard user.action as an appendix to default.action, with the advantage that it is a separate file, which makes preserving your personal settings across Privoxy upgrades easier.

    Actions can be used to block anything you want, including ads, banners, or just some obnoxious URL whose content you would rather not see. Cookies can be accepted or rejected, or accepted only during the current browser session (i.e. not written to disk), content can be modified, some JavaScripts tamed, user-tracking fooled, and much more. See below for a complete list of actions.

    8.1. Finding the Right Mix

    Note that some actions, like cookie suppression or script disabling, may render some sites unusable that rely on these techniques to work properly. Finding the right mix of actions is not always easy and certainly a matter of personal taste. And, things can always change, requiring refinements in the configuration. In general, it can be said that the more "aggressive" your default settings (in the top section of the actions file) are, the more exceptions for "trusted" sites you will have to make later. If, for example, you want to crunch all cookies per default, you'll have to make exceptions from that rule for sites that you regularly use and that require cookies for actually useful purposes, like maybe your bank, favorite shop, or newspaper.

    We have tried to provide you with reasonable rules to start from in the distribution actions files. But there is no general rule of thumb on these things. There just are too many variables, and sites are constantly changing. Sooner or later you will want to change the rules (and read this chapter again :).

    8.2. How to Edit

    The easiest way to edit the actions files is with a browser by using our browser-based editor, which can be reached from http://config.privoxy.org/show-status. Note: the config file option enable-edit-actions must be enabled for this to work. The editor allows both fine-grained control over every single feature on a per-URL basis, and easy choosing from wholesale sets of defaults like "Cautious", "Medium" or "Advanced". Warning: the "Advanced" setting is more aggressive, and will be more likely to cause problems for some sites. Experienced users only!

    If you prefer plain text editing to GUIs, you can of course also directly edit the the actions files with your favorite text editor. Look at default.action which is richly commented with many good examples.

    8.3. How Actions are Applied to Requests

    Actions files are divided into sections. There are special sections, like the "alias" sections which will be discussed later. For now let's concentrate on regular sections: They have a heading line (often split up to multiple lines for readability) which consist of a list of actions, separated by whitespace and enclosed in curly braces. Below that, there is a list of URL and tag patterns, each on a separate line.

    To determine which actions apply to a request, the URL of the request is compared to all URL patterns in each "action file". Every time it matches, the list of applicable actions for the request is incrementally updated, using the heading of the section in which the pattern is located. The same is done again for tags and tag patterns later on.

    If multiple applying sections set the same action differently, the last match wins. If not, the effects are aggregated. E.g. a URL might match a regular section with a heading line of { +handle-as-image }, then later another one with just { +block }, resulting in both actions to apply. And there may well be cases where you will want to combine actions together. Such a section then might look like:

      { +handle-as-image  +block{Banner ads.} }
      # Block these as if they were images. Send no block page.
       banners.example.com
       media.example.com/.*banners
       .example.com/images/ads/
    

    You can trace this process for URL patterns and any given URL by visiting http://config.privoxy.org/show-url-info.

    Examples and more detail on this is provided in the Appendix, Troubleshooting: Anatomy of an Action section.

    8.4. Patterns

    As mentioned, Privoxy uses "patterns" to determine what actions might apply to which sites and pages your browser attempts to access. These "patterns" use wild card type pattern matching to achieve a high degree of flexibility. This allows one expression to be expanded and potentially match against many similar patterns.

    Generally, an URL pattern has the form <domain><port>/<path>, where the <domain>, the <port> and the <path> are optional. (This is why the special / pattern matches all URLs). Note that the protocol portion of the URL pattern (e.g. http://) should not be included in the pattern. This is assumed already!

    The pattern matching syntax is different for the domain and path parts of the URL. The domain part uses a simple globbing type matching technique, while the path part uses more flexible "Regular Expressions" (POSIX 1003.2).

    The port part of a pattern is a decimal port number preceded by a colon (:). If the domain part contains a numerical IPv6 address, it has to be put into angle brackets (<, >).

    www.example.com/

    is a domain-only pattern and will match any request to www.example.com, regardless of which document on that server is requested. So ALL pages in this domain would be covered by the scope of this action. Note that a simple example.com is different and would NOT match.

    www.example.com

    means exactly the same. For domain-only patterns, the trailing / may be omitted.

    www.example.com/index.html

    matches all the documents on www.example.com whose name starts with /index.html.

    www.example.com/index.html$

    matches only the single document /index.html on www.example.com.

    /index.html$

    matches the document /index.html, regardless of the domain, i.e. on any web server anywhere.

    /

    Matches any URL because there's no requirement for either the domain or the path to match anything.

    :8000/

    Matches any URL pointing to TCP port 8000.

    <2001:db8::1>/

    Matches any URL with the host address 2001:db8::1. (Note that the real URL uses plain brackets, not angle brackets.)

    index.html

    matches nothing, since it would be interpreted as a domain name and there is no top-level domain called .html. So its a mistake.

    8.4.1. The Domain Pattern

    The matching of the domain part offers some flexible options: if the domain starts or ends with a dot, it becomes unanchored at that end. For example:

    .example.com

    matches any domain with first-level domain com and second-level domain example. For example www.example.com, example.com and foo.bar.baz.example.com. Note that it wouldn't match if the second-level domain was another-example.

    www.

    matches any domain that STARTS with www. (It also matches the domain www but most of the time that doesn't matter.)

    .example.

    matches any domain that CONTAINS .example.. And, by the way, also included would be any files or documents that exist within that domain since no path limitations are specified. (Correctly speaking: It matches any FQDN that contains example as a domain.) This might be www.example.com, news.example.de, or www.example.net/cgi/testing.pl for instance. All these cases are matched.

    Additionally, there are wild-cards that you can use in the domain names themselves. These work similarly to shell globbing type wild-cards: "*" represents zero or more arbitrary characters (this is equivalent to the "Regular Expression" based syntax of ".*"), "?" represents any single character (this is equivalent to the regular expression syntax of a simple "."), and you can define "character classes" in square brackets which is similar to the same regular expression technique. All of this can be freely mixed:

    ad*.example.com

    matches "adserver.example.com", "ads.example.com", etc but not "sfads.example.com"

    *ad*.example.com

    matches all of the above, and then some.

    .?pix.com

    matches www.ipix.com, pictures.epix.com, a.b.c.d.e.upix.com etc.

    www[1-9a-ez].example.c*

    matches www1.example.com, www4.example.cc, wwwd.example.cy, wwwz.example.com etc., but not wwww.example.com.

    While flexible, this is not the sophistication of full regular expression based syntax.

    8.4.2. The Path Pattern

    Privoxy uses "modern" POSIX 1003.2 "Regular Expressions" for matching the path portion (after the slash), and is thus more flexible.

    There is an Appendix with a brief quick-start into regular expressions, you also might want to have a look at your operating system's documentation on regular expressions (try man re_format).

    Note that the path pattern is automatically left-anchored at the "/", i.e. it matches as if it would start with a "^" (regular expression speak for the beginning of a line).

    Please also note that matching in the path is CASE INSENSITIVE by default, but you can switch to case sensitive at any point in the pattern by using the "(?-i)" switch: www.example.com/(?-i)PaTtErN.* will match only documents whose path starts with PaTtErN in exactly this capitalization.

    .example.com/.*

    Is equivalent to just ".example.com", since any documents within that domain are matched with or without the ".*" regular expression. This is redundant

    .example.com/.*/index.html$

    Will match any page in the domain of "example.com" that is named "index.html", and that is part of some path. For example, it matches "www.example.com/testing/index.html" but NOT "www.example.com/index.html" because the regular expression called for at least two "/'s", thus the path requirement. It also would match "www.example.com/testing/index_html", because of the special meta-character ".".

    .example.com/(.*/)?index\.html$

    This regular expression is conditional so it will match any page named "index.html" regardless of path which in this case can have one or more "/'s". And this one must contain exactly ".html" (but does not have to end with that!).

    .example.com/(.*/)(ads|banners?|junk)

    This regular expression will match any path of "example.com" that contains any of the words "ads", "banner", "banners" (because of the "?") or "junk". The path does not have to end in these words, just contain them.

    .example.com/(.*/)(ads|banners?|junk)/.*\.(jpe?g|gif|png)$

    This is very much the same as above, except now it must end in either ".jpg", ".jpeg", ".gif" or ".png". So this one is limited to common image formats.

    There are many, many good examples to be found in default.action, and more tutorials below in Appendix on regular expressions.

    8.4.3. The Tag Pattern

    Tag patterns are used to change the applying actions based on the request's tags. Tags can be created with either the client-header-tagger or the server-header-tagger action.

    Tag patterns have to start with "TAG:", so Privoxy can tell them apart from URL patterns. Everything after the colon including white space, is interpreted as a regular expression with path pattern syntax, except that tag patterns aren't left-anchored automatically (Privoxy doesn't silently add a "^", you have to do it yourself if you need it).

    To match all requests that are tagged with "foo" your pattern line should be "TAG:^foo$", "TAG:foo" would work as well, but it would also match requests whose tags contain "foo" somewhere. "TAG: foo" wouldn't work as it requires white space.

    Sections can contain URL and tag patterns at the same time, but tag patterns are checked after the URL patterns and thus always overrule them, even if they are located before the URL patterns.

    Once a new tag is added, Privoxy checks right away if it's matched by one of the tag patterns and updates the action settings accordingly. As a result tags can be used to activate other tagger actions, as long as these other taggers look for headers that haven't already be parsed.

    For example you could tag client requests which use the POST method, then use this tag to activate another tagger that adds a tag if cookies are sent, and then use a block action based on the cookie tag. This allows the outcome of one action, to be input into a subsequent action. However if you'd reverse the position of the described taggers, and activated the method tagger based on the cookie tagger, no method tags would be created. The method tagger would look for the request line, but at the time the cookie tag is created, the request line has already been parsed.

    While this is a limitation you should be aware of, this kind of indirection is seldom needed anyway and even the example doesn't make too much sense.

    8.5. Actions

    All actions are disabled by default, until they are explicitly enabled somewhere in an actions file. Actions are turned on if preceded with a "+", and turned off if preceded with a "-". So a +action means "do that action", e.g. +block means "please block URLs that match the following patterns", and -block means "don't block URLs that match the following patterns, even if +block previously applied."

    Again, actions are invoked by placing them on a line, enclosed in curly braces and separated by whitespace, like in {+some-action -some-other-action{some-parameter}}, followed by a list of URL patterns, one per line, to which they apply. Together, the actions line and the following pattern lines make up a section of the actions file.

    Actions fall into three categories:

    • Boolean, i.e the action can only be "enabled" or "disabled". Syntax:

        +name        # enable action name
        -name        # disable action name
      

      Example: +handle-as-image

    • Parameterized, where some value is required in order to enable this type of action. Syntax:

        +name{param}  # enable action and set parameter to param,
                     # overwriting parameter from previous match if necessary
        -name         # disable action. The parameter can be omitted
      

      Note that if the URL matches multiple positive forms of a parameterized action, the last match wins, i.e. the params from earlier matches are simply ignored.

      Example: +hide-user-agent{Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.1.4) Gecko/20070602 Firefox/2.0.0.4}

    • Multi-value. These look exactly like parameterized actions, but they behave differently: If the action applies multiple times to the same URL, but with different parameters, all the parameters from all matches are remembered. This is used for actions that can be executed for the same request repeatedly, like adding multiple headers, or filtering through multiple filters. Syntax:

        +name{param}   # enable action and add param to the list of parameters
        -name{param}   # remove the parameter param from the list of parameters
                      # If it was the last one left, disable the action.
        -name          # disable this action completely and remove all parameters from the list
      

      Examples: +add-header{X-Fun-Header: Some text} and +filter{html-annoyances}

    If nothing is specified in any actions file, no "actions" are taken. So in this case Privoxy would just be a normal, non-blocking, non-filtering proxy. You must specifically enable the privacy and blocking features you need (although the provided default actions files will give a good starting point).

    Later defined action sections always over-ride earlier ones of the same type. So exceptions to any rules you make, should come in the latter part of the file (or in a file that is processed later when using multiple actions files such as user.action). For multi-valued actions, the actions are applied in the order they are specified. Actions files are processed in the order they are defined in config (the default installation has three actions files). It also quite possible for any given URL to match more than one "pattern" (because of wildcards and regular expressions), and thus to trigger more than one set of actions! Last match wins.

    The list of valid Privoxy actions are:

    8.5.1. add-header

    Typical use:

    Confuse log analysis, custom applications

    Effect:

    Sends a user defined HTTP header to the web server.

    Type:

    Multi-value.

    Parameter:

    Any string value is possible. Validity of the defined HTTP headers is not checked. It is recommended that you use the "X-" prefix for custom headers.

    Notes:

    This action may be specified multiple times, in order to define multiple headers. This is rarely needed for the typical user. If you don't know what "HTTP headers" are, you definitely don't need to worry about this one.

    Headers added by this action are not modified by other actions.

    Example usage:
    +add-header{X-User-Tracking: sucks}
    

    8.5.2. block

    Typical use:

    Block ads or other unwanted content

    Effect:

    Requests for URLs to which this action applies are blocked, i.e. the requests are trapped by Privoxy and the requested URL is never retrieved, but is answered locally with a substitute page or image, as determined by the handle-as-image, set-image-blocker, and handle-as-empty-document actions.

    Type:

    Parameterized.

    Parameter:

    A block reason that should be given to the user.

    Notes:

    Privoxy sends a special "BLOCKED" page for requests to blocked pages. This page contains the block reason given as parameter, a link to find out why the block action applies, and a click-through to the blocked content (the latter only if the force feature is available and enabled).

    A very important exception occurs if both block and handle-as-image, apply to the same request: it will then be replaced by an image. If set-image-blocker (see below) also applies, the type of image will be determined by its parameter, if not, the standard checkerboard pattern is sent.

    It is important to understand this process, in order to understand how Privoxy deals with ads and other unwanted content. Blocking is a core feature, and one upon which various other features depend.

    The filter action can perform a very similar task, by "blocking" banner images and other content through rewriting the relevant URLs in the document's HTML source, so they don't get requested in the first place. Note that this is a totally different technique, and it's easy to confuse the two.

    Example usage (section):
    {+block{No nasty stuff for you.}}
    # Block and replace with "blocked" page
     .nasty-stuff.example.com
    
    {+block{Doubleclick banners.} +handle-as-image}
    # Block and replace with image
     .ad.doubleclick.net
     .ads.r.us/banners/
    
    {+block{Layered ads.} +handle-as-empty-document}
    # Block and then ignore
     adserver.example.net/.*\.js$
    

    8.5.3. change-x-forwarded-for

    Typical use:

    Improve privacy by not forwarding the source of the request in the HTTP headers.

    Effect:

    Deletes the "X-Forwarded-For:" HTTP header from the client request, or adds a new one.

    Type:

    Parameterized.

    Parameter:
    • "block" to delete the header.

    • "add" to create the header (or append the client's IP address to an already existing one).

    Notes:

    It is safe and recommended to use block.

    Forwarding the source address of the request may make sense in some multi-user setups but is also a privacy risk.

    Example usage:
    +change-x-forwarded-for{block}
    

    8.5.4. client-header-filter

    Typical use:

    Rewrite or remove single client headers.

    Effect:

    All client headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions.

    Type:

    Parameterized.

    Parameter:

    The name of a client-header filter, as defined in one of the filter files.

    Notes:

    Client-header filters are applied to each header on its own, not to all at once. This makes it easier to diagnose problems, but on the downside you can't write filters that only change header x if header y's value is z. You can do that by using tags though.

    Client-header filters are executed after the other header actions have finished and use their output as input.

    If the request URI gets changed, Privoxy will detect that and use the new one. This can be used to rewrite the request destination behind the client's back, for example to specify a Tor exit relay for certain requests.

    Please refer to the filter file chapter to learn which client-header filters are available by default, and how to create your own.

    Example usage (section):
    # Hide Tor exit notation in Host and Referer Headers
    {+client-header-filter{hide-tor-exit-notation}}
    /
    
    

    8.5.5. client-header-tagger

    Typical use:

    Block requests based on their headers.

    Effect:

    Client headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions, the result is used as tag.

    Type:

    Parameterized.

    Parameter:

    The name of a client-header tagger, as defined in one of the filter files.

    Notes:

    Client-header taggers are applied to each header on its own, and as the header isn't modified, each tagger "sees" the original.

    Client-header taggers are the first actions that are executed and their tags can be used to control every other action.

    Example usage (section):
    # Tag every request with the User-Agent header
    {+client-header-tagger{user-agent}}
    /
    
    # Tagging itself doesn't change the action
    # settings, sections with TAG patterns do:
    #
    # If it's a download agent, use a different forwarding proxy,
    # show the real User-Agent and make sure resume works.
    {+forward-override{forward-socks5 10.0.0.2:2222 .} \
     -hide-if-modified-since      \
     -overwrite-last-modified     \
     -hide-user-agent             \
     -filter                      \
     -deanimate-gifs              \
    }
    TAG:^User-Agent: NetBSD-ftp/
    TAG:^User-Agent: Novell ZYPP Installer
    TAG:^User-Agent: RPM APT-HTTP/
    TAG:^User-Agent: fetch libfetch/
    TAG:^User-Agent: Ubuntu APT-HTTP/
    TAG:^User-Agent: MPlayer/
    
    
    # Tag all requests with the Range header set
    {+client-header-tagger{range-requests}}
    /
    
    # Disable filtering for the tagged requests.
    #
    # With filtering enabled Privoxy would remove the Range headers
    # to be able to filter the whole response. The downside is that
    # it prevents clients from resuming downloads or skipping over
    # parts of multimedia files.
    {-filter -deanimate-gifs}
    TAG:^RANGE-REQUEST$
    
    

    8.5.6. content-type-overwrite

    Typical use:

    Stop useless download menus from popping up, or change the browser's rendering mode

    Effect:

    Replaces the "Content-Type:" HTTP server header.

    Type:

    Parameterized.

    Parameter:

    Any string.

    Notes:

    The "Content-Type:" HTTP server header is used by the browser to decide what to do with the document. The value of this header can cause the browser to open a download menu instead of displaying the document by itself, even if the document's format is supported by the browser.

    The declared content type can also affect which rendering mode the browser chooses. If XHTML is delivered as "text/html", many browsers treat it as yet another broken HTML document. If it is send as "application/xml", browsers with XHTML support will only display it, if the syntax is correct.

    If you see a web site that proudly uses XHTML buttons, but sets "Content-Type: text/html", you can use Privoxy to overwrite it with "application/xml" and validate the web master's claim inside your XHTML-supporting browser. If the syntax is incorrect, the browser will complain loudly.

    You can also go the opposite direction: if your browser prints error messages instead of rendering a document falsely declared as XHTML, you can overwrite the content type with "text/html" and have it rendered as broken HTML document.

    By default content-type-overwrite only replaces "Content-Type:" headers that look like some kind of text. If you want to overwrite it unconditionally, you have to combine it with force-text-mode. This limitation exists for a reason, think twice before circumventing it.

    Most of the time it's easier to replace this action with a custom server-header filter. It allows you to activate it for every document of a certain site and it will still only replace the content types you aimed at.

    Of course you can apply content-type-overwrite to a whole site and then make URL based exceptions, but it's a lot more work to get the same precision.

    Example usage (sections):
    # Check if www.example.net/ really uses valid XHTML
    { +content-type-overwrite{application/xml} }
    www.example.net/
    
    # but leave the content type unmodified if the URL looks like a style sheet
    {-content-type-overwrite}
    www.example.net/.*\.css$
    www.example.net/.*style
    

    8.5.7. crunch-client-header

    Typical use:

    Remove a client header Privoxy has no dedicated action for.

    Effect:

    Deletes every header sent by the client that contains the string the user supplied as parameter.

    Type:

    Parameterized.

    Parameter:

    Any string.

    Notes:

    This action allows you to block client headers for which no dedicated Privoxy action exists. Privoxy will remove every client header that contains the string you supplied as parameter.

    Regular expressions are not supported and you can't use this action to block different headers in the same request, unless they contain the same string.

    crunch-client-header is only meant for quick tests. If you have to block several different headers, or only want to modify parts of them, you should use a client-header filter.

    Warning

    Don't block any header without understanding the consequences.

    Example usage (section):
    # Block the non-existent "Privacy-Violation:" client header
    { +crunch-client-header{Privacy-Violation:} }
    /
    
    

    8.5.8. crunch-if-none-match

    Typical use:

    Prevent yet another way to track the user's steps between sessions.

    Effect:

    Deletes the "If-None-Match:" HTTP client header.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    Removing the "If-None-Match:" HTTP client header is useful for filter testing, where you want to force a real reload instead of getting status code "304" which would cause the browser to use a cached copy of the page.

    It is also useful to make sure the header isn't used as a cookie replacement (unlikely but possible).

    Blocking the "If-None-Match:" header shouldn't cause any caching problems, as long as the "If-Modified-Since:" header isn't blocked or missing as well.

    It is recommended to use this action together with hide-if-modified-since and overwrite-last-modified.

    Example usage (section):
    # Let the browser revalidate cached documents but don't
    # allow the server to use the revalidation headers for user tracking.
    {+hide-if-modified-since{-60} \
     +overwrite-last-modified{randomize} \
     +crunch-if-none-match}
    /
    

    8.5.9. crunch-incoming-cookies

    Typical use:

    Prevent the web server from setting HTTP cookies on your system

    Effect:

    Deletes any "Set-Cookie:" HTTP headers from server replies.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    This action is only concerned with incoming HTTP cookies. For outgoing HTTP cookies, use crunch-outgoing-cookies. Use both to disable HTTP cookies completely.

    It makes no sense at all to use this action in conjunction with the session-cookies-only action, since it would prevent the session cookies from being set. See also filter-content-cookies.

    Example usage:
    +crunch-incoming-cookies
    

    8.5.10. crunch-server-header

    Typical use:

    Remove a server header Privoxy has no dedicated action for.

    Effect:

    Deletes every header sent by the server that contains the string the user supplied as parameter.

    Type:

    Parameterized.

    Parameter:

    Any string.

    Notes:

    This action allows you to block server headers for which no dedicated Privoxy action exists. Privoxy will remove every server header that contains the string you supplied as parameter.

    Regular expressions are not supported and you can't use this action to block different headers in the same request, unless they contain the same string.

    crunch-server-header is only meant for quick tests. If you have to block several different headers, or only want to modify parts of them, you should use a custom server-header filter.

    Warning

    Don't block any header without understanding the consequences.

    Example usage (section):
    # Crunch server headers that try to prevent caching
    { +crunch-server-header{no-cache} }
    /
    

    8.5.11. crunch-outgoing-cookies

    Typical use:

    Prevent the web server from reading any HTTP cookies from your system

    Effect:

    Deletes any "Cookie:" HTTP headers from client requests.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    This action is only concerned with outgoing HTTP cookies. For incoming HTTP cookies, use crunch-incoming-cookies. Use both to disable HTTP cookies completely.

    It makes no sense at all to use this action in conjunction with the session-cookies-only action, since it would prevent the session cookies from being read.

    Example usage:
    +crunch-outgoing-cookies
    

    8.5.12. deanimate-gifs

    Typical use:

    Stop those annoying, distracting animated GIF images.

    Effect:

    De-animate GIF animations, i.e. reduce them to their first or last image.

    Type:

    Parameterized.

    Parameter:

    "last" or "first"

    Notes:

    This will also shrink the images considerably (in bytes, not pixels!). If the option "first" is given, the first frame of the animation is used as the replacement. If "last" is given, the last frame of the animation is used instead, which probably makes more sense for most banner animations, but also has the risk of not showing the entire last frame (if it is only a delta to an earlier frame).

    You can safely use this action with patterns that will also match non-GIF objects, because no attempt will be made at anything that doesn't look like a GIF.

    Example usage:
    +deanimate-gifs{last}
    

    8.5.13. downgrade-http-version

    Typical use:

    Work around (very rare) problems with HTTP/1.1

    Effect:

    Downgrades HTTP/1.1 client requests and server replies to HTTP/1.0.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    This is a left-over from the time when Privoxy didn't support important HTTP/1.1 features well. It is left here for the unlikely case that you experience HTTP/1.1-related problems with some server out there.

    Note that enabling this action is only a workaround. It should not be enabled for sites that work without it. While it shouldn't break any pages, it has an (usually negative) performance impact.

    If you come across a site where enabling this action helps, please report it, so the cause of the problem can be analyzed. If the problem turns out to be caused by a bug in Privoxy it should be fixed so the following release works without the work around.

    Example usage (section):
    {+downgrade-http-version}
    problem-host.example.com
    

    8.5.14. fast-redirects

    Typical use:

    Fool some click-tracking scripts and speed up indirect links.

    Effect:

    Detects redirection URLs and redirects the browser without contacting the redirection server first.

    Type:

    Parameterized.

    Parameter:
    • "simple-check" to just search for the string "http://" to detect redirection URLs.

    • "check-decoded-url" to decode URLs (if necessary) before searching for redirection URLs.

    Notes:

    Many sites, like yahoo.com, don't just link to other sites. Instead, they will link to some script on their own servers, giving the destination as a parameter, which will then redirect you to the final target. URLs resulting from this scheme typically look like: "http://www.example.org/click-tracker.cgi?target=http%3a//www.example.net/".

    Sometimes, there are even multiple consecutive redirects encoded in the URL. These redirections via scripts make your web browsing more traceable, since the server from which you follow such a link can see where you go to. Apart from that, valuable bandwidth and time is wasted, while your browser asks the server for one redirect after the other. Plus, it feeds the advertisers.

    This feature is currently not very smart and is scheduled for improvement. If it is enabled by default, you will have to create some exceptions to this action. It can lead to failures in several ways:

    Not every URLs with other URLs as parameters is evil. Some sites offer a real service that requires this information to work. For example a validation service needs to know, which document to validate. fast-redirects assumes that every URL parameter that looks like another URL is a redirection target, and will always redirect to the last one. Most of the time the assumption is correct, but if it isn't, the user gets redirected anyway.

    Another failure occurs if the URL contains other parameters after the URL parameter. The URL: "http://www.example.org/?redirect=http%3a//www.example.net/&foo=bar". contains the redirection URL "http://www.example.net/", followed by another parameter. fast-redirects doesn't know that and will cause a redirect to "http://www.example.net/&foo=bar". Depending on the target server configuration, the parameter will be silently ignored or lead to a "page not found" error. You can prevent this problem by first using the redirect action to remove the last part of the URL, but it requires a little effort.

    To detect a redirection URL, fast-redirects only looks for the string "http://", either in plain text (invalid but often used) or encoded as "http%3a//". Some sites use their own URL encoding scheme, encrypt the address of the target server or replace it with a database id. In theses cases fast-redirects is fooled and the request reaches the redirection server where it probably gets logged.

    Example usage:
     { +fast-redirects{simple-check} }
       one.example.com
    
     { +fast-redirects{check-decoded-url} }
       another.example.com/testing
    

    8.5.15. filter

    Typical use:

    Get rid of HTML and JavaScript annoyances, banner advertisements (by size), do fun text replacements, add personalized effects, etc.

    Effect:

    All instances of text-based type, most notably HTML and JavaScript, to which this action applies, can be filtered on-the-fly through the specified regular expression based substitutions. (Note: as of version 3.0.3 plain text documents are exempted from filtering, because web servers often use the text/plain MIME type for all files whose type they don't know.)

    Type:

    Parameterized.

    Parameter:

    The name of a content filter, as defined in the filter file. Filters can be defined in one or more files as defined by the filterfile option in the config file. default.filter is the collection of filters supplied by the developers. Locally defined filters should go in their own file, such as user.filter.

    When used in its negative form, and without parameters, all filtering is completely disabled.

    Notes:

    For your convenience, there are a number of pre-defined filters available in the distribution filter file that you can use. See the examples below for a list.

    Filtering requires buffering the page content, which may appear to slow down page rendering since nothing is displayed until all content has passed the filters. (The total time until the page is completely rendered doesn't change much, but it may be perceived as slower since the page is not incrementally displayed.) This effect will be more noticeable on slower connections.

    "Rolling your own" filters requires a knowledge of "Regular Expressions" and "HTML". This is very powerful feature, and potentially very intrusive. Filters should be used with caution, and where an equivalent "action" is not available.

    The amount of data that can be filtered is limited to the buffer-limit option in the main config file. The default is 4096 KB (4 Megs). Once this limit is exceeded, the buffered data, and all pending data, is passed through unfiltered.

    Inappropriate MIME types, such as zipped files, are not filtered at all. (Again, only text-based types except plain text). Encrypted SSL data (from HTTPS servers) cannot be filtered either, since this would violate the integrity of the secure transaction. In some situations it might be necessary to protect certain text, like source code, from filtering by defining appropriate -filter exceptions.

    Compressed content can't be filtered either, but if Privoxy is compiled with zlib support and a supported compression algorithm is used (gzip or deflate), Privoxy can first decompress the content and then filter it.

    If you use a Privoxy version without zlib support, but want filtering to work on as much documents as possible, even those that would normally be sent compressed, you must use the prevent-compression action in conjunction with filter.

    Content filtering can achieve some of the same effects as the block action, i.e. it can be used to block ads and banners. But the mechanism works quite differently. One effective use, is to block ad banners based on their size (see below), since many of these seem to be somewhat standardized.

    Feedback with suggestions for new or improved filters is particularly welcome!

    The below list has only the names and a one-line description of each predefined filter. There are more verbose explanations of what these filters do in the filter file chapter.

    Example usage (with filters from the distribution default.filter file). See the Predefined Filters section for more explanation on each:

    +filter{js-annoyances}       # Get rid of particularly annoying JavaScript abuse.
    

    +filter{js-events}           # Kill JavaScript event bindings and timers (Radically destructive! Only for extra nasty sites).
    

    +filter{html-annoyances}     # Get rid of particularly annoying HTML abuse.
    

    +filter{content-cookies}     # Kill cookies that come in the HTML or JS content.
    

    +filter{refresh-tags}        # Kill automatic refresh tags if refresh time is larger than 9 seconds.
    

    +filter{unsolicited-popups}  # Disable only unsolicited pop-up windows.
    

    +filter{all-popups}          # Kill all popups in JavaScript and HTML.
    

    +filter{img-reorder}         # Reorder attributes in <img> tags to make the banners-by-* filters more effective.
    

    +filter{banners-by-size}     # Kill banners by size.
    

    +filter{banners-by-link}     # Kill banners by their links to known clicktrackers.
    

    +filter{webbugs}             # Squish WebBugs (1x1 invisible GIFs used for user tracking).
    

    +filter{tiny-textforms}      # Extend those tiny textareas up to 40x80 and kill the hard wrap.
    

    +filter{jumping-windows}     # Prevent windows from resizing and moving themselves.
    

    +filter{frameset-borders}    # Give frames a border and make them resizable.
    

    +filter{iframes}             # Removes all detected iframes. Should only be enabled for individual sites.
    

    +filter{demoronizer}         # Fix MS's non-standard use of standard charsets.
    

    +filter{shockwave-flash}     # Kill embedded Shockwave Flash objects.
    

    +filter{quicktime-kioskmode} # Make Quicktime movies saveable.
    

    +filter{fun}                 # Text replacements for subversive browsing fun!
    

    +filter{crude-parental}      # Crude parental filtering. Note that this filter doesn't work reliably.
    

    +filter{ie-exploits}         # Disable some known Internet Explorer bug exploits.
    

    +filter{site-specifics}      # Cure for site-specific problems. Don't apply generally!
    

    +filter{no-ping}             # Removes non-standard ping attributes in <a> and <area> tags.
    

    +filter{google}              # CSS-based block for Google text ads. Also removes a width limitation and the toolbar advertisement.
    

    +filter{yahoo}               # CSS-based block for Yahoo text ads. Also removes a width limitation.
    

    +filter{msn}                 # CSS-based block for MSN text ads. Also removes tracking URLs and a width limitation.
    

    +filter{blogspot}            # Cleans up some Blogspot blogs. Read the fine print before using this.
    

    8.5.16. force-text-mode

    Typical use:

    Force Privoxy to treat a document as if it was in some kind of text format.

    Effect:

    Declares a document as text, even if the "Content-Type:" isn't detected as such.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    As explained above, Privoxy tries to only filter files that are in some kind of text format. The same restrictions apply to content-type-overwrite. force-text-mode declares a document as text, without looking at the "Content-Type:" first.

    Warning

    Think twice before activating this action. Filtering binary data with regular expressions can cause file damage.

    Example usage:
    +force-text-mode
    
    

    8.5.17. forward-override

    Typical use:

    Change the forwarding settings based on User-Agent or request origin

    Effect:

    Overrules the forward directives in the configuration file.

    Type:

    Multi-value.

    Parameter:
    • "forward ." to use a direct connection without any additional proxies.

    • "forward 127.0.0.1:8123" to use the HTTP proxy listening at 127.0.0.1 port 8123.

    • "forward-socks4a 127.0.0.1:9050 ." to use the socks4a proxy listening at 127.0.0.1 port 9050. Replace "forward-socks4a" with "forward-socks4" to use a socks4 connection (with local DNS resolution) instead, use "forward-socks5" for socks5 connections (with remote DNS resolution).

    • "forward-socks4a 127.0.0.1:9050 proxy.example.org:8000" to use the socks4a proxy listening at 127.0.0.1 port 9050 to reach the HTTP proxy listening at proxy.example.org port 8000. Replace "forward-socks4a" with "forward-socks4" to use a socks4 connection (with local DNS resolution) instead, use "forward-socks5" for socks5 connections (with remote DNS resolution).

    Notes:

    This action takes parameters similar to the forward directives in the configuration file, but without the URL pattern. It can be used as replacement, but normally it's only used in cases where matching based on the request URL isn't sufficient.

    Warning

    Please read the description for the forward directives before using this action. Forwarding to the wrong people will reduce your privacy and increase the chances of man-in-the-middle attacks.

    If the ports are missing or invalid, default values will be used. This might change in the future and you shouldn't rely on it. Otherwise incorrect syntax causes Privoxy to exit.

    Use the show-url-info CGI page to verify that your forward settings do what you thought the do.

    Example usage:
    # Always use direct connections for requests previously tagged as
    # "User-Agent: fetch libfetch/2.0" and make sure
    # resuming downloads continues to work.
    # This way you can continue to use Tor for your normal browsing,
    # without overloading the Tor network with your FreeBSD ports updates
    # or downloads of bigger files like ISOs.
    # Note that HTTP headers are easy to fake and therefore their
    # values are as (un)trustworthy as your clients and users.
    {+forward-override{forward .} \
     -hide-if-modified-since      \
     -overwrite-last-modified     \
    }
    TAG:^User-Agent: fetch libfetch/2\.0$
    
    

    8.5.18. handle-as-empty-document

    Typical use:

    Mark URLs that should be replaced by empty documents if they get blocked

    Effect:

    This action alone doesn't do anything noticeable. It just marks URLs. If the block action also applies, the presence or absence of this mark decides whether an HTML "BLOCKED" page, or an empty document will be sent to the client as a substitute for the blocked content. The empty document isn't literally empty, but actually contains a single space.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    Some browsers complain about syntax errors if JavaScript documents are blocked with Privoxy's default HTML page; this option can be used to silence them. And of course this action can also be used to eliminate the Privoxy BLOCKED message in frames.

    The content type for the empty document can be specified with content-type-overwrite{}, but usually this isn't necessary.

    Example usage:
    # Block all documents on example.org that end with ".js",
    # but send an empty document instead of the usual HTML message.
    {+block{Blocked JavaScript} +handle-as-empty-document}
    example.org/.*\.js$
    
    

    8.5.19. handle-as-image

    Typical use:

    Mark URLs as belonging to images (so they'll be replaced by images if they do get blocked, rather than HTML pages)

    Effect:

    This action alone doesn't do anything noticeable. It just marks URLs as images. If the block action also applies, the presence or absence of this mark decides whether an HTML "blocked" page, or a replacement image (as determined by the set-image-blocker action) will be sent to the client as a substitute for the blocked content.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    The below generic example section is actually part of default.action. It marks all URLs with well-known image file name extensions as images and should be left intact.

    Users will probably only want to use the handle-as-image action in conjunction with block, to block sources of banners, whose URLs don't reflect the file type, like in the second example section.

    Note that you cannot treat HTML pages as images in most cases. For instance, (in-line) ad frames require an HTML page to be sent, or they won't display properly. Forcing handle-as-image in this situation will not replace the ad frame with an image, but lead to error messages.

    Example usage (sections):
    # Generic image extensions:
    #
    {+handle-as-image}
    /.*\.(gif|jpg|jpeg|png|bmp|ico)$
    
    # These don't look like images, but they're banners and should be
    # blocked as images:
    #
    {+block{Nasty banners.} +handle-as-image}
    nasty-banner-server.example.com/junk.cgi\?output=trash
    

    8.5.20. hide-accept-language

    Typical use:

    Pretend to use different language settings.

    Effect:

    Deletes or replaces the "Accept-Language:" HTTP header in client requests.

    Type:

    Parameterized.

    Parameter:

    Keyword: "block", or any user defined value.

    Notes:

    Faking the browser's language settings can be useful to make a foreign User-Agent set with hide-user-agent more believable.

    However some sites with content in different languages check the "Accept-Language:" to decide which one to take by default. Sometimes it isn't possible to later switch to another language without changing the "Accept-Language:" header first.

    Therefore it's a good idea to either only change the "Accept-Language:" header to languages you understand, or to languages that aren't wide spread.

    Before setting the "Accept-Language:" header to a rare language, you should consider that it helps to make your requests unique and thus easier to trace. If you don't plan to change this header frequently, you should stick to a common language.

    Example usage (section):
    # Pretend to use Canadian language settings.
    {+hide-accept-language{en-ca} \
    +hide-user-agent{Mozilla/5.0 (X11; U; OpenBSD i386; en-CA; rv:1.8.0.4) Gecko/20060628 Firefox/1.5.0.4} \
    }
    /
    

    8.5.21. hide-content-disposition

    Typical use:

    Prevent download menus for content you prefer to view inside the browser.

    Effect:

    Deletes or replaces the "Content-Disposition:" HTTP header set by some servers.

    Type:

    Parameterized.

    Parameter:

    Keyword: "block", or any user defined value.

    Notes:

    Some servers set the "Content-Disposition:" HTTP header for documents they assume you want to save locally before viewing them. The "Content-Disposition:" header contains the file name the browser is supposed to use by default.

    In most browsers that understand this header, it makes it impossible to just view the document, without downloading it first, even if it's just a simple text file or an image.

    Removing the "Content-Disposition:" header helps to prevent this annoyance, but some browsers additionally check the "Content-Type:" header, before they decide if they can display a document without saving it first. In these cases, you have to change this header as well, before the browser stops displaying download menus.

    It is also possible to change the server's file name suggestion to another one, but in most cases it isn't worth the time to set it up.

    This action will probably be removed in the future, use server-header filters instead.

    Example usage:
    # Disarm the download link in Sourceforge's patch tracker
    { -filter \
     +content-type-overwrite{text/plain}\
     +hide-content-disposition{block} }
     .sourceforge.net/tracker/download\.php
    

    8.5.22. hide-if-modified-since

    Typical use:

    Prevent yet another way to track the user's steps between sessions.

    Effect:

    Deletes the "If-Modified-Since:" HTTP client header or modifies its value.

    Type:

    Parameterized.

    Parameter:

    Keyword: "block", or a user defined value that specifies a range of hours.

    Notes:

    Removing this header is useful for filter testing, where you want to force a real reload instead of getting status code "304", which would cause the browser to use a cached copy of the page.

    Instead of removing the header, hide-if-modified-since can also add or subtract a random amount of time to/from the header's value. You specify a range of minutes where the random factor should be chosen from and Privoxy does the rest. A negative value means subtracting, a positive value adding.

    Randomizing the value of the "If-Modified-Since:" makes it less likely that the server can use the time as a cookie replacement, but you will run into caching problems if the random range is too high.

    It is a good idea to only use a small negative value and let overwrite-last-modified handle the greater changes.

    It is also recommended to use this action together with crunch-if-none-match, otherwise it's more or less pointless.

    Example usage (section):
    # Let the browser revalidate but make tracking based on the time less likely.
    {+hide-if-modified-since{-60} \
     +overwrite-last-modified{randomize} \
     +crunch-if-none-match}
    /
    

    8.5.23. hide-from-header

    Typical use:

    Keep your (old and ill) browser from telling web servers your email address

    Effect:

    Deletes any existing "From:" HTTP header, or replaces it with the specified string.

    Type:

    Parameterized.

    Parameter:

    Keyword: "block", or any user defined value.

    Notes:

    The keyword "block" will completely remove the header (not to be confused with the block action).

    Alternately, you can specify any value you prefer to be sent to the web server. If you do, it is a matter of fairness not to use any address that is actually used by a real person.

    This action is rarely needed, as modern web browsers don't send "From:" headers anymore.

    Example usage:
    +hide-from-header{block}
    
    or
    +hide-from-header{spam-me-senseless@sittingduck.example.com}
    

    8.5.24. hide-referrer

    Typical use:

    Conceal which link you followed to get to a particular site

    Effect:

    Deletes the "Referer:" (sic) HTTP header from the client request, or replaces it with a forged one.

    Type:

    Parameterized.

    Parameter:
    • "conditional-block" to delete the header completely if the host has changed.

    • "conditional-forge" to forge the header if the host has changed.

    • "block" to delete the header unconditionally.

    • "forge" to pretend to be coming from the homepage of the server we are talking to.

    • Any other string to set a user defined referrer.

    Notes:

    conditional-block is the only parameter, that isn't easily detected in the server's log file. If it blocks the referrer, the request will look like the visitor used a bookmark or typed in the address directly.

    Leaving the referrer unmodified for requests on the same host allows the server owner to see the visitor's "click path", but in most cases she could also get that information by comparing other parts of the log file: for example the User-Agent if it isn't a very common one, or the user's IP address if it doesn't change between different requests.

    Always blocking the referrer, or using a custom one, can lead to failures on servers that check the referrer before they answer any requests, in an attempt to prevent their content from being embedded or linked to elsewhere.

    Both conditional-block and forge will work with referrer checks, as long as content and valid referring page are on the same host. Most of the time that's the case.

    hide-referer is an alternate spelling of hide-referrer and the two can be can be freely substituted with each other. ("referrer" is the correct English spelling, however the HTTP specification has a bug - it requires it to be spelled as "referer".)

    Example usage:
    +hide-referrer{forge}
    
    or
    +hide-referrer{http://www.yahoo.com/}
    

    8.5.25. hide-user-agent

    Typical use:

    Try to conceal your type of browser and client operating system

    Effect:

    Replaces the value of the "User-Agent:" HTTP header in client requests with the specified value.

    Type:

    Parameterized.

    Parameter:

    Any user-defined string.

    Notes:
    Warning

    This can lead to problems on web sites that depend on looking at this header in order to customize their content for different browsers (which, by the way, is NOT the right thing to do: good web sites work browser-independently).

    Using this action in multi-user setups or wherever different types of browsers will access the same Privoxy is not recommended. In single-user, single-browser setups, you might use it to delete your OS version information from the headers, because it is an invitation to exploit known bugs for your OS. It is also occasionally useful to forge this in order to access sites that won't let you in otherwise (though there may be a good reason in some cases).

    More information on known user-agent strings can be found at http://www.user-agents.org/ and http://en.wikipedia.org/wiki/User_agent.

    Example usage:
    +hide-user-agent{Netscape 6.1 (X11; I; Linux 2.4.18 i686)}
    

    8.5.26. limit-connect

    Typical use:

    Prevent abuse of Privoxy as a TCP proxy relay or disable SSL for untrusted sites

    Effect:

    Specifies to which ports HTTP CONNECT requests are allowable.

    Type:

    Parameterized.

    Parameter:

    A comma-separated list of ports or port ranges (the latter using dashes, with the minimum defaulting to 0 and the maximum to 65K).

    Notes:

    By default, i.e. if no limit-connect action applies, Privoxy allows HTTP CONNECT requests to all ports. Use limit-connect if fine-grained control is desired for some or all destinations.

    The CONNECT methods exists in HTTP to allow access to secure websites ("https://" URLs) through proxies. It works very simply: the proxy connects to the server on the specified port, and then short-circuits its connections to the client and to the remote server. This means CONNECT-enabled proxies can be used as TCP relays very easily.

    Privoxy relays HTTPS traffic without seeing the decoded content. Websites can leverage this limitation to circumvent Privoxy's filters. By specifying an invalid port range you can disable HTTPS entirely.

    Example usages:
    +limit-connect{443}                   # Port 443 is OK.
    +limit-connect{80,443}                # Ports 80 and 443 are OK.
    +limit-connect{-3, 7, 20-100, 500-}   # Ports less than 3, 7, 20 to 100 and above 500 are OK.
    +limit-connect{-}                     # All ports are OK
    +limit-connect{,}                     # No HTTPS/SSL traffic is allowed
    

    8.5.27. limit-cookie-lifetime

    Typical use:

    Limit the lifetime of HTTP cookies to a couple of minutes or hours.

    Effect:

    Overwrites the expires field in Set-Cookie server headers if it's above the specified limit.

    Type:

    Parameterized.

    Parameter:

    The lifetime limit in minutes, or 0.

    Notes:

    This action reduces the lifetime of HTTP cookies coming from the server to the specified number of minutes, starting from the time the cookie passes Privoxy.

    Cookies with a lifetime below the limit are not modified. The lifetime of session cookies is set to the specified limit.

    The effect of this action depends on the server.

    In case of servers which refresh their cookies with each response (or at least frequently), the lifetime limit set by this action is updated as well. Thus, a session associated with the cookie continues to work with this action enabled, as long as a new request is made before the last limit set is reached.

    However, some servers send their cookies once, with a lifetime of several years (the year 2037 is a popular choice), and do not refresh them until a certain event in the future, for example the user logging out. In this case this action may limit the absolute lifetime of the session, even if requests are made frequently.

    If the parameter is "0", this action behaves like session-cookies-only.

    Example usages:
    +limit-cookie-lifetime{60}
    
    

    8.5.28. prevent-compression

    Typical use:

    Ensure that servers send the content uncompressed, so it can be passed through filters.

    Effect:

    Removes the Accept-Encoding header which can be used to ask for compressed transfer.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    More and more websites send their content compressed by default, which is generally a good idea and saves bandwidth. But the filter and deanimate-gifs actions need access to the uncompressed data.

    When compiled with zlib support (available since Privoxy 3.0.7), content that should be filtered is decompressed on-the-fly and you don't have to worry about this action. If you are using an older Privoxy version, or one that hasn't been compiled with zlib support, this action can be used to convince the server to send the content uncompressed.

    Most text-based instances compress very well, the size is seldom decreased by less than 50%, for markup-heavy instances like news feeds saving more than 90% of the original size isn't unusual.

    Not using compression will therefore slow down the transfer, and you should only enable this action if you really need it. As of Privoxy 3.0.7 it's disabled in all predefined action settings.

    Note that some (rare) ill-configured sites don't handle requests for uncompressed documents correctly. Broken PHP applications tend to send an empty document body, some IIS versions only send the beginning of the content. If you enable prevent-compression per default, you might want to add exceptions for those sites. See the example for how to do that.

    Example usage (sections):
    # Selectively turn off compression, and enable a filter
    #
    { +filter{tiny-textforms} +prevent-compression }
    # Match only these sites
     .google.
     sourceforge.net
     sf.net
    
    # Or instead, we could set a universal default:
    #
    { +prevent-compression }
     / # Match all sites
    
    # Then maybe make exceptions for broken sites:
    #
    { -prevent-compression }
    .compusa.com/
    

    8.5.29. overwrite-last-modified

    Typical use:

    Prevent yet another way to track the user's steps between sessions.

    Effect:

    Deletes the "Last-Modified:" HTTP server header or modifies its value.

    Type:

    Parameterized.

    Parameter:

    One of the keywords: "block", "reset-to-request-time" and "randomize"

    Notes:

    Removing the "Last-Modified:" header is useful for filter testing, where you want to force a real reload instead of getting status code "304", which would cause the browser to reuse the old version of the page.

    The "randomize" option overwrites the value of the "Last-Modified:" header with a randomly chosen time between the original value and the current time. In theory the server could send each document with a different "Last-Modified:" header to track visits without using cookies. "Randomize" makes it impossible and the browser can still revalidate cached documents.

    "reset-to-request-time" overwrites the value of the "Last-Modified:" header with the current time. You could use this option together with hide-if-modified-since to further customize your random range.

    The preferred parameter here is "randomize". It is safe to use, as long as the time settings are more or less correct. If the server sets the "Last-Modified:" header to the time of the request, the random range becomes zero and the value stays the same. Therefore you should later randomize it a second time with hided-if-modified-since, just to be sure.

    It is also recommended to use this action together with crunch-if-none-match.

    Example usage:
    # Let the browser revalidate without being tracked across sessions
    { +hide-if-modified-since{-60} \
     +overwrite-last-modified{randomize} \
     +crunch-if-none-match}
    /
    

    8.5.30. redirect

    Typical use:

    Redirect requests to other sites.

    Effect:

    Convinces the browser that the requested document has been moved to another location and the browser should get it from there.

    Type:

    Parameterized

    Parameter:

    An absolute URL or a single pcrs command.

    Notes:

    Requests to which this action applies are answered with a HTTP redirect to URLs of your choosing. The new URL is either provided as parameter, or derived by applying a single pcrs command to the original URL.

    The syntax for pcrs commands is documented in the filter file section.

    This action will be ignored if you use it together with block. It can be combined with fast-redirects{check-decoded-url} to redirect to a decoded version of a rewritten URL.

    Use this action carefully, make sure not to create redirection loops and be aware that using your own redirects might make it possible to fingerprint your requests.

    In case of problems with your redirects, or simply to watch them working, enable debug 128.

    Example usages:
    # Replace example.com's style sheet with another one
    { +redirect{http://localhost/css-replacements/example.com.css} }
     example.com/stylesheet\.css
    
    # Create a short, easy to remember nickname for a favorite site
    # (relies on the browser accept and forward invalid URLs to Privoxy)
    { +redirect{http://www.privoxy.org/user-manual/actions-file.html} }
     a
    
    # Always use the expanded view for Undeadly.org articles
    # (Note the $ at the end of the URL pattern to make sure
    # the request for the rewritten URL isn't redirected as well)
    {+redirect{s@$@&mode=expanded@}}
    undeadly.org/cgi\?action=article&sid=\d*$
    
    # Redirect Google search requests to MSN
    {+redirect{s@^http://[^/]*/search\?q=([^&]*).*@http://search.msn.com/results.aspx?q=$1@}}
    .google.com/search
    
    # Redirect MSN search requests to Yahoo
    {+redirect{s@^http://[^/]*/results\.aspx\?q=([^&]*).*@http://search.yahoo.com/search?p=$1@}}
    search.msn.com//results\.aspx\?q=
    
    # Redirect remote requests for this manual
    # to the local version delivered by Privoxy
    {+redirect{s@^http://www@http://config@}}
    www.privoxy.org/user-manual/
    

    8.5.31. server-header-filter

    Typical use:

    Rewrite or remove single server headers.

    Effect:

    All server headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions.

    Type:

    Parameterized.

    Parameter:

    The name of a server-header filter, as defined in one of the filter files.

    Notes:

    Server-header filters are applied to each header on its own, not to all at once. This makes it easier to diagnose problems, but on the downside you can't write filters that only change header x if header y's value is z. You can do that by using tags though.

    Server-header filters are executed after the other header actions have finished and use their output as input.

    Please refer to the filter file chapter to learn which server-header filters are available by default, and how to create your own.

    Example usage (section):
    {+server-header-filter{html-to-xml}}
    example.org/xml-instance-that-is-delivered-as-html
    
    {+server-header-filter{xml-to-html}}
    example.org/instance-that-is-delivered-as-xml-but-is-not
    
    

    8.5.32. server-header-tagger

    Typical use:

    Enable or disable filters based on the Content-Type header.

    Effect:

    Server headers to which this action applies are filtered on-the-fly through the specified regular expression based substitutions, the result is used as tag.

    Type:

    Parameterized.

    Parameter:

    The name of a server-header tagger, as defined in one of the filter files.

    Notes:

    Server-header taggers are applied to each header on its own, and as the header isn't modified, each tagger "sees" the original.

    Server-header taggers are executed before all other header actions that modify server headers. Their tags can be used to control all of the other server-header actions, the content filters and the crunch actions (redirect and block).

    Obviously crunching based on tags created by server-header taggers doesn't prevent the request from showing up in the server's log file.

    Example usage (section):
    # Tag every request with the content type declared by the server
    {+server-header-tagger{content-type}}
    /
    
    

    8.5.33. session-cookies-only

    Typical use:

    Allow only temporary "session" cookies (for the current browser session only).

    Effect:

    Deletes the "expires" field from "Set-Cookie:" server headers. Most browsers will not store such cookies permanently and forget them in between sessions.

    Type:

    Boolean.

    Parameter:

    N/A

    Notes:

    This is less strict than crunch-incoming-cookies / crunch-outgoing-cookies and allows you to browse websites that insist or rely on setting cookies, without compromising your privacy too badly.

    Most browsers will not permanently store cookies that have been processed by session-cookies-only and will forget about them between sessions. This makes profiling cookies useless, but won't break sites which require cookies so that you can log in for transactions. This is generally turned on for all sites, and is the recommended setting.

    It makes no sense at all to use session-cookies-only together with crunch-incoming-cookies or crunch-outgoing-cookies. If you do, cookies will be plainly killed.

    Note that it is up to the browser how it handles such cookies without an "expires" field. If you use an exotic browser, you might want to try it out to be sure.

    This setting also has no effect on cookies that may have been stored previously by the browser before starting Privoxy. These would have to be removed manually.

    Privoxy also uses the content-cookies filter to block some types of cookies. Content cookies are not effected by session-cookies-only.

    Example usage:
    +session-cookies-only
    

    8.5.34. set-image-blocker

    Typical use:

    Choose the replacement for blocked images

    Effect:

    This action alone doesn't do anything noticeable. If both block and handle-as-image also apply, i.e. if the request is to be blocked as an image, then the parameter of this action decides what will be sent as a replacement.

    Type:

    Parameterized.

    Parameter:
    • "pattern" to send a built-in checkerboard pattern image. The image is visually decent, scales very well, and makes it obvious where banners were busted.

    • "blank" to send a built-in transparent image. This makes banners disappear completely, but makes it hard to detect where Privoxy has blocked images on a given page and complicates troubleshooting if Privoxy has blocked innocent images, like navigation icons.

    • "target-url" to send a redirect to target-url. You can redirect to any image anywhere, even in your local filesystem via "file:///" URL. (But note that not all browsers support redirecting to a local file system).

      A good application of redirects is to use special Privoxy-built-in URLs, which send the built-in images, as target-url. This has the same visual effect as specifying "blank" or "pattern" in the first place, but enables your browser to cache the replacement image, instead of requesting it over and over again.

    Notes:

    The URLs for the built-in images are "http://config.privoxy.org/send-banner?type=type", where type is either "blank" or "pattern".

    There is a third (advanced) type, called "auto". It is NOT to be used in set-image-blocker, but meant for use from filters. Auto will select the type of image that would have applied to the referring page, had it been an image.

    Example usage:

    Built-in pattern:

    +set-image-blocker{pattern}
    

    Redirect to the BSD daemon:

    +set-image-blocker{http://www.freebsd.org/gifs/dae_up3.gif}
    

    Redirect to the built-in pattern for better caching:

    +set-image-blocker{http://config.privoxy.org/send-banner?type=pattern}
    

    8.5.35. Summary

    Note that many of these actions have the potential to cause a page to misbehave, possibly even not to display at all. There are many ways a site designer may choose to design his site, and what HTTP header content, and other criteria, he may depend on. There is no way to have hard and fast rules for all sites. See the Appendix for a brief example on troubleshooting actions.

    8.6. Aliases

    Custom "actions", known to Privoxy as "aliases", can be defined by combining other actions. These can in turn be invoked just like the built-in actions. Currently, an alias name can contain any character except space, tab, "=", "{" and "}", but we strongly recommend that you only use "a" to "z", "0" to "9", "+", and "-". Alias names are not case sensitive, and are not required to start with a "+" or "-" sign, since they are merely textually expanded.

    Aliases can be used throughout the actions file, but they must be defined in a special section at the top of the file! And there can only be one such section per actions file. Each actions file may have its own alias section, and the aliases defined in it are only visible within that file.

    There are two main reasons to use aliases: One is to save typing for frequently used combinations of actions, the other one is a gain in flexibility: If you decide once how you want to handle shops by defining an alias called "shop", you can later change your policy on shops in one place, and your changes will take effect everywhere in the actions file where the "shop" alias is used. Calling aliases by their purpose also makes your actions files more readable.

    Currently, there is one big drawback to using aliases, though: Privoxy's built-in web-based action file editor honors aliases when reading the actions files, but it expands them before writing. So the effects of your aliases are of course preserved, but the aliases themselves are lost when you edit sections that use aliases with it.

    Now let's define some aliases...

     # Useful custom aliases we can use later.
     #
     # Note the (required!) section header line and that this section
     # must be at the top of the actions file!
     #
     {{alias}}
    
     # These aliases just save typing later:
     # (Note that some already use other aliases!)
     #
     +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies
     -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies
     +block-as-image      = +block{Blocked image.} +handle-as-image
     allow-all-cookies   = -crunch-all-cookies -session-cookies-only -filter{content-cookies}
    
     # These aliases define combinations of actions
     # that are useful for certain types of sites:
     #
     fragile     = -block -filter -crunch-all-cookies -fast-redirects -hide-referrer -prevent-compression
    
     shop        = -crunch-all-cookies -filter{all-popups}
    
     # Short names for other aliases, for really lazy people ;-)
     #
     c0 = +crunch-all-cookies
     c1 = -crunch-all-cookies
    

    ...and put them to use. These sections would appear in the lower part of an actions file and define exceptions to the default actions (as specified further up for the "/" pattern):

     # These sites are either very complex or very keen on
     # user data and require minimal interference to work:
     #
     {fragile}
     .office.microsoft.com
     .windowsupdate.microsoft.com
     # Gmail is really mail.google.com, not gmail.com
     mail.google.com
    
     # Shopping sites:
     # Allow cookies (for setting and retrieving your customer data)
     #
     {shop}
     .quietpc.com
     .worldpay.com   # for quietpc.com
     mybank.example.com
    
     # These shops require pop-ups:
     #
     {-filter{all-popups} -filter{unsolicited-popups}}
      .dabs.com
      .overclockers.co.uk
    

    Aliases like "shop" and "fragile" are typically used for "problem" sites that require more than one action to be disabled in order to function properly.

    8.7. Actions Files Tutorial

    The above chapters have shown which actions files there are and how they are organized, how actions are specified and applied to URLs, how patterns work, and how to define and use aliases. Now, let's look at an example match-all.action, default.action and user.action file and see how all these pieces come together:

    8.7.1. match-all.action

    Remember all actions are disabled when matching starts, so we have to explicitly enable the ones we want.

    While the match-all.action file only contains a single section, it is probably the most important one. It has only one pattern, "/", but this pattern matches all URLs. Therefore, the set of actions used in this "default" section will be applied to all requests as a start. It can be partly or wholly overridden by other actions files like default.action and user.action, but it will still be largely responsible for your overall browsing experience.

    Again, at the start of matching, all actions are disabled, so there is no need to disable any actions here. (Remember: a "+" preceding the action name enables the action, a "-" disables!). Also note how this long line has been made more readable by splitting it into multiple lines with line continuation.

    { \
     +change-x-forwarded-for{block} \
     +hide-from-header{block} \
     +set-image-blocker{pattern} \
    }
    / # Match all URLs
    
    

    The default behavior is now set.

    8.7.2. default.action

    If you aren't a developer, there's no need for you to edit the default.action file. It is maintained by the Privoxy developers and if you disagree with some of the sections, you should overrule them in your user.action.

    Understanding the default.action file can help you with your user.action, though.

    The first section in this file is a special section for internal use that prevents older Privoxy versions from reading the file:

    ##########################################################################
    # Settings -- Don't change! For internal Privoxy use ONLY.
    ##########################################################################
    {{settings}}
    for-privoxy-version=3.0.11
    

    After that comes the (optional) alias section. We'll use the example section from the above chapter on aliases, that also explains why and how aliases are used:

    ##########################################################################
    # Aliases
    ##########################################################################
    {{alias}}
    
     # These aliases just save typing later:
     # (Note that some already use other aliases!)
     #
     +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies
     -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies
     +block-as-image      = +block{Blocked image.} +handle-as-image
     mercy-for-cookies   = -crunch-all-cookies -session-cookies-only -filter{content-cookies}
    
     # These aliases define combinations of actions
     # that are useful for certain types of sites:
     #
     fragile     = -block -filter -crunch-all-cookies -fast-redirects -hide-referrer
     shop        = -crunch-all-cookies -filter{all-popups}
    

    The first of our specialized sections is concerned with "fragile" sites, i.e. sites that require minimum interference, because they are either very complex or very keen on tracking you (and have mechanisms in place that make them unusable for people who avoid being tracked). We will simply use our pre-defined fragile alias instead of stating the list of actions explicitly:

    ##########################################################################
    # Exceptions for sites that'll break under the default action set:
    ##########################################################################
    
    # "Fragile" Use a minimum set of actions for these sites (see alias above):
    #
    { fragile }
    .office.microsoft.com           # surprise, surprise!
    .windowsupdate.microsoft.com
    mail.google.com
    

    Shopping sites are not as fragile, but they typically require cookies to log in, and pop-up windows for shopping carts or item details. Again, we'll use a pre-defined alias:

    # Shopping sites:
    #
    { shop }
    .quietpc.com
    .worldpay.com   # for quietpc.com
    .jungle.com
    .scan.co.uk
    

    The fast-redirects action, which may have been enabled in match-all.action, breaks some sites. So disable it for popular sites where we know it misbehaves:

    { -fast-redirects }
    login.yahoo.com
    edit.*.yahoo.com
    .google.com
    .altavista.com/.*(like|url|link):http
    .altavista.com/trans.*urltext=http
    .nytimes.com
    

    It is important that Privoxy knows which URLs belong to images, so that if they are to be blocked, a substitute image can be sent, rather than an HTML page. Contacting the remote site to find out is not an option, since it would destroy the loading time advantage of banner blocking, and it would feed the advertisers information about you. We can mark any URL as an image with the handle-as-image action, and marking all URLs that end in a known image file extension is a good start:

    ##########################################################################
    # Images:
    ##########################################################################
    
    # Define which file types will be treated as images, in case they get
    # blocked further down this file:
    #
    { +handle-as-image }
    /.*\.(gif|jpe?g|png|bmp|ico)$
    

    And then there are known banner sources. They often use scripts to generate the banners, so it won't be visible from the URL that the request is for an image. Hence we block them and mark them as images in one go, with the help of our +block-as-image alias defined above. (We could of course just as well use +block +handle-as-image here.) Remember that the type of the replacement image is chosen by the set-image-blocker action. Since all URLs have matched the default section with its +set-image-blocker{pattern} action before, it still applies and needn't be repeated:

    # Known ad generators:
    #
    { +block-as-image }
    ar.atwola.com
    .ad.doubleclick.net
    .ad.*.doubleclick.net
    .a.yimg.com/(?:(?!/i/).)*$
    .a[0-9].yimg.com/(?:(?!/i/).)*$
    bs*.gsanet.com
    .qkimg.net
    

    One of the most important jobs of Privoxy is to block banners. Many of these can be "blocked" by the filter{banners-by-size} action, which we enabled above, and which deletes the references to banner images from the pages while they are loaded, so the browser doesn't request them anymore, and hence they don't need to be blocked here. But this naturally doesn't catch all banners, and some people choose not to use filters, so we need a comprehensive list of patterns for banner URLs here, and apply the block action to them.

    First comes many generic patterns, which do most of the work, by matching typical domain and path name components of banners. Then comes a list of individual patterns for specific sites, which is omitted here to keep the example short:

    ##########################################################################
    # Block these fine banners:
    ##########################################################################
    { +block{Banner ads.} }
    
    # Generic patterns:
    #
    ad*.
    .*ads.
    banner?.
    count*.
    /.*count(er)?\.(pl|cgi|exe|dll|asp|php[34]?)
    /(?:.*/)?(publicite|werbung|rekla(ma|me|am)|annonse|maino(kset|nta|s)?)/
    
    # Site-specific patterns (abbreviated):
    #
    .hitbox.com
    

    It's quite remarkable how many advertisers actually call their banner servers ads.company.com, or call the directory in which the banners are stored simply "banners". So the above generic patterns are surprisingly effective.

    But being very generic, they necessarily also catch URLs that we don't want to block. The pattern .*ads. e.g. catches "nasty-ads.nasty-corp.com" as intended, but also "downloads.sourcefroge.net" or "adsl.some-provider.net." So here come some well-known exceptions to the +block section above.

    Note that these are exceptions to exceptions from the default! Consider the URL "downloads.sourcefroge.net": Initially, all actions are deactivated, so it wouldn't get blocked. Then comes the defaults section, which matches the URL, but just deactivates the block action once again. Then it matches .*ads., an exception to the general non-blocking policy, and suddenly +block applies. And now, it'll match .*loads., where -block applies, so (unless it matches again further down) it ends up with no block action applying.

    ##########################################################################
    # Save some innocent victims of the above generic block patterns:
    ##########################################################################
    
    # By domain:
    #
    { -block }
    adv[io]*.  # (for advogato.org and advice.*)
    adsl.      # (has nothing to do with ads)
    adobe.     # (has nothing to do with ads either)
    ad[ud]*.   # (adult.* and add.*)
    .edu       # (universities don't host banners (yet!))
    .*loads.   # (downloads, uploads etc)
    
    # By path:
    #
    /.*loads/
    
    # Site-specific:
    #
    www.globalintersec.com/adv # (adv = advanced)
    www.ugu.com/sui/ugu/adv
    

    Filtering source code can have nasty side effects, so make an exception for our friends at sourceforge.net, and all paths with "cvs" in them. Note that -filter disables all filters in one fell swoop!

    # Don't filter code!
    #
    { -filter }
    /(.*/)?cvs
    bugzilla.
    developer.
    wiki.
    .sourceforge.net
    

    The actual default.action is of course much more comprehensive, but we hope this example made clear how it works.

    8.7.3. user.action

    So far we are painting with a broad brush by setting general policies, which would be a reasonable starting point for many people. Now, you might want to be more specific and have customized rules that are more suitable to your personal habits and preferences. These would be for narrowly defined situations like your ISP or your bank, and should be placed in user.action, which is parsed after all other actions files and hence has the last word, over-riding any previously defined actions. user.action is also a safe place for your personal settings, since default.action is actively maintained by the Privoxy developers and you'll probably want to install updated versions from time to time.

    So let's look at a few examples of things that one might typically do in user.action:

    # My user.action file. <fred@example.com>
    

    As aliases are local to the actions file that they are defined in, you can't use the ones from default.action, unless you repeat them here:

    # Aliases are local to the file they are defined in.
    # (Re-)define aliases for this file:
    #
    {{alias}}
    #
    # These aliases just save typing later, and the alias names should
    # be self explanatory.
    #
    +crunch-all-cookies = +crunch-incoming-cookies +crunch-outgoing-cookies
    -crunch-all-cookies = -crunch-incoming-cookies -crunch-outgoing-cookies
     allow-all-cookies  = -crunch-all-cookies -session-cookies-only
     allow-popups       = -filter{all-popups}
    +block-as-image     = +block{Blocked as image.} +handle-as-image
    -block-as-image     = -block
    
    # These aliases define combinations of actions that are useful for
    # certain types of sites:
    #
    fragile     = -block -crunch-all-cookies -filter -fast-redirects -hide-referrer
    shop        = -crunch-all-cookies allow-popups
    
    # Allow ads for selected useful free sites:
    #
    allow-ads   = -block -filter{banners-by-size} -filter{banners-by-link}
    
    # Alias for specific file types that are text, but might have conflicting
    # MIME types. We want the browser to force these to be text documents.
    handle-as-text = -filter +-content-type-overwrite{text/plain} +-force-text-mode -hide-content-disposition
    

    Say you have accounts on some sites that you visit regularly, and you don't want to have to log in manually each time. So you'd like to allow persistent cookies for these sites. The allow-all-cookies alias defined above does exactly that, i.e. it disables crunching of cookies in any direction, and the processing of cookies to make them only temporary.

    { allow-all-cookies }
     sourceforge.net
     .yahoo.com
     .msdn.microsoft.com
     .redhat.com
    

    Your bank is allergic to some filter, but you don't know which, so you disable them all:

    { -filter }
     .your-home-banking-site.com
    

    Some file types you may not want to filter for various reasons:

    # Technical documentation is likely to contain strings that might
    # erroneously get altered by the JavaScript-oriented filters:
    #
    .tldp.org
    /(.*/)?selfhtml/
    
    # And this stupid host sends streaming video with a wrong MIME type,
    # so that Privoxy thinks it is getting HTML and starts filtering:
    #
    stupid-server.example.com/
    

    Example of a simple block action. Say you've seen an ad on your favourite page on example.com that you want to get rid of. You have right-clicked the image, selected "copy image location" and pasted the URL below while removing the leading http://, into a { +block{} } section. Note that { +handle-as-image } need not be specified, since all URLs ending in .gif will be tagged as images by the general rules as set in default.action anyway:

    { +block{Nasty ads.} }
     www.example.com/nasty-ads/sponsor\.gif
     another.example.net/more/junk/here/
    

    The URLs of dynamically generated banners, especially from large banner farms, often don't use the well-known image file name extensions, which makes it impossible for Privoxy to guess the file type just by looking at the URL. You can use the +block-as-image alias defined above for these cases. Note that objects which match this rule but then turn out NOT to be an image are typically rendered as a "broken image" icon by the browser. Use cautiously.

    { +block-as-image }
     .doubleclick.net
     .fastclick.net
     /Realmedia/ads/
     ar.atwola.com/
    

    Now you noticed that the default configuration breaks Forbes Magazine, but you were too lazy to find out which action is the culprit, and you were again too lazy to give feedback, so you just used the fragile alias on the site, and -- whoa! -- it worked. The fragile aliases disables those actions that are most likely to break a site. Also, good for testing purposes to see if it is Privoxy that is causing the problem or not. We later find other regular sites that misbehave, and add those to our personalized list of troublemakers:

    { fragile }
     .forbes.com
     webmail.example.com
     .mybank.com
    

    You like the "fun" text replacements in default.filter, but it is disabled in the distributed actions file. So you'd like to turn it on in your private, update-safe config, once and for all:

    { +filter{fun} }
     / # For ALL sites!
    

    Note that the above is not really a good idea: There are exceptions to the filters in default.action for things that really shouldn't be filtered, like code on CVS->Web interfaces. Since user.action has the last word, these exceptions won't be valid for the "fun" filtering specified here.

    You might also worry about how your favourite free websites are funded, and find that they rely on displaying banner advertisements to survive. So you might want to specifically allow banners for those sites that you feel provide value to you:

    { allow-ads }
     .sourceforge.net
     .slashdot.org
     .osdn.net
    

    Note that allow-ads has been aliased to -block, -filter{banners-by-size}, and -filter{banners-by-link} above.

    Invoke another alias here to force an over-ride of the MIME type application/x-sh which typically would open a download type dialog. In my case, I want to look at the shell script, and then I can save it should I choose to.

    { handle-as-text }
     /.*\.sh$
    

    user.action is generally the best place to define exceptions and additions to the default policies of default.action. Some actions are safe to have their default policies set here though. So let's set a default policy to have a "blank" image as opposed to the checkerboard pattern for ALL sites. "/" of course matches all URL paths and patterns:

    { +set-image-blocker{blank} }
    / # ALL sites
    
    privoxy-3.0.21-stable/./doc/webserver/user-manual/files-in-use.jpg000640 001751 001751 00000040313 11147744254 024000 0ustar00fkfk000000 000000 ÿØÿàJFIFooÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ ‚"ÿÄÿÄN  !1AQa"2Rq‘¡b#3¢Ñ$B±Áð&SVr‚’”Óñ%Uc“•67Ceu£²³ÿÄÿÄÿÚ ?興€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ"µ~’xJ†²zJ›°dðHè¤og”ésNÈnã¹{‹Ò MHê¨î™³2þÏ(ÃÜZ=Þð×}<ÂÒú_ÿÝËVäÚ±úH¼úb.1ls/õœE¹;gD›|t?¢xyôP;e爭¾‘"áëÅ øjèÍLnŽ(û[ uÉëžï’ˆKé:áZÚë„\GMo1ÈîÍku ¤4tÕ ÓÃ䃵€OMþKMlâ»æç=ºÝpeET .‘Œk° Fät%VÕq›‰8J úgŠJšÊbXýü™Æ@=t»»¿õ\„ïw.ôy5Ò–©’ŠšÃIOHøZΙ úŸe½6õéúoðë­]EÃ4RÔvVKÈ“y18Óžƒ®0´1]¸—†¸ªÏl¾Ü ºS]Cš×²œDèdn2ž£q×í…Îáÿá¯ñÿù”A"‚ܯ7ÛÏTðÕŠº+ltTíšz—@&s‹´;cu “ޝñZÛS<±²[=ÔQ\ÄQ4²x²F¡Kwk‡³{ôAÖV¾¾ùn¶WÐÐÖTrªkÞYLÎ[Ž· dd xuÇUÏ ô…[ÝQ0u‰©Ž™¡­Ç28 ž‡Ç:•º(âfþ ueÃW®*etìäF3Xßw#bNzû^H:ª.Oëî1¯wKIy† {-DÆ0êV=Îk ý€q€0Þ¤²kxîóUfáZ[q† ëJ‡3-‹ÓÓ¶ç'}€t?ÇÄw,+µÞßc¡umΩ”Ôípn·däžàäù  ºñ5¿ÒU].±UÒ¾ÓjŽ™Œæ{Ø$wF0YôÉD–KC£© „W¶7DcÔâÓ¥Ù;û8vݯ$z9á»›*ßGræ¶ŽœÔÎy ’íÛ¿Èn·Û%ÞÝ } ¼ÚY1¿In­ñЀz…ͧº_oØ.wNÛ ™ïk»'>H:r,+ÅLÔvzºˆ&¦†hâs™-KËbk±Õäw.gkã;Ô\Oe¦–ýÞ’ã!Ž]4&Dí¿w!¿ýz ë9ÎF:å;ñßáÞ¹× ]8¢ýÅ÷ȽpØm¶»‹™ÊìÌ.‘šÞ€7¯U—ÒmƱ•µñq5¿•#…-­ÔLÑÓT˜ØŸŸ_ƒµÿgŠ×Ù¯–î  íÖºŽ}6²ÍzÏhc#÷…ç‡î¾½áú §/–jb,ë¡Ýà|ˆ?Ú¹hãž%>èî͸‡\d»ögHaxô§ÇQ× ì˜ß ÝŸÕ@­—~"¶úE‹‡ï+à«£5,1ÓˆÄG}†7#-=sº,ßH÷ˆÍo¨¶Tr%šá;C]–¿#½¡ÿ ޾[(wßn6¾+áJ*žU=}CÙS†»X˜ ‘ÔôÇU oñ»ÈÊûÕ5ž¥•¶¶„ˆKï”ïìùAØñ¾;üþ«žqçÔZ/Vë=5Æ\sÅÚ'¯u9¨ÐÜYƒœé=ÝýUx+‹+8÷‹7­¢¨¨‚-T—8©´jcQØÝ®ÆÝ>¡Ð¿TX¶Øjé­ÐÁ]]ÛjX?iQËóŽ‘°Ûe """ """ """ """ """ """ """ """ """ """ """ """ q‡ þ+¶ÒÒvÎËÈ«eN®^½ZC†ž£÷_%^0áÅvêZA[Ù m©åëÉhpÆ21ïyôRA©áŽÑÇtœL+4özSOÙ¹YÕ»Žugo{ùiG£êÚ'ÔÁeâŠËe¶¦S+écˆ8´žº$È-ýr" 4”â’’vÉ,¢& &ysݲãÔ“Ô¨u£zH8&N¬®}K æxê-Ñ»OïèJ›¢¯‚g†ùMv½_&»TѰ²>ÆØÛ$íw­c=éá*[»ç‘qÜîÏïa¥º4êóë“ò]Eo\-mû×–‹Ä¶«“¢äÍ#al­•›ukŽ3° ^iø†Ÿ„..Ñ$²Wê’¢®Q©Ï”à‡ãÈ€qŸÔ©b ç•^Š©ê8B†Æ.e²ÒÔ>gUr2dÕœ:¶ÛHΫÑo®¼Âãõ0Õvx¬%òõsÎFœhð=T•D©8'²SñLBã¬ßŸ+µr1ÈÖ:jö½ÿ%âî£áÞáø*%¸:ksÝɺQÀ$êÕí°»§†Ú|ðzªyÉÂGÂmuãÒlZk•UÞ(œ*+æ§ä°¿pÖ`Œ·Ž¢§œ_Ê­Ô”³²öz¦TêåkÕ¤8iÆGÅÕHJ£‚D÷¾"¸úÃH¼PšN_#<œÆÖjÎ}¯w8Û¯UjOGñIÛX¹Ke­Úé«¢Œ×g'-$íÓl÷)’ ‰SðuÁñׯܫ&©‹”×B{3bß:ƒq«a¿ÏÅcÛ¸xït+Åúk™·ŒR±Ô툎á­À’ü`uꦨƒ[³AÄ6*«UKÞȪ=¦lZAêÊ)£ºá_e«¬âiªÝi{9,u3ZÞXǰvÇlj9îðSÔAáÎõÊõWÛ9þ´«5:yZ9YsŽ=ãŸ{®Ý˜z?®£}L^(¬¶[je2¾’8A-që¡ùËzw)Ê ³IN))!§l’Ê"``’g—=ØÛ.=I=J‚3ÑoÒØ}r£Ü;hŸ³uÃKtéÕ·\ç'äº Ôð¸¨ãºN&íz{=!¦ìü¬êÉyάíïøw/|[Ã0ñe—°MPúw²VÍÌ´<úõ[ÔAü[Qz´]®/²§9äãVþA”‹œÿ‹Ï¢sŸñ}e"Åç?âû'9ÿÙR,^sþ/²sŸñ}e"Åç?âû'9ÿÙR,^sþ/²sŸñ}e"Åç?âû'9ÿÙR+JçH9 ÿr" """ """ """ """ """ """ """ """ """ """ "" Y¿zUµø\÷’Ýyìïñ(,¢½ÙßâÕNÎï ´Š÷gxêB§g‹PZE{³¿Åªþ-AiÞÎÿ§g‹PZE{³¿Ä*vwx´„†öÛ‡qâJ'­(i¢uºö¶BؤÈ.{Ç?l,©x¦âïFÔå“IOYOVË}|àeбÌû#>$®Ik§ ŒÅGOέº@yd+ÀÐ.fëK«8“â ¬©¤õuEh6Hâ% ¶4üŠõU=Lj8kˆ8¢ÒÉ›SQ)¨Üó 2÷ä“'Ÿ²t¬Ž¹ñÊ.y@mmâ»[¸o–-‚Šo[èýØnÙó3·39Î}¬g;,[ ÒÞi™qŽcÃÕÖX›9ö@íŸi¥Ü¼ôn@ÝMéÕcQÖÇZjyM~˜'tq-8Çp'̵Ï)¨‚Ñp/ìü*$¨©yI¤Nòòâ ¾ò©§šŽ^"’-ä|mŽ2‡LG´Üwçxæ2;¯ÁG%b“†ª$-¶ÆæS9àã#r@>ðÀ9éœä;Øü–³×Tÿ‰}CË›µv>Û¯Fz1ž¹Îý1¹Pim¢‹Ñ¥ŠZ wG Gb–êøæ>ŸN^IÑ?£sÝ•îË-ŽJ•SÚd§ŽÝŒ½ïˆ 1+us¤:‘¶utÝHÆA8®¾†ª÷l§š: )Jꈪî2“FâHÀ ËÞFÉèvê£vé«ÝÁUq±Óº‚.#ÑPؘöé¢öKƒ[’æ·pq¹Â¡t»ÒYûksšj꣤„ç2?§ÈlNVLÉ77™M,$,o4´óþ¸Òã±óü@\¿‰©øjF[&¶ÒÂëlº^Ñ3XÓHØÜÌ >èo²Ý}ÙÆrzxok;ÿ$OÙKëNul·_Mü3Žì ë=øAãÝâ¹Wgâ³`åþõºùö§K¿wg:zéïëºY© ¶^}II…õÖù{Qñ\üpã·‡A¶À:=s䎂WÃ’Väµ…ÚuÓžåüGNxDßÌD3‘Ì0ç'WN^HÜêözuRY¿qŒî:õèTZêÿú›³Hm=¯ÖœÒßcyYéûì»$”W *jja´‘Ë#/Š*®d‘—7$=ºFŸ-Î@ÎËÔ7›eHœÁq£”@ ›—;]Ë©vߪ…],·[…wEG ¬}dT‚žGÖÎÏi­wCÓO\dî³m”-«»ÛËÙy‘”ôò²VÕÓÅOMs4˜Î˜›¯®ÚN6(%â²™ÒŨ„É+ ‘°<öŒeÍãq¸XÏ O[e‚fK ¬ÌppÚZpw`¨0¡¾ÑÀnQÑUI]fsh)Y “4@HÝcÄq’GÀ¦6«{-WËE=ª¥„÷¸ë¦ËÌä •¢"" """ """ """ """ """ """ """ """ """ """ """ ""_ÔõúªŽ¹Î¹fŠ ²20\ Ü.' ÷’@ ß~»òLlFð%Ò:6½¥ìÁsAÉnzdyàý·ÐK¶s܃]Gd¦¡¾].ÑI1žåÊç5Äio-¥£N;޹ÎëcãóçÕyŠHç…“BöÉÚǴ审¼/HÿÛžôÏø*ÌutÓTÍMD2OžlLG¨eº€ÜdtÏUyþªŽiÄyŽ£ë•S·]¾{" e¦+ghxžzŠŠ™“Ï9n¹£:@À¿Ågãcãýéãä¼2h¤tŽV<Æí p:]€p|ÛÌ ¸O]Ïê©ã× ÌutÓTOODOžŸO:&<G¨djFFã=UìŒg; tèwñÇ_šm¾Ãñ¿ö,jk…d“GKYO;àv™[¡Æ3¾ÎÁØìz¬œ wçc¾z'Éxšh©á|ÓHÈ¢¥Ï{ÜÖÔ’zâ*ºiÄfˆ¤Æ%Œ±àëaÆ1Ôn7óA9úä*`};Ó.©ƒœct ¼Ïü$=þ}OŠñ$±Äd‘Œpku8 DôÄù/õtÕ|ÞÍQÜ©œ§‡hxêÓŽ„g¢ ßMºñýÈ|†ßãæŸ¢ ¯z¦ÝÃw" ŸöÞÊ=<òël󚃒cŽzmÕj¿Ê_û²Õþå/ü…º¬¨”2Îç9¬/sš :@$ì7=:,x„Úýf+cäóù¹8ÑYñèƒü¥9ͶÕÿ©Iÿ#ù J¹7Û ­ý©ÿeCíüMÄ—;1¾SÓÕ†™œN{+)´éÒç=âPì» ‘¶:ô1K­}`iíŒB_¨û$ŒànIÏS¶z k_¶I*Ÿ;¨‡·/9Ñ "sööv‚{ýÒ‚ St¨áÎ ô…w†I*%§eˆÞÖé%íÃIÀ ÎÈë“‚$wYQ['¤žöʹkàd10±Œ‘’Hñ¶– Yß$c©[×X­¯¬­} tÕ±ªu9ų4 ægI l2!Y¥á‹=ÑK +ù‘csç‘ú4‚Öê' 8oNüdÚYï¼_ÄVŠ[Ça¢¶COÙcmH‘óHç1Ÿ Iq-o“HÆ6UoÚᆅR5ž¯É¤ÃÜ ¸s¾IÏ~PGí¼E_q6ky˜E]åuÙÁ:²áÓ[‹HÆøÎˆîuñ3‡¨©e4³q DõrÕ:6‘Ì ÀE¥­çÝèVê×õ7ªë”4í©»a“EO#‹f€Ðü5Ù;’@F:em+­4*Héj©Ãâ‰Áц’à \Ò O˜þytÛ­g Üý \µŠêªfÑH怖–‚qŽ€ï€3ƒÑHmÕ|BnttÕ/¯VE ’j“F×FíkâlnqvýÎùê·t\3f·º¸ÁDÒkÀ\׺Nv2v²|NvÜ“óU áËU¶¡“ÓS¼K qºYŸ'-§ q È ˆâ§NæµïÔØ›Œwd—ç=صÜ_}¤±q{ELÌ©µ>”ÓMS "`%xÈx`,;tÛ¼÷©»8FÇºŽ‚:'GœúcÒ6H‹‰.-;PÉ'½z‡…,pC]-ì-¯kT÷?›§8$“×ruuÎýÁo‹.õ¾¹¾Ú;FhG ÔT˜´·÷ºœÜçé¶3…®áeüqbi—„éÝ£K1Mnw8ϵ×9ïDz¦Qð}Š*$mÜúŠGQJ÷ÔHç>P’ãà7ê’¼Þ´²Zic§|RSRv(ŸDsaÆ4d8gA;ƒƒ± ×ñ Öh®ôvêJêˆät.™ðQR¶j‚Üà;/Œns¹žê=KÆW‰8qáä ç_½PÉ夯 [šÓ¤¸gg eUÖÊÙiæš)¹ôñrc•R²]ísÚàç™9$¯0pµ’žÛSnŽß£©“,G$à C|´û#¡ê2‚Ætµí¨°ÓO~’¡ÂùIËÒÈ„±ëÜ1±iÓ¶]ì=þ-»2ßqxÝ<œLûU<²DÜSÆHÁÀƬo×Çrz)[øNË-/g’–G´ÌÚƒ#ª$2ó0×s5kÈ»°¯³Š:êCDÃuCªjâ\+°K·;ÓÆÀ Wß.¶zÛõ©Õ¦­ÔöY.4ÕO‰|nn—´5Ûàdm±Îr­Úow¨î\"ÊËkŽùG$“Fè˜Á›d¥ óƒœøŒ „¦µCIYLÚg9•¬1TºI¤{äi`½Î.#Ž»w/L°Û-ªVÓûTf*3­ß²kšG_kÙoŸíA²ÿðNôîƒÅF 9Î1¨uùÍÄg‚ptšîý±Cûß§ÿ-t lt4bIc¨x2<“8lwÒÆ“>ˆ]­b¯¶z¶ãÚL|®w©ªuéÎtç—œg|g¯è‚-t½]¨kxòJ)¦‘ô‘QšhœK›¦{nkNÃ.éܳ(_ë qq×SÊ‹¬Õ/”hÚFf6†q¸ ã[Ö]­‘Ï=C-×ÏQ4³T‡I¨ò²ìj–²ÉA$’QYëi¤“ßtV:†üÈ‹t8øž¾™ô·Jª‰»5®6Ñ\#.8|úd$x‡2<ñ©UŽ škµŠ*Ùd’«ÕUN™Ò8“¬ÉNHÜ“€I~{5ÖWÅ4.³Öº9¤æÈÃd¨Ãß×Q¬l7òW¨ª›pâÊIমl1PÔ±òOE,-ÔçÀ@ËÚ'KŽÞ5¾’„„ðø‰ìd†÷Jç·SZt»ŒŒ,Œø­åWXæ.¸WQMn†•Ñ8ºGm×líÕ»õUªz—QÜmµ5Ív=W5DaÚF-ai ãâ¶ðÝ C*)8~zyÙ2Å`Žnv8"/PAoÓÍsôe]t¸Ü*ÊJ³´¦c¡„J—œ³^x%_ãI¦©‡Žá–¦wCJës ‹œí .; 9Î1ŒàõM*%áêÉŸ5UЦid^ùl3½ÎlI‹=F@®¾¾ÊóR_h­qª —Yj30hÀýŸµŽì Ì´ÆØ¸¢á ÜÖ[¨Ú Ü\H¨¸îO̓⤠5Ãæ9o× i©*)éEK\ÚI)ǰé‰kCÚÝ€sz €¤¨ˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆá:ÿ>å©»M+«í40É#5G6RÇžTm.?¡v€|œ£ƒÒm¹Ñº±¦‹°6^_µ\ÁRá«N¶ÁŒéïÆ Hçç·Í: žž*ÖZø—Œ§»êÛdtü¸™!%š›ì†#%ùÉ$ìp¡¸ÜTÞî°Z«e©µvI…6ªW2~`tŽöZÇ#Ô[Ó#~¨$˜Oú¨ŒGqŽíq°PÚkíÂ$¨š¬´Íª0íÁk޳¾2wÁ$Žóøåµ.áÑh·šÏ]‰L\ɹ\£µa§Ì:i8Ê r(aâ¾Ãw½ó­ÒA} +$íÏ{ÙY»ÚÂ0ÐÜîêz-•Ó‹©íUS<.4¶Êxåžv¿~cÎoy#9ÛPA!OШí?U6ïKk¹[GS_ å¤ÅG1¯,st.ŽjÍÔ\*{%þ±¯5°I.†S8{£^ŸkYÓ§Änp‚Q„ñòQên*Žº’Å%5)|×W‘É/ýÈh&RN7ÐFžƒ'……AÄrÃtµRÉæmò¢²X¤|§Gö01¸sZØÜ“º wDÁð?E “Ò,±FöÝg¶²iêtB9A§SäÒtg`ç e]Å‘Zøn­Âùål „ÌÇ5Ïq8<Ìéѱ$œl:e#Ä}QD ã¸$†è4QÍQEBúàÚ*æÏŒ`܆.ÎíïÊÜpíÖ®õk†áQA$U2XZÚŽcˆpÎþÈÇwŽsÝŒ ÚãìÙîQkïMe5o}8§¤n­U5­†IöÉå3WLnFNÁ^wŠª‹m%ªµU×Q àÉeå68N0\í.9$ã}Hü|º¢çuÜKwoV6¦’Hhbáé«DjœÇAps[âá¤`ìÓ¨û+uKÅ.š+5¶Þéë«-Ì­1OTCaˆ€©Hsœr@žþ¨%Iß…Ÿ®’ª c䪚èÛT´Î”1ÑK¾wÁp:`oºÚÙ/ò\îWKeM¥­¶¾13Y/1„=ºšZìàz€ƒvˆˆ‰Þ‚.2ý Xßà Ïj?æÙ÷þi] U4Á3C¢“Ø{Ox åsöÔTŽü7Ìp¸v¯Tjö¿3Ïî}¯ŸÑ@íGº6–šv£þmŸæ¹üœEUqc›m¥l6¨èÚÎLz_6¶`5îÉÈ l<Öuþõ=TtΦ2¾xd-“ÕÕ02ž@Ü´=ÒÓÓ ·~íÐL»S¾óúÿ5‚úùÏQR”u2¹šFîcá 9ê0á±ÆýV5tÕÖ¶É ,¢¨¥«ç1LZ÷|¿dðG]Æëce«ª¸^,••ŒdsÔZê¦sZÀt”å ä“8ïñA*–c…¡ Œç¿õ^;Qÿ6Ï¿óPÏIÍcâ±6JnÒÇ^iƒ ÃO4iw³í7é¹u°³RQÁXçSp·ªžcÓÏåS c#Ùý›ÜïAn£{Z×;]FH8çlŸ™RD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@@ˆƒ Õú¯Bâ÷‡Sò#O»—eç>zYþêÒÒp¥]¶”Û­÷—ÓZùÆQaÌÌÚ‹.¡†“ž­'ïRGLÖ;ç´3ÁÈ#u¼Op¸_¤©ª.¤¼Ã %„GíFøÀ s]žƒ®1¹ÇA±ÈoÜj*)d¸ÞMS)ݲ$ :pÖrýA‡WM±Öó´3ÁÈjàäª[MæN=⪚Z—PE3iXÉ¥¤/d¿²ÁsZ54÷ä“‘Ñléø.–†³†ä£œÇ“µ±9šŒÜÖà’ìŒåÛ ÉîR.ÐÏ'hgƒibáh}mÄ5u3ó¡½GOƒF45‘–òs|±æ±éx*˜p]ŽáW%Y¬quEV×½Ûi8ÎØ `ï÷T‹´3ÁÉÚàä(8n­×:[•Æèʺº()ùlapÞᨗÀë€:‹t<'êªÊ{” \ ÍÂgD]ÛC· ´gÝÆp6ß*CÚàäí ðr}ŠÃ$·KíÎ},5â·ŠˆKLZÀtÐì7ÁÇ»ò[Jî¾É=X¥¨³µÌ¦s¢æ0µÌ psC›Ü0vÂÞv†x;桞A¢àºÛ}=Ka¾s$¨¯š²VÍH¢@dŒÔ5{¹È#sÑ\‹€é#áÿVŠÉ;k}aDlkD3ç ±›€Ñðü÷ïR~ÐÏ*‰ÚNr $ö…}Ê…ãšêº7Ò1°ÀcŠ-@‚ýĹÛõÈé²Vmº¦Ûe¶[©j¢"Ž8¡’I!'šÆ7IÒ†— òqæ³EC@äí ï:®’Yo-Šç!º½ï™Ï¤NÍC¬»fùp3‚T\%-­UTÃp  e½Òɸæˆï3P#pHþyR>{AÁk²©Ú{œ‚+UÁÔT¾£×¾Y­3['|ñks„…ÎÔpÓ‡;¦ãc".’Öªš ƒa¸PP6Þédƒ\sÆÐ:³ hdaß<©hgƒ“´3ÁÈ#àh… ¾ëßÍ‚î˵DÒG¨ÔJ3¨`Œäxãëin°ú¿‰/W~ÓÌõŸ#ö\¼rùl-÷³íg9èÌT0ôñNÐÏ ºŠß=¿ •;C<‚ê+]¡žNÐÏ õQûƒþ°þ´ ¢üDo`ÉÚL\­±ŒêÓìç=Òºšßs€A_E \AÚÄu6F‡`Œà÷àŸªÀü3Âÿèí¯þ ?äƒü3n–²ó<âI…ݱ6¦94KFœFǼ­ÅGUOPúúê§S0²ÔHÒ"©h$ã½Ù;•‘øg…ÿÑÛ_üÉ? ð¿ú;kÿ‚ù ÕMÁ6™­× '>¡±VÔö—‘ ‡9ÒÃe»¸cóÖÈ47ŒmÍ` u^Û™OöþKßá®ÿGmðQÿ%“Ek³[ftÔ6š:YÒ×: vFHÎpH6¨1ø’ÉðÓ2Z‰éßIQTR@[©²5¾Ï¼#~˜^)­ÕPT6I/uõ1Œƒ¬€5Û`gLm;y‘We°×Ôº¦²ÍAQPük–ZV=ÎÀÀÜŒô~ŠÏážÿGmðQÿ$zþ¶×PÔ[û]tÈe4°½‚6¿V¬·-$ ÷dÎÝúî¶Ü]z52T[ˆøx¼ tí·Mó•±ü3Âÿèí¯þ ?䟆xcýµÿÁÇüx´±ÑñMÁ‘ò9¶ê0dçúÎù>C @µöëu®Úé¶ÝKFeƾD ^3Œéã'궈€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ1fýéVÕÉ¿zU´D@DDD@DDD@QH•U| r¨¥žX'g+L‘<µÍ̬yd~ªNµl5,Œ’J¼ MÜÌ~÷o>XXÓzE†¸fÄÉ鿏WÔQ2g—Í‚Ó%ÄI ©-ß„ýmz©¸vÑžÕ%»G+VeÇ^uo]>ë^•Zd·Þ$¢¹[é…(«l x’?Â~›íæ‚õ£‹ÝÄ-5ÒÑltõqH#4O±œå¿×;{®Îq¾0¤ì.1´¹ºI-ÏCáú-%=’ãGï §¿Tö÷»Y¯‚bÒHÈ qÀÇvV퀵v§wŠ ¢&È?|Õ”±aýëVR" """ """ """ """ """ """ """ """ """ """ "&ýÝP?ÆUNÝvù•¦»ÿI»YíãpfuTƒ?ÕˆmÿätEF)8îãp¢7J* %¥2‘$VÚ™$aÚK„Í0í‰Æî'=úª÷õû®lëýgñ/\êæ0Q²“D8nöþÍ — jö¶ÜœŒt2ú»ý-ž³¶š>hÊi)šæòæ‘ÁaÇPËÔ1Ó A'§–ùé… ¤¹Þݼpý¦;tT–h)Û ª#{œíQ €ñ×qÓ ´Þ7¸]¾¨‚–/]¶£™ÚšçòŒ@gHÈί˜ÇN¨'jžwP)8†²Ýzâg¶†Þ}XúVO;›$ñ9Ÿ´q:·-·=#|ål.übûX¾V2ç·Úà‰¤‚uKPòhvq¤5ÌÎÙö¼K¾ªŸ¯ÝEã½]¨8‚Ýh»6ϹC+ ’š74DøÛ©Íp.:†¼ sŽcÛx’óuºOfŽ (®ݾGeѸ‹–³ílãŸtm¹(&vë·ÍEh8ªªãŠ(!‰µÕ’?¶ÆàH€E‘.ÙØëÃ[Ÿ‹88Xt÷ªšXíPÐÇoâ*©ê,À–2&AÄ Œ ÆOz ¿Cƒ×ÁQs*KÝG^øúëpŠ9§¦9e>XÇ’ÂÖàéÎ[‘¾2z©ºÿx©¸CG,:Loý¿ªªae4¹n³&9Ûœí¶r‚\¨¹\d´ðº¼MmŽªáS'6ª¨N︪gd7"NUO¤ „.$™±RÍUh4ܹ]O$QÊÙ\ñ¸‡ ³ß¾Çpƒ£ýU3¶T#‹ou¶ûa,€Òþ¨¬ÖAÖ©ÌÆsŒcË9Z¾–¼ñŽ#TÞËøV EŽØe£âÆ­X:±ÐcötÏ×î˜>k™ñW4z@¯–¦:*ºz.–²jªböe®#p]ï Ýðû8Ï´µõu•×¾²—“G+¸LÖà ‹ÛÔZÀ p2s¶Ç~„:ßë÷O¯ò\òÝÅ5´vî²ÄCêæ´EW-Obš 6=šÁËŒ—wFF2ʯâûÍ=šß4vè㬨¼2Ýý*žX™#\ 5®ÒàÝsƒ¨o„”Vi[RÚf6²X¥¨û⌱®Üã .qc¼ÿr¼€ˆè-ÔÎÚjY'sÙí9ïÆÜIÏ@±½`;7hçÅÈѯ›ìéÓŒêÏLc|¬Š¦6JW1íkšã‚2Åsé=Kø?[»Gmì9Î]ÙqÌÕÿ”tüÐN©îðUÉ#)«)§|mkžØœÇ‡ ´œtnÓù‰;Oåû Óp5¶ŽÝj¤¥«­†K[¤u-S^Þcy„—g--9Ï{{‚µ:+»*e«ªõ³bFiA$³:\'§M†0¤£òïþ²vŸË›GÏÑÉWYUSr¸ÔÔUÛŸn’Ida<§w€púwõ$«ðp•%%e]%ed–ámcÚXuD²H-#P8vÛd ädÏiü§ê§òÿ =_ Q×ÖÏYSUTùê-n¶Jì°jÇ%ø ƲOQ·’¶Î ¶6F¸ËPð-ÌZ猽Lsté;lÎÆ2z«öž·Z.0ÖG-}K©šæÒÇU?2:|õÐÜmžè5þ‹ê+ë8A“ÖÊ&/šC…ÎsÈÎúÉóÏNà¡TÖ_Z_xŠQÂôt¼ïYvn_´}9ßÇ>kªpÿ ÓðÝ$´´/ªt”ÈÖLýA™în1üÊ÷háø,²ÜLéÞkªS/3qÜ ·øÊ?6šŠóWn††(Ä<+3Y&·™Á¬gV’<Ësæ±O]l–µY-&¶²[ls¸žü3vìÖ`ž‡å·ŠœÜ¸N’çtšá;ª[,Ö÷ÛÜØÈ å»9# ïhï•UÀ–úŠ;| š¾šk|\˜*éåÑ6œt.éôAjÏxâß MPÛdvû»$å²:èäl/Á»ö0HïÜ);5hn¼jÀÕŒãôû­4%KGÃÒY觯¤dŽÖú˜%Ó9vA.׎§;tÊÝ2'±np1“¹(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢P~ù«)cB× A €²P?Lù";ïÛ¸vãm¤¯æƒq{™¡ µšt伓=¡ÓõYU·ºj+Ý®Ó$rº{—7’ö´Ž[u[äl{”o‹)a®ãÞ¥©‰²Ã3+ØøÜ܇4Â6ZfšÚ/I<)e­æIØ{a§ªvü豓ÞöésOÈôC99Ïß»üe3¶s·Írxl¯ñïoÀëÏÏ7ëÊå÷û½VeÒßI[}ôS<-’JZ($ÎßCû3ˆpð ·cóß êyÇzާ2¹eKêê¤áiî•TÑÚe³Fó5ÂKNjH™¶Œ–ãÇö„¿‚Ú#²ÍË«5ƦNÎá¢`fÞÌmsÜK3œoßÓ ’o柯^›õ\¢Ç-=ºýoäh¹ÔIXøß!†áueÕ$=8ÛXp 9¥ã^iÍëÖµ]ƒæó3ìr±¾ucV;±°ƒ±ç®N0Ÿ¯ÝskÛ.N¼X½{QI«@™õÐi…fÚõ€ö4gÛ ðº†Ô³‚£ìµSÔÛ á¼÷Aâ £ÕûFÄ5¹Ü¼ôÁèNØG¨šXyB:i§2HÖ;–Z9`õyÔFÃË'Éji8–;•mU= ¶º¢:j£I=CyMŽ7{g<8†ç¸oÝ• ½›'6ÊÛ?¢~#¡.tvg?—µl5clã©ÊÓAIMO§³ÓE xȇ-¸c3¥»tQÀîÉAÙüÁùcqš®þk“×Ä_wâ/_VÑSÕv‡>×Fù¦0ãö}ÂFàù4g9$­ÅÁ­AdüLþeœ[1®­šc5y2‚H-Î'r@ݶÏ{¦½vþÌəث$¢“šÐܽ˜É'#q×u³Ïš‚z/‹eû³käz¬Zt³Ns¾p§H+Ÿ4Ïš¢ ®|Ó>jˆ‚¹óLùª" çÍ3樈+Ÿ4Ïš¢ ®|Ó>jˆ‚¹óLùª" çÍ3樈+Ÿ4Ïš¢ ®|Ó>jˆ‚ªˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€éÿ_ñöODžO_Õ2|wóÊ" íŸ/ñ÷TÉñÝüÿRµ¶‹%5”ךi&y­¬’²NkÒ÷ã ÞªÙ"ÇèÝrˆßýÉÝýß$D ±€r;r"y(ˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆƒÿÙprivoxy-3.0.21-stable/./doc/webserver/user-manual/startup.html000640 001751 001751 00000036523 12116120072 023355 0ustar00fkfk000000 000000 Starting Privoxy

    5. Starting Privoxy

    Before launching Privoxy for the first time, you will want to configure your browser(s) to use Privoxy as a HTTP and HTTPS (SSL) proxy. The default is 127.0.0.1 (or localhost) for the proxy address, and port 8118 (earlier versions used port 8000). This is the one configuration step that must be done!

    Please note that Privoxy can only proxy HTTP and HTTPS traffic. It will not work with FTP or other protocols.

    Figure 2. Proxy Configuration Showing Mozilla/Netscape HTTP and HTTPS (SSL) Settings

    With Firefox, this is typically set under:

     Tools -> Options ->  Advanced -> Network ->Connection -> Settings

    Or optionally on some platforms:

     Edit -> Preferences -> General -> Connection Settings -> Manual Proxy Configuration

    With Netscape (and Mozilla), this can be set under:

     Edit -> Preferences -> Advanced -> Proxies -> HTTP Proxy

    For Internet Explorer v.5-7:

     Tools -> Internet Options -> Connections -> LAN Settings

    Then, check "Use Proxy" and fill in the appropriate info (Address: 127.0.0.1, Port: 8118). Include HTTPS (SSL), if you want HTTPS proxy support too (sometimes labeled "Secure"). Make sure any checkboxes like "Use the same proxy server for all protocols" is UNCHECKED. You want only HTTP and HTTPS (SSL)!

    Figure 3. Proxy Configuration Showing Internet Explorer HTTP and HTTPS (Secure) Settings

    After doing this, flush your browser's disk and memory caches to force a re-reading of all pages and to get rid of any ads that may be cached. Remove any cookies, if you want Privoxy to manage that. You are now ready to start enjoying the benefits of using Privoxy!

    Privoxy itself is typically started by specifying the main configuration file to be used on the command line. If no configuration file is specified on the command line, Privoxy will look for a file named config in the current directory. Except on Win32 where it will try config.txt.

    5.1. Debian

    We use a script. Note that Debian typically starts Privoxy upon booting per default. It will use the file /etc/privoxy/config as its main configuration file.

     # /etc/init.d/privoxy start
    

    5.2. Windows

    Click on the Privoxy Icon to start Privoxy. If no configuration file is specified on the command line, Privoxy will look for a file named config.txt. Note that Windows will automatically start Privoxy when the system starts if you chose that option when installing.

    Privoxy can run with full Windows service functionality. On Windows only, the Privoxy program has two new command line arguments to install and uninstall Privoxy as a service. See the Windows Installation instructions for details.

    5.3. Solaris, NetBSD, FreeBSD, HP-UX and others

    Example Unix startup command:

     # /usr/sbin/privoxy /etc/privoxy/config
    

    5.4. OS/2

    During installation, Privoxy is configured to start automatically when the system restarts. You can start it manually by double-clicking on the Privoxy icon in the Privoxy folder.

    5.5. Mac OS X

    After downloading the privoxy software, unzip the downloaded file by double-clicking on the zip file icon. Then, double-click on the installer package icon and follow the installation process.

    The privoxy service will automatically start after a successful installation. In addition, the privoxy service will automatically start every time your computer starts up.

    To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the folder named /Library/StartupItems/Privoxy.

    A simple application named Privoxy Utility has been created which enables administrators to easily start and stop the privoxy service.

    In addition, the Privoxy Utility presents a simple way for administrators to edit the various privoxy config files. A method to uninstall the software is also available.

    An administrator username and password must be supplied in order for the Privoxy Utility to perform any of the tasks.

    5.6. Command Line Options

    Privoxy may be invoked with the following command-line options:

    • --config-test

      Exit after loading the configuration files before binding to the listen address. The exit code signals whether or not the configuration files have been successfully loaded.

      If the exit code is 1, at least one of the configuration files is invalid, if it is 0, all the configuration files have been successfully loaded (but may still contain errors that can currently only be detected at run time).

      This option doesn't affect the log setting, combination with --no-daemon is recommended if a configured log file shouldn't be used.

    • --version

      Print version info and exit. Unix only.

    • --help

      Print short usage info and exit. Unix only.

    • --no-daemon

      Don't become a daemon, i.e. don't fork and become process group leader, and don't detach from controlling tty. Unix only.

    • --pidfile FILE

      On startup, write the process ID to FILE. Delete the FILE on exit. Failure to create or delete the FILE is non-fatal. If no FILE option is given, no PID file will be used. Unix only.

    • --user USER[.GROUP]

      After (optionally) writing the PID file, assume the user ID of USER, and if included the GID of GROUP. Exit if the privileges are not sufficient to do so. Unix only.

    • --chroot

      Before changing to the user ID given in the --user option, chroot to that user's home directory, i.e. make the kernel pretend to the Privoxy process that the directory tree starts there. If set up carefully, this can limit the impact of possible vulnerabilities in Privoxy to the files contained in that hierarchy. Unix only.

    • --pre-chroot-nslookup hostname

      Specifies a hostname to look up before doing a chroot. On some systems, initializing the resolver library involves reading config files from /etc and/or loading additional shared libraries from /lib. On these systems, doing a hostname lookup before the chroot reduces the number of files that must be copied into the chroot tree.

      For fastest startup speed, a good value is a hostname that is not in /etc/hosts but that your local name server (listed in /etc/resolv.conf) can resolve without recursion (that is, without having to ask any other name servers). The hostname need not exist, but if it doesn't, an error message (which can be ignored) will be output.

    • configfile

      If no configfile is included on the command line, Privoxy will look for a file named "config" in the current directory (except on Win32 where it will look for "config.txt" instead). Specify full path to avoid confusion. If no config file is found, Privoxy will fail to start.

    On MS Windows only there are two additional command-line options to allow Privoxy to install and run as a service. See the Window Installation section for details.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/quickstart.html000640 001751 001751 00000047673 12116120072 024055 0ustar00fkfk000000 000000 Quickstart to Using Privoxy

    4. Quickstart to Using Privoxy

    • Install Privoxy. See the Installation Section below for platform specific information.

    • Advanced users and those who want to offer Privoxy service to more than just their local machine should check the main config file, especially the security-relevant options. These are off by default.

    • Start Privoxy, if the installation program has not done this already (may vary according to platform). See the section Starting Privoxy.

    • Set your browser to use Privoxy as HTTP and HTTPS (SSL) proxy by setting the proxy configuration for address of 127.0.0.1 and port 8118. DO NOT activate proxying for FTP or any protocols besides HTTP and HTTPS (SSL) unless you intend to prevent your browser from using these protocols.

    • Flush your browser's disk and memory caches, to remove any cached ad images. If using Privoxy to manage cookies, you should remove any currently stored cookies too.

    • A default installation should provide a reasonable starting point for most. There will undoubtedly be occasions where you will want to adjust the configuration, but that can be dealt with as the need arises. Little to no initial configuration is required in most cases, you may want to enable the web-based action editor though. Be sure to read the warnings first.

      See the Configuration section for more configuration options, and how to customize your installation. You might also want to look at the next section for a quick introduction to how Privoxy blocks ads and banners.

    • If you experience ads that slip through, innocent images that are blocked, or otherwise feel the need to fine-tune Privoxy's behavior, take a look at the actions files. As a quick start, you might find the richly commented examples helpful. You can also view and edit the actions files through the web-based user interface. The Appendix "Troubleshooting: Anatomy of an Action" has hints on how to understand and debug actions that "misbehave".

    • Please see the section Contacting the Developers on how to report bugs, problems with websites or to get help.

    • Now enjoy surfing with enhanced control, comfort and privacy!

    4.1. Quickstart to Ad Blocking

    Ad blocking is but one of Privoxy's array of features. Many of these features are for the technically minded advanced user. But, ad and banner blocking is surely common ground for everybody.

    This section will provide a quick summary of ad blocking so you can get up to speed quickly without having to read the more extensive information provided below, though this is highly recommended.

    First a bit of a warning ... blocking ads is much like blocking SPAM: the more aggressive you are about it, the more likely you are to block things that were not intended. And the more likely that some things may not work as intended. So there is a trade off here. If you want extreme ad free browsing, be prepared to deal with more "problem" sites, and to spend more time adjusting the configuration to solve these unintended consequences. In short, there is not an easy way to eliminate all ads. Either take the easy way and settle for most ads blocked with the default configuration, or jump in and tweak it for your personal surfing habits and preferences.

    Secondly, a brief explanation of Privoxy's "actions". "Actions" in this context, are the directives we use to tell Privoxy to perform some task relating to HTTP transactions (i.e. web browsing). We tell Privoxy to take some "action". Each action has a unique name and function. While there are many potential actions in Privoxy's arsenal, only a few are used for ad blocking. Actions, and action configuration files, are explained in depth below.

    Actions are specified in Privoxy's configuration, followed by one or more URLs to which the action should apply. URLs can actually be URL type patterns that use wildcards so they can apply potentially to a range of similar URLs. The actions, together with the URL patterns are called a section.

    When you connect to a website, the full URL will either match one or more of the sections as defined in Privoxy's configuration, or not. If so, then Privoxy will perform the respective actions. If not, then nothing special happens. Furthermore, web pages may contain embedded, secondary URLs that your web browser will use to load additional components of the page, as it parses the original page's HTML content. An ad image for instance, is just an URL embedded in the page somewhere. The image itself may be on the same server, or a server somewhere else on the Internet. Complex web pages will have many such embedded URLs. Privoxy can deal with each URL individually, so, for instance, the main page text is not touched, but images from such-and-such server are blocked.

    The most important actions for basic ad blocking are: block, handle-as-image, handle-as-empty-document,and set-image-blocker:

    • block - this is perhaps the single most used action, and is particularly important for ad blocking. This action stops any contact between your browser and any URL patterns that match this action's configuration. It can be used for blocking ads, but also anything that is determined to be unwanted. By itself, it simply stops any communication with the remote server and sends Privoxy's own built-in BLOCKED page instead to let you now what has happened (with some exceptions, see below).

    • handle-as-image - tells Privoxy to treat this URL as an image. Privoxy's default configuration already does this for all common image types (e.g. GIF), but there are many situations where this is not so easy to determine. So we'll force it in these cases. This is particularly important for ad blocking, since only if we know that it's an image of some kind, can we replace it with an image of our choosing, instead of the Privoxy BLOCKED page (which would only result in a "broken image" icon). There are some limitations to this though. For instance, you can't just brute-force an image substitution for an entire HTML page in most situations.

    • handle-as-empty-document - sends an empty document instead of Privoxy's normal BLOCKED HTML page. This is useful for file types that are neither HTML nor images, such as blocking JavaScript files.

    • set-image-blocker - tells Privoxy what to display in place of an ad image that has hit a block rule. For this to come into play, the URL must match a block action somewhere in the configuration, and, it must also match an handle-as-image action.

      The configuration options on what to display instead of the ad are:

         pattern - a checkerboard pattern, so that an ad replacement is obvious. This is the default.
         blank - A very small empty GIF image is displayed. This is the so-called "invisible" configuration option.
         http://<URL> - A redirect to any image anywhere of the user's choosing (advanced usage).

    Advanced users will eventually want to explore Privoxy filters as well. Filters are very different from blocks. A "block" blocks a site, page, or unwanted contented. Filters are a way of filtering or modifying what is actually on the page. An example filter usage: a text replacement of "no-no" for "nasty-word". That is a very simple example. This process can be used for ad blocking, but it is more in the realm of advanced usage and has some pitfalls to be wary off.

    The quickest way to adjust any of these settings is with your browser through the special Privoxy editor at http://config.privoxy.org/show-status (shortcut: http://p.p/show-status). This is an internal page, and does not require Internet access.

    Note that as of Privoxy 3.0.7 beta the action editor is disabled by default. Check the enable-edit-actions section in the configuration file to learn why and in which cases it's safe to enable again.

    If you decided to enable the action editor, select the appropriate "actions" file, and click "Edit". It is best to put personal or local preferences in user.action since this is not meant to be overwritten during upgrades, and will over-ride the settings in other files. Here you can insert new "actions", and URLs for ad blocking or other purposes, and make other adjustments to the configuration. Privoxy will detect these changes automatically.

    A quick and simple step by step example:

    • Right click on the ad image to be blocked, then select "Copy Link Location" from the pop-up menu.

    • Set your browser to http://config.privoxy.org/show-status

    • Find user.action in the top section, and click on "Edit":

      Figure 1. Actions Files in Use

    • You should have a section with only block listed under "Actions:". If not, click a "Insert new section below" button, and in the new section that just appeared, click the Edit button right under the word "Actions:". This will bring up a list of all actions. Find block near the top, and click in the "Enabled" column, then "Submit" just below the list.

    • Now, in the block actions section, click the "Add" button, and paste the URL the browser got from "Copy Link Location". Remove the http:// at the beginning of the URL. Then, click "Submit" (or "OK" if in a pop-up window).

    • Now go back to the original page, and press SHIFT-Reload (or flush all browser caches). The image should be gone now.

    This is a very crude and simple example. There might be good reasons to use a wildcard pattern match to include potentially similar images from the same site. For a more extensive explanation of "patterns", and the entire actions concept, see the Actions section.

    For advanced users who want to hand edit their config files, you might want to now go to the Actions Files Tutorial. The ideas explained therein also apply to the web-based editor.

    There are also various filters that can be used for ad blocking (filters are a special subset of actions). These fall into the "advanced" usage category, and are explained in depth in later sections.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/config.html000640 001751 001751 00000340031 12116120072 023110 0ustar00fkfk000000 000000 The Main Configuration File

    7. The Main Configuration File

    By default, the main configuration file is named config, with the exception of Windows, where it is named config.txt. Configuration lines consist of an initial keyword followed by a list of values, all separated by whitespace (any number of spaces or tabs). For example:

      confdir /etc/privoxy

    Assigns the value /etc/privoxy to the option confdir and thus indicates that the configuration directory is named "/etc/privoxy/".

    All options in the config file except for confdir and logdir are optional. Watch out in the below description for what happens if you leave them unset.

    The main config file controls all aspects of Privoxy's operation that are not location dependent (i.e. they apply universally, no matter where you may be surfing). Like the filter and action files, the config file is a plain text file and can be modified with a text editor like emacs, vim or notepad.exe.

    7.1. Local Set-up Documentation

    If you intend to operate Privoxy for more users than just yourself, it might be a good idea to let them know how to reach you, what you block and why you do that, your policies, etc.

    7.1.1. user-manual

    Specifies:

    Location of the Privoxy User Manual.

    Type of value:

    A fully qualified URI

    Default value:

    Unset

    Effect if unset:

    http://www.privoxy.org/version/user-manual/ will be used, where version is the Privoxy version.

    Notes:

    The User Manual URI is the single best source of information on Privoxy, and is used for help links from some of the internal CGI pages. The manual itself is normally packaged with the binary distributions, so you probably want to set this to a locally installed copy.

    Examples:

    The best all purpose solution is simply to put the full local PATH to where the User Manual is located:

      user-manual  /usr/share/doc/privoxy/user-manual
    

    The User Manual is then available to anyone with access to Privoxy, by following the built-in URL: http://config.privoxy.org/user-manual/ (or the shortcut: http://p.p/user-manual/).

    If the documentation is not on the local system, it can be accessed from a remote server, as:

      user-manual  http://example.com/privoxy/user-manual/
    
    Warning

    If set, this option should be the first option in the config file, because it is used while the config file is being read on start-up.

    7.1.2. trust-info-url

    Specifies:

    A URL to be displayed in the error page that users will see if access to an untrusted page is denied.

    Type of value:

    URL

    Default value:

    Unset

    Effect if unset:

    No links are displayed on the "untrusted" error page.

    Notes:

    The value of this option only matters if the experimental trust mechanism has been activated. (See trustfile below.)

    If you use the trust mechanism, it is a good idea to write up some on-line documentation about your trust policy and to specify the URL(s) here. Use multiple times for multiple URLs.

    The URL(s) should be added to the trustfile as well, so users don't end up locked out from the information on why they were locked out in the first place!

    7.1.3. admin-address

    Specifies:

    An email address to reach the Privoxy administrator.

    Type of value:

    Email address

    Default value:

    Unset

    Effect if unset:

    No email address is displayed on error pages and the CGI user interface.

    Notes:

    If both admin-address and proxy-info-url are unset, the whole "Local Privoxy Support" box on all generated pages will not be shown.

    7.1.4. proxy-info-url

    Specifies:

    A URL to documentation about the local Privoxy setup, configuration or policies.

    Type of value:

    URL

    Default value:

    Unset

    Effect if unset:

    No link to local documentation is displayed on error pages and the CGI user interface.

    Notes:

    If both admin-address and proxy-info-url are unset, the whole "Local Privoxy Support" box on all generated pages will not be shown.

    This URL shouldn't be blocked ;-)

    7.2. Configuration and Log File Locations

    Privoxy can (and normally does) use a number of other files for additional configuration, help and logging. This section of the configuration file tells Privoxy where to find those other files.

    The user running Privoxy, must have read permission for all configuration files, and write permission to any files that would be modified, such as log files and actions files.

    7.2.1. confdir

    Specifies:

    The directory where the other configuration files are located.

    Type of value:

    Path name

    Default value:

    /etc/privoxy (Unix) or Privoxy installation dir (Windows)

    Effect if unset:

    Mandatory

    Notes:

    No trailing "/", please.

    7.2.2. templdir

    Specifies:

    An alternative directory where the templates are loaded from.

    Type of value:

    Path name

    Default value:

    unset

    Effect if unset:

    The templates are assumed to be located in confdir/template.

    Notes:

    Privoxy's original templates are usually overwritten with each update. Use this option to relocate customized templates that should be kept. As template variables might change between updates, you shouldn't expect templates to work with Privoxy releases other than the one they were part of, though.

    7.2.3. logdir

    Specifies:

    The directory where all logging takes place (i.e. where the logfile is located).

    Type of value:

    Path name

    Default value:

    /var/log/privoxy (Unix) or Privoxy installation dir (Windows)

    Effect if unset:

    Mandatory

    Notes:

    No trailing "/", please.

    7.2.4. actionsfile

    Specifies:

    The actions file(s) to use

    Type of value:

    Complete file name, relative to confdir

    Default values:

      match-all.action # Actions that are applied to all sites and maybe overruled later on.

      default.action   # Main actions file

      user.action      # User customizations

    Effect if unset:

    No actions are taken at all. More or less neutral proxying.

    Notes:

    Multiple actionsfile lines are permitted, and are in fact recommended!

    The default values are default.action, which is the "main" actions file maintained by the developers, and user.action, where you can make your personal additions.

    Actions files contain all the per site and per URL configuration for ad blocking, cookie management, privacy considerations, etc. There is no point in using Privoxy without at least one actions file.

    Note that since Privoxy 3.0.7, the complete filename, including the ".action" extension has to be specified. The syntax change was necessary to be consistent with the other file options and to allow previously forbidden characters.

    7.2.5. filterfile

    Specifies:

    The filter file(s) to use

    Type of value:

    File name, relative to confdir

    Default value:

    default.filter (Unix) or default.filter.txt (Windows)

    Effect if unset:

    No textual content filtering takes place, i.e. all +filter{name} actions in the actions files are turned neutral.

    Notes:

    Multiple filterfile lines are permitted.

    The filter files contain content modification rules that use regular expressions. These rules permit powerful changes on the content of Web pages, and optionally the headers as well, e.g., you could try to disable your favorite JavaScript annoyances, re-write the actual displayed text, or just have some fun playing buzzword bingo with web pages.

    The +filter{name} actions rely on the relevant filter (name) to be defined in a filter file!

    A pre-defined filter file called default.filter that contains a number of useful filters for common problems is included in the distribution. See the section on the filter action for a list.

    It is recommended to place any locally adapted filters into a separate file, such as user.filter.

    7.2.6. logfile

    Specifies:

    The log file to use

    Type of value:

    File name, relative to logdir

    Default value:

    Unset (commented out). When activated: logfile (Unix) or privoxy.log (Windows).

    Effect if unset:

    No logfile is written.

    Notes:

    The logfile is where all logging and error messages are written. The level of detail and number of messages are set with the debug option (see below). The logfile can be useful for tracking down a problem with Privoxy (e.g., it's not blocking an ad you think it should block) and it can help you to monitor what your browser is doing.

    Depending on the debug options below, the logfile may be a privacy risk if third parties can get access to it. As most users will never look at it, Privoxy 3.0.7 and later only log fatal errors by default.

    For most troubleshooting purposes, you will have to change that, please refer to the debugging section for details.

    Your logfile will grow indefinitely, and you will probably want to periodically remove it. On Unix systems, you can do this with a cron job (see "man cron").

    Any log files must be writable by whatever user Privoxy is being run as (on Unix, default user id is "privoxy").

    7.2.7. trustfile

    Specifies:

    The name of the trust file to use

    Type of value:

    File name, relative to confdir

    Default value:

    Unset (commented out). When activated: trust (Unix) or trust.txt (Windows)

    Effect if unset:

    The entire trust mechanism is disabled.

    Notes:

    The trust mechanism is an experimental feature for building white-lists and should be used with care. It is NOT recommended for the casual user.

    If you specify a trust file, Privoxy will only allow access to sites that are specified in the trustfile. Sites can be listed in one of two ways:

    Prepending a ~ character limits access to this site only (and any sub-paths within this site), e.g. ~www.example.com allows access to ~www.example.com/features/news.html, etc.

    Or, you can designate sites as trusted referrers, by prepending the name with a + character. The effect is that access to untrusted sites will be granted -- but only if a link from this trusted referrer was used to get there. The link target will then be added to the "trustfile" so that future, direct accesses will be granted. Sites added via this mechanism do not become trusted referrers themselves (i.e. they are added with a ~ designation). There is a limit of 512 such entries, after which new entries will not be made.

    If you use the + operator in the trust file, it may grow considerably over time.

    It is recommended that Privoxy be compiled with the --disable-force, --disable-toggle and --disable-editor options, if this feature is to be used.

    Possible applications include limiting Internet access for children.

    7.3. Debugging

    These options are mainly useful when tracing a problem. Note that you might also want to invoke Privoxy with the --no-daemon command line option when debugging.

    7.3.1. debug

    Specifies:

    Key values that determine what information gets logged.

    Type of value:

    Integer values

    Default value:

    0 (i.e.: only fatal errors (that cause Privoxy to exit) are logged)

    Effect if unset:

    Default value is used (see above).

    Notes:

    The available debug levels are:

      debug     1 # Log the destination for each request Privoxy let through. See also debug 1024.
      debug     2 # show each connection status
      debug     4 # show I/O status
      debug     8 # show header parsing
      debug    16 # log all data written to the network
      debug    32 # debug force feature
      debug    64 # debug regular expression filters
      debug   128 # debug redirects
      debug   256 # debug GIF de-animation
      debug   512 # Common Log Format
      debug  1024 # Log the destination for requests Privoxy didn't let through, and the reason why.
      debug  2048 # CGI user interface
      debug  4096 # Startup banner and warnings.
      debug  8192 # Non-fatal errors
      debug 32768 # log all data read from the network
      debug 65536 # Log the applying actions
    

    To select multiple debug levels, you can either add them or use multiple debug lines.

    A debug level of 1 is informative because it will show you each request as it happens. 1, 1024, 4096 and 8192 are recommended so that you will notice when things go wrong. The other levels are probably only of interest if you are hunting down a specific problem. They can produce a hell of an output (especially 16).

    Privoxy used to ship with the debug levels recommended above enabled by default, but due to privacy concerns 3.0.7 and later are configured to only log fatal errors.

    If you are used to the more verbose settings, simply enable the debug lines below again.

    If you want to use pure CLF (Common Log Format), you should set "debug 512" ONLY and not enable anything else.

    Privoxy has a hard-coded limit for the length of log messages. If it's reached, messages are logged truncated and marked with "... [too long, truncated]".

    Please don't file any support requests without trying to reproduce the problem with increased debug level first. Once you read the log messages, you may even be able to solve the problem on your own.

    7.3.2. single-threaded

    Specifies:

    Whether to run only one server thread.

    Type of value:

    None

    Default value:

    Unset

    Effect if unset:

    Multi-threaded (or, where unavailable: forked) operation, i.e. the ability to serve multiple requests simultaneously.

    Notes:

    This option is only there for debugging purposes. It will drastically reduce performance.

    7.3.3. hostname

    Specifies:

    The hostname shown on the CGI pages.

    Type of value:

    Text

    Default value:

    Unset

    Effect if unset:

    The hostname provided by the operating system is used.

    Notes:

    On some misconfigured systems resolving the hostname fails or takes too much time and slows Privoxy down. Setting a fixed hostname works around the problem.

    In other circumstances it might be desirable to show a hostname other than the one returned by the operating system. For example if the system has several different hostnames and you don't want to use the first one.

    Note that Privoxy does not validate the specified hostname value.

    7.4. Access Control and Security

    This section of the config file controls the security-relevant aspects of Privoxy's configuration.

    7.4.1. listen-address

    Specifies:

    The address and TCP port on which Privoxy will listen for client requests.

    Type of value:

    [IP-Address]:Port

    [Hostname]:Port

    Default value:

    127.0.0.1:8118

    Effect if unset:

    Bind to 127.0.0.1 (IPv4 localhost), port 8118. This is suitable and recommended for home users who run Privoxy on the same machine as their browser.

    Notes:

    You will need to configure your browser(s) to this proxy address and port.

    If you already have another service running on port 8118, or if you want to serve requests from other machines (e.g. on your local network) as well, you will need to override the default.

    You can use this statement multiple times to make Privoxy listen on more ports or more IP addresses. Suitable if your operating system does not support sharing IPv6 and IPv4 protocols on the same socket.

    If a hostname is used instead of an IP address, Privoxy will try to resolve it to an IP address and if there are multiple, use the first one returned.

    If the address for the hostname isn't already known on the system (for example because it's in /etc/hostname), this may result in DNS traffic.

    If the specified address isn't available on the system, or if the hostname can't be resolved, Privoxy will fail to start.

    IPv6 addresses containing colons have to be quoted by brackets. They can only be used if Privoxy has been compiled with IPv6 support. If you aren't sure if your version supports it, have a look at http://config.privoxy.org/show-status.

    Some operating systems will prefer IPv6 to IPv4 addresses even if the system has no IPv6 connectivity which is usually not expected by the user. Some even rely on DNS to resolve localhost which mean the "localhost" address used may not actually be local.

    It is therefore recommended to explicitly configure the intended IP address instead of relying on the operating system, unless there's a strong reason not to.

    If you leave out the address, Privoxy will bind to all IPv4 interfaces (addresses) on your machine and may become reachable from the Internet and/or the local network. Be aware that some GNU/Linux distributions modify that behaviour without updating the documentation. Check for non-standard patches if your Privoxy version behaves differently.

    If you configure Privoxy to be reachable from the network, consider using access control lists (ACL's, see below), and/or a firewall.

    If you open Privoxy to untrusted users, you will also want to make sure that the following actions are disabled: enable-edit-actions and enable-remote-toggle

    Example:

    Suppose you are running Privoxy on a machine which has the address 192.168.0.1 on your local private network (192.168.0.0) and has another outside connection with a different address. You want it to serve requests from inside only:

      listen-address  192.168.0.1:8118
    

    Suppose you are running Privoxy on an IPv6-capable machine and you want it to listen on the IPv6 address of the loopback device:

      listen-address [::1]:8118
    

    7.4.2. toggle

    Specifies:

    Initial state of "toggle" status

    Type of value:

    1 or 0

    Default value:

    1

    Effect if unset:

    Act as if toggled on

    Notes:

    If set to 0, Privoxy will start in "toggled off" mode, i.e. mostly behave like a normal, content-neutral proxy with both ad blocking and content filtering disabled. See enable-remote-toggle below.

    7.4.3. enable-remote-toggle

    Specifies:

    Whether or not the web-based toggle feature may be used

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    The web-based toggle feature is disabled.

    Notes:

    When toggled off, Privoxy mostly acts like a normal, content-neutral proxy, i.e. doesn't block ads or filter content.

    Access to the toggle feature can not be controlled separately by "ACLs" or HTTP authentication, so that everybody who can access Privoxy (see "ACLs" and listen-address above) can toggle it for all users. So this option is not recommended for multi-user environments with untrusted users.

    Note that malicious client side code (e.g Java) is also capable of using this option.

    As a lot of Privoxy users don't read documentation, this feature is disabled by default.

    Note that you must have compiled Privoxy with support for this feature, otherwise this option has no effect.

    7.4.4. enable-remote-http-toggle

    Specifies:

    Whether or not Privoxy recognizes special HTTP headers to change its behaviour.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Privoxy ignores special HTTP headers.

    Notes:

    When toggled on, the client can change Privoxy's behaviour by setting special HTTP headers. Currently the only supported special header is "X-Filter: No", to disable filtering for the ongoing request, even if it is enabled in one of the action files.

    This feature is disabled by default. If you are using Privoxy in a environment with trusted clients, you may enable this feature at your discretion. Note that malicious client side code (e.g Java) is also capable of using this feature.

    This option will be removed in future releases as it has been obsoleted by the more general header taggers.

    7.4.5. enable-edit-actions

    Specifies:

    Whether or not the web-based actions file editor may be used

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    The web-based actions file editor is disabled.

    Notes:

    Access to the editor can not be controlled separately by "ACLs" or HTTP authentication, so that everybody who can access Privoxy (see "ACLs" and listen-address above) can modify its configuration for all users.

    This option is not recommended for environments with untrusted users and as a lot of Privoxy users don't read documentation, this feature is disabled by default.

    Note that malicious client side code (e.g Java) is also capable of using the actions editor and you shouldn't enable this options unless you understand the consequences and are sure your browser is configured correctly.

    Note that you must have compiled Privoxy with support for this feature, otherwise this option has no effect.

    7.4.6. enforce-blocks

    Specifies:

    Whether the user is allowed to ignore blocks and can "go there anyway".

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Blocks are not enforced.

    Notes:

    Privoxy is mainly used to block and filter requests as a service to the user, for example to block ads and other junk that clogs the pipes. Privoxy's configuration isn't perfect and sometimes innocent pages are blocked. In this situation it makes sense to allow the user to enforce the request and have Privoxy ignore the block.

    In the default configuration Privoxy's "Blocked" page contains a "go there anyway" link to adds a special string (the force prefix) to the request URL. If that link is used, Privoxy will detect the force prefix, remove it again and let the request pass.

    Of course Privoxy can also be used to enforce a network policy. In that case the user obviously should not be able to bypass any blocks, and that's what the "enforce-blocks" option is for. If it's enabled, Privoxy hides the "go there anyway" link. If the user adds the force prefix by hand, it will not be accepted and the circumvention attempt is logged.

    Examples:

    enforce-blocks 1

    7.4.7. ACLs: permit-access and deny-access

    Specifies:

    Who can access what.

    Type of value:

    src_addr[:port][/src_masklen] [dst_addr[:port][/dst_masklen]]

    Where src_addr and dst_addr are IPv4 addresses in dotted decimal notation or valid DNS names, port is a port number, and src_masklen and dst_masklen are subnet masks in CIDR notation, i.e. integer values from 2 to 30 representing the length (in bits) of the network address. The masks and the whole destination part are optional.

    If your system implements RFC 3493, then src_addr and dst_addr can be IPv6 addresses delimeted by brackets, port can be a number or a service name, and src_masklen and dst_masklen can be a number from 0 to 128.

    Default value:

    Unset

    If no port is specified, any port will match. If no src_masklen or src_masklen is given, the complete IP address has to match (i.e. 32 bits for IPv4 and 128 bits for IPv6).

    Effect if unset:

    Don't restrict access further than implied by listen-address

    Notes:

    Access controls are included at the request of ISPs and systems administrators, and are not usually needed by individual users. For a typical home user, it will normally suffice to ensure that Privoxy only listens on the localhost (127.0.0.1) or internal (home) network address by means of the listen-address option.

    Please see the warnings in the FAQ that Privoxy is not intended to be a substitute for a firewall or to encourage anyone to defer addressing basic security weaknesses.

    Multiple ACL lines are OK. If any ACLs are specified, Privoxy only talks to IP addresses that match at least one permit-access line and don't match any subsequent deny-access line. In other words, the last match wins, with the default being deny-access.

    If Privoxy is using a forwarder (see forward below) for a particular destination URL, the dst_addr that is examined is the address of the forwarder and NOT the address of the ultimate target. This is necessary because it may be impossible for the local Privoxy to determine the IP address of the ultimate target (that's often what gateways are used for).

    You should prefer using IP addresses over DNS names, because the address lookups take time. All DNS names must resolve! You can not use domain patterns like "*.org" or partial domain names. If a DNS name resolves to multiple IP addresses, only the first one is used.

    Some systems allow IPv4 clients to connect to IPv6 server sockets. Then the client's IPv4 address will be translated by the system into IPv6 address space with special prefix ::ffff:0:0/96 (so called IPv4 mapped IPv6 address). Privoxy can handle it and maps such ACL addresses automatically.

    Denying access to particular sites by ACL may have undesired side effects if the site in question is hosted on a machine which also hosts other sites (most sites are).

    Examples:

    Explicitly define the default behavior if no ACL and listen-address are set: "localhost" is OK. The absence of a dst_addr implies that all destination addresses are OK:

      permit-access  localhost
    

    Allow any host on the same class C subnet as www.privoxy.org access to nothing but www.example.com (or other domains hosted on the same system):

      permit-access  www.privoxy.org/24 www.example.com/32
    

    Allow access from any host on the 26-bit subnet 192.168.45.64 to anywhere, with the exception that 192.168.45.73 may not access the IP address behind www.dirty-stuff.example.com:

      permit-access  192.168.45.64/26
      deny-access    192.168.45.73    www.dirty-stuff.example.com
    

    Allow access from the IPv4 network 192.0.2.0/24 even if listening on an IPv6 wild card address (not supported on all platforms):

      permit-access  192.0.2.0/24
    

    This is equivalent to the following line even if listening on an IPv4 address (not supported on all platforms):

      permit-access  [::ffff:192.0.2.0]/120
    

    7.4.8. buffer-limit

    Specifies:

    Maximum size of the buffer for content filtering.

    Type of value:

    Size in Kbytes

    Default value:

    4096

    Effect if unset:

    Use a 4MB (4096 KB) limit.

    Notes:

    For content filtering, i.e. the +filter and +deanimate-gif actions, it is necessary that Privoxy buffers the entire document body. This can be potentially dangerous, since a server could just keep sending data indefinitely and wait for your RAM to exhaust -- with nasty consequences. Hence this option.

    When a document buffer size reaches the buffer-limit, it is flushed to the client unfiltered and no further attempt to filter the rest of the document is made. Remember that there may be multiple threads running, which might require up to buffer-limit Kbytes each, unless you have enabled "single-threaded" above.

    7.4.9. enable-proxy-authentication-forwarding

    Specifies:

    Whether or not proxy authentication through Privoxy should work.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Proxy authentication headers are removed.

    Notes:

    Privoxy itself does not support proxy authentication, but can allow clients to authenticate against Privoxy's parent proxy.

    By default Privoxy (3.0.21 and later) don't do that and remove Proxy-Authorization headers in requests and Proxy-Authenticate headers in responses to make it harder for malicious sites to trick inexperienced users into providing login information.

    If this option is enabled the headers are forwarded.

    Enabling this option is not recommended if there is no parent proxy that requires authentication or if the local network between Privoxy and the parent proxy isn't trustworthy. If proxy authentication is only required for some requests, it is recommended to use a client header filter to remove the authentication headers for requests where they aren't needed.

    7.5. Forwarding

    This feature allows routing of HTTP requests through a chain of multiple proxies.

    Forwarding can be used to chain Privoxy with a caching proxy to speed up browsing. Using a parent proxy may also be necessary if the machine that Privoxy runs on has no direct Internet access.

    Note that parent proxies can severely decrease your privacy level. For example a parent proxy could add your IP address to the request headers and if it's a caching proxy it may add the "Etag" header to revalidation requests again, even though you configured Privoxy to remove it. It may also ignore Privoxy's header time randomization and use the original values which could be used by the server as cookie replacement to track your steps between visits.

    Also specified here are SOCKS proxies. Privoxy supports the SOCKS 4 and SOCKS 4A protocols.

    7.5.1. forward

    Specifies:

    To which parent HTTP proxy specific requests should be routed.

    Type of value:

    target_pattern http_parent[:port]

    where target_pattern is a URL pattern that specifies to which requests (i.e. URLs) this forward rule shall apply. Use / to denote "all URLs". http_parent[:port] is the DNS name or IP address of the parent HTTP proxy through which the requests should be forwarded, optionally followed by its listening port (default: 8000). Use a single dot (.) to denote "no forwarding".

    Default value:

    Unset

    Effect if unset:

    Don't use parent HTTP proxies.

    Notes:

    If http_parent is ".", then requests are not forwarded to another HTTP proxy but are made directly to the web servers.

    http_parent can be a numerical IPv6 address (if RFC 3493 is implemented). To prevent clashes with the port delimiter, the whole IP address has to be put into brackets. On the other hand a target_pattern containing an IPv6 address has to be put into angle brackets (normal brackets are reserved for regular expressions already).

    Multiple lines are OK, they are checked in sequence, and the last match wins.

    Examples:

    Everything goes to an example parent proxy, except SSL on port 443 (which it doesn't handle):

      forward   /      parent-proxy.example.org:8080
      forward   :443   .
    

    Everything goes to our example ISP's caching proxy, except for requests to that ISP's sites:

      forward   /                  caching-proxy.isp.example.net:8000
      forward   .isp.example.net   .
    

    Parent proxy specified by an IPv6 address:

      forward   /                   [2001:DB8::1]:8000
    

    Suppose your parent proxy doesn't support IPv6:

      forward  /                        parent-proxy.example.org:8000
      forward  ipv6-server.example.org  .
      forward  <[2-3][0-9a-f][0-9a-f][0-9a-f]:*>   .
    

    7.5.2. forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t

    Specifies:

    Through which SOCKS proxy (and optionally to which parent HTTP proxy) specific requests should be routed.

    Type of value:

    target_pattern socks_proxy[:port] http_parent[:port]

    where target_pattern is a URL pattern that specifies to which requests (i.e. URLs) this forward rule shall apply. Use / to denote "all URLs". http_parent and socks_proxy are IP addresses in dotted decimal notation or valid DNS names (http_parent may be "." to denote "no HTTP forwarding"), and the optional port parameters are TCP ports, i.e. integer values from 1 to 65535

    Default value:

    Unset

    Effect if unset:

    Don't use SOCKS proxies.

    Notes:

    Multiple lines are OK, they are checked in sequence, and the last match wins.

    The difference between forward-socks4 and forward-socks4a is that in the SOCKS 4A protocol, the DNS resolution of the target hostname happens on the SOCKS server, while in SOCKS 4 it happens locally.

    With forward-socks5 the DNS resolution will happen on the remote server as well.

    forward-socks5t works like vanilla forward-socks5 but lets Privoxy additionally use Tor-specific SOCKS extensions. Currently the only supported SOCKS extension is optimistic data which can reduce the latency for the first request made on a newly created connection.

    socks_proxy and http_parent can be a numerical IPv6 address (if RFC 3493 is implemented). To prevent clashes with the port delimiter, the whole IP address has to be put into brackets. On the other hand a target_pattern containing an IPv6 address has to be put into angle brackets (normal brackets are reserved for regular expressions already).

    If http_parent is ".", then requests are not forwarded to another HTTP proxy but are made (HTTP-wise) directly to the web servers, albeit through a SOCKS proxy.

    Examples:

    From the company example.com, direct connections are made to all "internal" domains, but everything outbound goes through their ISP's proxy by way of example.com's corporate SOCKS 4A gateway to the Internet.

      forward-socks4a   /              socks-gw.example.com:1080  www-cache.isp.example.net:8080
      forward           .example.com   .
    

    A rule that uses a SOCKS 4 gateway for all destinations but no HTTP parent looks like this:

      forward-socks4   /               socks-gw.example.com:1080  .
    

    To chain Privoxy and Tor, both running on the same system, you would use something like:

      forward-socks5   /               127.0.0.1:9050 .
    

    The public Tor network can't be used to reach your local network, if you need to access local servers you therefore might want to make some exceptions:

      forward         192.168.*.*/     .
      forward            10.*.*.*/     .
      forward           127.*.*.*/     .
    

    Unencrypted connections to systems in these address ranges will be as (un)secure as the local network is, but the alternative is that you can't reach the local network through Privoxy at all. Of course this may actually be desired and there is no reason to make these exceptions if you aren't sure you need them.

    If you also want to be able to reach servers in your local network by using their names, you will need additional exceptions that look like this:

     forward           localhost/     .
    

    7.5.3. Advanced Forwarding Examples

    If you have links to multiple ISPs that provide various special content only to their subscribers, you can configure multiple Privoxies which have connections to the respective ISPs to act as forwarders to each other, so that your users can see the internal content of all ISPs.

    Assume that host-a has a PPP connection to isp-a.example.net. And host-b has a PPP connection to isp-b.example.org. Both run Privoxy. Their forwarding configuration can look like this:

    host-a:

      forward    /           .
      forward    .isp-b.example.net  host-b:8118
    

    host-b:

      forward    /           .
      forward    .isp-a.example.org  host-a:8118
    

    Now, your users can set their browser's proxy to use either host-a or host-b and be able to browse the internal content of both isp-a and isp-b.

    If you intend to chain Privoxy and squid locally, then chaining as browser -> squid -> privoxy is the recommended way.

    Assuming that Privoxy and squid run on the same box, your squid configuration could then look like this:

      # Define Privoxy as parent proxy (without ICP)
      cache_peer 127.0.0.1 parent 8118 7 no-query
    
      # Define ACL for protocol FTP
      acl ftp proto FTP
    
      # Do not forward FTP requests to Privoxy
      always_direct allow ftp
    
      # Forward all the rest to Privoxy
      never_direct allow all
    

    You would then need to change your browser's proxy settings to squid's address and port. Squid normally uses port 3128. If unsure consult http_port in squid.conf.

    You could just as well decide to only forward requests you suspect of leading to Windows executables through a virus-scanning parent proxy, say, on antivir.example.com, port 8010:

      forward   /                          .
      forward   /.*\.(exe|com|dll|zip)$    antivir.example.com:8010
    

    7.5.4. forwarded-connect-retries

    Specifies:

    How often Privoxy retries if a forwarded connection request fails.

    Type of value:

    Number of retries.

    Default value:

    0

    Effect if unset:

    Connections forwarded through other proxies are treated like direct connections and no retry attempts are made.

    Notes:

    forwarded-connect-retries is mainly interesting for socks4a connections, where Privoxy can't detect why the connections failed. The connection might have failed because of a DNS timeout in which case a retry makes sense, but it might also have failed because the server doesn't exist or isn't reachable. In this case the retry will just delay the appearance of Privoxy's error message.

    Note that in the context of this option, "forwarded connections" includes all connections that Privoxy forwards through other proxies. This option is not limited to the HTTP CONNECT method.

    Only use this option, if you are getting lots of forwarding-related error messages that go away when you try again manually. Start with a small value and check Privoxy's logfile from time to time, to see how many retries are usually needed.

    Examples:

    forwarded-connect-retries 1

    7.6. Miscellaneous

    7.6.1. accept-intercepted-requests

    Specifies:

    Whether intercepted requests should be treated as valid.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Only proxy requests are accepted, intercepted requests are treated as invalid.

    Notes:

    If you don't trust your clients and want to force them to use Privoxy, enable this option and configure your packet filter to redirect outgoing HTTP connections into Privoxy.

    Make sure that Privoxy's own requests aren't redirected as well. Additionally take care that Privoxy can't intentionally connect to itself, otherwise you could run into redirection loops if Privoxy's listening port is reachable by the outside or an attacker has access to the pages you visit.

    Examples:

    accept-intercepted-requests 1

    7.6.2. allow-cgi-request-crunching

    Specifies:

    Whether requests to Privoxy's CGI pages can be blocked or redirected.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Privoxy ignores block and redirect actions for its CGI pages.

    Notes:

    By default Privoxy ignores block or redirect actions for its CGI pages. Intercepting these requests can be useful in multi-user setups to implement fine-grained access control, but it can also render the complete web interface useless and make debugging problems painful if done without care.

    Don't enable this option unless you're sure that you really need it.

    Examples:

    allow-cgi-request-crunching 1

    7.6.3. split-large-forms

    Specifies:

    Whether the CGI interface should stay compatible with broken HTTP clients.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    The CGI form generate long GET URLs.

    Notes:

    Privoxy's CGI forms can lead to rather long URLs. This isn't a problem as far as the HTTP standard is concerned, but it can confuse clients with arbitrary URL length limitations.

    Enabling split-large-forms causes Privoxy to divide big forms into smaller ones to keep the URL length down. It makes editing a lot less convenient and you can no longer submit all changes at once, but at least it works around this browser bug.

    If you don't notice any editing problems, there is no reason to enable this option, but if one of the submit buttons appears to be broken, you should give it a try.

    Examples:

    split-large-forms 1

    7.6.4. keep-alive-timeout

    Specifies:

    Number of seconds after which an open connection will no longer be reused.

    Type of value:

    Time in seconds.

    Default value:

    None

    Effect if unset:

    Connections are not kept alive.

    Notes:

    This option allows clients to keep the connection to Privoxy alive. If the server supports it, Privoxy will keep the connection to the server alive as well. Under certain circumstances this may result in speed-ups.

    By default, Privoxy will close the connection to the server if the client connection gets closed, or if the specified timeout has been reached without a new request coming in. This behaviour can be changed with the connection-sharing option.

    This option has no effect if Privoxy has been compiled without keep-alive support.

    Note that a timeout of five seconds as used in the default configuration file significantly decreases the number of connections that will be reused. The value is used because some browsers limit the number of connections they open to a single host and apply the same limit to proxies. This can result in a single website "grabbing" all the connections the browser allows, which means connections to other websites can't be opened until the connections currently in use time out.

    Several users have reported this as a Privoxy bug, so the default value has been reduced. Consider increasing it to 300 seconds or even more if you think your browser can handle it. If your browser appears to be hanging, it probably can't.

    Examples:

    keep-alive-timeout 300

    7.6.5. tolerate-pipelining

    Specifies:

    Whether or not pipelined requests should be served.

    Type of value:

    0 or 1.

    Default value:

    None

    Effect if unset:

    If Privoxy receives more than one request at once, it terminates the client connection after serving the first one.

    Notes:

    Privoxy currently doesn't pipeline outgoing requests, thus allowing pipelining on the client connection is not guaranteed to improve the performance.

    By default Privoxy tries to discourage clients from pipelining by discarding aggressively pipelined requests, which forces the client to resend them through a new connection.

    This option lets Privoxy tolerate pipelining. Whether or not that improves performance mainly depends on the client configuration.

    If you are seeing problems with pages not properly loading, disabling this option could work around the problem.

    Examples:

    tolerate-pipelining 1

    7.6.6. default-server-timeout

    Specifies:

    Assumed server-side keep-alive timeout if not specified by the server.

    Type of value:

    Time in seconds.

    Default value:

    None

    Effect if unset:

    Connections for which the server didn't specify the keep-alive timeout are not reused.

    Notes:

    Enabling this option significantly increases the number of connections that are reused, provided the keep-alive-timeout option is also enabled.

    While it also increases the number of connections problems when Privoxy tries to reuse a connection that already has been closed on the server side, or is closed while Privoxy is trying to reuse it, this should only be a problem if it happens for the first request sent by the client. If it happens for requests on reused client connections, Privoxy will simply close the connection and the client is supposed to retry the request without bothering the user.

    Enabling this option is therefore only recommended if the connection-sharing option is disabled.

    It is an error to specify a value larger than the keep-alive-timeout value.

    This option has no effect if Privoxy has been compiled without keep-alive support.

    Examples:

    default-server-timeout 60

    7.6.7. connection-sharing

    Specifies:

    Whether or not outgoing connections that have been kept alive should be shared between different incoming connections.

    Type of value:

    0 or 1

    Default value:

    None

    Effect if unset:

    Connections are not shared.

    Notes:

    This option has no effect if Privoxy has been compiled without keep-alive support, or if it's disabled.

    Notes:

    Note that reusing connections doesn't necessary cause speedups. There are also a few privacy implications you should be aware of.

    If this option is effective, outgoing connections are shared between clients (if there are more than one) and closing the browser that initiated the outgoing connection does no longer affect the connection between Privoxy and the server unless the client's request hasn't been completed yet.

    If the outgoing connection is idle, it will not be closed until either Privoxy's or the server's timeout is reached. While it's open, the server knows that the system running Privoxy is still there.

    If there are more than one client (maybe even belonging to multiple users), they will be able to reuse each others connections. This is potentially dangerous in case of authentication schemes like NTLM where only the connection is authenticated, instead of requiring authentication for each request.

    If there is only a single client, and if said client can keep connections alive on its own, enabling this option has next to no effect. If the client doesn't support connection keep-alive, enabling this option may make sense as it allows Privoxy to keep outgoing connections alive even if the client itself doesn't support it.

    You should also be aware that enabling this option increases the likelihood of getting the "No server or forwarder data" error message, especially if you are using a slow connection to the Internet.

    This option should only be used by experienced users who understand the risks and can weight them against the benefits.

    Examples:

    connection-sharing 1

    7.6.8. socket-timeout

    Specifies:

    Number of seconds after which a socket times out if no data is received.

    Type of value:

    Time in seconds.

    Default value:

    None

    Effect if unset:

    A default value of 300 seconds is used.

    Notes:

    The default is quite high and you probably want to reduce it. If you aren't using an occasionally slow proxy like Tor, reducing it to a few seconds should be fine.

    Examples:

    socket-timeout 300

    7.6.9. max-client-connections

    Specifies:

    Maximum number of client connections that will be served.

    Type of value:

    Positive number.

    Default value:

    128

    Effect if unset:

    Connections are served until a resource limit is reached.

    Notes:

    Privoxy creates one thread (or process) for every incoming client connection that isn't rejected based on the access control settings.

    If the system is powerful enough, Privoxy can theoretically deal with several hundred (or thousand) connections at the same time, but some operating systems enforce resource limits by shutting down offending processes and their default limits may be below the ones Privoxy would require under heavy load.

    Configuring Privoxy to enforce a connection limit below the thread or process limit used by the operating system makes sure this doesn't happen. Simply increasing the operating system's limit would work too, but if Privoxy isn't the only application running on the system, you may actually want to limit the resources used by Privoxy.

    If Privoxy is only used by a single trusted user, limiting the number of client connections is probably unnecessary. If there are multiple possibly untrusted users you probably still want to additionally use a packet filter to limit the maximal number of incoming connections per client. Otherwise a malicious user could intentionally create a high number of connections to prevent other users from using Privoxy.

    Obviously using this option only makes sense if you choose a limit below the one enforced by the operating system.

    One most POSIX-compliant systems Privoxy can't properly deal with more than FD_SETSIZE file descriptors at the same time and has to reject connections if the limit is reached. This will likely change in a future version, but currently this limit can't be increased without recompiling Privoxy with a different FD_SETSIZE limit.

    Examples:

    max-client-connections 256

    7.6.10. handle-as-empty-doc-returns-ok

    Specifies:

    The status code Privoxy returns for pages blocked with +handle-as-empty-document.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Privoxy returns a status 403(forbidden) for all blocked pages.

    Effect if set:

    Privoxy returns a status 200(OK) for pages blocked with +handle-as-empty-document and a status 403(Forbidden) for all other blocked pages.

    Notes:

    This is a work-around for Firefox bug 492459: " Websites are no longer rendered if SSL requests for JavaScripts are blocked by a proxy. " (https://bugzilla.mozilla.org/show_bug.cgi?id=492459) As the bug has been fixed for quite some time this option should no longer be needed and will be removed in a future release. Please speak up if you have a reason why the option should be kept around.

    7.6.11. enable-compression

    Specifies:

    Whether or not buffered content is compressed before delivery.

    Type of value:

    0 or 1

    Default value:

    0

    Effect if unset:

    Privoxy does not compress buffered content.

    Effect if set:

    Privoxy compresses buffered content before delivering it to the client, provided the client supports it.

    Notes:

    This directive is only supported if Privoxy has been compiled with FEATURE_COMPRESSION, which should not to be confused with FEATURE_ZLIB.

    Compressing buffered content is mainly useful if Privoxy and the client are running on different systems. If they are running on the same system, enabling compression is likely to slow things down. If you didn't measure otherwise, you should assume that it does and keep this option disabled.

    Privoxy will not compress buffered content below a certain length.

    7.6.12. compression-level

    Specifies:

    The compression level that is passed to the zlib library when compressing buffered content.

    Type of value:

    Positive number ranging from 0 to 9.

    Default value:

    1

    Notes:

    Compressing the data more takes usually longer than compressing it less or not compressing it at all. Which level is best depends on the connection between Privoxy and the client. If you can't be bothered to benchmark it for yourself, you should stick with the default and keep compression disabled.

    If compression is disabled, the compression level is irrelevant.

    Examples:
        # Best speed (compared to the other levels)
        compression-level 1
        # Best compression
        compression-level 9
        # No compression. Only useful for testing as the added header
        # slightly increases the amount of data that has to be sent.
        # If your benchmark shows that using this compression level
        # is superior to using no compression at all, the benchmark
        # is likely to be flawed.
        compression-level 0
    
    

    7.6.13. client-header-order

    Specifies:

    The order in which client headers are sorted before forwarding them.

    Type of value:

    Client header names delimited by spaces or tabs

    Default value:

    None

    Notes:

    By default Privoxy leaves the client headers in the order they were sent by the client. Headers are modified in-place, new headers are added at the end of the already existing headers.

    The header order can be used to fingerprint client requests independently of other headers like the User-Agent.

    This directive allows to sort the headers differently to better mimic a different User-Agent. Client headers will be emitted in the order given, headers whose name isn't explicitly specified are added at the end.

    Note that sorting headers in an uncommon way will make fingerprinting actually easier. Encrypted headers are not affected by this directive.

    7.7. Windows GUI Options

    Privoxy has a number of options specific to the Windows GUI interface:

    If "activity-animation" is set to 1, the Privoxy icon will animate when "Privoxy" is active. To turn off, set to 0.

      activity-animation 1
       

    If "log-messages" is set to 1, Privoxy copies log messages to the console window. The log detail depends on the debug directive.

      log-messages 1
       

    If "log-buffer-size" is set to 1, the size of the log buffer, i.e. the amount of memory used for the log messages displayed in the console window, will be limited to "log-max-lines" (see below).

    Warning: Setting this to 0 will result in the buffer to grow infinitely and eat up all your memory!

      log-buffer-size 1
       

    log-max-lines is the maximum number of lines held in the log buffer. See above.

      log-max-lines 200
       

    If "log-highlight-messages" is set to 1, Privoxy will highlight portions of the log messages with a bold-faced font:

      log-highlight-messages 1
       

    The font used in the console window:

      log-font-name Comic Sans MS
       

    Font size used in the console window:

      log-font-size 8
       

    "show-on-task-bar" controls whether or not Privoxy will appear as a button on the Task bar when minimized:

      show-on-task-bar 0
       

    If "close-button-minimizes" is set to 1, the Windows close button will minimize Privoxy instead of closing the program (close with the exit option on the File menu).

      close-button-minimizes 1
       

    The "hide-console" option is specific to the MS-Win console version of Privoxy. If this option is used, Privoxy will disconnect from and hide the command console.

      #hide-console
       

    privoxy-3.0.21-stable/./doc/webserver/user-manual/filter-file.html000640 001751 001751 00000111022 12116120072 024041 0ustar00fkfk000000 000000 Filter Files

    9. Filter Files

    On-the-fly text substitutions need to be defined in a "filter file". Once defined, they can then be invoked as an "action".

    Privoxy supports three different filter actions: filter to rewrite the content that is send to the client, client-header-filter to rewrite headers that are send by the client, and server-header-filter to rewrite headers that are send by the server.

    Privoxy also supports two tagger actions: client-header-tagger and server-header-tagger. Taggers and filters use the same syntax in the filter files, the difference is that taggers don't modify the text they are filtering, but use a rewritten version of the filtered text as tag. The tags can then be used to change the applying actions through sections with tag-patterns.

    Multiple filter files can be defined through the filterfile config directive. The filters as supplied by the developers are located in default.filter. It is recommended that any locally defined or modified filters go in a separately defined file such as user.filter.

    Common tasks for content filters are to eliminate common annoyances in HTML and JavaScript, such as pop-up windows, exit consoles, crippled windows without navigation tools, the infamous <BLINK> tag etc, to suppress images with certain width and height attributes (standard banner sizes or web-bugs), or just to have fun.

    Enabled content filters are applied to any content whose "Content Type" header is recognised as a sign of text-based content, with the exception of text/plain. Use the force-text-mode action to also filter other content.

    Substitutions are made at the source level, so if you want to "roll your own" filters, you should first be familiar with HTML syntax, and, of course, regular expressions.

    Just like the actions files, the filter file is organized in sections, which are called filters here. Each filter consists of a heading line, that starts with one of the keywords FILTER:, CLIENT-HEADER-FILTER: or SERVER-HEADER-FILTER: followed by the filter's name, and a short (one line) description of what it does. Below that line come the jobs, i.e. lines that define the actual text substitutions. By convention, the name of a filter should describe what the filter eliminates. The comment is used in the web-based user interface.

    Once a filter called name has been defined in the filter file, it can be invoked by using an action of the form +filter{name} in any actions file.

    Filter definitions start with a header line that contains the filter type, the filter name and the filter description. A content filter header line for a filter called "foo" could look like this:

    FILTER: foo Replace all "foo" with "bar"
    

    Below that line, and up to the next header line, come the jobs that define what text replacements the filter executes. They are specified in a syntax that imitates Perl's s/// operator. If you are familiar with Perl, you will find this to be quite intuitive, and may want to look at the PCRS documentation for the subtle differences to Perl behaviour. Most notably, the non-standard option letter U is supported, which turns the default to ungreedy matching.

    If you are new to "Regular Expressions", you might want to take a look at the Appendix on regular expressions, and see the Perl manual for the s/// operator's syntax and Perl-style regular expressions in general. The below examples might also help to get you started.

    9.1. Filter File Tutorial

    Now, let's complete our "foo" content filter. We have already defined the heading, but the jobs are still missing. Since all it does is to replace "foo" with "bar", there is only one (trivial) job needed:

    s/foo/bar/
    

    But wait! Didn't the comment say that all occurrences of "foo" should be replaced? Our current job will only take care of the first "foo" on each page. For global substitution, we'll need to add the g option:

    s/foo/bar/g
    

    Our complete filter now looks like this:

    FILTER: foo Replace all "foo" with "bar"
    s/foo/bar/g
    

    Let's look at some real filters for more interesting examples. Here you see a filter that protects against some common annoyances that arise from JavaScript abuse. Let's look at its jobs one after the other:

    FILTER: js-annoyances Get rid of particularly annoying JavaScript abuse
    
    # Get rid of JavaScript referrer tracking. Test page: http://www.randomoddness.com/untitled.htm
    #
    s|(<script.*)document\.referrer(.*</script>)|$1"Not Your Business!"$2|Usg
    

    Following the header line and a comment, you see the job. Note that it uses | as the delimiter instead of /, because the pattern contains a forward slash, which would otherwise have to be escaped by a backslash (\).

    Now, let's examine the pattern: it starts with the text <script.* enclosed in parentheses. Since the dot matches any character, and * means: "Match an arbitrary number of the element left of myself", this matches "<script", followed by any text, i.e. it matches the whole page, from the start of the first <script> tag.

    That's more than we want, but the pattern continues: document\.referrer matches only the exact string "document.referrer". The dot needed to be escaped, i.e. preceded by a backslash, to take away its special meaning as a joker, and make it just a regular dot. So far, the meaning is: Match from the start of the first <script> tag in a the page, up to, and including, the text "document.referrer", if both are present in the page (and appear in that order).

    But there's still more pattern to go. The next element, again enclosed in parentheses, is .*</script>. You already know what .* means, so the whole pattern translates to: Match from the start of the first <script> tag in a page to the end of the last <script> tag, provided that the text "document.referrer" appears somewhere in between.

    This is still not the whole story, since we have ignored the options and the parentheses: The portions of the page matched by sub-patterns that are enclosed in parentheses, will be remembered and be available through the variables $1, $2, ... in the substitute. The U option switches to ungreedy matching, which means that the first .* in the pattern will only "eat up" all text in between "<script" and the first occurrence of "document.referrer", and that the second .* will only span the text up to the first "</script>" tag. Furthermore, the s option says that the match may span multiple lines in the page, and the g option again means that the substitution is global.

    So, to summarize, the pattern means: Match all scripts that contain the text "document.referrer". Remember the parts of the script from (and including) the start tag up to (and excluding) the string "document.referrer" as $1, and the part following that string, up to and including the closing tag, as $2.

    Now the pattern is deciphered, but wasn't this about substituting things? So lets look at the substitute: $1"Not Your Business!"$2 is easy to read: The text remembered as $1, followed by "Not Your Business!" (including the quotation marks!), followed by the text remembered as $2. This produces an exact copy of the original string, with the middle part (the "document.referrer") replaced by "Not Your Business!".

    The whole job now reads: Replace "document.referrer" by "Not Your Business!" wherever it appears inside a <script> tag. Note that this job won't break JavaScript syntax, since both the original and the replacement are syntactically valid string objects. The script just won't have access to the referrer information anymore.

    We'll show you two other jobs from the JavaScript taming department, but this time only point out the constructs of special interest:

    # The status bar is for displaying link targets, not pointless blahblah
    #
    s/window\.status\s*=\s*(['"]).*?\1/dUmMy=1/ig
    

    \s stands for whitespace characters (space, tab, newline, carriage return, form feed), so that \s* means: "zero or more whitespace". The ? in .*? makes this matching of arbitrary text ungreedy. (Note that the U option is not set). The ['"] construct means: "a single or a double quote". Finally, \1 is a back-reference to the first parenthesis just like $1 above, with the difference that in the pattern, a backslash indicates a back-reference, whereas in the substitute, it's the dollar.

    So what does this job do? It replaces assignments of single- or double-quoted strings to the "window.status" object with a dummy assignment (using a variable name that is hopefully odd enough not to conflict with real variables in scripts). Thus, it catches many cases where e.g. pointless descriptions are displayed in the status bar instead of the link target when you move your mouse over links.

    # Kill OnUnload popups. Yummy. Test: http://www.zdnet.com/zdsubs/yahoo/tree/yfs.html
    #
    s/(<body [^>]*)onunload(.*>)/$1never$2/iU
    

    Including the OnUnload event binding in the HTML DOM was a CRIME. When I close a browser window, I want it to close and die. Basta. This job replaces the "onunload" attribute in "<body>" tags with the dummy word never. Note that the i option makes the pattern matching case-insensitive. Also note that ungreedy matching alone doesn't always guarantee a minimal match: In the first parenthesis, we had to use [^>]* instead of .* to prevent the match from exceeding the <body> tag if it doesn't contain "OnUnload", but the page's content does.

    The last example is from the fun department:

    FILTER: fun Fun text replacements
    
    # Spice the daily news:
    #
    s/microsoft(?!\.com)/MicroSuck/ig
    

    Note the (?!\.com) part (a so-called negative lookahead) in the job's pattern, which means: Don't match, if the string ".com" appears directly following "microsoft" in the page. This prevents links to microsoft.com from being trashed, while still replacing the word everywhere else.

    # Buzzword Bingo (example for extended regex syntax)
    #
    s* industry[ -]leading \
    |  cutting[ -]edge \
    |  customer[ -]focused \
    |  market[ -]driven \
    |  award[ -]winning # Comments are OK, too! \
    |  high[ -]performance \
    |  solutions[ -]based \
    |  unmatched \
    |  unparalleled \
    |  unrivalled \
    *<font color="red"><b>BINGO!</b></font> \
    *igx
    

    The x option in this job turns on extended syntax, and allows for e.g. the liberal use of (non-interpreted!) whitespace for nicer formatting.

    You get the idea?

    9.2. The Pre-defined Filters

    The distribution default.filter file contains a selection of pre-defined filters for your convenience:

    js-annoyances

    The purpose of this filter is to get rid of particularly annoying JavaScript abuse. To that end, it

    • replaces JavaScript references to the browser's referrer information with the string "Not Your Business!". This compliments the hide-referrer action on the content level.

    • removes the bindings to the DOM's unload event which we feel has no right to exist and is responsible for most "exit consoles", i.e. nasty windows that pop up when you close another one.

    • removes code that causes new windows to be opened with undesired properties, such as being full-screen, non-resizeable, without location, status or menu bar etc.

    Use with caution. This is an aggressive filter, and can break sites that rely heavily on JavaScript.

    js-events

    This is a very radical measure. It removes virtually all JavaScript event bindings, which means that scripts can not react to user actions such as mouse movements or clicks, window resizing etc, anymore. Use with caution!

    We strongly discourage using this filter as a default since it breaks many legitimate scripts. It is meant for use only on extra-nasty sites (should you really need to go there).

    html-annoyances

    This filter will undo many common instances of HTML based abuse.

    The BLINK and MARQUEE tags are neutralized (yeah baby!), and browser windows will be created as resizeable (as of course they should be!), and will have location, scroll and menu bars -- even if specified otherwise.

    content-cookies

    Most cookies are set in the HTTP dialog, where they can be intercepted by the crunch-incoming-cookies and crunch-outgoing-cookies actions. But web sites increasingly make use of HTML meta tags and JavaScript to sneak cookies to the browser on the content level.

    This filter disables most HTML and JavaScript code that reads or sets cookies. It cannot detect all clever uses of these types of code, so it should not be relied on as an absolute fix. Use it wherever you would also use the cookie crunch actions.

    refresh-tags

    Disable any refresh tags if the interval is greater than nine seconds (so that redirections done via refresh tags are not destroyed). This is useful for dial-on-demand setups, or for those who find this HTML feature annoying.

    unsolicited-popups

    This filter attempts to prevent only "unsolicited" pop-up windows from opening, yet still allow pop-up windows that the user has explicitly chosen to open. It was added in version 3.0.1, as an improvement over earlier such filters.

    Technical note: The filter works by redefining the window.open JavaScript function to a dummy function, PrivoxyWindowOpen(), during the loading and rendering phase of each HTML page access, and restoring the function afterward.

    This is recommended only for browsers that cannot perform this function reliably themselves. And be aware that some sites require such windows in order to function normally. Use with caution.

    all-popups

    Attempt to prevent all pop-up windows from opening. Note this should be used with even more discretion than the above, since it is more likely to break some sites that require pop-ups for normal usage. Use with caution.

    img-reorder

    This is a helper filter that has no value if used alone. It makes the banners-by-size and banners-by-link (see below) filters more effective and should be enabled together with them.

    banners-by-size

    This filter removes image tags purely based on what size they are. Fortunately for us, many ads and banner images tend to conform to certain standardized sizes, which makes this filter quite effective for ad stripping purposes.

    Occasionally this filter will cause false positives on images that are not ads, but just happen to be of one of the standard banner sizes.

    Recommended only for those who require extreme ad blocking. The default block rules should catch 95+% of all ads without this filter enabled.

    banners-by-link

    This is an experimental filter that attempts to kill any banners if their URLs seem to point to known or suspected click trackers. It is currently not of much value and is not recommended for use by default.

    webbugs

    Webbugs are small, invisible images (technically 1X1 GIF images), that are used to track users across websites, and collect information on them. As an HTML page is loaded by the browser, an embedded image tag causes the browser to contact a third-party site, disclosing the tracking information through the requested URL and/or cookies for that third-party domain, without the user ever becoming aware of the interaction with the third-party site. HTML-ized spam also uses a similar technique to verify email addresses.

    This filter removes the HTML code that loads such "webbugs".

    tiny-textforms

    A rather special-purpose filter that can be used to enlarge textareas (those multi-line text boxes in web forms) and turn off hard word wrap in them. It was written for the sourceforge.net tracker system where such boxes are a nuisance, but it can be handy on other sites, too.

    It is not recommended to use this filter as a default.

    jumping-windows

    Many consider windows that move, or resize themselves to be abusive. This filter neutralizes the related JavaScript code. Note that some sites might not display or behave as intended when using this filter. Use with caution.

    frameset-borders

    Some web designers seem to assume that everyone in the world will view their web sites using the same browser brand and version, screen resolution etc, because only that assumption could explain why they'd use static frame sizes, yet prevent their frames from being resized by the user, should they be too small to show their whole content.

    This filter removes the related HTML code. It should only be applied to sites which need it.

    demoronizer

    Many Microsoft products that generate HTML use non-standard extensions (read: violations) of the ISO 8859-1 aka Latin-1 character set. This can cause those HTML documents to display with errors on standard-compliant platforms.

    This filter translates the MS-only characters into Latin-1 equivalents. It is not necessary when using MS products, and will cause corruption of all documents that use 8-bit character sets other than Latin-1. It's mostly worthwhile for Europeans on non-MS platforms, if weird garbage characters sometimes appear on some pages, or user agents that don't correct for this on the fly.

    shockwave-flash

    A filter for shockwave haters. As the name suggests, this filter strips code out of web pages that is used to embed shockwave flash objects.

    quicktime-kioskmode

    Change HTML code that embeds Quicktime objects so that kioskmode, which prevents saving, is disabled.

    fun

    Text replacements for subversive browsing fun. Make fun of your favorite Monopolist or play buzzword bingo.

    crude-parental

    A demonstration-only filter that shows how Privoxy can be used to delete web content on a keyword basis.

    ie-exploits

    An experimental collection of text replacements to disable malicious HTML and JavaScript code that exploits known security holes in Internet Explorer.

    Presently, it only protects against Nimda and a cross-site scripting bug, and would need active maintenance to provide more substantial protection.

    site-specifics

    Some web sites have very specific problems, the cure for which doesn't apply anywhere else, or could even cause damage on other sites.

    This is a collection of such site-specific cures which should only be applied to the sites they were intended for, which is what the supplied default.action file does. Users shouldn't need to change anything regarding this filter.

    google

    A CSS based block for Google text ads. Also removes a width limitation and the toolbar advertisement.

    yahoo

    Another CSS based block, this time for Yahoo text ads. And removes a width limitation as well.

    msn

    Another CSS based block, this time for MSN text ads. And removes tracking URLs, as well as a width limitation.

    blogspot

    Cleans up some Blogspot blogs. Read the fine print before using this one!

    This filter also intentionally removes some navigation stuff and sets the page width to 100%. As a result, some rounded "corners" would appear to early or not at all and as fixing this would require a browser that understands background-size (CSS3), they are removed instead.

    xml-to-html

    Server-header filter to change the Content-Type from xml to html.

    html-to-xml

    Server-header filter to change the Content-Type from html to xml.

    no-ping

    Removes the non-standard ping attribute from anchor and area HTML tags.

    hide-tor-exit-notation

    Client-header filter to remove the Tor exit node notation found in Host and Referer headers.

    If Privoxy and Tor are chained and Privoxy is configured to use socks4a, one can use "http://www.example.org.foobar.exit/" to access the host "www.example.org" through the Tor exit node "foobar".

    As the HTTP client isn't aware of this notation, it treats the whole string "www.example.org.foobar.exit" as host and uses it for the "Host" and "Referer" headers. From the server's point of view the resulting headers are invalid and can cause problems.

    An invalid "Referer" header can trigger "hot-linking" protections, an invalid "Host" header will make it impossible for the server to find the right vhost (several domains hosted on the same IP address).

    This client-header filter removes the "foo.exit" part in those headers to prevent the mentioned problems. Note that it only modifies the HTTP headers, it doesn't make it impossible for the server to detect your Tor exit node based on the IP address the request is coming from.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/introduction.html000640 001751 001751 00000012446 12114164411 024375 0ustar00fkfk000000 000000 Introduction

    1. Introduction

    This documentation is included with the current stable version of Privoxy, 3.0.21.

    1.1. Features

    In addition to the core features of ad blocking and cookie management, Privoxy provides many supplemental features, that give the end-user more control, more privacy and more freedom:

    • Supports "Connection: keep-alive". Outgoing connections can be kept alive independently from the client.

    • Supports IPv6, provided the operating system does so too, and the configure script detects it.

    • Supports tagging which allows to change the behaviour based on client and server headers.

    • Can be run as an "intercepting" proxy, which obviates the need to configure browsers individually.

    • Sophisticated actions and filters for manipulating both server and client headers.

    • Can be chained with other proxies.

    • Integrated browser-based configuration and control utility at http://config.privoxy.org/ (shortcut: http://p.p/). Browser-based tracing of rule and filter effects. Remote toggling.

    • Web page filtering (text replacements, removes banners based on size, invisible "web-bugs" and HTML annoyances, etc.)

    • Modularized configuration that allows for standard settings and user settings to reside in separate files, so that installing updated actions files won't overwrite individual user settings.

    • Support for Perl Compatible Regular Expressions in the configuration files, and a more sophisticated and flexible configuration syntax.

    • GIF de-animation.

    • Bypass many click-tracking scripts (avoids script redirection).

    • User-customizable HTML templates for most proxy-generated pages (e.g. "blocked" page).

    • Auto-detection and re-reading of config file changes.

    • Most features are controllable on a per-site or per-location basis.

    • Many smaller new features added, limitations and bugs removed.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/configuration.html000640 001751 001751 00000027113 12116120072 024515 0ustar00fkfk000000 000000 Privoxy Configuration

    6. Privoxy Configuration

    All Privoxy configuration is stored in text files. These files can be edited with a text editor. Many important aspects of Privoxy can also be controlled easily with a web browser.

    6.1. Controlling Privoxy with Your Web Browser

    Privoxy's user interface can be reached through the special URL http://config.privoxy.org/ (shortcut: http://p.p/), which is a built-in page and works without Internet access. You will see the following section:

    
    

        Privoxy Menu

    
    
                
            ▪  View & change the current configuration
            ▪  View the source code version numbers
            ▪  View the request headers.
            ▪  Look up which actions apply to a URL and why
            ▪  Toggle Privoxy on or off
            ▪  Documentation

    This should be self-explanatory. Note the first item leads to an editor for the actions files, which is where the ad, banner, cookie, and URL blocking magic is configured as well as other advanced features of Privoxy. This is an easy way to adjust various aspects of Privoxy configuration. The actions file, and other configuration files, are explained in detail below.

    "Toggle Privoxy On or Off" is handy for sites that might have problems with your current actions and filters. You can in fact use it as a test to see whether it is Privoxy causing the problem or not. Privoxy continues to run as a proxy in this case, but all manipulation is disabled, i.e. Privoxy acts like a normal forwarding proxy. There is even a toggle Bookmarklet offered, so that you can toggle Privoxy with one click from your browser.

    Note that several of the features described above are disabled by default in Privoxy 3.0.7 beta and later. Check the configuration file to learn why and in which cases it's safe to enable them again.

    6.2. Configuration Files Overview

    For Unix, *BSD and Linux, all configuration files are located in /etc/privoxy/ by default. For MS Windows, OS/2, and AmigaOS these are all in the same directory as the Privoxy executable.

    The installed defaults provide a reasonable starting point, though some settings may be aggressive by some standards. For the time being, the principle configuration files are:

    • The main configuration file is named config on Linux, Unix, BSD, OS/2, and AmigaOS and config.txt on Windows. This is a required file.

    • match-all.action is used to define which "actions" relating to banner-blocking, images, pop-ups, content modification, cookie handling etc should be applied by default. It should be the first actions file loaded.

      default.action defines many exceptions (both positive and negative) from the default set of actions that's configured in match-all.action. It should be the second actions file loaded and shouldn't be edited by the user.

      Multiple actions files may be defined in config. These are processed in the order they are defined. Local customizations and locally preferred exceptions to the default policies as defined in match-all.action (which you will most probably want to define sooner or later) are best applied in user.action, where you can preserve them across upgrades. The file isn't installed by all installers, but you can easily create it yourself with a text editor.

      There is also a web based editor that can be accessed from http://config.privoxy.org/show-status (Shortcut: http://p.p/show-status) for the various actions files.

    • "Filter files" (the filter file) can be used to re-write the raw page content, including viewable text as well as embedded HTML and JavaScript, and whatever else lurks on any given web page. The filtering jobs are only pre-defined here; whether to apply them or not is up to the actions files. default.filter includes various filters made available for use by the developers. Some are much more intrusive than others, and all should be used with caution. You may define additional filter files in config as you can with actions files. We suggest user.filter for any locally defined filters or customizations.

    The syntax of the configuration and filter files may change between different Privoxy versions, unfortunately some enhancements cost backwards compatibility.

    All files use the "#" character to denote a comment (the rest of the line will be ignored) and understand line continuation through placing a backslash ("\") as the very last character in a line. If the # is preceded by a backslash, it looses its special function. Placing a # in front of an otherwise valid configuration line to prevent it from being interpreted is called "commenting out" that line. Blank lines are ignored.

    The actions files and filter files can use Perl style regular expressions for maximum flexibility.

    After making any changes, there is no need to restart Privoxy in order for the changes to take effect. Privoxy detects such changes automatically. Note, however, that it may take one or two additional requests for the change to take effect. When changing the listening address of Privoxy, these "wake up" requests must obviously be sent to the old listening address.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/index.html000640 001751 001751 00000050413 12116120072 022754 0ustar00fkfk000000 000000 Privoxy 3.0.21 User Manual

    Privoxy 3.0.21 User Manual

    Copyright © 2001-2013 by Privoxy Developers

    $Id: user-manual.sgml,v 2.174 2013/03/02 14:39:24 fabiankeil Exp $

    The Privoxy User Manual gives users information on how to install, configure and use Privoxy.

    Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks.

    Privoxy is Free Software and licensed under the GNU GPLv2.

    Privoxy is an associated project of Software in the Public Interest (SPI).

    Helping hands and donations are welcome:

    You can find the latest version of the Privoxy User Manual at http://www.privoxy.org/user-manual/. Please see the Contact section on how to contact the developers.


    Table of Contents
    1. Introduction
    1.1. Features
    2. Installation
    2.1. Binary Packages
    2.1.1. Debian and Ubuntu
    2.1.2. Windows
    2.1.3. OS/2
    2.1.4. Mac OS X
    2.1.5. Installation from ready-built package
    2.1.6. Installation from source
    2.1.7. FreeBSD
    2.2. Building from Source
    2.3. Keeping your Installation Up-to-Date
    3. What's New in this Release
    3.1. Note to Upgraders
    4. Quickstart to Using Privoxy
    4.1. Quickstart to Ad Blocking
    5. Starting Privoxy
    5.1. Debian
    5.2. Windows
    5.3. Solaris, NetBSD, FreeBSD, HP-UX and others
    5.4. OS/2
    5.5. Mac OS X
    5.6. Command Line Options
    6. Privoxy Configuration
    6.1. Controlling Privoxy with Your Web Browser
    6.2. Configuration Files Overview
    7. The Main Configuration File
    7.1. Local Set-up Documentation
    7.1.1. user-manual
    7.1.2. trust-info-url
    7.1.3. admin-address
    7.1.4. proxy-info-url
    7.2. Configuration and Log File Locations
    7.2.1. confdir
    7.2.2. templdir
    7.2.3. logdir
    7.2.4. actionsfile
    7.2.5. filterfile
    7.2.6. logfile
    7.2.7. trustfile
    7.3. Debugging
    7.3.1. debug
    7.3.2. single-threaded
    7.3.3. hostname
    7.4. Access Control and Security
    7.4.1. listen-address
    7.4.2. toggle
    7.4.3. enable-remote-toggle
    7.4.4. enable-remote-http-toggle
    7.4.5. enable-edit-actions
    7.4.6. enforce-blocks
    7.4.7. ACLs: permit-access and deny-access
    7.4.8. buffer-limit
    7.4.9. enable-proxy-authentication-forwarding
    7.5. Forwarding
    7.5.1. forward
    7.5.2. forward-socks4, forward-socks4a, forward-socks5 and forward-socks5t
    7.5.3. Advanced Forwarding Examples
    7.5.4. forwarded-connect-retries
    7.6. Miscellaneous
    7.6.1. accept-intercepted-requests
    7.6.2. allow-cgi-request-crunching
    7.6.3. split-large-forms
    7.6.4. keep-alive-timeout
    7.6.5. tolerate-pipelining
    7.6.6. default-server-timeout
    7.6.7. connection-sharing
    7.6.8. socket-timeout
    7.6.9. max-client-connections
    7.6.10. handle-as-empty-doc-returns-ok
    7.6.11. enable-compression
    7.6.12. compression-level
    7.6.13. client-header-order
    7.7. Windows GUI Options
    8. Actions Files
    8.1. Finding the Right Mix
    8.2. How to Edit
    8.3. How Actions are Applied to Requests
    8.4. Patterns
    8.4.1. The Domain Pattern
    8.4.2. The Path Pattern
    8.4.3. The Tag Pattern
    8.5. Actions
    8.5.1. add-header
    8.5.2. block
    8.5.3. change-x-forwarded-for
    8.5.4. client-header-filter
    8.5.5. client-header-tagger
    8.5.6. content-type-overwrite
    8.5.7. crunch-client-header
    8.5.8. crunch-if-none-match
    8.5.9. crunch-incoming-cookies
    8.5.10. crunch-server-header
    8.5.11. crunch-outgoing-cookies
    8.5.12. deanimate-gifs
    8.5.13. downgrade-http-version
    8.5.14. fast-redirects
    8.5.15. filter
    8.5.16. force-text-mode
    8.5.17. forward-override
    8.5.18. handle-as-empty-document
    8.5.19. handle-as-image
    8.5.20. hide-accept-language
    8.5.21. hide-content-disposition
    8.5.22. hide-if-modified-since
    8.5.23. hide-from-header
    8.5.24. hide-referrer
    8.5.25. hide-user-agent
    8.5.26. limit-connect
    8.5.27. limit-cookie-lifetime
    8.5.28. prevent-compression
    8.5.29. overwrite-last-modified
    8.5.30. redirect
    8.5.31. server-header-filter
    8.5.32. server-header-tagger
    8.5.33. session-cookies-only
    8.5.34. set-image-blocker
    8.5.35. Summary
    8.6. Aliases
    8.7. Actions Files Tutorial
    8.7.1. match-all.action
    8.7.2. default.action
    8.7.3. user.action
    9. Filter Files
    9.1. Filter File Tutorial
    9.2. The Pre-defined Filters
    10. Privoxy's Template Files
    11. Contacting the Developers, Bug Reporting and Feature Requests
    11.1. Please provide sufficient information
    11.2. Get Support
    11.3. Reporting Problems
    11.3.1. Reporting Ads or Other Configuration Problems
    11.3.2. Reporting Bugs
    11.4. Request New Features
    11.5. Mailing Lists
    12. Privoxy Copyright, License and History
    12.1. License
    12.2. History
    12.3. Authors
    13. See Also
    14. Appendix
    14.1. Regular Expressions
    14.2. Privoxy's Internal Pages
    14.2.1. Bookmarklets
    14.3. Chain of Events
    14.4. Troubleshooting: Anatomy of an Action
    privoxy-3.0.21-stable/./doc/webserver/user-manual/seealso.html000640 001751 001751 00000013060 12113150317 023277 0ustar00fkfk000000 000000 See Also

    13. See Also

    Other references and sites of interest to Privoxy users:

    http://www.privoxy.org/, the Privoxy Home page.
    http://www.privoxy.org/faq/, the Privoxy FAQ.
    http://www.privoxy.org/developer-manual/, the Privoxy developer manual.
    https://sourceforge.net/projects/ijbswa/, the Project Page for Privoxy on SourceForge.
    http://config.privoxy.org/, the web-based user interface. Privoxy must be running for this to work. Shortcut: http://p.p/
    https://sourceforge.net/tracker/?group_id=11118&atid=460288, to submit "misses" and other configuration related suggestions to the developers.
    http://www.squid-cache.org/, a popular caching proxy, which is often used together with Privoxy.
    http://www.pps.jussieu.fr/~jch/software/polipo/, Polipo is a caching proxy with advanced features like pipelining, multiplexing and caching of partial instances. In many setups it can be used as Squid replacement.
    https://www.torproject.org/, Tor can help anonymize web browsing, web publishing, instant messaging, IRC, SSH, and other applications.
    privoxy-3.0.21-stable/./doc/webserver/user-manual/templates.html000640 001751 001751 00000014140 12113150317 023642 0ustar00fkfk000000 000000 Privoxy's Template Files

    10. Privoxy's Template Files

    All Privoxy built-in pages, i.e. error pages such as the "404 - No Such Domain" error page, the "BLOCKED" page and all pages of its web-based user interface, are generated from templates. (Privoxy must be running for the above links to work as intended.)

    These templates are stored in a subdirectory of the configuration directory called templates. On Unixish platforms, this is typically /etc/privoxy/templates/.

    The templates are basically normal HTML files, but with place-holders (called symbols or exports), which Privoxy fills at run time. It is possible to edit the templates with a normal text editor, should you want to customize them. (Not recommended for the casual user). Should you create your own custom templates, you should use the config setting templdir to specify an alternate location, so your templates do not get overwritten during upgrades.

    Note that just like in configuration files, lines starting with # are ignored when the templates are filled in.

    The place-holders are of the form @name@, and you will find a list of available symbols, which vary from template to template, in the comments at the start of each file. Note that these comments are not always accurate, and that it's probably best to look at the existing HTML code to find out which symbols are supported and what they are filled in with.

    A special application of this substitution mechanism is to make whole blocks of HTML code disappear when a specific symbol is set. We use this for many purposes, one of them being to include the beta warning in all our user interface (CGI) pages when Privoxy is in an alpha or beta development stage:

    <!-- @if-unstable-start -->
    
      ... beta warning HTML code goes here ...
    
    <!-- if-unstable-end@ -->
    

    If the "unstable" symbol is set, everything in between and including @if-unstable-start and if-unstable-end@ will disappear, leaving nothing but an empty comment:

    <!--  -->
    

    There's also an if-then-else construct and an #include mechanism, but you'll sure find out if you are inclined to edit the templates ;-)

    All templates refer to a style located at http://config.privoxy.org/send-stylesheet. This is, of course, locally served by Privoxy and the source for it can be found and edited in the cgi-style.css template.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/proxy_setup.jpg000640 001751 001751 00000100773 11147744254 024110 0ustar00fkfk000000 000000 ÿØÿàJFIFooÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÅ?"ÿÄÿÄT  !1AQTU“Ò"4aqs‘”Ñ2R’²#36Sr¡¤³ÃáB•±ã5ÁÓ$Cbt‚¢ð7uEc£ñÿÄÿÄÿÚ ?êJŒW¤”ÅQ[R K_ KUxtQ;Çžøb{ƒhÀ/`ul×ßê6xw ë*NÕ©áÜ'¬©;V­´qÔÔÁKƒš³LÛÌèáŒm|¢ö¹µ‡8R…~±§–N)¨³DÈÜïEˆú„xw ë*NÕ©áÜ'¬©;V¯F'„“R èX)¥J^ÈÚëkŸ_¼e¹ÕXsÆ¹Ô tÎÀ[.o8ç”<;„õ•'jÔðîÖT«VöÕaÎ’XÚêøA246;° ÷Ÿjõ•6W3ˆ¸DHµ‘œ„oMGðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«U…´œH"àû•/ #àž(æC ]Åž.ØšïRè«|à{(ÿPUKŒa°J覯¦ŽF›9®ÂzÊ“µjèìç  ¬„RUQSNñй¡ÒÄ×61ir®5ŽpƒµÂ‡~IRX$ÙÉNÛå7±Ñ¾‚ƒ‰ðîÖT«SøOYRv­_KÂé¸3añWá´˜eU,¿BXàa÷)žÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù(¢“ƒgv(°î<ØAƒ‹·0Œ¸´;vë‚|ËøOYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉ͘öÉ$cƒ˜ö‡5ÀÜ8Ä,–ºfµ”Tíh he€À •±VaÄ k$€-E¿öfVkŽ‚S„ø½DBXÜÚ2ç3~Pmë(6ÈÌNŽ®¹Ô-¥ž*£´fÒ\†92†ë¡¸òAU؆ ŠN‘M1¢’cc‹îâëùå7n€ÊÜðKƒå³[‡Tì'H)êâ׿¿%ŹyýJ®l?ƒpãqanÃA‘á§hä´¸<†Ÿ*÷"7rs ÂL±óm$m„†6V>"àac”ÛÃ뺯Äb‡T›*%Sb cžçÊ·¿S{ßBI*üà,4ôÁíÅ»Sp„ïÜ,W‡àÈò)²Fì¯vØÙ§˜›èPWø­ÔœWcAÆž¦&NÇùR™úi{ÜïÕH¬‚𒂆ŽFGZÙj∆¶3x÷ jìºhlÒ¤¿àÌQ2Y ¦doú/tÄzõY;ƒœl‚7RÀw4Ènt¾ëó »Ú3ë·Þ›F}vûÕ0 É•S:0l^Ù‰ó^ëÇ`\lL•Ð҈ߣf6w¨ßTÛF}vûÓhÏ®ßz£ñwƒœc‹ñj}µ¯³ÚœÞëÝmñSêö}ç|Ð[íõÛïM£>»}ê£ÅL«Ù÷óO0>¯gÞw;џ]¾ôÚ3ë·Þª»}ê£ÅL«Ù÷óO0>¯gÞwÍ.{±@Òx»¹WI[çÙGø¹ãÁ< Àƒ‡FAЂçkû×E]ç#ÙÇø /û0ó~ÿûw&%U‰»ö½ŠŒÃk^pšq+k¥sžKZÍ7V¿öaæü#ÿöîþLK¸ð6¡ÕÄîhk¤ ‹FàNû øì<ÅðŠîpbL^£ mt¸œõLÂf1´4åxcN›®@6ÒúY8Iˆ‰íÃqþâ|ðú†˜*O·%€¹÷½æpuÅ…÷Xk{ý‰ôðIKšAû'ñšÂ4ƒöOâ+4K‡7†ÃØ@sb¤p¸¸¸Út©pÖ—ðǤøé ®^_ÉPé+[OKš}¼¦‹KŸ—/+…€Ð.R|¾aWZ*ee[ªDñÀ yB.K/ôG:ë§‚‘‘m)1jjÒÙȘAmÁסs°ðŽ)fÅ`tŽZîk\<Æ\Ón}ûi΃œ¯Ãê*0Jù›ENÆE.!3ª3ygY[–ÖþÖNªÀ+*j¸À §Š6> `‚¡Ñ™ZÖÈÒs6ÖúbÃÿ.«¢n-BgŽõ12¡ík¶EÞP¸¸^I‹Q#••P;j×:,ÒX<7ék®ä“à•€PŠH,‰’Üm#˜ç8K¥kɽ씘dx5Sd†<úéØç¿Êk Mɱ<ã•^Å‹aóLèc¬Ò4Z.ßî±Qäá ©mdrDdŽ;Æàu{€Õ­ý@ ¦¦ÀkÍQ5Ô®4ä6GGäˆÜòE˜ÆñNEºl"¶Ÿª­§¡¥ªcó£‘ùvwk,wn%¦öW1cXdí•ÑWÓ¼DyH&ÀŸEôR ž*˜[4/kãvç7qäAÍÐà3Á‰m*i[!6VÍTcl‚+ÛB ¾ÅÔ" """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚½´4!Ïq £{Þâç¾Jv=Î>’A+Þ'CÕÔ unUÕx»)ëE4µ5u6d¾Cy .pò ßDøWP|$}Ôât=]Að‘÷Vš\R’®’*†É³ÜMä8¡i” ÏFe`y6 .<»cÄèzºƒá#î§¡êꄺ£Qbôõ°¾vƒ-s›´‘ì±³‹yyG-”ÖÈÇÛ+ÚëÞÖ7A¯‰ÐõuÂGÝN'CÕÔ ue·†íV]Â톺_O±{ÑNÒè¤dıÀ„q:® øHû©Äèzºƒá#îªï³hÜÔ§uI¥6afpó 8¸ákÛ”+UÓ2ùê"mÞ¿ûbÄèzºƒá#î§¡êꄺ²3 XîfÎïzÅ•P–Åíò´9¬sÛ›^M 캡êꄺœN‡«¨>>êËoÛcµf×~LÃ7¹j}},UFšIØÉD{B×Y·µýè3ât=]Að‘÷S‰ÐõuÂGÝ[öÈÀö89§qi¸*¾ƒ¥Äf«Ž0öqbC!mœœÒábt»¾È&q:® øHû©Äèzºƒá#Ê×qˆr¸Ù§8±>…–Þ#1‡jͨ×&a›Üƒ'CÕÔ u8WP|$}Õ“'†G=¬•Žs>·×̽Šh§itR2FƒbXàEÐaÄèzºƒá#î§¡êꄺ¢ÃPO1Ž9Ú@»É·k˹å¸*c§‰’67ÊÆ½ßE¥Àê1ât=]Að‘÷S‰ÐõuÂGÝ^MY=D0Épe!ÚXe7X͈RSÇžJˆÃvŠá׳Ül¼ Ï‰ÐõuÂGÝN'CÕÔ ud* /{DÑ—0]Ã0»}|ËUNÐIž Ênñ¿™‰ÐõuÂGÝN'CÕÔ udéâd­Ò±²;è´¸}AaKWlN–žA#÷FHúÍ%¤{ÂxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷Vä@òCÆ28ØÆ†µ‘°1­ DDI‡’8_Œ9®-sb¥p#¡ íRaÿ¥Ø×°¥þ¢š³¯Ä#luUN’6»8nF lG ë”ĸ?=fU 5;·M$°JÓ`Üú»MAÄ.a7æ$ý“þˆ9š®â2UI$SE—m­Í<€g’X]KI¾»÷-Þ-Ëš¼š–F¾:f—¸ˆÚ÷ºþ²¹[b¼Gª«`k;å 'BZÒmû”IøEA·¦Š–²šgJ÷å“1cDo~kK@ûPPÁK[4°á‘66šxjÉ„f\Í!¥Äè ȸ¾ý—pop” k^ÈZÖ:¢I2ìåÞḀwm7«ÃвX¢|ÎÎòÖælO,pëY¤‚ ‰QÎJ~ar°™$–6BÇÁ òËqËf‚G-¿rŒàõt°²:§Q5°ÒŠhö-w–3µÄºû´`°×Ru]>å’²‡©dTñÅR÷K$01À¶2âKEΟòTõ|¬‚’ž:9V")aœÆÆ–µÍ~[µ€›F·úK±D‰Ãq ÔVŒÌ’”ã ß3¹,oþ|·áøÐb¦jšBé ªvL§P2_’ö¶í/uÓ¢VªŽz€è!u+ îfbydhËéx'qçSð >¦ŠZ×Ïcf,,ÌÈÄš Æ0Fëhûò+´AÍÐ`%•“>¢ŽÁÆw±¾yœö›ry$±FƒõjZHŒ-â΋ –K™Ûùrò®rpv¡”µqº‘©Ð͜՗5åÀfò^ãxÑZœ9´°ì›I²`Ê4}ù½Ú«¤AÉÇ€TqÖ>ª•ÓþN ²¶­Ì¹­À¿VÞâ÷º¼ÁéEK42@ÆU3À!ítŽp6õ,y•‚ eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"-Åi¬¼-܈Ï5¥ö-DI‡þ—c^—úŠíRaÿ¥Ø×°¥þ¢ µ„ß™“öOú,Öþeÿ²PE­Ãã®Âª)XÌð: ðÛåÌÜ·äºbX„ÚìöOs¾ïš7³Ÿÿ=þůÄI‚ÕÔÁ,N–wÈÀMîC †žå"ºµ´0¶GC<ÅÏ k!fbIýÀzIdœ‘õtò²­±¶-™%±!ʶ`à,mÊÒu:î´jÚ+bf(ÆÓÖ=ÆVqk¸4¼¸†»6†Î"ä{?ÃÐ8ÄȩꦖF¼ˆã`%¹àMì,O?©`ÎQJö˜£©’>(ÄíˆìóI—(¿þàok}º Œá“øjJ]¬•5EñÈÆþd¹Äæ:îŸZ¼¦§Ž––xšL h€ ¸­3¡§”m2Ôy7>H$è= *á%6Ff¥¬d²–ì t_”“6ë éË|ÖµÐ\¢¤¨áVM $—hÇ=ï`ŽL±ºì¶o¦@БË˦‹søAJኦ¡’Al­q³IÎã¸È-QI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^ âxŽ!&z‰ß³† ëfu¯¿ S£ó8=rÿ5ê5M5•rÊ÷Æêi¶­s'qXé¨$}º Õ†;šY£¯¤§`™Ä°K™®ô@:/+ëjiê)©éiâšIË¿;1Œ44_xk¿Ñ]g§§ŠA$¯CÈÊ9tå*“¥ª–ª’¦Ãžû¶[؇ r  \96SÍ»9Z^K~}ØrŒÚP7msðÞ±l¢©®c‰ -ß@t°Ôj5Ü¡¿¨Ûyªg|Εà%£bøÃ[Ëþ uô¬+pNp÷¶*)ø¬GSÚo—QÌnßÞ‚tØö ž×UÆç1™Ènºq¨ÓQ»d1Š!†Ó×K0Š€Óq©$\ sªèð\BœÉOMQI$¯cß–8°4µ£p(õ Û­ïÃ+ؤ§ã4%¿M¤±þAaô ÐHf;…¾¢:v×De€Öß”ÞÀó‡U²I'¢6ÇNü²I#²¡žíÓ_ݸý»ÛŽaŽ€Ì+#ȳ7¸9­šÖß{kéTópjº¢9µ°:GJ&l·¼DÖjÑ¥®Ð}D©àõo¯mm\´ûAPÙK"iÊØÞÁ©Þnûýˆ,dÄ©£Ã%ÄóÁòZ5Óx·:ÓKŽá•“2jãtÏ3–öÞ»È0çŒ>¾›hÛÔºWo£žêºƒÄ)䥎iéM4©s—8[s¥sµæ² •øý-c©^Ñ‚'<¸Ù¡¯~KßѾÊIŨ0¨ã Ù—e½ïÍk]F®Âe«Ä„âHÄDC™®÷Ž\ÿ¼lCƒïª©’qÅe½^ÜEQf²ldO“{ ³ªÄcƒ ›ˆ ™NmšÃuùž Ûº4Ã#Ih¹±ǯеI†ð~\9‚L‘9€D̬iu÷·íX %Â0Ñ#oÇQ6Þ3^Þ´Ópƒ¨¤¥¨ÛìÅDbFµàÝ ýn@·IŒáÑ>F>®6º#•÷?DÜ MÈÓÒ©"༬Øm£ÃjrÓGNã<%Ź.›}÷všò«Ga1=™ÙåÖ¶¨éÈ ½z qzL*8ÃveÙF†÷æµ®¼ƒ¤©Ä //~ÄM˜ I#>Š»àûꪤ¨–kÕm„Uæa&FAôÝ—¿¥K Ã$£¬l­ì‹‹ˆŒp³(kƒË´ÞQAhˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¬&üÄŸ²Ñf°›ó~ÉÿDjé[]†OF÷²x]sw€ákz®¬À¤Ä"‰••î˜E(•ôñW7PEŽŽýÁoÅ+6[QœÙ¢¥|‘»&ç¢ÜÊ=N5#*¨[Åj©â|¯ÚºXÀhŠGXju»Aûm°p—´Å3ÞÖ ZÐàâ4”~õP0*ÚI©èiPê6ÏO#žùcÙÚ,·'üyŽ@2Ú× ÝJ$}]#Ý5E;ƒ¢-|‘œ®k¤kN¤Zö+tœ'ŽešŠ¡”ÙæŒM¡Ñf$Xêëzfþ²FˆY9‘±ÆlÀö¹§’çéiu]7㬣’SQm›OQkØ`Òu Ü‹‚y@Sâá –<áõMHÈÚÂÒ3’‰›^mìs~€KS™”õ/kc‹;Ú$y 'Kn} ‡‡àµ†êf¨š’µ²Ìë‚Ù d„]®Ó-ü–7[z•ˆðz,LDÙç{ƒ˜±¥úÝ®µÚ}"ÜŠ.Â&Ôº©ô¹¢{bœH°µ«ßA‚i†R[OÒ§VÞ ö»—R »‘B‹œƒ‘ŽŽ'Å5ML²:8ãfV´þRP5ä³c7õs­µü(‡ {W…Û#,‚Iãih7qÐÚÈ/‘sáTÔ‰é¥9&tPGiÚþl6÷ÜIs uÜ¥ yù„'œUƒNaÌÝLàÞöµ\¢¢ªá44´¬•ÐyNÚÇÊÈü¦8µÍÄn]±ÙØ×e-¸ÎÞ=h2Rk¼ä{8ÿQ”šï9Î?ÀFÌàõËü×¢GæpzåþkÕ>?Q3,R>ÕO³|Ìаe&À$IåÜ‚á=ÀˆSO[S5.#@^ÖÓÔÍ£-¼¡˜f×v§Ô³á Tô•xlñLöC’v4Ø>0kú%ßûP_"å1SO‰âÕaΖșO œrfÚ9„‹u#r)tü ©ª,† HÝPj³9Ìh´bKùMµœä*šLeÕ.‘®€5ÑÄ÷ºÎ¸Ìǹ„ 7]§_J€þ½’³þìÝ–H\ò ÉxÂÍÊ,7‘½JŠšBZnbϼϧ’­á®vðÉ$³oÉ i“ÄbÄY@ü>¼¯nC·òr¹’:çMàÆA_¢ç ÆñJˆàspêqÆ£{éÁ¨:–ê¼.9®°‡…–—Žñû¤ñ—Ñ–’_-œÖX¶ÞIÌæ¿z‘memdu”´t´ðÉ4±¾GºI ZÀÜ î\9 ^UÔ'uBŽye†7²|ÎÌÀãrµ‰c¬AæçAТåkñŒFl~B:yj©„ð–N뵡ч@ÐþPZÞË?*⦮}= dŽ…“I)’ Üå’F€Ûƒú²uÜ4:tUŽÅKb‘ûäV²–Ù·ÝÍnoþ[½ ¸AVÚ j“G xËívq°’CZO''>¶AÑ"åOªdx¨1)’+±¯-v~1³'p6ÐèwÔ­þ0×Ed¨ÃãZaQY5î35¥®¸>[O(Þƒ£E†²yª*)ªbŽ9¡ qÙ¼¹¤:öÞº9žkKìZˆÏ5¥ö-DI‡þ—c^—úŠíRaÿ¥Ø×°¥þ¢ µ„¿™앚ÂoÌÉû%ºŠhëh%¥šû9¢1¾ÆÆÄXÿªòªŽÃØž^Ñ{\–9†ÿcŠÕU4§ Ÿ`íŒÛlå‘¶k—B}®zŸ— .uIÄCi\M%\¡í™í-»™&ëùGA¾÷°² ¸p8"¦â–!”1²Ë|®} o¹Q à̶I¤¼• ŽÌmí@çÊëz.l‡ÄXê¦YMQ4Mó†[äjFqpmè%`Îb.¦u32eŠ76B\KçF\ yHÚsŒXLQÆÆÉQS9cØöºi.F]Ãw¤úO:‘QGLÔҽϽ;Ìh:”·_°•WE‰â5x–š)j)$Ÿ(›;ô1ÚþHâä<¾…S‹Ôb»©§ãצ¹&e@DÐÈÜIf·ä‘mEÐ]W`b¦¾˜¦–?ˉeÊûhžÀ[¦ý[{é¢ŒÞ Á¶ž7MP)$…‘¹¢sš_-î~~{—òsžE²Ln»ŒìiðèžTêXÜúŒ·sAqqòM†VŸMù9T:ŽËMH÷? &«fó8˜,Œ²F ékƒmG2 98=G!kšù㑎ÎÉ#’ÎaÌç\}÷ y Ôx-Dc’1=`d±l¦mes®ãkÞïvëoZ$áFx$¨£¦ŽZf¼µ•”†>Íü-qô¸ä7#—3HdŒÃJ$’h©Ë[Æ_ÊðÓ&ñ¾þ„äàÝÁûIj\_®m¥‹]fy@¡¼m>°·Ó`ÔôÒ6]¤ÒÌ&3%}Ëœ[“_FSk ÃÕŽª––<:7ÍL×:¢ÕhÄß(›ò€4Þ®(ê8Ý =N\»XÛ&[Þײs`°KNèÓÇÝ#žÖ¸ý£‹œ ‚.ãȧà tðG MËm cy€fˆ Mwœgà 2“]ç#ÙÇøÑùœ¹šôs±ÅŒyaÌÜìóؤ~g®_æ½o’­ïˆÄÖ²(ÜAsX-˜×P§¤‚¥Í3DÙ2µÍÂâÎ"Ü· r ƒ&A$;'Afåkn×¹§Éva¨7¾bM÷Ý)pj 9ŒÐA–BìåÅî7v\¥Úäo;Ï*œˆ Kƒaó´6J{¶î$¸f%αò$›V¹x=…Íq%3‹Hh-Ú¼7É4Úö¸XïÑo~/†Æ÷1ø…#^ÒCšéš<ÇTn/†>ùqGX\Úv›}è1«Ã#›¬Ãá´M¨ŽVÜÜÙÒ^çÓ«‰^Sà¸u$ûhišÙs‡‡æ$‚Z¹Üˆp¾I§¬¦«4ÕÌ¡1¼:ÞåÄ(…O5”â{åÙm[šüÖ½ÐCñoü­¨À5Ì =À¸ÝÁ¢þH'}­uNF'M=ÚÚx§ãOR_0nV›ÞÀo`5 +tA ¿ ¢Äòq¸3–¸9Íp"í ØòËLÂijðQG›|¡¤†´‘bZÛØ®ÕšÅä†8àŸ†Ñ¾8˜èlQl˜.teÚmÿÁ¾åQ‹ð^‚9”ôTuDX¤ÕõŽT\¡`Íq»U“pÚ&V:±´Š—ºPÁ˜›[¨..žš8çÂêàæÈq …™*wŽšX k¦—3Ä@’Ȉ>¿+—‘W·„5ÒGQ)­¦…Ð:(Äg•&cbíüºnV”Š" )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耱’FCä‘ídlÎsƒ@ÞIY(ØŒÕa•TÓI³ŽhŸp2‡ __Z´˜Ý=`‰í†¦8&6ŠicÊÇßuµ¾¼—ús…f¸úúšìN:PÈ-k$`–V×4E”;\¯¹¾ÿ)»¯Ë`b¿ šš‚G7 -ðÃ(ÛûÄ»VØÝ„5ò•ånÑhú˜ÙU3‰ÚJ×9ºifÚÿˆ-Ë“¢àø—3M„2›9íJ÷1ÍÍf Å%ºØé¯Ñëe¢£ªšZn7E=Dm§ÙDz–0`x{ü½ÀµÍÕºŒ›· ìÕT¸õ<2HOU²Š]“çÝuÀä7¶»ì½Ã°ÆÓâ5õrÀÝ´³ œ„ævM›ly5iæ½½JÃkïAxµ¶xPøÁ•ŒkÜÞ`â@?üO¹qtܬO…¸P¦›ˆIDÂvž7)"θ7;œnëšÊö "ž‹ª–*=„´Ð´:60]í{˯r õa¿-·Ü2~mÞ¢¹\ƒôø%-UI«|Ò\áY+o©ä°]TŸ›¨ªŽ ~ŒPþÁüE>)á?V¯ã¦ï§ŠxOÕ«øé»êíRx§„ýZ¿Ž›¾ºÁ-%17+IÞw“©>’µ)5B—ØÄPFgšÒû¢3Íi}‹QRPp·ö4»‡´Wj› ~φx¬„Ê77Ø”od‘ØÉ ¬ØÆæ‹ý¡Ež¾ŽšfÅ=\Hÿ¢É$ .äÐ9ïkYXÖ×b5F¦´TRØÀ`†ÿ„ tõZÞ›ñ²TáToÆ¢Å`¦g—æuLdZ0Í÷ņãÈ.ƒ¬Zß2Db|LtgRÂÐG>åȳªŽ²8MUE$íšš8p×·h]šÜ丂]k¾îÃ&ª]'„ªëiÛ&'PÈæeKœÖ1ƒ.IZÖvèlNºß÷ ¿4nnWR@FšÇ&{ÄéKØþ-vì‚í¶ës.:|bµ”®/Å&Š¡”Ë !Æy‹¤O“©vV‹ Q¸­Ø^+[PÆÛ’j‡QI%LO§Ò–`E›`Û‹á”Üœ·AÖŠZv½ïDñg¸0]ÃÓÎÓÁN‚âxcCoî\ƒqzá†×9•ÎsYÕ««§ã3ÚaNÇfç–Èáp4侺  ‹‚ªäá†3<Žx‘ÑeŽ KÁ ´Y¦äZöšî7O°¾/·mKF¼9‘=ÙƒŽQk Mô j9l‚ÉŒdl cZÖ´X5¢À/\c6ÕGm}3ËC^]e³ç¤Øa¥õßÌyŠß'æŸû%U ¸-†ÑÅGøxd#(Í3ïé¿”¤xéÁ¾‘†öÏï*\«‰ðs ¤Ú‰äºM,˾Úë~], YY[Kˆ5¢Š—Šºhá`/ü¬¡ÖÌæÈÛî¼Å*q b­˜ÇONhéåŽ ‹Ïà$n°g¼ójütàßHÃ{g÷“ÇN ôŒ7¶yhÄjgŠ ÁEOLçÇ šMµÀµì·.…{]ˆ2Ÿ ж 33eÈFCˆÕ×>žK Ýã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÊM pZ¬BžÐKTù‰Œ‘î%×ÒÃ2ÏeêÛîR°ØØÜR†4³5ÒhD\óñڸșÂ`kM.Ï9´1Ür¥í̃¡EU 0‰™+ÙV2G¦.tnÌÅÍ$YÀVÜ,©±ºjºé颎¢ÑDÉ3ºž@ç .Ý~ŽýÆþ‚‚ÉÖ, è-ª©¢á7°Ú8¨â¨ÃÃ!FiŸMü¥k'æßê+‹¥ÅÆÁÌ!¡´¬Ç+ŒÕ7 ·9nó}=GzŸÇN ôŒ7¶y(â£7Hòi%°ê-å{^Å^ÚxÙW%Hk#ù\Gâ+já©êª¸ÓãÄ#Æ NÆÚq9.»#-»¿8A;K\èt6Ð+L£›âuq,[g]w9ÒjÖ¸·B[åè4Õºh ÊŒFŽ’x¡¨¨drJ@c\wßAïYUÖSÐÁ¶ª™±G˜73ŽòM€åqü$‚µ¸ÄõÑ2¦YcÙ2FA#á™Ùž[¡!Îu?áݪè1Æ2L>™òÇWvOÄ”­»áw×Ëcq­ˆ±ÐO¤®¦¯ÒRÌÙZ×»/!æ<ÊBã'~&úc¬ÂÕ0KW‘É+vdæ4‡èðÝE´ä²ô¾¦Ž2üj¤6œqMƒÌÏÎï¤.u'çIÔët’ÁóGƒ^ðÒEõÓ”ù…Î>ª»%5+Y[·eEA™Â7å É1`͸Yk_P7(Ø…Oƒéã{±˜êq,çi!q“i#wfÐ[—Dz* jɱ ¨'|†ÅÚçL¦÷'üG&KúIܯÐI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DDAãŽV“bl/`5\à’1‚ŇlqÉ–§~¹\»ì]" .ʺ¦§=öáƒ-­—(#þj,¸@—ª£t ¶¢gJIeÀÙ­kë̬ÑšzJj@áMO!Ú‘oîQi°zX*&¨|0É<“:Q!ˆfmù/¿E`ˆ)߃NÆÂúZÆG4ULøs´‰âZEÁÓ6ðF弞'RNkÚùè³>˜?ÆòL¤€íC OJèQpé©iªê\×C%Lד7ÊŽèÆí[•䟚ì•’ñÄ8‘päöIÆø+…·>M›Û.ëß+ɲ’pjË‰ŠŠgç- lÔî{â`±ÙÀ77·/*QðÖ’7Ña8“©­hË$`m†š ËxßTb½¬}ä  t5õµ†VºJŒ­g|†´hºêIäÞ£O„O-[Ü*£m,ÒG5D[\÷°pìÞH9Y¥Ñô•·Æ¼oª1^Ö>òx×õF+ÚÇÞAnWQ.Úž²e|n†Bè Áa7m†ab.uÖ÷Ü·O‡m°ÓBÙ"g-ËZÛhu×vý7­~5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò %'ÿ‰Òûf¨Tž5ã}QŠö±÷”œ;„8Õv#OJê FœK fÖI[•—å6q($ªú,–‘ï”à •šIvÛ 3¼º×ß 6û‚ ãèðÙª#e Õ5F8éIN_@èÃm«ÜM‰³4·ï]™¸¤Õ‘ÌÀ%‚8‹6,sïq¼<‹[›Ô¦¢ düÛýEr¸F=f„ÕRÔÅ ÐÃ4•ƒjÒ×t¸±òF·ç««q„‘qmÊž†Œ´‘¾ ÄMkFY#l4ÐfA¾— m#0Ö2b[CŒ]º¾íúnܼªÂU'¦ W47Fƒ’Í·.õïxßTb½¬}äñ¯êŒWµ¼ƒÌ3 šŽ¦¦ª¦¢)§±°ì Ù45€ÛK’O”u¿0äW•B—ØÄU'xßTb½¬}åjé*'†žzœâIbÈ÷]Ì:ƒy­/±j#<֗ص& á~2Ö´¹ÎŠ• Rv€+µK†¸ÇÃ^F€K#¤xÚö/(:ZÌ.¾‚6ÉUHè£s²°ëby æU2bt±âqáî{¸ÌÌÖä$[Ê·•k ïr³¨ž‘ñlépšz2燽ñÈIuÓw¥qU8f%4õX«•µM’8]NLŽl~K@v}Äßâ<è:‡ÔEñ@çZIo[}·­«†§Á%¬|0ˇÕÓÔº–xêjäv`dvç+S(snÑož“ª¡e]] ÛÕTFf…±¹Û623½¢AqŸ’ö×qAÙ-ÔTôŽ™ÐDéžd‘ÛËœyI\æ†TÕI1JWìámCr:íf²4²ÍÌt˺äÚÊ5&!aªÃª¦Ä¤ØÚ©ÓY±·fÜÚßBuŵ'Òƒ³Z¢¨ŠwÌÈÝwBý›ôÜë[Üุ0š¦P1Iv|nº6 ,à]l€n;Îëó«î Òñh+òÑËI•|QÊ|¬¹Z/¼Ø ‡" ´D@DD)(©è!0ÓD#aqyR\MÉ$êIç+z"" )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆƒ”55´Ø‹Ÿ]WYãƒg#Z$¦|EùC …Øuîµ­ÈJzŠÚzøü!WY †¦ÁùD”Ó1Î 4$îúV7çR‚Õ ‡IÄ©2>]³â㲘Ëï|Ù2å½õÝ¿UcA ¹Û™D†A¥qŒ:÷¸a9FºîA³šJœ‚yž_,”ìsÜyIh¹TÕVIQWŦğVÊÌ‘²8¯PF„‘–Ö½õº¿¢Âi°òÞ.úÆ7#Xú‡½†“e&x©ö›6Ûhó#µ½Üw”¬’vÅO†5ûI厒 4ˆsšlÝ=wä¶§WŒ“¸SFÜ:Õ5aÍ‚ÎiH•¤€@ ›òúôVS`ÔSÄÆ9nI_3Žkš÷\C¾¥ÅiÃã…¬Š'·fÖ¶;Lñ—)Ì,opIÞF§–è2¡Æ‰HæRÆ×:8˜ùs>Á®q>NíàO­¼úXÉù§þÉU¸Fhi'lÎnÞ¦wTLa.kshÝo`›zU”šÆïQAËasUCÁœÐJÆFé˜ÉAmÜàdµ¾œ·ÑI­–£Ã톟õXÝÅ£ŽñEø¶†ÆÄùV7ß—ÒUŽTx·‡ÃW Zøí k¥h!ÁÄŽ_R—âËE|•­22i^×É’°µ®- ´:Ç@ ”Òp‘Óâ5;:q¶©Ï¸9¯‘ƒM7}sé…]EO¬«mL¬mT4í¤dxpa%Ü·ü¯ÿé] x#¢–¢F4ÔéP,-®šs-2pf9kYVö“+2鯼—e½‹›šÄ‹ï?òAW‰™ç®}Õ¿4âÑö­ù ŒŠO¨æµoÍ8…G4}«~h#"“Ä*9£í[óN!QÍjßšȤñ ŽhûVüÓˆTsGÚ·æ‚2)Õ¿4âÑö­ù ŒŠO¨æµoÍ8…G4}«~h#)8üN—Û3ýBq ŽhûVüÖú*Ib¯§‘û0ÆÊ×8í[ Ö‚½rMª¬šriæÄŸR1°´Eù”ƒwkC{®µj‚ž*hÜÈ›•®{¤"÷òœââ}ä ¢g §âœjl1ÌŠZGÕÓÚv¸½¶Žò\CšyF»ôRé+±9qzªyéiãdtñHƉËÜçƒs—™»µµ·›éƒ¸9EOO(£¦{£0µ“Nüa7-nü£Ô9› |®«©`Ž­ñ¶'ìfqnV¸–ósžNRK“óoõÃÃS] ÓÑŠ·‰ ¨{ã¤-¶Ênál »Q{Ü‹¹wk½ETa\uW°æWBèæ…ŽÊYS³{C‰¸»\ ˆ¶ž€ƒF[];ðGËQ⨥.5„?(7ÖÚkºÁyU[_&>ãPÍ¥;A€µ†Ì—jIÿí—CØE0ŽÚ)šY¶Íµ·óä¸fmSd†76¨Z`fo”-n}4AAÁÊŠ×Õ×ÓÖq¦Û ㎬´È34Üݺe$jMïmË©«ú¾Ä~"¡Ðpq¸i•Ôì»åËòTíl,Üâl9½%M­nN.ÂZ\Ø€6p67<È"³Íi}‹Q派Ũ€©0ÿÒìkØRÿQ]ªL?ô»ö¿ÔAv°”‘È6!§UšÂoÌÉû'ýa=Lt”RUNì±E‘îµìÐ.NŠ2Ê©„RÑÕÒ9ÐíØjÐË€ui q¡±Õošî¡‘°ù D1³8–8å°çë——Ä$§c)hOLÐ×MA=H|rÙÌ9XA!º5ÂäXÞÖÖà;4D$aqÌ5X²¢7GœDnx#œ./É¡·¹QÐáRIв®« §¦…EHv[˜ìHf9\tÐiÊ©›ƒÔÉO.p覩m%,;gJÁíh»¾Ë_ɹ6·¥eu-DÍìtr_!&Ù¬mʽ¬«Ž†•ÕÜ´´ïsœCZôÔ5°×RäæàýYÃá†*¶F°³ÿ ñ‚â šuß{ Ï.à¯qÜ9Ø–;áÛÂ%k§§k²íZ/äÜ>–S©äA&жÕqE0 Ì™å‚ÝâÛØlVˆ±ú)]‡6Ó5õìÏ]ÐZþQ£ðb†» –ž±®c%©ãt­~Hì,ÝÔ}¾µWj顬,Š'ÉŒ4Ó›–¶WKk‘äÜ;'/ÑæAÑÐâqW¶G²)cdr:<Ò€Ðâ×›k{\oRLð†™XtÌ,W3¦†Žšµ²ÆÈ©[)/¾w6lòuå%cY‚LÌJi›„A[F] Š›hÖæŽ!pƒV¼_*ú èé+éë)içà âl¬kˆÊáq§©oÚ2öÎÛÛ6þNuÅÐpv¶©)æÃ!2µô¯5›ax™Îð¹¶ûÖ³Á|[Œ4^0Á!¢.¾†‹Gn½ó oÜyvâXËò ^5Ë}Vk›‡¨‹„1ÔGL $‘ÅïÈá•×ú.}õ:àj€.‘I®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DEáÜPbÙ¢{Ë#á¼B¢lÌŒÏõs û—…)_@Ú!GZû½TCxêYv;ó̱¾ IØÙnª~þ ›£v$h²ŸûÇ¿ó_7ÙoBÅóEò1¤îpY\^×Ùr’œµØ¿†Äf{ ¢§–‚Û;úsnÖëP}d’>J(dŽAJù¢©yÛ˜Ãæ»n/åZúú-Ëpk§‰–Í+›Qwu™ o r.6¼áuUͨ§Ÿ ž)iÎ-X21Ñy@ßc”ßB,y7+:§É?°×ÀÃM#¥¥ÊÙÚ^Xs·G ‚}âè/î/k‹ï²õr8­F#AŒS:£¥iÌÔGLZ"i{nHsÜ5Ð\è/ʽ~1YàÒöâ {<±¶¦6ÆÇJl¤gòÔƒkanTjÅç+Fð.¹Ü*ªZŒNYfÄ6˜}4®cc—È 7¶îsô½Vè¤üÓÿd ç0ÙøE‰áðÖ2®‚6J t$jGÖô)[ôì;áÝÞYpSôb‡öâ*å&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wyKÂé1¹qZXë+(LùZÙ. žBNŠÁIÃÿât¾ÙŸêFZÄñ6bVg½²æ÷-‹’§Â§¯ÌæRPFÖbRÈjˉšÍÄ€Fû[én÷ ëQqTøý{è318ª&’‚J‰"ÅeYºkmH³µòU½+gƒ„5±Tb’<ñHƒä nÐ]ûΈ/^r±Äoë›Ãgá'‡ÃXʺÙ($5Ð8‘©[к9?6ÿQUý¡ýƒøŠ v%éØwû¼›ôì;áÝÞWh‚“aÂ^‡|;»Ê÷bøiiv¯™Ð‡Hæ‹ë›Ør *M_Ð¥ö#ñ™æ´¾Å¨ŒóZ_bÔ@T˜év5ì)¨®Õ&ú]{ _ê »XKù—þÉܳXMù‰?dÿ¢ &ž:Z9*'vX¢Œ½î±6h'WÓbõRKMÆ0š˜!¨$1ÿL°òmÙq˸n6Rj°è«0Ùé^ÆÍ ¢.P rÝBŽŸžZ6UOK P?<ÒS=ÅÕÐ4´´{Nà íÅ0÷>f6º”¾L­6ñ¼»]-éQÝa’' Êc{@™¹”´Xºö¿–;7±y¡Š<ôyc.qd’¹Ñ¼“{å \‹®ó®šÝÓáÕòã1bì¢nͲ5Œ†î-¸h1h¹ÑÜ‚ÀÛ]PXM‰PÓìvÕ´Ñí¿5žV§ìÜë¼nçR—*î Õ #&:Z†:˜A#_<‘å!ïp#(òÁ7۷꺖·+tÐ[D¢"" """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆ0lQµÅÍcCŽò¥61gϳfmù²‹¬ÑlØL“Êé)X.I „†úã&Êe<.‚ ÇÏ$ïå’@ÜÇî€?r܈5˜" ®Ñ¢Ø@;ÅÑxæ5âÎh<š…‰Š2ÀÃKFæÛEš Ç#/|­½­»‘zñ™Žy^¢ 8.ƒRÒKYy#mœ[µï~JŸ±¥éN쿺§Äq1B衎 *j¦¾Îì ¶òIÐI[0ê¹ëiä’jé]²9²kúÞ=;ZlizS»/î›^”îËûªZÌ]´µ¢Ž*:šªƒ˜²Ï%—µîç ç\è¼ðÌod Z©åž=«ac\ÖÿæÌ@o¨ž{ »ØÒô§v_Ý64½)Ý—÷\ñá#i$•ðÔ²xåØBÀe2ÍA½­­Öc‰¼aµuTÒÂã­i.kˆÍ-qi6:Ü ¾ØÒô§v_Ý64½)Ý—÷Tµ˜Í53¹’É=šãA»É0k«®G _RÊ,@ÕÏ4QÔÒËi-˜6Îö ´w[ ¶ØÒô§v_Ý64½)Ý—÷P…D. -š2HiQÀçZ¨«éqß%$Í–6Hc.nìÃx¿* -/JweýÓcKÒÙuSVãü^¢Hi¨f«186W1Íhi:€.nçz¨:-/JweýÓcKÒÙu':H#•ÑIÑ¡Á²6ÎÒSqøßPæ2†±ð6§Šº¥­i`}ò3f¶m/–ßf¨: /JweýÓcKÒÙuE>6": ʨ $I$-mìà]ÿ´ãñêwKTpO[$Ñ ƒ` òXw8—õ[èP_lizS»/î›^”îËûªJln–¥°œ²Å´dp•¹Ly Cƒ¯¸ŒÃœ,fÆÙ”±GGU4Õ!îŽ6‚XÛ]Ç3€QË}w ½ØÒô§v_Ý64½)Ý—÷U”µñTÐ2±Í};pæÎ29„}7ÿE£Æ à ]4¯~]œo`-ЛœÎ 9÷‚ëcKÒÙtØÒô§v_ÝC‰æXY!Ñ—4ÇK}ÄqY “±¥éN쿺lizS»/î£" ;^”îËû­´ÜR ¨f5."7µÖÙo±¿:‚ˆ ÀÜ,½D£ÖcFmöÖ±LE[çtÒ9®hh‰Á¹[é_ÞVôAãÆf8 äYjÁpÈpìš’ZËÉlâØ®I<þ•¹IØÒô§v_Ý64½)Ý—÷Q‘/Jweýוoæ&Äâæ²0Û‘k›“ÿ5派ŨŒóZ_bÔ@T˜év5ì)¨®Õ&ú]{ _ê »XMù‰?dÿ¢Ía/æ_û%zú³A„UV5æ(i6Í•¤Úÿbƒá™hñSb¥…‚™Õ;H¦. k\ÖœÀ€GÒ>‚¥Wa±Vá54lqºx~O£™¹nµÍÑ šj*ZjGNÜ®tPµ·æ½­t7„XSªG¶ÅŽ_($‹m¥÷òoYøj‰â=”í.¶Ùšá¡G®šÚXò¨µX5\Õµ:¸™ISL32:bè›Y`7\ÛrÓãvÓÇfÿ’xÝtñÙ¿ä‚íQKÀš QÏãµD0VñÈÚæâÁ#x6ä±ë/°.ž;7ü“Æì §ŽÍÿ$T‘¸Ç..Ž6å"ÄësûÊäg«¤Ä%šXéj]P+ ™Ícãò‘‚3£)¿îRünÀºxìßòO°.ž;7üxÁ‹añTRÒÐÅ;Üêy]0hòü±¿BNîE®›Äpy };#¬ŒÒ² šÍÁÌ.!ÂæÖ9Ξ¥·Æì §ŽÍÿ$ñ»éã³ÉsÕâbŸÃR AdûFFì¢<å…¬[6P§”Ì•4X…TÑVáÐU\ö—¶rÉ4¶Ií'[÷RI)b/‘’T>HÚÇÆAk£ngsiªÐþí µ¯’iÝ+¤“ ¾1ƒîQ«x sêä}d­– Bs4~mì7/f¾IpÐÛ‘ƒ8AE!acj nk]µ0¸1¡Çɹ<ÿó ÉxE‡Ã ²ÈérºòË<8´´¼ù%B¬à”5HÉbŒa4í{ãÈ:ÛÉzNªt¸.zàŽ¥Ì–:§Õ2LÃ3žçZw‹<„Y‹AUƒMˆQ¸HÖ1ä_ë4 Õ;L爞%ÎÓ%pŒäcžÖ–‚}9”(žì:ZY§Îéæ¹á¶¸¶€(ã`§ž³­,ñLM·Ä`·f=è1—§fÔ2‡–2G5Â#‘åŸHn¾ÿq^CÓÈØsÃQ|q½î1‘—îÛ¿ÿ¡j<Ø›ëLÍkœÙxâ sƒÅ¬÷¦ #xl9x Ù\^ꨌ—͔Ҵ½¥hq7Ƚ‡9Õ¸1çg¨uLcee?’cœã–gÆ÷¸hûWµ\"Š“[ À½Ïd…ñ›Â[}ÜÞ]-¥Æ‹ø5ôòÆj?8ìÇâ©(xWÈê¶L×2W5å”î ‰¹Ë[˜Ü릧÷'ƒxcðúZ‰f‡e5LÅû3bcŒ ¬apßfö’µ;ƒ.b8±c‚¥Äϧ7–\@<—Ü¿b (18je™²gì^X÷ͳbåçõ)r~iÿ²Tzz3K ¬Ž]_3åÌ[{fvb?}”‰?4ÿÙ(*8)ú1Cûñrªx+Ç(|‡}Éÿ˜«ŒúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅI«ú¾Ä~"´dÔw¹o«2˜c±ˆ ŒÏ5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚÂ[˜žü¥fˆ+qJóKVÔS¼ ⦒HÉòƒ òU5xõT4˜]žÖ͵x–\dk„orç=ú—EYKmE$¥Â9ãtn-66p±·½A›¡šJ‡½²^¡ì|–vü®ÌªÿêƒL\#‰àhªéó1’F%k|¶¹á·&Ö.ÇU"³‚ò±ÑH÷Ææ6Àµ —w¸€4yÛÈZbàåg9„Ý¢ÃÉË’ÖäËn[_TçáE4Ô²º–¤¾¤9͊ͤn]kj7{¬ñ|Mð`b”Ò:8Ë.h‹œas€p¶ðloè²õœ‚é…-UM4°gË,E€¸<‚àZZ[b@:4ZÚYXKG ø{è¥ÎødˆÄüÏ9œÒ,|­÷·*^§„µ¬€Í³ aïäê$ºüú–žO¤­pìbWÚ*¸e$ÕMN*Zç5ïZ÷ú-ßkzVñÁú0ÿÏBIŒ™]w\‚sýo(5Þ°=K{p¸ÈØûGPú‘¨úN.'“uÞr ê^ÐUE4Â*†C&p÷4ö j,M· ¸¤\!Â./°»ŒÇ”4Ý®¾â ‡–þð¤C€A è]WY-!ˆÂÈŸ ´l<€€ ¶€E½ktxPk#ÖUTº9ö¾g6ã-ì,ÖÊuµÏ)ÐX,šï9Î?Àe&»ÎG³ð£ó8=rÿ5è‘ùœ¹šô@DDD@DDD@DDDANyä¥c«Þa³\!îknãMÄ+]T@Bë‘ {Èôm‹M‡?­I6%<¾Yk%dlœã!° >;UÒfí ùý>Rì²:ŠjÙ*ßHæJÙv9%’âÄ€\n. Ž—ç+ ŸĨÝ=#¸¤Tò°Ç&Í[´­êAÐqÚ®“7hSŽÕt™»B¸ÆSNé°¾=„O,”ôоJ–¹î”„’n"çŸÕ{õˆ7ñÚ®“7hSŽÕt™»B´" üv«¤ÍÚãµ]&nЭƒªé3v…8íWI›´+B ßÇjºLÝ¡N;UÒfí Ј7ñÚ®“7hSŽÕt™»B´" üv«¤ÍÚãµ]&nЭƒªé3v…8íWI›´+B ßÇjºLÝ¡Z¤‘ò»4sÝÎãr±Dy­/±j#<֗ص6Ö»†˜«_ôÚ0ím¡/º¹T”ã@‹…/õt“Ã;#«uNGI’´G «|¥ìÙÜèZ./+žâÚ\òr®%‰â Ä&d”ÒÊccˆÙÙ›ݧ:èC ÃZ©W¿¢|²9ûw6W—¾#;ön'Sv^ß¹Fð†Gâ"–<>i×G²1¯9\æµÚY¥¶â÷p;ôÝx±ð†®Ž‘’ÕÑ:Hd–xã˜JÛ—5Î ÛA•¦Ç]Úuppz3\êÀÙ#Ë\ö¶W<´Y¤´,=ÁGgp¶Hçì¤}ÌŽ |ÏsZ_ô‹A6뻵¸Ì°b­Ã©¨öõkÒéCÏ{›-“ÝLëN!D* .„—½†7KK^[­´ääU•œˆ‘5+ ês4™&©‘¯6Ík<GÒ<†ãE;¡~…CK#£t.s¶`†‚ç/­…ì/Ì‚z" """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5ê›2<áôÅÏe-EHŽw°à,r‹×u‡Ûɽ»^׋±ÁÃÐn²Q𜂅õSÓSº&l¼¬®vFžK ØtUœ$•Æž–‘Èþ1;v‚6›Ng[Q¾À}¥Ú.wĦØÐÐÎ,b‚fLéZëÄèÚÓ©6»]s¿UŸÅ*qzvESDÆVÓÂæ #qk/µ$€3“ÑÉͨv(¹CÂR\:Ià ¥’ig=¯sæy6#Év[ß[zTš¼W¢’ªšIf ÐäöG½¤˜—[&ŸGìAÑ"ã*1Êù¡šLЖÒÇTÉct.h”²6¸\g9l]k\î;¯¥ÆŠÔUO稡O4±ENÀí§‘}s^Äù:Œ¢×ßÎh¹ê¬j¶ú ÇЊzjÈiÌoÍ´x‘¬7ö›hocº×1"Ç1‰ib”Í…Âça⸵ì}¬GÑúCM÷w%À±ÞC¬EË¿ÄA†éÉŠ»ìÜàcÊÈYÚ˼óXƒe9¸ã¤Á±,R(Øè)„› › 2s~bàGÙ}n‚é0üc”8cq Õ/§uKäÙ¿+Z°ËŸ[Þù³nDn?ˆÍC-tM¤d0PGXö¹åäµÄ´€“£¬}EN‹Œv#W†×ÕšGK=D­d²µÍþR ùZ.çuì7+j,Z®\EÔsšWäª|| €CakïbMÜAÛw¥ÛÈ£lqµ¬c@kZÑ`ÜY.~“¬®žñ:S±’Jçås³5²½€6ÆÚµ ß_Q¾•’cø¥E3¡/†äµ x§sr7hÆÛWÝÀ‡oòw5Ð;4\ƒøA_XŒœ>8è ’IÙ¦i`sy$†o±»Žåf1:ñ;äwâ­­¡ŽÎà\›5ì-}Ö7¶ð‚ñkå á4ÍHòNòÞEBò+1œœXׯ%ªü˜”Ø‹êm¥ÈûJÁ7ƒ=þ‚2\Ö¶*¡³.¾KLÀé°Ñt@?;‰sK4ÊÔsÜßT- ¡¤m[ªÛK©p³¦Œäz]¿-耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]ªFS Rzî5UTæ6E C¢Ù6Ú;É ›ïò¯èWj V ‡ÖÌéª)ZùÐǸ €½±×yÞƒš«ªŠ—eˆmc’‰^Ã+EXŒ;È \´ }&ÛÕµ6/SNk·˜¹Y]cž¡ìû,ü¹ùÃéŒqxíZÖ,C€¢ûƒ£i¸§`7w(qxÿäIûPTTcuðÞ–:FOZ* FFSù6ÉpáÈà7ò)ïÄ&‹–º¦C4q=Î¥® ‹î±#’ûÖêŒ.†¨;oLÇæJNãœ46÷ç°om, ¥â͉»¹r[B9Ps\¨­ee]&*[ZÙžé#`Ý™¯$ý+Ÿ$h2,‡Ó²gãURÖÔÀúyNÎARö² !c¯“6[I±<ªÖ“  ¡ÓÓS1“8é5. ÛBN¿áåä˜>-KêL#Üó˜ÙÄ5±ÐPcUn¢36 ÓІ¾@ÜÑ“‘·;ô³G-Ï*‹ã$¼cŸ!“S½—‡;¡ûF´9úÝtÔ\ ·®Ž|:’ ÔøADԔ즛#ÍCIˆNatí’Æ¼j—ÓꑹWPâSA'ƒé„ÜaÕ%®‹›;©Áˆ<àIswÚæú‘ȯê0úJªVSO d……¥­uü’7wßÒ¢M€ÑÊiš#ka…î³R\KrÞ÷½ý>„ÎámC"t¯¦ŒxÀ’È35îiÁ¹ZSbã˪–ì~®*×Ë.ÉÅí†/åA oÐîÔrs©çƒØC˜#41dˆò †å…·r¯YÁü%Ž{…7{\Ãqqg}-ëØ]¸M]}K%ô|Yí#/”ß(@s­ïV*=% 5 )¢ƒ¿RIûJ€¤×yÈöqþ£)5Þr=œ€ ™Áë—ù¯Y1ïáìqk†â ˆXÇæpzåþkÑéj¦™™à{äcC[~{ úTWA §dîŠ33kd-šðð¶*¬k«¢}TQA$ÕSl†ÙÅ­I7¸òs —&A6m­ 3óÛËÜA8`ø`݇R -ù†îË—›êéêÑl¢†­õqQÓ²¥à‡ÌØ€{¯Îë\îå[Ÿ…íåî&~t|·—¸‚lxM#k¦¬’¥òíX÷Æ £9Ï$ïC÷¬æÂðúˆáŽziY´M|-pŒs4¦á»™WçáGGÁûy{‰Ÿ…íåî Q†SÉ ‚ ‚w<ÈÙ„-%’lúÿŠÚ]gCAO‡áÐÐÀÀ ‰€5ç'ÒwžrUv~t|·—¸™øQÑð~Þ^â žÂ6PìsgÙñveÍk^Ößm£KNæ=†‹dfÍà°YÍ×É<ãS§¥TçáGGÁûy{‰Ÿ…íåî ŸY†ÓÕA$b(Z÷‚ Œ-uîA ‚5(¿=‚E€RSQKMS5L–]«šø ƒ@k-`h N~t|·—¸™øQÑð~Þ^â fRÓÇ|DÛ‚VpI${É?jŠÜ k27 ¢ Ôeì¶¶¿'-‡¸(yøQÑð~Þ^âgáGGÁûy{ˆ,…aÒI ¥sâqtnt-%„œÄƒm õõê·ñxlFÆ;í-”}+ß7¯Òª3ð££àý¼½ÄÏÂŽƒöò÷YÕÐQ×µ­¬¤‚ 4Ý¢hÃì} 6SÁÏg lÙ´±™ZVé æpU9øQÑð~Þ^âgáGGÁûy{ˆ'Ôa8u^^3‡ÒÍ”¸¤-u‹ÉÔrêDTðÀ†(ã¡ 1 h4N@ª3ð££àý¼½ÄÏÂŽƒöò÷]¢¤ÏÂŽƒöò÷? :>ÛËÜAvŠ“? :>ÛËÜLü(èø?o/qÚ*Lü(èø?o/q3ð££àý¼½Äh©3ð££àý¼½ÄÏÂŽƒöò÷]¢¤ÏÂŽƒöò÷? :>ÛËÜAvŠ“? :>ÛËÜLü(èø?o/qÚ*Lü(èø?o/q[PG\pçMˆ v͵ÈNç9¹m{Ü€oö ÚŠUkYS!cY-çhÿBWœpþ¢Ÿ²#"Û>+3çq0›f‘­h¿Ú½‡Ž¢1$,¤‘‡s˜Æ~ЃJ)|gɲ¦ÍkÛf/eï?¨§ì‚Ȥ:¼0]ÑS4\ ˜ÀÔè¼pþ¢Ÿ²#"ί|TsÈÈ)Ùœ?$7€«p9¤©À0Ùæy|²RÄ÷¸ï$´POgšÒû¢3Íi}‹QRaÿ¥Ø×°¥þ¢»T˜év5ì)¨‚íI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DIŽÅ0?ýaþ[•Ú[‡I_ˆá’6X¢e4æY%÷e"ÂÀ›Ü žŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêÊOÿÆl?Ñ8´]:ŸîÉÝYK²Ž‹dÙÙ+Œ™¼€í½ Æ›Íë=ˆülQ—¯«e[+Ù,Ÿ’¬‰…ïqÎÝ ÆFõF1ðexë%|øKadO“Ž6[åü̻쩪ªë(8ÃQ ¤¯ ša¤qþA„X¹¤tÔä«oÕÇÁ”ñ‘½QŒ|AMS_S E ²â-²ÆØæ®Ž0Z#Ú:ÎEìÑšÙ|«Iqʾ-Dщœ²I9mE£ˆÔ1…¡¶ÌÒ 9¿ÂÝm¢´ðëxÖßÁ¸ïÑ˳â§'®ÜëoŒêŒcàÊdc²bÓº§Êêª!cm¥Æ\nFcåçÄ’ÇUôIã#z£ø2ž27ª1ƒ(,ëÿáÕ^ÅÿèT^þŒa?ú8Pj±ýµ$Ñ7ÅÞÇ4^‘Ö¹ ÊH8=†Ã+É#¥‰¯k…‹H` óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_æ½?3ƒ×/ó^ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_æ½?3ƒ×/ó^ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_潌˜ÒÂ#‡=Œ—ü¬lµäq9Àî ý©³ªè¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@gšÒû¢È±ÑCoË‘485ÁÖ6Ýq¢ÅaK--]MWŽYê2½î~æƒ` rŸ©fˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼µO1žc!k[pVÞÀa¿Ôµ¢" """ """ """ """ """ ƒK&%UGOR‡Æ'‰²µ®šK€à½£µìVܘ—>ÛKÿM0ßø6ÿ¢ƒùmRPFɉsá½´¿ôÓ&%φöÒÿÓRUlÓVTâÒRK …t’9™‰.½€µ¬Iɉsá½´¿ôÓ&%φöÒÿÓToÇêpâ#ÄLdÃRè¤|,$Ê݉‘¹[Èw j®ðùßUFÊ—¾76`$fÌÝ¡¤h/ËëAîLKŸ í¥ÿ¦™1.|7¶—þš’ˆ)j1Šš.a˜TñR¼×m<¸eyÈÒíC˜/{Y^ÅšfDî úWùƒ?³Qü·.Ò‹Ïéý«Ô ÈÓÓ‚A¬nŸùòM…?Lofï’ÐÿÎ;ÖT,J­Ô8lõ,ŒHøÛv´›w ”› ~˜ÞÍß$ØSôÆönù* fãTÓñªšY⑤JÐÍ™c­'~aè6X7„´†)d|Q5‘>V‡°f‘  Æñ£€: è¶ý1½›¾I°§éìÝò\ûñø£‘°:г<·%8cs¹§5ô²ä»yMÛ¯®§…4• ‚vK… È×åiŽæÚ‚à]¸ýëò_D&Ÿ¦7³wÉ6ý1½›¾J«©’©•K^:‰#u‚˜ƒDUTVUÓÂâþ*ñkKAÓÞ¦ÓÀ'sxcZÒââ Óì\ö ÿÇõMþ[WIIôj}‰ÿP°§éìÝòM…?Lofï’Œˆ$ì)úc{7|“aOÓٻ䨪±aG‹¶šVLèÐliß)ÍšÚäÃÖ¡xÕMOÒ¤<ºIådL DìŒ v…¶Þ4ß®íè:­…?Lofï’l)úc{7|—68A. ’h%ŽNØ£»œç‡ž_Ùôºj¬h+£Ä)̬ŽXË^c|r·+˜á¼O´\ ³ØSôÆönù/ 3Z\k`/ù·|”u„ß™“öOú ÓA[!C\!Â9EÛ›}®¤ª~ þŒP{?ù•p€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ#a¿ðl7ÿEòÚ¤®f«TÕr5òâØ¸ÈÆÆÆ²¤5­k@ÈÿJÑâ[c_ýuªVéëUdô²†dqˆ4‡ŽK‡.9ý*‡Ä ¶Æ¾/û'ˆ=m|_öAuI‚AJè¤ÛM,̙ӾY ¤yinºs¶à¤QP¶„ÎØæ‘ÑI!{cyE}á¼¶¾¶ää\ïˆ=m|_öO(zÛø¿ìƒ­EÉxCÖØ×Åÿdñ‡­±¯‹þÈ×ÿ‘83û5Ërí(¼þŸÚ·ýBäðîPaØ­>"ÚÜFy©ólÅDáíšZt·1];èäkØlæAæ(üã½eGª¦Š²–JiÛš)•ÂöÑVIÁl*Y#ÙT縗8šÙµ'ÿzÇÅ<#õU_?}È06ª–zªÚšÃJÒ e³ Í 6ÒåB§àu%;XÖÕMfÓº›FFÜÌ9wÙ¢æíûÔŸðÕU|lýôñOýUWÆÏßA"·e^ ÚæUOORÖ±­|yt ÏÈAûC¿˜-Tø>Jµ¥Ì šîkŒ¶$Ü’.§u–)᪪øÙûéâžúª¯Ÿ¾‚Ò–•”•¬sŽÒWJoÎãr·ªOðÕU|lýôñOýUWÆÏß@Á?âøïþ©¿Ëjé)>O±?êN…QáL‘”q½‚Wgy|®y&ÖÞâNà¥MžžX^#•™‘夎k‚ûfŠ“Å<#õU_?}IÌçVžå_âžúª¯Ÿ¾ž)᪪øÙûè.Ö~fOÙ?è©üSÂ?UUñ³÷ÓÅ<õU_?}|ý öó*ái¤¤‚†’:Zfd†!•.&ÃÖu+r" """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""ÿÙprivoxy-3.0.21-stable/./doc/webserver/user-manual/whatsnew.html000640 001751 001751 00000104670 12116121500 023507 0ustar00fkfk000000 000000 What's New in this Release

    3. What's New in this Release

    Privoxy 3.0.21 stable is a bug-fix release for Privoxy 3.0.20 beta. It also addresses two security issues that affect all previous Privoxy versions. The changes since 3.0.20 beta are:

    • Bug fixes:

      • On POSIX-like platforms, network sockets with file descriptor values above FD_SETSIZE are properly rejected. Previously they could cause memory corruption in configurations that allowed the limit to be reached.

      • Proxy authentication headers are removed unless the new directive enable-proxy-authentication-forwarding is used. Forwarding the headers potentionally allows malicious sites to trick the user into providing them with login information. Reported by Chris John Riley.

      • Compiles on OS/2 again now that unistd.h is only included on platforms that have it.

    • General improvements:

      • The show-status page shows the FEATURE_STRPTIME_SANITY_CHECKS status.

      • A couple of assert()s that could theoretically dereference NULL pointers in debug builds have been relocated.

      • Added an LSB info block to the generic start script. Based on a patch from Natxo Asenjo.

      • The max-client-connections default has been changed to 128 which should be more than enough for most setups.

    • Action file improvements:

      • Block rover.ebay./ar.*\&adtype= instead of "/.*\&adtype=" which caused too man false positives. Reported by u302320 in #360284, additional feedback from Adam Piggott.

      • Unblock '.advrider.com/' and '/.*ADVrider'. Anonymously reported in #3603636.

      • Stop blocking '/js/slider\.js'. Reported by Adam Piggott in #3606635 and _lvm in #2791160.

    • Filter file improvements:

      • Added an iframes filter.

    • Documentation improvements:

      • The whole GPLv2 text is included in the user manual now, so Privoxy can serve it itself and the user can read it without having to wade through GPLv3 ads first.

      • Properly numbered and underlined a couple of section titles in the config that where previously overlooked due to a flaw in the conversion script. Reported by Ralf Jungblut.

      • Improved the support instruction to hopefully make it harder to unintentionally provide insufficient information when requesting support. Previously it wasn't obvious that the information we need in bug reports is usually also required in support requests.

      • Removed documentation about packages that haven't been provided in years.

    • Privoxy-Regression-Test:

      • Only log the test number when not running in verbose mode The position of the test is rarely relevant and it previously wasn't exactly obvious which one of the numbers was useful to repeat the test with --test-number.

    • GNUmakefile improvements:

      • Factor generate-config-file out of config-file to make testing more convenient.

      • The clean target now also takes care of patch leftovers.

    Privoxy 3.0.20 beta contained the following changes compared to the previous stable release:

    • Bug fixes:

      • Client sockets are now properly shutdown and drained before being closed. This fixes page truncation issues with clients that aggressively pipeline data on platforms that otherwise discard already written data. The issue mainly affected Opera users and was initially reported by Kevin in #3464439, szotsaki provided additional information to track down the cause.

      • Fix latency calculation for shared connections (disabled by default). It was broken since their introduction in 2009. The calculated latency for most connections would be 0 in which case the timeout detection failed to account for the real latency.

      • Reject URLs with invalid port. Previously they were parsed incorrectly and characters between the port number and the first slash were silently dropped as shown by curl test 187.

      • The default-server-timeout and socket-timeout directives accept 0 as valid value.

      • Fix a race condition on Windows that could cause Privoxy to become unresponsive after toggling it on or off through the taskbar icon. Reported by Tim H. in #3525694.

      • Fix the compilation on Windows when configured without IPv6 support.

      • Fix an assertion that could cause debug builds to abort() in case of socks5 connection failures with "debug 2" enabled.

      • Fix an assertion that could cause debug builds to abort() if a filter contained nul bytes in the replacement text.

    • General improvements:

      • Significantly improved keep-alive support for both client and server connections.

      • New debug log level 65536 which logs all actions that were applied to the request.

      • New directive client-header-order to forward client headers in a different order than the one in which they arrived.

      • New directive tolerate-pipelining to allow client-side pipelining. If enabled (3.0.20 beta enables it by default), Privoxy will keep pipelined client requests around to deal with them once the current request has been served.

      • New --config-test option to let Privoxy exit after checking whether or not the configuration seems valid. The limitations noted in TODO #22 and #23 still apply. Based on a patch by Ramkumar Chinchani.

      • New limit-cookie-lifetime{} action to let cookies expire before the end of the session. Suggested by Rick Sykes in #1049575.

      • Increase the hard-coded maximum number of actions and filter files from 10 to 30 (each). It doesn't significantly affect Privoxy's memory usage and recompiling wasn't an option for all Privoxy users that reached the limit.

      • Add support for chunk-encoded client request bodies. Previously chunk-encoded request bodies weren't guaranteed to be forwarded correctly, so this can also be considered a bug fix although chunk-encoded request bodies aren't commonly used in the real world.

      • Add support for Tor's optimistic-data SOCKS extension, which can reduce the latency for requests on newly created connections. Currently only the headers are sent optimistically and only if the client request has already been read completely which rules out requests with large bodies.

      • After preventing the client from pipelining, don't signal keep-alive intentions. When looking at the response headers alone, it previously wasn't obvious from the client's perspective that no additional responses should be expected.

      • Stop considering client sockets tainted after receiving a request with body. It hasn't been necessary for a while now and unnecessarily causes test failures when using curl's test suite.

      • Allow HTTP/1.0 clients to signal interest in keep-alive through the Proxy-Connection header. While such client are rare in the real world, it doesn't hurt and couple of curl tests rely on it.

      • Only remove duplicated Content-Type headers when filters are enabled. If they are not it doesn't cause ill effects and the user might not want it. Downgrade the removal message to LOG_LEVEL_HEADER to clarify that it's not an error in Privoxy and is unlikely to cause any problems in general. Anonymously reported in #3599335.

      • Set the socket option SO_LINGER for the client socket.

      • Move several variable declarations to the beginning of their code block. It's required when compiling with gcc 2.95 which is still used on some platforms. Initial patch submitted by Simon South in #3564815.

      • Optionally try to sanity-check strptime() results before trusting them. Broken strptime() implementations have caused problems in the past and the most recent offender seems to be FreeBSD's libc (standards/173421).

      • When filtering is enabled, let Range headers pass if the range starts at the beginning. This should work around (or at least reduce) the video playback issues with various Apple clients as reported by Duc in #3426305.

      • Do not confuse a client hanging up with a connection time out. If a client closes its side of the connection without sending a request line, do not send the CLIENT_CONNECTION_TIMEOUT_RESPONSE, but report the condition properly.

      • Allow closing curly braces as part of action values as long as they are escaped.

      • On Windows, the logfile is now written before showing the GUI error message which blocks until the user acknowledges it. Reported by Adriaan in #3593603.

      • Remove an unreasonable parameter limit in the CGI interface. The new parameter limit depends on the memory available and is currently unlikely to be reachable, due to other limits in both Privoxy and common clients. Reported by Andrew on ijbswa-users@.

      • Decrease the chances of parse failures after requests with unsupported methods were sent to the CGI interface.

    • Action file improvements:

      • Remove the comment that indicated that updated default.action versions are released on their own.

      • Block 'optimize.indieclick.com/' and 'optimized-by.rubiconproject.com/'

      • Unblock 'adjamblog.wordpress.com/' and 'adjamblog.files.wordpress.com/'. Reported by Ryan Farmer in #3496116.

      • Unblock '/.*Bugtracker'. Reported by pwhk in #3522341.

      • Add test URLs for '.freebsd.org' and '.watson.org'.

      • Unblock '.urbandictionary.com/popular'.

      • Block '.adnxs.com/'.

      • Block 'farm.plista.com/widgetdata.php'.

      • Block 'rotation.linuxnewmedia.com/'.

      • Block 'reklamy.sfd.pl/'. Reported by kacperdominik in #3399948.

      • Block 'g.adspeed.net/'.

      • Unblock 'websupport.wdc.com/'. Reported by Adam Piggot in #3577851.

      • Block '/openx/www/delivery/'.

      • Disable fast-redirects for '.googleapis.com/'.

      • Block 'imp.double.net/'. Reported by David Bo in #3070411.

      • Block 'gm-link.com/' which is used for email tracking. Reported by David Bo in #1812733.

      • Verify that requests to "bwp." are blocked. URL taken from #1736879 submitted by Francois Marier.

      • Block '/.*bannerid='. Reported by Adam Piggott in #2975779.

      • Block 'cltomedia.info/delivery/' and '.adexprt.com/'. Anonymously reported in #2965254.

      • Block 'de17a.com/'. Reported by David Bo in #3061472.

      • Block 'oskar.tradera.com/'. Reported by David Bo in #3060596.

      • Block '/scripts/webtrends\.js'. Reported by johnd16 in #3002729.

      • Block requests for 'pool.*.adhese.com/'. Reported by johnd16 in #3002716.

      • Update path pattern for Coremetrics and add tests. Pattern and URLs submitted by Adam Piggott #3168443.

      • Enable +fast-redirects{check-decoded-url} for 'tr.anp.se/'. Reported by David Bo in #3268832.

      • Unblock '.conrad.se/newsletter/banners/'. Reported by David Bo in #3413824.

      • Block '.tynt.com/'. Reported by Dan Stahlke in #3421767.

      • Unblock '.bbci.co.uk/radio/'. Reported by Adam Piggott in #3569603.

      • Block requests to 'service.maxymiser.net/'. Reported by johnd16 in #3118401 (with a previous URL).

      • Disable fast-redirects for Google's "let's pretend your computer is infected" page.

      • Unblock '/.*download' to resolve actionsfile feedback #3498129. Submitted by Steven Kolins (soundcloud.com not working).

      • Unblock '.wlxrs.com/' which is required by hotmail.com. Fixes #3413827 submitted by David Bo.

      • Add two unblock patterns for popup radio and TV players. Submitted by Adam Piggott in #3596089.

    • Filter file improvements & bug fixes:

      • Add a referer tagger.

      • Reduce the likelihood that the google filter messes up HTML-generating JavaScript. Reported by Zeno Kugy in #3520260.

    • Documentation improvements:

      • Revised all OS X sections due to new packaging module (OSXPackageBuilder).

      • Update the list of supported operating systems to clarify that all Windows versions after 95 are expected to work and note that the platform-specific code for AmigaOS and QNX currently isn't maintained.

      • Update 'Signals' section, the only explicitly handled signals are SIGINT, SIGTERM and SIGHUP.

      • Add Haiku to the list of operating systems on which Privoxy is known to run.

      • Add DragonFly to the list of BSDs on which Privoxy is known to run.

      • Removed references to redhat-specific documentation set since it no longer exists.

      • Removed references to building PDFs since we no longer do so.

      • Multiple listen-address directives are supported since 3.0.18, correct the documentation to say so.

      • Remove bogus section about long and short being preferable to int.

      • Corrected some Internet JunkBuster references to Privoxy.

      • Removed references to www.junkbusters.com since it is no longer maintained. Reported by Angelina Matson.

      • Various grammar and spelling corrections

      • Add a client-header-tagger{} example for disabling filtering for range requests.

      • Correct a URL in the "Privoxy with Tor" FAQ.

      • Spell 'refresh-tags' correctly. Reported by Don in #3571927.

      • Sort manpage options alphabetically.

      • Remove an incorrect sentence in the toggle section. The toggle state doesn't affect whether or not the Windows version uses the tray icon. Reported by Zeno Kugy in #3596395.

      • Add new contributors since 3.0.19.

    • Log message improvements:

      • When stopping to watch a client socket due to pipelining, additionally log the socket number.

      • Log the client socket and its condition before closing it. This makes it more obvious that the socket actually gets closed and should help when diagnosing problems like #3464439.

      • In case of SOCKS5 failures, do not explicitly log the server's response. It hasn't helped so far and the response can already be logged by enabling "debug 32768" anyway. This reverts v1.81 and the follow-up bug fix v1.84.

      • Relocate the connection-accepted message from listen_loop() to serve(). This way it's printed by the thread that is actually serving the connection which is nice when grepping for thread ids in log files.

    • Code cleanups:

      • Remove compatibility layer for versions prior to 3.0 since it has been obsolete for more than 10 years now.

      • Remove the ijb_isupper() and ijb_tolower() macros from parsers.c since they aren't used in this file.

      • Removed the 'Functions declared include:' comment sections since they tend to be incomplete, incorrect and out of date and the benefit seems questionable.

      • Various comment grammar and comprehensibility improvements.

      • Remove a pointless fflush() call in chat(). Flushing all streams pretty much all the time for no obvious reason is ridiculous.

      • Relocate ijb_isupper()'s definition to project.h and get the ijb_tolower() definition from there, too.

      • Relocate ijb_isdigit()'s definition to project.h.

      • Rename ijb_foo macros to privoxy_foo.

      • Add malloc_or_die() which will allow to simplify code paths where malloc() failures don't need to be handled gracefully.

      • Add strdup_or_die() which will allow to simplify code paths where strdup() failures don't need to be handled gracefully.

      • Replace strdup() calls with strdup_or_die() calls where it's safe and simplifies the code.

      • Fix white-space around parentheses.

      • Add missing white-space behind if's and the following parentheses.

      • Unwrap a memcpy() call in resolve_hostname_to_ip().

      • Declare pcrs_get_delimiter()'s delimiters[] static const.

      • Various optimisations to remove dead code and merge inefficient code structures for improved clarity, performance or code compactness.

      • Various data type corrections.

      • Change visibility of several code segments when compiling without FEATURE_CONNECTION_KEEP_ALIVE enabled for clarity.

      • In pcrs_get_delimiter(), do not use delimiters outside the ASCII range. Fixes a clang complaint.

      • Fix an error message in get_last_url() nobody is supposed to see. Reported by Matthew Fischer in #3507301.

      • Fix a typo in the no-zlib-support complaint. Patch submitted by Matthew Fischer in #3507304.

      • Shorten ssplit()'s prototype by removing the last two arguments. We always want to skip empty fields and ignore leading delimiters, so having parameters for this only complicates the API.

      • Use an enum for the type of the action value.

      • Rename action_name's member takes_value to value_type as it isn't used as boolean.

      • Turn family mismatches in match_sockaddr() into fatal errors.

      • Let enlist_unique_header() verify that the caller didn't pass a header containing either \r or \n.

      • Change the hashes used in load_config() to unsigned int. That's what hash_string() actually returns and using a potentially larger type is at best useless.

      • Use privoxy_tolower() instead of vanilla tolower() with manual casting of the argument.

      • Catch ssplit() failures in parse_cgi_parameters().

    • Privoxy-Regression-Test:

      • Add an 'Overwrite condition' directive to skip any matching tests before it. As it has a global scope, using it is more convenient than clowning around with the Ignore directive.

      • Log to STDOUT instead of STDERR.

      • Include the Privoxy version in the output.

      • Various grammar and spelling corrections in documentation and code.

      • Additional tests for range requests with filtering enabled.

      • Tests with mostly invalid range request.

      • Add a couple of hide-if-modified-since{} tests with different date formats.

      • Cleaned up the format of the regression-tests.action file to match the format of default.action.

      • Remove the "Copyright" line from print_version(). When using --help, every line of screen space matters and thus shouldn't be wasted on things the user doesn't care about.

    • Privoxy-Log-Parser:

      • Improve the --statistics performance by skipping sanity checks for input that shouldn't affect the results anyway. Add a --strict-checks option that enables some of the checks again, just in case anybody cares.

      • The distribution of client requests per connection is included in the --statistic output.

      • The --accept-unknown-messages option has been removed and the behavior is now the default.

      • Accept and (mostly) highlight new log messages introduced with Privoxy 3.0.20.

    • uagen:

      • Bump generated Firefox version to 17.

    • GNUmakefile improvements:

      • The dok-tidy target no longer taints documents with a tidy-mark

      • Change RA_MODE from 0664 to 0644. Suggested by Markus Dittrich in #3505445.

      • Remove tidy's clean flag as it changes the scope of attributes. Link-specific colors end up being applied to all text. Reported by Adam Piggott in #3569551.

      • Leave it up to the user whether or not smart tags are inserted.

      • Let w3m itself do the line wrapping for the config file. It works better than fmt as it can honour pre tags causing less unintentional line breaks.

      • Ditch a pointless '-r' passed to rm to delete files.

      • The config-file target now requires less manual intervention and updates the original config.

      • Change WDUMP to generate ASCII. Add WDUMP_UTF8 to allow UTF-8 in the AUTHORS file so the names are right.

      • Stop pretending that lynx and links are supported for the documentation.

    • configure improvements:

      • On Haiku, do not pass -lpthread to the compiler. Haiku's pthreads implementation is contained in its system library, libroot, so no additional library needs to be searched. Patch submitted by Simon South in #3564815.

      • Additional Haiku-specific improvements. Disable checks intended for multi-user systems as Haiku is presently single-user. Group Haiku-specific settings in their own section, following the pattern for Solaris, OS/2 and AmigaOS. Add additional library-related settings to remove the need for providing configure with custom LDFLAGS. Submitted by Simon South in #3574538.

    3.1. Note to Upgraders

    A quick list of things to be aware of before upgrading from earlier versions of Privoxy:

    • The recommended way to upgrade Privoxy is to backup your old configuration files, install the new ones, verify that Privoxy is working correctly and finally merge back your changes using diff and maybe patch.

      There are a number of new features in each Privoxy release and most of them have to be explicitly enabled in the configuration files. Old configuration files obviously don't do that and due to syntax changes using old configuration files with a new Privoxy isn't always possible anyway.

    • Note that some installers remove earlier versions completely, including configuration files, therefore you should really save any important configuration files!

    • On the other hand, other installers don't overwrite existing configuration files, thinking you will want to do that yourself.

    • In the default configuration only fatal errors are logged now. You can change that in the debug section of the configuration file. You may also want to enable more verbose logging until you verified that the new Privoxy version is working as expected.

    • Three other config file settings are now off by default: enable-remote-toggle, enable-remote-http-toggle, and enable-edit-actions. If you use or want these, you will need to explicitly enable them, and be aware of the security issues involved.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/proxy2.jpg000640 001751 001751 00000130567 11147744254 022756 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ/"ÿÄÿÄ\ !Ñ1QTr‘”Ò"256ARSUt’“²³#Vaqsƒ±47Be•ÁÓ$%3d£Cbc¡´ð&Duá¢ñE‚¤âÿÄÿÄ8Q!13q±AR¡Á24ar‘Ñ"#ðBSá‚ÿÚ ?º­´¶âÐulíÆÐK`c†ˆÙ~çEçùØOwèÑz¡TБoÔ­¥§––gC3pÈÛ¯ƒv‹ü èðƵtï{›Lý¼^ªÀÍOÁ¢õV¦±ò¼269ï;h¼•¨¨Hª$ç©ø4^ªg©ø4^ªŠŠp’JÏSðh½TÏSðh½Ueo•ᑱÏyÜkE䥱#=OÁ¢õS=OÁ¢õTUa´¶Žk;±_‚ë÷E÷}WÞ¡¸­¬$Ù§=OÁ¢õS=OÁ¢õTU“#|˜°1ΠÂû†ú›!bFzŸƒEê¦zŸƒEê­;]²0ü–<¯µ×ÝrÖ–BĬõ?‹ÕLõ?‹ÕQQ0‚VzŸƒEê¦zŸƒEꨨ˜A+=OÁ¢õS=OÁ¢õTTL •ž§àÑz©ž§àÑzª*&JÏSðh½TÏSðh½UÀ•ž§àÑz©ž§àÑzª*%+=OÁ¢õS=OÁ¢õTTKVzŸƒEê¦zŸƒEꨨ–¬õ?‹ÕLõ?‹ÕQQ, Yê~ ª™ê~ ª¢¢X³Ôü/U3Ôü/UED°%g©ø4^ªg©ø4^ªŠ‰`JÏSðh½TÏSðh½UÀ•ž§àÑz©ž§àÑzª*%+=OÁ¢õS=OÁ¢õBЉ`JÏSðh½P™ê~ ªTKVzŸƒEê„ÏSðh½P¢¢X³Ôü/T&zŸƒEê…À•ž§àÑz¡3Ôü/T(¨–¬õ?‹Õ ž§àÑz¡ED°%g©ø4^¨Lõ?‹Õ *%+=OÁ¢õBg©ø4^¨QQ, Yê~ ªÆÜn‚6û¯s ¼ýÀ¨+d,¦†ï äü˜Š7v¦ºï `Î;°¼“ÿⲜSS'Š(‰Ü§‘¿›U…±EadÑž–H¥µ&uÎI`7ø7€¥Zäýl¹U`ÖÇkFÇ1ŽÂÙpà¾ÿ¬oý+ ÍÁ9´ð§mºÿ¥cHÁ=WÖr‚¦‰ø³L§”·KƒXAH s™NÁÙÇNÇxZXãw +Ÿ²´ÔTŸòçßbì¬J‹8Zõ0Z‡g^öF÷žÅ¤“}û×ï¨Ó&è»DÓG¥‰¶TRoÒû7ôV·¾Œ{©á¿¢­-¼“¯¥´ce<:èÝâço}j]¯gXù=“†–®êŠú{\Ósƒ·ÆóGý.m¨vû%k6îqõs2í– ÐÃÙ«Ûá oèÿ¢(µƒû²›ìñ‹Ú Üé©U!IÄ—BÏaúíj³qUÚÕ§ŠgG™Â$mà^.\•šÐic¿Å’µ2ÊðüS=Ù˱Þâq]¹~ú´qKýš0s³-©ÄQåâ‚8ÅE0{š†’ ѽ¹w*×dÒÁ%=UDôñ‰³å¥†ðÁ£@hÒ7OÕr¬2I¿Í8íÃybɦ‰î{'‘Žy½Å¯ Ÿ­bè¶µ0ª"Å¢ŽœÚ³ÃK¬ˆÇ›l±ö¤’¸é|BÓM4PY/«}<²>¬¶ç0\h7 È_t†÷ŒG²;ºw×ËÝšÍãvnüXoÑ~ýÛêÝSïayHÛZÑ–]a®Œ¼ Å籫}TÄÚhšøÈx1–`uÄès@q* O0˜Ì'”Jtâ7Ÿ½|2ÈfÏ¤ÎøøŽ.UTµÝ÷Xž±da ºÕóFØ€œ²ëƒ{-"ï ãbZ]rg®~o9~söswî_õx?ýªw n.s‹œMä$•·dOšÍl‰sw]ƒºíë•¥öSH³…­4Õ3ÁA [Ý\æŒLÅØ~ï€ÓJÊ™¤µ­H)àíÌ5¥¸´Ü;¨“¹ô*ÇÃBi¢sã&\æq î]rŽÉ$ŽC#%{^w\×OÞ¨©IÜ·X‰TðÃ=‘J$Š6šØ mÎ-"óyûÿèU$nŠÑôCß ­fãvÿ…Q^ìÖo³wâÃ~‹÷îßY¾y¤7$ò½ž+žHäRé6ïrD[ÀÊWOABúÙéCŸ&~áû¿ê£RÁ¶ Ìtñ‰YÜù$€œZeû€Ü  ecÄÒ°ak±Ú7†ð_DÒˆs"i^ q»‘:©w1Ö"˜J•©«¦å1p”ÂT¬ L KŒD\%0•+SRã L*V¦ï¥Æ".Â¥anúanú\b"áL*Vï¦ï¥Æ".Â¥anúanú\b"áL*Vï¦ï¥Æ".Â¥anúanú\b"áL*Vï¦ï¥Æ".Â¥anúanú\b"áL*Vï¦ï¥Æ".Â¥anúanú\b"áL%JÂÝôÀÔ¸ÄEÂS R°505.1p”ÂT¬ L KŒD\%0•+SRã L%JÀÔÀÔ¸ÄEÂS R°505.1p”ÂT¬ L KŒD\%0•+SRã XVv4ÔßKäü˜¦àjhÁ,´ôûÊX÷âlm."ðÛÃê*Ðk¿ûPoQ–(g®§Žwàòµ²>û°´'‘t™O”qSQ‹ÄÍ2“7säˆßx;­Ìî›ùyú(ª!¯§–{6®H+]#6;Ž&‚ qÐ¥e™hV²[2Æ«§„DælLºòo¹º7äQQBuã‹Z_k“ŠJÛJ« i©åϾÅm±g¯µæ¥§Œ¾WÌðã'èPlšJˆjj$¨§–: Î0¶ó‰§Eÿ@+ ³-j»Ñ®–;2J˜çs‹ØÉð’; 74é ¤Ýäœuÿ‘ÝÑò²yØí)ê`°i(¨+ëÃçb×?èx/+†ËKº’Ñ}|¯|ôó;±î³þ½ô*Ú×ÚuõO©©¥«|¯7’aw Ѹ­Y”6³l¬É¬ÊŠ‚æàŽI!qÂߤ]¦ïòe‘éSX’iærÕ‚û*˜ÿÊwÄz-õ±:+"ä²2'biÝi.q¸ýÄ"ú=ýTN J.râXRÇEOdÇ$Û"J‡ÊcŠ6<5¥­ $’Zn»ߣé!R8 êY‡±:ÕP?ÚÇ~eXE¡WW×´á™3b›´Õ7Õ:×ÃH8XõNµ¯¹k.;é¯34Íûp¶ú§ZlAÂÛêj6#¾˜Žúḵ'bßTëMˆ8[}S­FÄwÓßMy‚NÄ-¾©Ö›p¶ú§Zˆï¦#¾šóˆ8[}S­6 ámõNµßLG}5æ ;p¶ú§ZlAÂÛêj6#¾˜ŽúkÌv ámõN´Øƒ…·Õ:ÔlG}1ôט$ìAÂÛêi± oªu¨ØŽúb;é¯0I؃…·Õ:ÓbßTëQ±ôÄwÓ^`“± oªu¦Ä-¾©Ö£b;éˆï¦¼Á'bßTëMˆ8[}S­FÄwÓßMy‚NÄ-¾©Ö›p¶ú§Zˆï¦#¾šóˆ8[}S­6 ámõNµßLG}5æ ;p¶ú§ZlAÂÛêj6#¾˜ŽúkÌv ámõN´Øƒ…·Õ:ÔlG}1ôט$ìAÂÛêi± oªu¨ØŽúb;é¯0I؃…·Õ:ÓbßTëQ±ô¼ï¦¼Á#bßTëMˆ8[}S­F¼ï¥ç}5æ ;p¶ú§ZlAÂÛêj5ç}/;é¯0I؃…·Õ:ÓbßTëQ¯;éyßMy‚NÄ-¾©Ö›p¶ú§ZyßKÎúkÌv ámõN´Øƒ…·Õ:ÔkÎú^wÓ^`“± oªu¦Ä-¾©Ö£^wÒó¾šóˆ8[}S­6 ámõNµ„,lÒ~Ó;×¹£ò%ZXt6Õ\·ÖÔEMÅ+Ä®¿èOÐUe'¹7©“nȮ؃…·Õ:ÓbßTë]%$v³<”5Öƒ*ZÒ[!™ýÞyÓÿEÇÕìû?(gTULü5 áÒ×´‘¦ã¾ ê)Í͸ìk]š%ÆÖd͈8[}S­biÀÿÝ·Õ:Ôë:j¦¥¥†l˦måøðéÄá÷è‰nÒZ6-N** ôÇ ‘×8rè?Bæž™‚N6:©èŽikÚ@0ÿ»oªu¬â‚@ùÞù¡ý¦ÂìwE÷ƒ¢ý>°­,+*Ó·s’6®¢ v3®‘ÄxéúU VÈ ¬Š¢lóà•¬Çw÷ìBšzR©% m-=oöƒ&lÚšxª!©ªtR°=ŽÄà‹Æ‚Õ·­*/Uë·RÇ#OZ´x(æ‘·ÉsÚæ~QÛî^ÿkóuG¯MyµkV„ÜTž¦J„-°¤ëJ‡ËÕzíÔiPùz¯]º•ßö¿7Tzñô×Ö8¸½¯ÑÈ˱1÷^/ÜÜ$,Þ“]É“ÕÓÈ£ëJ‡ËÕzíÔiPùz¯]º•ò*û]o'ª†EZT>^«×n¤ëFƒËÕzíè«ôOj­âcª†G?Ö}—«õÛÑ_:γü½W®ÞŠèQ=®·‰Ž®9WX¶M†êˆ%Ï/Ásܺâ|o"µêƒÞÏâuȽí¤§Jòz̤¢Ž!¢ú¡Ä™] q3­á.ç6^wi»åûÊŽâ«Ìæp|¡mÆë¼ J÷Õc•µ±šhlý˜&‘ób…¸žòÜW}ßrÙ-Šý“K¶XêA,“ næ“x[á­ŠžJ€ÊA±§hk¡/>ø¹RKQû*–H`lqÓäè:Ÿ©bÝKêÿjüœm¬[GKLƘ+›PìWµ„]ôßáR*ìQODú˜ç{Ã.Ä$Ñè:4_º²–ª˜Ë ”ô …ñÊ$$<›þ©Iªµ›SM<&•àMº];q¾ýî}AMêê·¡7޲P-º‹‡‹î…2Ê¢¥m vc[޵Æ8‹€½ ¤_¹§ù(6„Û>¬Ôf°9À WÞ@ºõ-öÍ[CHv<,`heÁÛžÈPã7£vÈ´¶SeÙ›& SŠRÉf-ÒGòûïYÐØ¢µ²Ê*…’`k„EÅßMÃsÀ¶ÔÚ"¡•`S`uHÇ~–ÝÏ ùgÚ&†žHŸ‹±°ƒõ¨'òÙ¾ÿè^7#²ÉºÒ–Ši\Ó¿q:K÷.Ð4î¦Ñ 6}Cb/Æ×0=®ÂZn;àî šÒ0MT÷Dù9ïœÐ7-ß¡i´ª…¡$OÌ˜ÜÆ`¼¼ºñàÝSS½„7)è)ªì:XCce\¢GFû®.-vá?QZæ²vUe\u1[ä[öÚå T §©|Ly{Z{bÂÒ~ã¤-7+ éMul•%˜ îìA¾ë…ßÉGÌ®¨=Jæm«‘ÑH̔̕7"ätR3%3%..GE#2S2RâätR3%3%..GE#2S2RâätR3%3%..i¿ %Qÿ¾ûV˜­*ÊX&†žwÇÀ‰ÝÇ.þjMC0YÕnÿ¿ª¯#umJ*Qw]ÿ‚²•ž£³É».—'è›”6­@a{>B1¤Üá£ëqÝú9*»EÖ®U2¹ÍÞ«Œµ»Í9WÖõdy-fUOiàpŒEˆ76Â{kôÜË”£îµÿ3¼z4Ôë7vî¸%ÜLæÔ£ Y3¸±´×ˆŠðG˹°'~RØÒÓZ”æXÙsD§F?ÿèo…ÈÅ ,¶­ 5²˜ t}“ÇüŸZ»Ê,¤Šžª²ØâŒ`|‘›¿þ­?™^ÿ’\Oršr¥–»m6e¥SdQÁfYðjW²ìãt ¼Q½ôøt®45iäõÞY6õ·g>Ë·ÌA·¶W›±á¿Àá¿á\cc„6Ñe<†X[4a-¸¸]%Æå:#þx–©ûhÊ-kVþõvIå=™gdÍ%5DÓƒ“=$t²ÉÈãò²µ¥‘ÜÒqsHq¸WC×E—³öz|YÜÆ{b˱ó—áÁŸÃ›Å‹°»ø»ÛBär.ŽÜ ±¦}™,6…Kê=Lïk©Üb»6Ö  îÝ—â-Ñv#&Ž«ŠÖ!ìdÔfÒu~}ö­X™ÌàlAtW‡ âºðA7°ç_{./™È¶ö¾YÑÑ>:zI1Ô¾¾š9ôò^_;#‘Œ–àÇÈÖ—ö-q ±×ŽÅÀY’]jÕ_äb÷ž¹É¬lÂ,¸ œ,öÚÍ´MCåy–Fš±Rèóa·0‹ÈÄëðŽÅ¸¯gBÓ}§UöQ~oXKc'¼Üˆ‹"áD@r½P{ÙüQ{?Š=×"ú.ŒÜóÚrv}<õ6ƒb§` }ד»ô,êíhlú§RÔHÃ349±î ËÀ Ã¥UÚVE‘eÔVÒ» Í6×An>ÀAx>r㩦~áqïõt}Ö“”Ÿíó¹åiUº´¬µž†Ûz™Û‚_a'E µ‹/°~¥Ä É€ÿÜ¥|u|þUþ±]} ÙÃíÕ<(í¶îoa&¤Û¸Qü©¶5>Qü©ÙÐÍm©áGu·0oMìÑM¹ƒzo`þŠávƧÊ?•6ƧÊ?•;:±íµ<(î¶æ 齃ú)·0oMìÑ\.ØÔùGò¦ØÔùGò§gC6=¶§…ÖÜÁ½7°E6æ 齃ú+…ÛŸ(þTÛŸ(þTìèfǶÔð£ºÛ˜|Y½ƒõ/›s‹7°~¥ÃmG•¬Wͱ¨ò¯õŠvt3cÛ*xQÝmÌ>,ÞÁú“nañföÔ¸]±¨ò¯õŠmG•¬S³¡›ÙSÂŽënañföÔ›s‹7°~¥ÂíG•¬Slj<«ýb ØöÊžw[s‹7°~¤Û˜|Y½ƒõ.lj<«ýb›cQå_ëìèfǶTð£ºÛ˜|Y½ƒõ&ÜÃâÍì©p»cQå_ëÛ*ÿX§gC6=²§…ÖÜÃâÍì©6æo`ýK…Û*ÿX¦ØÔyWúÅ;:±í•<(î¶æo`ýI·0ø³{ê\æNÁ%±hIõ2Ç1gdÀëœá¬x^4ï_»¸ºfdý4õM§§†Ò–Bn¹¶ƒ?¤¹+R£NX]õpõ:)Ô­5t—™¶©Ü×1ñÈö8\æº .#‘hÙ–Ww«Q­_OÔþ¢s ¤®yòÆÚl.ø+–ØÔSVE@ÆÚ0TO+aïªldŽ8F&æÚn¿AÓ£éÜYStf›‹v[l×£/'^:œW™,ÕÙ\Þ¥Fµö:û.[,Tnd7µÙ©ÇMá|°¬«ìzzʹªä’¡¥ñÅÂ<-s4ÞÇ^IiÞð}Ûê, :žGG+mF=¦âÓ^ÀGú+–¶Ÿ Ñœ¡)ÊëS;hh}x©Â ÏZÖŒ$¶¨e Ó¾\=©t2‚ÜûIWgVÕ¶–X3î lÒI"H÷I'piX6ó§~nmiq8Y^ÂnOû•Ìe%%==—%e êšÖLÈ&ЦFËy{^æ¹® o“p"íí:tgJ¿Gi587Š[.މè½%£ÃD”VÛ3ÑNLÖŸÿ…‹œê-sX6•5$®mœÈah2?  î Ó{‰7 Õö@Zµ6ÖCYuÕnÇ;˜èÜûÉ.À÷08’M䆂Nù*æÖî=w£Éî•æ{D©VÁ…];lþ]ç rvâWä]çÉZ9]S.—°`ŽáòŽ“ÿUÐmdžr¬ä‹ ª² ¼Ê.<ßë¥YVÞK‹æLv"¿jäó•g$]¬XØd|‚ЫÆðÑéû¿cé*ÑV$®Ú—yƯ’.‚mK¼ãWÉAX¢Y»j]ç¾Hº µ.ó_$]b‰d í©wœjù"è(P]YLùŸ+a{C\𸱧ÀÝ%_*&wfÒûF|6*M+Ž{ª{?Š=×"uAïgñGºä^ïFn g´ól§Ó“•?…ñªòJÇ6ý³Ke óðï•Án^/Ü»uZe(¿'ªGÙûíXu<©§³ò¾Ïª«¨Šžó¥òLðÆ7äž4“ i+ݦå¤áµ^ÜlyBŒªF2ØÚ2´rvš;&’Ô±mAjÒÕTlf`¦|Rgn¼40é7€龩ª¬»BѲ¦‚ªJKcl°¹¥äˆ:Hå]Ÿ”õv½¡“­ªŽÎ ³éjá¨m=9ˆXK…î7“¸ ¼ i*M” ŸªvÚÚv‹ê("­¨d21Çw½Œ,@n†Æí×›Õ)i]5iÆîÍüþKRµÌgJ„àí­/—™ËOcZ´†!QfVÂé\’íÆã¸ãIúùjKQ,Ùµž³±6G~æ!uãï]Ý»_ y'jÙse%­__h±ô­Ž«=™f6“ˆ“tcp»CEÿJߕ͡’ÒPÑÛÐ>¾ð>¦Pö0V¹ ]÷öE®¸èÓxßT‡IV•¿jÖíßní|5Û‰¤´HFúû¯Ýö<èYµâJ†lœtÍ.™¹—_¥ÂîÄ}j×&²h[ñWÔM]±)hckå{`tÏÓ}×1ºNá¿î]VXZtkGWJá”m‰õ@6æBußAvàÄ ÝTêšJꚪk~ŠÈtqÓÉ´ö¦ýhÒwEúÏJ­WFEûZÕý«_>û¥÷2ê©Â¬bõßüŠ«Rʧ‚Øu“Zm{ÚÒ$‚/qáóyëîú·AZà±-9­z{$ÑÍ dî lsDæíuøEÄ“và+Ьûc'iú¥OUôm†[;•<²T“{‹_¸hð“áUÖÆR¶l±É¸ãž…‘Yïk¤©£µ_Y{ ¯‘Íi¼5¼o\ðÓô‹Æš‹×ÝçgÜlôji9·±ì9¨2Bר´m:éÜf³X÷ÍØ>çaÜ ìo%ÃKEÝÒ¢ "gX°W5•Nš¢«cÅ i^Y ¸öM“µ'-Â4è]}›]šÊì²crŠ™›>ž¤AZk…²:ãÊx àÝ®ƒbZT±d¾MÒË]]RE3"’` p‰.¸›Ã&ó¹y;ꤥ{x|Ö¿2=ž•í|üŽbªÉ´¨"ÖYõTñ¸áš1¤ïFî…‘±mQI²Í™X)°cÏìwàû‹×]ô®ªÒÊWZ6YÃSk2vKhÄ,ö¾f¸9‚ ƒšéÓØø4øI]ÖPº¶ÒŽªË²*,©+k¨&´¤ ‡9”×ÜëÇÓ}×(ŸJÖ¦£Š [þ­dý|‹GA„¯ilü´xì»A”"±ô-¤79…Â3~Ù]r†½Ú¯¢­ê}NÊ‹J”×ÅOM5-%¤÷´8^eƒCAM÷ÍÝp™£}ËÓÐt‰×Œœ•¬Ú8«Ó&¬ö«š‘l͔͕݅œ÷F´[3e|Í”ÂÅÑ‚,óe3e0±t`‹<ÙLÙL,]"Ï6S6S F³Í”Í”ÂÅÑ‚,óe3e0±t`‹<ÙLÙL,]"Ï6S6S F³r^ÌÙLy0±tk¼%álÀw“ÞL"è×xKÂÙ€ï&¼˜EѮ𗅳ÞLy0‹£]á/ f¼˜òaF»Â^Ìy0äÂ.‹ü~ mG~<+¶±òŽ+:ǘ%L¬Ã€‹› ÝxÞ¾îEÂä÷ÉGk¸ø)ÿq ´24i^F‘£Æ¬ç­WôG¥B£ŒG_"Öª·ä®’Y]GÂW½Ä‡¸î¤ß§èûÕ­QMQÕB))0›Nœ^ÝÂàöXkkÛõpä… %%eNŒ–¡Ñ`d—¶ó…ßñÏÒ>õÅY. Êko×ÓüV®*T\ÕM!«ji%’ïfµ+(¸RZõÞçS“V„–ebÔFç6™æç ÁþÑ2ì­ L°³vm›kÎk·üW#ÿƒ‚±i欳ìJ:vc‘ô¸H›OÔ»âú‰³7O_6’/¸»SGý/ÓôªÊ~íß3먬:5Kß²·™GÙùdžÖ¢Ó»¾äÑÿ_ËÊ2¢¡õy7iÔI‡•ô¯v€/,©ðêö¥›E–ö`´,÷6:ø›„µÇÿÁßÈÿàòk~ cÉ»Ržf9’Å_J×1ÂâާBž‹ríQ^íõÒp½¬¤ÿ“Uï·o#Òú•þ­¬®4ÿEÓZÝÇ®ôy=Ò¹ž¥w³›0§Û=tÖ·që½Ot®šÿ/©ó<ˆnד$2~‚»&)j&’¼H÷ËxŠÑ¨‰º$pÐÖ<4nx½ëVÊò¶§ñj¯ê(y nÈú><ßë¢Ä•¥.²Zûß2©FÛ žµl¯+jªþ¢u«ey[SøµWõ¶$ijÄó' r9›vȧ±¬ûN†ªÒަŽÔFd´g•¤±¥×½å¤®Ò\¹Ì±?ú.Ûô þ—F¦íÅ6I»DPX*&wfÒûF|6+ÕBÎìÚ_hφÅIì%ÿTö{®DêƒÞÏâuȽΌÜÏiæÙIÜ Â÷Ú¹¸'­¸r®ªÛhu‘ pEx3S=ŒÕïkäÿ˜ìÎi¤ë_'üÇfsHõ'êj~÷/àyè|f¦z«ß:×Éÿ1ÙœÒ=IÖ¾OùŽÌæ‘êOÔÔüî;^#ÀóÐøÍLô>3W¾u¯“þc³9¤z“­|Ÿó™Í#ÔŸ©©øÜv4¼Gç¡ñš™è|f¯|ë_'üÇfsHõ'Zù?æ;3šG©?SSð?¸ìixÏCã53ÐøÍ^ùÖ¾OùŽÌæ‘êNµòÌvg4R~¦§àqØÒñe‡Âæò¯™ØG@^§ÖÆOùŽÌæ‘êNµòÌvg4RótŽÏ¯RU%''wf­±êèÚV›B„j²mk±å”Vس&tÔyMeÆòÒÓØTAú3:U³_KµuÍ´"¯©ª©ŽwËxkC Ò^Ö’âd> n›ô{‡Zù?æ;3šG©Uå&NØpä½­,V5Œ¢™Ì{)X Ha ƒv‚´Ð=ƒGÒ#8BWOUÚ¶¿è/KÒëÒ”&ãg¶Ë^­{H½J¿W”i?Åzéínã×z<žé\·R}=N¬î<ß멵»]èò{¥a_ã%õ>fPÝ®^HC$Ù#I›¬žžöTÇòA†ç:W\þɧ²mÆïÙìà軨Ä7×’V Õ¹5OPËrÒ¦|¿%ƒn‘ÃF(œ|é'u^õ­Qó–Øä¦þŠšëù%¯½ó!=[ |C}1 õQÖµGÎ[c’›ú)ÖµGÎ[c’›ú+< ¿È×–f[zöü7.sNÉÎ3u–Õ©Wíà”ÂÖÈ7ŽÚnúˆ]"·u‚½î}Eñ±õP³»6—Ú3á±^ª&wfÒûF|6*Oa(çú ÷³ø£Ýr'Tö{®EîtfàÆ{O=¶{•'/|/Yɾõ¬B‡Ü É­žåIÆ‹ß Öro½[#С÷t·ÃËô0Ñ÷¯‡©fˆHòn@µ+Í›-D79®cK¥±‡84Èë¿e —#CN‘º>~1r’Šï;›²»'¢çé-Û¢šgÚ–e§06ëdCv¸ò¼Ú.4ßë£\ÞA÷›EÇ›â½tŠkï%ÅóØ‚",‰ˆ€""¨™Ý›KíðدU;³i}£>g°•´çú ÷³ø£Ýr'Tö{®EîtfàÆ{O=¶{•'/|/YɾõlB‡Ü É­®å?¾Õë97Þ­‘èPû:[ááÅúhû×ÃÔŸ(1´éÚFþ‚¾TÇ4´îlfeÐZüÀoÒè;‡H7qHÉý¼\oäVk瓳¹Üsõ¹;QkmJºižÆ`‰±Ò–Çþ$rmsÝŒÀ·F!á(2a´U4õÔ1¾)Ä¥”t-Ž9‰¿åI¼’4¼“w<킃?ÃrÚ†òóh¸ó|W®+ï%ÅóØ[&?_díI²YâËì©mEž²M[&?_díI²YâËì©mD£Ut»Fû£pï!n_"â ÕKú$fßɹQ3»6—Ú3á±^*6wfÒûF|6*Ïa+iÏõAïgñGºäN¨=ìþ(÷\‹ÜèÍÁŒöž{mw)üh½ö¯YɾõlB‡Ü É­®å?¾Õë97Þ­‘èPû:[ááÅúhûçÃÔ°oùšÁý¼\oäVkçNó‘êW=NÚUTÒº)â³g|onëH’Šð®º²¦y„t6ÝmWɵäG¼Ð\.Ãàq"ÿ ×øW¾e3jëöQËfD#.§›l¡tñH×=ÍÍw“ÒNø»pªŒ›²ßeå}š*K²ID¥Œ²¬ÃM3€ŒÞKŽëâñ¾Z½]J¡B2Ui©7²ýÆ2NRÔíbªŽ¯;”YYS+q2š'UÈâd†ŽPì~œn¸ßá7/K‚¾Ž©å”õpLð/-Ž@âþ…Ä´¤Êx*k©«êi©„ù¸ã‰Ôò€dÑ#N’ww´B’ͦ¶+k²Ðµ…L¾™©¥î qcœ0>&Þ ktÝà¸ÕÅVmXºe¢*|—¯¨´¬M‘Tðù[US Ð/lsÉw<74^®;.scgÇ%%=`©´!›fQS]<-,}Llp-cÃo-{…÷_ôèaiÚ³dÓ…™JÜî~”msªe’g ƒ;"9ç½ÅŘª "âHMæƒÑÕRA] a¨f(Û,syœoaѼæ´ýÚTJë>ZÛbʨ.`¦¢t³ Æf,1°n]ƒ’߸o »EênAG½m˜M¥0³ÅmWY‘¼Ë#MY¦l˜Ë®a‚[…×á:[ŠæhÉì­´mŠ›.S䥴[ŒÆÛ&¦HÓ¤Ô<˜å€ËÚˆ¼8\ÆÊÉÉ*jWÉ=k¦šwWÔU¶=™3 ç|‘œÉvoCš{]"õ:',Ê ¶TSÅ0tWæc’ªY"‚ñwÉÆçGsIhÂÍ%¢àHM@µDE„D@Å[BZœ´«§u ¹] Vu3Û›ifÄçIP\3ñ‚\Ý:{_…Onå™lTZN³çeÕ9¶»9Y+hã•×;CcÜtáuàÝ…¸ow\Ê:vWM\Øî©š&C#ï:XÂòÑvæƒ#ù~€µ‹2Šê溙e{±Õ2NͲœÛc7ƒ¢ì h»sGÒTÜ‚‚º×·lie‚ª{2²SA=tNd¥`:SþÙVQÓÚ¦©Oºð iÚF–¸p ‚ªY‘ö#3Îm4Ây°g*v\ÙòY ³¸±âG·+ðœ7á"°(,ª«j<¤µì˜êìñ_=d•2Õºæ,1ÓQ7‹:'<Ý8Ïhtv]Ì®¶¥­©²Ù5ž!¦žzš™ÝñHç×ÕµÍc1ÜÐDw‚\pî\ûïoBܱbc› 4Ð9ò™5=\ÑJç¹­k‰‘®8³l.¼öNhq½ÚT«.Á²ìLfÌ£e0{C c'h’I ¾à1K!¸]Û]¸pr¶VY[6ŒTuTô¬°:XéfTRˆNeÒ0©/‰à¹­ ¼8hMÊ+aÔfß ò2V &MTrSÆàþÉÔn9Ù\ÀÐæºâ\ãp:û˜rRÆ…äìWË1´óÔI,µÀ´†D÷0a%·5¢æ’Ñ ¾Œ–²DˆÇT÷¹Í~È}lΨih a˜¿8О.ç¿Æuë n³jêm ³²z]”ö½­•‘¼Æ mîÅ®ivQ“{MíÄH½r™)he5¡dYÔm´ìüó,š:ÇTTQÉ+¤lÍpk]òÀ—ƒ‰}ý–1ضî˶££§³éMM™}À’âI7—8.q$’âI$’I%Tõ¡c·ü&VÓøÆ´*!¹¿²Áâæ7Nv­Äì b7À0vPË.IY6Ü027׺€˜žKÃ<±5Âñuä Ç| ¢Ù·m:K^®†Š¡‚šWN)d©t"GTãd:A|1´ÜF2ãxi ö[6Ž[8Yî¦ciZÖ±‘GØÃnà ҤÒÛ‹H\@UŒÈû™ç6ša<Ø3•;.lù,Ç…ÙÜXñ#Û‹øNð€P(äÊëBZ¨é`ž=”¬šYá²*ë[!t’ÇqŽ2×@á™7±ä\[`Ië¬Ê¹kìš*ÊŠWÒMQ%’žKñBç4ÃxðMÛƒsqA“%¬—¶&²:¨ mÁŽ–¶h ¼»åLJHq9νěÞãºâM¬EMO='¬|`8K#\؃ïÜ©ÀZ_àÅ~Œ§´,Ú[R°Õ1ä1ØØø¥tRF눽¯ai¸‘x"ðHÜ$-6 ›gÔGQO öC#3ÒÌù$pyf,Nq%ç䣸’rµÈ+¬Ú²eQŠºøf¤Š¼G"‡G}<8È@h7€Ý.%׋ð®DŽÍ¥ŠÒ–ÐeDÍÃ&\ýÁˆ²ü%÷5£Ø®_p¹KU$""°—´fþaf°—´fþaš©Êžô­ŸAŸá¹[*œ©ïJÙôþ–Ô7‘â¹”©î2ƒ©7êâÎãÍñ\º›[¸õÞ'ºW-Ô›õqgqæø®]M­ÜzïG“Ý+jßþ§Ìˆnד$-KBŸ&)a‚À¯«®–颖­wÊ;p>@íšG_mÝ«óRÔöô¿ÖQrÄduÿŽoŠõÑc;êkIu’ÕÞù•IÛiO·v§ÍKSÛÒÿY6îÔù©j{z_ë+Œg}1õž/‘6y”råM$fzëѤ¦oø“É$lc|†Hç]õ~¨rÅ笫sOþ†å|ŽÍ\+ÞÁj¥ý³oä¶­4¿¡Ãömü•{Ë•;³i}£>â£gvm.;>Oa+iÏõAïgñGºäN¨=ìþ(÷\‹ÜèÍÁŒöž{mw)üh½ö¯YɾõlB‡Ü É­®å?¾Õë97Þ­‘èPû:[ááÅúhûçÃÔ°oùšÁý¼\oäVkçNó‘ʬ†Ò¬§´ml­„ÓÀø³.piq{ƒã~œÝ£A-næ’¶Ù>Û6Û³ªã·­+E®šHK*d‰ÌiÉyìÓˆ‘»¿¡tuT°ÖÓº Ù‰Ž»ÂAÁi#H ¹úL‰³¡¦¨‚iëfÕºªöÕÍkàXð{W\I$¸é;€ Rj_#L4œ½¤¾[²ž®Ï«vGKM]E4µ,´ÃŸð‡‘ +áo;·boj´du›±òªŠ]«ÌaÇò›]š»°pí¶¾+½£~þÔÜMaÚñOgSØv%§eÄð‹ZºidÀIÇšoÅqÄtâ×EeZÖuS*¨²7#iªc¿ÐT=mâãq÷½z1Ò¡Õ¸µ­œî.å†D÷¸ïþB¿þîeЪŒ˜³jì« ´Õ¹‘Rj*'xåìnrgÈqkI¸< Á¸­×œö—µ‰âuCéÛ+ Ìk^èÆ&µÄ†’7@%®¸øpå[W•?A Ž²Ý³)ä8®lÕq°èqiÐOÍsOÒÒ< -‘SI•Ù5"|™Cd1“7nul`=·–Þ;-"ö¸_¾ð$™]“Q2'É”6C3qÆçVÆÛymã²Ò/k…ûàX(ˆ€""ˆˆ-0ÒGYiT2gM†8c- ™ì’ûûR7‡"ÝgK$ìŽi^è_‚V¶¶BXì!×;²Ðp¹¦ãà øVŠž­¥q0‹vÒÑÿ™çrô“ihÿÌó¹zIf.Í(µÓÒÙRÉ5cæ’/ñ|Ž,ìœÍ ?GdÇ·ëc†è*VÒÑÿ™çrô“Ì]šQnÚZ?ó<î^’m-ùžw/I0,ÅÙ¥í¥£ÿ3Îåé&ÒÑÿ™çrô“Ì]šQnÚZ?ó<î^’m-ùžw/I0,ÅÙ¥í¥£ÿ3Îåé&ÒÑÿ™çrô“Ì]šQnÚZ?ó<î^’m-ùžw/I0,ÅÙ¥í¥£ÿ3Îåé&ÒÑÿ™çrô“Ì]šQnÚZ?ó<î^’m-ùžw/I0,ÅÙ¥í¦£ÿ3Îåé(–•™OOeÕͪD‘À÷´ì©MÄ4‘ûIÕüÈÄͨŠ5mæ49ÍÇo¶?…TÿMe…üÉÅÍ™`ôe·èü7.qÕªûfÅ­²èìÛPÔV@ø š&‚æ–Þ\ö¾ý%vÊöj6a4Û°Z©D‡ìÛù-«U/èý›%NòÆÕHÎìÚ¼¶RÐÒP™ö%$ùù]<Ù˜Ã3’;¶{®Ýq¸^N’€–ˆˆ" ˆ€""ˆˆ" ±ÜZÿF“Ý*rƒlw¿Ñ¤÷J";Š‹]ô좌ÔÕÍKʧHI/301†à{; OÐã}Û«}gøpúL«zÑYþ>“ÅjÆ>ò--Œ«Êº=²Ê"‹k¨­Pij¥Ø“°Ó/€gIÁ'Ê7Œ’?²m×:¡ôpË‘–lÏ|쒊ߎ&Cïl1]iµ† ÀCd˜p0¹ºÖÖÄwV“g[4í§´è)k`kÃÛL-•¡×x_q"ÿ¤¨õ™7aZRÓÖØ¶mLÁOÔ¬{amÀ\ÀEÍ4 †ðÞ[Vå]vd¥v)óÛa$8sïÍáØ•&üÝø1_ûWb»E÷h\ÆÃùm¸ÚÚø3[w‹ûÃôüÖkðÿÜßÿ N÷kµªÉLœ®0켟²ª36sÔQ¿7{V6ñ¡¢óp“´VFÜm¾ÕPíŸ ØìÏv¸{{±vº7w4 ,•M£ÝZO°›Þ[*›Gº´Ÿa7½‡°öƒŒßÌ,ÖöƒŒßÌ, ™ªœ©ïJÙôþ•²©Êžô­ŸAŸá¹kCy+™Jžã(:“~®,î<ßË©µ»]èò{¥rÝI¿WwoŠåÔÚÝÇ®ôy=Ò·­ñOê|Ȇíp4ä'yÔ\i¾+×F¹Lˆ…®É*2] ½ónHà?Å€ÐfãÍí­V¼¿–\_1ˆ–Š&Ço7¶v´Ì7Ç›Û;ZÏ$´Pf5åd’‡1¥ÂùF •9Jwj¥ý³oä¶­4¿¢Cömü•#;³hñÙðØ®Õ$}Ù´xìølUžÂVÓŸêƒÞÏâuÈP{ÙüQћƒí<öÚîSøÑ{í^³“}êÙ…¸“[]Ê/}«Öro½[#С÷t·ÃËô0Ñ÷χ©`þÞ.7ò+5ƒûx¸ßȬ×ÎáD@ES_nZóCKfVÚ5,‰³JÊSsLqpa&G°Ë¹}ØM÷^/K”vU%%<öl6S§Ä¡+ ~&›œ;#s®>’ à‚AlŠ M·dÑWÃAWiÑAY>Õ<µ l’b7 -&óy ¼+9-K>*8«$¯¥e,ÍÇΙ¡nû︌ s¯Þî´U³å ‹MO%EE¯A1Ni¤’J–5¬˜ Ìd“px³º¥²¶’Hé¤eT.ŽªíŽæÈšö— ö»]£À @oDDªö³:6nÄÎaÑžÃ}߃uhþáýÛþš•uj>Â/zE½’¶GÈÐ ñ» ¿~àš½í¨¥®WpþíÿM?¸vÿ¦­1ñûŒ%_÷îßôÓû‡÷oújt5,žG±¡À³vþ3›ù´­ÉÜa*ÿ¸vÿ¦ŸÜ?»ÓV‹ÞÙclŒ7µÀ8ðS¸ÂVÿpþíÿM?¸vÿ¦­1ñûŒ%_÷îßôÓû‡÷oújѸÂUÿpþíÿM?¸vÿ¦­1ñûŒ%_÷îßôÓû‡÷oújѸÂUÿpþíÿM?¸vÿ¦­1ñûŒ%_÷îßôÓû‡÷oújѸÂUÿpþíÿM?¸vÿ¦­[O¹UŸ`ÿt©R»¶¿¸jÈ”µTì|öVk3£vì;º/¿Fêû4ñS°>iY šÀç¸\âѧÂI -6‡èÌûx~#U#µ{¿Ü?»ÓOîÝ¿é« gd7cÄIÜ iqäV&®¶2ehÎ-A&û®»wwwy[¹\$îÝ¿é§÷îßôÕƒ§‰“2HÑ#ûV_¤îϸ¬vT9̺ûðâÀpß½Šë·tnîèL|~ã û‡÷oúk}&ÖgNÂØ™Ì:s8o»îðn)ª,Õ§û }èÒ÷Ô-bRÂ^Ðq›ù…šÂ^Ðq›ù…Bæj§*{Ò¶}†ålªr§½+gÐgøn[PÞGŠæR§¸Ê¤ß«‹;7Årêmnã×z<žé\·RoÕÅÇ›â¹u6·që½Ot­«|SúŸ2!»\ Œ‘¯m.IR‚ÐCsŽsœì!¥Ó¹­¿è'çÁ‡ê]{jß#„º0ÒL2çq¾í7 :‹·•ERÅ&FÓ¶âÓ$²H\œBSqû°£Bè¡…Ñâ/šiœ|/»@ú€þ—ÿÑg_{./™1ØÈˆ³$ÓUúÿfïÉKQ*¿CŸìÝù)jbÕKú$ìZy dõÉS,N–˜Éžyáhn2_€µ‚ᜠ4^zK€ˆŠ ˆ€‹uj>Â/zEñ›+§…Ï€¼èÍ—‚ì1Ünï8_õ­˜SÚr½ì˜µðÆdNx¼߸ø[6§›IÑWi½…SH‹Lk¯ª§sâ#äšb/Â1¸îpö%›Û—xfÈê°öÀÖÈ%må°A¸€¿9}ÚG€x ÞT­°‡Ä©æÒtSl!ñ*y´e‘8‘š‘²TÌgƒtámãüIáѸG/Ò´¶7:•Ùèdu[£ni´à¶»±ì¯Ý#}NÛ|Jžm'E6§›IÑL2ÈbF–B6k‡"ìeÑp›÷_¸á¸w®Þ[¬èÛqˆónhAƒ î¸^~Ÿ­6§›IÑM°‡Ä©æÒtS ²‘)]°‡Ä©æÒtSl!ñ*y´Ã,†$JEl!ñ*y´Û|Jžm'E0Ë!‰‘EÛ|Jžm'E6§›IÑL2ÈbD¤Qv§›IÑM°‡Ä©æÒtS ²‘)]°‡Ä©æÒtSl!ñ*y´Ã,†$JEl!ñ*y´Û|Jžm'E0Ë!‰”[O¹UŸ`ÿt¦ØCâTói:*=udsYõ1GI{âsZ64šIïÙS»­D6¬o´ZçS02…•§? Í=Í£8ÛäÓ¢öÌxIh»MËí¡ú3>ÞˆÕ)E´/Ø †¹Øe‰Ä5¥Æàö“ iÜ #µö3åXpš'ß+à_18F‹®: ÇMÞ§KÉŽ†6º9KŒÁýŒn$ uæá ‘¦íWoÛ|Jžm'E6§›IÑL2ÈbF537;JìŒÝÀµÃÀ7ÈѺ´à~<ßÊߟŚÁòwc¾üWov]¶î¡HÛ|Jžm'E6§›IÑL2ÈbD¥NêÓý„¾ôi¶ø•<ÚNŠÖÉ…E§ØÉƒY €—Äæ ÉeÛ o)5´†Ó',%í¿˜Y¬%í¿˜T,fªr§½+gÐgønVʧ*{Ò¶}†åµ äx®e*{Œ êMú¸³¸ó|W.¦Öî=w£Éî•Ëu&ý\YÜy¾+—Skw»Ñä÷JÚ·Å?©ó"µÀ…ð¹ù#Fá<óh·ŠýðºŽþ7#z+ÈŒÿZ4x$Œ7×ÂOø¯úWCý§ÊÅìÏIV½ºÙq|Äv#îÇ —‘½Øîá3r7¢¾iò±{3ÒOí>V/fzK-E¥Ä.|ò¹§u§)*$’TC¤s¢sZ/ 0‚G×z”¥XVš_Ñ!â7ò[VªoÑ!û6þJH7*Xû±hñÙðØ®U4}Ø´xìølU–ÂQÏõAïgñGºäN¨=ìþ(÷\‹ÝèÍÁŒöž{mw)üh½ö¯YɾõlB‡Ü É­®å?¾Õë97Þ­‘èPû:[ááÅúhûçÃÔ°oùšÁý¼\oäVkçNðˆˆ" ˆ€"äm¼¦’ƒ)e³]oXvD1ÑÃ;]iD\éœ÷Ê×ü´bà#o€öËe}~P2¢ÆØ6µ‹55§+ad¢Ï‘ãôwÊdiÜæ¸Æná¤Ýy›uH¸*Ü®¯ ¯µi¤¶,CUg9ŒŽÍ09µ5îÌG%Ñüµí/{ÜÆŒ»GlWlÊœuÓRæ&¸™&x³ä߈¼ak¼./#ÀÝô°7¢"‚B" ˆ€-YeA…”ÓLæ°<–€$ × â¾l¹¼ßSëGÓHû«Qö{Ò)JÎ˸ª»"ì¹¼ßSëGÓM—7›ê}hújW…ÈX‹²æó}O­M6\Þo©õ£é©H˜–BÄ]—7›ê}húi²æó}O­MJDIJ"ì¹¼ßSëGÓM—7›ê}hújR%ÖDÛæEÙsy¾§Ö¦›.o7ÔúÑôÔ¤K¬…¾d]—7›ê}húi²æó}O­MJDºÈ[æEÙsy¾§Ö¦›.o7ÔúÑôÔ¤K¬…¾d]—7›ê}húi²æó}O­MJDºÈ[æEÙsy¾§Ö¦›.o7ÔúÑôÔ¤K¬…¾d]—7›ê}húk kä†'Ë%Hc\ã|zÝýµ5E´û•Yö÷J”Óv±ém%-UŠxs…ŽdÖ†¶ëÉ$º@Ý+ìÓÅNÀù¥dl.kžàsˆkFŸ $<$€´Ú£3íáøUŠ»D½ƒeÍæúŸZ>šl¹¼ßSëGÓR¾‹ÑMÖBß2.Ë›Íõ>´}4Ùsy¾§Ö¦¥"]d,EÙsy¾§Ö¦¾ÅV_P!}4йÌ/å¤qÇ|)*,Õ§û }èÑY÷î‰K {AÆoæk {AÆoæKªœ©ïJÙôþ•²©Êžô­ŸAŸá¹mCy+™Jžã(:“~®,î<ßË©µ»]èò{¥rÝI¿WwoŠåÔÚÝÇ®ôy=Ò¶­ñOê|Ȇíp d-C’ôÞDtÆâÒ/×n»º/»rõÓ.O!¢¹5­#ϰÈH{³®¸îv\F‹ï¾ó¸º›äÇÚ·-ÜZn»wsvýoi¿À³¯½—̘ìFhˆ³$ÓUúÿfïÉJQj¿CŸìÝù)JbÕMú$àN–øxq~†>ùðõ,ÛÅÆþEf°oùšùÓ¼""ˆˆ" 9ú³Wge-M}=“hZ ©¤‚±;ZÃæ:L’´’s»× ·M÷ o¥’×u“[43PÉETêƒO8cžoŠX®%ŽsGø˜¯î]¢ý¨€ƒCglÛR£;gÕ6£°] q]»§ü;ïÑ»w‚õ½‘T ù¦uN*gDÆÇl åÎźq0]àÁô•½D@DDXû«Qö{Ò)J$‘Ô²µóC/kãc|…¤\| >2ûœ¯àÔÜáÝf®U;¼øÃw…EÎWðjnpî‚g+ø578wA0²nJE9_Á©¹Ãº œ¯àÔÜáÝÂÅÉI½¤(¹Êþ MÎÐLå¦çè&.JE9_Á©¹Ãº œ¯àÔÜáÝÂÅÉH¢ç+ø578wA3•ü›œ; ˜X¹)\å¦çè&r¿ƒSs‡t %"‹œ¯àÔÜáÝÎWðjnpî‚abä¤Qs•ü›œ; ™Êþ MÎÐL,\”Š.r¿ƒSs‡t9_Á©¹Ãº …‹’”[O¹UŸ`ÿt¦r¿ƒSs‡tª–×ÔRMb™¹Æ9˜³î7^.ñÅY¢Ôl´ZçS02‰•§? Í=Í£8ÛäÓ¢öÌxIh»MËí¡ú3>ÞˆÕ)G¬ŠI©ðÅ„¼=Æàp¸;v㼫¨—°‘§ÿ7ÑEÎWðjnpî‚g+ø578wAN.JE9_Á©¹Ãº œ¯àÔÜáÝÂÅÉJ,Õ§û }èÓ9_Á©¹Ãº äqÔ¾µ“M,k#{d…Ä’Z|-*%b¹-a/h8ÍüÂÍa/h8Íü©c5S•=é[>ƒ?Ãr¶U9SÞ•³è3ü7-¨o#Ås)SÜeRŸÕµ“õÏñžºk[¸õÞ'ºW3Ô§õmdýsüg®šÖî=w£ÉoŠSæD7k"3ýhÑàŽ2ÜS\KÈ?â¿è]öŸ%µ=I½çÑq¦ø¯]­uü²âùˆìFí>J/hz)ý§ÉEíOEoE‹dŽ¢XÝ›Záq!ä>«”¤DHª›ôHxü–Õª›ôXxüU<}Ø´xìølW ž>ìZGL æ"ë„Bæ·t¸ÞpáfÚ•vœ¦Ï°-¶ H[#ª-JYf•ø¦š<Ùi|NiŒÀæ’üNuâóx%ÓbµK–Ý¡`Úvü0Ùôô4GTiÞ×É,Í4‘T:f—Ô8à•·µ¬ìCqcnÖ!m R¾€ÕºxÝŒxŽ8K›˜¯%ï Çs®h' íh½, $DPHDDI$©}ká†HXÖFÇ’øË‰$¸xÂ/zE)Y»Jä\Ý ¦æîé¦n¿„ÓswtÔ¤LL›suü&››»¦™ºþMÍÝÓR‘11b.n¿„ÓswtÓ7_Âi¹»ºjR&&,EÍ×ðšnnîšfëøM77wMJDÄň¹ºþMÍÝÓLÝ ¦æîé©H˜˜±7_Âi¹»ºi›¯á4ÜÝÝ5)"æëøM77wM3uü&››»¦¥"bbÄ\Ý ¦æîé¦n¿„ÓswtÔ¤LLX‹›¯á4ÜÝÝ4Í×ðšnnîš”‰‰‹suü&››»¦µTº¾ž’ióôÎͱÏØp¾áާ¨¶Ÿr«>ÁþéSvˆkQ)G¬–HiñE„<½ŒÂð187rñ¾¾Õì¼Ëvg;zü9¼c9ußµƒÞ î¿BÂÐýŸoÄj¬v¢^Á›¯á4ÜÝÝ4Í×ðšnnîš”Šq1b.n¿„ÓswtÓ7_Âi¹»ºjR&&,EÍ×ðšnnîšù•,­d3I ÚøÞðYi Œ¥¨²wVŸì%÷£DîCV%,%í¿˜Y¬%í¿˜U,fªr§½+gÐgønVʧ*{Ò¶}†åµ äx®e*{Œ êMú¸³¸ó|W.¦Öî=w£Éî•Ëu&ý\YÜy¾+—Skw»Ñä÷JÚ·Å?©ó"µÀ½çÑqæø¯]ç2¼ú.<ßë¢Q_{./˜ŽÄ}EñE¨¾"êÕMú,ìZK`ï9þ¨=ìþ(÷\‰Õ½ŸÅë‘{½¸1žÓÏm®å?¾Õë97Þ­‘èPûy5µÜ§ñ¢÷Ú½g&ûÕ²= p'K|<8¿C |øz–íâã"³X?·‹üŠÍ|éÞDDþPØUöÅD/¦¯¥¥dM!®0Î&žÈ bž#€ÜÛÛ¸KA7Ü.Ñfäe==b­î™ŽyPTUR9ís‹È‘Ù÷>Cò:÷8ÝŒÜæþ܃—¥ÈÊÚœµ,x¥¨ž3$RÇe°EÂ×Ü/Ââ-¸ÖÓPl-‰˜ù •²ðcwø¹ìö+ï¿üNÊíÏ×hS‘EÉ(ÎGدŽX_M3à’' ’®gEÒÂ#Œ» ]‹œÑ€6æ’ÀÜ­j© ®…°Ô3m–9€¼ŽÎ7‡°èÞsZ~í+z ˆ€"",}Õ¨û½é¯þ·Tii ê Ì©š9„04‚$n´ï•óbMç ŸV>‚³³ï*®‰[ßRåÊ.Ä›Î>¬}Ø“y§ՠ˜VdßäJEbMç ŸV>‚lI¼áSêÇÐL+1‘)>ïüþJ.Ä›Î>¬}Ø“y§ՠ–Y‹ü‰H¢ìI¼áSêÇÐM‰7œ*}Xú e˜¿È”Š.Ä›Î>¬}Ø“y§ՠ–Y‹ü‰H¢ìI¼áSêÇÐM‰7œ*}Xú e˜¿È”Š.Ä›Î>¬}Ø“y§ՠ–Y‹ü‰H¢ìI¼áSêÇÐM‰7œ*}Xú e˜¿È”Š.Ä›Î>¬}Ø“y§ՠ–Y‹ü‰J-§ÜªÏ°ºSbMç ŸV>‚ÂZ &‰ñI_RXö–¸]waJI;܇v¶ª© ®…°Ô3m–9€¼ŽÎ7‡°èÞsZ~í+ Côf}¼?ªRÕQ¨‡6^ævMpsn¼A Ð«f‰{ ·^|?zoý .Ä›Î>¬}Ø“y§ՠ¦Ë1‘+ÿ4¢‹±&ó…O«A6$Þp©õcè&˜¹)E“º´ÿa/½lI¼áSêÇÐ_b¤,¨>¦iœÖðÐ$¸Ñ¼YwîÉ+ {AÆoæk {AÆoæKªœ©ïJÙôþ•²©Êžô­ŸAŸá¹kCy+™Jžã(:“~®,î<ßË©µ»]èò{¥rÝI¿WwoŠåÔÚÝÇ®ôy=Ò·­ñOê|Ȇíp#d/yô\y¾+×D¹Ü…ï>‹7Åzè”WÞË‹æ#±DYˆ€-TߢÃÄoä¶­TߢÃÄoä€Úª#îÅ£ÇgÃb·U÷bÑã³á±D¶óŸêƒÞÏâuÈP{ÙüQћƒí<öÚîSøÑ{í^³“}êÙ…¸“[]Ê/}«Öro½[#С÷t·ÃËô0Ñ÷χ©`þÞ.7ò+5ƒûx¸ßȬ×ÎáD@EÌ[ô•“Z¢I(­zêà V]~ÅtR‡?8çü¬Xƒˆ7K®Àí ¿²ÑgZv…£1³ljÖ@Ê8ùd´àuL¸4ј‰lŒÓÍ..~=»¦Är.VÀ·ml¨kkiECGÇÎSËç‘ùÈ"œá=º& °émþ"³%­«BL³å³)˜ø¨¬êZw±Ï”É‚åV}ƒýÒ¦2wZÈiX”¢ÚìPœÜRÄÒZâÓq{AÒ4î^ËÌ·afs¹Øñg¯Ã›Æ3—]ûX1]à¾ëô,-Ñ™öðüF¨ŽÔKØÆ×ÃãÔó™:Iµðøõ<æN’”‰ŠYŒ(‹µðøõ<æN’m|>=O9“¤¥"b–c "í|>=O9“¤µ²OiÄÆ>b×Ã!!ò¹âðYvé;åNQdî­?ØKïF¥6öÒD¥„½ ã7ó 5„½ ã7ó …ŒÕNT÷¥lú ÿ ÊÙTåOzVÏ Ïðܵ¡¼Ì¥Oq”I¿WwoŠåÔÚÝÇ®ôy=Ò¹n¤ß«‹;7Årêmnã×z<žé[Öø§õ>dCv¸²¼ú.<ßë¢\æCwŸGÆ›â½tJ+ïeÅóب¾"ȱõÄ@}Z©¿E‡ˆßÉlZ©¿E‡ˆ?$åQv-;>²©‹ºöŸ Š%°wœÿTö{®DêƒÞÏâuȽތÜÏiç¶×rŸÆ‹ßjõœ›ïVÈô(}À¼šÚîSøÑ{í^³“}êÙ…¸¥¾_¡†¾|=Köñq¿‘Y¬ÛÅÆþEf¾t""ˆˆ ÛB¡´êQ>ÊŽ`ÜJZÉiÜæ‚H1¹¥Ànû±:ë¯7è“%¬—¶&²:¨ mÁŽ–¶h ¼»åLJHq9νěÞãºâMÊ%ÁÊÕd¥nÚ6ªÊ­¢³à7›§Ž –·°hb©Ž7èhYÚ†´ÞVƒ&¬†ÒELÚL1EJÊFÈðDl Ǥ˘EíuøšI- “}²)¹lV ›Ã½ñgã©s¥™òHùX湎sÜKœAc7IÐÐ7ÊÉA!D@Eºµa½"”´ÍGMPðù©¡‘À\ Ø »ïZö²ƒ€Ó{&êVveu¢R(»YAÀi½“u&ÖPpodÝIûIÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJEk(8 7²n¤ÚÊM웩?hÖJQm>åV}ƒýÒ›YAÀi½“u&ÖPpodÝH°§rÚ3ª¤‚ºÃPÌQ¶Xæò;8ÞãyÍiû´¬-Ñ™öðüF©K "ŽhÌr±¯aÝk…àýʳ¹/Z3Ek(8 7²n¤ÚÊM웩OíÉH¢íe¦öMÔ›YAÀi½“u'íÉJ,Õ§û }èÓk(8 7²n¥²:jw—ÃM n"âXÀ ßr+"5³rÂ^Ðq›ù…šÂ^Ðq›ù…RÆj§*{Ò¶}†ålªr§½+gÐgønZÐÞGŠæR§¸Ê¤ß«‹;7Årêmnã×z<žé\·RoÕÅÇ›â¹u6·që½Ot­ë|SúŸ2!»\¹ Þ}oŠõÑ.w!»Ï£ãMñ^º%÷²âù“ˆ""ȈˆÕMú,çÔGcÕÊæˆó]‹éDãž÷8‹šÓþðôv=uu«“â¡ñlJÇgciž™ìµîcd18‡†ºàüÞ®ÅáU±%²/5È㔵sÃ+m=ÓM`Ù³:¦¢šI„šŒ-ss ½ä—&!¸; 7ìËÛJ¾šJê7 Ê(c²êjÝPçÓÇ>QÌŒœàgdÓu؈¸Ü&Àô4UVýuurÐÅ{(l³lgÔæq8³1ù/pkniÑÐÒ©ªr–©Ô4FšÑ¥NkÌí‚Ǫ­ÐZÒYšè -x,}ä89·’ÂLXr.L±µg¡–Ó¤¦¢Š’žÃ§¶%Ž\o‘ØÄÎ0´‹€¼Fy‰£±v;-,ªµ¬ºý¬©e(«™Ð¹“SRÍRØ#j€ÄÃŽbÝŒF!‚üx°´4‚°;TTù9iÖZtu.¬…í|˜™3¨å¤·]ŒE/dÐ ‹4“ya7é¸ròåu¿E’6ý[,ÇìúÍ4QÉòR I*œòþɧ4A`kHÇv3†÷,@EÍËY”¾’ËÙd5•QOWœØÒK1ÆbnjìãKÝ|·ç/h¹½ ¿D•VˆŽ–<ÝšªY¨˜òpµ“ET)Ý!iuåŽÆx¸´GΕ‰`vH¹ÊK~®¢ßmŒc„TÃUS²\pv273¾üwTÓ_x»D·n6õ¿mZ6m|mˆCb祚håuç$z)šÐL>û»^°:4\T9[hÔZ„Cä§‹¨+,Š’C[9…Òl sW Œ„aÐe÷öKu—oÛrdõnZ"Ïöƒ©SFüQ¶a€ç:ç$‘.[Œ^ò+¯EÁ·,­ÃLØ\Êa5uì{,ŠšüPÍ$¹¦¹°¸fÞÖFÜW’ç:¦Ó'm«jÝ«žZŠzj JwDÙ)¤cÝQ‰ôÑJXI- ,t—_qÄ4ai¹`u¸<ºÎ‹^žjˆè+lÊ;&¶ºJ ÊS+et.„›‰v¼µØZü'ïÐìW V½½” ðRLë2¾¦¯€² )˜ßí4ð¹®½òx¨¼8v¸w}Á`vH¢C$´Vi–Ô«¥/‰®|õ ŒÁh¼ßsœì Ò\w Ѹ¸;c(«jì ~Ì«~;aÖÔ6M¨© Á­iL]œ¿: í#7⣢¢°{³•ü›?ìé—9.W[ôY!CoÕ²Ì~Ï¡|ÑSEŸ% ¤’ 9Ï/ìšsD´Œwc8orÀô\ܵ™@+é,½‘fCYUõyÍ$±Ãf&æ®Î4½×Ë~rö‹›Ú ôsõÙGmEU ¦ÊŠQ j>¦—2ü5¥¨Ž ç.axobHvo‡g~…船BÛ¶ìJ¨(«&³ë&­hòÃJø[ D^ö™^/¨¸ö„_Ù^ÙrÕ[ñWÒY:Ì5•OS²¶™¶Ç‰¸3yëˉ–üXî·aÓxX.[f¾{JÏ®Š’VÃGiÓ?ns~N®šÊ#€ t™°K؉ ®›'í­ Q42˦7::y)ݸg œNì· 7Œ.ç²"($""ˆˆÂ^Ðq›ù…šÂ^Ðq›ù„j§*{Ò¶}†ålªr§½+gÐgønZÐÞGŠæR§¸Ê¤ß«‹;7Årêmnã×z<žé\·RoÕÅÇ›â¹u6·që½Ot­ë|SúŸ2!»\9Q 2J¯š6¸>kÁpüW®ƒeÓpˆ½p¨ò½ ><ßë¡T®ÿ–\_2c±¶]?‹× ²é¸D^¸[æ½{× ÁðBú²¹&­—OÂ"õÂÚ op„ZiEÐ7Þ¬T¦ ëU7è°ñä¶-tߢÃÄ’j¨‹ºöŸ ŠÙTÅÝ{GŽÏ†ÅØ ¨=ìþ(÷\‰Õ½ŸÅë‘{ݸ1žÓÏm®å?¾Õë97Þ­‘èPûy5µÜ§ñ¢÷Ú½g&ûÕ²= p'K|<8¿C |øz–íâã"³X?·‹üŠÍ|éÞDDRÃiSÛSÖÑÓRTG5ÒlÕr²€RÎÙ+§– Ly·˜Úç\ËÁp¡¤5Ä !uH—+FȤµ3f LÙ#¿´õA#AºöãÍvsIm÷Ö’4 £É“vDÔ”ô菉(1aÇ‚ðã{Û!¾ùó¥íy!çK*ÕÑäµ’ÆÊ×ÇU9‘¸1ÕVÍ;ã‡|›ÞòèÎ&µ×´ƒ{wZúr^Íu3!s­Îsf6•Fy¸€h—9Œ0ái,¿ -ëÅêáàª~MÙ/†K{a‰ñFìãñ odŽv+ïÆ_œ¿!ŠûÉ*UŸfÒÙtîÆ÷Ë+¥’G\î{ÉsÀ É7àKDD@XKÚ30³XKÚ30€ÍTåOzVÏ ÏðÜ­•NT÷¥lú ÿ ËZÈñ\ÊT÷AÔ›õqgqæø®]M­ÜzïG“Ý+–êMú¸³¸ó|W.¦Öî=w£ÉoŠSæD7kG’.­ƒ&¨fkÁ§3¹˜KÆã¦-:0_áñµ.Š:¹ éXé)*¦a/,nrîK›§Z¨Èš:Wä­$¯¦…Ò9ÓòÀIÇß«Bé6<"c(Š<á —á’ÃOÔHûÖu÷²âù“ˆ«±Øá#œq†Ÿ±Ñpí¾‹ü”ý\,lÁ†6·p¶áv£@Þ"ÍdHZi¿ÁwÚ?Þ+rÓJo„‘¸^ò=b¥rÕMú,\Aù-«U7è±qä¤UL]×´xìølVʦ.ëÚ§ÙAkÚQÒÁ“µT|`7fBø˜÷µƒÎ{@¼Üç]õݸ½MA†“JsQQÏ¿”æâÒJ羜¤žŸ(¬«*SOR+ˆrÝŒfŸ#]ÙŠñ\7A¼î.™pT9+nÓZy-Rû5Å–M4PÎÑÞâÚgÄpöZF'¦í‹¯m¦Ý¶ŽÌ¨¥žž¦XPÆÉ€‡1Žk\ok…íÝß^}HÙêØ]2r",˶†PضMCií+^Ï¢™ÍÆØêjY‹o"ðAºðtý Ér³ÛVM—––ÚZtT9Û27²ª;¥ª¾ìD_uã”**'ÑÒÎi²ŽÒšÈ³[¥³#’¾K<>¦ †Œ/a8aÃ6âæÞAµˆ=#[QjËÔöÇ–¦¦ªŽÔ¨u˜Ú‰˜Ñ¬{ç…²v$\dàZEÛ ‹´*ëMâÈ·öªKF¶ ìYªåžÐ–øƒÙX/5~8Úd†œhpèý²°;¹'Š'ÄÉ%c3°F×8÷\]pß75ÆíàOl^kRÚ³GS=§RëŠÛ{`¯œ¢6Àê#{@}îòX\H$ƵuVÅ©“”¶eE}{(¬ÇQÕ1òO0Ž68 $†ãÂ%¸nÜw…EÐ"òç[R¾VÏiÔ–ºjÃMLêɨêom\àc--©“¢ 43H·ÅhWÉ”f7WSEi‹UÌÍ>ÙœÌiÅAlÂËŒC¼R%$ipœ"ç¥"ärª²Š ¥² µm·Ù–t´un íŠÙž×Óáix ‚/qH:¿ p02aµ6µ»9ª´­ )) ŽJHÛTö²Vlº¶Ã! ß 1G’H]Œá",õœÙv…XÒ>Û™ÖŒÑ;®]jHM364Ž•ÏÔØf š€ÜÐE÷-Ôv•¢Ë[ZЬ­Öt´•0ÎÜÈØy¦‰èAÓØ¾yñ,xx‰·Í訩"´ ÈÇlº™©íY)dšY{%Ôó<Æ ñµŽq `¾ðÖ‹Ê⤵Þ,ö²’±Ž Ù‘Š¹Û”SKFÖ¦7lâÌäOÆÈ±4hÓâºø°=IœX¬©µ­ªJ9my–ø«$–}©4Ì{±%ÍkäºGÈq4è¼³ÁÌR­Iò‚›fІZ—>Í‚®Ñ¥sœ–GKÈ1ÍÒÌ㪃Y‡Fb+üÖz‹ÊEuT‡—lÅ––9ŸgÛÓZokÝYNÖœR³ ]‹¥IìñÚàÃw¥ÃgAœhú£ k™‰õR¾[}ÿ*\_~ûÆ‹®¸#@ÆÎµé-\é¢3>8îºWSÈÈäûÜÐÙn¿ oÒÕåÙ:Û*ŽÉ²!¶íŠª ,ZŠS5±53_3Úñ0c³¼Ø{p²ñpn3}æD6дM¡lÕÚ­Ôí4ÒJ裉t—Ä.—=Ç "ö†’âe v«Eme=AS]W&nšš'M+î'  &á¤èqr™ciC}=Á#bÎFd¶*(3åÄŒçNñ„^Û¯Ùuø×#[jÁjd­Q”¥VÚËe2J:hêå„ÎÇQFòñnFg]6'\ eÀ=fª® [5CðÆéc„‰ìäxc÷9£ïÒ·¯5´jhgs e¡Tûq¶ô-Øb²[£…µí9ôív°Ä#¹îh¹¦òç~5Õ”y“vƒí©Í ÚgZUÖ¬´ñ†lw¹·ÊÐs#lbhçqqq%`zZ/0Ù²‹.9j-ª1fš©[NÃnÔņ®ºÐÀ#ƒ³Ý†q¸_ò76{-):à³Ý5ucç›céf«u=dlsFš™·—ºIh €\a,@EåV-¥jT²“ ­ =ªúih­*‹B¢7æIu.l¸ hºâÜØíƒOW‘u±ÔìèàŸ?3nǪûFŸÅxlÒüz&n4ÈÒ÷_ £¥«‚ºMNüQ¶Y!&â;8ÞXñ§yÍpû´-ëÍlêº(žñGn>Kt[Ó1¶{+¯,…Öƒ„£c´Üáš2<¹Í.—^[†¶ŽÖ·g6j*ØM¼(&’®ž+ZzÚƒ(§yÂê7FY„Ø/HÍ‹ña3„\õ‰çŠšžJЉY14¾I$pkXÐ/$“ <+bóVг©öÐäå·[RÆäõ£3åe©=Tm•™œ¯sÜÐöâqìN  ºñ}ŒB¦+0ÛFÒ´$«û©XTó!u¢a1æïÀးà\/ÐÕÞ­pOM¿ÛLêúÊzÊ«qÓ6&×ÈúsgOcãsKÃãÎ4Û‹ZæáMéȹZ9c§Ž×¢©´+b¤¢¶)`¦Ìù$›LöÆç»œ×I!iÄObò/ º¥RBÂ^Ðq›ù…šÂ^Ðq›ù„j§*{Ò¶}†ålªr§½+gÐgøn[PÞGŠæR§¸Ê¥ ÃÔÞË7öΘÿ¬ðº‹[¸õÞ'ºW3Ô§õmdýsüg®šÖî=w£ÉoŠSæD7k""k²FŒ’ûñ͸ò?Þ¿é]a›ò{GkTy Þ…oŠõШ¯½—̘ìF¬Ã7äöŽÖ™†oÉí­mE‰&¬Ã7äöŽÖ™†oÉí­mD£OÐìnÎy#’õµU1w^Ñã³á±[*˜»¯hñÙðØ¢[yAÕ½ŸÅë‘: ÷³ø£Ýr/{£73ÚyíµÜ§ñ¢÷Ú½g&ûÕ²= p/&¶»”þ4^ûW¬äßz¶G¡Cîéo‡‡èa£ïŸRÁý¼\oäVköñq¿‘Y¯;Î?*e³g6Ñ«­cL#¡©ÌËqc ÷´c —ÝØƒuâõÀ¢³¨²¶ÌØ6N<î7TÚ†¡Œº3pÀãºoÐá¹q®2šÇ²ë$¥¬¯²lú–²F²¢¦¦–9] 9Û®æâ¸àç°©³í,…³*©­J(¬{,CVúi§lQBtÇ%ÃÝk°‚4ÜnßëÆ¢¾ÝLðº‹ZäXØv_dÔÚö½UÒKY›RÐlÈÛuÂMpÐtã"ýÛ‰¹H°ª¬«Qí§¬É¨©jžâfTð}æI`Œ4îè?F’MËžž üx¦ž+n-³µ0Ã%K_ò 3‘U;Aìo;×b±:ò:Ì4ùWE.Õæqü¦×f®ì;m¯Šïhß¿µ>—SNp”Ì/f‘Òä[œì›Óc]ZÆÞw*¥}@ÔºÏdO{Žÿä+ÿîæ] òÞÓ@‹LÕ”Ôï š¦ÜEà=à¾õ¯lè8u7µn´ÂòFu”‘×R>šgLØßuæ ß ôô=„8nxТÐX”–mC¦§š½ïspShTNÛ¯Cd{€:7n¿•oÛ:Mí[­6΃‡S{VëS†YtJElè8u7µn´Û:Mí[­0Ë"q"R(»gA齫u¦ÙÐpêojÝi†Y Hù%Ÿ–½5¤ç?=O°5 Œ%²:78ß|M»O„ýÒÔ]³ áÔÞÕºÓlè8u7µn´Ã,…Ñ)D´lø­JQÔ9⹆F°”k\XëÁŽ ‡…®#¾í¦ö­Ö›gA齫u¦d1"R(»gA齫u¦ÙÐpêojÝi†Y H”Š.ÙÐpêojÝi¶t:›Ú·Za–C%"‹¶t:›Ú·Zm¦ö­Ö˜eĉH¢í¦ö­Ö›gA齫u¦d1"R(»gA齫u¦ÙÐpêojÝi†Y H”Š.ÙÐpêojÝi¶t:›Ú·Za–C%"‹¶t:›Ú·Zm¦ö­Ö˜eĉH¢í¦ö­Ö›gA齫u¦d1"R(»gA齫u¦ÙÐpêojÝi†Y H‡AašZñ]UiÖÚ5,‰ÐÄú¡sLqix60Ë»}ØE×^o¶Qv΃‡S{VëM³ áÔÞÕºÓ ²"蔊.ÙÐpêojÝi¶t:›Ú·Za–DâD:«×W¶j‹Nµô–9…ÑqÆC˜o Îh{Zîßt\thVÊ.ÙÐpêojÝi¶t:›Ú·Za–B蔊.ÙÐpêojÝi¶t:›Ú·Za–C%"‹¶t:›Ú·Zm¦ö­Ö˜eĉK {AÆoæÈg†¡…ðÊÉ ıÀ‹þåö^Ðq›ù…Pfªr§½+gÐgønVʧ*{Ò¶}†åµ äx®ej{Œ£êSú¶²~¹þ3×Mkw»Ñä÷Jæz•~­lŸÇøÒ.šÖî=w£ÉoŠSæD7k"#s²FŒ‰žÑŽm*ÿ¡t§ùy9©qÙ%”¶Ÿ“TÔµ–Å=C.(¥¨k\Ûäq‚wˆ*ﯙùÁfs¦kJñ—Y-]ï™”m´¶Í?ËÉÈÝIš—“‘º•O^93ó‚ÌçLÖxäÏÎ 33Z˲'s-³Oòòr7RfŸåään¥T2Ã&‰¸e™ÎÙ­\G#&²Fðö8^×4Þß ZÚJiì5º9Codî.ðqúî doÎDÇÝv&ƒrÉj¦ý. ü”mU1w^Ñã³á±[*˜»¯hñÙðØ¢[yAÕ½ŸÅë‘: ÷³ø£Ýr/{£73ÚyíµÜ§ñ¢÷Ú½g&ûÕ²= p/&¶»”þ4^ûW¬äßz¶G¡Cîéo‡‡èa£ïŸRÁý¼\oäVköñq¿‘Y¯;ÂKCMDÙ[M cÊ餻uÏq¼¸Ÿ ÿèn!•&•“ÔRÕX5SWTTÓe±BÙÜè)³ ¼b‰ÇHhÝ+W[ö—Ï, å¥þ‚¿E8™[ö5”ËËe uNÖÉ,®–|8Þé$tŽ'¶qÜX"($ûgwV¯ì!÷¤VʦÎî­_ØCïH­–ëa@ˆŠ@DDD@DDD@DDD@DDD@ZfqeÄo0·(õFæýßÌ(`ÔéÞÑy’áõñ“ÈdhÆH.‚‡=1¨“åò@v-n;çÿ?ûΙ¯fm¯~2ÿEê·$LòúŠÇ×HÃþ”kt½ ã7ó =oSÆàƤKÚ30©=¢; ÕNT÷¥lú ÿ ÊÙTåOzVÏ ÏðÜ´¡¼ÌŠžã(ú•~­lÇøÒ.šÖî=w£Éî•Íu*ýZÙñä]-­ÜzïG“Ý+jßþ§Ìˆn×NBI‡#¨‡üs|W®“8¼‹$-k^¢§lÄ¢¶à¡ŠŒBÌ.dÏ€?®ÄnÏ9͸¶ç_ˆ½·4]TÛ6£)bµ¶ó1Ÿ·›f¶…ñDctm­Ì‘¸?8XÂâKœ.ÇsGbY÷²âùˆìG¡ç g âèmKDe+YY[>ƨªžš ‚J90c!‘¹§<ÉCc%æKÙ‰’´ ,»­Ä³¹&×>ö@"í¨2Xb95•µl`kjd Ü®\îĪl–î4žŸ[ÿu*Ÿø²¿ò_ì‹¥ª›ôX¸ƒò[VªoÑbâÉP¹µTÅÝ{GŽÏ†Ålªbî½£ÇgÃb‰låTö{®DêƒÞÏâuȽîŒÜÏiç¶×rŸÆ‹ßjõœ›ïVÈô(}À¼šÚîSøÑ{í^³“}êÙ…¸¥¾_$a£ï_RÁý¼\oäVköñq¿‘Y¯;Â" ˆ€""íÝZ¿°‡Þ‘[*›;ºµa½"¶[­…")D@DDD@DDD@DDD@DDG¨ip4ÑxÝHRŠ“s~ïæ0B1¼~Ô~ÌôÑŒ~x^æ~èŒèÿó?’ÓQTiäùF|‘‹Æ;Çÿ?úÙLù›tŒ qxÑ‚õRHÔᢦ°7µÎ2ï«5Û/h8ÍüÂCþ%O?ƒ‘/h8Íü¤öˆì3U9SÞ•³è3ü7+eS•=é[>ƒ?Ãr½ äx®dT÷GÔ«õkdýsüiMkw»Ñä÷Jæz”þ­¬Ÿ®ŒõÓZÝÇ®ôy=Òº+'íO‹æD7kM‘‘Yã$àlS“%CæÇe#e8^wÜ02ãº0·x,«lkmçW¹öTQ>X%‘ñYØk$Í=’5®Ÿ–㉗Œ¨»A¹ÃNHdõ‰]“µ5v5Q;ß.)f¥îuÒ8 ÉyÖžMüÞ²9Œ]íÖK_{îù¯m†qÓÙZRÚQÑÒ2¾f`–©°´JöèÐ_uäv-ÐO€o#)¬˜ÚÆÇIHÖ1‘1­´¶'bˆ Œ:Z?dé,:ÓÉ¿›ÖO2‹¢iäßÍë'™EÑXÙfOîÈšêØ 2 ®Uù&àû8Ó{$¬«‘‡Ækªd  ‚ ÙÖžNxÉë&ÿA‹¢­˜ÖÆÆ±kXÐÖ´\€fÒVA'{³êÕMú,\Aù-«U7è±qä¨XÚªbî½£ÇgÃb¶U1w^Ñã³á±D¶òƒª{?Š=×"uAïgñGºä^÷Fn g´ãíK ²2®Ö2Ì&†h£ `pÎGº.¿ö…z>M÷«dz>à\Ewê¾Òô¨~$K·É®õlB‡Ü ŸO“• }Ò|‘%j¿×«,ÛÅÆþEf°oùšñNÀˆˆ" ˆ€ûgwV¯ì!÷¤VªŽj:j‡‡ÍM Žà^ÀMßz×µ”›Ù7RÕMX¥™ÐÞ—®{k(8 7²n¤ÚÊM웩N8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3¡½/\öÖPpodÝIµ”›Ù7Rcˆ³:ÒõÏme¦öMÔ›YAÀi½“u&8‹3 Qê…íbÜÝ &í ø>¥Oµ”›Ù7Rme¦öMÔ£E™0ºñqkÏàÉÑF^eiÃ&‚ Ù§‹ùEÊÖPpodÝIµ”›Ù7RŒH›3í+K**ØíÖÈÀ}Œkt½ ã7ó ä0CNÂÈbdm&òÐÿrû/h8Íü¤Ù)Yª¬¨ïJÙôþ•ªªÊŽô­ŸAŸá¹iCx¸®ej{Œáúœäm«vmlµµÑ¾S-í‰ì Jñ¢ö“àß]Oû<³üãizñôž¤Ÿ«+#ëŸãÈ»UݤiUi%.÷ÌÎŽ¨…dÙØödTï‘ñÆ\C¤ ¸âqq¾àé>5qI¹;³PˆŠDDj¦ý. ü–Õª›ôX¸ƒò@mU1w^Ñã³á±[*˜»¯hñÙðØ¢[yAÕ½ŸÅë‘: ÷³ø£Ýr/{£73ÚsõߪûKÒ¡ø‘.ß&ûÕ²= p."»õ_izT?%Ûäßz¶G¡Cî˧nÔù#:[ßþ}Köñq¿‘Y¬ÛÅÆþEf¼s°""ˆˆ" 5‰âuCéÛ+ Ìk^èÆ&µÄ†’7@%®¸øpä†xª_ ¬‘Îasi-pÑáG€‚?U[Ibeme}«U U40ÔTH¤ŽIË™ˆèºF ÄŒW_…×r•Íeǵ5SC’ªª–ŒVIGPs•SH×CÚ™\×Gòv¤48 á lAéè¼Ö+B¾L£1ººš+LZ®fiöÌæcN*`\`â‘)#K‡A–•Ÿ`ºkBjo”Ž¢Ñ–ÎŽGö8NÈŒ+£=°sþí,©•Z½£,õeõ»»5 ³E¥jÍGS¦ž7°âŒ²wgKïNŽëš¸´¶i®¶ë"µ«á–jŠŽ™±Íòp2VÒ6BAk‰»CÃN–€I&læIâ‰ñ2IXÇÌìµÎ½×\7ÍÍq»xà[œÛ¶­e%•SXùhí9á£a‘óÈïî§ÌÖìN“å]ˆbÓpÜ 55™<Èi›geæ³XÖZ“¶Ü–QY™ŒwÊd&e ‚ÜFæ›ï¹EÛTVSÒÍK Òa’ªS "âq<1Ï#FçbÇ;ßRÞ¼ÂÔ­«nvĪš¶:{N§içl†¨Éu—3»»—匃Iv[à¸m´k)sôôù/”USRÌèW<›« 5´¬²‘Ï %Ÿ±ÜxðàÝ`zR/?¶ë*¾ºÎŽÔš :(©*ÚëFv5ÎÔµÁÕwºHZLqo¸–hÎú¬›Ÿdزb™Í8Ú×M.wCȲ\ Œ Ç‘{Û…ÇI*, ñÕÓÏWQM˜å§Ã˜\/ 's×7ÞšH¹Âýê#tä›#ÿI–,íX;¢¥äºpáû.ΗÞÝMâáuÊuéÝ[jjæšFÕ4M„–ÀüÌd1— ÂZíé{¾ “}5e=f{1&'A+¡•¤¹‘ ‚7Á^'1Os±'›z.c&jieµ­(¬›Eõö; §tsÇU´N](‘¢W9ÆðÖÂK/¸^ Ãæ‚дë©m]´5ÒÕÚÂ*à )ªŸ$¬"7º!% Ù‚6 ˜ÖÈÝ2;6t‰]zÀôd^M-ªøà’J+~–š‰®¦SÑ[óZF"jéÚçÌÌÃ(¸›ž ½® 7ZÍkÐÓ2҆ϴ]b=´Íecí©D0NLΓ`sŸÃ#$b{Ã8Iœ ôD^c“µ56í¼,éëë"³áÙxb¥´fx•”.o˸6W·¯{^Ð냌fã"Ö·\̦ôŽÍTm=,ºÖÓ23;"sDbcÒp½ÄÇæ„°= â¨a|2²F9…Ìp 9¤µÃG„A[‘5ÐÙ€Wæ¢Vƒ«b¯Ê Š1öI4ÄÈ œ×>7HàÝÁ{Î"ÐWgMUj·©ÅeU<ÙûE”µO¤|ó⸿0ç´nh`-8îÅÙb¼¬©kšx©Ø4¬…Í`sÜ.q hÓá$€„–Šê© .ÙŠ8-,s>Ï·¦´Þ׺²­8¥f»J0“Ùâ7µÁ†ë< ³ã‰õöY©´ ŸJë*¸™+§s¢ÅW#fy¿`Ž0í.ÂÜÅÄ^–<ñSSÉQQ+"†&—É$Ž kä’t…l^wK{:›å ³KlZ/l›(çut’68™,¢2ÊçÞý7bÃpb´+äÊ3«©¢´ÅªæfŸlÎf4â €6aeÆ¡Þ)’4¸,JEÁdíµElµ–›ê›MG%EmDu’Ô4\é {o¤öDBÍ$|›Wz¡ A!D@DDa/h8ÍüÂÍa/h8ÍüÂ5U•é[>ƒ?ÃrµUYQÞ•³è3ü7-hoÌ¥Oq•]IV6G×?Ç‘v«ŠêKú±²>¹þ<‹µ[é[ùq|ÊÓ÷DEpˆˆ" U7è±qä¶­TߢÅÄ’j©‹ºöŸ ŠÙTÅÝ{GŽÏ†ÅØ;ʨ=ìþ(÷\‰Õ½ŸÅë‘{ݸ1žÓŸ®ýWÚ^•ĉvù7Þ­‘èPûqߪûKÒ¡ø‘.ß&ûÕ²= p.];pþ§ÉÒß^¬°oùšÁý¼\oäVkÇ;" ˆ€""ˆˆ" ˆ€""ˆˆ" "RPEEQS%;žÈêœt7ŒÛ^I.{Eׂâo"û‰®Äçl¦£§£Ïf#ÂéåtÒ¸’ç=çÂIÒtð €oDJZ©j*j|•.¾I¤ »' ÀÆ‚@|“{œçhˆ" "Z6|V•3)æsÚÆO à°€qE#dhÒ7/`¿è¿qKD@DDD@DDD@DDa/h8ÍüÂÍa/h8ÍüÂ5S•=é[>ƒ?Ãr¶U9SÞ•³è3ü7-hoÌ¥Oq•Iæ‰Lì–ºV4ƒ>‚à?ßH»=“–Ö êKú²²>¹þ<‹µ[é[ùq|ÊÓ÷«dÁå£õ‚l˜<´~°[Q`\Õ²`òÑúÁ6LZ?X-¨€Õ²`òÑúÁ6LZ?X-¨€Òê¨ZÛÄqð5¦ò~ ³…¥F× ˆh‘fˆ©‹ºöŸ ŠÙTÅÝ{GŽÏ†ÅØ;ʨ=ìþ(÷\‰Õ½ŸÅë‘{ݸ1žÓŸ®ýWÚ^•ĉvù7Þ­‘èPûqߪûKÒ¡ø‘.ß&ûÕ²= p.];pþ§ÉÒÞÿóêX½‚FÜ~â7BùÞUüƒRÍŽv`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,цyWò IÞUüƒRÍ`w• Ô˜å_È5,×Â@Ý }h p;Ê¿jLò¯ä—Ümñ‡*coŒ9RÄ0;Ê¿jLò¯ä—Ümñ‡*coŒ9RÀùÞUüƒR`w• Ô¾ãgŒÞTÎ3Ço*X0;Ê¿jLò¯ä—Üã`w• Ô˜å_È5,Áq|.h:\Þ„˜àw• Ô˜å_È5/¸ÛãTÆßr¡Ìò¯ä“¼«ù¥÷|aʘÛãTÌò¯ä“¼«ù¥÷ƒ?ÃrÖ†ñq\ÊÔ÷WÔ—õed}süyj¼÷©e¤ êqeE±*¤Âfì˜qùgï¸ØíÀྫ:k}+./™Z~â,QWmÀྫ:i·€Vú¬é¬ –(«¶àp ßU4ÛÀ+}VtÐ(«¶àp ßU4ÛÀ+}VtÐ(«¶àp ßU4ÛÀ+}VtÐ*¦.ëÚnÙ<Æ>Šu¥“7lžcEZ^—¨Äɲ*úÒÉ›¶O1¢idÇÍÛ'˜ÇÑUŒ¥ClZ쮩®dVuS)`ŽŽ¶Zaq‚)\çÜÒç-ÚI4\..ƒ”¹QU“°Îúzý˜Û:—LN²gò½­ÄCê!"(\æá=“;A×a )»VGCÖ–L|ݲyŒ}ëK&>nÙ<Æ>Š¢‡(mà ´çp³Ûk:Îì‰æYjÍ3dÎ\Â/· ¯Â{&⹚úä¶¢É8r–yh]M]3©éb¢•ÒSš‰#kKˆ™° 4µ¬ay0Þ—yŒ+#¡ëK&>nÙ<Æ>Šu¥“7lžcEruVÕ¡iY²SÖÆù¥e>:³fOB×—V°æ$’Ü—qÎpºóè¦'˜Â²*úÓÉ›¶O1¢ª²’À°ìÌš´ë¨,ŠJÊji'†zzfFö=­.€wBêoT™bô]·èü7)‹nKX”V¨žEÆåS•=é[>ƒ?Ãr·;¥TeOzVÏ ÏðÜ©Gx¸®e§î2©OêÖÉúæøÏ]’ä:”SG'SK%ÎÇy3î=Ãýô›Åv{ùžÑÚÖšRþyñ|Ȧÿb5¢Ù±!ÿ™í­6$?ó=£µ®l%îkE³bCÿ3Ú;ZlHæ{GkL"æ´[6$?ó=£µ¦Ä‡þg´v´Â.kE³bCÿ3Ú;ZlHæ{GkL"æ´[6$?ó=£µ­%™ª‡Æ -Â/7Ý}ú‘¡s—êƒÞÏâuÈP{ÙüQî¹ÐôfàÂ{N~»õ_izT?%Ûäßz¶G¡CîÄW~«í/J‡âD»|›ïZÈô(}À¹tíÃúŸ$gK{ÿÏ©fˆ‹Ç;" ˆ€""ˆˆ" ˆ€""ˆˆ" ˆ€""ˆˆæ-·ˆòÊÂ{ˆ Ï{ŽàÈN ÚV=ŸlDØëé„Ía½‡˜æŸ¡Í ¸­iMBI½†u"å"nÙQp¸= M²¢áp{@¹þ±²{Ôsúê'XÙ=Àê9ýGõס›û/É_äÉ¿£ Û*.´ ¶T\.h?Ö6Op:ŽQýDë'¸G?¨þ¢^†oì¿#ùr_ïè“EfäõŸTÊšy€tWæc’ºI"‚ñwÉDç–GsIhÂÍ%¢àHR) °©"³ã§’ÛgE™¥"s{#€›ïsn ÐëÁ-iÝh"»¬|àuþ£ú‰Ö>Nð*ŽQýE7¡›û/Èþ\‘Ðm• ƒÚÛ*.´ Ÿë'xG?¨þ¢u“¼ £ŸÔQ/C7ö_‘ü¹# Û*.´ =m£Hê †¶ª8ÄàMÊŸ¬|àUþ£ú‰Ö>O_~èçõÔE* Þïì¿$5U÷#fGßÖÛ ðÕUÿÑ"‘aHÖZY@×8¶ 7FXSÓÁGM54,†šÈØ. e…gWT‰¡•³sŸL°—ù·6ÿ½bê'9I÷þK(5²-³Ìñ‡*g™ãUEÖÅ—ûÃø¥Wõ­‹/÷‡ñJ¯ê%ៗþ“idK´l{:Ò¨mD`ÌJJÙ©œö‚H19¥Àë¾ìNºëÍñ+rK'mŸ ôCcI‰ô±O$P=¡¸ZLMpasZˆÄÜ ¸Œ-¹ÖÅ—ûÃø¥Wõ­‹/÷‡ñJ¯ê&(gåÿ¢Òȵ–fÂØy¡±öVÌÁœwøÙìþ+ï¿üNÊíÏ×hQcÉ«&KS™‘˜ºc@89¹¨ËðÄZZÒÒÀÒˆ–¾¶,¿ÞÅ*¿¨lY¼?ŠUQ1C?/ý»#|6‹³c–)]%E\³H]ÃãÞâì-p¼6ü7—hìöÙæxÕQu±eþðþ)UýDëbËýáüR«ú‰xgåÿ£÷d^ç™ãUK•ò°äm´1 Í Àiÿ€¬:زÿxªþ¢úÌ™²[#^èjeÂààÉë§•„ËÚ÷~ð¥J Þä5&¬\Òª2§½+gÐgønVÄÞIßU9SÞ•³è3ü7(¡½\QiûŒ«êKú²²>¹þ<‹µ\WR_Õ‘õÏñä]ª×JßÏ‹æVŸ¸‚ª´-(à©Â*"a§h•ìsî/¿F/Òpâ7oàVª Y¤ §ÁÒ9ØŸ97ö× 9s'VJú“,1Ê3m“8ép´‡;ßþ¼8²¾Z‡µ´´áÁвlRI„ëôÓ£óûôÓÙó6¡î2IOòmkLO²yÂ/m×[vƒÂ¶ 6¬˜d–Ûq°±Àè׋œûtÝÓº€Æ:üUm”f%ŠÙÓ}Æíòp¿èSc›9Q4a½ŒXAuÿ´Eä]ôÓÓô(ÒQÇNdP:VÉióxîƒד¦îËIŸ¡I¦‡cÓ¶2ìN—:ë±8›É»Áy$Ü€ÚˆŠ@Q%ý1ÿfßÍÊZ‰/éû6þnPör½P{ÙüQ{?Š=×"÷ú3pc=§=h87©m¦çª†ò~Ò%ÓXAcA“–\SZôÈÊHšæ>¥€´† Áè+Š‹(¬wäýE‹iÐ:®šyäfuÑîa ^Ñ~‚ÐwU^ÇÈ›þ!>´©£õt柼ÝÕ»Ò]ïäd®¤¥ÝnóÖºæ°|÷fó¦kN¹¬=Ù¼î=kÉv>@|Øñ õ¦ÇÈ›þ!>µÏÙÔò——äÓ¬žkÌõ®¹¬=Ù¼î=i×5ƒç»7Ç­y.ÇÈ›þ!>´ØùóaÿÄ'ÖO)y~GY<×™ë]sX>{³yÜzÓ®kÏvo;Zò]6üB}i±òæÃÿˆO­;:žRòü޲y¯3Öºæ°|÷fó¸õ§\ÖžìÞwµä» >l?ŸÏ­6>@|Ø?ŸZvu<¥åùdó^g­uÍ`ùîÍçqëN¹¬=Ù¼î=kÉv>@|Ø?ŸZl|€ù°ÿâëNΧ”¼¿#¬žkÌõ®¹¬=Ù¼î=i×5ƒç»7Ç­y.ÇÈ›çóëM6üB}iÙÔò——äu“Íyžµ×5ƒç»7Ç­:æ°|÷fó¸õ¯%ØùóaÿÄ'Ö› >l?ŸÏ­;:žRòü޲y¯3Öºæ°|÷fó¸õ§\ÖžìÞwµä» >l?ø„úÓcä͇ÿŸZvu<¥åùdó^g­uÍ`ùîÍçqëN¹¬=Ù¼î=kÉv>@|Øñ õ¦ÇÈ›çóëNΧ”¼¿#¬žkÌõ®¹¬=Ù¼î=i×5ƒç»7Ç­y.ÇÈ›þ!>´ØùóaÿÄ'ÖO)y~GY<×™ë]sX>{³yÜzÓ®kÏvo;Zò]6üB}i±òæÃÿˆO­;:žRòü޲y¯3Öºæ°|÷fó¸õ§\ÖžìÞwµä» >l?ŸÏ­6>@|Ø?ŸZvu<¥åùdó^g­uÍ`ùîÍçqëN¹¬=Ù¼î=kÉv>@|Ø?ŸZl|€ù°ÿâëNΧ”¼¿#¬žkÌõ®¹¬=Ù¼î=i×5ƒç»7Ç­y.ÇÈ›çóëM6üB}iÙÔò——äu“Íyžµ×5ƒç»7Ç­:æ°|÷fó¸õ¯%ØùóaÿÄ'Ö› >l?ø„úÓ³©å//Èë'šó=k®kÏvo;ZuÍ`ùîÍçqë^K±òæÃÿˆO­6>@|Øñ õ§gSÊ^_‘ÖO5æz×\ÖžìÞw´ëšÁóÝ›ÎãÖ¼—cä͇ÿŸZl|€ù°ÿâëNΧ”¼¿#¬žkÌõ®¹¬=Ù¼î=i×5ƒç»7Ç­y.ÇÈ›þ!>´ØùóaÿÄ'ÖO)y~GY<×™ë]sX>{³yÜzÓ®kÏvo;Zò]6üB}i±òæÃÿˆO­;:žRòü޲y¯3Öºæ°|÷fó¸õ§\ÖžìÞwµä» >l?ø„úÓcä͇ÿŸZvu<¥åùdó^g­uÍ`ùîÍçqëN¹¬=Ù¼î=kÉv>@|Øñ õ¦ÇÈ›þ!>´ìêyKËò:Éæ¼ÏZëšÁóÝ›ÎãÖsX>{³yÜz×’ì|€ù°ÿâëM6üB}iÙÔò——äu“Íyžµ×5ƒç»7Ç­:æ°|÷fó¸õ¯%Øùóaüþ}i±òæÃÿˆO­;:žRòü޲y¯3Öºæ°|÷fó¸õ§\ÖžìÞwµä» >l?ø„úÓcä͇ÿŸZvu<¥åùdó^g­uÍ`ùîÍçqëN¹¬=Ù¼î=kÉv>@|Øñ õ¦ÇÈ›þ!>´ìêyKËò:Éæ¼ÏYëšÁóÝΣ֫2“(lI²^ÖŠ+bò>Šfµ©a.%„úJó6üB}i±òæÃÿˆO­^!%$¥«‡ä‡9µk¯3»êUœÿfÖNžÑ|Úo–~ø]—Ëp‰9©yÅ‘—=‡fCgYÖS¡¤‡óîu׸¸ép'tŸ ™þÓi8 ½©è®ZÚ‘R¤¦£©¶ö¬øšFqQHîþ[„IÈÝIòÜ"NFê\'ûM¤à.ö§¢Ÿí6“€»ÚžŠË³ôŸšü–ë"w-Â$än¤ùn'#u.ý¦Òp{SÑOö›IÀ]íOE;?Iðù¯Èë"w-Â$än¤ùn'#u.ý¦Òp{SÑOö›IÀ]íOE;?Iðù¯Èë"w-Â$än¤ùn'#u.ý¦Òp{SÑOö›IÀ]íOE;?Iðù¯Èë"w-Â$än¥ñ­¹ÅÎsœãºJáÚm'wµ=ÿi´œÞÔôTv~“áó_‘ÖD²êƒÞÏâuȹ|£ËZkrÊ4§18;v2ëôvàßEìhtgN’ŒÖ³)8·sÿÙprivoxy-3.0.21-stable/./doc/webserver/user-manual/installation.html000640 001751 001751 00000054276 12114164411 024364 0ustar00fkfk000000 000000 Installation

    2. Installation

    Privoxy is available both in convenient pre-compiled packages for a wide range of operating systems, and as raw source code. For most users, we recommend using the packages, which can be downloaded from our Privoxy Project Page.

    Note: On some platforms, the installer may remove previously installed versions, if found. (See below for your platform). In any case be sure to backup your old configuration if it is valuable to you. See the note to upgraders section below.

    2.1. Binary Packages

    How to install the binary packages depends on your operating system:

    2.1.1. Debian and Ubuntu

    DEBs can be installed with apt-get install privoxy, and will use /etc/privoxy for the location of configuration files.

    2.1.2. Windows

    Just double-click the installer, which will guide you through the installation process. You will find the configuration files in the same directory as you installed Privoxy in.

    Version 3.0.5 beta introduced full Windows service functionality. On Windows only, the Privoxy program has two new command line arguments to install and uninstall Privoxy as a service.

    Arguments:

    --install[:service_name]

    --uninstall[:service_name]

    After invoking Privoxy with --install, you will need to bring up the Windows service console to assign the user you want Privoxy to run under, and whether or not you want it to run whenever the system starts. You can start the Windows services console with the following command: services.msc. If you do not take the manual step of modifying Privoxy's service settings, it will not start. Note too that you will need to give Privoxy a user account that actually exists, or it will not be permitted to write to its log and configuration files.

    2.1.3. OS/2

    First, make sure that no previous installations of Junkbuster and / or Privoxy are left on your system. Check that no Junkbuster or Privoxy objects are in your startup folder.

    Then, just double-click the WarpIN self-installing archive, which will guide you through the installation process. A shadow of the Privoxy executable will be placed in your startup folder so it will start automatically whenever OS/2 starts.

    The directory you choose to install Privoxy into will contain all of the configuration files.

    2.1.4. Mac OS X

    Installation instructions for the OS X platform depend upon whether you downloaded a ready-built installation package (.pkg or .mpkg) or have downloaded the source code.

    2.1.5. Installation from ready-built package

    The downloaded file will either be a .pkg (for OS X 10.5 upwards) or a bzipped .mpkg file (for OS X 10.4). The former can be double-clicked as is and the installation will start; double-clicking the latter will unzip the .mpkg file which can then be double-clicked to commence the installation.

    The privoxy service will automatically start after a successful installation (and thereafter every time your computer starts up) however you will need to configure your web browser(s) to use it. To do so, configure them to use a proxy for HTTP and HTTPS at the address 127.0.0.1:8118.

    To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the file /Library/LaunchDaemons/org.ijbswa.privoxy.plist (on OS X 10.5 and higher) or the folder named /Library/StartupItems/Privoxy (on OS X 10.4 'Tiger').

    To manually start or stop the privoxy service, use the scripts startPrivoxy.sh and stopPrivoxy.sh supplied in /Applications/Privoxy. They must be run from an administrator account, using sudo.

    To uninstall, run /Applications/Privoxy/uninstall.command as sudo from an administrator account.

    2.1.6. Installation from source

    To build and install the Privoxy source code on OS X you will need to obtain the macsetup module from the Privoxy Sourceforge CVS repository (refer to Sourceforge help for details of how to set up a CVS client to have read-only access to the repository). This module contains scripts that leverage the usual open-source tools (available as part of Apple's free of charge Xcode distribution or via the usual open-source software package managers for OS X (MacPorts, Homebrew, Fink etc.) to build and then install the privoxy binary and associated files. The macsetup module's README file contains complete instructions for its use.

    The privoxy service will automatically start after a successful installation (and thereafter every time your computer starts up) however you will need to configure your web browser(s) to use it. To do so, configure them to use a proxy for HTTP and HTTPS at the address 127.0.0.1:8118.

    To prevent the privoxy service from automatically starting when your computer starts up, remove or rename the file /Library/LaunchDaemons/org.ijbswa.privoxy.plist (on OS X 10.5 and higher) or the folder named /Library/StartupItems/Privoxy (on OS X 10.4 'Tiger').

    To manually start or stop the privoxy service, use the Privoxy Utility for Mac OS X (also part of the macsetup module). This application can start and stop the privoxy service and display its log and configuration files.

    To uninstall, run the macsetup module's uninstall.sh as sudo from an administrator account.

    2.1.7. FreeBSD

    Privoxy is part of FreeBSD's Ports Collection, you can build and install it with cd /usr/ports/www/privoxy; make install clean.

    2.2. Building from Source

    The most convenient way to obtain the Privoxy sources is to download the source tarball from our project download page.

    If you like to live on the bleeding edge and are not afraid of using possibly unstable development versions, you can check out the up-to-the-minute version directly from the CVS repository.

    To build Privoxy from source, autoconf, GNU make (gmake), and, of course, a C compiler like gcc are required.

    When building from a source tarball, first unpack the source:

     tar xzvf privoxy-3.0.21-stable-src.tar.gz
     cd privoxy-3.0.21-stable
    

    For retrieving the current CVS sources, you'll need a CVS client installed. Note that sources from CVS are typically development quality, and may not be stable, or well tested. To download CVS source, check the Sourceforge documentation, which might give commands like:

      cvs -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa login
      cvs -z3 -d:pserver:anonymous@ijbswa.cvs.sourceforge.net:/cvsroot/ijbswa co current
      cd current
    

    This will create a directory named current/, which will contain the source tree.

    You can also check out any Privoxy "branch", just exchange the current name with the wanted branch name (Example: v_3_0_branch for the 3.0 cvs tree).

    It is also strongly recommended to not run Privoxy as root. You should configure/install/run Privoxy as an unprivileged user, preferably by creating a "privoxy" user and group just for this purpose. See your local documentation for the correct command line to do add new users and groups (something like adduser, but the command syntax may vary from platform to platform).

    /etc/passwd might then look like:

      privoxy:*:7777:7777:privoxy proxy:/no/home:/no/shell
    

    And then /etc/group, like:

      privoxy:*:7777:
    

    Some binary packages may do this for you.

    Then, to build from either unpacked tarball or CVS source:

     autoheader
     autoconf
     ./configure      # (--help to see options)
     make             # (the make from GNU, sometimes called gmake)
     su               # Possibly required
     make -n install  # (to see where all the files will go)
     make -s install  # (to really install, -s to silence output)
    

    Using GNU make, you can have the first four steps automatically done for you by just typing:

      make
    

    in the freshly downloaded or unpacked source directory.

    To build an executable with security enhanced features so that users cannot easily bypass the proxy (e.g. "Go There Anyway"), or alter their own configurations, configure like this:

     ./configure  --disable-toggle  --disable-editor  --disable-force
    

    Then build as above. In Privoxy 3.0.7 and later, all of these options can also be disabled through the configuration file.

    WARNING: If installing as root, the install will fail unless a non-root user or group is specified, or a privoxy user and group already exist on the system. If a non-root user is specified, and no group, then the installation will try to also use a group of the same name as "user". If a group is specified (and no user), then the support files will be installed as writable by that group, and owned by the user running the installation.

    configure accepts --with-user and --with-group options for setting user and group ownership of the configuration files (which need to be writable by the daemon). The specified user must already exist. When starting Privoxy, it must be run as this same user to insure write access to configuration and log files!

    Alternately, you can specify user and group on the make command line, but be sure both already exist:

     make -s install  USER=privoxy GROUP=privoxy
    

    The default installation path for make install is /usr/local. This may of course be customized with the various ./configure path options. If you are doing an install to anywhere besides /usr/local, be sure to set the appropriate paths with the correct configure options (./configure --help). Non-privileged users must of course have write access permissions to wherever the target installation is going.

    If you do install to /usr/local, the install will use sysconfdir=$prefix/etc/privoxy by default. All other destinations, and the direct usage of --sysconfdir flag behave like normal, i.e. will not add the extra privoxy directory. This is for a safer install, as there may already exist another program that uses a file with the "config" name, and thus makes /usr/local/etc cleaner.

    If installing to /usr/local, the documentation will go by default to $prefix/share/doc. But if this directory doesn't exist, it will then try $prefix/doc and install there before creating a new $prefix/share/doc just for Privoxy.

    Again, if the installs goes to /usr/local, the localstatedir (ie: var/) will default to /var instead of $prefix/var so the logs will go to /var/log/privoxy/, and the pid file will be created in /var/run/privoxy.pid.

    make install will attempt to set the correct values in config (main configuration file). You should check this to make sure all values are correct. If appropriate, an init script will be installed, but it is up to the user to determine how and where to start Privoxy. The init script should be checked for correct paths and values, if anything other than a default install is done.

    If install finds previous versions of local configuration files, most of these will not be overwritten, and the new ones will be installed with a "new" extension. default.action and default.filter will be overwritten. You will then need to manually update the other installed configuration files as needed. The default template files will be overwritten. If you have customized, local templates, these should be stored safely in a separate directory and defined in config by the "templdir" directive. It is of course wise to always back-up any important configuration files "just in case". If a previous version of Privoxy is already running, you will have to restart it manually.

    For more detailed instructions on how to build Redhat RPMs, Windows self-extracting installers, building on platforms with special requirements etc, please consult the developer manual.

    2.3. Keeping your Installation Up-to-Date

    If you wish to receive an email notification whenever we release updates of Privoxy or the actions file, subscribe to our announce mailing list, ijbswa-announce@lists.sourceforge.net.

    In order not to lose your personal changes and adjustments when updating to the latest default.action file we strongly recommend that you use user.action and user.filter for your local customizations of Privoxy. See the Chapter on actions files for details.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/appendix.html000640 001751 001751 00000134651 12116120072 023464 0ustar00fkfk000000 000000 Appendix

    14. Appendix

    14.1. Regular Expressions

    Privoxy uses Perl-style "regular expressions" in its actions files and filter file, through the PCRE and PCRS libraries.

    If you are reading this, you probably don't understand what "regular expressions" are, or what they can do. So this will be a very brief introduction only. A full explanation would require a book ;-)

    Regular expressions provide a language to describe patterns that can be run against strings of characters (letter, numbers, etc), to see if they match the string or not. The patterns are themselves (sometimes complex) strings of literal characters, combined with wild-cards, and other special characters, called meta-characters. The "meta-characters" have special meanings and are used to build complex patterns to be matched against. Perl Compatible Regular Expressions are an especially convenient "dialect" of the regular expression language.

    To make a simple analogy, we do something similar when we use wild-card characters when listing files with the dir command in DOS. *.* matches all filenames. The "special" character here is the asterisk which matches any and all characters. We can be more specific and use ? to match just individual characters. So "dir file?.text" would match "file1.txt", "file2.txt", etc. We are pattern matching, using a similar technique to "regular expressions"!

    Regular expressions do essentially the same thing, but are much, much more powerful. There are many more "special characters" and ways of building complex patterns however. Let's look at a few of the common ones, and then some examples:

    . - Matches any single character, e.g. "a", "A", "4", ":", or "@".
    ? - The preceding character or expression is matched ZERO or ONE times. Either/or.
    + - The preceding character or expression is matched ONE or MORE times.
    * - The preceding character or expression is matched ZERO or MORE times.
    \ - The "escape" character denotes that the following character should be taken literally. This is used where one of the special characters (e.g. ".") needs to be taken literally and not as a special meta-character. Example: "example\.com", makes sure the period is recognized only as a period (and not expanded to its meta-character meaning of any single character).
    [ ] - Characters enclosed in brackets will be matched if any of the enclosed characters are encountered. For instance, "[0-9]" matches any numeric digit (zero through nine). As an example, we can combine this with "+" to match any digit one of more times: "[0-9]+".
    ( ) - parentheses are used to group a sub-expression, or multiple sub-expressions.
    | - The "bar" character works like an "or" conditional statement. A match is successful if the sub-expression on either side of "|" matches. As an example: "/(this|that) example/" uses grouping and the bar character and would match either "this example" or "that example", and nothing else.

    These are just some of the ones you are likely to use when matching URLs with Privoxy, and is a long way from a definitive list. This is enough to get us started with a few simple examples which may be more illuminating:

    /.*/banners/.* - A simple example that uses the common combination of "." and "*" to denote any character, zero or more times. In other words, any string at all. So we start with a literal forward slash, then our regular expression pattern (".*") another literal forward slash, the string "banners", another forward slash, and lastly another ".*". We are building a directory path here. This will match any file with the path that has a directory named "banners" in it. The ".*" matches any characters, and this could conceivably be more forward slashes, so it might expand into a much longer looking path. For example, this could match: "/eye/hate/spammers/banners/annoy_me_please.gif", or just "/banners/annoying.html", or almost an infinite number of other possible combinations, just so it has "banners" in the path somewhere.

    And now something a little more complex:

    /.*/adv((er)?ts?|ertis(ing|ements?))?/ - We have several literal forward slashes again ("/"), so we are building another expression that is a file path statement. We have another ".*", so we are matching against any conceivable sub-path, just so it matches our expression. The only true literal that must match our pattern is adv, together with the forward slashes. What comes after the "adv" string is the interesting part.

    Remember the "?" means the preceding expression (either a literal character or anything grouped with "(...)" in this case) can exist or not, since this means either zero or one match. So "((er)?ts?|ertis(ing|ements?))" is optional, as are the individual sub-expressions: "(er)", "(ing|ements?)", and the "s". The "|" means "or". We have two of those. For instance, "(ing|ements?)", can expand to match either "ing" OR "ements?". What is being done here, is an attempt at matching as many variations of "advertisement", and similar, as possible. So this would expand to match just "adv", or "advert", or "adverts", or "advertising", or "advertisement", or "advertisements". You get the idea. But it would not match "advertizements" (with a "z"). We could fix that by changing our regular expression to: "/.*/adv((er)?ts?|erti(s|z)(ing|ements?))?/", which would then match either spelling.

    /.*/advert[0-9]+\.(gif|jpe?g) - Again another path statement with forward slashes. Anything in the square brackets "[ ]" can be matched. This is using "0-9" as a shorthand expression to mean any digit one through nine. It is the same as saying "0123456789". So any digit matches. The "+" means one or more of the preceding expression must be included. The preceding expression here is what is in the square brackets -- in this case, any digit one through nine. Then, at the end, we have a grouping: "(gif|jpe?g)". This includes a "|", so this needs to match the expression on either side of that bar character also. A simple "gif" on one side, and the other side will in turn match either "jpeg" or "jpg", since the "?" means the letter "e" is optional and can be matched once or not at all. So we are building an expression here to match image GIF or JPEG type image file. It must include the literal string "advert", then one or more digits, and a "." (which is now a literal, and not a special character, since it is escaped with "\"), and lastly either "gif", or "jpeg", or "jpg". Some possible matches would include: "//advert1.jpg", "/nasty/ads/advert1234.gif", "/banners/from/hell/advert99.jpg". It would not match "advert1.gif" (no leading slash), or "/adverts232.jpg" (the expression does not include an "s"), or "/advert1.jsp" ("jsp" is not in the expression anywhere).

    We are barely scratching the surface of regular expressions here so that you can understand the default Privoxy configuration files, and maybe use this knowledge to customize your own installation. There is much, much more that can be done with regular expressions. Now that you know enough to get started, you can learn more on your own :/

    More reading on Perl Compatible Regular expressions: http://perldoc.perl.org/perlre.html

    For information on regular expression based substitutions and their applications in filters, please see the filter file tutorial in this manual.

    14.2. Privoxy's Internal Pages

    Since Privoxy proxies each requested web page, it is easy for Privoxy to trap certain special URLs. In this way, we can talk directly to Privoxy, and see how it is configured, see how our rules are being applied, change these rules and other configuration options, and even turn Privoxy's filtering off, all with a web browser.

    The URLs listed below are the special ones that allow direct access to Privoxy. Of course, Privoxy must be running to access these. If not, you will get a friendly error message. Internet access is not necessary either.

    These may be bookmarked for quick reference. See next.

    14.2.1. Bookmarklets

    Below are some "bookmarklets" to allow you to easily access a "mini" version of some of Privoxy's special pages. They are designed for MS Internet Explorer, but should work equally well in Netscape, Mozilla, and other browsers which support JavaScript. They are designed to run directly from your bookmarks - not by clicking the links below (although that should work for testing).

    To save them, right-click the link and choose "Add to Favorites" (IE) or "Add Bookmark" (Netscape). You will get a warning that the bookmark "may not be safe" - just click OK. Then you can run the Bookmarklet directly from your favorites/bookmarks. For even faster access, you can put them on the "Links" bar (IE) or the "Personal Toolbar" (Netscape), and run them with a single click.

    Credit: The site which gave us the general idea for these bookmarklets is www.bookmarklets.com. They have more information about bookmarklets.

    14.3. Chain of Events

    Let's take a quick look at how some of Privoxy's core features are triggered, and the ensuing sequence of events when a web page is requested by your browser:

    • First, your web browser requests a web page. The browser knows to send the request to Privoxy, which will in turn, relay the request to the remote web server after passing the following tests:

    • Privoxy traps any request for its own internal CGI pages (e.g http://p.p/) and sends the CGI page back to the browser.

    • Next, Privoxy checks to see if the URL matches any "+block" patterns. If so, the URL is then blocked, and the remote web server will not be contacted. "+handle-as-image" and "+handle-as-empty-document" are then checked, and if there is no match, an HTML "BLOCKED" page is sent back to the browser. Otherwise, if it does match, an image is returned for the former, and an empty text document for the latter. The type of image would depend on the setting of "+set-image-blocker" (blank, checkerboard pattern, or an HTTP redirect to an image elsewhere).

    • Untrusted URLs are blocked. If URLs are being added to the trust file, then that is done.

    • If the URL pattern matches the "+fast-redirects" action, it is then processed. Unwanted parts of the requested URL are stripped.

    • Now the rest of the client browser's request headers are processed. If any of these match any of the relevant actions (e.g. "+hide-user-agent", etc.), headers are suppressed or forged as determined by these actions and their parameters.

    • Now the web server starts sending its response back (i.e. typically a web page).

    • First, the server headers are read and processed to determine, among other things, the MIME type (document type) and encoding. The headers are then filtered as determined by the "+crunch-incoming-cookies", "+session-cookies-only", and "+downgrade-http-version" actions.

    • If any "+filter" action or "+deanimate-gifs" action applies (and the document type fits the action), the rest of the page is read into memory (up to a configurable limit). Then the filter rules (from default.filter and any other filter files) are processed against the buffered content. Filters are applied in the order they are specified in one of the filter files. Animated GIFs, if present, are reduced to either the first or last frame, depending on the action setting.The entire page, which is now filtered, is then sent by Privoxy back to your browser.

      If neither a "+filter" action or "+deanimate-gifs" matches, then Privoxy passes the raw data through to the client browser as it becomes available.

    • As the browser receives the now (possibly filtered) page content, it reads and then requests any URLs that may be embedded within the page source, e.g. ad images, stylesheets, JavaScript, other HTML documents (e.g. frames), sounds, etc. For each of these objects, the browser issues a separate request (this is easily viewable in Privoxy's logs). And each such request is in turn processed just as above. Note that a complex web page will have many, many such embedded URLs. If these secondary requests are to a different server, then quite possibly a very differing set of actions is triggered.

    NOTE: This is somewhat of a simplistic overview of what happens with each URL request. For the sake of brevity and simplicity, we have focused on Privoxy's core features only.

    14.4. Troubleshooting: Anatomy of an Action

    The way Privoxy applies actions and filters to any given URL can be complex, and not always so easy to understand what is happening. And sometimes we need to be able to see just what Privoxy is doing. Especially, if something Privoxy is doing is causing us a problem inadvertently. It can be a little daunting to look at the actions and filters files themselves, since they tend to be filled with regular expressions whose consequences are not always so obvious.

    One quick test to see if Privoxy is causing a problem or not, is to disable it temporarily. This should be the first troubleshooting step. See the Bookmarklets section on a quick and easy way to do this (be sure to flush caches afterward!). Looking at the logs is a good idea too. (Note that both the toggle feature and logging are enabled via config file settings, and may need to be turned "on".)

    Another easy troubleshooting step to try is if you have done any customization of your installation, revert back to the installed defaults and see if that helps. There are times the developers get complaints about one thing or another, and the problem is more related to a customized configuration issue.

    Privoxy also provides the http://config.privoxy.org/show-url-info page that can show us very specifically how actions are being applied to any given URL. This is a big help for troubleshooting.

    First, enter one URL (or partial URL) at the prompt, and then Privoxy will tell us how the current configuration will handle it. This will not help with filtering effects (i.e. the "+filter" action) from one of the filter files since this is handled very differently and not so easy to trap! It also will not tell you about any other URLs that may be embedded within the URL you are testing. For instance, images such as ads are expressed as URLs within the raw page source of HTML pages. So you will only get info for the actual URL that is pasted into the prompt area -- not any sub-URLs. If you want to know about embedded URLs like ads, you will have to dig those out of the HTML source. Use your browser's "View Page Source" option for this. Or right click on the ad, and grab the URL.

    Let's try an example, google.com, and look at it one section at a time in a sample configuration (your real configuration may vary):

     Matches for http://www.google.com:
    
     In file: default.action [ View ] [ Edit ]
    
     {+change-x-forwarded-for{block}
     +deanimate-gifs {last}
     +fast-redirects {check-decoded-url}
     +filter {refresh-tags}
     +filter {img-reorder}
     +filter {banners-by-size}
     +filter {webbugs}
     +filter {jumping-windows}
     +filter {ie-exploits}
     +hide-from-header {block}
     +hide-referrer {forge}
     +session-cookies-only
     +set-image-blocker {pattern}
    /
    
     { -session-cookies-only }
     .google.com
    
     { -fast-redirects }
     .google.com
    
    In file: user.action [ View ] [ Edit ]
    (no matches in this file)
    

    This is telling us how we have defined our "actions", and which ones match for our test case, "google.com". Displayed is all the actions that are available to us. Remember, the + sign denotes "on". - denotes "off". So some are "on" here, but many are "off". Each example we try may provide a slightly different end result, depending on our configuration directives.

    The first listing is for our default.action file. The large, multi-line listing, is how the actions are set to match for all URLs, i.e. our default settings. If you look at your "actions" file, this would be the section just below the "aliases" section near the top. This will apply to all URLs as signified by the single forward slash at the end of the listing -- " / ".

    But we have defined additional actions that would be exceptions to these general rules, and then we list specific URLs (or patterns) that these exceptions would apply to. Last match wins. Just below this then are two explicit matches for ".google.com". The first is negating our previous cookie setting, which was for "+session-cookies-only" (i.e. not persistent). So we will allow persistent cookies for google, at least that is how it is in this example. The second turns off any "+fast-redirects" action, allowing this to take place unmolested. Note that there is a leading dot here -- ".google.com". This will match any hosts and sub-domains, in the google.com domain also, such as "www.google.com" or "mail.google.com". But it would not match "www.google.de"! So, apparently, we have these two actions defined as exceptions to the general rules at the top somewhere in the lower part of our default.action file, and "google.com" is referenced somewhere in these latter sections.

    Then, for our user.action file, we again have no hits. So there is nothing google-specific that we might have added to our own, local configuration. If there was, those actions would over-rule any actions from previously processed files, such as default.action. user.action typically has the last word. This is the best place to put hard and fast exceptions,

    And finally we pull it all together in the bottom section and summarize how Privoxy is applying all its "actions" to "google.com":

    
 Final results:
    
     -add-header
     -block
     +change-x-forwarded-for{block}
     -client-header-filter{hide-tor-exit-notation}
     -content-type-overwrite
     -crunch-client-header
     -crunch-if-none-match
     -crunch-incoming-cookies
     -crunch-outgoing-cookies
     -crunch-server-header
     +deanimate-gifs {last}
     -downgrade-http-version
     -fast-redirects
     -filter {js-events}
     -filter {content-cookies}
     -filter {all-popups}
     -filter {banners-by-link}
     -filter {tiny-textforms}
     -filter {frameset-borders}
     -filter {demoronizer}
     -filter {shockwave-flash}
     -filter {quicktime-kioskmode}
     -filter {fun}
     -filter {crude-parental}
     -filter {site-specifics}
     -filter {js-annoyances}
     -filter {html-annoyances}
     +filter {refresh-tags}
     -filter {unsolicited-popups}
     +filter {img-reorder}
     +filter {banners-by-size}
     +filter {webbugs}
     +filter {jumping-windows}
     +filter {ie-exploits}
     -filter {google}
     -filter {yahoo}
     -filter {msn}
     -filter {blogspot}
     -filter {no-ping}
     -force-text-mode
     -handle-as-empty-document
     -handle-as-image
     -hide-accept-language
     -hide-content-disposition
     +hide-from-header {block}
     -hide-if-modified-since
     +hide-referrer {forge}
     -hide-user-agent
     -limit-connect
     -overwrite-last-modified
     -prevent-compression
     -redirect
     -server-header-filter{xml-to-html}
     -server-header-filter{html-to-xml}
     -session-cookies-only
     +set-image-blocker {pattern}
    

    Notice the only difference here to the previous listing, is to "fast-redirects" and "session-cookies-only", which are activated specifically for this site in our configuration, and thus show in the "Final Results".

    Now another example, "ad.doubleclick.net":

    
 { +block{Domains starts with "ad"} }
      ad*.
    
     { +block{Domain contains "ad"} }
      .ad.
    
     { +block{Doubleclick banner server} +handle-as-image }
      .[a-vx-z]*.doubleclick.net
    

    We'll just show the interesting part here - the explicit matches. It is matched three different times. Two "+block{}" sections, and a "+block{} +handle-as-image", which is the expanded form of one of our aliases that had been defined as: "+block-as-image". ("Aliases" are defined in the first section of the actions file and typically used to combine more than one action.)

    Any one of these would have done the trick and blocked this as an unwanted image. This is unnecessarily redundant since the last case effectively would also cover the first. No point in taking chances with these guys though ;-) Note that if you want an ad or obnoxious URL to be invisible, it should be defined as "ad.doubleclick.net" is done here -- as both a "+block{}" and an "+handle-as-image". The custom alias "+block-as-image" just simplifies the process and make it more readable.

    One last example. Let's try "http://www.example.net/adsl/HOWTO/". This one is giving us problems. We are getting a blank page. Hmmm ...

    
 Matches for http://www.example.net/adsl/HOWTO/:
    
     In file: default.action [ View ] [ Edit ]
    
     {-add-header
      -block
      +change-x-forwarded-for{block}
      -client-header-filter{hide-tor-exit-notation}
      -content-type-overwrite
      -crunch-client-header
      -crunch-if-none-match
      -crunch-incoming-cookies
      -crunch-outgoing-cookies
      -crunch-server-header
      +deanimate-gifs
      -downgrade-http-version
      +fast-redirects {check-decoded-url}
      -filter {js-events}
      -filter {content-cookies}
      -filter {all-popups}
      -filter {banners-by-link}
      -filter {tiny-textforms}
      -filter {frameset-borders}
      -filter {demoronizer}
      -filter {shockwave-flash}
      -filter {quicktime-kioskmode}
      -filter {fun}
      -filter {crude-parental}
      -filter {site-specifics}
      -filter {js-annoyances}
      -filter {html-annoyances}
      +filter {refresh-tags}
      -filter {unsolicited-popups}
      +filter {img-reorder}
      +filter {banners-by-size}
      +filter {webbugs}
      +filter {jumping-windows}
      +filter {ie-exploits}
      -filter {google}
      -filter {yahoo}
      -filter {msn}
      -filter {blogspot}
      -filter {no-ping}
      -force-text-mode
      -handle-as-empty-document
      -handle-as-image
      -hide-accept-language
      -hide-content-disposition
      +hide-from-header{block}
      +hide-referer{forge}
      -hide-user-agent
      -overwrite-last-modified
      +prevent-compression
      -redirect
      -server-header-filter{xml-to-html}
      -server-header-filter{html-to-xml}
      +session-cookies-only
      +set-image-blocker{blank} }
       /
    
     { +block{Path contains "ads".} +handle-as-image }
      /ads
    

    Ooops, the "/adsl/" is matching "/ads" in our configuration! But we did not want this at all! Now we see why we get the blank page. It is actually triggering two different actions here, and the effects are aggregated so that the URL is blocked, and Privoxy is told to treat the block as if it were an image. But this is, of course, all wrong. We could now add a new action below this (or better in our own user.action file) that explicitly un blocks ( "{-block}") paths with "adsl" in them (remember, last match in the configuration wins). There are various ways to handle such exceptions. Example:

    
 { -block }
      /adsl
    

    Now the page displays ;-) Remember to flush your browser's caches when making these kinds of changes to your configuration to insure that you get a freshly delivered page! Or, try using Shift+Reload.

    But now what about a situation where we get no explicit matches like we did with:

    
 { +block{Path starts with "ads".} +handle-as-image }
     /ads
    

    That actually was very helpful and pointed us quickly to where the problem was. If you don't get this kind of match, then it means one of the default rules in the first section of default.action is causing the problem. This would require some guesswork, and maybe a little trial and error to isolate the offending rule. One likely cause would be one of the "+filter" actions. These tend to be harder to troubleshoot. Try adding the URL for the site to one of aliases that turn off "+filter":

    
 { shop }
     .quietpc.com
     .worldpay.com   # for quietpc.com
     .jungle.com
     .scan.co.uk
     .forbes.com
    

    "{ shop }" is an "alias" that expands to "{ -filter -session-cookies-only }". Or you could do your own exception to negate filtering:

    
 { -filter }
     # Disable ALL filter actions for sites in this section
     .forbes.com
     developer.ibm.com
     localhost
    

    This would turn off all filtering for these sites. This is best put in user.action, for local site exceptions. Note that when a simple domain pattern is used by itself (without the subsequent path portion), all sub-pages within that domain are included automatically in the scope of the action.

    Images that are inexplicably being blocked, may well be hitting the "+filter{banners-by-size}" rule, which assumes that images of certain sizes are ad banners (works well most of the time since these tend to be standardized).

    "{ fragile }" is an alias that disables most actions that are the most likely to cause trouble. This can be used as a last resort for problem sites.

    
 { fragile }
     # Handle with care: easy to break
     mail.google.
     mybank.example.com
    

    Remember to flush caches! Note that the mail.google reference lacks the TLD portion (e.g. ".com"). This will effectively match any TLD with google in it, such as mail.google.de., just as an example.

    If this still does not work, you will have to go through the remaining actions one by one to find which one(s) is causing the problem.

    privoxy-3.0.21-stable/./doc/webserver/user-manual/contact.html000640 001751 001751 00000037560 12114407603 023316 0ustar00fkfk000000 000000 Contacting the Developers, Bug Reporting and Feature Requests

    11. Contacting the Developers, Bug Reporting and Feature Requests

    We value your feedback. In fact, we rely on it to improve Privoxy and its configuration. However, please note the following hints, so we can provide you with the best support.

    11.1. Please provide sufficient information

    A lot of support requests don't contain enough information and can't be solved without a lot of back and forth which causes unnecessary delays. Reading this section should help to prevent that.

    Before contacting us to report a problem, please try to verify that it is a Privoxy problem, and not a browser or site problem or documented behaviour that just happens to be different than what you expected. If unsure, try toggling off Privoxy, and see if the problem persists.

    If you are using your own custom configuration, please try the default configuration to see if the problem is configuration related. If you're having problems with a feature that is disabled by default, please ask around on the mailing list if others can reproduce the problem.

    If you aren't using the latest Privoxy version, the problem may have been found and fixed in the meantime. We would appreciate if you could take the time to upgrade to the latest version and verify that the problem still exists.

    Please be sure to provide the following information when reporting problems or requesting support:

    • The exact Privoxy version you are using.

    • The operating system and versions you run Privoxy on, e.g. Windows XP SP2.

    • The name, platform, and version of the browser you were using (e.g. Internet Explorer v5.5 for Mac).

    • The URL where the problem occurred, or some way for us to duplicate the problem (e.g. http://somesite.example.com/?somethingelse=123).

    • Whether your version of Privoxy is one supplied by the Privoxy developers via SourceForge, or if you got your copy somewhere else.

    • Whether you are using Privoxy together with another proxy such as Tor. If so, please temporary disable the other proxy to see if the symptoms change.

    • Whether you are using a personal firewall product. If so, does Privoxy work without it?

    • Any other pertinent information to help identify the problem such as config or log file excerpts (yes, you should have log file entries for each action taken). To get a meaningful logfile, please make sure that the logfile directive is being used and the following debug options are enabled (all of them):

      debug     1 # Log the destination for each request Privoxy let through. See also debug 1024.
      debug     2 # show each connection status
      debug     4 # show I/O status
      debug     8 # show header parsing
      debug   128 # debug redirects
      debug   256 # debug GIF de-animation
      debug   512 # Common Log Format
      debug  1024 # Log the destination for requests Privoxy didn't let through, and the reason why.
      debug  4096 # Startup banner and warnings.
      debug  8192 # Non-fatal errors

      If you are having trouble with a filter, please additionally enable

      debug    64 # debug regular expression filters

      If you are using Privoxy 3.0.17 or later and suspect that it interprets the request or the response incorrectly, please enable

      debug 32768 # log all data read from the network

      It's easy for us to ignore log messages that aren't relevant but missing log messages may make it impossible to investigate a problem. If you aren't sure which of the debug directives are relevant, please just enable all of them and let us worry about it.

      Note that Privoxy log files may contain sensitive information so please don't submit any logfiles you didn't read first. You can mask sensitive information as long as it's clear that you removed something.

    You don't have to tell us your actual name when filing a problem report, but if you don't, please use a nickname so we can differentiate between your messages and the ones entered by other "anonymous" users that may respond to your request if they have the same problem or already found a solution. Note that due to spam the trackers may not always allow to post without being logged into SourceForge. If that's the case, you are still free to create a login that isn't directly linked to your name, though.

    Please also check the status of your request a few days after submitting it, as we may request additional information. If you use a SF id, you should automatically get a mail when someone responds to your request. Please don't bother to add an email address when using the tracker. If you prefer to communicate through email, just use one of the mailing lists directly.

    If you are new to reporting problems, you might be interested in How to Report Bugs Effectively.

    The appendix of the Privoxy User Manual also has helpful information on understanding actions, and action debugging.

    11.2. Get Support

    For casual users, our support forum at SourceForge is probably best suited: http://sourceforge.net/tracker/?group_id=11118&atid=211118

    All users are of course welcome to discuss their issues on the users mailing list, where the developers also hang around.

    Please don't send private support requests to individual Privoxy developers, either use the mailing lists or the support trackers.

    If you have to contact a Privoxy developer directly for other reasons, please send a real mail and do not bother with SourceForge's messaging system. Answers to SourceForge messages are usually bounced by SourceForge's mail server in which case the developer wasted time writing a response you don't get. From your point of view it will look like your message has been completely ignored, so this is frustrating for all parties involved.

    Note that the Privoxy mailing lists are moderated. Posts from unsubscribed addresses have to be accepted manually by a moderator. This may cause a delay of several days and if you use a subject that doesn't clearly mention Privoxy or one of its features, your message may be accidentally discarded as spam.

    If you aren't subscribed, you should therefore spend a few seconds to come up with a proper subject. Additionally you should make it clear that you want to get CC'd. Otherwise some responses will be directed to the mailing list only, and you won't see them.

    11.3. Reporting Problems

    "Problems" for our purposes, come in two forms:

    • Configuration issues, such as ads that slip through, or sites that don't function properly due to one Privoxy "action" or another being turned "on".

    • "Bugs" in the programming code that makes up Privoxy, such as that might cause a crash.

    11.3.1. Reporting Ads or Other Configuration Problems

    Please send feedback on ads that slipped through, innocent images that were blocked, sites that don't work properly, and other configuration related problem of default.action file, to http://sourceforge.net/tracker/?group_id=11118&atid=460288, the Actions File Tracker.

    New, improved default.action files may occasionally be made available based on your feedback. These will be announced on the ijbswa-announce list and available from our the files section of our project page.

    11.3.2. Reporting Bugs

    Please report all bugs through our bug tracker: http://sourceforge.net/tracker/?group_id=11118&atid=111118.

    Before doing so, please make sure that the bug has not already been submitted and observe the additional hints at the top of the submit form. If already submitted, please feel free to add any info to the original report that might help to solve the issue.

    11.4. Request New Features

    You are welcome to submit ideas on new features or other proposals for improvement through our feature request tracker at http://sourceforge.net/tracker/?atid=361118&group_id=11118.

    11.5. Mailing Lists

    If you prefer to communicate through email, instead of using a web interface, feel free to use one of the mailing lists. To discuss issues that haven't been completely diagnosed yet, please use the Privoxy users list. Technically interested users and people who wish to contribute to the project are always welcome on the developers list. You can find an overview of all Privoxy-related mailing lists, including list archives, at: http://sourceforge.net/mail/?group_id=11118.

    privoxy-3.0.21-stable/./doc/webserver/p_feedback.css000640 001751 001751 00000000377 10546014107 021315 0ustar00fkfk000000 000000 /* * Vary the gereneral Privoxy Stlyesheet to * meet the needs of small popups: * * $Id: p_feedback.css,v 1.4 2002/04/09 13:03:42 oes Exp $ */ body,td,th { font-size:10px; } div.info { width: 60%; } div.warning { width: 60%; text-align: left; } privoxy-3.0.21-stable/./doc/webserver/README.txt000640 001751 001751 00000000363 10546014107 020231 0ustar00fkfk000000 000000 All files contained in this directory should eventually be on the project's homepage ijbswa.sourceforge.net:/home/groups/i/ij/ijbswa/htdocs/ which is indeed http://ijbswa.sourceforge.net and http://www.privoxy.org/. -Stefan, April 2002privoxy-3.0.21-stable/./doc/webserver/index.html000640 001751 001751 00000011636 12114164411 020532 0ustar00fkfk000000 000000 Privoxy - Home Page

    Privoxy - Home Page

    Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks.

    Privoxy is Free Software and licensed under the GNU GPLv2.

    Privoxy is an associated project of Software in the Public Interest (SPI).

    Helping hands and donations are welcome:

    The most recent release is 3.0.21 (stable).



    Privoxy is developed on:

    Copyright © 2001-2013 by Privoxy Developers

    privoxy-3.0.21-stable/./doc/webserver/announce.txt000640 001751 001751 00000055170 12116121451 021104 0ustar00fkfk000000 000000 Announcing Privoxy 3.0.21 stable -------------------------------------------------------------------- Privoxy 3.0.21 stable is a bug-fix release for Privoxy 3.0.20 beta. It also addresses two security issues that affect all previous Privoxy versions. -------------------------------------------------------------------- ChangeLog for Privoxy -------------------------------------------------------------------- *** Version 3.0.21 stable *** - Bug fixes: - On POSIX-like platforms, network sockets with file descriptor values above FD_SETSIZE are properly rejected. Previously they could cause memory corruption in configurations that allowed the limit to be reached. - Proxy authentication headers are removed unless the new directive enable-proxy-authentication-forwarding is used. Forwarding the headers potentionally allows malicious sites to trick the user into providing them with login information. Reported by Chris John Riley. - Compiles on OS/2 again now that unistd.h is only included on platforms that have it. - General improvements: - The show-status page shows the FEATURE_STRPTIME_SANITY_CHECKS status. - A couple of assert()s that could theoretically dereference NULL pointers in debug builds have been relocated. - Added an LSB info block to the generic start script. Based on a patch from Natxo Asenjo. - The max-client-connections default has been changed to 128 which should be more than enough for most setups. - Action file improvements: - Block rover.ebay./ar.*\&adtype= instead of "/.*\&adtype=" which caused too man false positives. Reported by u302320 in #360284, additional feedback from Adam Piggott. - Unblock '.advrider.com/' and '/.*ADVrider'. Anonymously reported in #3603636. - Stop blocking '/js/slider\.js'. Reported by Adam Piggott in #3606635 and _lvm in #2791160. - Filter file improvements: - Added an iframes filter. - Documentation improvements: - The whole GPLv2 text is included in the user manual now, so Privoxy can serve it itself and the user can read it without having to wade through GPLv3 ads first. - Properly numbered and underlined a couple of section titles in the config that where previously overlooked due to a flaw in the conversion script. Reported by Ralf Jungblut. - Improved the support instruction to hopefully make it harder to unintentionally provide insufficient information when requesting support. Previously it wasn't obvious that the information we need in bug reports is usually also required in support requests. - Removed documentation about packages that haven't been provided in years. - Privoxy-Regression-Test: - Only log the test number when not running in verbose mode The position of the test is rarely relevant and it previously wasn't exactly obvious which one of the numbers was useful to repeat the test with --test-number. - GNUmakefile improvements: - Factor generate-config-file out of config-file to make testing more convenient. - The clean target now also takes care of patch leftovers. *** Version 3.0.20 beta *** - Bug fixes: - Client sockets are now properly shutdown and drained before being closed. This fixes page truncation issues with clients that aggressively pipeline data on platforms that otherwise discard already written data. The issue mainly affected Opera users and was initially reported by Kevin in #3464439, szotsaki provided additional information to track down the cause. - Fix latency calculation for shared connections (disabled by default). It was broken since their introduction in 2009. The calculated latency for most connections would be 0 in which case the timeout detection failed to account for the real latency. - Reject URLs with invalid port. Previously they were parsed incorrectly and characters between the port number and the first slash were silently dropped as shown by curl test 187. - The default-server-timeout and socket-timeout directives accept 0 as valid value. - Fix a race condition on Windows that could cause Privoxy to become unresponsive after toggling it on or off through the taskbar icon. Reported by Tim H. in #3525694. - Fix the compilation on Windows when configured without IPv6 support. - Fix an assertion that could cause debug builds to abort() in case of socks5 connection failures with "debug 2" enabled. - Fix an assertion that could cause debug builds to abort() if a filter contained nul bytes in the replacement text. - General improvements: - Significantly improved keep-alive support for both client and server connections. - New debug log level 65536 which logs all actions that were applied to the request. - New directive client-header-order to forward client headers in a different order than the one in which they arrived. - New directive tolerate-pipelining to allow client-side pipelining. If enabled (3.0.20 beta enables it by default), Privoxy will keep pipelined client requests around to deal with them once the current request has been served. - New --config-test option to let Privoxy exit after checking whether or not the configuration seems valid. The limitations noted in TODO #22 and #23 still apply. Based on a patch by Ramkumar Chinchani. - New limit-cookie-lifetime{} action to let cookies expire before the end of the session. Suggested by Rick Sykes in #1049575. - Increase the hard-coded maximum number of actions and filter files from 10 to 30 (each). It doesn't significantly affect Privoxy's memory usage and recompiling wasn't an option for all Privoxy users that reached the limit. - Add support for chunk-encoded client request bodies. Previously chunk-encoded request bodies weren't guaranteed to be forwarded correctly, so this can also be considered a bug fix although chunk-encoded request bodies aren't commonly used in the real world. - Add support for Tor's optimistic-data SOCKS extension, which can reduce the latency for requests on newly created connections. Currently only the headers are sent optimistically and only if the client request has already been read completely which rules out requests with large bodies. - After preventing the client from pipelining, don't signal keep-alive intentions. When looking at the response headers alone, it previously wasn't obvious from the client's perspective that no additional responses should be expected. - Stop considering client sockets tainted after receiving a request with body. It hasn't been necessary for a while now and unnecessarily causes test failures when using curl's test suite. - Allow HTTP/1.0 clients to signal interest in keep-alive through the Proxy-Connection header. While such client are rare in the real world, it doesn't hurt and couple of curl tests rely on it. - Only remove duplicated Content-Type headers when filters are enabled. If they are not it doesn't cause ill effects and the user might not want it. Downgrade the removal message to LOG_LEVEL_HEADER to clarify that it's not an error in Privoxy and is unlikely to cause any problems in general. Anonymously reported in #3599335. - Set the socket option SO_LINGER for the client socket. - Move several variable declarations to the beginning of their code block. It's required when compiling with gcc 2.95 which is still used on some platforms. Initial patch submitted by Simon South in #3564815. - Optionally try to sanity-check strptime() results before trusting them. Broken strptime() implementations have caused problems in the past and the most recent offender seems to be FreeBSD's libc (standards/173421). - When filtering is enabled, let Range headers pass if the range starts at the beginning. This should work around (or at least reduce) the video playback issues with various Apple clients as reported by Duc in #3426305. - Do not confuse a client hanging up with a connection time out. If a client closes its side of the connection without sending a request line, do not send the CLIENT_CONNECTION_TIMEOUT_RESPONSE, but report the condition properly. - Allow closing curly braces as part of action values as long as they are escaped. - On Windows, the logfile is now written before showing the GUI error message which blocks until the user acknowledges it. Reported by Adriaan in #3593603. - Remove an unreasonable parameter limit in the CGI interface. The new parameter limit depends on the memory available and is currently unlikely to be reachable, due to other limits in both Privoxy and common clients. Reported by Andrew on ijbswa-users@. - Decrease the chances of parse failures after requests with unsupported methods were sent to the CGI interface. - Action file improvements: - Remove the comment that indicated that updated default.action versions are released on their own. - Block 'optimize.indieclick.com/' and 'optimized-by.rubiconproject.com/' - Unblock 'adjamblog.wordpress.com/' and 'adjamblog.files.wordpress.com/'. Reported by Ryan Farmer in #3496116. - Unblock '/.*Bugtracker'. Reported by pwhk in #3522341. - Add test URLs for '.freebsd.org' and '.watson.org'. - Unblock '.urbandictionary.com/popular'. - Block '.adnxs.com/'. - Block 'farm.plista.com/widgetdata.php'. - Block 'rotation.linuxnewmedia.com/'. - Block 'reklamy.sfd.pl/'. Reported by kacperdominik in #3399948. - Block 'g.adspeed.net/'. - Unblock 'websupport.wdc.com/'. Reported by Adam Piggot in #3577851. - Block '/openx/www/delivery/'. - Disable fast-redirects for '.googleapis.com/'. - Block 'imp.double.net/'. Reported by David Bo in #3070411. - Block 'gm-link.com/' which is used for email tracking. Reported by David Bo in #1812733. - Verify that requests to "bwp." are blocked. URL taken from #1736879 submitted by Francois Marier. - Block '/.*bannerid='. Reported by Adam Piggott in #2975779. - Block 'cltomedia.info/delivery/' and '.adexprt.com/'. Anonymously reported in #2965254. - Block 'de17a.com/'. Reported by David Bo in #3061472. - Block 'oskar.tradera.com/'. Reported by David Bo in #3060596. - Block '/scripts/webtrends\.js'. Reported by johnd16 in #3002729. - Block requests for 'pool.*.adhese.com/'. Reported by johnd16 in #3002716. - Update path pattern for Coremetrics and add tests. Pattern and URLs submitted by Adam Piggott #3168443. - Enable +fast-redirects{check-decoded-url} for 'tr.anp.se/'. Reported by David Bo in #3268832. - Unblock '.conrad.se/newsletter/banners/'. Reported by David Bo in #3413824. - Block '.tynt.com/'. Reported by Dan Stahlke in #3421767. - Unblock '.bbci.co.uk/radio/'. Reported by Adam Piggott in #3569603. - Block requests to 'service.maxymiser.net/'. Reported by johnd16 in #3118401 (with a previous URL). - Disable fast-redirects for Google's "let's pretend your computer is infected" page. - Unblock '/.*download' to resolve actionsfile feedback #3498129. Submitted by Steven Kolins (soundcloud.com not working). - Unblock '.wlxrs.com/' which is required by hotmail.com. Fixes #3413827 submitted by David Bo. - Add two unblock patterns for popup radio and TV players. Submitted by Adam Piggott in #3596089. - Filter file improvements & bug fixes: - Add a referer tagger. - Reduce the likelihood that the google filter messes up HTML-generating JavaScript. Reported by Zeno Kugy in #3520260. - Documentation improvements: - Revised all OS X sections due to new packaging module (OSXPackageBuilder). - Update the list of supported operating systems to clarify that all Windows versions after 95 are expected to work and note that the platform-specific code for AmigaOS and QNX currently isn't maintained. - Update 'Signals' section, the only explicitly handled signals are SIGINT, SIGTERM and SIGHUP. - Add Haiku to the list of operating systems on which Privoxy is known to run. - Add DragonFly to the list of BSDs on which Privoxy is known to run. - Removed references to redhat-specific documentation set since it no longer exists. - Removed references to building PDFs since we no longer do so. - Multiple listen-address directives are supported since 3.0.18, correct the documentation to say so. - Remove bogus section about long and short being preferable to int. - Corrected some Internet JunkBuster references to Privoxy. - Removed references to www.junkbusters.com since it is no longer maintained. Reported by Angelina Matson. - Various grammar and spelling corrections - Add a client-header-tagger{} example for disabling filtering for range requests. - Correct a URL in the "Privoxy with Tor" FAQ. - Spell 'refresh-tags' correctly. Reported by Don in #3571927. - Sort manpage options alphabetically. - Remove an incorrect sentence in the toggle section. The toggle state doesn't affect whether or not the Windows version uses the tray icon. Reported by Zeno Kugy in #3596395. - Add new contributors since 3.0.19. - Log message improvements: - When stopping to watch a client socket due to pipelining, additionally log the socket number. - Log the client socket and its condition before closing it. This makes it more obvious that the socket actually gets closed and should help when diagnosing problems like #3464439. - In case of SOCKS5 failures, do not explicitly log the server's response. It hasn't helped so far and the response can already be logged by enabling "debug 32768" anyway. This reverts v1.81 and the follow-up bug fix v1.84. - Relocate the connection-accepted message from listen_loop() to serve(). This way it's printed by the thread that is actually serving the connection which is nice when grepping for thread ids in log files. - Code cleanups: - Remove compatibility layer for versions prior to 3.0 since it has been obsolete for more than 10 years now. - Remove the ijb_isupper() and ijb_tolower() macros from parsers.c since they aren't used in this file. - Removed the 'Functions declared include:' comment sections since they tend to be incomplete, incorrect and out of date and the benefit seems questionable. - Various comment grammar and comprehensibility improvements. - Remove a pointless fflush() call in chat(). Flushing all streams pretty much all the time for no obvious reason is ridiculous. - Relocate ijb_isupper()'s definition to project.h and get the ijb_tolower() definition from there, too. - Relocate ijb_isdigit()'s definition to project.h. - Rename ijb_foo macros to privoxy_foo. - Add malloc_or_die() which will allow to simplify code paths where malloc() failures don't need to be handled gracefully. - Add strdup_or_die() which will allow to simplify code paths where strdup() failures don't need to be handled gracefully. - Replace strdup() calls with strdup_or_die() calls where it's safe and simplifies the code. - Fix white-space around parentheses. - Add missing white-space behind if's and the following parentheses. - Unwrap a memcpy() call in resolve_hostname_to_ip(). - Declare pcrs_get_delimiter()'s delimiters[] static const. - Various optimisations to remove dead code and merge inefficient code structures for improved clarity, performance or code compactness. - Various data type corrections. - Change visibility of several code segments when compiling without FEATURE_CONNECTION_KEEP_ALIVE enabled for clarity. - In pcrs_get_delimiter(), do not use delimiters outside the ASCII range. Fixes a clang complaint. - Fix an error message in get_last_url() nobody is supposed to see. Reported by Matthew Fischer in #3507301. - Fix a typo in the no-zlib-support complaint. Patch submitted by Matthew Fischer in #3507304. - Shorten ssplit()'s prototype by removing the last two arguments. We always want to skip empty fields and ignore leading delimiters, so having parameters for this only complicates the API. - Use an enum for the type of the action value. - Rename action_name's member takes_value to value_type as it isn't used as boolean. - Turn family mismatches in match_sockaddr() into fatal errors. - Let enlist_unique_header() verify that the caller didn't pass a header containing either \r or \n. - Change the hashes used in load_config() to unsigned int. That's what hash_string() actually returns and using a potentially larger type is at best useless. - Use privoxy_tolower() instead of vanilla tolower() with manual casting of the argument. - Catch ssplit() failures in parse_cgi_parameters(). - Privoxy-Regression-Test: - Add an 'Overwrite condition' directive to skip any matching tests before it. As it has a global scope, using it is more convenient than clowning around with the Ignore directive. - Log to STDOUT instead of STDERR. - Include the Privoxy version in the output. - Various grammar and spelling corrections in documentation and code. - Additional tests for range requests with filtering enabled. - Tests with mostly invalid range request. - Add a couple of hide-if-modified-since{} tests with different date formats. - Cleaned up the format of the regression-tests.action file to match the format of default.action. - Remove the "Copyright" line from print_version(). When using --help, every line of screen space matters and thus shouldn't be wasted on things the user doesn't care about. - Privoxy-Log-Parser: - Improve the --statistics performance by skipping sanity checks for input that shouldn't affect the results anyway. Add a --strict-checks option that enables some of the checks again, just in case anybody cares. - The distribution of client requests per connection is included in the --statistic output. - The --accept-unknown-messages option has been removed and the behavior is now the default. - Accept and (mostly) highlight new log messages introduced with Privoxy 3.0.20. - uagen: - Bump generated Firefox version to 17. - GNUmakefile improvements: - The dok-tidy target no longer taints documents with a tidy-mark - Change RA_MODE from 0664 to 0644. Suggested by Markus Dittrich in #3505445. - Remove tidy's clean flag as it changes the scope of attributes. Link-specific colors end up being applied to all text. Reported by Adam Piggott in #3569551. - Leave it up to the user whether or not smart tags are inserted. - Let w3m itself do the line wrapping for the config file. It works better than fmt as it can honour pre tags causing less unintentional line breaks. - Ditch a pointless '-r' passed to rm to delete files. - The config-file target now requires less manual intervention and updates the original config. - Change WDUMP to generate ASCII. Add WDUMP_UTF8 to allow UTF-8 in the AUTHORS file so the names are right. - Stop pretending that lynx and links are supported for the documentation. - configure improvements: - On Haiku, do not pass -lpthread to the compiler. Haiku's pthreads implementation is contained in its system library, libroot, so no additional library needs to be searched. Patch submitted by Simon South in #3564815. - Additional Haiku-specific improvements. Disable checks intended for multi-user systems as Haiku is presently single-user. Group Haiku-specific settings in their own section, following the pattern for Solaris, OS/2 and AmigaOS. Add additional library-related settings to remove the need for providing configure with custom LDFLAGS. Submitted by Simon South in #3574538. ----------------------------------------------------------------- About Privoxy: ----------------------------------------------------------------- Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks. Privoxy is Free Software and licensed under the GNU GPLv2. Privoxy is an associated project of Software in the Public Interest (SPI). Helping hands and donations are welcome: * http://www.privoxy.org/faq/general.html#PARTICIPATE * http://www.privoxy.org/faq/general.html#DONATE At present, Privoxy is known to run on Windows 95 and later versions (98, ME, 2000, XP, Vista, Windows 7 etc.), GNU/Linux (RedHat, SuSE, Debian, Fedora, Gentoo, Slackware and others), Mac OS X (10.4 and upwards on PPC and Intel processors), OS/2, Haiku, DragonFly, FreeBSD, NetBSD, OpenBSD, Solaris, and various other flavors of Unix. In addition to the core features of ad blocking and cookie management, Privoxy provides many supplemental features, that give the end-user more control, more privacy and more freedom: * Supports "Connection: keep-alive". Outgoing connections can be kept alive independently from the client. Currently not available on all platforms. * Supports IPv6, provided the operating system does so too, and the configure script detects it. * Supports tagging which allows to change the behaviour based on client and server headers. * Can be run as an "intercepting" proxy, which obviates the need to configure browsers individually. * Sophisticated actions and filters for manipulating both server and client headers. * Can be chained with other proxies. * Integrated browser based configuration and control utility at http://config.privoxy.org/ (shortcut: http://p.p/). Browser-based tracing of rule and filter effects. Remote toggling. * Web page filtering (text replacements, removes banners based on size, invisible web-bugs and HTML annoyances, etc.) * Modularized configuration that allows for standard settings and user settings to reside in separate files, so that installing updated actions files won't overwrite individual user settings. * Support for Perl Compatible Regular Expressions in the configuration files, and a more sophisticated and flexible configuration syntax. * GIF de-animation. * Bypass many click-tracking scripts (avoids script redirection). * User-customizable HTML templates for most proxy-generated pages (e.g. "blocked" page). * Auto-detection and re-reading of config file changes. * Most features are controllable on a per-site or per-location basis. Download location: http://sourceforge.net/project/showfiles.php?group_id=11118 Home Page: http://www.privoxy.org/ - Privoxy Developers privoxy-3.0.21-stable/./doc/webserver/team/07member.jpg000640 001751 001751 00000001644 10546014105 021602 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄÿÄÿÄÿÚ ?•ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/03andreas.jpg000640 001751 001751 00000122562 10546014105 021747 0ustar00fkfk000000 000000 ÿØÿàJFIFÿþXCREATOR: XV Version 3.10a Rev: 12/29/94 (PNG patch 1.2) Quality = 75, Smoothing = 0 ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ<"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?òî´´Rö÷¬FwÍÍ'J`/z3Fhï@ ïŠ1š3@é@Å£4™ô P¸£ŠLâ—4¼ %í@ @u¢†ý(¤4¹¤€¥Óix 4 Z3Å'9¦÷¢Ž”¹4\BQÏZ(ê(¾Ô J=è° ÒŒúRw¥éH`GzJ3ëKÇjb”™£½{ÒE˜4´”½³F8¥Î ‘GŸ…¿}:Òcb†yæƒAéF9ë@i:Ò÷¢‹”¼)3ž=h z;ÑE1 É4¸ô£µb…¤}(úÑš(í@ƒœÒQGZ@'zZCF*c ÒRÑøÐu4v£84@ƒ8¤ ”Q@Äb—µ% (4œÐšJZ8 7ç4½hÇRâ’–/“QLõ¢Š(ÀPh¥ Aïš šZN”gµ:ŠN”´h¢”cÖ€Bv¥âƒIj\àÑÁ£µ)¦ŒñÍ&izÓ>ÔF)(sÚŠ)\ £­M%-£­…1…/j@)i(ÍQp æ­Qï@J(4RRö£=¨(À¢“½(£=©;Ñ@ šJ1ÞŒP‘š3E!¹ãgÚ’Œæ˜0(£¥J(Í%€8gÒŽô逓íEíIƒ@ šNMs@zNô½ ,'J3AëAäP ¤£·v “µ)¤ ¢ƒÍ ÏåKšJ(hý(¤÷ ¥ïIü©zŠ—ëIÐÑ@ Ö—¥6—4´cšNô¢€æŠSÍ&hꓞ´‚­Ö€”Szô¢\4Ÿ™Å.x Q@£Ó½¨íG^ôŸÎ„!{QúÒPi´u¤Í £<Òw¥ ëG~);Ñß wjO æ“=©Eôf“9éEIÒ€x£¯J\ÒgšJ3@j-”wÍ ÑFhÍëGZ3Ò÷¡ Z9£µÍ1^h¤Ï¥&hÍ)i)g­&ir)=èi;ÑÒŠ`£4z1Í Lâ–’€(¢ŠJ_j(ëŠB´3Î3Hi€Phã­%( âõ aô¥¤é֌Рã"—µ7­.i´R†–˜ @&“9£4 wz%.iqKIÚŒæ˜ ßgšoAN éKMϵö¤³ëE'Å ;ÒÑÞâžà8¾´”qF}(½è™4PæŒÒ )êNsIéFsÅœÒûRf“4áëFAúÒi8ìÐj 'UûÄ~uZKõå4ÐíÍ1œsYÇQaô¨e¾/€=hWÎOZ…ïB7|V?ÚœwsëëQ½Ã°ç­gûJ,óšd—Ê:V.ãœçœR³±ïš«eÔþnAúÓ—Sx|úqŠ„‚¥òþBý©¡8ëEÀh'ô¤ŒƆÀ\müi iˆ–9?1 UËkÓÇ­SùÕpÊ4Ìóš@tKuc­JcŠæÖfB'­^·¾`ß1Í+Í­Ynч^*pÙ¤‡J 74d‘@ :ÐzÑGô ¥'4‡Š\ô¦E¤ Í™£4´RPi¦“­%yÄu¢’ IÍ)¤í@&=éi3LQI“øP)£¥(Á‚—W^GáVÀªíaÔ‚y©Coá•ïqÄSr)(€’~ݧ,&_äyÁ©Ö™Ê§ÑÎ?iYJ!Úf©¸X…옮P‚= Aå•;Hç¥i –0ØäÒÊ*y‘‚[?0­ ”Íh‰Àäô¨€òÜd‘ŠÒe¾B³RMËÞ¨ëO˜V3Ñã'>Zàÿíî*9"R7!⦑"ÿ–JCtœÎˆä–ßxØWÌRŒÎAúÿ1Ͷº”ö7_zMØ>õe]£À#+ŸJŠTå{Õ¦+C/î¦9* ŸCš·k{ýê¡`JޤåQ¯â‹èbd5.qŒW?ÅFrsVâ¼#ž EÄö úUX®UßõïVæŠhíIÔQ@‰6'p?0lzcüi™íéRG‚’ösQ{Ð6.i3Iš(¹8¢“ÒŠ)g“¥ 3Fh¤=h8¥Í'Z>´À QžhȘ†çRbç@ŒúÒ 3@ /zolPìŠPi½­ÐºÒQA>Ô ֌њ:Ð!sFi(ë@Çw£<Ò{P?Z Ó¹æš)hi=¨Î(Í)ãëUä“ÿúÕ0ÏZ§{"ÄL@eäŠC –ç pFB¥à!>ý…:8b[/ZЂݨ òŽsŽ´ÛH¤„‚HC»' ïRÆŒXáq“Å[Ï âžûc;NÕu'9¨¹z٣ą˜uÛŽ)ñÛ,œ²6ÁøÎ\m¨K}¥í>[zRîRH°-áUåÎGaÅH“[ˆ{3ï¿ùŒV{]ßx/àjUÔ!*¤Ç‚)YŽèµ…bÞP¡Fi§3:#‚BôµUûj¾qòöxž·¡‘KQérw1¬€8Á=ÓœS&Ê±Ú ViÕX„pI霊•.Š.49ädf‹1‘‹_-°¼ØäÓ[1¾T:‘ÜéO3+ÊT¼TmrI8ÎSOP²ÒHýXœwÅ7ÊeÎHéƒD“Ç(* ×¥@ÆUM4…b6‰Æ9ÏJ‰ÐvñíSoÈ;¸ô50çDÙ¬nØŽØ«E0rä/~M@]±ŽŸJo w1•™ÀzŠ6ý¼ãŒR°¬m$Êý*LÖE¬¬€³goJÒò¢#` Ïpiƒ Í"µ(¡ÀÒw£½(ïEèRæ’ó@ š(ö¢… šC@…£4™çð¤ 4””´Æ´”´¹ë@<Òw£?5 9é@bjìv«Œî9Ï94›CQ*Gkq.vBʧû­¶¤lŠ 0o|Éš¹å#6Ñ"¯© Ö¢™n~S^´“)¡¿eNT€N3ïYóYÆív\wŠ˜íBqÁö¨Ü–äÙ NÅ\´lw©*1óŽßZš À ¨Þ&¢o0gÐv5—»‘Áª½ ­:>æt_fU ¸qÙXz0Ȧ,$ŒpÖ‘Pç~T¬Š³#.Æ>‚œJ¤J¡Ïü œÓLG¡Jtp¥H$QqØa^2Ãô5gCŸ¼= «>K©ùNiÆ<õojk•äL®äå;f«çšÒ05Û0±@r”yê)Üpxj°Ð‘Í*B$lt5DجG÷ºÓ6\0Uæ…€G#¥BÈKÒ½´¶O?… <‚*Ç“œ‘Øf¢1~´Ñ6\ç )$Žy¤*x=éÀä}h`4¤…C€Bþ†H㤅lqK#xŒì)ˆc.2j<qR±ãÚ¢bGaM ‰’FZR¡¿¥÷4w Vª±;†åô&£ÎjWå6Ó ž½½)¢u\ˆp Ÿ5$7eF3‘ïUdûõ78Í;hK7!]rZ—ubÁ!ëR ­×ƒr|þtf“9¥÷¤ïE'dÓMhÈÅ! BÒzÑÐÒR¤çñ¤æŽÔvÅ0 Nh'ƒFMJJn9£<Ð1Ùçš3IÅ”¹æŽØ£ÞŠ\ÑH .h:3IE!¥Í'ZO~ÔÀuÑëE =ésMϯZۤñšk>:ÒžR¸”ã€æã©U¢…¦|L“éHAí’kJÒÏ÷gqÇ®OéCv*(Kqä /sÎ;Š´3¶é>Dþéê hPŠ®xlô=ª_3 ºFÚ{“×ò¬üËV&1¬°‚v=MI Án?|ÜŽ¸Á5™-óëmÏñɪ™n¥³G+cf]K,X Ôn«µó¾à7¿JÏRû8Ç#ãæEtͦÙÁÁëJlqòœŸCK˜=™ÆË¦lŒß¡ªí`@%GCÍuòؕʔ85 V]ƒƒÚ­H—H牸¶Œ2ÖsY°`vòk¸‹OòþðïƒÅU¸ÒÇÚ0ªH9ˆtÎHZ•#Š>ÀIÔÔ„éœl–¤q´æ¡6Ås‘Åu’Ø/žÄ Œàj£{i“ò®F*¹ˆp9¹cùGƒQȧn:VœÖ­ž‡š‚HìiÜÍÄ¢T•Ük óVJ§Š„®?Æ©14A×ΜœƒÇÐÒ„ÇAK£ɰÜàzct-ÜP2I'ð¥ôÄ1±¸sLÇ4æá©Ü1L‹¹"¯[ÍëÚª„$d•NÖàcžh`ѯïéOªVóc‚pqéVƒd B:RúRsAéš@Š;QLBçŒRRRÒ;QÐÑÞƒLaKIÓÞŒß4¶IFs@éLBô£<)3Ú”P÷£4Üþt´d Z( ÍÏ”t =84¹â›Á8£4Xb“Fphþ´wÅ BŠ\ŒÓhw|P29æ!H^+>IŽ0§'¹«SÙÛ£¿­VnojW™gNç“qùT¦µfuÆ"N=꽜$ Â:Ô“òDi÷‰è; ‡©kDSÉPXvîÄôZyä$±Æ0*Ó»chF½TvRÇ&©Œ)\8?­H©æc°>ô‘®ï½Z¶6›Š»/àPØâ®Ä·°fF=ëV-7ËP >ƒ¥_´¶D·Zºsð8¬œã>+2Ä0Z½‰ qW`€uÅ\TPfäl¢PK6Œ‚™ÇCš•W2늾¨H8¥òrG4®ib8ÑqƒïéS-°lôõÎ(HHéøU¨“ž´›D fÏQV£¶°5:&š(*c"[UϦX€)ËéOíŠ@F"Üz cZ¯ðŒÜU¥†„4V·šÑA$õ5aPœsëS(C±F[E‘x?J¢Ö;$Ü÷­Â=ª6Lö¦˜$e$ ÃæýzzÚ ÿ0Õwɵ(Aœ÷£™ƒF|ö!¾`åU¾ÀZP °€bÍ9Gµ;oµ!€¥ïJœW=($h§ã‘Wš\ÓÅ4SÀÅ.E#+Q‘S) ‘M5!¤Å Ô®ËQ7e‡`Ž”‚Åv#iöªåwMX•~SQ•ùxªL,eMf³HXöâªM§¢Œó[eqÚ •;b©H—™– ƒYweXâºÉ-Ç'qm·'¤dg(´°oR1÷kæ¬xâºÉ-ÎKc†æ³n-71,>†µR9¥™qê*5až™­[‹ Ž*©µ~p¤ãӚטçqÔšÚ#,nA£ ÿ¼ ]‰C‚Ýn*„Lѧïqõ«Ñp¥³ÏQíRƈ‚‹Dàá¹UpváO;ö"¶¡HÙöÜgË9 ŽÆ³o-62)EŠHtn`ŽiÙÇÒªFà.On¸«J~QïZ‹G~h¢J1Á =q@ëE—ë@ Ø(ö¤'èÜ -% v4´ÚSÏ” PM¤Š/õ¥Î>´ÜÑšvh’Š:u¤¢íJ}i™¥Ï ±&sÀ¨®Ï’5RJ™½G,€.99ì*W+iEÖfýJ–RD+šõP ¬d~5¼ˆ°É`KrG÷j¾—k¶ÚK—Æîù•FîÆLgpôô©nå쉥”ùnCž}*¡‰Pînx÷5e—(KÇËì=*68Q‘Ž>´†0[lc<±­­:ßb`uc’j¼$sÇ&¶íU!„2zÒl¸-M hÒ8óëÎ=iì>cž™Í6#ònÇ^€v§1'“ߨ¬™ÕJ½ñ×{T±)æ9#½B¸«*8 Õ"Ty©S­F‹‘S"ò*J&Eç¥N«ÇZdjsÏJTsH¤‡"Œf¤cŠP½)ê¹5#ÏZzÒ¬y5&ÌqŠcE?ŽÜS”w MW#¡iiàƒE€nÜt£ ÷éC ”ÄB{ÓzTÅF 0¯4X¤DH4dmÇZV4„ qŽy¤QÔR} "l!.;T„LzÐY*j8u—"«ÃÚ¢±Õ¯i×ô¨Xv¦”¤sT§MÃn8"´&]¹ª®œ´ÉhÉš¨<çp­¹—Ž•IâÈâ´LÂq0.,ò§‘Y;^²«{Zêg]½ºŠÆ¼€oߌm Ö‰œÓF]Î6!#9àTð/Lœ«u>”·*nñ»(Ü6?nš srÊ‘ßOc>¦¥¼a£;øeùOµQ.n`‘X~õG¸z){™ 0}f¹Åè”dò=(@ÌÖ&6Æ8=jÜgŒuª¤›Óµ:Øœ Õ¦fË—cJ)’QEúQži3Ò‚h½¸¤ f“#i¦@ G×ò¥€Òf‚‡QMô¥Ï4hæZJ\óÅ”y¤úÐóKô¦ƒKß4uÜÑš@?Žy¨Ù¹ ŸÒ™Ë6Zc!f0ÏÝ^qëW#F¸»(Ì„Ž?•S1åÎ;qZÖ„Ëtg#l¯áÅK--KÓ3X†)ËPGi ÿž‡?AEÄåKŽîFj8nH¨½GÔ-†[³8ac÷¿ãLò¾m£¯µ>EÞþ^3ÎÕü(fÆæ_¾zgµ1—B¢… äâ¬Â„œž‚ªÄ¹ÚMiÄp©?xõ‚¥ØÒ(±p8þ¿- „ö¥?xÞ²lê‚&@jÂ*(êt5 š¢T\ UˆùÇjÌIÐÔ²‰I5aW"*P¸R\óš°©LTÇ5(ì ŠvÜÒ…8â•U4Ò1ŠvÜ”íÍ(DRJWtŽ›Tc¥U¼¼iÖ8½ýMC-²;›ƒ,²3ݪ]9 ³¨Ú9cëU™–MŠ3#3{“Z6.–z{8#Í—gøEWA"ܳ:DŒàªóìOZj8&:Î;ŸZ ŒÁe~N÷Îê»oµcÉè¼zž…-M8Ž0ǃéW¢”¼™è£› C9ã rž• ÚÓFÜÜzÔÓ““ÍVƒ9«È¹ŠÆG\Q,IÅXvõïQÂ9éW3QsAc5iö¨‘1Ö­E€94‡qöêØ!‡z±ƒÅ$[qRd}@)â¦9%ª%jxl÷¢åjN g§€ `=ªó‘Rð:>´Ó%’ ‚>I-ì)WÉ 23ÍGŸÒó×­±9’-ã÷g™ëNY`InçµWQך8â˜X³ç&Õ“éÍ5¦‚€ ˆ6¤çž´ ÄË,]á$ýi¦HwpŽzŒ’¦’h‰±ôà nôÝßõÎiW9æìLJà ‰‚³ž”„J@C¥1Xd€+`}Å'AÁ”®yÒ9Šå}*\Ǥ$ç­FÞ´†ˆ¤^þ• ûTï÷*6Å!dªS-hÈ*œÃšhFd©H™­“­Sq¶­$RÚsJ§$`ÈT޵¢ëU™G™¸ý+H³­ MR,"`uâ¨[ÄRêSÞµG$‘_G'CÒ©¤cp瞇ÛÒ§i7Œ~`r*¤ŽJ>öpj‘“e]FL>ÓÐV8%dÝï‘ZW€È¬G;FMPU½FGµZ3fŒ2©õæ¬/J­ùYì@´¹™¥ b‘Š¡=ŠÈå¿:ÐëG„b6›óuàP©å ‡µmâ©Kd&˜é3Fx¤¨áÓÞŒòi9¢Ž /j\âš(è)€¾´¿%·h¤Á s@÷¦yéLjnæCÁëZ6NÌ…˜Çš¹g.Å=:f•´)P®æ8PjŒç·AÔ}jùÀSÀëU.|¢x? MÛ'­Mn#Ò A““VíΊlhÒ·AÀµm¨ÏëYVk¸‚kb5 ã½c#¦š/*ÔЯÌj1è*Ô+ƒ‘Y rüúUÑ€µN"ɩўEfÍ‘eHÇ"œ¼ŒŽµì:Šš>3ùT´2eädÔ€ŒÕLzSרé ™04ô52â OÒŸŠTZDÜÌÀ©?2ä^9§d)⟌hhA!²qE€n=H§,tÿ/œb‹ä{wbÈéÖ¤pJ~ÌöÅU…q‹È ¯ÿ.œ£ŒS±-‘€A§”ý¼Ž)iˆ€¥FË•ÅX*Ôýhe\¦ëŽ)ŠŠ ã½ZxÎ9@¨°Ó +“ÀéLSŒÕù~ï5Ÿpv‚{V‘2žÄ ªX1g?JeÂ.3ž¤Sc“©`9ö ~r«Éä¬éŸw æ¯_°%N01Ò³99íBå5nÙK§ò+NÕ9RzÍ‹4ùG¥iD~lU(Àæ¯Ã‚Ý+uA#«pœ*’Þ®[œ úÔ¢èn€Tªþu^6Î@íV#9êjZ5¹2žÕ:ñôªž`-Öœ&&M äµ,¤ô4þµ20ÀÀª«òãéß½Jó` EœÔéÈTKÈ©S< tJš‘SŽ:Ò©ÂÔ±¡<“ôªHiŒ1y˜ÏAV:g §¢¨ÈÏsRáqž*’%ÈaN:SvjÔHzÑ*®à£­"º)f©Bä|Õ œƤdâ„äV+Î;RùazT›îzPx .GŒŒP"Í(9?Z“8^=( Q—ž;S¼¡ŒÔÅ1Œ P§ M”];Ó |V‹¿ñÍ&†¤Qeç<Ôl6Õÿ+œv¦4Y4¬R‘D“ƒÀ¨XJ¼ÑðAT p)4;™²†9Ö¥–­2 g½0 <Ò°Û*7µWr2jä‘õôª2&{P$FüŠ®çÐÕ‡8«¸àæ„€¯) +2ë;H­)xë2ç©­"Œæô3»ý)'#4÷ù[#éUîò­QË"„²ùr8ìA¬ûfÁÛзb÷·5B"MÀö9iïrÄŸ#ƒøþUZfCúT÷gŸqUP†Æi¢Yvß!EZ « ÍQ˜¾Ôw¢ŠQÖ”zÒw÷¥ÎV…%/µP#4´(fŽ”PO4_¥™ Qq‹Fi( bÑœRP(&˜}©æ˜zÐdõ¥‹rç¦h=霃ÇZ·pÅñžN3U™rëR«eXŸP9ãùç€ÀP2—ŸzÙ³A»'µeÂ>`1ÍmZFBä÷¨‘pÜЀœJ»ÀÍU„m=1W¦+&uDysW"}±ç°ªy zJç׊E§cId*¼õ<Ô¾oÉœŒÖs\+ óŠh•˜¤àR±jFˆ”ïÞ¦Ž`¹õ5ŸlÇÄš´Eå £¯iXi—¡”³ÎÖ­‹¤‚Ý«$Í €^E²Šc3¸2du£”nFè±Á\ñS­Ò©0ù®Eo¡ËŽÛ[ŽâT ¬Ÿ)’)ò!sÜéþÚV#ê1S[jŸË‘öžÇæÛ†Émät$ÕŸ´‰%ð1¶ŽPæ¹Ô} 0Ìn­ì ZÄ™¥=IÇé\­ƒL­¸>øIåÉ_b+Qn¥…Ér²!èsŒÿ…Ð@æ)]7ghÈúrKÿ/øQY±^+!lã‡Vê*{i¿v[’Tzæ€4¢u<äÜ‘S7·æk9gØp¨žI©Ñ÷–'Ú‹ŠÄîã=úÔNœàÓцGúÐï“Éæ\HÐgPè£æçJhÈ~)’Lø?.WœäÓ¸¬Äš]ž£ØÓ7—\nÈ=½*3…(6žùªaÌ3m$òÇݨ­î§¥@Ã?37â› ÌŠrz¯Z£y¨D6ªî!8ÀZ4¥—•j³È6pA¬{­AÌ„"lÝPµéyR®ìÒµÆVqÊž)¬ê3Y-¨yƒï«c¸84Õ¼Œ9Ïn´œJF›¶xÅT¸Šb]«> cØÔrɵۺž'¥+d20+ïQnR@&šÌI#·j¬ï–<ò 4‚âÊvñY·]êä’>õJà3ަ©6g»uÍT¸ä}jÔøÉ"©JÜÑÒfMÙ%ž€âªÃŸ<6*ìë¾é¿úT0'É‚9Ö†p¸$³gçÖ«Å øUÙW1=ÀªÑ)ŲÌ}:b§^•*©¯­Q™'z_jhï\SF¢ƒœ°ëž•ææéÜä¹ç¯&JÄýâ=˜ÔÙé&õTrŸ¡ª²ÞM+|„ctWò>÷ëO2`gs©Í>@m½ÎÈy¨x8ÏÞ–Øà³äŒ×ö…•÷w犚;¼t¸!»sÅ5.‘ݬÑÀ·r žß>!),U·3‚y£áLJ?á*Õ¼ú¤p¢.æE‘¾™®³ÆÞºðÞ.§a¨[Ém bܯ‚À ¸'žsVè;]2#‰‡7+2,ÒE_4  YOJÔŽBöì–Qó'õ®]@«ç[ÆÀ¼§·çZ¶^2±ó,3ÆO°Çó®wv©Á­Ú® V\å† zz·jÆ1È\çÞ°ì|A¦^&!¹ROcÖµa˜1ÅdîŠL¸“deŽ ì;U˜f 0Çš Œ­ Áç©Ã‚ÞÕ7‹áýéK–9è“UÃæž¤1àt¡1XŸsÏJˆ¾ú Iœ'z®òmBÒ†Á"À•xÃT3HÊÙ*¹rÒ¤ c¸¢÷V#–GÞ¬¹¤‘„³ÄÝœÀŠx¿_º*¼ìˆ«“€¤šw%¹¹s7—;qùšÌ¸›ÈCóor >‹ÿשd¸VpFvñ“XWº•¬ ©™W’MZ»Û‹qsŸ™‰# +n;—žµyâ œº±bx=?ƨËâxTa!Ï¡#ÿ¯ZF,ÎRÔÔveÃ,ÍžþÔö¼ fÜ ûÇ®k˜“Än\íŒ ÜcµTmjLäF ý*¹YÞgd5U†P¥²3Ž3ÅiG¨Cse²ÍÁ#Šóƒ­OœíCŽ”å×®S¦Ïû擦ÇÏæz4¡•¶#1‘¸ŒÆª»2¿9渓â‹Ò›K)§ËCx¦õ¶îÙÀþíÍ öˆì$”—éó d’oS‚5É?Š.nR,ŒãâGÜ3úñG³d¹ÜÚšA»ŸJ¦ÌséYòkqÊså²â“ûNò3ê*¹Y“d¥K ƒ×5hQ˜c…ŸÜ%ÁÝ×µ#Nžl…[ Ó3b;䎕RGò£ßÛ8«ò99È5Nÿý@óMoahEçJà•Î*?µ:žI­M*ö8¬&Ð7˜AÎ9ô¬ÛåFºs*„ð=ibcfKó9«‹z­Ž•±÷§@£”,ä•[¡ëOëXܲ¸ô­«y7Æ KMɳéE””„`ûQŽ)ëKHaGãG¥Æö¥¤¥¤ÍvÇj(ïKIøÒÐâŽiÞÔ†€×9¦µ!Â2Ô ™¯QÚž»|´aÃy€gÛ‘£ÈÄ-ߊ”ÚL°qe~cÅ/•Úö"™Xßž*/0”$öæ›v㞩Ȥa ¾jŸ”¥1[Rž} ;½ ¢ŽõE M*õ¤ê+[B²wfFû°1†:‘Ð~”¶W-+» m¤Ï+ e<€|±Ô}}+rÛÂr³.ôUSÏBkzÂÀF|ݪŽæoS[0¸ †Î{ÅÍté£Óêq*9ìH­x|9§lÁ„äú±«añÜT‚áTõ¬œ›:J°øzÍ °úš°šžsºÝN?Ú5#Þ" –F5HÐòë‘þÕ+·°ÞA¼5¦1æ÷ÍT—Â:cò±~¦–ã[DŒº° zR®°LJv·#ƒŠiL‡(÷ÇB‹K¸R42œðz}i|C­®[$WâXÐ’ªÀä=©§TÜŠ¶ÓÐàóQÿj)8éõ­}µU\ÉѤåÌÒ¹È\øVíX²`ŸcY³èÚœ'/tÇC^‘ÂÈ;›ËŽaó(5š«%¹~Æ,òy>Õ fDûæ¬Zk—–Rf ‰##û¦½çHµ˜Ñ©¬ CÂp²³ÂoJÑUOFg*Ö#tßÞÅ ç/¸×}¡x‚×XŒ˜_æ_¼‡|W‰ÞZKaqåÈL©Æ3Zz§=À–Ú_.aÆOF_J'F2WDF«‹´vŽBßJ¹ œ޵Ê'‰!ƒM¶¼¸ †çw–òÊðÁ[8^{/ž¥ZñŸ…¢Ò´ nÛÄ/o$c CÉKW‘iþ?Ô´iâ] ¶WlpÆFwë×>õjëSñŠÙMýÔ‚3ÎíÖ½%ì©Äó¯R¦Bî¥`ù³ÞÝKœfGƒø)5†ë,Œ¦+'PFAØÇ#êk²³ð¥²a¥Ï|æ¶WO¶|ƒ ì+šU•ôGlh>¬óTÒµ)€) ‡ÿZ¬EáMJVËí9=«Ð•a–§‰â¿z³Z³®§»A·2Îàë´ ,¶>büô©Q~vP2jÛEæ0[v8b®Îaì&A¦«4l§`× HÞ0vŽƒµdßi (b‹‚jÍ\OÒº¯ G»í ÿF?s)ŽFSÔWQáFÿŽå¤xýj¥ð…5ïš ‡nx©|ÕiàÕbøÁö¨.'Ø îk›s½;"Ì·*€±n5™.®‡×=+*öòPrXíì+8»Ù ÁÆ@b85¤`º˜Ô¬ú¸’Vs¼qÁª“꿹FUbûpÇ<)þµ¿£ø>)6Mxìì>X#Ê ñ}¤6³ÚA J‘ˆú(ÀêkK$´9¥'©ÍNãÊ10m¬ÙÁ5b×T™mdY‡– ÄÎNp~ƒBdã8É®¿þ½¾G}(Ö}¯aµ—qŒýÜæ´„y¢ÙIòI#2-vUŠ èX(ã'?Ò­Ã}Ü©Ò%'‘ZÁµRÐîÛò’@é^«¦xrÏUðͼ’D#˜ "d8?Z‹]s¸´sB6…³’1’µzÖã*j¯qeq§Ë$L­"©Áuä‘ëI‚CÆÀ©ô¸Ð¢ýžp7dç¸ôÎ+¹¹g‘›'“žµÛ¯€ #‰îÕ—ü* Û¢‘ö©·v*X²£„œv8q1ÝZº¥ÍÕ½´³;A"$,p™98¹§êš Æ™‡l4gøéYdóVžšÊ6z›ÓΡ©<ÇV`{žÃô¯K·b@Gà+•ð5¸û Óã™\Ë?ã]ÊÚ±@@8®Z²ÖÇU$”nW2„&³.õ¹E95oR+hB7.à {VDv²_LÔyŒÜ{}iB7.sIï®î-yŒSwëz"ÕmÑchvbþ Wõ¿ÿgims{3¼ç„U?(úú×ã,ŽsŠèP[N«ÖW: µÆ‰ü¤sóô&¬¯ˆÖ1´±fÇ$f°µmUÒ¬lïoí+{¤ o! ‡SÈ7]ˆÈ@OèkЕ|ɤ`3Žk*S×ÁFй™©º‹s‘׊å.‘™6Ÿº§#ò®‡S|Ê‘÷<ÖãÝØâˆ™bõ1át¯i÷·JεC#7gô­+q†'¶j¥±ÇKsN1œ“Š”@ôíIl*JЊ<ŸZÅ»Š7<Û_³6·åÿ…¸üjÿ„Xy³¡êv0ü ­Ønµó•rWž>•Ìø~çÉÕ þCøœÖñ|Ð2·,ÎùÔþUJtf;W¯½_aº£h‰ æLìåÐÁ¸²%°ÄíVôûV0#©=êôv›ß‘ÆsVZÜíU©æµNâTÑoOÕDM·¯nj$Z•tÈ™Ê;cÚ»cãž[ÐT+os$Ëñ Én95W¹2 ™ÈJŠ×8'±§¥¬­`÷?Ý'¦Zì…”·sÈW1£Œõ#ØzÕ·ÓÚÂ@€ ` SÕ4íÔÅлÔät»oµKº:ùyùµz冭ie§Åk»!=…r-¥n·Y•H#iÏ©ïNò]°˜'=1K›BÖ=[4®õ±úÜÚ¼‘Ë%]x*NG…cÝ^¥À H¹û¥U®Ñߎÿ…<ÚJ\aÓžÕ4˜P=2k7#©rÅX“C»–Ýã2!Xåúæ§Õdó¤ßÜÔRÄa‘K ¨£å†£™„Ç#îYkrRDLçìÅF2z ò‡™Ÿ³1jõmFD³ÒnoÙ€X—jŒòXú~uå–¶í4±Ä£,XWU%esŽ·½+Ç…,vZý¥†$—“ô®Æ¶ªäõ¬Ý:5‚@8QÒ¶ @ëŸÒ±“»¹èRŠŒRŒ †æ òzÕň*ƒÆhuÜúR4Z3˜Õ-Öϼ1^]qA;ÄÝT⽚ízb¼ÃÄöâ-KÍUÀ“ü«jO¡ÃŒ§öާÁx]ë+çó®ÖâøZÙ ’­y÷ƒnAÓyŽR~™®ºæE”F¤ñŽ*Æ¢|áNÎ(ÎÓµ?²ë ¨J‘K29aé¹AÇÖº¸|H5[¸¤¸ŠÞJæö Ï<×=6ž[æTù±ž*1dѸVBæ­H©ÓŒ‘³âôMGG‘bpZ%fëÖ¼¦hÆÎzƒùûWxöÒI•N€dûUðüO–H¹$r É­c;js<6–0üCâ[ívÃN±¹`°„E ¯Žyë€áXЦÐXý+°ºÑâY$h÷ F<¯”;œO=j¾™!…ÀFÁœçÌîÌá†äVGGá{_³èjdãÌÉü2k—ñ“Þ<öÄóɱöÙ£• `BŸ”}j½Ì3´€îÊçGj\Æ‘¡¦§)̶Ì‚GAZV—Nò‡è=*ÍΞ©Á5^3ã —$ÇÈâ͈çÞ)ŽsÖ E*<Ô¸,pg±¥îµ+] Äíè+Äïû»ÿ»'ñÅtױǨÀ®7]˜Ë©ºçˆÀŒ~VÔÝÎzš14X—°ã¥m-ºÅz‡ƒPi6Æ×#æ&´¢‹Î¼@sM¾¦QÖF’\³8 [­(=¼±ã*î’9<¼cqZÓF Éã†ÍdÝSÙ)@òIbò¥hÏT$£&I?t"ƒìÚ´«ÓwÌ?:À8,OjÙ\ñçI¢<šc#Úœd늌±5DiÀ´˜Ç=é2IÏjb¿8¦î&‘½¨Ãbþ)húRⳃŠ_J6ñNÇZAa¸§íKŠ\ñO  QN Z:t¥¤¥íEÇ`ëHy4¹¤ïžÔÖx<]\NGAÁü w`ý–yzñ\¯‚¡ÝjÈ. ð&º/´y:5î߿¨õ9Œµg·KݦŒfŒÝ^¼ƒî¨Û\ö±¹e˜(ùTJílmDq` çœ×3â(<ê:žiAêsâ#x™ÚpÙ˜/,?*ž&ù€ëU¬ÉÈõÀü*Ä+ó_J¹”Ö¦Õ¨fKHÐó,Ò2_?÷‹çŠƒÌDr6œb¡Kv-Î:æ§XãAEîCH]ÉåȨ ³6A$zŠp Ï`r ¨äš aAn¸ÅgI4·.v©éš.„¢ØOp×cuNsëCmŠ?åš|h?AXZ¶ªÈê§{GÕ3ŸsÚ”bäö梌Ïj€Û¦›Èl3‘õþ¸¬ß Øù·å×(§ûÖfÛSP;Ay$Ã>‚½ ÇNO²H#ä’Øêk¢O•Yô—4¹™vß­«T8¬‹P7(ô­Ëf  Ö ôv'UÚÀÚ¢'HìAÈ'µBìW'ÿv•ÀÍ¿!Ep>'·óagQÌg?†+¾ÔpË\¼ð‹—‘p˃ùVvÔÇïFÇ/á{Ñk~Ð1ÂÜQÏñŸÎ»ÝÅg‚+̯m$Ó5‹$m £úŠít-j+èÖ7;nÁV9Ýî?®¬oï#’Œ­î³«´ºù·ðέ,–ýâã'—½có¼Õëyáeî'îûzÖ ›¸Ž“Ël†ç±§ye ?¼ÆÂ‘× ÃÁG½FREâËIÅ'•¼mûÄ“øÕ·BÇj²ò=ÅHò²õÎi†]ÝEÌ¥A4(ÒÄûFåp*|ˆ­ÖžHnÔÇäqEÇb¼±€8ªµ¸-º®íÈç4àƒŠ.CFx€ŽH©cUWâªH¦<“ÐRßB²¹[P‘`´iX´3ÜöpF6¹Ôö·$±fǯS]­ŸŠl´¯Û_\ÚE}ª¿ú<£)#0àœƒ÷NNµ‘aÛ5+ÝI£EûDÍ(T\*†$àÚëIBúœ“œßbÒG·fÇ55£lÖž `ÕiX†Ç¡¢Ï-¨ÆÃ×úÔ=‚ ßGJƒÈÔ£Þ VÕðÛ*‘ÆFk"íNRUêjй¸I’CÈ?Ñ”öæ”teÎÑg içsg?X·b$ɪ9Þ6à/J±ùÅk#ÏŠ³±½h~_zѺV]£V¬w>•„ŽÈìL2ŒÕKý5/¡eeÁÅh,y©Uì ‹Ø»i=®£¡É8´y!)GØØÞ¾‡½«>ßS¼±|FòEÏAÒ½rM>;ó¨ ÖMׄ­¥bÊJ±ôÅl«ifG±ŽëC–¶ñµÄk¶h¢z€Aþu¥ŒìúÈ·4“ø#p%d_¡ãúV\Þ ž H#Ñ©Þ›Ý B¢Ù$~*Ò_¬®§Þ6?Ò¥_hìx¹<úÄÿá\oü"×A³ƒùÒÂ7wÉãÐÒµ0ýéÝÂG¢ìéG8ÿž/þ«â} ;µ`cƒå?_ûæ¸UðÝé䆧¯†.É19÷§ËL-TïÄÚPf0É#ð1û§8?÷ÍtÑøsÄw°G<\†”HçÆ¹dÈú^M…nÉ1ô&» |Ain–ñ]•‰T(Ÿ˜æ´‚¤·üLjGöKúè¬÷šLk6<ÉugÓóøW1ˆ£)*Ëuck´£Ë’fcéò÷«Zž‹©jÏ›»ÂãÓsqùÕðd+ Üìxõ¥)R½Ò t«¸ûÒ4´xnÃW·»»·Ôu%ØVhæxÖN0Â=¤œzXž.ÔŠõâÚM”6vAB$6ñ”ãÍŒdûúV¢xvÎÜ«¸ÿµÍ^‚Õ#_b‡ˆº²A"R擹C@ðôv1¬Ò kޤœ¼v­YØ *Ám‘ãÚ©JûœV ¶õ:TRОÕ:VŹùdB{zV¥®@$Òf«bøåz ¯7<÷©TåiŽ€ƒÍGR‘‘{œf¹ÒvÝ{1®¢ê޵Ì]¦Éxê¼Ö±2ªC«èÑj–ùlˆ Väújâæµ¼Ófýⲑхz=£†­Esj“0VÕ©µ¡ƒ¤¥©ÇYxšöÙU^O1Gi~oþ½lÙøÁ7ƒ,;q˜ÛÖ¬7†mnIà«J©'Á$Ç1V§Í¸½E³7#ñnšäo˜§bYÿ!V×Ä\˜ wÑÜ‚3úW'ƒ®×”pqT¥ðõì9ïøRµ1Ú¢=ê6æwù©­qn@ÄÑ{üâ¼á´ÛµíúS •ØÿirC¸ùê.‡¤à&þûqócÇû¼ßìwx<:AevÇ ÏãOÙǸ{JCkû4ÎëˆÇãU›[°–¹N½?Ò¸…ÒîØt?­Mƒtü*9!ÜWªú%ߊ¬‘s÷>˜À®oQñÕà(…Qe?žjÌ~¸p à{šÒ¶ðš£/˜ù'ÒªðŽÄÊI|Læ,m&¾¸²W#5ÚEn¶ÖÊŠ84vÚ¨9éÓœÇô©sm‘ÉdaÜ‘œôÍYðý¹–ð1ëÚ«\ðÜ~ÓhV¡!FHªoBhCšw4e¶Þ€zV|JñjF~ë5ÑÆ€¯JÊÖ"ò£ó—¨9³]B_ ÂøâpÚʪãh^s«oÄ öL¹þ謱­“I-FÜ›)I§˜‰QWDB´ |ýˆå)%±Ï5/Ù#>•`)¦E^ô¹›T1mÔv©`pD×J*3v=(åa¡%Š)’/=é{ AKÒ€ŠNÔ£­1‹ÖŠ@)Æ©;Rö¦L4ãÒ˜x  ¿ ¶Ýa}1ý+д2 ÜòùêÃô¯>𾦠ÿíôy¼¹g^âV¬æzXUxÁõ¬ù‘dif¹Ï~j¨˜æ¡#µÇC‘Ö#ëªx*8¨lÔúÃgX'¯ËUÇ\æ­ž\¾&lÙrƒÔœVÌ_/ëOþjÚ‡æ9¬duCbò=˘ ËŦŒ'575‹#²2y@Ë÷¥Yv}GÂ:SÐðp94a”.9Îj¤°îVY›q"˜nlôŠ‘­ ÌŠ¼ȤÀÅjʧ$‘R0ÂL¢¶RNGJx…ð5: Ž:Ó„@ŸjdHðñRl^OsJÄ À¦oNF1H-ÔB0ÀqÍ@@°ôÅJà°ëô¨$;Ñp±Rb3ÇZ`Fj,Uk— ‡HͲ‰ÿ„®äTd—cÏZ³<äÕìJÔµžk[®ET·‡'ŠÑ¦2)6j‘0PqÛŠF\©"Œ})q‘ëR‚æ|èvãõÏj’X⺉~pEcÞÆE\E%tsöò˜¤ç€x­3ó¦áY·lsгg1*P𧱄tf„ ´ *xük)TŒW¡r¤VLÝ<°[zÔSÚ† R£9¥?wÍÍHXÌ{Û‚*£Z…8ÅoÈ¡”Š Ñžs@ìg až@”€¼ñR„tæ‘£G4r“àð=ë.ñ _|Ö¼ão8ëY—#9öäP†`]ÄsÓš¢Œb›=«fár¹Ç5›$!‰¢1šê+iÂÖ’Â ñ\ÌRàöë[vÒnMÝ0k Ë$)­¸øt¨‘Õ ýqV!äÕl}êämÎsÅfѪ,㟌sÞ£ sÁúTÁÁTúÒ¸®:Jr&94ßáÝŠ•FTzÐXcä>¹©€Ü? fâ=*dSÈ#8õ ccF^§“V‚Aõ¤sÛŠp?1| Š«î0¡gi[ÜSD„«N9¦3ö@q p9ÅrWó4×;aÍtwŽDf¹˜c2ÈòwÎ «‚ê/ Ž0*xíð¦¬ÁÖ§òÀàÕ\MB`йåTr.E[¶LÒ)cR>™íWá^2F*;uÒ´màÞGy4Ò¹MÙ T c×¥ù­H,šL»”w•ípû8R9ùª¹L=¢¹ƒqdÛÓ²®áê{×Quk±7c=úÖ-ÔYݟʦÖ5Œ“9©”‘»Ö©”ËV´Ñmù{æªygÌçÖ„)X¡,8<Ž´¶Ò5µÊ·cÅh<[ª”Ñei­I±ÕÙȲ¢¸«ÁCÈÍsºEÉ1í'ߎ@AíXìì4DöåIj˜8«ÛòÙ$”c¦ãš«\«”0Tžþ”ÉréSÊ<±Œçµ0Ë»± eM§4Ö%MXuÉæ ~G½2XÇ”J‡ j¼‡(A©!„E èNj ¾U †U›ö¬ÉÎ7Ué² î=EgLxlõ«G<Ù‰ỹֶ´èÕ gÏj¾8‘qÉãó®ÈØíµÀÁLZ=¬eJüÍ—îdU´Ú= gZBC´­ß¥?wœ*d´:pò´¬vª…±“šÐ¶ vð1Ulðã5l·8ƒ}þSžñ;"np[šÆ_›¹â8óf­Ó ÅaFqZ¸ìrTV™±eÀý¬V¹'Ö=€Ýƒîk``óè+9ÃbtnZ¸¬v©¡æ©BÃjýjâ=‰¨f—.)ÉvÍHÙܸ㊆>N{Nr1ÇãSèZd«Êmâ¥F\ÔJ@m¢•×ÀÓ-ø5(ONETS¸tÁ&§ÜÙ½¨cÌÚyäŽx¦´áy< hl&Häw¨%ĘôÍ Œ˜H¬29£ßµ0EòéÎ)lj›Ü›•ï3ä°ë‘Ò¹ËÄl§®îk£˜îv®bpm.ØrùúV°Fª¸ÇJ”¶AõªÝ(\çŠcjhÉú Õ4L™rFÀ©í§‡¨â±¤Ô£Sµò­èÀŠ•'ò§4$J•ŽºQÚ·´¿/ÎMäÉi÷AÙEnÁ6A§Ís+C\[ZÀËlŠŽç,sO¯µg\]«ÈH^OJÌ–ë<ç¥W’s»µS•ÌcE"ýÄÛÐ/ó¬Kɫʭ´ÿ.ìæ°u+ ±‘žj´t)Ï6æ&¡Þ3Š£=Ò',ئÅ-ų[[¼FXçüéØ›ÝšLAš‚@OÒª¥ÄÙÛ$E×4ùf3ŸJ,Zر¦1(éÅo¬‡ÓÎé‘$Ç£GÐVè”V57)’A‘V<ÍàEgoÚ»q8oÂ’eZ噜u¨HHÍ=w%⣅]I±Zc·§sU‡Ì[54¤±ëøzT$€<ša!ŒÛMW”¼Õ†ÇéU¦8ŒúÐdÌËòHLzÖ|ç-ŒöëZ7¾™¬ÙFyö­Ï3ëýt~î+Ñl¶˜ë‘^{8ÌñçûÕÙ[ÎÑ¢†ô§+ÙJ÷d,’Á!¹ãŠ«qvÛHn+d”‘rkUEXXŒÉ¡;³wuœˆfóõL瀸ýMeÍO} –òFŒÔ®¥±ä7v;Œ{ÔmÖŸLn´Ñ7`=qN˜)hâN)„S#ÓB©EæŽÕ™³éi3K@‚š8Í/4€õÅ-&(èh`;­Š3@Æ‘L5!¨È¤2 6)ZˆpGqRIÒ«7ÑIØô ]IãÙVP9µÒ[ºJr¼m%d ©­ý;ÄóÛ*£àu㚉RìuÓĦ­#ºñ +iScª‚k”ˆå÷À¢ëÅBî#Êo›ŒŸÆ›Âc$~T¹ZDNjRº6´ãÇãZËíÜÖ6š÷­ˆNZ²’6ƒÐž8ù#ñms´{U˜?µN¤nÖlÙàÁdôã­V‡ N9oLTìZIÞpqRO•þpzŽôg284"œóÈ9©ƒŽ*ª¶7p´ýÙ`@â÷,1oº §ÔqüÊ ©Ô`hbl$gÒ¢cÖ¤fÛš¤ÎÂSÇÊIæœPDYy¬ë«U¸k*ëJsžMWžL0'8ô¬t/N¦–7}ý=I©-ddo½kJXDH®8ªŒŠÉó ÷LÉx ¹^Q[#©™=´–n<´}Á=*Ú±É Æ*G› ±€äf‹ M43N¾RÊÊüfº8¯NÐA×'6ž7=͹Ã÷SÐѦbýÔÀÆê9ÝÒ¯°£;nuïz0Nj$½#usê%‡ÈA¢;Ò$Š\£s‰ÒK~¡8eÆ ì½…nZË´cf8éT&•T²¯ðõª,’HX`õ¤ÕÍŠEûË«0“Þ€Vcy—2#l]ÏsVÒÝž„qš‚xéNÖÔ½lqªWã'5—ô§À¬d ™AïQ¤˜lµ?ry5UÆ#ñ¬ÐâË‹&@¨¥}ï‘ÐThã §màœÕ‰‘˜š…ð¬Ç¾zT¥‚±|ÍÅ4Kdg§=ê ‡,{b§fÔ2wLÎLËœg'9ÅQ”`ê_”å˜ÕK‘òqV·9äaÊ›µ“8ç5ÛË @Åqlo’p„ª0úfº·¾G¤¨5­Ç1)ŸJ傘ì=äÈéPŸZu%R˜ POJLÓá°]¬ŠødáHÉ®g5µ§È~Τd‘ÛÖ¢h¨ît¶C€sÉë[v¬w{Ö© ¦H€5·lá€Ç­sÈê†Æ’°gÆ;Tá2:sP Ò­/ÌqÞ²7Dñ‘ô¤ŠF’g^pÓãÆ®*tŒ"3êj4½ˆðÁíH3O“åNþÔÆ‰¦ˆÚ@àQr.VŒË6à¸ô§…Šì mÆ{U··Cç†+‘õªÆHr¼3/JiŠã´$ (ÃSE„{²@¯Z|PË2aI]½8¥–T„,qßÂâŠ3´ `ç“ÌlUDw†ÜÇ œtïO†ßlkƒ'J©=sŠßµÉâ¹$wSfä/“ÔÕHEaÔj”IãmZF;FyÍdô6L½É¯&0sÐv¬ÈdÚÁIíÍhDwGšÍ¢®G  ª¨ÅÎÜqëëSÎHzÓ \0ô©¹¢eˆÓhÉ©Àã©ô¦Ç¥0¯ï7ç…à{Õ%re"“ku$cîæ¢tÀ-Väš–ômô9ÁÅA„Ú‰åÁÁúU$ȹX‚ +ÁÕ09òûÔÏ'›€02NáÖ«¤dÌqŽœU¢®YYFrǯ O‡lpüÄsƒëQ´jßïu&šÁ™H_¼G¦2Èýä>¬>lšz H‘›—'4`<’㌚|#lâ7]Á‡S@ÅX¢'·QéK€ÙËàb¦Dg2…8ôÿ•-WxbN0xõ¤&Šå@’bêvQ4y±Æ1ZðÛ‰#Ã(ÈçëMû'ÎCœŒS±6e+ f21qŽ:SníœJ6¯ËÞ´Q 9}¥ˆç´í¾j‘* gv=)“ÊbIi³tmŒžT‘I‰$”`²G VÔ–É9 ·p#>´Ù Eo‘ìu¤;3DÍ$™àŽjˆdœ‘Z’Äà yªmNH ¡üóEËHÏ–-¨äœuª±Éæ‚ø>_P}êíÊ“óg{Ô$¯’ÊØt¦ubY€4rmmq× †P¸Æç4+~ø‘üB6hÂù`XàƒÇ½\‡æn"±¢>rmV “úÖÔ ‹ût¨i‚cÕíÄŸJB»¯Zs°F9<i¥ÕÀaøVzܴƸ檶|ྵ}—rdt#­Uu@{Óc\m" cÈ•bB7dš« ?iëÁ)£&C9`߯³/Ÿ÷gëZS²–ÆzV> À)­i)=7ÄavðwJçëg^;ÆP0k»¡±çOpáMüéàSd ïKAâ—ñ BŠFí@íCt¤¥”v¦Ç9¦ž´ášiëHLѧ­GœÒç­fh?4f™š;P1Ù“ƒMíNSÍ $íIN4é€uâ ›­OPË× ¯z…ºÔÀTF„Ú“ìw£Ö¬‘€RÅØÔ°#v=ϪbUECÏ­R VI”w4±¿ï3ßÙgˆ¹†J‰."ÝÃÚ­jREèÐç“G53Ã’£û¢ª­Úz¦[ØöòÜÑfh¢Ë±(\J .['5Ÿý ˜ã­*ßðNiòšÆ5—ŒõëS! €zÄû[wsJ.8ÝÅ>SEISFNjŸr1ëÅr«;«õâ§ŠñÁëUaº ¹Ð:èj3Ü < ¥óq¸Šl÷ìñÖ‹ª.ö4‰* d^2EcO|ì¸ É5Zk‡2c=èhÕP]My]EV8ç޳䜆Àj¯Š)É©q&T‰®£VBqÈôªX*€¶ÍJ÷ŠS“P¼êpëJÌÁÁ¢'Âä×µEäaÜ‚JÕ9‘yþ” séHÅ¡‰ÖW‘Z{ÄhÁ0C|ÜÕDF(:õ©Ö0~U=9ô¥p°û¦!e#JD b“´ÔWL̯ çõXŸŒ`ô¤Ö±¥móCס¨®c ©¬ï1qÈ4Ûÿ•Hk%¹Ft„ðäÌ«Ç_Ê#Œ®:æ¢‚ÍŒŽØ­Q“")NG\Öë˜ؘ¼jyÎÆkÔ%Ù»wëZCs)½7Vm÷„g ªräù²3/95PŠìG·½H6ž£ŠÔƒšVàÒ `( ô¤•©ÊZ(¦ÇÒiE¬]÷íJsMÜSÅ&ñÞ³5EGæS|ß­zrš¢Rq“R¯-øP§¥6žÔÚ=ª ~õOüê¼¼5&44T'­L:ˆõ4Ð1):\qEQ-Ó[Öjabi¤OéM¢•FHbÜ¿¦?ïödÃ95Ôi“±'¯¥qÃ( Ž tZeÀ* =zV5õ7¦ìÎÚÖesâÅ^S„Ú?ˆV> Î8äV€˜yªŽqŽ8®VŽ´Ë•;ºqùÕÛ)ò£-ŒTn^2õ¦A&Æ1±9俦×Ά)ƒœÈ«Ñ.àzÇÓÛ±u­kfÈ#Ò²h´ÇÍQxÈ<Õvˆ'ÍÇ^*ü§÷Æk6YàzzÐ=YRòî8ºƒ“XÌ“Nãæ(¾‚µeŒÈC¾3Ò¡D½ªâìZW2.´Â~mí‘Ӛ̖;ˆ9W-õØÕÇ"³®lÆÞ´ŒËIìw×í(OãVVòOî“R=®×'m ¥NÖ©šÆ¸õ»c‚8ÅXŽíÁ=j¿–£"¤¦BƒAªƒ.-Ú¬?:•o·Z£öDrÐ(û<¥(3XLƒ05>zzÖRÚ13gµ4q̪?xÜt£A¸³P1p?:‚âvê5U¤›¦îj6K·c–àúÐ$™.ò[æ¤iG˜}F!” ÛÎzTRC $nl÷æ ³óòOj¨÷HÒ½¾p 'ñ¤kh€û£>´âÙYîóž8ÍW}@ƒ M$j§UÁâÌ'DÚ¤…ˆE$þT±Ïy#¬úc4$ dÎ:ÖÅ¥˜ùXÒ“h׸YÝÉ p'€Þµ½ˆFFF+9­”¯+šµooÇÊOÒ±“D´ óž„v©-#OaéOT1–$rÃ5$k¸FéY¶M‰tînfÇ@:Ôz£SVmWÊwˆæ²µ™È áN:±Iõ2g˜اž•s;$óY„Ë7˜T0Î+dªÆnp*Ú1M²ì‹Œ•Çkóí™W¹þµÓê2ǽpÚÍ×p±À'8ï[RWfu_C0!UäÕyW*Óâ£eãë]ç’º*ŠzŽ)¬¸cN½i˜µaŽ=é)ÒSh£¦)Hâi{t RÒRÓW¥éÅ ;PqšBdß3Š‹4”ùJ¹!ñI¼Ó)qN¹zõcó©Ó©ªðÿ«b>µ‹ÜГ®i;Ó6SíPIË œÔ}êL¤"ô9¨O\Ô£¡¨Zh™¦3uÅ#·\Td’kDˆ¸„Ñš;QT ©#]ÄSÉ«(»G¹¤ËЏæ^•=„Þ^ô=z­EÐ`Ó(C§;š>çq¦ÜñŠÝ È|ÀF6öë\>—w’¤+«³¹ÞŠç¦+šq³: î‹ zñM¶P6öÅO7îðùÈàÖ]ÌrµÎ1œsŸJÓˆ1° ã'Ö¡èR¹¥gpjÜ·zäm™£` èsŸQ[Ð\‡‡¯"²’5‹6w–:Ò©´h¬pj$¹,€ç‘ÓÖš²î˜cÞ³4HtÊÄíõUuˆªŸSV$òßJnÖÞïTh´!\‚i$]ÀŠ’xßiÀäñUq=5*½¸aÒ«}·v­#q®jDMǃÀ«L¸ÌÇd‘ŒSU yÍnµ°~qP½ŸEZ‘ÑN¢{™«ÐZµ°¡­Šœc©#?•3¢é–a„†©ÅNðm ÓƒÈÍGÌ€¨ÈéZŠèÁ‘· LŠ£);ÂÝZ`@éÚ¥û0ÃÞ¯Bˆ²0ç¡©d^@lóž(D9;˜¯Wb¨ËÓZ³a÷rsÆÐj„îX9¤Í¢Ìù’݇5^SÇ+î.àô ˆZ@qÀ¦9hR™K8Å'•œúâ¯,%»Tëi·’)6sT’*[Zçô­hãÂíM=*ÒŒ{ÖRg3wcBàŒÔ«…曌)=ê9­CÔh™¥2ð8"à õ隤²ý좭Bá£U=Í"$[g+{÷®gW¹.ÄOA[wB(1îs\Ä_險!û‹–&® Ú˜Mô5të_³D rv`ŠÇ'=yíVfqÐp+'P¹D8É4ÕÛÈËÕ.‚ÄÙ<í®&Gó.ØõÕbIG•¸÷MT³ŒRlÏrH”±ó©É¯OZ[xöŒÒ¸ˆl`ÖW¹i ÞrzÔS8)ÒJ«ÀïÒ¨´ßxT›&ëÁ«hÛp`ŸÒ³ÑÕYŽsëíMš÷ËŒ;psE®Ìå-õ{¢~Eù‰8Ç­;M#‰ÙÇÌýª…¯úUÇšÙàžµ¤d£¶*›ÒÆKWpžlcœg“í\æ«}˜=+Fþã€3\f­vdZž¾õ­8Üʤ´(Í9žb[ 7ŒûTj¿(ôþ:µÑc(>Þ”Óžx§{RÀt c:RÍ<ýÑŠ‹vMr`Ȩ†*WËv¦ÛÒ„ÌÄÍ?¶)D.OJpÏj.…fW=hÕjÆž-Hš9ÐùYZ—l[zÓ¾Ì*yÐùY›Ú–’ŠÔ‘E¤¥ eèîÀ©£ëPÅ÷Ò¦ŒdÖ,²V¦õ¥4ßåI*ûÄÔõýãNã[‰ØÕw#Ö¬ SpwSˆ¤0óE(4G©iEÒ€,B8©‡Ò ˆ§Ž*T'œô©fËaJ–ô4½h'oNiA޼b‘B:ƒŠ–(ØEæGœ¡&£Ï'fTâ±:/¡jÝÁŒ óŽjrJ€#šÍg!7¡€ã5lLvÄÞØ5-™,L؆z ´¹Cê3ÅWVÉÏj0äŠLÑ‘J6ry§ç,F~\ñYðî`2jêç`#¨h´‘)$ŽÔÓÃCJ’ƒÒ‘>VÚÝGZR8ãP’á‡Ê9ÍY)Î8cNxKdvªNÂ+¢9ÎTò>”É“ÍO j˜ü§`ëŽ)]¡éT˜Zå6*°e7eríN†Rc!€t¢E*@ÈäóLòå*‚Iõª¸¹l0pí¹Ž àTÞiUÕ±y‡i' QOD*û@'<’iÜ-rHæÀ;ºg‘ÊÊÄti]22Gª´ WR&bÁÿÛúRË*äóŽGáR´L£qÇáH‡ ÎNN{Tó) W}ªG1V;Ú¤ÙµxêEFŒUöú Ô¶4‰—Mg_Lc²z¼Ì6ýk>ô퀩9n´D±Q.¢RܰïP³¯jx_”v¨Þ2XÒ´2“¸¬@W#©Vs‡‘vŸ¡«%ö±’{‰ÛiÆæ¦bÝÉbe…ϵ¹ØA=jÈv :¯ª÷—Ï Ô%v²2µ›ï)x8í\¶æ™óVuK£qq´tæ«}Ю¨ÆÈä”®Ç3Šw·4ÔsÍ ¤óÚ¨ G+Àç==©¤†'ŠØËrJ äw4¬’±íR¬KŒ*1Æ=iLûG"¦Zì'æLqÐRì•XÝõàSMÙì.V+¢àŽ”¸@Ý5*NÌÀv¥ÈÙl]õ¥Í"ãŸÀ¬Û/”nsK†ì*A@aK˜|¦ Q]§(´¢›J:Ðä(úTÑu5 }Ñô©¢æ±4$oåM§1äÓ¥#оõOõ¨³HhùjÇ9«ÀG½WcóœÓˆ5vFƒæžÊŽÔ»¸Æj…näMz A©K~´›…;°²œb¤\€})¿Ã‘OL°#ô Ñû¹•ãµ(ûÙéŠ_—9zŠ $õfɶÜc¹éU›9öëRÂÛeFô"“6d‡Íˆ®:Õ[YšÖg…úg ÖŒl ñT¯mù§ÞÖK±R]Q»gpäÏ5x>×ïƒ\Õ•á,ñŽs[ÐÜ,ˆ¹#"¢Q±¤%tNrÙû½1ëV qå…'š¢HBH§,¸o^:f³µËLØFU@õÅY@\ŠÎ¶˜1ÁäÖ…³‡n¼Š‹ ’)*ÀtÉ«QI†ÁËgŽ*'’8Ïju¾PáªlUˈP òMIÓ\•Wµ)l>¥"®LQ6Ž)ÊÃÈ'ïéPd†9É«• 94!0±*GÞëšpˆÇqÞ¦ó6çŽüfš§{sÓ¨ªL.Wh9ÈÁô ŽARƒÐÕ’¤éQ4/¸²±=ñéEÄV—rîJr(AùT’DyÞy4ß!š3þsNú¬Ãæ\ tïH8P£< ”_¼Ã= ö¤|+eWZ.4ÆwÁ轩ÊÇOzœ•)ž€ñQ` ŒŽæ¤wBǶj»!RÄ~bVø=WwÝœBí´d¥pÂ@sÉ«¿Ql½Ãœð*‘"Œª½NsL™ö¹ò(6ü~Rò`wVZ$dÝŒÁP“TZF3\œñK<¿.Üæ–Û ¡ß®j¶1nì–F#võ®wT¼Þ¦5É$ö«šáH‰'äÍdE™¾áóÎqWmYœåwdeMŸ=È,zŸziìió\â‘Wåõ5¹ˆ«ÎçNV;ˆ=JŒóè)Ùc¯J´œ¿ŒSNRZ]ÄdÿÖ¡°¸=ÍÈùš‰²Äõ5?ò§* Ñr$UÚ”BÞ•x(Å.O3&Å!jzÀÊj榷CIÉ-ESÛ‘ýj> O?v±fÈw&1Ž´ÕM=~ç5}é2)i;Q]§* Qɤ§´ÅÕû£éSGÔÔ+÷EOZĶ=©´æêi”SÒ o¼jcÒ¡'“H´/ðT$dÔ¿ÁøÔ~¾”Ф&Þµ&Ìš}1˜ dŒ+M#S·fž*€rT¨Ä}ÞµyzT«ëA¤v çž½é̼㡦† ô¥rsÞ‚…jU㚌1åz➤súÒîoÙ$‡U>õbD 3Ž5¥Ë´ûV®Ýí<ŠÆ[št0§ßo0P>MÙ©ar‚qQÞÛyœuŠ¥”E#p‘sæÝxªz£5î³§Sæ'ÞHX¤ƒùÖmµÁ,îß­_9tã®+&¬ÍS.ZNzõÍj[>Â}?…sÈûºjÚ·˜œü¸â¦HÖ7"”`g=ý*Fl·5ŸàFŒO'Ò§ŠF—q8Ú=j5æ.«‡d|ãŽLòn”‘έgÊYT=9©•ðÊ£’G~ãÖ¦Å\³Ê® 8äÕ˜Á2ŽqŽ‚«$‹ælUäžj_0»nSí@î[|¡qÇLÐŽØBç÷ëM@våçóSĨɒÒvÒ Esž=}i¢6218 ÒŸ ŒqÀ4åØY†I|p=j’ÊÎ¥Ãy‰€sšjäpÉÊœ*$  Ãw®Aô¢×Cæ*4{²@çëQ aŽEh: ÿ…UsÊNsŽÕ!r/5v‚¼©ö¦JK(ÚvƒÞ¹çrñŽ D’•4"®,’:}ê³KˆÉïD®ÊøûÕZY £œŒŠh†ÅF.KÞª3aä Án¦¥F&2¤ò Vvà±ÁÎjÒ"R#’]ª¼d™„ÎXñêjkÙp§k|ØÇ5š¬ÅŠŒäö5ªG<äö&t_;‰7 <61Ÿ|Tw7A_óŠ%‘Q95›w(O˜ãäúÕ%܇+"%ûs4@`séÍOp¢8 ¯ –ÎÙaPqÎ2j²<·>”ïwbmdsä|çµ8dsÞ•”ç$õ4.B¶lÖ¤-‡;óJGzI+éJ^ù¦1À  ŠECŸJ\íõ¨ßå$ ‰¸G¥*IΧGKg®Òj‘ÏãEˆ±qH sNéU£“b ŠÎZ ÁÛ­#t« ªduªŒÄqR¤žÃåcÀùjOᨗ%jUåqRÍäåj6á=¨Žæ$Å%¸=Q•E™®Ã”\Ò§Þ¦Ò¯Þ1—× ©£¨W ©£ïX–Çž´O½­'zCPž¦¦8Å@~õ"¿ÁøÓ=êOà¨Ç\ÓDÈk«ÅBO5;Œ­W<z¨€ÞMX··i\T)ÔV¾sW#<â›`•Èî­šÞ(÷ nÎ*¨QÇ?ýzêuóÙbH¹ùyô¹|€ô“ÐÕ« @8ÇJ‘ÇJN¯íOQ·'ô¦6ã¿­ŒQŽ:óš;ûR/Y¾É×=®Š/š=Ï ×&ŽC èìeB¤+9®¦‘,²nR;Ö5ä ¥Ó<ðkwnñß‚¥Cs º• ØsÑ‹ 1í|ñŽ>•« À}¤uV<ñYŽ3šKyÞ7'½[WÔÉ;hl•ÚäçƒÁ¯C#&Ù2¡Kí žrk9&9§†É7Ê¥Aw±Ðý¨Ë²1÷FqÇçVÒS1#(¹ëI RF0HöíZßiI#ÚÞæ¡£XLÓwÛÉÉ€ü*xdP7ÿeC;*"©$7?Z–LȪAÚ3ÎjÔÑHÔ.RËÃ?Õf&uMÝAɬ¸ J¿'ÝÚ®A2ùáÇ8ê? L£VÜûG _z³lK).†³ÒUûãß5e›pPñœ®)X«–YV(†ÄîIö¢)1.?‹®{І7$oCÇÝ;©ë*$j@ @QÓ&©"Yt¸^Àpr}ê)ŽÖYÿ«QœŽ5²„„였8ç5¹1•9Áäi±ÜYÝ¢qœÕc/íç¦Úl’¤± J…— ̧=Èïš›ãßÏQ×MpÒíäd‘š°dA‘œàãÿ¯T„€6þ}År™|¼ÆÝ_£ ¨C VÈæ¬Þ#cëéYâQÉÎÀÛqT‘ï;æb:c§­V¹”F¹#¨ãëOžáz¯9>ǵcÜÝ+\ v,¾}½êÒ1”¬6YÈ>\ãר¦Ç¶8B~bÝ* ‡C3ÜP1Û¸sz¯=ÎȲCŒw­-ÐÅ˨ˋ€…û“ëI§[ ¸o¼ÇŠ‚îà’ƒ“[ñC·o@(“KAÁsjÈä]¨Mf^ݰü+Z_º[ò¬BQÊþ”£«*{¤ØíŠS´ƒÏ^´ÂsGb=«c0,Ïó¦`c5"à'LÔg®1Öš»^è'æÆ(Æ _Ò­EÕâ!‡ ˆà¶;ýQ¿•QAçªñ]f«c4qâ6XãQÊãïW/*á°)EßPjÌ„õ©RMQ•>´wäÓi1ÍÞåµDXÅCŽ:RA¨äK`¹m>é©TaqU£¦¬ ¹²’f‰¡PrE'—â4ª~jco'#¤&dÒRÒWaÊ©÷Å%9>ø¡‚/¯ARÅÒ¢^•4]+A[­ ¥=i(= @~ñ©ÍW=sH¨þ `4ã÷Öš9¦‰{éP8ªÁ#Ájh,F«[Úmi™‚©îk,Ürk¦†k¦É3’Òm!G¥93Zq¼¬eê2#‚ǃŠÎVÉ"¬±2ÎI'­V`ò:R‰½jvW@ïÖeÝÏÖÏJ™[h#Ö™€‡­ŒRƒ…òGjBåºSàþ^•¯¥ÌzzÖ0u\œc½ÁV!¸ UZûk9Y`qÀ$µj RL€ÀcëY+0a’r_jš9D88ÈÎjlRv:§!@Ç*p¥^Žau·½s‰x²ƒ– –Î+F;ËÀèÒ¡ÄÖ27…Ò¡ÁÆJ°›YL¨GÌ2}ë ¥SÈþvÎGøU›iÙ1nϸœþµ<¦ªf¢ÈÎF:/úšÑŽyÈpWÔV-¬ë‚OfÝWZè`… ç'¬_6…Ƹhˆ@~Rq@jc.q½}ÜàŠÃ3´Ž§“‚ ëÞ§{¢C;œÈRzQa&kÀ! Øã<⢊ç,@ž+-.Uç.O!~aëéRý¬7Ê:‘Å 2íÓ—Tòzš„3,²sÐd}*‘–E™KçkqŸCJeFw>Iè;ñE‚èži‚Hvœ×ÐÕW2ÈÃŒj.7ž@äóÒ©5úÍŒg øSå!Ì|³¶vŒg8ëQäy)æí,9$zÕfew$7Ì킾ýPº¿X‡,I?(¹«Q¾†Nv$Ô®DQ·•‚[ ±òÏ7ÍÓ·2<Ä>T¯_›"£ž@‹÷°GZÒÖѹ]ÜY¦w ¢»®ßËBJâÅ0†»— ¹àÖí…ˆtúRmDIs2Å•ªÅ¨\åVön`£îŽ´åFb=Ï ¦^Ì–°ðËs©+#;P¼+Ž8ÍM!š]Þµ=íÑžfÁã< ª½tF69å+°$ô§®ÒáÛ­0ŒŒ~´§å^O¥P‚@FßÊ›€GcØRdîùºRZbaó­ß ÄMò0U=kAf ’MtÚE«@œ62:Z™1£WZ–;Ù¾ÏæªˆÇÌTôõÃ\·òT6õ®’þ)!ŽgW_œsÏ5ÍKÇNôGA=H›Ž£šE†¦nÇNµdÜspqLïN<Ò´Cô§+º þ”žæ“<Ѹ‡-ÓÔñtj™?…GŠ\‘d¹I M§J²§Æ2àSsO‹ý`¡ì5¹ttÅOJ€u©âf±,SÖ’”ÒJ@#t5 ïR±À&ª¼ Ši\H”°ÚDÒ…éÖ¡i ¦ô«Q%²@å©ê2\ÔIúÔŒÝsM–¶44È„’’xº9£’{î|jæ­‰:÷ԙͪºÈʲŒ>:ãÚ³‘ÑB×9fC0pCŒ‚`1Wï^'¸fvvêj„«“ÅÜ몯>Xõô§«un¾´Àr1NLsÜb¯sƒ`R[§\u§€GnœÐ2F;iTΧ8¤À20OZPJö¦WvZ^M1‘v|·lpkuõß\DnP‚zë4»:ÙGuëXM[Sx2ÙäÃ"«ËSÐì«„ ÝÚG¢åØÅ–z Ϲ°Wà !»â·åˆÆÛÝ<ƒUš/nõi™J4$x_k‚9ÅhE2bÉÆ;ÑÊ?icgûEÌœœ€psëJÓ$à+g9¬I¯H*ÊWäTS^I‹É·¿û¸§Ê'PÒ’ì4Ä+zÕsq]—€†ÀïY_Ú-"È#êqŽr*K‡l³(CÏ“O”‡;—æÔVÙ 9ù”Ž£5H—e-(ã=Oò¥Ž$cqîÇ¥V{·ž*5à¾à¯JiÉ%¹[ØR1š®°Ku).NÀx9ê*žŸ¹÷É×Ðt«¸ÎjNVظŲ K ¥~^•¯x8š#…¸U&­–Ñr3Žõ“wgD!d#´vÑ18ÎI®[X¿‘6@àÕÍ[RY``„ÜW5!ÎÜÖ°…µdT—D#üŠNFâiŽ[ŒŽÔæÇ4„—`­L@1É4AÚÀ㱨À5#¹À9êpiˆc ¡¥p? |ݨsR* ™–¬ w”¹>•è6Pˆ­LrÚÆŽ¹ X–Q6H‘Ÿhº¨=–š¯pí$˜À_JÍÝ›ÍE"m-a–L,̧`­qr×­oÝêñÊ¥¤‡2¸ÁµsÒHY‰3À­#¢9¤1¸=)6ŒÒ±$ç§ÑÉçɇ¥7Ðf!è:â‘qÍ1uoJÀéNÙ×Âb€žsIµiÄb“fhD4Þô½¨«2 |_ë™OŒáÁ¤öܻڦŒàsTÌÀt¦›–ÇV\¬«¢ãÈ£'5ÜÕT¹=i:еâæ%iÙ±ƒQsÉ¢“½R$^1E%/jzR™Nj$©W3ô©f¨µc)†`ØÉ÷®žæÐIo›-ž˜®VÜípÍɧ­t®$³,s…äb¢FÔ_¼eÝ*¬ì£•¨BœҜĖ;ºæ—ØÀõ¨=$®ŠÓE±¸Á÷Ý ŽµnB¾Q\|ÕL>ÞØõ«‹º8ñù]Ыœœ6ÑŽ¤ñQŸZ~x¨ÁoÔRu94»=Å;!”ã·Rîq޵§¦_ yBîùI沑ÅHô¤Õô*2³;Ø¥I¢VBïJËŒàñ\†¤ðÊ ·Ê8 ×Qo:\Æk FÇDZd…|ÄÆj«®ÖÁéV²1éÚ‘Õ] °ätö4†ÕÊʹ9ª_'xžÔÌ%ð>µf?º {PJFmÖ ÀƒqêEeM¡ÜÅó@r=ë­Û½qŠ˜Ã¹:`ФÐ:Iœ!7Ð03Bç¶à8©~Ü»ñœ+¯{Eq‚ ƒÚ³îü?«»Ë½EW´]LÝ&a‡ù` >†—Ë…›r€xÀÉ«oáÀ§÷LêjÐncû“l¥W2#‘‘´a•TzžÔ¾FÒs gÉÔ¨ô¥ƒ²]½Ç<š…l¯Ûî¦Ür:Ó—N¾$†\Ç¥]Õf‡p,Û€]¸ö¨™¡DÀÀžº-ÓšM¿ð³‡Ù¿ÖLÇØ NHjfsÝ…ŸaÚ£S4ÍÄm´zŽ+ ‹E‚"~LûžµlY¢Ž§t)Rg:šcNÊóüÄ AWâ³ô§åÚ,c¥.kîZY!À½êä0’p‹Ï­:+w”ä3É¥¼¹Kf Ý3šÝRÕ–{{(~gPÇ“Ír¶¤gˆÜã®j­þ£%̬ñØU,Ï¥m[S)Ô¾ˆibsÍ9”ž¤f“oÍíI»98ÆßÖ´2§’xçŠLmÎ'¥9Ø4yÏZˆÝº SpŸ¯­# °¥)'=M'Oz+‹·'¥^´µ’YDäô¨ ·w`HÇ¥všFƒuQÜOaÕj$Θǒ7#µÒ‹Æ­*eƒ­=îÁ\v«÷ñÏ,qÛÆnw·÷¾µAÓdŽ9ÜJƒÖ‹èDÀ7'ƒéPÈ›ˆ#°©úý=i¸Ï=… ‘8ó+Cvô§O¥>XÀ9©ªCqëZßC‚¤d<¤™i ÍÏ´§óHÛP wíH̰NJPß{:PŒ§¨äö¡~ñÀë@C€3Ö¶4íD[e8úÖ61Í80lœÒjåÆV;‹{¸çŒ2œóÐÓÉÚ9ÉÅq¶×ÒÁ÷[¥l[jË!Pç½dàl¤™²À9äÿõ©Ñ¤‚r;TB@À2AéSDUÍÓÚ¡ö-£Á rI=*”{£<ŽÆ®+ž}ªYªÔ”Æ7ŸlSZ3ƒÏQžiÀç8ö§'ÈrøÀïRQ…[¨}œt#57ÊÄsÏjr9Í •žÎ öëL6ªGþ¤c “Ôi‰U 9ÇsEÅÊQªFJŒúRý•Oaô«Ì¡Tœt¤*¸ÈÒ¸r¢™·\cÑAÒ¬±ç ŽzT.Ľ8£P²+ìùØö¨ÜuϵLì˜õª3Þ*’8õ«I²ƒ˜ÎiBždŸ,`óžõ—&¯NwOÒ³¯µ––ˆÙ_Jµfä‘·w¯Ab€gÁÅs7úŒ·nrH&©ù…œœÓ\îè2khÁ#)M°bÇZj§nzóõ¤Tã$óHÎOATfû3ïHÿ/#?ÏæƒœMã=hŒ ¤fš$àãš'v(ÜSCœ˜ìØÇáSC r hŒà`sïZÚu™”üêå1œ/SíRÞ‡l)ÆÈ» µ¼v–ÛMĤü€rx®‹GŽæ ‚ÜÞ˜á%['Vn‡£¼—)tñ°Š9ª÷ˆÂJïik iXœ…85»RvÛao¼Aö²Öúz«°9Ü8­pšŒ³–iÆ+éVÚâmçtl»ÈǨÅe\Ü½ÌÆY,Çò­#¶9e+¢0Àý})XsúRäž´= QÚ@9Í0ßZR¸Î*2s@0œRöÅxôcÖ˜… €}iNvã¥! °Åô Fc`½i\òëMfçµ´ºÑEF!@éGz3@íèw QEf€ô´„b–€µ-%€)ãœT]ªDazL¨±ýu­M2ÿìÖ¥;ËËÜO$+ó¸GL÷©f—¶§^oV+vºU„Ê·GÒ°®éZFx’1[zm­ ÓneÔá‰ÀÎx¬{ô{{“ÁÛ÷HïYÙ^Ç} ÝX®HÛ³ñ£o8­4pÄžI©nrÔ¶:Ö UT€ã9ªr¦É ƒVÙö¹ÊäP²î= 4Ì«SSVDúfžrFG TnOÅ øéÒ´<ç™2ã$šPvñÚ¢VùI'µ,rryö¥aYO?- A' ŠBß&ÚS‡ùOn´ A!#ä|LÊ«c¨§YqÔq@&hC${W< Ö³Ôƒ° ÷®eIQZzÌSHÅCÍTìw–×HÃòjÜQÇ2 ŽW¦¸8µ#xÔÿÛãås¸t¨tÍcUêHÙ:Ôù Œõ«Ž´ñ „Û!íŽ+ZÇ\€°I`w$sPàÍ”âÍþ9ÉÏ¥1¤òztªU·À9=EV}fÚ1¸L0N"§‘•tk›…gÚƒsʬ¡ã$ ×/>· #rH'µV>* ¥áMSd¹Åu;ƒÒšx®*?L­ó|Ëߊ&ñ[í!Aý(T˜½¬N²y‘[sŠË½Ôã·]¤üÕÍO®Ë *+>êùîÞ}ªÕ#9V] ‹mL¤¨äÖMÖ¦dlƒš¥¸¼MÆãœVª)JmŠò3ç½#yî=i mréR3`”n¸ª3#;Y·g¥ï:Rì#8ëMq„84qå‰íM3hRT~¦Ž3L7ŒOjN0¤™5óÄã·jÏÐ`º²Ì»ÑÜ s“]1†(bI¢l³™<~›} ëMÞÅ-ED°Ë,S²8 ë\ :”¶²Ü£q¸©fýkwV½µ3J«,±N£¡éÒ¹ >flŒ’zúÖ±V9dÇ\\½Ì»Ü媻rÝ)Á”vóHA$œ€*¶ CÆ9ëÖƒ‚<æŒ6)ʾô°ïMÁRŽQ×éLB`ƒœÑœ’Mš\`t íÚ)NÑM'4‚¸¡¹5ëNcÍEšiÍ¢’–™GSE%/ozJ;RРͣ½cš(¢€ÒŠ:Q@õ(ëIKšN¸ dÐNF1Q¡ç9©Çz“U©©mªÈmc³d/Ý>œÖ¥Õ‘¸µ‰fCÉ>ÕÎ&æ'œqìk¡Òõ0cPÄ -D•Ë„Ü]̙ˮrAÅ9—q z×Cƒ ÝÏ›$ÞTd–a·ÛÖ³/­ $Œ“Î9ô¨oSÒ§U5bË–Î:T{ Š•S÷œúÑsV®Dc$T/Üâ®(.äöÏ:dà£&š‘”è©"ŠŒzPãó©dƒ Á¨9F ÕiÜá)AêL0ç"‘ùÃLVÆOåFrA'Ìü‡ü¤ƒšBùöö¥ùAÀ¤$d‘Ò€b©b¾¦ž#4€…lŽ@ïDd´Ÿ\àR–p1J„(Ï\qKÔJj²ˆÉµxÝ“N_˜rÔÇvYû\€m{Ôfvn7qQp²b¼Øè=iX™'˜Ì>÷ËLÝóPÀÏà ¶;ž”ÄbB’iÇO¥WVéQŸ•â”y= PÌù8!søÓ8É>âûÎèÉ?ƒ#Ž9ÛNÓõ¨ÇÊÎsN.¨I4ìŒ {ûÓù#·ZLç4ÒIà}sLnÊî=MŒtëïIŒ”„Æ(ШűwNù¤±ü*TŠ‚zTå6* c­K—cªvõeqqº§Eù~^µ"¿ž@©í`2È ”œŸ¥Klê5 Û;#që]D–6ï ÛéÖÿi¸3"ó†î+4yš„âÖÖDC®@Ͻmè‹q¤[\Í(òð0=êYI%ª"±kû¶s[œrAÇJuÖ©ko‰"¼hÏÍA XWúÆ©tAYe »•ùüê…õ˜ŠÖ)~Ö$™†YqÓëT¢pÎ¥Ù§v/o¤˜íéÅQl”÷Å”ÜÓs•'=½êÌ€~CÉÎi®6ž¹Þ½ )`H˜ ÁÎ@¤fÝŽ”ýÛrzfê)’RŒÑ8ÆM/^”€4¿x=èÆ #œŠcÀ=@¦7ݜܮj6=»PL„$šOÂ’—8ª2¸””´”Z(¤ bÐ( q@‚’”PhQ@£­(÷ R;PÑÞ ZrœTJ‡¥874™q•‰3‘Î¥¶œÁ&GÝ'š„`(§¯-€)vÚf¹ v¦6 Ì݈Í&µ ¹ÓêÙòáÂ:{`ó\”<p#+Ò·´c¹ŽcpG&³”zšÓ©ÊÌÛˆ5RT©==êHP3ÍnjêŠcoÏzÄ?ëŽ}jQèÆ\ÊäªpŸ‡åB‚äãTd€ w4¼UÏ^i\]£v:ŒTsFÈëR ­— ‘Öš&qMX¢Ñ”稤'8«N0¸éÜ“ž*ùŽ9áõЮ hŒÆž`lØS-ÖÌ]!ʧž½( ØÂðAÆ}*2Náž1NåOÔæ™“DŒùÀ=h yÅ0¾Nê‘J°ËŽ3Ú€¤G&€r¤1Þž?)AÜ 'Ò¦ò08¥q‹œä÷¤”ëI§©æ‘˜äý($-ódô4¹•ºc‘P9"°ã=zPkñžiËà}ãÐ{TY;Áô&¤/€HÓ¨§rŽ@ú”—×ñÃwrém’[i=t^.Ôd–Å¢¸M—.ã…)ó\,ò*¶S=;Ö°Z““gC©êzrÙùz~âû¿p1\ÃLÍœ“­5˜°94̰\wôªµŒÞ Oïš\–ǵ ÀÎFOjBØZdŠëŒéšglûÒÀÇ­ íLB‘Ï­.Os@*Š ÉÆ);“è)Åi£îçÞ€lõ¥ Bž3H~æj2ÆÉnÂ?6”RU¶¸¤£)- ­%-E%/Nh)IÈ¢Š;QEÔ(Í  ;Ð)hç­œÐ~í &ìŒSòsŸj‡8§+ò3JÅÆ]És‘‚p*{;¹mÙ„g†НÁ9'4n9éH³¡¶@öì žTãØÕw±’(DÇ•9éP[j2F¨­Ï<ŸjÞ†ê ˜Ò'«uéYÉ«8½N~?Ÿ9è:ÓˆË@àҸҾϞ¹òÙ¸‚–m6H­–tV`Ã'¥EÏB‹²¹šàŒ½i§“€:S‰sƒ´ãÖ“ É4Í® ·?ZWõÍ"òh`FÐ9ÈýhêmÛGzfÜž½1R¶áPp)™Ãg<ƒÅ$6µ"šòäÔK“Wœï\޴Ч†ã޵IØÊT#&Q(ÈJ‘“í@'%H8«ÛG2:ÓYzbŸ1ÕWB§–åwÇJhfB:Ö‹&ØðQš‰b–ëÜP¦9aWB‰,Í‘’iÎÙo˜Š´ÊªøQøÒ¼jX–ïG1U)7ÍÎ (3й䇽©vÑÌU×RŸ' 52¦åüóV5;†ÞÜSvûN1K˜Ò8dµ"hFÑÉ©c@‹‚ìõ§äãåäPU÷>`9¡³eN1wHrm ŽýèQ´°M3v‘óT’»p¸$T³DÆãTúfž«º2£Žç46p%=x©’&‘ÉN^}ÅBXYËwvD¹f8Ï¥YÔ´‹‹Q*c'F[›_2úÞÜÌ‘Œ¶; عÑgÕ¹’ðFÎ7ÈÎ3éJç3šR³ztØ´ù„PYY´—J¹,ÿw8æ´´o7Lº’[Øqædå;;S´ÒVk“þ´´úã½a^ø²ååcåGzŽïÒ„œŽiÔ[#°¼¹û±»HNöïø{þUŸ¨ë"Ê$¼‘|œæ¹ç×ï~ ¿ê$ÈØzþÎÏ)ˆD1äüµQƒ‘kWÕn5c#åU‹*ö=«)ˆeÀ<Ò´ŒqÁëP†ùɪFw$z}i¬NïJW94ÎyȦ&)#MEÚÇÖ‘JLŸ$³otQéz¤¯“O’+'s°MZ)-â×r(åOz¿þÐÓÚ+)öJú¢r0+‚ŽgC÷Žnx~ðG~¾Öç•C¤*¸»› §¯ö%ÊÜF£RÈÃÖ¹ž‹Ï5Õj×Eîç¶“ .мEa6Ÿ6ÒñØúÔZÇm:É­YTãfà8Í4HCïZé“Ä‘.ÝÌÃ8õ¬àŸa0ã“:Óµ‰“Æ&@êH k‹­ˆ2ÇŒT—V²Y9†dÄ‹Ôu Ñ;•÷ü‡jã4«‘cÐñM%)\ìEî ¸øÎØ‹w4…¿w‚9¦ÆÛ²ª¤Šc¾ƒ‹’ˆ£¯­$ƒf2yïHU™²8©vpù9"Æà·n;R M3-ÓµHç9Î}h9øêy¢]¥hÁîi$ùGëH>hÀ¨d à`ñš‰ã¶ç“Í6FmËúâ fd©¢ÂæÐ8Û´}sB1@@9ã­:8$‘FØß?J|v­çˆNCÇŠ..d@F$eªL<À9Åt¡ivºw›w<ÂV]„ôéTôm.-GTkE•q”~;Pgí®g¥»M · LØÀZÛOÝÿg­ÔR+1ÈóÍhiúJYêë,òÑ–ä|ÑšÙ’Ëùž]´‡: M¾†Ä7°ž,´Æ·Â³¾U¸õÍs^ Ö~Ï/Ù-÷,Šq¸` Ú[¥¶¿`Í„‚ž•Êjš¼­wÄ2 G gŽj µ9%+êXÒu™îoÌSì´ØKó׎™ª^"M2,iÌ<ð1éX¦EÎ#×31Áû½Íh¢¯s;ܵ-ì’"ÄÎLiÑsÀªŽàœŽ¸¤$€?MéÇ¥;pl©SÖ™Ð┘zž}éØMŠƒ—'°¡}OJqùMÈÆäœ­8Ž˜ïGÜ\÷€ nÆE4)• –Ÿ j>lãŽXÖ ¼ŒeLž‡Šë!ê±)Á#ð¬åB«F=µÄZ“´@!SÍÓ­u%ÅéYC)ê½ÅZÔµ“—¼`¿÷Fj]:Ö+é“í ¿ïŠMYQ¯ÝZEå‘'1ÍŽô&¹é®Põ¯+Ðç°¶þÊ»ˆÄ ¤e—žAÅrÑYÁ6½×æ89¤\*«y*›zúÒà;ÜqWᵉ¤œpG5Nâ1 àãš.l§q8PFF)<²Кй¶Ž=•ϘíƒÏëwMÛ&Œc‘Õq€E§-.ŽH+–Ûü'­9“ÊmÙÎN+VÞæÔ‘Y~ROº«ýÅôû r¤–Éö©;}Û¨Ø,¾Õ+(óXPQKEÇ­]‹r± S€3ÍXŠˆA¸§'è+CS³†ÙÆ;ò{šÔÒ¡Ž-:GU¦ç>´¯c)UI\ÕÓuØîàXm-œŸ1$`b±ïô Ù&kÉe èNGéZº`–("P3Ï"«®«toœ1Víå{P“{þÕ«ò‹§iV«§ g,À‚['¨ºzØÁt/ }» OaYž(¸•ÕQ¶«1Æ8ªz ‰îdiFâŠJ線ь¦îu·¯i}i-Àp?”zÉÖ5a/‡6/]Ø'ÛÈMw4w²„líÇãU^i 2î8ÎqV£c7#Fç[–k(à'>Zí«(¹ ’y¨Øô‡îUÍqå½iŽä’E!ëŽÔÞø MŠOåIŸ–•Fåæ›L[€ªq‘Ž *œiÉÈæ€¶ ¸ Öžê\žô\“ŽÕöÏZ@Ý´FÚp=é¦RT)éM<ži*¬fäÀN¦–ƒL‘{Rph¤ÇÐ\⓵v œæŒóEµéXä’;ÑéE·ë@¤¥ gÿÙprivoxy-3.0.21-stable/./doc/webserver/team/06member.jpg000640 001751 001751 00000001644 10546014105 021601 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄÿÄÿÄÿÚ ?•ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/05member.jpg000640 001751 001751 00000001644 10546014105 021600 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄÿÄÿÄÿÚ ?•ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/index.html000640 001751 001751 00000003170 12026576114 021463 0ustar00fkfk000000 000000 Privoxy - Team Photos

    Privoxy - Team Photos


    In our day jobs, we're all models ;-)

    privoxy-3.0.21-stable/./doc/webserver/team/02jon_t.jpg000640 001751 001751 00000003767 10546014104 021446 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄD  !1AaÑ"2QTVq‘“”Ò’¢Â$%Bc¡´Á34Rdrt‚±²ÿÄÿÄ"Q!1qA‘"ÿÚ ?í·)ÒÑq””J})KªdõÕ~p›ç’>*»heæùojó=¥È!hâT95£žŠ¨oÖáÆB‡­¥öS ´ç ¾y#â«¶³œ&ù䊮Ú^:ŽÔ8ËÖ…vV½óZ<õ?q]”é†Ë‘œ&ù䊮ÚÎp›ç’>*»is¾k?ž§î+²¼ï¢ÍçÈûªì¢˜l¹9ÂožHøªí¬ç ¾y#â«¶–­±'ɑ벼:ÂÀ8Ýþ=”jøñähç ¾y#â«¶k˽Ê6‡ÔOƸÌeö­ÒÛ¾¤© (‚9Æ©e§Ç¬yì¡ÃQÚ.º7RC·Ü~JíS–Òw–R½Àì£VG’MDË‹Ôb”(ŽìÞ*ƒ½ÒNÒ}¦Ÿd4…Ü®[[?ß$q?½]P¹lÑ•:í1¦à,ø.)8 àzü¦C³DO,ÓLGp?åQ9 Ó»ÃÇ®™bÞl“îN3áLGl-ç€Æ×Šxñ8VÓ®¶(“¡Å2Ðã’œ-$´B‚T1¹Dpân=T¾'„(9oYÎvª«¶Ïõ{Eu“f ݲªÏØÛXÞØ5µÔÄÃéeG$rØ7ñ÷UG-Àgq÷WT‘§ÒIÂqCž°„çÁþµž,›éäŽbì ?dûªKd`x^Î1f¹ÿ"ýþ€ÔÓè @9Ü¡[SL›ƒ]‰\r#`*3ÒK˜ÞRF+C5[ %iå ÜU€Ml˜)v2Ýei  ÊG#ÁðâðÑIñžllƒÙMä"XåÁã“Á ¤e2JNãV,«e|ò¦ÆÉ6[žÿdÿ]zäTÛ=Ñ/¬aAµç¯ÈUOm·;“Ý1Þi6kŸ‹ŒŒÂ~ž<±´åŠ_GÑ÷ Ên³!Á+å–JŒFЉÉÞINIëªkf*Ó…Û­ŠC“ùhu÷Xi¨×»‹u™—ÚâmÉ­%HPQUAèª=ûé_Iì>×Õ]t‰Xx1$m¶NHîwŸ/‹^.<7[mjç 'òÐ.ýô¯¤ö?Ÿkê¬ïßJúOcùö¾ª)mPà-!+µZT‘À{$ÁZsu³õ5ŸÕÌoü¿}+é=çÚú«;÷Ò¾“Øþ}¯ªPì4˜VôììÚm#g†-ìîü³±a:’—m–¥¤ô*$æ÷ï¥}'±üû_Ug~úWÒ{ϵõQªà-†Zng<•¢ÐŒñÙ·°?%×±âGк™ØÖëk T´‡„Ò¦È$nòÖýûé_Iì>×Õ@µæ°ÓRt>¢b6¢³<û¶ém¶æ´¥-E¥ É$ôQª gÿÙprivoxy-3.0.21-stable/./doc/webserver/team/04rodney_t.jpg000640 001751 001751 00000004132 10546014105 022146 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄD  !"1AaQTVq‘“”ÑÒ2¡#57su²³ÁBRd‚’µÂðÿÄÿÄ A!"1aÿÚ ?vܧKEÆRQ)ô¥.¨ “ßCó„ß<‘ïUó©tý'3öËþ#BÓW8MóÉõ_:œá7Ï${Õ|èZ”W8MóÉõ_:œá7Ï${Õ|èZ”W8MóÉõ_:œá7Ï${Õ|èZ”W8MóÉõ_:¢×—{”m¨Ÿq˜Ëí[¤-·}IRQr#®¬ë=´OÕþ§ý×+ùK µ&³D]O>/ÂDç ÔHÊÁ'{x{h–.³Å×"´‘Ö¥6¬þêSë‰ ±¶ ËŽÝÉJ*òA«¸÷–æÏ¹8ܶ„}Ô'Êök ·N2ÄÍ•ÓÆJeIyWLg›}[¡\Æ~ßé’«$ˆl˘©*ݨ*PG2¯ÎuqYªí(ã(¶ÛâÂZk‰Q<xÕ6©¾MºjBÓNÃDHd-½ãÒ*8=¤ddmUwJI¶DêJI#A¨.ŽYo¶ÛcΗ4 r­Dè7¾½Äç.‚xõà ¬Ö—Ebº·Ùn‡rIŒ© uŘá88ÝU’kâäë·kŒ)ÒänËŠ”-)ha'#‡Úïx˜õÔ´—¾\$eH8Þ{êü)ùÛÜ%Ö£Ž_ŠÙq¿G$=¤ÒŒ‰ÕúÐjü îi=-4ÀõÈWÓUûbÒ­Ú-qç%…3Ê,¤…ÒïãJ›Kl‡Ôäy ‚G äÖˆÍIj3>Iã¨ü¡§¨àéèÉõÈWÓEÇÚäaõe‘ib3r-r­¼TAn#Îv”cï¤TÔ§ÂBZH €­.ÍÿM\p9–ëÿ"©=Dò{†ãko9jZ¤„•%ÙʃՌgúUP—&ÚË®º¶ÙBSÀž$’8UÞÙV¯í&û½å­ù®%‰$¡dãïêÍ-nLÏT×!I}Ò´/wuÄœï#¬b³¸ò‘²3p¬×Ù5ÆTØ6÷¤˜ð!·U½œÓÜiy…*cÀšGm¡Å:w•‚HÉïÍ$tÎ"ß©m¥jàW÷NGK¬ÓÖ8EÑä6‘ù¥åK c ¢ª×“ðÇe’ñÿtùƒ¨Þ\K±Ô¥¶œ$!ÁÃ1Ç]i‰×”°âT^l>¶””ÞIÇHùGgq¥êT§qLàò +Vxg]hvyr[÷K ;»»ˆ #ÉÝÒ®³øµuÙÎ?*×éôg¶ÐÔÇ—©:¢TWÓ$¤¯»®–Þ›ä"¿¼½ÒUÊÔŽ=†›[y}ÏíWŽtùR…+¸ƒÃÚ)y§!¾å»œÚe¹nnô÷Úè·Ž¡ž¼šálxzÒ¹r["•v¥!N­i ÊB¤/ìùO}Zlý—#Þn(p›-מ"¹ß'Í—.33""m u'xáŒÿJ3C©NݧºIRWeºOaðò)Räã÷XÇ4”¾¿ƒhMÅVØnJ¸°òàµr.¾YJ‚·wÀ8W«ÉBmb>ŸwYÂ:I·AlœmÝòVO^rpq×Míe²ý)~Õî74]×)ÇÔ¥„MJQö’ÙÀîªÉ#ÒOISÈUíŒB–ÒRŸPäi¨.Μä&gZ]¸Èb­‹YeÐÒå4ߎÍå?Ò_¢jS/)#8iKŠêqµ€x–ÓÙë¦Þ›Ðº~Ä·ÊyšÛ¤J\Ô©>T„¶œú1:b×t‰V—n–ÅH!O";¬).+ÊyFTs÷Õl’Äsq×¢&\D“fmùA¶*´Ê’’0¢RGWp¢ô%Þß.ø˜aä¦[ R[Hi%$¨äuö{)¯tÙ¦“º?áX».I9SÂpIQí$÷x÷]el÷N¿hnìËl(¨:Ô†Rê²Iâ®G«Z²^µâ]1Qxˆ«ŽÏ. K;† Åòeîˆ)Þ$žÃ“Kvf;àìDi/ÂYSÛ…) ùxq}zzÓ³Í=o*®^§ÆFò&ÌmÀì’ËešbjÈK·ÈÑÊB|‰Lò@w2qí¥'¾ÇaåíCp~UÁfCÆfë{‰ZÓøgm\ìíÔ‰¹9žêVµ+üƒøÀì¯B³²=+Á#ÝXZ† Ñ-²}…¢? ¬¿ìëNiÝ?¨¯Vþu\æ­ž^CE8Î6I i$ðQíjW¡ñ{£^éúNgí—üF…ªËî°ÓQ¯w$ê+3/µ!Ä8Û“ZJ ¢ « ƒÙ@øï¥}'±ü{_U2Í JÏxï¥}'±ü{_UOô¯¤ö?kê  JÏxï¥}'±ü{_UOô¯¤ö?kê  JÏxï¥}'±ü{_UOô¯¤ö?kê  g¶‰ú¿Ôÿºå)u¢b6¢³<û¶ém¶æ´¥-E¥ É$öPÿÙprivoxy-3.0.21-stable/./doc/webserver/team/01stefanw_t.jpg000640 001751 001751 00000003550 10546014104 022314 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄE !1A"57aQqsu±²³Ñ$26BV‘’#%&bÃÓ3Sr„¡ÿÄÿÄ!1"AQÿÚ ?vÔ§¦ÑQšJ&ŸJRê€Â=ñ\4ç¤k¾ß¾ ៕•2͹ͥÌc¬ ÛŸ‹Të9Ï,¿XÅLå%Ú7ý6½*†ˆ%Â+å‹H8ú×RýCÝ 1éï]KõtÆSH±‡/¦[õ*<åÍPpw¹@KÓø½©¹ê ËϦ¡ Qè¤â=Êv­iOŒÇhí‡ß,7÷Þª—ëèÇË ý­U/Ö=Ð žc='Gçm : ýð. ûo“¥ïrÜ´ëUÚÌä⥓ •¯AýlcêŸÈAíùW©KX÷òÕÆ_j0¶Ümõ%HPiDAÈ ð§ä·‹.Ünç¤}0ÊÒ'g÷?šæ½’áYXp+ªuœç–_¬b§òo_HÛNÀÚôª-…S¬ç<²ýc3”šŠt±Xù“[?@º à³KHKlmHJw$G^Qú*ÏŒFæž9“ªc½¦{qN­zŒ “á‚ë^ÃvRìÔÉIQÜb•—ç•e52D<­yF$h8dRnQG’aÄÎS1ô’®›}Ê“ÇOFÌ9¯¡uÛX—zY,ªI-=Rë+(ÂJwB2þ¯·=<™Y•ÊKP¥m W×¥ÔÍvElÐÂùÇ…¨¤¤àÉã gÙq•”<’•Ž)Ž?¬_‘•?¬xX~IK*¦^ZØÿZC†>ÌÌ5´‰ÙýÏæ¹¯d¸SòIêÛËËHz³0ØÒ'g÷?šæ½’âèÌ‚º§YÎyeúÆ_I7‹¤pe¿D8«·…µ-[¨±3qQ™}©‡ãnN´•!ADAVA„(´ƒð:å¹Ú]rÝvYM¥!J­Ê6r6Šÿ!'´p½Q?¼ÙãŒë Cߊ¡¹·[o~~°Hÿš4üE0þ)mŸó‡ù¢>XíSšu'‰Ìj¦¶·ß-l ¨gx‚ºµŸ;0ö»5lìûÅOÞŒQí éy’§jÚQŒgöŠ@ú‹Ûò ÙÊ… Y€Ú;€5‰O°!.'r±mÚ¡kJÜ­Û(ÀÆÚô‘þìOÐmj ž`Ôîu,¡ZË?Inìb[C-è!äÃoÏR-Ë’nu¾m¹É‰DµŸ´—ò|]1ùCHŸÜþkšöK‰'¯ :Rˆ‰vnkq® 7SaX*àßåámLØ÷×çݧL!¶ÛiJZ‹J’Iáƒmlf’tÿÙprivoxy-3.0.21-stable/./doc/webserver/team/02jon.jpg000640 001751 001751 00000247600 10546014104 021117 0ustar00fkfk000000 000000 ÿØÿàJFIFHHÿÛC  !"$"$ÿÛCÿÀ "ÿÄ ÿÄG!1AQa"q2‘¡#BR±ÁÑá$3CbrðñS‚’%4c¢ÂDT“ÿÄÿÄ5!1A"Qa2q‘¡#B±RÑðñb3ÁáÿÚ ?-fïÆZ{ZƒÎjÄyåq´“늎EÛ0?•z;Û9»$ÎqRÇo+·­â·L/ÁÈ£! $€  ÔK'Ѥq/l£·Óç•öí#µÁÿyœf¬Zæ@>šo×pÀ”¥7ѪŽ4{¦ÿ,AGAU²ÙH<ZÐ>£ &7ç÷<„–$|¨Œ¤‚Kä§’ÒEo„;TöZt²uã4aºƒÌÏJzj±Â–œöâ¯t½"…ÛdÑèÁ1ŒžçŠ0Ä ÇÂZ¤¸Ö®%8ɸ¡$Ôn9cÏÖ£Ç9v_š蹚x£ny5í4«Dª).glîrG½DÒ¹nG^õkÙ›Ô}’ê7l w=Åü|ÏÒªL’ãÖ˜ÅÏ;Ž{U,Iç“,Vø«exùóQÍ|IåÛ5^êÙéHPãj¼q%åQ¼äŽi†þMÀ©86ÃÅ4£zSÚ…¾A_´¦Æ7½é¥sœ—<ÐÄôý)»?íÆiìBß/°‰u †Áö¨Úòàœ—$ÔEsÍ&Ìdã­Po“ç‘,ÇëQïlç?éN)‘Ò“n9ǵ4­‘îbIÎ ¤bHTŒ¹=é»O¦sB±„œéHzñ)åOR?JnÒ;|ê‡cyÍ3'8&ÓŒm4…G (ùɦG­JPã§Фvä{R #lÒÔgçR„êGLúSJ±#4v;"oNÔŒ8ô©vqíM)ŽÔ!YðGjiã­K´ã§jiR9Ç”0#Á<Ò}ñR•>œ nÓœãôpQJB2>µ&Ò#šB‡vqLÍ'Ö¤*~C4ݧßò©§¥4:TŒ§Ó4ݧÓôª߀ºÛ‚ƒ¸¦˜nò@@QVI<]—ï =3ï^F÷ô{. 쬎Öè¶Jc4l0ȱìeé/°~CK}/'$ÀÓù1-± >`(¸ô¦f‰ph6¾—=‡Ò£7­×'üÓXؼ‘ óîA9‰séOYnghå@¦¢z´ï¿Hy§zÕ܆ÏéKeú:Kùùà÷“±Æ8ùPÆ^û¾”Ó79=êö/¢^OÉ;^M’vã>µ ^Î9ÛŸ™¨šeõ5ÊŸÍŽzÕ¨/£7?ÈöÔn@Î1L¤äã?:†GSÓúÔ-³ëZ(GèÉÎ_acU[Z"ù¤üj¥V €ûàä¶CŽÂ“ƾƒÉ%ì²v2‰Tûš|~P@6&j«;‹|ëšCžXñèhñe/UöðbŸ÷—AHð:Ö~9HÀ.}éë1ãâïëRñæ/ ÉŒB*7Y‰š¬I]IÃ|éÿ|pçKcCò¢yí®|(£µ2;)•Få¹oÝG-\Ú‹°ÃAN¤¸'tdrÚJÜ,+Šé÷%ñå¨^”_í§œÒþÑÉÉíTœ×¡¦ØiòÆv•ÓÞ¡6“‡ÉŒqVM~®¤ƒ’:qLûÜd‚@?ZjSŒÒ&Q–Œ|±SL$xÆÈGÔã4;r?­p½TRätPNs(QéŠs´ÉÑŒŽõ^±=HæšorÅ-­úèýŒJ’y„sÀ‡rÛÍH÷JÇq|ª7ºø¸*N*éý·åYÏFEtq\1!"Õ?š[“Š‘.‚ô>´íý £b¬S,xÚ™ùT' ñ(Ç¡®’âF š†O0ŽûГö7$HªKã`Ç®jc'ݱð+{ƒßó¦0®2ÇÐ{lõÑ`n¹R˜=k£¾òú²ª(Àœ ýj2‡8ÁæŸ1yd]6 €tCj‰uUBß»>õPAÎÜœÓYH4Ö(Ñ/4ËWÖpÇzµ›’ÇlkëÚ€ÛÆsþ´Œp)¬qú%å›ö&«vç;@ç ßÝ’áKŒ.IãµZŠú'tŸlW½º#?ã ]]ñôõ§ã®=+ˆL⎡rý‘5ÍÉÆ@ÇúS ó(Ïz™“áÅ!Œc<Óà’#=ÆG›çMƒÍM´wì=i¥9ÿ4p‘¦Ï Í5ä˜õQž•0A]³ŒƒO„.AÚI”S|ɰ>DãúSv u¢ÐQyrAZBóq•: ç4Ý£ÖŽ@$›Ÿ„{W%ãá8ûv¦íÁÇ¡¡ÐÒ 2L}©<ÉFr¢§*Îk¶ ïL@ÆIÇð × %Ç*8ëSìÀþµÌ£ÔÙT d›ùA¤2MÂ¥´*nÎ3ù i¡ÑyIÈQÅs<ÙÆÑÇz›n»gÊŽ1y³ÊR&Îv­P3Å0(Ï=èµôåæãá›æ?Â?ÍPg'¥qQëG‰%é´}4<Ý6x4YEÎ)¥P)iºlàBÓgʧڸ(=¨´= »¦êRo—®ÁDã]Œ÷â†ÐP.éxG4™˜ñ·VwCIO RÒöQùR7ùEqíIŠV@É”¤ß(ãËŠÚ'wÎí•8Rz}) xöïE‰& ^^>´…äÎ6Ž”C'"šW¾;Ó´@^AÑGÊ;Ÿá1P9'šB‹Ÿõ¥C_“Þ•°GËÒÁdcšSTÆk¾íƒñŽàW›ÁêòE ÜqP¼i“‚:zÑ~@Ûð‘LkbSƒéM4‰i°°8)¢3·­ÖÄ #¯=*3Úp¦¯q-Tœœçµ9UT“ëSšå¶'ƒ’sNÕL„;Žz×|]WŸ•NöÏAåQ=¼™ä’Gj- ¦BÅ‹ t¤=€ç>Õ#A(ã¯Î“É“9ÇZ¥Bä‰ ãñQ±cÁ9ÍmŸ#Šä·$á‰>”ÓDíl®;äõ¦Ÿ@ õ«hA )ßwq·¥=É cef =8«œGµY^2Fi ºð4Ôж2¬©¡Æ{ÓFqž‡úU£Zè1éšgÜÛ<­=èŸ+NÎi=8֬ձȕ5­„T¤‰p`8Ï_J@=èß»çé†Ù¸ÝèMÙ `Ì4íÇ×·2Û»áhànaô46‚¤@ #¿*BïŒô4GÝöœi„ãšv*d; íÖšÊÊ É4G”Ø×Žps“éE¤>A;±Ž)§#•ÿâŽ"šÖäŒsB’‹Ï^õÙÆw1Á¢ÜŠk@ç>ôøb¦@IÇ曹¸Á©|¶Ï9ÏzC àfš'’ ìO#µ4³nÅL#= Œã¨æ˜¹’I‚)7¸è:”!#Þ“aà{zÒà:$rjS+sŒ{‘]³ž})¡8Í;b‰ßŒ z× †à‘]°ö¦ÏcùÑH-3ñÈæ¸Î ¨éÖ›°uô¦•<ôR Ìy‘sÊ–) GÎ@¤‘šI ÊÅÉ<’y¨öç ëBˆncÛc˜È½”.OQíM#áÀ9¢±›éŸCÅ&ÑŒ”ÿCš@CÓ>)̃íHPôÍJËŽôœ‘޼Ð+!Úp?:Lu8íSÅÅ!^ã  DA[Œ>tݼúÔ»x®Àí@YÞ: i^?SSœà}i¬;ŠiðFW$qƒMÀ x©Jtì})6ñH°O ùu¤+×#ÿŠ›n{|©»H>´ã­!óRãž9¤ÛÇ<Ó,b‘êqô©v‘I·ž($ˆä‡šn29É©Bæ“¿4Dx)1“ÓçÅLGô⛳Бv9ëIާ K³¨® žÃ4Š!ÁÎzb“aô Ôà|=½ë±‘ŤS¿µ!^sƒŠœ© ŒLÀÇÂh±íô¤Àà‘RííŠì~Yô Šú]·'çRàc°úRmÉù (‡8ö¤)Æy58AŠFw¥`E°öëIå“Î0µN[®9Ï­#1,|l<æ¸ÇÁÏNµ6áŽ4䌎¢ÕˆàSL$óSœý=éz ,t å|'¹¤(q:w¢NkŽÜp4XpbÍ4Œ1š0¬dói¥'6:cÏ"˜ØÁ÷£LC¨Á5‘Ÿ†šh¬÷ãò¤ãÒˆ00tïLh[<­;&z¹ëÈü© >þô3¹'åQ´¤‚;÷5ç¨{=/zç§õ©C(~U\²v'?ÚŸç•ÈààSØ%•ciÀ޴Lj|zn÷÷®ó—’çU¥§9¤.ã¹Å?‡™–‚U#< g™ ŸOJ®Üç§JFgÛÔš<`óÂê 3޵]#d ¥V ãÿJâXç,I æaþrmäŒÓLÉÊñÍwy÷¤ä`àš{åaÆe< SL«Œ äàw®9?Oz~1yh‘3Ú•îvÎhœã<|ë†rAÍ'ò…y±g•”<}”{P€·{×a‚œý*¶‹ÈÂüÈÈ ûñH$œBŒƒéžô­œ`cûÑ´7²q"ãßÚ“xÁ‡4?Qí]Î{â–ÐÞNYHíŒSv¨äÓ¦j"NFO§­vH4m Ⲇ<(‘“áêG¥4NAéÇ4¥N§=)Óè›b>½©~표ƒëJà¼S„„zSä.$-lǧçšk[9÷&§ó[9Šï=¹âŽGñò\6ñÒ“È|ãoúQ^gÁ—Î`)úQȪ žSÈ´y‡ðý)†ÝÎp§?•=È[XÑœi zQžKõ H qÆÃOpl`eA>‡­4¯cG4FÎ;TbÞF8(hM kçI³ ~bŽkIBçÊ<ûT~Kç9ô£rÇôFÀç¾+ŠŒätè·‰†2¤qÅ …ÏM ض°M§ŸJiAߥ¶Òœwâ‘ídRSò¥¹²TF8Å4¯Äx£¾ë7âÙ‘Þ™ä¶ã¸sè)©"v02£8æ“hÝŽø£ ¹ì2)|•â‹CÚÀ ûcœR'µÑÉŠO„tÅ-Á±‚yNx G¯Í„¤Qþi \Q?ŃŽôí… `£<þT¤.:dŠAÍ7¿J`7p9F)®£ªŠ~ÑŽ™ùW0;sǰ ƒËÏ=é1ÇLö¢0OlRí'µMò*ÙÎ1]°n$Š›o±ù×c¶>TD*€v®($T§qÉ5̾ßéEŒnãÖ˜SŠdÚšÈ;ð(D´W¸õí\W‚h€Ž˜÷¤d\gŽ´XèŽÕïN*vAíHcŒ¡£€öB~˜¹éÓçOdÛÍ7`ŽzÐ1¤ØÇθ†ç¥/OJíÃÓ&¤ƒŒôÆÆyÎiìÇÅ7p9ãÐÂÃéIº•±Ú“áö£ =ɸœÄ>”Ö*Oü¦ãÖ¡RüÄzSÃHe‰¶k¦»ìp*&3ýi@¸Øyõ¦ £çNóœœä¥*`¦…ò—ù /Ý”©8¨üÆ'œ¥(‘oÊŠcßèæµäá?*gÝôÎ>U*Í'Cž”ñrÙ8§òB¸0fµl ä|Å4[¶y^(øî‰øXdTÂxœŒ¨·H{`ú*Í®@À=*7·‘NJäzö«rј9ì FþYhüèS`ñÅ•^3Ž?½ N¤ZuÅ@^Æ‹m=×4⣟j˜¦yÔXP>Üv8¥&ÓŒŽ´FÀ8É$×4yç4œŽÕ܆ÿZ›g=+Šzb‹Hw¿~Ô¾aô§”=x¦”É$þ´p4ØžqàOΗÍàezÒã¾kŠNWj)Úäx•8éIç.p3f nôÝ£¡&–ÔØã Ï ®g LØ1Ç_!Cœ“ý)íA¹Ýž™Å&åõÏjfÜ»ZB§ÐóKhnd›€<(¦‰:`S1ïIȆ‡½²Sqµp3\ÓŽIùqQ îàŠnsŽ˜õm ìž`ú×}ç®NzTG'tö®ÀÏN;sFÔÚ÷–ë×çH÷LÜdŠˆ…'“I°éÞšŠöHg$òi†d=@úÓ ®0F~”…8#Z6 ÜÇùèð1í\e‹Ûò¨ö‚2[‘Å3aÏ<ѵöL²B3ÆA¦“;xïQmí‘I·9ì}©¨ ÞÇ_ýæ—dø…DPäRl<Ž£Þ¢ßøËlsñ})@GáäJ„ƒü úæ ‚9íCCÜ=Œ<ák³n3íQ¸ri¡ISúP¢lyh@Æ>TŒðçùŠkwçÖšT“è =¨Nl‘ä‡íëŽ*2ÈrpsI´ž{SJ’9ÇÒŠ&)dÎqúS7Î8æù iü‡½lnåÜ1Þ‘ŒâŒxÚšG¯ ƳvÅ!'Ž)zi1ŽœÑAddãÞÿÛÆ*Fã°ãÚ‘³Œzõ4è,‹'ž´×^jB2: šCéŒÓ‘–ã±®#Ò¤#®qž)9ãŠDÃŒ`œSv‚N*oË#ÚšsÖ&DWò¦íy©XSHí@Ïn6é’v}©¯mà!J²ÙÁt5ÁáÅy«#='«h„†›÷!œÞ­1»p4…6œœsG‘‹Ä½•¢Å¶ëÍ7žjÈŸ–ï•p p3UäbñĪ6òrBv¦ýÚLPäûUÖÑéý©01Éý(ò±<(¦û»69ô®kyü´ Ý(÷²uÆj‹i#•JI‘(4È<â’r0¿J#ÉlþÿjC?„çÖ‹AL©Ú÷4Ö\‘‘E‰ íZC*riØšØAŽ•Ìœ`gÞŠòɆ›°ŽI÷ëE…mã“ߥqCº‰(@ù×lÈ¥=Á´G“ÛÒ•cç•åðÀGZM‡Ž¢‹˜×¶G¸®1 à9¢6:Š@„/J,t Ñ@}1Hb 䎿¥zìdcÓ½ƒm‚2tã½" 9ëŠ(Ä=w–@>±EŠ ¿‡åŠâ™>´HAœàãÒ('ÒŠö2GÖ›´sÁ4NÌ ò=kŠútïE…ì¾ÕÛF)ÇéI°@÷æªèL(Ç\fšS®çEëÇÍŸÇÖ•Ð~ŠÃé\S¯4CGÒ¸ÆzÓ° fN1ÜúÓJ‘ÀïDì'=é:àóEŒ®8#åšâ‡Îh‚ž´Œ¤ð:çµ$Å@Ûž¼RlêqD…ôëI³âqT˜Á¶c'œÿZc!ÈÿS*ûRr?*VM0m¼:b‘£ïŒñÇ4FÀ9#ÿ})6÷è)اÐSvNM´ÐuíMÚëþhüÁ&šS<çš'nlu¤)“è{R dúR4g>ýh¢ŸsÅ1“ø†xªL(nzdóMÛ“E2‚G&šPã¡Ç­ €60FsM(pOZ'Ëîy®dé€y¡±P)O\ÓBqÁÅSŽ)¥q‘Š1_oÖ›°ã8¢Y8ëƒJFNøüéÝ Šã¡¦ìâˆ)Ƥ*vŒ ,( ùÿZfÞqD²ägÊšS<‘‘JÂÊcI´’;Ôå7{ÓH¨NzcÝ£ž1D2üñMÙÏ#: *2i ôÇ4AQß§ZnÑŠƒg=:Sv÷Tæ%[âR1×#¥*>NBœ×Éïp0*Ó¥4 ÇAÒˆ÷+J žôXm@†=@$Ò›tŒÑ{$ýqIŽpSçFæ'vœÓß' £€såœÓ>ñêj­’ÔA>ê3ØW-±ëEýâ.1œŠpš#Œ ôܤNÈ PIàñJ° Òó#WˆõÁçÒ–ù BF8‚þk&06öÅX¨Œ·i¦4<:f…?±ì^ŠÓÉ$ñíKå§#š°ò{ R°½y5[ÈxÀ0ÈÎG½5àF<¨«(Žr>´Ó¾sÒš˜ž2©íÈ'"šb8Ïl`'“ƒQ=·^ «ò¼Ea‹‡›°äçŒU· ~)¯nyãóªSFo+ʱ Þšœä-XýØîéM068¦¦‰xØÓž†‘”Þh#ƒÅ'Ýþu[‘. ( dw®+þ8£¹íŽô©ožœ{¶;ÛÎ:×ÎOJ8[g94ãk9/ÚêÃÆý•ÅW$œsIåŽØÏj²«Çǽ*Ú!à¿#½Ò²°Æ3Žô…rH`›÷EÇ3êhÞƒÆÊÒ£RùôÅXµ ÇâóN‘‘ËàѽP¼l­Xr9Ï)âsƒïó£ãŒ«`HTeN%±IÌ¥ÀÍw–¹¹¤6‘ç¨ü©nCxØòÀÚ@ëÚ—‹ó4kZ&Ü`qê)¦ÙqÓýinCØÁquÚ´†Úrèß»(ÆnqKäväš7~JÙé•ßu„öëHÖqŒ1Ú¬šÜŸæ4ß#çí‘OÉù‹ðU5-€Ê~f£kV û¹k|õŸJl)bvdÓY>$R vç*}¸¦ù3•9½[µ·Z‚H•N2ØéT²YEXŒç$¥!R>jË`çϦ3Qì㪜Žj÷Y~Î:WàðhÖP0j6Œç§|SÜFÚdéÇ9¤*£“š$¦N#&08Î:ÓÜ žH¦„ÿNh“Âx¤ “œryXP3'$“œSJŒƒ¥³>ÕÁ:àbŠJð?>i $ÅšiŒœR»1^“nAŸJ#aÎ8úÒ2LS±´ TbšWÐ{Ñ[0yéI³Ø*7 vàãM#!Á Ñ%8dž@À#8ëF\pH¤1(:{Ù;Sè Ås±³\#¶Î0ÃÞ³þ7Öîô»«{kI &Mß ôÈ5’û4ñü·w—Z7‰5+tÔ¢•ˆŽà‰‚7áaŒc§Ö¹¥«ŒdÓ:!£œã¹Qé¾]°þ/žM/— HWß5Q£x“EÕî&··ºUž)$R®ÖR;ö÷«Ñ<”^yÈ®œyc>S9òbœ;Da"õãÔÓLÿΧ5¯ý´‚Øòp?*¿ù"ßÑÅ#$ ãžøžBàëÏ ®û¶sÎQLky1ðŸÖŠ_brC…ªñ‡ÓŠCOüÁùSZÇb ®)p Îï:d¹~<2î°"£ò®1ž¸éÅNÉ8=ZšPy,¥R²]~HZ;Œä©9¦ùsàŒsDy³M5¤˜õ¦¬—@Â9G; úW2¹ä£px¢„ÓìÕmçˆ4»"ëwªÙÀPübI•Jüý(s®ÁCwVJUû‚2xâ“ âšž ÓÛN]DÞDmdKŒ¯çÒ‚ïÎ cP@8åÏçPµ8å*M_õ4–›$S“OûÝ v#©ùQæF{œP¥Àmü€•ãv)6ûqò£=‚Š]§v0?*-‰DoôùÒ…8Æ:аçhéJ¶äŽ«ÓÖ“˜Ö6ÁÎÐhˆ¤Ùƒ°*oº“Æ3ý««€>ý*\¢Í#.†É>ìp8®B˜øq¶`yS\aažßZž+‚îWÉŲFpGN´ÒF1j’8“ cS‹8 Žsîi6‘I7Ð ,Í(f<b§{" H¨Ú%XQº!¶HÉÉšˆã=I4@ˆÓÒùIבÖÑ4Á6‚ØÉ¤Uíù ÑËo9jTŠ!‘µ¿:Òƒe^ðÏ5¶îÜ„Í]ˆ£ÆE!‰vãö¥å¦? £:ÖÒw_Ê£6ïž#åZqÃcЉ£\e_Ÿ•h²³)`E ¿Ÿ•'Ý™¿ªð(Çã^;b² ã¢+'ÃÙ±çZkZ0ÿ¦zÕÉs‘¶%ÇÊ‘¥”y ô¦²JÁã‰Jm_$„lgÒ™÷fQø•\4òôëPÉ4¬?äâ¯|ˆpRa9ÆÓM17B¿J²yL`TNIƒßš{™1@QîH"“É$gûÑ„ž8ëM#·@J¤Ù;P/‘!±Í5¢m¹Úzã¥Cs†ÈÍ)Œäa‡>ôìI ¼Rðxö£ü¹ÆGçMh¥ÝÓçÅ A´¡éÖ¦Àš<Á)÷TÓŒæ6£pœ@JuàiL;zŠ4ÅŒÒ4Iœ0~)î ¬`ëÜÓJ’1ž*ÀÀ¿ÌùÿÆ»îð•ϘøÊQ¹ÆWl!xþ”Ý™ U·`H0}E µFóT{bÈ^cϽsDܹ«‡`àÆãÖ¤IS£F£åIÏè¥ì«îßÂM7É=×ýjï|Y;cÅ4ùl0TgÜf—‘ý±¯²Ð8çÞ˜GàéV×èpQPr@ÊI`>œÕÆVD ÐBOCßZå„ðxÅSœýi9ïéÐS³0C çŠi„ç%h܃Ûõ¤f9Æ3E²©P ´Ãdà fŽÝŸàâ¾ ;Ü-… ŒŽ:õ¦•ã§£™‡ Ä?*gø0)î±R*HçÌ1Ž”k"ö\SB äŒúñNÅ@a22G'µ&ÎzcåF4KžxùÓ $ ã4[ 1þRyD’pzÑ[ÓUêÚ•”z„&Ò@vÈŽ§·)Þ«~ɯµ­â÷CÕæÚ[c‘ùøOc^^x)dîš=],ÚÇO£æ'Ðümá]rnm¯šl Ý<C'r1Ô{W®xÄ·žµwÖõ9u=&òq÷[Å\Ç#”rpclãá#êþ!ƒJÔ®Ò[¨b,Ùdd`­Ïbâª?øb[=Ü0Ã+NgŠA˜/#é¶Lt>Ôq\ï6H»ÿ£­bÇ(×Ù µ¸ŠâÝ&‰²®¡—§B)ÛušóÏø‡Àþ°Ô-_»ÒäE-“¨)ó-äþToãBxf½ÅÚâÆÞáÐÂÒÆ®Qº©#8?*õ4ùü‘¶#S¦ñˇÀ€’zk‡<•©¶p8¥1ƒÓ¡ö®Ç6Æ IÏ ùSCŸ€óÒŠdÇ\gRy)Œ íBš ]Jr»(zôÏ¥ä¡#ŽJk™ÎÞ)¹¢vH€ÈŒvâ‚Õ¯ôí.ÑŠ“ñ3±xr0?*ñïë>0ѵãá»Ûm,éwsi©É–`¬ÙÚ;C.q“ÛÏŸ4 ®'FŸÉ*™§Ö5»ý[Lž 'Nº´q2Ú]ÌÌOñGR=νy6©öuö§ªÞ›84ía­3ÖæTMç»6?­{ý¥x;ÂvÐYÇ+ë:ÝÊ„X >lò7`ÍÐuè:vèV÷z–£aˆD°Ô$€I|ÈÛ–É8»ãõ=:ù²Í–TäzÐÁ†ÅÉã?fŸd“G7ˆµÓ©­£l–ҳƌ;;ðPµìº•…­¾”«ÑÚR2:qZ/ÙØØØ=®Ÿ†_Ý”úŸrsœûÕg‹WrA¨nlc½k¦ÄüŠRf:¼·ŽQŠàËýÞ2ß‹ô¤6œžF¥O÷v<}+’&RNì^Ò›®Ïb¾£ã‚ Ïza³…¿¬TqÉɤò@ Sž3Ú”BÙÎqÇRÞŠXØÜ·Sã¯áp[¬Gž:Q>A<î¦ý݇Fæ“”F£ }Êp6cæ)®À?§4Q…Žy¤9â–ä7û€ß‘¦y¸üP¸ôÅX˜Ür;t¤òÛñmÍVäFÆW‰Ð“ðÉí\'‹ÕÁ=8£Œ*Ù&*ŽHc#ð‘OtCl?výõéŠO»†? ÷À¢|ˆË` õ¤òÊœ+ð{fý“¾AÔ«``qL’Øã ÏÒ¬¾êÙ˜‹'âj<Œ~8•FGÒ£Ù‚~*¸Ûó·4×X|вã÷eC?'9¥&1É\žø£Þ(HêÒ˜ö黌 µ4Cƒ@$ÂËÂ=3Q´Q6p0hÖ·SØ|úTohü"š’û%ÅýÉl¸àÔ_wê÷£Í«ƒéL6îzíÅZ—äÍÂý}Ør2) ·¸ÑþKgàÓ 1ØœU)‹gà[1?Þ˜ð6î§^ô{Àê™üê'F÷Áý(R¾„ãHÂÝNWåMØùïÇ4yYJU‰ÛŽ:÷÷‰@®Ã9¦íññ´’ÞT8)õ R¸á³ò§¼:+Ùdž8çšLI‡4~á÷§$;—;W#¶(s¡m²·2ŒàœÒ4’Œrxö`öäŒlçúÓ<‹mͶ°–Nç§ý´Âź¢üñF´GsL1½0iÚ `8ÔÛšo#ŒsÛš4½8öâ˜c Îzvª´M0bÄq–üé¬KOéDªfðä×ú¥Òè©oðù¯yJ‘Ø9ùv¯D•vs³lKаå¯Ê°šæ› ’-bÝntýBdPÊI^EsÏ×ÇGT'j½žo…­¼Yqe­<ó}Î)„™â@Ò9 ÐdW£ð7qC¤6ÚTØÆ‰ p‰óÛ:¶Ÿ& lê1vwÿ ‘êäq]˜” ª'ŸšS›·Ðh<`Ó€ÁqŠiÆ"— :þU¥™$(Æz×âùÒm^1ŸÎ”/I#Þ‹ŽÏ·ZìgZUQ?µq ñIðñÏ5Šû`M&óÁ†©ÞGo%Ä-I?— P9ëŠ'íÄÏ¡i‹›¯í+œù ò­jðûYoõ½XÞj×rÝLxÜç ôµDª¹¶ø+þÅ4;ÿ êsë—0Áu¨ýÝÒÉÈÈ‚Vé)Ïâ"½çJñåͽ½½ŒšcCj"?zuýä—Ëqß¡ªŸè‘Ì‹:g¥lÃVòZ¤ãrç‘Æ?J㜣&ÛG¡4’²Óì¯_}O[Öí ­,-åÍ 8ÁÆ0AØ£ñ>LÑü'x>õå׺}æ‡|º–›3C:ÊÈ{zQ^…£ëöþ)ÐÂlŠúÛ‹ˆAåO¨ö5®•f¹ P«»šFEÏl˜€G#4yä=k±3®H J{ô¦´@®(’ƒ/4‚>qFêÄ äŒqŠF·=úûQ[2úWzü©ïdøÐ‘2ôlëMBÌAaŠðßö´ñηáÛ};EѯZÏïªï<‘œ>ÑÐÚ¼Cì×í;ÅÕã’ Ny£fýä¹xäùƒßÜsD[’±¬jèû› G·¥pWÚHo®:W•iÿmº;Ýiÿ´-–ÆÒâ?6y‹4…@€ª2Nr3Ó½jtÏ´ß kz­Œ:Þ§¶¹.FšÝ¢1ÐäŒ09éÖ“Ê¢ùf‹I9+Iš­³9:ã>Ô…$rG½ßш“£åšd‘°ç˵N|ÁÓ|fšI'žŸ*vKHÑ—þ“zc„?pÉ<°ú @™ÎyùÕn'a^#‹9,*S9ÿ˜WÛa÷u98â˜ÖñãG’ı°»§yq\m—´qp>~´Ö`rYj”¤fÔ@·þ´Æ0yÉæ+ÎWò5ÞT%_n*· ÇeiO‡¥!J5¡Ê‚5 8Î2¥5+'kxÀàÒ™åñÍb>Ÿ?ZcEì1U¸ L€óŠi@Gõ¢üµÎ;zŠï.<ã¥=ÂÚ ±qƒÇʘQAÆIŽòá$î-íHÐEŽ {ÒÜ=Œ¢\õý)<ƒûÁùQŸwN}?*ï»GÕœƒFä9+Ì@È9¤0ædm¢ã’}Á¨¼YêÀgžiïA±€ýß#ªþtŸwbO ÷£þìœ6üFЮHÞx¡O€p[bsž”mƒß¥ŸÃ&}8íI±ÿš–æ5zºšãߥ/FÅH·£?Âμ— Ê”B†Ý´ìdÐâéOP>†•nSùZ)¡§N«ÐâœGÄ1Ò¢[„î:Ó¼èÏ®}¨ä>#ñž(NôÑ,}7})Ë$dðØõ¥Èé3•q‘Nø¶l>½=) &:©=)ÙÆð}9¥l)ë0ýãH»„// Ÿ\V‡ìžf›ì÷FlòcÛÿó¥U€¤sÈ?¨¨Éââ-ö+»g\vªo©me†(^é† þç¡=ð:Õˆrn[ž†¨µ9—PÖ<€ÿ¸·ø[Û½\¤¨q(ñk¿²ïê:¾ŸÆ–·ÅsÑF:aƒqùV3ícßh¾ðìZø·Ô’ °l¯,äc=«Ær •=1Ó¥}C2£¢ˆÆÙ+êZf¥{dד² [ḫǦÉþ•ÌÜ`÷} 9*<ÀÿkzF¡ö±«¸ƒQ…Œ0ð eþ ;ýj8þÚ|6ò¬~tQ3~ÌO¯ûiÖ-µ««FÞÓîÂæé™V«õüšóYZæuBù"Ú§{þu›œ³|¢é¦-,â…ˆp<ð{kqöSâ-LqpâiÒb frI?¹äW7íóÂ[ÔìëÉ-,±¼n p}e¯kš~‹’úp„þQ–o¯ñßÛV³a?—¢ø|,9Àšë'?DÈúÕ,ú‡ˆu É.nšÎíÜ’XÈÀùb³~+֠Ѥ·¾»aiqf0‘\üºãÞ»ü­ºGÌþÞ1É•öŸiZ¶µâÁ¯Ã ÈÑ‘¶ù@žÞ½kOáùSÏY™Íx-åü±\A oÞ,ǯ½z†¼V¶Ù5”kQ2+Ç.2„è”80…ú>·û1Š‘ ÆqÞ½Q´Å’×3…ì+篲Ï@DrÛÜ$Ñ``£ {Þ‘âKIlÆéT9ÅsEE7¸ém´¨Êx¯O l@p}kÌ´BmÆQOnäm² <:ž ×¨x»Tµx%òæÝŽØé_9}§k‘Ù ¤I6HçbØÁ&¢¥H$Ϥ£•%eˆå\Sìy§çXŸ²øÅz0i2¬SY¢Ã%³‰vñǨâ´z—ˆ4]>øY_j––×,ž`ŽYB’¾¼×TejÎYE§E–A<šin{b¼íý¢4*i,¼7n·ò!*nfÈ>Àrߥy.±öýã«Ù‡SKdì …~dZ(6#í,ƒ×Ö£º–8bydeDE,ÌÇÞ¾&µûpûB‚@ë®Ë Îq$hÃúV·SûmñŸˆ¼)ªé‘éÌ×VB–Þ2J 3œœ ®~YKªÐEóE'Ûç‰!ûJñÌzn‡?vÒ•ÐݱâBHÏNÙéY=#ìæâK´gÔíQ!Y‹‚.3W^Ò¿giñÄÁ|ã1€êsŸïEx‚ÞIlåòº£ƒNwT °F.k(ÒýžßØx_ÇvV’MgoªÛ©ŠAÉŒ‚@^zgû×®èX´‹Äš©Q{‹b½B:ïL|ŽGÒ¾K··d¾ŠW•’D~Nq³µn|öâË–´ÛQ­¨Šã.\ …}Ÿ]¥Ï PÙ\z>¯ÑõIŒÖq…Ä2Û  äïZ}¾¦²þðΫmáý2çÅŒ¯«¢—ÛÀ±)脆íšÖ•x'5ݢǓ*lùïÕ2áÉ—ý5×d~´›}qÈéSíÁ¦°ŸJì<¼täÓv÷ïS•\vÚ“hçš,(§'ò¢L SóÍ4Ãß™§¾½†ËôÖàžGÓ4Ö·Éà5!QÈùá`œvæžòv~¹ Œã¸¦5¹ãã#=hò¼òHÇ…±<ŒóÒ˜ð°‚~”yUƒúRa‹¯[Ú'ÆŠ³ç•ç>”ÑÊ­X'wÖT9ø—´ÖB^%öUò¹¤"2£á#ëVmr¼Ó$ê{Éñ•…æšÈsëš²xQŽ;‘Ú£ktŽ*¥‘ ãen8äF×¹«l ñHmH'iÏüˆ+JgåHP÷$ °kvÆ{w¦w냊~D/çœvö¥BàðG¥Ð:Ž›ä`tùSܘ©¢#æ1'+HñÈ1)úTžO~iBHâ¤ÙiJ€Ž¯?:h‰=½èÙŽâ™·pè)î} j»hP â£ò˜£J.:{Rùjz£xl²¼£ò œçéJc[¿¥ñ’GéLhóÎ)X¶P F™8br;T~^õ£Z,0Fi†?sÖ«q.<€²|}@¯sûû¸ñ¡©â-5í4…ýá ¯7°=ëÙõö}û7Ö!2¾‘%„äÒR˜§#ô£$íz= ºéFr|!u|öÚtֱ’ù®¤“Õ çüÔÚ¿:K N\4D¢àæ½ûíKý˜5M"ݵ\ͬEñ´Ö²(YUxÁSŸ‹å€kæÍNÒâÞëÉ’) »„•tu*À‚x#é^†8B¸dœ®y5É©ÍRãÑèh´êOköy&Ÿuªi3‰´ûË‹7¬rZ†û@ñÒÜi÷2êÓLö2m˯|cŸZ»Öô Z´&9åKÎÉÎ=q[Í3GÕ|1¤E}`[ÀB´D'q8÷ãµa=|x{O^¡6¥òVŒK}¨}¢kÉçê‘[Æ£’€k=¨É}}¦é²ßÍ5Þ£}r]YØ“±xzdçò¯V}ÃPé‹•f·-sÂÉ!ÜOöëOÒ<ÑøÀEwnGìëEKRGÂÌG'ô?þTñêã;iUßÓ¿lâ®Û+Kgg¦ª¼HS&~7:ƒž1ë^qàßjž'Öí4=5 ×W2ˆ“j’#ÏWo@wbPÈ·ýLã(ÉCìÕý™}‹x£íCý¥§É)æ…ÌqêOʽ{Â_ì™›^ñYeÊZÛóŸfcý«è¿øsNð_ƒtÏÙìòì¡Fcñ1ùš.-J(‚úÈsFLŽø| j+«<ËDÿf¿³->.íoµ&®n09öP*ÃÅ> 𯂾ÍõÛ} KŽÚmI*«–.“É"½7ï±y;¾ÇAï^Eöÿâ;½?@ŠÙäZózy rvpwýïXÉîâÍ#hù¶Í€Cœš’âE c+•a‚(yc)¹”’=©ãnjç&‚L§Ô´-E÷L­¸ŸùˆØ?ZôÏöoðݾâßÚz~ƒq©ÝƘIä Gož¬Xð¦¨üà-_Ä×Hâ3mc»÷—2/öþc_IøgGÒü?¤G§iÈ4f?‰Û¹>æ¡'%^‡<ŠÔ·O2«\82Ðv¦ÃŽø®¸üB”HÃ}s[§Háj݉ÎrrHéHXÿò)sžk'­-ÂÚ79ÏLSyÎqŠx³×Öš)Z ¬kŽžÔ›²qÏJqži¤7>©îÖ cëõņ}iBõ¤<Žh´:bnÒ¸cÔb»iv9Ï\ÑÀéˆT渨éšáž†”Çô¢ÄÒ¼õ¤eëÉ>”ñé´gÖ»‘Ú–æPÏ/9;²M'–Ã!iÙ9Æ:R«{G=7cú޵Û[õýiýyÉö®þ½zQlªD[Xr@&™‡ÆçÒ§$Ý;×ëI°¥öIàÀÍ7Œç?¼úR¹íCbÚ@Ø8¦3€*r½;ñI³#ÒÈY ;⣠6ç§LQqÏAÇZa•I’âFUr8ãåMÙèx©A ‡=i¡FÞ'Ú™4Bcô®1àd“Rí'µ! ãƒïN‘ ‹ÔŒSL'ƒ‘z ã“Mã¦;ѹ… f„P}é­Çàç½A'š@„6ìN 4ç Çô¦˜G\QÅ[8à})öl9§½‹Æ™_äy8÷¦˜³Ñò X2óÀ´›F1·jjl^$Wvv¦<ÅÏéV{FoJaŒ’¹Ôü‚ððWyR{dÓ rc¿õ«#g…ß( Žiù¼%iIrŒ~•nÆJã­Zã¿ÆNÆŸ’Äñ~JÓ•ÏqMÜÝyÆ*Á“ÐToã… ~DG€§Ï‡coz9âRéQ¼)ü§žõJHŒ*FqŸí\ DS®HÅ'”:ï<Ò܇µÐ9ç9¦÷¢¼®sœûRÛv{Q¹kqžA¢hr øh÷Œ œsMòòFTôÉÅ `àŠÖ ùÓJ0ÇéV,‹Ü`jaŠ2r>õ[ÈxÊòOaLnNT|¨öOá#¦}Õ¿™j·"\$W ¬&U9êšU¾e‡/‹?¦+/‘Óö¤ãÃp £wp};V>Ð| àuaƒîs^å»kŽö¸MÄ|]M µ Õ²ÊìÔšDšk²V;´ú>Iÿc'M¿ñ½Å¥ÌAn¼®Ñ¿§QXŸö’ðŸ„5á.œ“}Þ[©¢Ìž„‘ÇҾǰû9Ðl¾Ôcñî–«gpmÝn A„•Û?±ÆsëÖ¾zÿi÷ƒÁ…Ô»[[ãr¬:`¹^>Œ(y¯,d½ã¬Uõÿ¹ãÿc¾#µÓ5)ô}Tºéš’ùr8(ÙX{‚p=hÏXjš/‰ÞYåÛÈ‘Kà–3ÒEö?¡È5æÐäÊ€ aȯGÒüTRÇýßñ-»ÞYƒºÞ@Ûe…ñFݪž iŸËr÷Ù82´¿+¢›ÄÏ{2F¤: Ê6yæ´šêÂ#Ã$Äá—Ú1ØcЇJM‡Qy#›Jº…ºäx˜ÿÚBåIùV£^ñƃ®i–VCÁº5ͱÿŸe##9í’úæ¹'Žã²(ô°ëöO|‹³ë´·ñ=’@÷Nd>ZB±éýkeâï­§Ú%ŒQʯi u9W—'Ìaí’ö±ÖòOáï\x›G±io$ql×@îŽÐ²œ€Oâ¨##…ÔÖKTÕm:ÎçqŽÚ7¸G#üÖQÃÏåÔ<ŽÙô/ìVûBÓ¬ü5µ%„-sçLœK °*:žTŒ×©}Ÿø/Â~ŽX´kádAç]?Å,˜–cïØqÅ|Õöqâ©4?è·sÊE´·knàôPÜgõÏÒ½ãí+\ò|3q% yf¹¹0G‰úäýíZFRQØŽw\ȶ×üw¡£¹7A]a`üð zóÿý¥Ç/—m¤¬³É†Qå.NqÅf´Í;›½zæG–QñAa@ô&¶%–—¤Å²ÆÉ"RåÔ×\4³—28ç«Ç%%ûM¾hþë§¼F»WÌLîwuªýOÂ0ñ%à¼×u(Â혶Ñè¯F[è™°K íÍ8ÜÏ™‘ïZ­2O“ké;²› ou‰dnëASšºÑþμ-a(’H¥¼u9_=þÈb´‚unB«àgŠæ¹R~8Û±ÍZÁú3zŒÙi ék!c ¨0|ªQxÄgp橌È‚{J·²ãxÖ´ØŒ\ö]‹¶ÅëO„t`>]êgÉÈuÇΛ÷“Ô8¡ã ìÐ-ëzšp¾lrO­gÖè1þ”átÁNNFz€x¤ñ¡ïf€_dO"ž·àãž•@·)ŸÇŽ= 8Î¥²%OΡãE¬ì¾ÜsJ/¯õª<À’{FœõÈúõ¥âCòHÑ%ädc=©ßzŒúŠÎùî9êzæ„ÔµxtûG¹»¸H¡^¬çTJ rÙ¦9Jn’äÕM{o –EEKNŽxw,ŠGb |Ñö­ö‹iâ=8èºt·°ÛyÊóL„)/!G\ àý*§Ãiz¦‹‚Ù®$F13†úãÓÄóãN¬úløÏꢥ²¯íŸXR4àËÔy¯ž4ï¶û˜Çüm„n¹ä¦TÿS[Ÿ }§øYÛºkYœà,Üì¥i ÂŘê¿ñí~•9N¿žž}x®#‘TqÞ¶2[ƒR A‡ñ~µÑâg)¤ù.1Ž™çšFÉêMV. Àþ#NÏ Ò—ŽHK$K,qÏZiñ‘A ð=>T¢üuëš[%ô¢Žàb‘‡Læ‡ûò‘K÷¤è ¥¶C¸’¶àtïT%ñVƒáǶ‡XÔ"´{’DJÝ_z|êá®c#©¯‘ÚóYŸPûD´Ó­‹˜¬-;{;ÇôÛQÎåH­ÊÑõN•¯i:¢+iú•­Á=’AŸË­Yƒœξðç‰uÛ5 áÀèX‚GçÍz?†©Q»FÄó'Ž,èO{ì…­ÈPVD|’>œ~”ø§1eû…:=áˆFT¡êeHÄ4ÊÙéÇznbX¾£¹ÛŸY}COŽC#î1Œz œ[]bïÈ=i$¶(ŸòŠŸcš^D)Q$w¦ìÖAîH§µÎžÝlYý²~´,k¼w äT›7DV$.~Ý*M¢’d…ôö'"dÏAj‹ÇZ‡®xzîÖá<×XÙ¢gQ”p8 ö«4 îWÐgýiolÇ|î9¤éª)Ý5økìëÆú¦ªSB³3LÒ}¤Yîl‚]¿þ&¾›[‰²ã×4ñî}—›lh=äìnÝqJ’¼l6º·¨=(¹8'nï‘Æ)é&ñ ŸLÖªôX=Ô›rV28éH$E]·g^êcÁxAü$ àFs™WŽô’Cä9ç=fš³8?òóŸPx¡LŒx?N✷.>ulóÊóóª'hQœòrƒž6‚*qs½@ÝÊõÉëUÂ\•!S|ÅsK•P{ —ÉTXù´0ê;R¬„Œ4©Ó±ª¤“ –‹¿QR3C'_–)4:-‚ÊÙa$nqŒÿZæWë†<᪖ž@xa“ë]÷©J¯ïg±þÕÊ¿H±IfVá$“é_<ý¨øºç_×$´ŠF[vÚˆ:1îO½zgÚV«=‡„ï9€y@ˆ2¶Ý×åÞ¾w³rÿ9'¯5æk²ºÚ²ÿÄtpž$×]ä J´%ÊLÖ­ä1WÇÃK¡Cp‰¶òOÄÜdçh¯%ãN;¬ýZ™,ññÓW~X¤ŠFSŒS5È®íìÕôäû̌܄ |¿*tK)µG– ¡cÕd\IJ1SFñÔã–w§§i_\sÚ~Çü_5ÔCG»´ˆ?pÇ©Ë^—÷ƒjùƒÂ·ÒXë6÷±R’Ÿ­}/jÏso Ò`Ç* ±¯{C¨ß gå_ù¿éÒçŽlJ”»þ¡Ir3Ëcߢàäü_J…„ ð¸ëÖ¡‘îU†T;­w*gÁ¸´— ©§¯€ô†«>ó6y·V¸¢"s ÇÝ׎¼šBWa?y$pON8\ž™ö #~ZÙÁölÒþã)2g¨5.†£$÷d’q_%Þø– WíOV¾Yƒ¤×.ªÌ06ƒ…ÇÐ ú;íú7ÁzÅìnû¢³‘”Îv‘ýëãyÊO1<Övnb9Cƒß5ŨƲܧ “ÆÔÏ¢4Í7ÃÚ‚ú•¬ÊGã*þ|Øx'Fð•ݺÙÚBÒÄÌðüEÈ`2yÏAÇZðÏ÷oQÖìmŒú|¥"02sŽãœW¨ý‹x{UÓ/'’b­o·“½¸ +6æ ž £>µãé4«Ê¿Ôþ¨öµú§â“Ù_L“ý«~µïcQ÷ìùÙ©ìá_}ôw9ϽH/— Exõ¯Úï…eÓ­îÄ¡æòDE˜|ñÇë[ _²Öt¸ïìdß #At-=«]OQ¶[_fÌ^¨ˆç4áy“Õ™ûÚôùSþõÏR>µ›ÂZÎi~õÏPE*\ƒÙx¬Ø¹îšp¹!¿ÏšO ~sFn3ɤóÀêùVx]0ƽp¼çâ§Â5œÑù©Œdç<æ“ÌLuBoœÈüéEñíKÂ?2/ '#p?*ì¦x`j”^ާ:S–ùAì ©ñ1ùb\pIçŒÓJç&ª…à?ÄGÖœ·c.ƒûS~ã¹2'€!÷ŠYެ¨RâO0‘º@ÃåBûý‚&U ÿLÖ’¿L{BfŽ\+)ªA¦6(¢3ÄâGa¶ H’^¦ŽQÛ<Ð¥ÝØºI$€éÒ”¬§ŸŒzÎδï²nbªÿvˆƒÆvæ†ÇæyŒ|9Dw(ǘ /¶Ås:J Ì„×m(¶)ÅW`×^EÌf+ˆ–XÏUc‘úÕ.¥áM:ãXJÖ¤õRw.­^ï·Ã Òãé²,cK6HîzUÊ—dFs‚ᘛŸ ë116ëÚþ›a¿#BÏâ“áÔKJ»YXT) uåˆçå^„¨B‚n œzg«õÝ.Ó^´6Z•º]FÜ~îPkàRá>Œz‡Ñ康ŠaÖÕ …®¢Š6,#¹Ÿy9Çáãç>) ©ÈÒÃå©áO\ß5ôV—ösá•EÅ‹Hð´ï€<þµ¨³mPÒ$Ó[@OºH~ˆ|j˜¹®tž'glg Ÿ+K«"³§ ƒÈ«OÚ7JIÛPXçšú"_öj²ŽÚâhõFêAÌ1-°Cì“Íy–½à¨½ ín-ò„0äÁU¬ñŸDO‹ážm3N³ùŠå 9àñš½ÑÒþòI\ìi%„Ä\6p©Ç÷ õ>ëI»XõvhwcrÄ=«e£]iXÀmÙaþ|U7Çœi_ež•g•ŒV©€#^÷çR΀àwǧʘ. ·˜„|꿵‹L€?eò5àëÎãUIžÓõZúÂ½Ž—¥ÇmjÁc‚<zã$ŸÌšùØkV6ò€n¢F''âUÄ^)Š(Añ*‘Æ\t¬²BR.ŠMºÞ$ŽÞöpò‡T N{Gë_1ý§K÷ŸÝN¯æHÇs0뜓ZË­~çSoºi®çf$¾?v…º’{žœ Ñ}“øK¿Òïõ-zÏöŒÒÜ´JÒ³/áüDïý+\šwìË6H×=_±ý*ëV×ⳌK÷uq5ÑAÆÐzïÓô…õõ¾Ÿi%ÍÓ‹x!MÌíªŠCÑì4+So¤éÖÖ‘’«’[Üž¦¼Çý¡|Mlº#è\!»’Di#CÈ^O>Ý?:éÚáýYÅ<‹+I>ŒÚÚž­¨k޾½šËO‹áB¼4§ùöÔu}s\³Ú:µÍʆ #y \úã¥gòzÖƒÀ÷z%¦¿ ψ¡»¸Ó¢øä‚ߥ#¢’HÀ'©§$Òà¬p‹tþɯ&Ó~Ñ´iíó.VÏB¯ðŸë_\l8Æòâ¾kð^•o⟵Í+mm%þª“ùp¥´{÷ôÒ¾ºñ/€µ&¸†á.-É`H#çF,©º FE'VfvÄîÆ2@¦„/ÃŒþ@Ò­ž¢¥¶…=¿"G¨Dß¼µ”¨ë°Šèm£J'ŸœtÏLñ]æJâŒÔT2IpI“ƒ·ru5 ]Ì?=ò´—!h)®P•!Hs—'4©$a†œPß~ »Š¦áÒ¸]1`H:)Ðn_e‚Ë`v @:\Ó[’¿5|b«ä–#rœã¨¨‹DAlR£e¹–Å oˆ$ÃÔnâ˜Æ"‡rL~GõªÅ”äíšEúÿ­3UÖâÓ4Ùîî®#Š—.Äþ˜îk9ÜWeFJ^‹ ° º¼‘ ï À×>•ç*ûCò$–×FXçpJýá¹LúÞ¼ëí+íëWf†Öæ[[uÈHѰÒûñý+/ˆµ¡bq©dÖ-äšø›ÂNäLÔu=_Qðäÿ´õ'¹7—Š£r±ª)'jެŒìã¿zŽïÄb é12nšX“וYe®y’÷~ò®,¸2I6}èšÝ6—$T݈ðGJŠîçÉ!X¬}j¾j<|PÉôÁ§]ÜÛÞ*£E6ãáÿÃRù.¹Ô~¯‚xÃ5»ûŸ ßÉ †p> Wƒ‘ÖŠ×ïòPÒpGlU—¨éöp¤2Jb#‚]þÕ%Ö©e<›¢óþk)ã•ðGEªÂá9§*ûAZjæí9Ç5ëpý§AỈô^'ŠÒ8“˹S¸ Œá‡Qó¯$Ñnmžò»m‰¨O&m»º¤â§$”#eâÆò΄×<<Ñ´­FþÕÿ…UYs–ÏLu8¯ÿjÿG.« Ùhž¹ý¡°ÆòÃj|©Ÿ…r-œŸ`h¯ /´]Px§PwŒjv¬¶×w$ÜKn,•ÇÖ¾Ÿð'Þ5Ú[ûÈ®çQ¹%T A#¡£5åËt³&ÑìcQÇŠ«³â/}‘} x.o¹i.ާµc{mÁ­äà”cì3ϱ¯vH.-´¸áóf2GRíR¯õ¨ûBÔOû×s Ìì°>Õ¼sYmGT6öòÊX4j¥ŽA®ØEÆ ¾þÏ?4÷ÍF=/GÌv>4¶³ðΣ¢_éÿyÔh«kõÆï‹‰Rõ‘¿½kٌי½Gâ(¾ë®ÞFŠÁ<Ö(ò“‘BÆÍÜsN8â¾KÙ¤ç&ö¿F—À×ßt¸{‰69쾕û=Ao¦H<å̲nŽ%ëŒrß#Å|™n²o ´gØãšõϱÏê3ø»E‚Hf–ÌR çáÚr}qï^†Ÿ4c B^úuJ“©lí>ÀW ‰' GÖ“Çcò~ Ĺ'£dtæœnsZ£YeoÂI®ó§_Å‘ô©ñ–¦^}éýsõ§ýõŽ8ïTîEÏB}ë…ë1çõ¥â¾¼ó“ó§ýðsqT&ûiR›Ì·=)x¬~Eö^ Ä#§éN(GâÿZ£[­ç9Û¿yõ#Š^$?#/~ò§$7Þœ³ãøÿZ¡ûÀ'©ÂsŒf—‰ÊËñ;qñ޵Âà’~!T?xuàIŸ­rÜÈâ©xSÈËó3gœgÖš&%¹ŽÕJ/$ÏÏ¥<]L3‘Å'ˆk#-üåÏçH&ïUKzÝÇ?Ò¸^ñÐ~•>!ùL´·NÛb²8lbßq°vÜ#'•ÜN¥]XµÂ¡=A?*pŸƒÌ‘†;WŠÙ«eFÒy˜dÈ ÷¢á™Ôyr,ÁñðäíÏΪžÛPWV)6ÎzW\­äkæHÒ¨Î>.qSIû”’ºeµåÌògïÊÁÏb3ý(Czª<µIþh^rI\Iü$ñŸjŒSñ4 tªŒ!ÎWÀzÝLo$ɽnHuý²AVGŒ ¤ŒW?ÍE¨—`W"@8ÃsŠRÚT\½’E óH¢¸¾1 ÊŸwo©ØÆ$’DÃ+‚*Ü´.¬ÄÄr0£Š“ö¢]NMür{¡ÀåSò»®Pª¾Hòi@W,}‰â–)g/G¶(¶M-±†ž?pÚ|pÛÉ}Ú[Ö## )Å?"®„±Jû_³[&GsSÏzàŸ&#'5O}Ü-¾h[oMÄS-®å ²¤žnGëObjм’‹©k©øâP”ƒECt$BÉb‘Øuª˜¡¸’Aç[‚3Èü4RÿÃ䤈sŸù¹ôÅL”z]— ˹pÝI¹|ÛdQíÔ|rÆùDóžIRj¥µWG.g‚çHuK†\,ª*9,ñéò\C-ä9kkÉÛB’ëUšÏ†a×®Úo&ñº»°Ã|èEž÷•<Ÿÿ‰H¯|Ò`ÎçÁÍÃk±-B‹º0~(ðÅÕ²¼:…˜’#Àa†Cõ€Ô<)$©:¬ê¤ ð ú׿©ÔU VgPpILŠ«Ôt…‹ÝZǸó¸.ßéP°É>$hõîQgϯàÝ@t¸„ýOø¦êJÀ›ˆÏLŸñ^î¾ÒI>jȾñ½94 3¼DÒ7ýÍÀ¢²ô?.ºL˜ë·¯4ä{WeQìÙ"ª8¥/ä)ê!áȆ<%c¤DÔȽH §ÿ{ÕêB!B‘´ 'à~3] é^Q€_±Î •ôÞ•ëÛ5¤><$a“çËbÍ,¨¿ ¸ãù«æOµxïcñö¦oX´’8doT*6þœ}+é’Úhˆ@v2XœŠÉ}¤x/LñEŠ˜.m!¿Œ*nGÊ{j¤ù²!wgÍrE$G#/ÌTö0Í=À¶ÞS…U,{[Ýw ·Ó,´‹é- ¬I"NŒIbáA;mz'Ø&—¦hÚ푵Ò-ouO7&úéø€zªôçšÃ.}‘|rwa§.ø='ý–þÈnü/£ßx«Äñ¦±ykåÙÛÌ?ä©þoF<|±^Ñes¬jV2è·û –U‘0yÅ^éW6÷¶Þ]´‘Í©YyVa×/Z’ìEmu ˆ£p8ùWr½öuM§ð£çeÔoa˜Ä1 GÅS[PYÙÕvv ¸~”‰#6Úýülޱ­Äp¸ãqÅÃDáã•âaß5ì&š³Âxöº5VZ±•ÀžhéÆAÏÖŽ{‹gR²m ö#"9ÿæ¥ûÚ$j°Ï l|C¨'ëEOѨò´–àÅNÕšf™.vHÉéµÿÍRA}"‚¬¡øá¶hË_¼Ê@[IH#¨Z‰dÇåFÁš|F6O.“*a¼ƒÀqP\iW­ñ(…ÿð8&­-4û×`ò†?µYA¦”É–é v­qfýWK‹¹¯û= ?£ë2õÿF6k[Øø–ÑØ@kÉ¿ÚTk-×KñÍq/˜Cpv.yüÿ¥}3cci5äQ˜)8;ç§Ê¾Kÿj-Eõ?´ ©›!íã T ­}~-[¬nÐóþ™›IÎDy1f,Ä’{ÒWWWiÌZ]C<ÐYª«ÝàqÇSV¾Ó·™ ˆáC`¾•L·÷CÅ<Šª8¸ê{VóÃë}áÙœÊìÀ˜˜à•=×ëýkQ7ŽôzúlqÍ–áÝ.ÿ¡áë_¤«Ø3§ï‰?N+Ó4]'ÂÿwŽhô»7Gç%s^á›Ûxþño¼wÀGʽ Kðî½Ùâk)¨O¼¶ÕƒfA ýkÆÔ¨É)FgÑèå8Ü'Õl¼7öyzÁ¯4>C· r§¿^+ ö›öK¢ÛYOw ™"R¥áø·+Oy妛¯OªyÐ\@×øe‘˜~uê~Ôõ;îÓÄkåG&dm¸DÄ$^¿–{ÖNñÖÙòlœ§&œx>r¹Ò%¶½OÞ0ËpRsZOy“ê8À;#DÏ®dþtGˆaµ(ŽÞ;¨¤EvmÈr¤uü¨ ©ÖIÚg9üG+Ôò9´ÿ‡›æ”_¥ÿ_ýš²?k~7×giR¥º!S=ö5Ï9ÉÁ¯eµû?Õlµ»{é¼Ye«%¾øÂFXaðãÿž+Eö-cqá¿°y|I¡[Ú¦¢Uæ’Y—;ðÀÇ¢ô÷Ímö]㌘µ‹V%ÙÈ`I?Ïç\š¼™âÓÃg_éRıÊf£Ç\óß>€áÑ®‡Ä·‘Ø5ͤêEò$IOf. ZŸ²ßùzê¶F@‡t`° ÎG5·þÑí pöÖ·{zm¸çŠÇ÷ÿ©Ç—ÿà·ú7èòU¿çÿr÷ì¯@3ëÒÜêQ-z)<;gž+qã1q.¨Og‰I·ÊFG‡ð‘èyZñûI|i§HRó@Ôãd\3$Lã8ë•;6Öm^$ŸïÑLvæ7Fé߃J¬dj²ãkú¿ñèÅÞ ‰£[/‡mõoéÖ ß¹H»TލW+ù>•¤ðÅ«ÙOäªb 0=H¯8ÿ|5_jO0ÊïWx©bÕüAtTAm©¸nNÈÛ§’ýZ)Ü`ÙRý%T¦’(|uêlÿû†9ížõç?h7òYØ¥°psÎ=+Ñ5OÁ¤-óë(Ö×cm¼¿ó_'–ÇaŽyë^CãÝe¼K¯I¨c·ŽAû˜¤j1ó#'ó¯_G­Ë¨‡ÊQãjÿLǦÉj{™å4ÑžæÔj.eˆbE×Ö²Zk[,Ù».Tt Þ½UÖMãëíTwÞ²¿—|­¤cñ*ôü«¶ø³&=ß%Ø€<3uâïXx{HˆÉ5äÃôEêÌ}€ÉúWÚž2Ð<7à éÚ†´ëKIP†žHÓHBãs7RO&©?ÙƒìòÃÂ^ —İZFúØaÄ͹Â0:`dv üS¨]\_3]·™;1g'±'|¸¥»"‰ÌMØ2ê|ä°$uϸj«îgsý?Zªšàž‹°þTÏ0íâ~ݯCj~%ÎIö\›â~$U^¹¨šã{TàÕA¹`ÅwïƒH·w?=ŸD¼¿eÌ—e”yFb)­0~^gÇºŠ­Gš@BØçý³ŽLN§ØR¤4äù ã3D1 ÌÀõ‰pí€êsë´Ð%¥…o¨¦‹‰W¨äÐ’)Éû.bmçi#¸jï-Cq+ôL.G#ŸŸJå¸<Æ ùÔíeo‹à¸0HÃp™qèš 9Æøºäðj Ü'TŒÝšd— F7²¨íœâ…}‰ÎÑ¡òâÛúaêB$8In9Wñµ¦`¸çáÍ+ÌáI†çpôÉ’‹^Êݺ rÁùW^OzA)ï; t¦-ä¨óXúår?J}´É#$(ÌxÎM7&•‰AK¦/™–ɻ֚ìÇ8ÆŠ+ \I¨é¹£‰”ÙÈê5 *ô[Ó¾™N1޽iÈ œ+¨5#…`6ìSî”õµÜwo^?”‘WåD=;²²¯uüéÀHFr§žÄTψ &ò@à5 KƒÖÛO<íÏô¦²Y/ \Xã+Ž|ÐÔ?zàÁëQÜE<`m @ÇBE5™€•À?÷ƒÍ=˲$ÉþôÜ=}é~òÿ—zm NÙÏ\WbÜJG®E;A²AÂï9þôõ¹ÿ¸ŽÜÕy ¯Á*6=:ÔeÜ|G?ÖŠLtÑj/ó㎔¦ó—óªV“v4»óÎÿÒ…D¹JÁ`‚Æ­ û”çúÑBy•b#ŸÅVòÉjmö-òÉÃ7!€¦¹²†(di¡ Ä‘ÃmolƒÅyï#}£ÖŽ5˜ I,ª—\A =}ë–ãMb3¨ÜpyYìÒÏv–÷Æ{i#+ûÂ?µ%•ï—\Ãom?ð°Qø~Tù~ƒ‹ì%®ôSßTö¾ÓZ8f— x&†¸Õ¢‘‹¶—Iä®7VóñéÈ®9PÙ\‘èjvûvSñÁ ú„bHb‡8;”ã:fØ|¿0]Æ9RpÖ™* ²^L[3`ê3QO¥$scï1º(à“ÚµŠFwt÷yåbb¸Az3àÒ“±˜s‚̵4¶M¿t 㑚ŠT–"Æepz€ É­¢ÓâÌ%扢3)æÂ«Œà¶) šþÖA,$:g¨…¿Í ';Hòdhÿ‹#š—ïVQÆŠé®áŒÒªà¤øNè°›X¾™JýÚ"1Ê‚(TÜÎ?àv“ÎÍ>Þî#û¢îaUÈÝD5Æ g˜KQÆÅÖw·„‹þNÛ!‘¯ƒ 1J±ô;FJ"->ÊTËêkÎ20ËUñ\]HÄÂ%S»*|Ëi#œCµ×QOžÈ.¢û¬˜Årž¡­H—–¸p²û ùR"È!¯µ$ÆÚ‰-@=zÿŠ«¾;#c\®¡¸Y‡—.–èvŸýÅ s%¬ ……áq×/‚Ektá†ÙÀÇ^OëK}nf‹eÌh@±<­eº¥É³†èü_ p]ágeçe"Š’uBæŽMØ9ßåUw6î$.O`2E m'b—>èkjƒæÎW<á£Föéä³»cñ½G,Ð{-·‡‰ã—‰Jãôª©-¥Q–VQÛŠf×·&í£ÔSQ_d¼®ÿ‰y+iàa’1Ÿäoô¨®$ÓË&ô$¾ªÖ]G™[ù»ÑÐG¥Íå…žXÛ¸u¢¶÷eîÞéQ’øeËè­íM–K\f4u=·6µ[ˤB^)¼À@8 œzr(;­*x•dÚc€0A:k,²%ƒ"ôæ!À Ÿ™¦»ÃÓÐÑãF»*Çly·ç¶Ö,&h™¸Î9 ~¾”ÞH®˜–·Ê3~*&]( ¹Ù c‘×·÷©¾ÉôtÖ5©-¤¿k[päŽ<“/<.ßϓҭuؤ¹ÓÞÔEñÆÜÖCÂúî£ámdÞiÓ¼.AðܾœçÒ¸u Iž’áìû7@›O³ÒÖ;G„¢ 3Àö£í6ÝN²8ÊôÞ¼+À'Ôu Ôk¶fø€–ÏËʽ³E¹-o½#-ŒQÜ×4%é3O²]sÂZV¯k47±+3~ •vȾŸë^7®éºN“ª\é—Vªó[‘–$ÀŒ‚>•ô N„¢“ñ8È© èú©2ÞØÃ+ãir¼‘èOzn›&h%†n-þŸªÅ§ÈÞhnLùïËð̪F#¡ EL#Ðj¬pï9=1^¹{àO ˆdСž<Œ1)î9éSéþð|J·:%”‹êWy,çò¯-h5χ•žËýKôÅÊÅþâï¬ÙÅpÖÖöÊî¤0òÝF«kx|Oƒ§èäÈ2Bc›`W·¥–ÌÛÛ[Å  ˆ€ÇúT ªýÍ•oÊ@vÈßý2z7þ'¦{U/ÑêälRÿÈ"•aÄ—õ<²ÃÁ~4½%çK[%?Ã$¥™~€zÐY}˜ÍËßkÒ¸'•Šœ|É5èsd:ʇƒ×½:‘â k³èúXw8s~¿¬ÉüZôFwJðŽ‘¤¹š1,Ò Æù[qÿ¿;>Û%kzæl¿|˜‘cé_¤º½Ê[ZË+£Iì5ù¡ö¡ ’ëŒrÛÿ2ÕÝ¥ÃÚ‚£ÊÔê2åW’VaOZCRùy>w–Þ_ócŠŽ½p…Z"\Oo!DèíÂ3þµèÖñýÖÎ ¨ØNî„{Öoš`Ø$™2fFà÷a¥ÎËe,n‚2ÊäsŒ×±|Qéþ›/õ–fðÝ_Ãg¯î˜;°”°>¾ŽÐü™~Ρ¶e]d`d¯LùBÂ/6ð[H&?.ÍÞÙõ¯Xû>ÖšÆ ¾+Ö/#´ˆb+hS!ò:–8öäk0ÔUú~¦3“Œ»//4­FÝ£ÔEø$PÂê ûc®W*M=¡¹Ó­.æØºlPÍs$rŠ@Š~3í¸Íö1ã Û=nûA‚[‹35»È¤\œpzV“Tñއ{ãí#ÃPϦÉ5ÔÁ.äºaäGn>&FìK;æ¸|SsÚ—'N£QÁßù€_¤š¥ÍÆá²8ÈSîx¢m®#‘JÊÊ@@ÝÆ~TOÚ^ƒw£xßÄ6v6òKem|ùž1PÇn1ÂŽ}kcögàkxbïWžîv’ ],±ln8c’¤ñÇLú ìPR>EÊskÕÿÙõwض›³þÏVóü¹.t¯‰³Ê³nÃ~cô¢~˵Ûô}kE×%?}µ’(òÜn“õ ×ë^cþÊÞ+’MÚ$×áÓe‚Wcÿ÷ÖãÆÎmu]^¶¾¡j±ÊGñÉýéY9SLI*qg¬µú›^äç°©tÝB9-Ea†äsÚ¼/Æž7“Lðó,r>î_"0@Xþ\}EUiŸi×V:Lª™®æøcV8_¯µiòŒeUH‹¸‚Ì I4ĸ¶œPŽ;ƒ_)øûÆ^1¶»† ­X+º LP "ƒøG©5iáO¶ ÛKo/TzÆœ2ŸÄ}*íµtJtÏñŠ|?áM5µZX£ 0Šª ¹ôQ^ãOö¼HeµÒtˆ¬ÅÇî­äi K’+ãÿßø³TkËÆ"%â³ÂóX;«t¸ÔášC¸Æß—ÿQÇ.Q/+L/_ÕîumoTšògšiBîÄœgž¿J”±Ù‘ø†Ò§éŠ­ÔbjI>0î¤ù†Ž FN1Tâ”i²ÊNØÙ¶Ê  ÎHÏC[¿±ÍI×µ‰­µIg/ïHã¨õgÎ|ëTÍj<d}`X[Z¤ÓÜí]îǠ䜿ZÉôUógÔ scáÿ´{‰lã]±<(ôÏsï^-«Þ[ßêS]Ù7¹ c8ªÇ]Õ˜¬О+UØAPCç¥V¼šC¯ï!HÜ(#ô·ÓÅÇäÑ隟Å4:ÖKé:;ö?ÓDPG)$%^¿ŒþµI1²7–’àæ üJcÜ¿ùêp¾S9U)2üØDr)c¥2?:oÜlA;¥ÇÖª¢¼žËO³Ñd4ù5i|bF÷`ÿjiI¥ s×ü kfRä©Ç©*Ù¹ Ç}Žxæ¨ßPb0¨¼ŽùÞŸoz\…u˜žŸÿšºûF7Ï »0ß`ª\«çœçšŠXµ!ÉÚß5ómÔ“#ÝDÞéŸïNKЭº;ä8þpF~•5›šíÿ’I$½RD–‘ž:˜¡&w,XÄ©Ï@¤TçV›,D¨Å{)©$ƒ,!?1T¢—Fr›|0Rûzp}A®SœãŸ­&&~ì‡Ô«T.Ñœo´öæ«ð [鑇pBí9÷¥ýæ3°öÿ¥”;yŸˆ‡ÉúUGtÌ¥žÿ”lÔGËáooüóR¬w*Ãt¡×Ѐk" «nÃnìh”Ô.”‚rØïÏ5NôÉŒáþèѤܨž(Š{­@Óiyø‘”çø[5S­0À*Çž™?Þ¦ý© <¬:‚£æ»EÔR §9;YÔc?dSDvÛÉKˆ6÷ 1C‹‰&ðûî u¨Œ÷«[Âßý¸¡2œiwþ †ÜU 9ÍMòù"ÿþ‚«êo3>R*žSÉF䬟þB¬jßÿ@i ²*ùŒ=9§ýÊFPMÛàvÅVû”<à+dFùÜE¦ó ´ã¿Ë5r}š%¿ù&šJ ã®ìSí­o¡“r¢uø—# )°Y@¯}ÿœò1ÛÛš‚êÅÖéþí8xóð“ ~uß'K¿ä¶Õnš …y!\>€yqUíšùƒÐ1⥷¶¸yÞÚ91“*äzõ¢G¿ua‰”õÅÇZ•(ÉÔçÌQÜ’å"V Kà\ŽMOop#Œ›‹xnÜÀö#Þš,g·IaºŒŒ\dŸQŠ­¹·6áí(M>’ï°ãqoZ³,¿1Ê2¿¥§Ëm,[fj: `{ÕD69s¶mçfsGG Ì0mk2à3&p(œ—ØA?}Þ%œoÃw¸“•\©ô©í­lšó>7Qëý«=y%ûJ Bœ )H€þ•6— •»…ÉoÂëVœ£ñ»dùSAWO§«”AaøŽ1ƒB A¸+ Vó Óï.4¨æx®-î÷gâÜEV]MbeýÔ2ì`ÕAYgO†‹¤»š×¥½¼c¸iE[X^ØJƒïSFƒ•V cò‘¡rŒ1ž¤ ’Êg²“Ï‚8¦B1—@Ãý Lñ'ýG KOŽÂ\ø}Q¿ynqü;FMuÙÑ|¸äSšàýH¬pÖ®I$En™8„tÿ4’^NБ |±Ò³Zy'vhõQj¨ÙÙK¥o_*òØ~"]@4eÅìo›[9]ý@2ßäWšÉl²fK2Î;«u/ZbÚ]¹ÂÀÜ{VôÑ—.D~îQáDØÝêzÒF÷PØÙ$iÌhH|[«ciH¤ùö¬ð{Ë6ä<ìpJšÑéÚ¥¤¶ù‡N€] ÎÂq»ÜŠ%Ž1_Å2#’SÉ¢9r1B¬¹íÍ(¹ºŒ«ÚGqM¨ËУ9EݳD×P*˜™Wð;Ö3ÇZé—±NcÛ ã'œínã?­\ˬ^#w+Œ`ƒPjWSêvmpw!Á‰;OlW4±I¸óÅv¹4ÿgúEÊiöZŽ«{_$e™Èÿ»°îš¦ >c.(ÀØz3Ÿ—½|³áÏ_hNÚeíÅÂÙä²*sµ¿˜ àüÍzÿ€|D5‰kHnwF§¡ÿ¸úW´ÏC‰.Ušê{wIf“¨$ä…ZxgX‹SÒåvŠHÌRy.®0Iàçò Ö+UÕÏC½¹ó Ž#Æüõ,BƒòÉ |7â ¨ÓS…N©²0Äî`"¿-¤ÓŽGK‚’=5n$š9Ø2ðMžÇ oz ôZ›€m¯Æù³´ðÊGb;üÇ5çfÿhözýѵIÂêL²GàHNxôÈ>µŸ¶ñÞ’5KŸøÍ\Ù³‘ky.CÄs±‚½{sZ9¡Éêqx®}Xhú°M;Rqû‘+~æãݿ˭.³â"Ð E.ž[*¯2~í½@~„{ùí/Q×t‹¹¼7}©þÓÓƒ‰ì¦‘ÄŒ³+õõSü/ö¡âK{/Ø—Ð {M‘v}ÚåK°ŠÝ:•llö]oǧÁ2ÛÏç.«á‹†Ûñ6çµ?Ê}WÓ½O'Úgªi÷°ÞE.•«‰"žeì}2§ô5óžµ§ê¥æ6u垟q‡û´’ƒŽzuçZº¾lÍ ŠxíüÁ"§8G÷£dšA¾)ò}Oö¯âµð åòH9ŠHÁ»!õ"¿?¾Ðç ªy ôšö¯x£ÄMàû}S¢+›W…ê/–vwI±ãh<Öšxµ&Ù†fšTW‰—NT*¸`cÝŽvƒ»2ÊÜ\ÜÛD7¾Ööæ7-pg‚y#xÕáGBÛŽÝqÓµáðN±l@'“ŠìG;=ÆÐm.Ò¢³r<–>%žÅÔ¤$pyⶱØQÔd©Èª´4ÜZE©Ú‚%ƒ®:•ëúË$T¸fØ2Ï|+cf©9ѭ✅Ú"[ólãé^1ö]ö‘¤@¶¥ê½žGʽORûoDÒ65ˆŽ`˜ÞÃ.µóÚ¼z‡'ìôšÍòf¶ËùS$ªƒ°†Ü6ŒsüF»3⎠»81f“ÈœÝѺûkï }² "ýw-gq!l«³G”ÁØ#®kèßÜA6—áH€ µ ‘ü  Í|™ª_ÛËã ½­•Þ›%«ÇfÖ÷ ÊÑà‚:œíø°3ίwûVÔ&‚;M¶fYDR Ô;N=ø®iFOjöÍSI¿£ÎõíoöÞ¹<‘9û³:BOBÄåèEy¨‹¸]dVê!ŒpSîO5ôŸÙïÙaá f²‰5Y"Y$ûÂU'¸õéRjþiZ_ Z]äae…â\ÙóæÀøƒkðuéð`ΩÍ&|Ýâ½eõ›äºdÚÉ D=ð:Õ#3·’kÞ®~Ïü>©$v—ö3¨É…dÙ‚}Å7@û$ðõí°·¼[È®\–G08ç;OtέF/Ôá6 “Oè×'é“„\í4 vÈ>œ{ÐðDMÍ×9ËÇÒ·^)ð¶‹g¯ÝÚiwwMk …¤Á,G|Õû½2ÊÒZÜDÄ·*çñŠõ£¾®RǺ¬¥¸Ùp¬¬HØÙ?ÍAB„“á~ÍZ¼/«Ix<´–?¨®‹Ã×çÏž“ñg#üÓIËÐ9F<ÙH¨W$õÇÔÖ·ì侟5Ö¨«‰LF+rÜ|G©ú }¦ƒj¬›¥óW#húUŸÜå@b@ª06ñZÇNîÙÏ=\j¢9­õˆË䇜à}µÍÄ~a!à÷¨GÞaB°ÿæ’V¹xÕá€.:œõúVÏrG7Ãß!‹¤Êχd =Íen%RzŒP¶ºÔ«²k#¿¹ã4¯­BåŠÈPÀÚxþµŒžSh­:Vû%šÎñ1²ûpôbTвÅpP+Âò ÂÛªxõ˜@ï(ǸØiŸ¶•+“ü[qúÓŒ¦»CpÂú`R£ëæÆGfÖ‰IÊË}:UÌr¼èy+ÐdnÞ£º³ècaŽª›OéT³ýôÜ|J‰" >L1ÉŽXýElãÆ|ÉG¾ oÜä*Â;ˆÛˆÛýkE•½<¾Šæ‚¿•KÐ*bâ þe8§\[\F~$ÉcÁ*Žæ)aeõŽqV¤¤gãpwA1Ï`èî¦Ó#üT¯{>p·‘Ìf_ò*¤Bθ œv÷K€ (뎙SR㱬“ôƒe½¸…ò$@’ªçNƒT˜^23œZðÌG¨Å0¤ŠA+»Þ«d(^\‰—ê¢u 2ôî„ dw§á™ºÿ`Õ9vC.½p˜`€£,Óñ%Ðyäß&/¡ †˜6OýÀÖûJ8É%æÛÛcƒýEgLªG<Þž$¶1Á÷zäb–ÊöTý#D5X±ÍÔËÆèÁÏåN‹U„uºˆû²‘Y¢YŽAã>½+‰ç•úæžÏÈ·«èÕ~ÒŒ‚K@üs‡ëùÓ–âÞeøaÝ“ÐsYˆ˜ ²ÜmõÈ?Ú§Žÿ‚înH#ó mí—¥Òÿ%Ün¯±¢U>Œ1OHíÏc9ô5L,.Z?ùÈîI¥wª¸óS¯sÒ–ø•⟫/b·€BAõ®{h‰ÎæçYÇ–êÝþ)mÍKûBîV#'=€5i'É Nµ ‰(]Ép¬½ŠñO87wýÉË9¥Uý ón Á$õ-€(ËV¹´¾ØÈÆy¨¸Äzõ¦+œpyk¥`OÙÆól};,®n¢¼ˆ¸íƒ ø_ “íÅ s˜ñâ,FÙêçó¡H9&†ÛÆrqWäK¶fñ¹u’-F[oùEˆî dUŒ:êÃY‚qÈÜ0hOM]<•œÌ;IŒŸ_j¨yoÝHÿ#Z(G"³'9âàÓKâ( XFÙM2F™Oßçô¬ÜR38,ûÇò’E­jW>_ ~ÄÒx ¸ Ži¾l7ÄWV¿j‰%¯ÝçOÁ*1óÇQGøOÄŽ‹¥¦0 f\ƒum ™ž~.…†{góªxcµ—…ˆôÉŸóS¢[U7¯®kàƒá8õ9eó¨ý¦<¹T«Ÿ²§­É‡ ‹“¯£eÙ<ÐO}ÝÍo{‚ ´ ÝÎ8¨å²·~Fõ#¾i`¶@qê+ÓxmBÔr±$Cöê€Xc Š,ë^Áÿ§Ú^7’wïB Á<⣎ªÙ9¬ž2Öª¤‚¹à“ðƒÓõ¤{»ÈP'¹sÆpH©Í¤\…vCì)Á? èqšÑBKÙ›Ëè-'Y¬ãu˜oîø¨XJÝž}qšM9Ê(ŽAœòH¨…µâ67¶sžâ®-£9F2|Éo)ÎåÝš‚âÙWBŒzõ9¢ìa»FÝ-ÇøIÍÛNxf“{¸ pVÙ›|ànÎ=¦* «V£„ç1¡íÈdžncLúàS¦…½2næLuR=\ZµÐ<É!…¨™tØ$å~3Å úV2\|ÍKÆŸh¸æq|0©5Û·@@Tg%¨Ž£w(#̃œrSiþ”;iÓ %ýi’YÞE?\Tx£‘·î'/a%Ú ¬HG<2ÿz†MEår$Î0Î()TÇ/=H⛼.îO½ (o$º, -™@e'œv§G:clÒ ôV Uvý߉ºý+·@'š6‹ÐKNÍ&öfcž§¯5ÓJ ðàuÂЦQÈ¥óÆ}iÒ'u’ˆr}³L’%ÉH=ù®Kq“šk:ä|@Ÿ•;®‰ÚŽòWi;úqŽ´Åˆ~!ϨÅH¬°HÇ^”íËŒcÛ"«sBØ™Âêz¯Ì7Zã$èI>Äf¤.F=)I!·9ÉëŠ[¾Æ±ý™‰<¢Žý1Lóä-z–Ü=BãŠo”ˆH÷zqFä&ýƒ OÀÌ¿#Šu •\œsšd¨8 ‚;fšÐ¯ðü°M;‹ìJ9#Ó,"¼‚h13âO\gú×[$¢ŒN}½ºUK£¡À]Ùî)9^™ãߥ-‹Ó+Í/÷#O Ìê ‘–lz5O¶G>d{Uùd‘r?Ò²Éw<| [­9/%ß–9Ï5“ÂÍ㩊/æ±´’]°I$FFùȦ7YL,sÌËŽ ¹ÅT-êçâÇ|Ñ1j`Ûrê=7Q²hk&9¢û‡ ÐŒb¢?–Ï®3š™£Œ«)*="[¦>%Ýò=«ÇÜsk"k™#a¹Ó¯ZVU”eÈ9ëÎhµ·‡!б¿Òq5½³’Ìa±oÔ¯¢Z¥ÉZ¶öVÜ NOÒªïá¿¶b¦6¼‚Ìœ·³Ç=ÇðÛÓáàüðhô¹ºŒ4ÄÇäH»F×ÜTô<ýk¡\'+’—àÊ B+w]°‰8V#zë6òçï¶È{m þ”·q,š“²8†eÁGŠ2Túãõ­V‹áó®Z}ÖxÙoJ“ç`2Ÿî+Iä‚«F0ŒÝÓ2FûM ßä¶sÃ>U¿%ÝT$œˆ®Ü|«Y?…B_8„© u8öªm{E‚ÒÒ Çp® nYFð=ÀþõQɺ–T­Øêî¬ÊmÙ£HnjÃtr[I9há+’É/ü½jŽ-±« \³õbÔÌ>ð¬ÄñŒî9Ï­^ÕºãÁ›”œj\‡3*ùL˜jï02‚½Î*šh§G H¤õ½er!ŠD[`ó1Æãñ–+¯ÊÒ8<1nƒþ%䂸¤Ý‚x,Ñ_ÜÛGâòFÓÏÖ‚1ÜÅ‘žLó¡gàoKÏìÛNÐÒ÷9ô ZÛS9À8þaDi±Ý+”¸£nâN”Þj戎Ý0€ðªMXi"x' (#ÌBÚXt]™ÃÝÒ‡ý—/–Z0Ü®ìnŠçž¡Mm:ñé^))}•­…Ú3I:£†ÎKäf¨’Ö$›c±ÛœoEÈëM6³‰”EŠÇ È Óã’óxda.q°Œb¢)ÅReNQ›·In­¼–wºúqŸ¥@¬ëð”?¡îhÙ Ôb·7,  d‚Ã8õ ã¹¼VgD ‘ÉÙŸëT›¢$¢™42Êr(„òI«-#Q¼²“0—ÇuPH`§ÒªâžöWȘäõÇåFDoÎŽgîs×Ú¢jÕ3\n¢éuÝDÉçXÊ­"ŠÚbIÀôä~´Ù;ÖšÑ2ùP^{b¢XÛI2¡%oi§—TûÄW [7²|d g§ôJ3Ǒܛ-1¤ ÆmÆzOÈ ÉÚÉåH®½¹Å[ëZ¼ÚŒ6ðÈG—8ã©=°§í\{ö¦ 1¥ŒfXŽñòî+Í@'µ{f¨ ryò"G·’ǼbáÎè’ r£oqë]åvŽyªälrX2žsœv­Ì6ñV¹àm/ìÖбŽá™#‰>9K1lP ©Ñü«ß^AEŒÊ9À=2ô­‡ÛO„tß³mSO±ÑµIn/&¶HçÃ.#·==¨œ¢Úl¬jI_£Ò?Ø[ñj>.Õ5ËèüäÒbE¶bO± ¢î¯³'¹òóñb¾Wÿeí{Gð·ÙêÚÏ2[Ý\Ln.7 q… æMm<[öšoÛiSÑÆ×˜¶â?½sɶé#GI+a_l^>’ââ] IÑ+s2wÿ´zò9g¸Y¤»øç"¤w²—s,î®O&UÎî}GJQbÒãÉžÞ_ü[ü×F:ÆqäO)ߦäÆsÐbš/Ý3•Sò8Å>‘r ”e\®H'¿qÅucqo™"ÆGBU†sò­£™?g<´òh°ŠýHÁµ"ßDOB9ÅPy²FJß~¹=Ï­Z”ˆÙ|ÿz„œžiÞjîÆsJέÑK瀒–gƒOÈ×¢<1û/ŒƒoW;r*‰f”€êÌ«œrjYfš5>UÊÉô¦²¯dþßé–ûÏb)|ÎãóªÔ.Ã|Ap}V‹[É‚—hЯBCô«ß)¾‹Ràúç5ÛøÈìj»öº¬ØÏÔT‘ÜÃ.r«@y¡4-’O ÂÇ8®-‘ýjn9#üSwÓü‘ýBKŽ{×>¹õÅ » ¥Ü3ÇóC‡!‡<Œ÷E Š%ÇÊ›æz’?¥vóÓ8¥CMú#–ÎÑÀÌ@c¸8¡ßL‹'lŽ¿Z,?sK¼b•"·Kì®—N—#˘c<äTmaqÝ”Œ|ªÏ°£j‘•&Öì1 ÀŽÆ¡û½À&'°«ÂÄô›óÏ|Q´<¬¡uš8÷4r ŒH$ldÆùíÅ_³óMøOP(ÚW¤ûÊç {ŠrÜ`7ÕlR2y>x¦`#þRý*\ Y‘RnÊó» ÷ûT‚ñœd8ã¶(Ùlmdÿ#Ú¡m.Ø„‘õ¡Àk/##¹ òúæžÁ7wTRi§ªL~F…šÂî1ðãØÔì4ò…«.âvuÅ5²I Á櫋΃ »¤‹â^³×ŒQAºý4g¯Ÿ ;Gø² þTª[»=©Äþèù„}OjjTKŠc|Ñ‘•<üªxžÜ Ê Õ{Ì¥ÎÔÊûӃŎŒ=³M«3èÞÃâ%Hó5µ´²ùÏ×°©5­`Ú¬r=€Š7Ìcá<ð:õÅb¦¿†L*ÁÉ=Kæºo¼ÊP5ÚÈáY¿ùW›ûx®Ïeê[þ&вù›­Ø¡ÁNØùÔÑxª½KRØïÈÏåY¨ …÷´·Çj‹ Ç>”t/¥[21æ”8ÉçÖ‰b‚ô(åÊû’¢Þ-J[é 1ZM ‡e@@î =¢Ù¬÷sqð…ÛŸÌUÕÇ^Jªf–ßPyÄ ÇЙµ›„—\©Á¾]²Ø%½²&u/Œ¾ç _ŠuVXÑÃÍ+WjŽO½+ÅnÞd‹Îæ(äªÝH›°Ç¥8Á¾Xå’1ᾡyk|.Ö >îê7£ãÑ'ÅÇ•.‘¦y¿‡Í‰y*}ùÍV¬ÖÆÛ]?;Ii1º™7ìáØ­äŽE? $ŸzÑ%ÓG<¯¸È1õH&IQ¥ŽÜÈÅ—)ÙžÙôüª³b¾bK¡NY”ã>Ø®xmdÞfB •Èý)±¥‚|-3³v# ñZ*Fm[å¢1¢íyFsÕr)‹²ž¤­°Ìò‡ŒdޤŒQKk’ƒ¶\§ ùbµy ‘’Å9>(„K:¦òûÿ*$­ØHåQ¼oñ½HúPÓÊ7˜r®‚HÞ8<’CeG¶+76ú-B+°ûëyb†)â‹|RöÝñ!ô"…|íò3“€?•A#,ç9Iîh›{‰f$"ÌH9ô!½hSÈ—d¼xäþ–þx÷.ö z©éFé„2J"º‰Kð¾züêÅ[§R!‘oIæÏÇß>ÇÚhš?ŠE Ÿ¥&”×=‰JXßv„bÐÓŽœŠƒSû¥å°F¸ȧp+'9÷õ¬º<˜?LsùÓ[ΉK2²ƒê:ÖK NìÞZ”Õm m-dPRK‰±È?Zl–F(öùrõà–¤²½»·P/9SŽ•;™n[{\8Ry qZ\Óå™%¸\€­³Œƒ ؃š¸ÓõÝFÊ#lŒvÂÍÉZ†Õ$‡ ³FÆy§ËJy˜+¸A‘JRRâEB<Å–6¾&ñòˆá[YŒÇž3Üv£tûÏ™b³·)6@ÈÎ^*ŠÒ9ldvzƒ¬ƒ*ì£iÁâ˜gºŠV’ùŽsÐßûïY4›ø¤hœ—òl½¼¹ñNãç[Åå`zg'­VÍa%Õ±/§¤SŒþñùmþ(?ÚòÈ‚]Bg Á”9ã#§zšêïSfêNÙ\$Ï­5¾9_vÀ¸µ˜$–©«Ó|d渮ß-˜äa8¢-õKؤSq"Ý ê“ a¯J¼´¿†ñ1ÇoÆ<·Eüšªskš8)qe~‰a¨‰Zh$^™Àß"ˆ¾QÃ×!œ2œ~BŽÔ-®.¡UYžÛŒaSÉ 8;¾ð {õ©Æá7s•Á®HÎ n8ßüƒÞ[Gu1c¬Û¸è ƒŸéKk¤Ú‰A“R· sÇzKHÌFÀ\P-(Ï™Èà ëŒqÉTfpJSƒ¹Cüš)í-n%CçDªÈ‰¿ªûÝ*å>+O9É%¶ ’£æ*¡ ¼g&¬le¿ ¢ 퀟„3õ©–ÄËŽhäu(5ýÖ ÒÞYµ™NTƒR?Vd6“(ÆNxâ6×Ò*\\Hò†l.”g8ô®7WV¨¾\îªNFé²çY¹7ÂhÓÇÌ®ŠöÓuµÄRÂz|ª[T½ $%Pà«æ®­µØZ&ûÍÄq¸ü Ùüª;ý{NhÊÉšJãá9Ƕk—%íq7Xp¥¹LŠÞȹó–H—Ø‹+"‘p-äROâ?Ÿj kN·yrÉ啿2¹ûô©nkUáÍ×Gâ€ÊË#nflsWðÇ#ñü£5O<[á~Wɘ{?]ݰ—^ÕfŸ¹œ}Oø©î|+§Ã¨ÀöÚs,pà ç¶s[¨í®d}¡Bc©“ŒU­Ž†gxÝ›©9|¨Þßn‘1KŽYž±MRÅ|í4B·l§÷ÒuÇ_ýëBIáÈ&½]WZ“öž¤æ\LÛ²{|9Àp+sþéʘ?´-Á?ÂÀæ‚»Ò¢¶b“ê(؉åZBXï†sN9ZåP…ÃÛ… mnëžê9`m2îuF‰¬³øÜ8`>œP¿q€E€ÏðÀÔÿ¸Û8]·W.}­NëZ9GúÆ:|’jZ]Í«3¬‚H1•™T¦qUɼ‰ÓãÅi,4Hmã7ê×6hz“OÌW‹¦ø hGßüI ’‘ø’„zŽ¿QY=TaÃçú#oÚ7Ê¥ÿ&jYÃ\9îÇ4úd†êryÜ?¥Xëú&…-¥ø’Ðóµ”ä}qÒ³R¡F)¹d7Ñ cÈ­#šqÉÓä¶RµO†{X'öM×Þl§Ì™ë†éYø@.2¡¹äÆka è¶sĦêÐ6FKÅx­î:Šœ» ­Ùx\òp«ûŸpOݤw˜qPµ‹‚J–8ïŠÛ/†|>îP)Þ;y¤é|/ hE¬®¼ÏιÿyÇ'CÑÉö—ü¤´™ŽÖ“b÷'¥•$ƒp¹F Rõ«;þ à†ÇÄ¿ÜP[ê ÒÚQÜ2 h³né‘àQí]Z]¥žÓ"$¿‚_ŽÝêUÔ0²Ä~`Օέg $Qºƒ“Ç?J‚îêÉŠmæ(Úrkó÷i±ÿê![È䤨¹ìÜbŸ½œäL ö=h+–±ðÇ*ŽÃ~µòØoRÛûñŠÞ9Ÿlåžž+„Ëuf‚wëÚ•“ULï† L«ÎxàÑ6ÓÆ2\ÜŽ:€©åFkNþË(Ô®C6F)wϧJ[¸ÖFIå’^6f= zæ…]FLd >¤SY°J%«7šì·>žõ^·àŒ•‘sÏLÓ…ô<øù©ªÞŒ¼oØnâjíÇý(O¾Â92¯çNQ…‘OÖ“´#q¥Ýƒş̌£ zC<Î?:CÚI=OÒ»qùf…ƒ2cçÅ$—(‰¸¶F{Sr^Æ ß ý}ë·`t Vú6Ïâàõ"‘õTòsò¥½Å/ ýÄñÍ&ãúUSjŸTT_BÇüP×ı»/–§š“à~&‹Ç F ‚1A^X¤ˆLAPóÈê´k³dæ%>œ×6ºÝ Ž Lã}v^7³¾„ËÅ!ÕIÁ®2˜WBj KÅ7 *î\óŒ*!2³ä°ù‘R“ök)GÑe‰6’#ö p<|QÐ!Ùyó?ËÍ*Ü:Œn‡ÿ¹y«%Ñq÷k©˜/—GÜb‰M*x–š&ÝÁã5ª²k›9•Å|$mØAçÛçVªº+Xm…ôÄ™Yr¾K|@p}?÷5åKP×£ÔŽž7}ž{aš©•ÉWãàoíŠd0ZL|´óbþUè«ka(ŽáZÅY$!D6•#äœÔ«ohŒ¾mÜÊP¨Ä…HìIÉÅJÔRç²ÿl·p¸<Þ==DùyöD:q“ùQ6ÚEÍÄ¥LÆã½{è-ã–Hd2]8ÊÀˆ¼q•=ÒŸq¯ZiÖ$¥Ôæâi·îòAé×)=Lšà¥¥Š|£ûù„¼çÆ6QZh’Hþ` £¦3Ím—UŠêÖ(_{¬Gá ‚iVæÜ¢ÚLŸS×õ¬¿w8ðjôP‘¹Òe‰Ç•Ä‚> AÉìïgheËt8ÉÍn~ñøVÓ Ž»…6y!1ólAõëIk%íÐGìÁIe©Èîäe<àâœÚEéoÜÃçrk­#„.Ã*³¿Oj%,­Ä{B3)ï¼ÓzÖ½ý>ÙŒ´ÒuXþn'ábÃá¥M#XÄJÙɓҵ7vÄ ÂUÇC¼ÿšXm­÷(@ä„ÈMXû¢–‰.,Ëͤêq*¿‘0TIŸëHtÛ·™#x Ë6 2c3[ ôø.b"P‡‹¬’Ôy°Ã°‘‚W¿Î’Ö?ù)è—üY<1¨íi"ñ/'Ê‘_åœÔ1ip$áe¼10?†HöŸÖ¶šdî™eŽPþ'cÈúÑW²Gwˈã•ÀÞ"©êåÓ2ý”(ÄÜi°Ã*ÊoÈ1¦÷ÍNßu½pÓÜ“,0¥b}êÎ]. [O$?öƒ•ýj#§l*eµŠá‡ñ(Ã}sOÌŸ¾CöÕÅA¤Âd*b˜®à>µ$¶ ,Šl¼ÄA‘ûã’}¿J|ëhÄÒÍO…þù÷¤„Ú[;I\<["$Ÿ!àTP\At®ZK&v䃟‡ß­bÖoŽ{-œƒ»‘‚={QrYI© ›*¥[€j®ãH6íûÈþylž+£Éªn™É,2Æí+EíÂéë/Þ#i%Á Ddm};Ó~ÿ–1Ú(%@Ë`þjŠÜ[Ãøep[©]Ü Óhº®œbÜÙu?–>/Ï¡¨–Ø®SeEÊo†"ÝÃ,ã͵dÄH5¢Ó¬"—2qê(Sâ2&"==”ƒÐªäSŸÅ¨ô÷U¨a“úW>IJÆ4tâÛç+-χt‰<ɤÓZêL¨?ZÆø´dF‚=òÂP˜X~¼ÞiúŒ¥ºÍ¤7B¥qIwmeyApªÌ0TçðŸ\VóJùY¶\1œ~4yU½¤÷@¶`Tg=3ó¤–ÒX”ù¶å} kõM6âÒdêöJá/4iä;›ë¯¼? /õÜõ­?µ·^Ê 6mFÔÂ:–ùü}*êÛR·•„$ì¸ymÜÿÚ{ÔѦnÂT´mé×÷E²~¢£}BÉgXå°}€ç"ÿœ¦¦ú6Œ>äX›KÐÁÅÀÇsQþÃóNù4ø—ÿ-¹ªËíJJD‰á½‰FÉÏj§Õ4kˆî"Qs,É @'ó©†6ût2%ÊVj×EP¤}ÖÙA‚V©õ?4DÍlÐÇ´e“ͦMV>‚PDÆæ^Þgb¹ëÁÁþ´\~¶ø^K¶“CZ/‹½ÿà‰'5[?ÉG%õälcó§P2/Ò¢3É*í‘ÙÎzÍ]M£Ú?˜É(APä|989ÿZñGyu ㌳ޤv®¨Î/£Šx§Á¤Ç÷PöÆAïëVš"[K4k}¥M2Áufúg=­½íºFUmíÔ¸Äwf™waªK©Dð}æXÌ€üi€yã°©y¸*Z{¿þ‹vÊÂ52é“ÅnÉÿJTÏn ¬ý¸¹½p u ‚ÐE¸Œöþ•jÖº”w2K$j¬­ŸŒŒç§þŠ—Ë·ò·I¼å`\8l3Üš˜7]šÎ*Oèe®Ÿg¨Âë ã«GÆ$T“ïͪhñÚBÓ-áeo„2Ž§ÓƒÓŠÒ6£áX-Äòîn·*€ì;‘Ÿz§Ô˜F×p³*Èä…Æà?¸¯@ÿxtÉn–[ÆÛ@ßo9Û ŸZ¶Ó еeu·Ö.VäŽ ºˆncè¬c‘+”KÒçŒ%þœ¹üöxÁð‰`Aum ¼¡NA`ñìkÓü3c®¿‡­ ¾fE#;•”Œ÷ïžEYCm{q"ÀòÅ ’Wpl®GLÿz5tÝKîÞT÷v¸Æ0“íêz|…q¶“¾Zzœ™`¡.ŠMRÖöÎ× mþhЕ?P*¦Ký ¾¹Œcÿâ·+q ¥¬]Äœ‡2ÿÓTó®#Ñ uUç5xó/hâÉ‚O©9ɼ’Ua“•?­s¼'iŠâåXö#§5|Ö,Ò ÀýÀ ÏåQɧÚÄìwwòÏ9­üÑôr=<ÑC4Š™ó>õœðÛ¿¾j8îÒ2g89¼ïùU¤–v±1òË|ñA\ÙÅ ø")ïž¿JÚ9"Ìe ®Pl^(™!HŲ¹Qå‰'è)Þk¶cHê8?æª „¼yj¤ôÀl*Ê-€¬ö¸K1úÒpÇÚCYrôØcø¯SPQ㌎êËœÕuÍòNþd¶6Ù#ª¸÷àÕ™†Ø¦<¨6‘‡9,Ö6ìÄÂÆ#ŽÒ”^8¾ $rÉs++#ŸLb!ìË]%ġ̆(ИŒ`T—VWþYuÆ7'48v^T‘í] §ÑÍ$× ‘oŽUG±Aþ*d½¸Œ’˜³ÝT ¤X1$ÿ?Òš`’C®Ùþ`A¡Óì’é–"úúá¿ýô²?CñÑ]ë‘ÿþMÑR½ ÏZÎK BØee>(û-sR³c¸.¤t~­D±ÚøÑ¤2Sù¶j´Íbä(·ž(#â ÝsF%Ô™È!n!‡<}k/ˆd…Ÿˆ…5r5+mN!Øñ¨¾qÓŠäž&Ñß*’¤ì&C%¦™U¢s¸ðCÜj²æ Gì¯d…$«“×úóS<˜Õ£‘Ôg ÊàŽÁ,Ëæ¨ßö‡\dúô§9±ÏŸDÛà­²9cœªä?µt-q#Ū3Â1“ŠLð…t·‘ógá·ZœN÷,¾T3°ødV`O¹Š·&f¢¾Ê·Žæ3æ¼3Dì§Ak,¹c+„Ç“Û×êK™/#³ky&A“Âã’9ÎhX¥mŒ0rûsZ¦èÉÅ_!Ï/ÆÝÜ:¯¥L˜€•aŒ¶åSK¦êÑ[«yg ßn<ޏ¨ÞìJ2F£„X9úÔî_elkзˆ‹#1@ŒPm‡CÞ¢ŠÆg‡x ·§ FGgvË"½£H /çš>ĪÛùd[oÛÉcžsS,›WÇçÉCqm4$‚¹îJqP‘#d®G<ñ[[wGóî-ÎþÁ󡦂;ex­.-W VÁ©ZŸTSÒû³>°Üá„›OáÅ"ÊÝ®mȃµ:þjê AsûNÝö0$¯P>¿*™#µNåö±`y¸ôÅ7™ `*¯­!Ž=âÐ’6ºœr}j±ôõ+¾) Ä7}¸ùV!Òa–$w¯†9Ï&Š{ 32>8Q¼ä{gµ Q´oL¥ôc$‚òžgªÂž²G"bQ=8Ö™´±Ã5«™HßH>µSyk~‰ %Pð0_zÖ9ÔŒe¦pe•vá ©éÔüýi¸ÉY ϯzŒB¡•]Y =[€)E¸ó±s“ð²r k¸Ëkn÷3³$Jìê3´.x§Ëmz±™f³}€gvÓBKIIÜ€:ã5©uÞ0R}Àªî¨Ï•ü‡™ª)VùÔHÑ—!óƒÖ Ã’2Íš|[Y€gØ;œUÕÛ x¬6—d~§^j¶y#%!Ü ê§Òšÿu;@•‡¾)¥ÐÏœÑÈWàs[}ê6õ í-½á‡Ão*ôø£Èb§ÅjøÜäô¡Õr ;ø†þÑ·q§@ à‘œÔ qá¼¼tɧ>•t£)$Dc †ÎiSM¾‘w,HÃ¥fœ³]¹küˆÚeŒ»´ëKRÄÝ3Àç¶h´Ó.ã·ýì¶èê¹.7gÛŒÕe޳gv»—âÚpwO5m°º«$€ûÕãd”×h÷±F”È"m@nD@g‘þ*d†\ïl{g¥L\É9ü©¥‰‡^¸Æ{V.wÒ7ŒkØ­@÷¦}Ê´ŸèW'ŽfU#Ô&[œ®Ð änÒ¦Øø6öá0m£ÇNR¥‰£ˆco`b„2…9UoþêC6Oģܚl«^‚<Õ'…Â“Æ 8ºŒàwÅ æÆà‹ŸaSC"³m!yíŠMP)0†’5@õ5Ñ´`„ ¿#;‰â ¸s°ªlR3œ€h;upûšHÀî5 A¾™pÛJà¨>¹¨’(GD^: <­‚‡ñ©ÄѯGLwÚâ§l÷ʼnra óô¸O,Æ2H€:P²Ê­/îÑY?‹Ô~”ç“<ˆ›nv°õ«ÚßdoK¢±”´ò@ÒIR à¦AõüèÍ!aµ‹îâé¤,p¦ÜR»‰ß•SÚ…ÕÕÄk%¤âÙc_À9,G~ÜÖôåÃàÁµ’ì¶ØŽÜïƒO Ä¥GÿpªM5õ#a4Òyrù'* €3Žý*Õ¯t¨ìDŸxÙq“¹e9c¦=k)cišÇ*k¢xZ 8º¶ŠpA $€=WÝZÙJeÄfЃ•‚£¸É©,î-.!"þ&ÉRçûRKi3[0[¹#süh™\ÓRiÕŠQRå"Š]B+i]?hLà)ááÁÏ׫mUðõÌ‘Ûj/{$’¹à.,Õf«¢ÝÈÑÇ%霅,IQœÇ•A%½Í»~þÙÔ°ç Ò»c y“‚y2ã—+ƒØ-ü9á8Á’;A)Ï#Z¸´Ñ<:‘ƒ›bÀr¹Ïç^#g©\[ȆÚY× “ƒZÛ/^Ú¡‘ùNÃà8àüóò®lº|Ë©Y¶,ØŸjûé:D.nÂÑÉP¡YTªý; ¨ñ+\Án’i¶Ö®°R~GÓj®ÏƱͳ͌¹u%Š Á,vùÓ$ñ5»éȰܕœðT.àO‡ÿšÊò'ò5œñµÁŸ¼ñf¿j&ˆG=¹f• òãŠÌI¥¸y¯%½,ç%·†=k]-î£,2O่ŸÞ$©’ŸŸjtM§]Úµ khÙÆ7¢‚FG^+ÐY±ÁsìyÒÅ’o‰tgÑí™VQ7›_t`H8ëïô«{h`žØ~È™"’›¥bX^zUÅ¿‡¡—MP\Ä’ƒº9¤ÿ–ãѰ>†¨ŸL)pï ì6Ì®Q¶¦=¹õ¬å–æ,Ú0œ8’)$Žt‘ÒIæ?Èg<þµ¶’S˜Õ¥Èä’r*ëö5‘Ø×‘‘Á9ø8#Ó¯®k­ì-’w…®ÉÇÀã I=sZùRèÃÃ&ù(š;„ÏÁ"òG¦>~Ôfqoÿ ÛD_ˆþÕxÖö‘푈 ªò½±P^Åc$Mi#x€$†=nx¥æÝÅûwS }V+$–P³1ø‹1*}‡ £ ¸º ’ ‚eRITuAÏ?J¬6Vöp›™R]Œ¡‘ÀSëÏ=yùTú~¦agžÊ¡”Ôç ÇëJQMpTg$êL6]ZÚ9Z{½<,³dîr2ç§&™$ñ?”º\V×nÃ>Tjw¡Ò«üK¸K}EäÜyVÎ{üª;)n´Ï.vœ S·*ÜúQF· –Y^×ýË |I©YÏ÷{ë%R§þTˆTïUú—‰/®¤&žÝqŒ#ãçVº®¯¤ê«_$×.>ßÄÌóTך~Ÿ5±ŸM>XÈräÏO•tà–NQ§þlë=5Zÿ%d³I+nšW÷,I4ÍÉÀjšÎ[˜šõ"`B…uÆIÏ~Ý:šO»FЬ±ÝA&NÃ)÷½—¦yž<¯š"Þçó®Þ98àÕ¥žºÚ[™îjðª‡q'Ò†2$qìkxvvœånyâ³z˜]G“Hé2UË‚ÓÂþ»Öàšð\[ÛZÁÿ6I[qž~¢u =..t/?}«2âgÓê¨;~uG4äG2LÃaʇG§>Ÿ=¢.f–RH?„ÿ_^+&\’w|ذ₪ä6ÖúâÆ£Šå·Á9PO¶(ÈoO˜ ØŒ°$°#w¬õú‹xÒE2Å#®öãšm®¥vaC*(Qñßéžµ‡r´n³¸:f¦Rxö¤K,0œà©?¨ !û¾$1ßG™ñg<çëY¥Ôµ Oî|æ ôçúTï¨êq”IíbÎwáÔ Åá~c¨O°»ËDÄ›–“œç*=p(uŽxYE¼²H d,4u®¬¤="Î>-­Ÿ¥JºÝŠà*8ÇLGŒQs\UŽ ùºa¹3äH®:‚8Ïõþ´ä׌¶Ÿ”#ñ¸UÖ¡k8.Û?Ę˜ ÍÕº¿Â%ãpo艥öT6©( ‹HÀ÷Ïù¦>«rCX=±ŸïZ[kO 껼ûÜSÿ1x=òZ¢Õ´¨-î™tùÅÜ}·|-ùVðÉ꩜³Ç’*Ó´ ºÐ#",Ž™QQɨ]‚ “iÿ´ Iš'(ÖªžCg4Ô¹p8XÎ{®…ù£™äa'S»bO!x4Ów+¶Zgažìh_5óøWò¤,Ü‘ÅVÔ‰ÞþÃLò•À™ÇÌšãlnvú梎Yņ0E=¦ :ȹÍ.‚ìà%\ì GË"™&ø“o®)ßÆÝ¼úsPÉÉîi®Å$váÙïJ’l`á™Hç*i „.ÞsŒT¢Ûs¥P޳ f¯r%'è:ß]½ˆ…iŒ¨pO5ikâKuu3BI‚~£ÓŠÌùs¤uá©ëÏÇÀxî²–,rìÞòǃu÷ý>ò0°ÝIæ18Œ9ð{t®Š) Ç”ñ9àŒ4 ®}HÿŠK9Õ‹î0?…ݰßâ¬cˆÄÖÂIA|üNOΤ¸Óì¦snï(Ÿ@§ô¨í¬$´•„SC€¤»²† ŽÙúÕ¹¦»3XåÑË{xë±ãm±’#v})$Ôdwf1*+ryÇÊ™n'™Õ% œ)ÜsŒàÔTŠËTçÔR"äFÌÑ>ü|C’1Óšúc»á¢{>y‰š7i);I ˜Ѕ£”óÂhމÎ>ªÖ ›4ž˜’Y”Ê¥»•6¬˜’WÏ+óJ9%†ñFI™W…K…bTä«®ËÖ›,Qº £1('•Þ2:ñŠÑN.56šÖá–Ú  ¢°ÚÄû“PÏáxZÛöŒCœ³cÔVë:MntsËNßñVfÔDARÀ°=6çöò†7¢Ï ~µguá‹ØFûYà˜cpelTS}á$+2±õ-šÞŽOâÎic–?åo)D›_rçÐgúQP[éëI4¥ØtÖ¦±šìˆ²K”P>ã#¥Ú6£t²iú2ÂÙøÔ>åü»TÊ|Ót\1ª´¬†-#d’/=pz‘D@!•ZI.Ä,ÌI]§óëFÿºzË\y’[‹|÷WÀOJ{xV,þóV]ßöÆq\Ï$=ÈéŒ'ê%¤º>™•ÿ ;<Ãþ”‘€ÙêNáU Õ“ËyæGµò6ÜÇÚ{‡ÿâVH†:°#ÿ}é³1¬26u®u9{:^8ÿ´f›ªMvIƒt˸(ó\ýhÙ¯g$ưÎp% 1ï‘Yû-Ëeevð¡ü¨ë+Ý^ÒTF±[ˆ—ˆHÏOo[Œ(…<‹†[Û›†Œ$—>i#—Dà|ééšÀýìäŽ*I/tÙ­â6ú4Ö—.pCÊŒŸ\òhŸºÞÇd!žÎÚ ÙÚÕ‰ÇÈãó®y$tFO¡~ïæG”¸,è$Ò%¤sÇ”–E`yÏ5_a‹%HÕö>ì‘´Ÿ\œæŽ¹œÏ!/3ï#‘Àò“Œ¬ÕI4HºÃÉrÝÈzm¶›,ìËRH}Çó«/G¹·„\][Hac¸I» Š·‘DÊ ²¸ŒÕOz®Ù’ôŠ+o NÎÌI‘’d;±G[øJ)¤XbºJÍÈH×8ïÖ´Úœv~U¼šfýÊ2`’{æŒkëtø—Hš9ðrD@ñìiîhÍò þàCin³OyoŒi'¸U€¾iTµ^½–Í_}þ2žgÝnwöiãóôª»™.&™¤sæ¨<Ê{t©ß'ø$ %že;Exb‚R3µ<{Õ¶—¢è·jL‹m”f8V½j–ãU¶Ó2feCØÝÎOçYýÆhf+ 2<˜—ÈàU(;Ñ­Öü- ¤LD‘‘×1HkÍõV·Óõ –7 *ªyú{Ó¤Ônõ(ÞêD TpÛÀ VŒ?›5¾9øïs³)ásæ<:tñ\Ä %cçá5,Ö6îùž”÷øsTe2ÄM´²!àà·8[©FÇœ!3@¬eÝÅÑ× QJJÙg µ¼$ù0¤~Û4óÊŠßaÇbÜ 4CÅ•ÈõëMo>5>]¤0ãù¹— ÷f4ƒ’uØ~õ4JHìÝ*+ét˘–)eŒã¦2*¢ù亮òÊEg;Ó–?y+äÝÛG0ÿê¯ ÊµXén³'’ÞÚ'¶³ÑüÖÚ†R§9.MMpÚL¶þS@tÀãûÔk¦ÙÆL‘O$nze¿­@‘£³$¬Š‚wGÎÛ»d¸¤©¤pû²Ínlw#Dÿ‡9Èî9©u Ý)žTŠãiåd‹ÉÜsÜ9è mÄW$aÆj¶ê]1æŽI.œ¸\oP?1ÜVðVýœùKŠ-#’ù`{;KÕÚÌÅ—á*8êßÒ› AÂ4`͹Œ}O°¥ ©la½ºîŒ‰–<G#9>õm¤]}öBÖÖådLoulÝñùS›qO‚ £&¹5¿Ùr*B³Œ¶æŽLasŽ=*·‚öÇ^¥Rx>¤u÷ªûØ|û‡Uçx˜<É/$@O_¥Wê–ßv =½Î\žbÿ¦ àýûÖNŸ\3]Ò|¡¾ ´Ô-™‰‡rç¼\¯½QÉ,ÊÛeá”ä†è*ïNÕîm®.d»…NÉca‚‡ß=;Ôúž•k¨³Kf»‘“·âü»VÐɳã4a<[–è{€YÇ šW$.cçùÔð[›ÈãûŒòܹ9hœc‘øAúš³Ò¼,É k¥f“€XgwÌQiÖšt±,¦5˜Ž6åwzh'QaS|È¥Ô#Ë9’à‚Š¾jF¤*ã‚°ëNÓ´Û ›Y¤[‰|f9çèh»(­¬ã1Ü]BÞc‚$ŸY¼¶‹D" ®yü52Ì×)`Rw#) Ì’[+'ÄyØvëïVö–®4§’ïNwE`Uly|àŸoïR¥Ý„vì–ÿwE$#ÍV^ø…ü¯.ÚPN1žy•VùÍÒD8cÄ­²öëúù¸¹´¾ŽÊ(—!b>h?1œ¯ëY»•°Ž7oÙd'À;HçïZ+Ö‚c=¯šã Œm¢¬ïl/®œêQˆ $|&}X{ûVŠ3nÑŽøK¥LM>çKŽÜýw:®K úqS›ï €ª¶7‰”í-鑚‹R³{9P%¢:crÈáÁîqBA ~ðÉb¬7Fãõ«øË›ÜÒÆ—ö µñ µ–<:b `0ò}OZ¹ÑÛÚ‘ó!·Ž9‚î‘g<“Üòk9¼— ¶(ŒH¤R@9õçµ °Ë÷¬5ÂG#æ'ŽºtÊŽYF·+G¨>‰áò±M$öhr Qߦy¡-O„­/]na¶qŸ…·a—ûWÆ’oÌ·q•^ã?¿J ì ]eŽUé¿âëÅd´íw&kû„ùPF£_ ßÜ×)´…ŒGñgóUU´ sæ(/n$NÒmP1õª’!%BËÝø¿ÍNtûi¤F†óâ-ñ¦áÇÈäÖŠ ·:3ryíªÍ ñ7ì¦òí´ÕØË“—R?JUñ[_'tË5‡9@Ãâ¹È ÿcJ—;á#ˆw~xìx«ýÃZUÛL—×Ð6Ú6Ú}ó‘Åe'†'ɪŽ\Ž—8Ë39R’{Œz „_…ܲ+©ÃÖ·7ºo† œÁ¿ ®Ó¼d±Ýì@À¬q‡II,Š…¡†zóÍk‹4fºfpÊ´,¼pÅ·Ë\“éÈ©ZâÊææéá¸=TG…¢í´M"á­ɸʼ ãä@æ‡Ô´í>ÆGC‰YHânAïÒšž6ø» ™ùU$Qä“(ÜO%[­L†IBã’ Ö„YlPÿûMÛ‡8vÍImû*F>dSÆ1wî\ Õ˯d§ëó]Ú”Ûp¢U=xÉú)ú>—¢jj=³gðH ~G8©-,íî'Û ¬2F§ |ÆüúñW–ÚFŸh8Æ[lcÏ9ê:VsÊ ©YqÂæí¤Ñ?û‡`@hï¥ ò QëUÚ‡‚¯£”‹Q êNFÞ1ǽk´è¢È,ѪçîÚc"_,±Âvàä9$í>þ¿æ¸?y–/³¿ö˜¤º£Íçðþ· eš(¢ã9@UÍ¥Þ#’e€†çzÌ0kÜ¢†5ˆD¡7¹Æ$ÏéBÝhñxÄknr¸§ËšpýFK´LÿO‹öxü¿˜oûÕ®«“ý>O ßÂë±ÖCàè?2+ÓSÃ[äFŽrç+ÇÐTzŸ‡®áC-»™H?…Gj§¯•ö% Ç\¦ydÚdñàÏit9<¬_ë@ȶÈä47ÿäûW¡ýá’cÊcdAíCÞÏ)yüœW<ÖñÕËÚ2–Š pÌ™ Ë ƒÿŸúR ÞY÷ÜkU=ÖÒšÞ-Øç1?*†+-ï-{;aY†?:ß÷r™Ìô®þ2E^MÒ=Œ ü súX/-Ñȸ±Àô'üÕÓøNa”¸–3Û⇓A1®a¾VÇgN ?4¼5­Î‰9À·‰1‡Í,ÚZ9ßgqåsÀ*ªèÑ[˸ (£2ŸÔb­måÒíÔ</þ>fOåYM¸»‹føÖåRHàëÖñeÔp&Ï.µW5Å䵦ŸGøMh§Öl£laˆ!¦GIž=ó„b½7ÇœUC$£ÜE“eÔÌÑ 0`ÒÃ(ÈbiÆYäMΰÜmèÃáoóFÞÝéMñ[]ÉÂù@¯ô ídR»ùìb8'èk¢2m]“‚‹ìç3F+»Ø\ l|°?QEésë–îcŽ9.Á2Çæ*šk©‘Š ddÆ>1ƒHׇx–7–øv9À¦àڪȢîÙ¢mOPf”Äê9Šæ5äZ*ÓXB»®R$øá—pü…cZVžEiå‘ùêy5Ï;ÿs+ŒüC?J—§F‹S5Ê5×ZΘ¬nÙÈnqQéŸJMJÎêE2.äs™¢¬4›½:?‚S¡ÏÁ+nüÇ5œ±¥ËVmÍð¸k­&ØcPAÆzštúâ“!HZ6ß»†ïùQ¦óGÍ¿OŠRXÆàGõpi3Ü´Œ‰Ä`ôæ¥míÄ¿Ÿ© VÕç™U<´i6°‘žãÞ’(5‰QJC>ĦÞ*ÞÏö,eP`2à‚ùçß5`±ÚÜ„š[p¹ÚŠûC|±CÌ£ÔB8e.äg#±×%—Ë–'Ý#~"¼ýM7T°žÓÏ<‘Œ|>bàЋI CÝM 9ノzsÍ we=ÄÞT“ÜÆÈ9|'åBÏoðSÓÒ÷fk÷ȹûÀLt*ý~”$²LΦI…éšÓMáü£¸èãÓ§ð½·’.š9?‹8 ·çÒ¶Ž|IösËK•® KK¡×ÜŠËÑZ=ÃúÕÅ—ˆõ¨K,B9a=U_ûõ[&šmB©ZE$D…¾”¸Óc%|»—ë× þiµ Ÿ’ž>ø4W>*¼â?¼Ý[ aŽIÛššMJ‹t¬c;öçéYS©BųÞ=$”ŸñMmM‰È´µÓüÒZxWCz¹'ÙéÚœ—SÅ#Fé<Œ1‡STvú"Æ‚S'‘p9…Žô9ëWŠ@ë€:R8$‚ ž‚¼˜åpTnX”²’dÖ­/žêÝbºù®(Í3^šWXõ 5 g8õ«-zÉ÷ãŠYm`˜©’5 rlÑæŒ—É Ã(¿Œ‡avÀö©# rdÝÜdÕmÖ™]ÖòÉ xlÊ£X®! ’’ú»H¨Û¸eîiò‹)„0ólã¡'¥E-²ÿÚ=ÛTyr’9Š™\–ÛùŠ8,’rÊ«•ÐZ}–vڭբƳ0§v¶}F¥¯J\ÛÁ9Ýû¥9ôCQÄÅ/ ‘Ù™ÈÉѽ}ª{¡-ÕðXíZì85T¸UÁ Ë»ä.ÓZÔîˆcI±†eÁý*ÿîzË[‰VqðS?‹Øƒ@ø~Óîò·îÝTa8ƽk ¹Aøü³ŽÛ³\ŒŠ/à‘éé±IÇæù(m®u1WòãÙÃ?:=&•Æ3Nàššþ[y¤S@àg±U73º?îˆÎz/cY/Ÿª6an—ª&§§Š¢¿Ô£Û$R]]‰ñ$x#¶E]Ás&Ó÷”ØÀuvÕ ý­®ù ½ÌH’6÷ ›Î~y­°Ö¡KoÀ¤ ÓH̲2ääcH¶³$lá™ã>ÿZ?6… É$ŠsÌd/úQ°ktHDšrn‚Iäü«µÍúG™ãîe ™â“ÌCµ»UÖ†P•­®>ï""“¿Ò‡Ôõ+GuŽ8Š6 02cš“N¿±…¶eýàÚ@c‚)MÊQë’°ÅF|¾ $ZT–ð+Á’NцêA©aÐtæ™>_ñ6îOoJ üCklÛ˜NÞFçPŸÃç©18^û‹Þ¸¶æg~üáš›…µ¤pn mÉêEEs slŽW”óÁV8ú⩇ˆ,®H y*1ãkGÎ~†=å’B¯ô²ÈßÀœw¬|SO“,à¹Kkp*u}ÜççU¦fÛ糸²ÎÂGÈUrë«m™³Í¹*W¾=;æ´ºN¥kªB [ œ^,Œ—¨ªqÉî–<Ÿ+ÞC‰á¢˜åÎÐ~]s×­XH«¯[ª¥ì¢â$ÉóâôÁÏϵm‚ŒI_å<Šª¾ðµÍÄ—PJö—6“CŸQVµnßOO%×&} á.!‹ÏóŒ§8¹¦ÉaµWm®ÞÃ+Ç4ÎåÉÿ˜9×¥vBrš¸´Î)B0u$Ñyaàë[¤YSÞÌr¥ ýI¢ÂzOžÑÍ,ÂLäî`ô•ý¥=«K-µÓÆe䢳>õwßµ;… 5Û¢¿$¼›zzzÔ¿§5ÃäSñ¿’ãð\ëzŠé¾[+ɼËö­Ìdçž:vü« n$›¦‘ø$–j,YÍ0ÈXÈÀç “šïÙӇה9ÀãèzÖ˜£ j¯“ ÒžF¸àWŸˆ–Ôø<‰%ˆLsÏëF-½åÄ~RZn*Ù$óî(=FØZ]G±‘3vƒø³Z©'dz'¹$øK°F“dŒš{Üyqˆí"dÇÄ]ò3ß ùW^[AäJÉ:pË# åzœž(S+FQÙp§ð–jŸ@þ$gÌQ¹a œúö©!*Zâ‘ þ"÷£®d†iìgWf$‹g—¸ÛÔûñLšíÒ8ækj¸LŸ„7sžô÷7è[+ÙwÚÓÖ飸…•v¦ö_<ç5Ôn.m¤¸ÈŽEÀyœc§_Ê©ú锬³ù¸‚¸,þâ™q~^v’híÕÔ ‘±úžkƒ³oÜ"xoDZŒ¦úç%|§×c=å¬ÍšzÂøÜ¿äqƒéϧz¡ÈŸk;üc¾:ŽÀš¹Óu#°’ÆúÚÙ]Fäy`ÞÄŒðÁùÕÎ>è˜OÕ‚](·ÑN¬_’ ø ÷¢,á]BarevýÚ9À'¯^ÔÍi!–i¥µ¶f<<[Óéžø£ŸÄ3ÁDƒLSŸ„CøO¯<ÔÏrá.JÆ¢ù“൳±ÓK„ºÀ¹ ³&<ƒÐv¢¿eÙ¡1¬Hë"î@ duŽ”6¨ Š85 ,®3·Œg‘‘W’àVp[p=«ÏÉ)ÆTzx¡ŽQ´€ï,ü8ðLÚX%‡çö¬ýòIhè-u)²Á°­ÈaÔtö«{!_´²™²6°8${ ¨ûÞŸi#ˆ%f'øqœcÖ¯ÿRsmKŽØj—Ñ«H/¢‰ü`·âÿßíVKâ™à{‘¢í;8*¥O#Ôpq@Of—±O¨<à©Ìm˜ôç€*¤µŽIoBévòÄ­ð³³îÇ®a[,xçmœÏ6Hpj¿ÞݶÓ_~ÕÛ¾M¡þx4Jø‹Æ69VÿŠPL‘©AÇNÕIþðÁa¹e€É*­#’ß^ƒ5Sqâ-NäÈ«tbRq°`T­>çJ*ŠyÒVäì°Ô|_¯MpÒµÓ[Éœyh»AAOâýz`]Vìñ‡Çôª¹ ܲ‰%Y%À<ëQ¼>l…ƒ`ÏA]qÃwpË>Fø“-“Ä·×¶îèÊ„à–$‘úÕ¤wq¼Ey ˜¡Ï¦+-…¹`÷B¯'Þ‡™Q2°ÊYw2¼Šrà ã¨ÉräÑÜÜÌÒ–¼µóãaÿ2!ÇÓÞ¥ÓnáB8M¬3µ“ ­e¢œ”&d ànµf÷ˆº-®ÉU®ü÷ÞHä&nþj%†•sÛ°ëÛ¨ò?vFNsíPÊ¡IÌXÂôâ†:•ÄŠ£WÛ§nqÀÿW-$³»0 ‚WâÀö¡c yT™ÎŽ}¯Ï8íŠlj\<íBx8«kT»žÚ)cÙ!ÁU\òÖ»VíRçËiܤ)*þÜt£É͇Ähå­^ð\ˆ GÚÏ»¾; X­ƒãö²_-ö«­;^ÑÆ–Ö ¬Xä3¦PŸ^Äu¡Chd±ž)cvÉ øÅg’MîáË\W—ì­vÓѶÉ0›ÜAî)U´y $v³™7aŽü zãŸëSÍ¡jLè ¨(¼~0súÓçÒQ7âÆé[=A$¯z×|~Ì|s¿â1$·Ž&e°ŽM‡ðÈìÃC@Þ^[UŒ1‡‘úÓdµ1JʲJŒÃJi’XÜVþ„jÒÛdJSªHÒév¹$U´’2ø¢ŒŽ™sº¸øc좰QÅq¤ Qyá¼Ð(ø5˜‚–Ô€#ÿâ‘ôÏ“ nÓ:pçISFªhÌg(3Œžh ­2ÚáËÉÓÝ”â«.õWšßîò^¤‘nÜ—È¡—T6Ññ<ÒÛhÁüÍg S]>M%›ì>O®ïÝÌHÉ™ÇÖ‚¹Ð#ÜŽ%NJ"Û¶kwu ý±V¶º••ÊbÞMÎv–þÕny¡Ù+ 3#÷ICå1V€zÔ%î!”bÝÏFò­«•·ËlGr([Ëfš2Ö÷ØŸEý9­¢ß(ÊZJ_QZ]Ù¶r—1ë´ï_˯ëEɧ:í/Öm£=J°ú6嚫Ԭµ ’iKƒüAúý(ç0Ýñb·PRæ,æy%Œ“-×[Õ혤Ž$#ùÆqGÁâÙž_ø¨ÈRJšÏÀ×°@CüÄU‰µ‘biÛ2€a‡OJSÅÚä¬yò_ź-×[iù†=ç¯-DÚë0çt‰Œ‚îEdË6Hv(GU¥rù‹ÂèTçšÉé¢ÍÖ®~Í”WNIÐŽãuGuao8>d17¿zÉÆe.óÕΖ¡ðÿµ\±l˜Šàéɨ– œ¦iO“†„“ÃÖlÛ–I#õŸëRÇáí?`ýäÿ˜ÿeu9Qû”“øWI=þó²vü©)ä~Æñc»q4‰zVS:ù-l©¹œ±£#ºiâWŒ*£ Œ¢¡Ù´ Qž©áU@ÏNد6[YêÇrt¤näôÁ54s8êvZ@qГM–h÷,lÁKþ'­CV4èÞgq\Ž:ÓÕ¨;”äpheŒ ô9ö§n ëó¡¤4ÉÙ£ÚpO<⪮t+IÞ $‚Rr ëò«$‘qÈêzÔw7ФÂÀyqƒÒª’|8ů‘Sasqi;Û]ܰ>W“ÍXÁ«[;mA!9ÁšŽ;'¹¹W{ð¦y?:µŽ8b‹á@¼ôyäœjI}ñI`›» 8»²“å0ÏB@ç‘F ==*)&>QrO¶1XvøFÝ.YVØYãgŒPO8‘žk'–Ã~!z5–å—áQŽå¸¨…œî8<ò3[FivÌå.ZElÅí õVæ ûíÜS0–ÑOD>u}oló"Ýk§·ŠMÌÑ㞨ýÄo•bðJ¸tP¨.¤­ÌÓ³rÍ‘DÇäà,âl`Ùýi'²·’s@ÉäÆH"¢—L¾Ž¶×©îã§Ö¶¸ËÙ•8zßåí’æ6,Ì9¨'Ô-`p^VŽ&©® Ô-ÕÅÉ‘ãî^A§;ï°¬ÚK¹†NG÷­8®[àÍå“â+’ÓöÅ¢ )*–ô šóÄR/Åý6ãûPÐøVü‚Þtq0è¹É?Ú­íô-*_Ý»û‡ýi? _Ø”³IuE3jóÝ?’ýXõëõ¥ŽÚùœ¢ZLç8  Åhl­thE#I­œî ‡Ê©'@ö×Mmåd äç€1N‘®ãƒË(È#9ç×çIâ‹à¸æ’äô¯ëþû£Çi Ä!dãËçw~ü{Uмbì@Ú|Z¯+,ƒÞàƒ‘X¸5›å¶E‹lqÄÀ²¢‹¹Ô7÷s\η^É"±,bbU”ç¦=0z×,tŽ97&tËY»ÖÕ¶æ?Ÿj«'üß<±8éÇN”$sGnU Ó-ÞrUÛ2•ôéÓåBZ£™­NŠqæsûöSüv?ØÑ2C>›slÖ÷1$˜ß4Q3Ø-_jÛe*nÌ\œ¹¡lgŠxåòÂõ+ðF|áÿpÇ´Ý`ØÞwkà 3>ï39çÅ%ÓÚ­ãO¥Í$FTÄÌ2»‰ëü_¥WÇiu#PÈö„ÎN:ç•Q7tDŸAÚ¦‡" “N1ÝÀFQÃêPGJª“ ,ªcrrÉ&A£´Íjky$Š/([îݸ®ì~TUìI-ð–K¶» (ÖÈ@^ëUN.¥Ðœc>P߳ѢK[[‹yp0^\ƒÏ<ñŠ6âÆ Ÿ)ä½q´œ¼êT{ÆAïÞŸ&”EÌ-§ÝIšØ¼ÎÀ’®3!Ͻ6m3MKÝ­ä‹+…_𻤠dÖo$x¦RÆù´K“ow7Ý%x­ä\q#¹ºcž*Å´xtVÍÜ ~dªìPÉeàçá ‰îº¾ ±8ÕíäŒê¶Òé£ö|tòœ–I²T7nÇûU²_É M,Ó4lØbÅÛ#9#êzu½à›Ê3KŒ:§?Óµ5¼WpŒíieml\|EW“ó®ˆ`È¿Œ¹Ï“<.¥/ìiô»iäÑ~ñ©ºZ”¢”° ÀõüÕ6‘=‚[\ÂÒGw*“÷ux9ì3œšÎ_êw×ÌZêåä>™ãò¡2¶TœûÞOt»ú0Ÿê´£¯³C­½ËÁÝ8ŽN6ÛÆIæ=êÇF½m<ÆofZí/å:í/Û¯\ÿŠÇ››•!ÖáÄkC§x¢‚8õ-=o ŽrHúÒÉ¥š…%eaÕÂS¶ëú‘j+uvÒiÙ1°$+FFÜõçœüê¶åÙdEêÌÜg>´Uæ§owwä[±#j9À ëÇyû;›!¿Üò#<.ì~•“—‰%%F‰ydÜ]”r_r!¼¥RÈ#¹ÁëDË%Åê"[i»Ò5ÃÊRp:R“m¥¬‘Ë*Ïv„P©žsž´4Ms8•ÚÜ•rdVòðOJ8|¤\7É5ýÅšù²¢Ÿ<É–ÇÊ„»³¹‚ÙežÞEI ‡ëS´º™åµ°˜í9y$<éE\âîÊÞÖÒá§øùG,±úuè~´ÔœjÆà¥tÊU(ÃËr7e¶®H÷©ÖØHBN³.2R3Åšlqî—R—ÈÙУ‚ì;ãÒƒ»ŽºÙñÜá/ÉúãŠÑM7Ã2pq\ ÛeH-·Á ãxž>TBÞhˆ&I=¯¥u“Lé$ÑHìèTFOçú×Z_¼Ý#Q##sÓÿJšjÊr‹I> EŽ©Ÿ§EotM¸ü*7(ëŒÓܵ9L¶wÀ¸0ÉßéX½M#’ûðz‚(¨b‘Ø ±?Œ©Íbôô÷_&ÑÕñ¶¸.µOwʹèVAʳ÷n—t>éz®:‡…ó˜¢f°žàïò]¸êF>|Ó%Ñ'P<8’USýkLuäìË+ræ ‹M;ÅÒ¢ˆ¯"ó?ï^åWpêÖwˆ>ïpð9Á¬Lº”XKu#¨\Ÿè)‹ @÷¦ Oé“S->9s¡¬É%Éèj ‹åˆSռ7 ¹{Ye…Ïð±Ü¿æ‚Ю¡ŠDYu)Êø@Ÿ5¤’th‰@qŽ¥¸®W¿¾'te<~HÂj.£jÇ0™”|þuV ‚0GoJØêWÚÔ.ÂáeìÊ2k3wss.n•Yÿð Jô0ä”»£ËÔb„ÆÈ ÇpëÀìiV䆸T“ïFiƒD%¿h-èçá#êMmtÖq4 B[…i có銩dŠtÑÅ)+M2JÏœªþT茟 "°2lti4d‚a6• ¬ ÆrÃåž•¡m4¤¶WrÛ@Ç$*9ÿ¶³ýÇ;hÛöGvëþ…U­Ö¦‘~éçuÆ6x¥s¨Ì3#Jœÿ`Rßé:Ì9gY.Œù‘6à}ê¤G,Œ@$‘ØõªŠŒ¹Tg)N; ¹·‘¥:ÈÇ I7~”߸_F2at~.?­ VA€Á”ö&¦Šy™‚—:bCZü—É8·Í’$R+,‘(÷gúQVα€Ë¨mç‚EIg¤Ïp¤îDAVÜ*+"î[Ê;çJÍÎ-ÓfËâ·$[»½ Ï—rO~V\B"ÿü…% ¼§e<ªJ¤¨:ÂóJYlÞ"x,°£ µÁÿ‚¹B”œŸóYë©e— <¬ç=*1!3!ÀBNù§â¾SÍ\5Á –NÙˆ@Jú/#ò®]bh†É ƒpë¹9ª›mSP·â¦({0Ïõ«[{ûù¢ÚgšznU85›ƒ]¤i‰ôÚ7 rÄgJU”óƒS2F¥¼ÒƒhÏ‚’òÑÃ8|ž‹É¯sÑï¾;'.ª¥ˆ$“Í n‚æáo’k•@6ˆp?¥<<’L¤1…Gów¢d‹xY†:'ªö’ÖîLþµ.¬oU¬öMrIÊžààóSiøŽHqpÑG¸çsòØôÀ⯣DŒ< ˜¹Q¼Ç*ÞoR3Xëm•CDyR/¼^ÌíîÈ8ϱ£ü˜’ãÍ@üM$—2*Wn}hv’G`ŒH¬·¹vÍV4ºA²MUÌ`zâ‘®#R0y={ÕsË6íl俤ø¢äìûg4œS“A²,2vŒŸ‘éS‰p˜UÀ«–p#ó#Ë?*&6nFy÷¬öš)rM÷…nNËH.m£'xrÙäb  à)ó30x¨ ôJ€Hª’ã8¦±ØžZ,%¼@HXžÙâ‡3ËðtÀ¡ÕÅÀÈfQœäTÑ,› ³ŽäSؼº$¯)‹.{š) ÆqU—·²Úżv'hÝ’åO´¿y±°È\Õ¸¶¬É: ¸6´¬zñŒt¦=ÂÚÄ¥®à‘HÎäŠT¸iQÆHmƒqàš=&W…ÛSd/Ó`éÉÅ5×È™ú„ZëZ,±Kºp>qñcŽÝ*¾Ç ù»Ð GåDåÉߎ{šlžµ•”‹EÜ0€>¼ûfw¢Þ‰ŠÛÊ"…@;7gÛ9­âñ#–qÌùe‡Þ<4–Fk­m®¯HÙŠŒö$•ãüÖGXÕ.o%Û ´VЯ!aiÿ&´ÁLBk»HTÅ‚ þ#—ô©ÓL¹ p!mÛƒ€0{¸ä„y£9áÉ.£",õ+ØÚE·™”/,Ücêi“¨,BW]–î$êνM½uK`®H9brÀãÔü«ã7S²Ž)f¸FµÝ²S óÜòj±j\¥·¢2é!»–V[i}â5¼¼…A$è>µk>±¢ØÇ,¶Hà`;ò>u—,…PÇñ80n†šd £8®‡‹2g:Íãâ:ãRo6[˜a&q‡*:|³ÓŠu†³um ¶…Ù¡•FS8ïš­ˆ#ðœSd^ø­|qjŒ<’Nìõ_øÓJÑÙÞÄ–¡Ž7ÇÝ’1’ÄtÇδ~:Ñà‚XÞêeeÉIBñQžõáÙ| Žž•Æ8ÜÃØæz8·ÙÒµ²K”{ä×–zý™hf·Q4~\¶·;‰Ü~zûRéZd¶Q½³µÃn*bB¬ùÊñŽ3ÓŠò_ xªûF™Lo ÛøŸä{UÍïÚ‰eŽ8 œÃ³†unX{çßšçz\—K£¥j±Õû=cG·Šæ_"çM–)‚’ñì8Ü ê1úÔÖš^—$2ÌÏå2ÞdÊ«Çr1Ž9¯ Æ^'Œì-´Ã$rO<ÔÖßhzôm–áHØ+ ~ƒ­KÑäô¼‡³Ðµ%t¶¹ŽáQÂ4jûÝ8®0GZ ×­ÚÚa÷ˆxІCG=¥feñf¡p%•nž)de16Ýã<äUDR]IÄ]J3Á !-·®*á§’íÐOU *«5‰a+\,ÑXZžÂnsëÚ‚Õ´5•ÃlÖòc%?‡óíKáÍ\ÙÝ mCqV â Ÿ_ozÜ\Å#ésHR)J.¡`C|½ΉJXä¹%(dG‘Ígsi3[¸Vü.9ÚA¡ ”"q½eáunŸ:ÜþÑš0êmÕ·’düÅW^>–à™ì­“B‚§ô®˜çµÊ0–‘®S(m®¬š9VòÜq2/Ä®^µÑÙÝ­ÌnOfH/"uQܲõ>•`täÕØÛèÚTÏp¬Jí“ÍEŽ·¥ËÓZKÅT¸%[¶lsW½zÿ&^9'OüÝé©uvóزM1bŽ8ùä÷ªk„[[D’{{†-¬>žýê÷PÕl¦Ì7:WÜ%\+´?ÄGó)íUúµ¦±Oóí×;V1ÐûzŠ0·iK„<±I7Y_o®È–Ùµ³4Øó ûb–GþKxÒXŒ€d™3ù  [¢C*§'Ì?SWmjéKwså<£p0*•%}w(#?ZéȱÅðrâygvè͵‰'plzc[Ϊp_ö5yeu§Ñ´ # <ÏR’1ŠçÏ9N[U$o†„-Ûe¶¡®ÛZj$x¸*Ì$A‘·"´~“O›V¾!ÑÑàUýʃ£œdw¯8ѯ¯WRY$œH²Â@ >ÙëZKU¼»±”Z[¥¨PpòÎ?íí\y°ì¨ÇûÚ|Ñi¹j*|qq¬E©Ïk½£ÈÏÀ8Á9ïšËÏqu1ÌóI#{’M[Å,ãP ²¦ÒÐÉКf­ ù• ·@Aù•è`ÉiE¥ýN F9e¹ÆOúÄàð .3Èþ•g°F>|²€9 †×”N‡§K©]}ÚÒÜËœåödë]/U­£‘hå&’e `?Ö—p'­XOóš5òQ”ëƒÆ"¤¹Ó¦†t1$Pà GgƒÒŸî`KÒLªlc$ô®æEqp²ƒo&Xg$ð@ëKn •‘1/Àø†*¿qÅûY]Y]Ž*Hç•mcõæµ÷~,#¹W\㎕Qo¤YÎåSP‰xÝÅdµxfž‡>7ÀÜ9ßi~Ìö«=—7›fi¥šÓ#r àc¶Þ*°´´—eó09<2‘óÍYÃ$óZÊ,C¤Q( ãì;×6iøx!“øÏÿô¯žX‘§kk_+ ø•È9ìH®ÓI¹È¸‹Ï[a8ß×=?÷ší^[û«n1¯¸Á'Þ«íä´‰-^à0$Œúâœaº»þá<Š9)õýƒ xî/Œ¬±#y€eÎU;uô£5F¾^pXÍ¢°Xä·;U›ŽFh-6öÜ©´Þ„Æ6ÎO˵\èš‹Éj±¶žÒ½©f‰Â(QÇ|ñYd¸»®`“\>Ê?N,éºHW€ õbzôúÖƒJ‹DµŽa>œ.æ`« ÈÛT9g#çTš´73Én×vÑZÆWj:®w÷ÎGzÝ®,K^-¶É‰ä¯·úTµ¾<:½’ù+-5ÍayyumÝ0k†YžWµ3Ðǧð­Íj¶‘RÖLÊ=zÖ3TûévŽú-‡Ý?½h#×ì–Ø<—L³ó•‰:óÅÐO•÷›ñIŒ¥i…d‹­¶NwŽj÷Q•xð289èzS_#h9äU”—°ÊÛ£±·‹#ž `ýMF×·’j¨þ =ºW ¤ë£ËqØF›.¡m*Èöo:Þ çëõ­=–Ù ómôÈSø„³nåÖ±-ÌÇ _'œžMaª\I’AäW>\{¹|Xr¸º¦Ñ¥¼ºñ*!ÖÇk?Ö³ú”Z­Ñ2\ÚʹXñùâ´ZjëAWï ä¶~Ubз?Ï®+‘eXŸHïx|Ñížu.Ÿ:`u'¦áPIkt¯°ÛIžØS[pkÈI‡dゃŸÊ³÷µã¹[Òò`m Ä©•wcÍ)+TyÙtñƒ§ØÒÛTâ†SI;GëWúwí¾ ÑBÉüÅÇ•R¬–÷?º3ìÏ?öõ© ’òÙˆ¶•ÊöÇF¢w.èxšƒáº/uxâT ql%ãñƤ‘õª VÁÎÑ$Ñ/rS8?]Ø^ê2 éò·ýʤQ7V\ÆKW}°Ãë\ñÉãásƲóú2¬-¡åR[Ùƒ?¹©­µKdÓ”s×q8ü諽 † Î{0ÉúTQéª@óؾO9ýz×O’\³“Ã’/„oy§Ü°¸”ƒm)µœœ­Ë0õÍC§±Ü)=Bîãt:|Æ\(ôÏúÖ2”WLê†)Ért¶^ha;³äs‡éëQÚY%´á ‚8\“õ¢ÌçoLûš;ÈägD™¯âçäî“TzÎ)0ƱĊ>b£eÜJ¿=3Qù„ò§ƒJ³ß]ðœ¶ÁŽœTrñš‡{®H!xÆMÛHÓÞja˯Ø >UJD²5Ùg<¯¸(L·½G#>?y&Ñì8¬«ê“¾ ñI©F¶áxx“©5_>­q’­qç®HÎÜ`v­ã¤“0–¶ÖÝ_Elv–ŒsÑÛªn<@ísäÀ© yÁ¬ô—),1Àôè*K9Õc!cÌ„ðäð>•Ñ4b¹ää–²R|:F»O·kËh¦¸vm­⭔ɭzÖ5íMcDó×àn¡G>Ƥ“Äw› ™r[ŽŸÒ²–šrfñÖãHÛ(EOª=:b‡º—OŠ1$óÄb1Ïʰ¢îPC=ñ<ŽºáŠ¢hÝ@+óªZJí‘-u®°“UÒЯ•qß°¡Æ¼%@%eƒ †XgÔVV9!^6 ƒ\ŸÅ6¡o=”­iäœFŒ9\æª-îdòˆPÉŒ¶Õm »´ðí”;t¢U<¸oÅôéV:E…Èl+ЫŠÉeÇHÒX²Í[|‚ø"âÂ[)á½¶IžœeëùuÏj³šþ fÚ-cFr€Ë€}=ê¼è`S²9ccüJç5 憳E²+ÙÓÎåâ¦R„åwÀÔrB5\…i7rL’Ï5ê29;Q$h>ýsG]ÜM aÖ7“íëX{Ý&êÄn ‘ŸÆŒHõäSì5;Ûue[…(Üù9ö­%§RùE‘ KÆHÒ=Õĺ)ar<¶ýj+9ïò°„ò$ GŽÅC÷è­¬¡»[c ‘°Ä&6íBñö,öŒŽs’¬p~B³ÙÅQ³šîÆEk­[ÜJ±JeÉÈve÷«™¢º­¼r“’¡¾%ãÐúÕlWšë[´«6æáAÎÈsLƒRÔ¦½û«ÂAاëòªÛ'Ý©Æ<+äVгId¬…»ß*ÏÜÛÜÚÊËt Ø ¶¶úD·V·¯§¾@ê]‰*cÔö«›‹[m]˜ÎXðZÕ8:—&rÓ,‹tx<¤°ÁPÇ wï]êF ŽœÖ¦ëEÓoIû’zqÒ«gðþ£þ謪O#;OÏšëYâýœ3Óä\•aœ…PU}vÒª•oŽÕ4¶W£,¶ïñ¿*_Ù÷^Nÿ+hƱŽÉþÑÐå8Û}}•–w÷7Ï4%¢}äà‚{Œ}jçVñnªšdv Ro1Ë‚J¶xÝ3Ѝ¸Ô¯/`#RrŠK})ÃO¸¸‘eãÊÌNÌqž€ï³ŒdÓ’0Y'ãTÉ,—WŒÒ0ŽI[sã’{“FÁ%Þ™/›ov€í²¿^ǃVš‡‡µ/Ù´ú|°OVYN ž:ò V6‰:ªµÓAøC"äàz¯\wÍiº-sÑ–ÙÅþHg¾S3_AÃ6¸[èG~j9­À&¶¿U,v˜%;Y}·t?¥ol8o.Igd!WaŸéPÞé÷C½gIÐ(Ë(ノ£ÛÔ⺌š¶ÓK~Eå¾ Œ¦3ò=êûA¹•°¶K™¢š3º/+Œtaß]Wʵªýâß#ñ`¦â;çM·žÖ;”’ÕæÓ.•¸’?î0yþ´N¦¿!¸°ùšÎiZ ÛiEÄcgšánù=ª¾m6â(|ØÕsÏ–û“åžß#ZIõ¹Ò$²¸qññ$ð'˜29è9ˆº¹¹‚)"@]wå[yû‘S‡|"òm‚¶h­lâ²€Ý_!F'!ZŠKÙµ AZ2ÆŽ+?&¯s3#\©‘‚ãñcô­w†5M"]‘Û.JÒËÏÏåO6)ã[¤­“ŠqÈöÅðª[½Æ›w)»ÜY@Ëà(8ÍQßéZµ¬Lóéñª£a 8÷ç±=è­f‘-µX5ˆ¥‰ßh2…9ëŠP,n.DÃw ?²DÄî03מõŽ&Ò6’»LªÊ¼‘DÊëü,‹ÕGz²Ñ/ÛKº[x®QmùQ#uÎOÕ–›xDŠp‘¼£ö#iÍæ@ÞU圲r£g®@ççZMÆwDB‹Üødz­ŠÚL.¤–óǘœœ‘ÓœÓì®ãŒ®äg/@ä8ã•os¤jòhéžÒZ¾zá”^:U1²µ¸o8ÎÈäàŸ%$Õ3G¥q$ƒNŠîÒivl”&ŒOlü¿ÅWC§nø’LX¾>µ=ŽyvÍoc²:ÿ `ô©µ¬(–x‘â¾1ÿ5O*ûŒÞ7/ö„C3\Û›y¯bQ `®uªÕŽ;™¬vöìTp|Í­‘דKs£O  ¸HÑä`W ZdÚUìM.ëY1Ëe2zdâ¦;{L¹9ñh.5ÒÊÈá$,¿Š7wŠŠâü[Mn° °Ü¡àçÖ«ì¥2J©2ˆHqï‘ï]wy-Ôb™¤RIPßÃÎjü|òG‘íà}äWwÂh<â~§ÄWn‘®¡kôQÎÆY·¨¨ïÓd–Óp¤‡Á*Ž{«»‹÷q#j“ÜÖ‰5Â3nùeõ¦…Z“0td‹ OPFA?J&úþïL´ÙVðÝG¸™±’Ãÿ·ÓåU–ÚֆѸä´ûÂå2რ{ëÒ–âí­¦·+’Ñ«ÈJå$>£¹ô¬e M§'gL2B1j*€uRK¡»¥IŠù„óØUžŸ{¤O§™®t¹æ’Žl˜1fWÌV Z_F…µh•‰¦0\UÍσQÈ'$޹Ê7Ý(‹ß Ù>ù¡–XH>˜4 –šíŒh\5Ä_ÂçN éVóJoã/îd°¬j¥—QÓõ[`À4gáÝzÇ\Ô,˜'˜Ò(ãcÿJÒYjóZ)KÛ›0 `«¶â}ÛïP꺶ƒzŠ^ÜK!ÿšÑ€„þuªÈ߯Q¿èCÅ·å ×ᎲñU¤€ ˆÚëÔUåµå½Ì% •ü-Ò² d¶±S¨2–cþ* ïîÚ2¾iHˆü¡ü«9`Œ¿Š£hj¥æïúcs+ûÉc\¥€Q©ÝhS†ûËÁ#ÿÚ21XƆYrCsÜšƒÉ¸/µQ˜ûVÒ¥Îã<š×%[KÎ’–n™bÁhÝ+Uµ´˜<j'ù }xª¥³ºD"hZ2N™…­>{5âêþ8Àê"ÏøýkyF SvsG$Ó´’6¶ÚÝ´Ä‹¸ö#pº\) #' ^}-Õ¼3“ldix'ߤ“T”2ÅçlB:\ÏK|£¶:ÚþFêV·‘AhÈCCIgáee猎+%o¨^Á&c›+Û<ƒVöúìÓ [‹fêÈ8ÅCÃ8tiN9ö;VضwLê½âáüê¬ë°çs•±ÆK ¼mGO…|ƹR‡œ¿•SÜêZ3ÌÍ÷4o+­^;¯’lS—þ™$k´»Ëv/u¨´ÀŒ#ŒÔ“i2Fʀ—1œùÑ_4Íä6Üó^~ù7vwøáT-´[@°DX*Œ œšs6Öæ™óê+˜¯sîi._%:K‚O4³âô¬·‹#•®„žVÕQŒç%¾•¦E,FÅÜ}…ªÚÜObñ,*¥² H­pËd¬çÔG~6Œ;DWnü©=¨ÑA}¤“ëÍYE¤\™öÝ-zä°ãÖ‹²ncèãÜ×£äŠöxÞ9?E0]€àžØæžUcy¤‡ c­h,ü? æeŽvy P .OqQÏáÛˆ×þT‰ ègáHö8æ§Íì¯ þŠXǘB bÇð€3Ís¦´0q>Æà…S“õ©#žçLŠFڱʜÛ“×±¬ýö£qw+;¹Ë}ëLXç‘üxCÈñáÏ—ôZɨi *ڽ䃴…ÏÈS!ñ$Öá¾ëeg·òóýj‡õÅ/CŠíZhW<œOU;øðj-[Ý7ñ.õoÃar`ò]ØsžªÛo^»Î|¨œpcSÆÑßçT×+™c¸¸rWÏÛ‰’ÙÉòpsøœc†¹a§‚UVÍ'ªÈݧHо»{%¹•69åÛ¯ZãQÔ‘ ©uç‘ÏÒ«-uk;(¼ÐbyOI$:þ}©V÷M˜ŒÞÈ¥—àø«Žž¹ÚL³Éÿ»Ÿê[E-ö ª²Ì#òFœ’sWÞ²’Ææ¯=3 øU'Óõ¬Íœñ¤°È“¤èì¨ñ€Gþ”ýfd·ÕÀ…Y@<ñò¬å 7µpZ-ÒäÓê5»Ë™ì–6ÀpuPh–ì$¹¸œ6ḶÜ2û¯ŸÄD", ÉƒDÛø‚ÖhÄ2FáOÂwÃó·,U£'玵ä÷º$¶ ID¶r?îÇ.‡=Fh‡Öf±‡îRK-°UýÞÈð1óäWL´ñ’^7gÜÿZ àÔoPÌ÷VÛ#N¬ØÏ8žhxçÔ[ÅçJ[wÀ#pO¸¨{åÛ4ÿN.Ò-¿jtÈ¢‰š1IFÜûd•mqk¼wöÿuk™BŒÀ÷õ=…fç,Óï-¢wBQèߞçp÷¨¦Òtù ¼¤PÈ3º'óŸæÅCÅÛ¢ÖY.•› dóLA‚—Ç § ÙëŒÐó‹YLzmÒȲ¶|·á8ëŸJ©µ¸Ô´¨¼›»48ø[pQVVͨÂA´ux!²=ù+šX¥}Ë|2¾Å¦A.Ÿy¬]»-F0ù=êM=4íF'š1!òFa¸õäý)N‡aZJÀI&ÿˆIËì÷ç¿Ê‹¾×tè$ïq¼vÇœq‚EWü-±rŸË¢+1©${® HÏ,ðFzô n"¹û»ÎuˆÑ–#ÈÛÿ¸ªýoYÑ,QÛùj½@bCÕdwòªE*nÜëha›åðe,°\æÔÝ:˜eŠ[“–3¼$ÏÌãUªIwµ”÷¯3 òß…ËŠÝä!<ýÑĹUõùzSä[1"-å=pÇýkXÁÅòDš}G¾sدjÜo€Äè»p@ÁÖ¦•R@ZÝ"$6JˆðGÔõ¥K ©ß0[HåŽ[jž+mÉöb âø Ó/ô›'Y¦ÓVæhÏ®ÙCó¦kºÅ–ªŠÉ§[Y´lqäǃŒt4%Þ™qlÞ_8?•Aÿéñ±/ròޏDÛúŸñY¨AËuòi¾imª@³,/"HóëEM9¹h°ª …Wç½%̶qò-Æ{4ŒXÿj>ÃQˆ  *ÂO ±0?AšÒRâèÎ+–¬„-ÝÜG|»n!Y›?Z’}+T·Óä¹’(¶£g÷qôâ¦6—R8™ˆÛÔ3ž (Žî9IK£c8AŽk?£UìÍJî ìHð0çj˜¥´d–c® •A‘ïW,ŠÂþ ?óaP¬~c¡©m<8·3ýÚÚæb¡¶ßR1ZKKedåšÓ^è–š}ÏÝËÜ4ƒ9RU~Dj¾=þóPX"±YrûA,žzõÅRÍŽ\±<9cÐMLjàž(`µßÀ$˜þÔÕÉ ¸Ü¤AlùÑÚ¯€µ{)1Æ›Ûð3³ÛwJ©¼ðö¥a# µh€î°ý+(Ë U#wû˜ó(²-BéUö"$n:ìÎö©ì.BÛ’óHÒƒ•L|$|ê4²p»¥Ý$Y(¼ÕŒ:5­Â‘exNÈíµ¿^µ¤¥©˜¯#•’hítEÔе±9òÙƒ0Ï`zÖ¯Nðþm8•RwsÓ|‡¥e Ñï#°”~ß5}e&«oo¨;ƒúäÎÛþ2;0$¿”m‡êöWŽYÞ5¦à^ÿßõ¬&¯aªF¦K‰¥Ÿ¯!‹VðjöÑF¢ë\àìɨ¦~аw- ‘sŒÆ²Å’x½Y¶\QËî,“,pOΓîSI›eÆq•矕z а¹”°Ó,É$…çëCºù<• Ï €WrÕ~¡®Ù™±Ó5‰¡ÿwa7§Ê¯­4›qYæ,@ÁUQƒõ5,Ò8B N9Éèi«³ÌB³ž¾Õ”òʃ|zxCòwìÍ>0BÆ “»ý*¿R±¼š¶Wø‹'Üsƒ]ÖŽœ¹^÷µVÓ¶oÕÔHÜmÜXª÷äÿŠ Zñ:^©x#á0Jî äg‘íW̯®ªØDÖü`†›Pc 9õ¬Æ§áÍwD»¸D´g‡f ËÂATùvræs]Ò Mzؼ“–TDÙÁ=A¯åV–º%äWæ!B c K;d’;cûÕ'…ã´y&³žwˆó)$®Þ˜ÇRrx­v¦mì ³º³šfŽÚ_1š[€ zà*2=²ÚƒÝ&›nŽÖCMd–BÜFÄ!ÈšƒP3Ü£É6,­;l€;󞟕¥ø’;·c,в´lŒÁØcž=ºzPºŒ³K,ðC;7îÃì²W¥qÜ×?)òtqFJ+;›“$z•¤1d¥Ÿ8^{uª×ð­Ú—¶˜©ÉÈ qïô¢e‘^YL±Ì²ÆLž ô óëVzEÝÅËùPFñ3.IXŽÐÃøG±®Å–xù‹£“d2q%f:ûÃrZd—á'äûõè³­ÚÛ‹Yf®v…Ò[µ³R&ÇÅü`zzÕGˆZòx–â:HIwXÎŽàâ½"]vàÙÜÉueæÌ¿…˜ò·cT6ºÄv·)tÚI;HB>sÔüõ©Ç¨žíÒ²òàŠŽÈÊ‘æ3M;¾I8õ&šÁŸâokµ‹Ø®æ7Z[#c|±úš®bÎ2ª‹ž6ª€+Ô†©5ühò¥¥–êÝe,VòÈvª}jHì®IÇ”Àwlp*Á¢u’1"¾ â¦xn'¦Œ³EéïŠoTÈZeìÊÍ‘’Ct±í9ü\Ö†Êþ5cQ檂nI&©àŒ`4©‘ß‘š±¶Ž‹fö„ç;Ž8®\ÒßË:°­Š‘µÓµÛ7µ0]DÁ^0=…Mq¯ÛC£É÷HÚP‘ü#Ž=¿*ŘVGßy àœ}Eaµæv†%›9>ß•qKNµ’L#OÔ-´í¦êÜIÔ%ã#âhÎyûÖ¦(ìïd+ ”+ ƒÒ²þ/Òâ´ÒìoâP›åhÛôåWZeÜšˆ²»ê«Xw#1•g™\Tâo‚[›„‹v\®2P`¢¥ÓR KSa •¤fp[sc8í¾ª?9{hMWSÝ•ÜT| w5Æœ›¤w8Â1·èŶ²º­7K ýäRð‘í󬹻¹›tó0fãžÔÝOTºÔ®§¹žLÍ1ËûûT·(Ù+È9æ½LX6G£ÈË©S’¾ˆµu<ÄŠ(Òeˆ`HË‚j’æîæäþòwaž™ÀüªMVÍíd-^å[ÓØÐ9'½{8qcQ¸£ÉÍ›+“RcÆ1Šå%Nåb>TÁÐæ»µtR0ÜË­3^½³Àó<ÄôcZÝ#]·¾€‹…ÊľŸ:ó€hÝ*çî×±¾r¹Ã\yô°š´¹;´ÚÉÆIK”z’iºL–ïų)`tœU†—á¨ØL t׊o¬Ž­ēޒS ÅÓpp8ö_Ý-üÉO¿Œd‡BÃ{÷¯Mõg¶”{¢ÎÓKð…”ÄlK³aF1Æï¯¥E ’Y]½ÕýÌ_vºÍžEÜàvçxÏ^”Û ^[I“ï¯ñ2ç§jÒ[ÇàÿXI¯rö·>€±Œr=8ŽÚæËnýc¡ÙÍ©Ïom¨Äº382A ó=ÊÇÛòÍfõk Þúhá¿3Y+:N2@aðäççLºÒmcÔÌ7mt!X• .îxÁïR·®î£/Ii’${™Â€{òØÍtÅí|ÈçxÔãÂ!´Õ¼=§ÅpÐÚ\Ý+²ùpLùULs–Ï©éíPÚx›O²[˜­ôHGÈle‘G`Çš¨ŸB¼·¼6±˜®þ.&Ê‘ëRK¡ê¨‹²ÔJR­œÒ±û}˜ÿ¨ºUE—ûÿ®G‘ÙÉ·%!³êê=hkxšyNÛ¦w9˪ ÃvÁŽ”$z5ÁÔÅœê!ŸiÎqÅYøgL6$É2Ï'.HØ0xéÞ‰,P‹ir8,¹$“|šmnúÝRîýÌyËoŸÓç\ú|jq± þ-ˆ?J·W¶ùa€—¨àóíÍ1á Çrmõë\¾JüË®y+íí•˵ÎF Ï5A¬h“Z»\A™£cœô)[†`ËŽ€bºDLm;³Ž:ÕcÎàÉ˦Y#F ;yçmÑ‘æ2¹ô8ëOKÝAL¶³_ËLw2sµ¦>¦®5}ïÓÙ¿•7$äà7ø¬½ÚIÉŽesŒ¸`×~9Ç'G•“°¾K)VQr¬åâQ‡ËÇ¡óSØi¢8Võ¯m#‘NìFHöÇz¢³¨Œà ? cŸ•5ÝŒ–"Ö#$r²deÛÇaÓéMÅ¢¢ù-­‘¯I¡‰É•ä†?„°ÕlÉ-¥ýâA§iÜΣ{;³¾ a$߯ÞX8'µKg¥ßÄ —p41çâyn}¾µ)%Í•ruH’×R»1ÉjT‰Çá&L#ßëNŽþÖYQ.ÔŒ¯Ç·álú†úÑÂÆr’ýþ(dÜ Š4-Ûœ¥ÑdÔĹxÑvcgsš‹éÜý²Ymî%·VÓ5ià ãc³=‹zUdúmü!I³Þœ$Gzž¾• kƒ±1Z˜ Lç–(+»ÛĈ 6ȇq ’[êiBnø6žÕ²¬éº’£l´™±‚LƒF[è7—*ÝÖ|lv“íŠ.ËX¿’27Þ!?‰XgúU¾®e‘„v’ùh:ŽOÿO&Eè˜`Æù²+\II%܆ÃGÜä|Ž+C xÞù¾!*€Ûs)#o˦iº}Á…ÈI&;~GÁ¹â´2Ê/í㸋QšÜ¢gl€¿2 rÏ6Gìꎟè3Oðv‡g ‰ãDd`UÎáú÷ªbÞ+uo%%šß?ÄÛ¶|Àæ“—òn&ŠåAÛ¶I9?"y«m#R²Ó,.¶G-Ì’6ØÕ™Tdמ½x®vßräÝE/â3ö¦¥`·)bÏhÜo•·>£ŠÇkÞU’Iô·RÏ—'>ÆŸ¬xÏÄZl—ÎÚ;X$c™U'¥c/üK­_nuŽIÈ^ÏÊ»0cÉÜ_§.5Ä×$w‘_[ÎñÝÛ:ºuR½>U,NVÔ¢ª¬e,Wš/.UÙ¼æmß‹qÎ:& Ü{Tˆ%!rv¹ôö5ÖÓK“Š2R|vÚ·«•@‡À}裪ZÎð[[Å"³¸ß!£ê9¬÷Ý'WÁ‰ÃЊ2ÇOÔÖæ×  n¸ìk9c‡fØòdº£Ie¥Â]Ï~ŒÃ!I#úP:þ»¥ÍiåéÉ*ÎFàIµ³ì}*§S²çY'†Kg’¾Bª~Fƒ±Ò.î£*UQùg~•Á')to,ùÂì}Χ%ð)rIÊ ßŠ°ÒãÔ%y.ô‹™™íÀ%!»ñïFéÖ)i+0i€w&¸·™¼ÕÞn3–e $vÅ2Å*Š zy·s`Z6­â; ®d à¥Ä€úò+M'‰4Ù´äy­²Ý1d¯¥SÌ4ÉçN¸‘Âáp ÷«=7OÒ eyí7¨çzÀý; à̱ËäãOðzx%–?+_“=«¿‹ÿÒôÃ# ±üð+7¨ÝjVr¢Og÷W^rÑr~D׸­é+i¦xˆÀ1ƽ}è]FÊãQ£Ô!µ½B0‘~„VXÿRŽ7N<S\¿£eËÊJÏ :ž¢î®og€>”m¯ˆ.P¯ÞÌSÐÖÃYû9ó_}€{2Ç%· ù´ë³Œƒ¨^–>‘tZô¿JãmžZý7]íKÿbš RÂýBDÞTƒ z1-ü¢’)“íëZëxJ]ñèFäË4™5jÚf‹ªi¦{xÞÙÐmPr0Gc\R×â¿‚tz?þ;QÞJ¿Á„{{–`VS»…ÇëBM§LË$°]m-ÏÇñ ûVžæ+ë7+瘹<•ûÞ¡ˆ5Õ£eæEÓ§¢Ì×(ÁãO†eÒÂñ-˜ËvòŒçàÀ#ó¢tÍ*óRÓ…ÖžÆhÕŠ’dã±hâÛË™öÈ#<„^Ÿ­e¶Â7†À7ͽFsõ­žTט¬nÿ-á­YíƒI±ü[7ÄU\Ö—°eÄLÁIã;}¥lìuÝ=oÔía’P» ðÄ|«W—á^Ô¾p"v8Yo‘Rj|²- Á3È"™·±ÈÌ0ÞŸ:±¤hƒ§JÝx‡ÂFÏM2[=»Æ¿‹wÀGËj±í¥Óì×ïpm·(;!ý+9åµiBÓfalYç2¬M¸rvä}i’Ç1I“ žŒ2*òÆîÚîAåO.îüæŸ$Ì\+’rN>¦j<Í>Q¯>ŒÜÁ´ª~ïØtÇʇ{BWr€àvî(ÍJ8¡¸Ûnþ`#ð¯%jd0†CÙ†ë[Æn¸2q]÷0BêRE^{Öƒ}>ßÝEÒ¬nîD ȳó"‘Šäç?*Ö3’]™K[èÑ4€(ÞÙóÍ ÷ÖHÂ(؉Ÿ¦Þß*.X‹mýàAé·–¡ÓD³IŒ›FXg8çó®H8û;&¥èk›ˆ 23ýâ–—ÌüCØ ¥¾†îEž–fÀÎøÎAì*×W¸Ó´µŒ\y³áSq#çVÚFÐ DÃpP1[Fn JŽyANã}ÞÔnn A%³KL°Šå‡ø«‚«NHÜ:|ê o4-5öÎò]L9)á_lÕ&§®+Ú}ÚÇÌŒ—rp[Ú¨A¹&½LFÕÏ…ôyyõqƒ¨+fÂ÷ÅÖò®Ètˆ’<ÿ’MmâVÙ’Î0¬0ÀÈô¬è=êXâšFÄq»|…tþÛ TÑʵy›´ÿÁµ‹ÆvÍŠ} ñùuX‡«°£,ì­!pû̸àt\×.LáÿcªŒÏù%ýuÛé©lu hà@𯔠wR$†EˆCñnç*\\o¬  ~Âàu?:"¬g¼X/ƒÛïü2Dpì ×"[W<JOãÀ}ljnÛNKGºFwùlZHuÛ•´ò–e…Pb5Š,Ž~¼R(òŒH àóȦ¶h#cb3ÎOzÎñtkY>Á5CY¸·S=Ãl`;†÷Å up#ÅÓ‘×k·CFj p–“,1ª‰‚½AíšÄ̲¬­æçx<ä×^› ruÁɨ›ÇÝ».^öÐ9 .à;…¤}NÄNÀw £úו޴Ñ8^wô\aP,Iy>•Q’I'©>”ʷСLï• Ý¼g·Z·³mrÍ$™[µ¸È#Û»%æ6Çʵv6ÈŠ¾z*±øNrHùv«Ñå´Sw¬“JÄ@ÏrZå–½GŠ:aú|¤b`±¼œ´®)­w†>μóTúvwu#…±ü[D›KwÈõùSX¤Õ¾ z”¸JÍ+¾åy“ß@#=nOåUš³xz[vÞk– íÚ¤m?3UOemÏŸ$ºN(­åÜOÆ{«{zV“»3žg%MEÒ×lPiìòC´²F8àb’hUŽ%W=G¡¤Øž[áÍ-ÃOJIa#¶Ò?tÔ’áÞj—Ä‚îF9ÛÇ;Íæ´yV“»îçô„ZÔA4®x¦yõ§Á÷háwÂű’¤TÒK„[“—p·E”0øsЊ³Hí ˆAuùÒþðοó#×±ãšÆH'»Tó"òÓâ$œpj;맺¸’îY>'9'ûR¶ø%$¹'Ôm.,픬†êɰCÆ2}{©ö5Q5Ú¬måîÀ_âŸj•n±ñÅrèêAO‹¹ž×PR Ggu€yRSü§ÜqN*»/Êë‚«I–b0 ''h>•gg-Ä£Ø{ íJ+û+ûk‡·Ì!+‚’0#‚1M‡Q[ˆö²ŵÎ?/J'òå. Å*ø·É}÷™¢tf@wrŠ2=búÍ·ÚÈ¥öŒ 09ìsTÏm;O À”Ü#áÝŽ=ÅNÆ/0K”ߌms‚+j;^ïeš¼·ãP¿Ž3>;•Ø”JÏ 72Ikl’y™^CŸlÜ ©#p«ÁÀ'·ô¤II%X32p9É'ßÒ¥«IvK ú´3Bѹ'(êŽüⲞ!ðo™)¸ÒÝIóT·ûUÜs‘„3¹NJñŸ­uÄ“[9º¶k}Œq°äc±4cœ±¶â,¸ã•m™Š‡ÃZƒ²!8<ŒUŒX@yAa׆ÉéÓ¥h§¾±·MÍuPAV?!ÞŠŠehQ”’r¼u¬õ9Z1†‹fG[´¿7¿ñ½‹•T·Ò³Ò뺤ìbÛÀ]µêR¹tÚi ñÞ‚¸Óì.†Û‹T—øNáÎ*ðêãçm$ßÿÇ*g'‰µ4nhäQÔc£Ð|Kopûe"91øpO±©Oƒ,no]ËŽWo þuËöu#’b’qŽFT èœô¹tr㎯¯²K™îÅÆû}’F,¼p=ju¹žDÄiœœGOô¢ì¼)yiœ|ÂQ0w .¦¡ŠÒ8ɹ'žkÊ#ÐŽ÷É ›þù½Oðþ{ñÍ—³Å &Rªn‚†¹™-Þ 3ÜZÈ ùÀ¹á½?*šÜŠOo³Giª,w ©,»„£øO÷úÕͦ²áGŸ‡ÿ˜ŸÜŠÃË:BŠa¸XÁê@¥Cs©¬P”.è ÂÉžG½sÏIžŽœZÙâö{„Ö×ñ,‘Ê$Uî(­xÚÈ€YÃ3. ‚NwßÞ¼JËÅæÁó9lòêØ'çëW—8ž÷MS§ZG5Úœ1•±ù ó\y?KË|z;aú¶+—hôà’2ØÎäÕ>­¬Yi’Æíw¸ÁÝ’Ÿ\¨¯ Õ|Q¯Ý†ŽæúXÓ§•À¿ªV”¿,图Nk»éîlóõ?¯n[qÄõSÅ:bo¸¶{›€çkl!{dóŽk7ãMJÉŒZu´V¿wnÞO¾zVN7pÁ:¯òž”M­ÆÁx#sÏÄ ÍzPÒc‡«`¶q^1á7W½‚ClnÌ$²».uÆM câ^3%­ËÉ,QÊÞbž$ON7…ó¾ˆSg¡6“ Ù+G 0ÿ¾îõDÖÚw»nfšh‹~“Vz}Yw#Ü3¢¹ø©ÜA¢´Ûio †ÝUˆn}ξ@ix¥VÙjq郦A£˜‡ìëkx³ÀÁäþté`7-o,`»AÆä˜ê>†¼Æ´²iÒ±™,²îÂã·¥k´\­ä‰+ZN¬€ª(Ë¡rÞ•Í“K5Ì]›CQš¡š¯…-¦™åÓ'+‚TÆÜ…>ž¢©_A×"m‚јêx­N§âéÓ*GF¡ÍPÍ®_Ë!rã'Þ«™*äàùA¾’kvšFqÞnIÚd8,Ìǰ >ÀÕ…ÜÞ¾†òÏÃþ)yõK8t¶‚ÚÞì ,Ë›É €pF}ª¯ì«JDñ¤WZµê 9íî,å‘Pæ5ž‹ÌÏ¢—ûf­4_²Û]>ââûÄ +hÝÖàÝG8€;­ñ–8éÐdœWt1aJÒ³ŠY3Éím#&‡ã?iòjÖÔå°·ÎécŠ'¯ sŽþëGàÿ x®÷MBšUýâÆ3»0ڸ݂23óµêziº»½ðN©£Ü,Z^™Iy(#K'YXÌd‚7z|@Ž´&³¿®øG—Á°¬p nþeŠ[7§—& ($gøwZmo%ÇÿC‚Ù+o“ÉuéåÓ½ÓõµyJyë,eÔÈ$ddvȯOðüޝm$躔B(ÁušÕÃ(Ú'Ž…YXz†¸«­º7Ž|UâO \ßÛ&%üZ¤7 Ç0·Dc¯™vøƒ^oãÏÞjÿgúÍë^µ½Åï‹ÌÞLo†X…¶#ëµF§ª8!(öFLÓŒ¹Fý´«™ug°Òm¯.äDIE©W T6Jr@çƒÜ`÷§ÚøföüÞÛËÔ7öfê8^ß/ƪ;ºóÒ©üI©Ï«ÉâmÃÚ•±Õô‹•îãˆ]@– ¯30RVFV+žÇÒ¯µsQÓ¯®Ò{Ñ5Úø "n!Ÿp–_:5!~#ÜŽ¸&”´ÑL#ÈEðž©/ˆ¡ÑgÓ¦³žDß—‰²ª%±Žœc>¼P0—X:AdŠðÈbh‚2°ë»=1ƒœôÁ¢ü­NÑýŸDEºïTŠO2P1å§–O˜œZòß ]júgŒöx‚Ý­Ã ‹;¹OÄð bxZM£©]û¸ëŽ+?ÛÆ—?üà~i&ø=y¬ôx¬>ñíÑ€ÆïMj3·Ì#š"ÏýM˜ö¬õܶ—z‰ÑoJZ_%ÇÝ·HÀ}ÛpÄq·=úcš©Õ¼/}«‰u©ï­æûœâ–§+F‰ž.w’ÑíBÞPMù;qÆN{QÓÄÞ9™¢Ô.dŽÖÕåo/rª¬K#“øI údÕfÓB—#éŸMpk|E¢ÛiºN¯&‹¬Áª\i@O{ZÝp…ã}Ä:†#¨SŽj-[ÃöRi³é‘ê6gÄÖ–&úëKkbFÁœÑ¬™Á'8Æ2Í ö ê¾ðÍæ‘áë;O÷z6IuMMõKi.5& ûµºÄ¤ü(?ÄÜôº’4‡íKWûQGÃóXMukp³¦f’kFAÈ;àŒq´“Ål´ÐUhÁê&øLÇGöaeâ ]2Í|Lº~¥¬B·6/dÒ&Ö$F]ãir§kuÆk+àß±ßëë¨\\ÜA¥ØÙA;ù×Ý,‘DdòÑ2 6É裓Ø`Ó†¡¬ø‹Á^+´¿´MÆÎÄê³4È<‡´a½Iܶ¼s¼b‚ð úoˆ<[©k+›K³a¨m~QÄH1׆É+EžXª>Œå§†[—³Âbð•Ú¸7,qu-´Ñ á$“Â^!ñ_º4öù>N|ÿ<Ê3»?ß/Ðç=±Ï¬ZñFð\ ›ÌÜyqgÊ\ã~;àsŠƒ]ð¼~ð‰týMc¸¶¿ÖtÓjTs}3I"¢±! ºõã-޵¦“W<’ù³=N’áðG—Ùøs_Òt¨5ÍSÂ:”z]Æ;éíb9ü$1Ïo^Õ¯O x‘¼96¡…µ4ó›G ±• p6Ùô ô5ªÖàÕtÏý¤ø·UÔ-æðî³§^E¦Î.c‘o ¤}Ò8ГÂz|YÎ*×KÖY¾Û¼1çj!­“A¶…³0òÔ‰89¦´ÔÅ7vNšU<¯À¾ÿ{ÕSƒ‘ÏŸ¿ñí¢µÕ4Í;u˜Hí§éöîí¹Nzf¹ã(¸Ú A©S›ÃÞ%0ÖµjÐiÒ*$WfÑÄdÃnÆ0{õ%÷ƒ|Em¢þÞÔ4Hi'fÛ¶‰‚m$`çÆxÍz¾¥çÁãoøÊîòÒo jUÂZL·(Ét’E¶Îåm¿Ý„œQ’Å­áy¯õD†ÑÝõ†oNÔ@·¼EŒµ–9-¹B•;†qŠN<ðRª1z·…5MãEÓO½óõK%žÙ^ÝÆâO0‚G2(ÚHí¸U~£á­zËTMºÑoཔf8Ùƒ¸õQ‹é^§ÜYŪèsßM ¦÷Á‡OÓÌ—¾Tmv¤o‹ÍR<·+¹3‘ø±W{ˆ¯|)m¨izvz«Mj <È…bw± Æ9%IÇs”°Å;]0Êê™ã®•©éW"ÛQÓîlnˆ“Æcb§¡ÁíT÷v—NÔ1¸Æ3·óewv^àÏu$— ÌYòßÉÉçÜ’~´F»} \y'FÒ¯tüóD÷âãwLc¦ÜsëœöÇ8FUÌN‰E> Ï€4·³Òe´‡Qi¯Ãâ5·m¥„…Œœù™ÇaÁÈíCê_e×Ö¾Ÿu§jð]ÜãÈ‚[R^߯[ŸJöo ÞCà¿2å,î'ѵH,î$`©ÃË2ÆÄž“ŒûÓü# Ɔ4­~h¡¾>'ŽêžUf†›dbA;U˜¯^»I®¸åÉÖïþprË>öž){ös¨é6jÚF¡¤ÿò¦¸·dG8㊻û6û?“ÅzŒÐ£_E¥»Ïq%µ§žØU$"¨À.ØÂ‚FMl´A%ðÇ£<—&K»IY\<¤NÛŠ“žpzàã5'‚æÒN«ªË£Ø^é‘>},÷¾w˜æ#·"`új^fÚÜËðÅ'µ»¿ k¶ö·WšV‹ª_éÖŽÛgû›)Døöä)¨ÉÇ­Wéž"Ôôë­_Jðþ§umn?}<<‘&NX p9>‚½;öOˆµ/}žkÚ%êC¤höð%ôr±‹GI™§.¬sñz|@IáT’ÿî{,!ý™k«ÞIi{§êkey¡G$™-*¿ÂP¯Ä8<3Úª£5mÙœóM:J‘æú–ƒ«Kà›ÜZÜ›+Û™-Óì…Û‡-Œa‰ z•oJ¥ñ„õÍÑ/µÍûM‚爧º·hœg#ÆN+Ö¼lít/ ]¤¾Ñô¿Ü›‹€§ ò|©Y3¤Œôìk)ö‡§¡x;ÅÑ_øgHÓaÔå‰ZêoKvú„‚`â[t,Ûˆä–8±ÉÅo‹[¤èÇ.i(ÛVbõ» cÃvQI®iZ¥ŒR³Ç \ÚIvŒá•wÈ=E¤iþ%Öl.u+º½öŸj¬'º‚t',O «·5½ñ/ÛŠ“OºŽõy%F7H©åÇ'k38Uà“Œ š¿°±×µÝ'ìçRðN·m¦Úè–m íÃ^GéW?x•¥žUc¬Œ§8;€Ç=+ª:\qG$µS“¤g¼3ã›Ý)õ øNîöÆÐŸ>á,xÆNæO ¡ôjº®©me-ºOs,¡bØÞÇ «Ô“Ú¶¶–zž·/ÙÆ¯ámfÌizíÔgQÀ–3­Ü’M<ŠÄY«GÄ1ž+%´jÿïµ ‚ßÃ_ïih¤óãóüÑû¼ï #ÁÎ1Û9â¦Z !¬Ëð©Åªê·PË¥Ý[ÏhI½1ÆÛcPÁrü|?œrqVú§„`Ñ|e«h׉}e¦¬&æúÚÕ•aY[sƒ-Œ“Î+m¨é—–V¿iW×­e¿ÚÀ­ännã7‘ºÉV$®Ð}ñëƒ~ÙõK?iú΋¤\Áew¢Ëô‘G8ÙªF`Œ4„ÿ‘ž‹ŸÂN9¸Ö%]’žç}ÙZš?†´¸íDO0äobw¡YsŒsQ>‰|ëptåÞr|À‡àeê8<ÿZÀXêQ[βÍéDxo‹žÕucâY-äK•i­°sž„ï^dã’þÎølKºÔ4+F oqÖ“ àòGÔ¡º°›NäÛ´±–Ú®€Øï[ÝwíBÔ´õ‰´‡’åÅ!Âî=3À¬å–·mv®Š jýÃùÖðœÒåó†9>&~ Úªèç7)äQÖב8ø¾Þ•e>Ÿ›Ib¶™ã,A 䢞¢³÷;l¤?x´€ðž¾£­h¤¦GŠQè±sdዸô5 ™?#ðóÚ«¬¦±¼BËc´ã-æNTLzÔW{­Ô)0 0#oâçFÛtÉIÖã@d±¾ˆÁzå. 9‡ôaýÿ­ v¯jÞP˜¬Æ:ƒÞ©•Õ¤%¤l·ÿj²¬‹µòrAÉÉö x’Ê^V[ê Z™ís–³ ±9ã×Òƒ’bg*ÎNÁÆ3VV0ÚOùÝĹÀDŒœÕÉR²"íÐ.Ÿ,Ñê€ÆÙu  \ X»žW{’Hbwe·sÔÓí4Ù–ýZÆÂèÜ#]Àú÷¤1jÛÐjö:x‰pTFÇ=>%úúÖYíâã†ef¶µ’=¦È‚x?%ÌpGnþZ”®Ð20qEj¯kkvêÊèp27Ý®gkU¶™q~‰¼aäŸ þt åÍ´„Ý0lHp l`ÿz_¼\D © ˜~¼·ZèvùF*0öhµ(§†ÛJ@wI ²'ãâ< |ê®m6Idg°Šw Ã!BÏÜTº&·»Y°{‡ÞR\:ÈH>µè7wŸ{•“€¤mðúg­rO$°ðÑÓ QËÓ0QÚê–[g³*ˆ¸î)í4kæ`zî­¬ZGÄL|¢˜m«’ƒ×?Ú¢Ô| éïuk«£]K´":Õ‰ {úÖPÔC'-Ñ´ðäÆª¸1­#D±Êãž§4ë;ù^è Œ¹lzT:–§©[ø_r íQSé×p]ÚùsªÄñTþž˜ÏzÝÕ_fQm¾è²–åãUX #~5MÀ|êæï.ü¿¹ÜDª§2¸ôñTLˆÛeV†'ƒò§ÛÝïD¸Ü„˾ëÂÍ÷º–…æ]‹›–“)UŒãh#©ùÔ:e†¥íoou „à¢ÈôôªðŸˆ|#>÷OirÆí“änD€ç€A5Íͯݦ‹B±îX¬h÷ 2îÏ''iéÇCSºKâÁí˜f¶—måvÝÐò3òäQãO*ŸwUßüK9ÆOô­D—n-ÿã.m#¿T(ó66:téšÎÜ­…îš%¼•ã¹bêòG>!í€Ö²R²ù²s¨yh˜´Hû8\ ûƒÐü©·WÍÑ£\Ž †Ûò'Ö«-´ÉímÕ¡ÔC§òÍðúÒ§¸E€´w2¬nGàŒç“ØŽ•¬d£ù2”7~ -d™Ô,RÈ[ðàšv¹¢@¨¨éåÝœ)óÇ÷ª-OYñ4væ=*ø2ªÇi : ÎÜÜøªC%ã¥ÌÛ?æ |àzàU8<®ãÁ1Ÿ‹‰râ]>óîþ\VÉ$PƒqÛ#½cu$»ŠÜüv—9!ñ“íZÍ!¼C-¹¸(¤ãs€S׉‹Á­uesq!óǾ5g'y>‡µta“ÅĨÇ7úªãhóÚZ‚… ‡Qد$“µÚù…À:ÖCáž6~ð×¶Jª“Æ_jbäÙ]Y\Á¹±4$ï]Þ|O”¨àxsG‰;°8ìüõ$EÁ-ÈþŸZ’ÔÄ“˜®·˜Ü âõ≰°Û4¶ò‰Á*p'ÿ´Ò\irO/¡›¯ÔV/"okf«’M"²k{€OÄQŽ7c&¥M:ÞâE[Y¶HzÇ&äz~x££Ò.f.nSÿ«àâ´š^Ÿk; t«i¤Œ‰ŒD|@r9ê~T§›jà¨i÷>QEiáBp¯q*AŠCÏÓjóNðž ó$¸–âC·d`ìß‘Æ3EÛ5ÔW+Ñ!ݽF·ÒŽK«–òÇ÷iU¸qÛ¯öç×ó®ij&ý1ÒÂ.è>Î8tˆ"ÓPs…_Äw={Ô’éš.¤Î#•ÄîùÞÒœ‘Êý:Sb¹n Ò]€»Ûl£2¥2âîÒæy-î­®!$oŒ{Ÿ=ýëžVùGDZ\WÞ½´Ìª ±v`=zdvªi­ñº'L•ᕇ­]NàG°î¹`Àù“ Š1Àâ©5)læ¼’K«ÄIÄÉ d~uPs¾Aí¢ªÚK«d1Áré l´=c=ºv?*—O²º¾–E»ÖÝÄ`ŒŽ„ŽqE´AžQ³ŸŠfå¾@Ð6šÝäây-Ñ/*¿åZüšm´• Û{´‘ÿhOg&ÞD2xôÍ,·vñ©¸Ì­œ3·Sò©öªï¿IúˆÞF;™pp¤óÉìhïÛVè¯ Û5•ÉbÛ° ìOSö…i.šÚ K»Qí-ä|˜ä\>\JÉêP~ÍÔf‚Þâi¡ðX!RÃäkUr×—ˆÆ)%‡w¯³2IÁçŒ|±MðÝ‘{+†k*e\­2†f¶úv­á=‰¶ÿàçœê—?fKÖ>ìí÷eÂL¬“ù_åÛÓ5 Žæ;Ó%Ûy1) ŸaÛåYwK¼´æ]d l„Æò=‡÷ªïÛÚåŸü;\\FWøX¶EnñG'(çòK¦{%Я\vª]N(îÞ&{Yáé.1ò+««ÈÅÙídèí'Q“zZê!Vág‚Oðkas©É>‹c¤É,&ÞÉ¥x°¿dÛ»'¿àÕÔgŠ‹àx¤ÚäMÖåÓ4Ëû;X-„—ј^è«yÉÆäS `ñœgšÏ3L.Ò¼änIcŸë]]J3i ŸeLJuµÑ-îmWHÒ¯mn ´]@Yw.v°*ÊÀŒ‘Áç<Ôzþ³y®jöïÉBbŽ(Sdq"Œ*(ì®®«ß* ñÆ.Ò*eI °Tÿ7¥2×t(CÌÒ±lîn uuþ$5òó|>fxê}«+¬Þ‹íT•lF‹µl†Åuuui¢·š¹5W<³… ŸÈ{S•̉Á ‰”žUyoc]]]¬óbù:×BGÄOÆ:z×h Ó༈ÚY5³¢f»{§ëé]]YgÇEÙ¾Ÿ$£5Eûë6Ö·QkZEº5•è+0Éq׌ÖIcá]JƯ‹É4ƒvöo‹3Öºº¼ÉüW¥“äÊkÞÒ¼çKx•rŒ­œqž´ :tÚu˜9!¶€Euugå“Ufþ8ýy(öÂÞà #÷<ŠÏjZœb’ìć”Yÿʺº¶Ç–K‹9òáƒíÅa¦Üß[Y&­Ý…? ãÓÍhµo èº<ñ´úÏß&@C,íqŒOö®®­rä’}˜Ã*衽Ö|=§Öö–¥Ô þõçÅV?ÚûI±AK|ÿË\°ÆuuzZ]<2GäyúŒóÆþ&ŸH¿²Õ­U®cósµ%Uѽ¢ÿd"˱îÓ ×’k««Ì̶Ií=\ktSf‹Z¿ƒXO´[Hm­´ësA”Abì~&bIf$ó@FFÇɶsй=+««žSmÛ6QK¢H¦š'Ã,$p{S<ë‡$ml7ó1 fºº½™M¾"vFäwþ•¯¤I­Àl Rbç}:Šêê¸IŦ‰œT¢ì¢²×nì5F‡T‰•BˆãBôäcÖŒ:‡ûÁ¨Ån4ÀúzÈ|ÙÝTº½>Y®®®ÉÅ%¹wG$ÛÚúñ/‡¼=o‘4ý’0¤LK9õ?QxwÂðê7íºmÜHFQÎp>fººž<ÙYª³e¨Åy3ÛHw|%¶ðG±®®¬qdl×$Ðû:þêa 0JÒ3mPWéV÷> ¹ÓlƱ5½«0øœŸ¦Tú×WTÏ$¢ø3†4û3FÕ$ÛQ_r»ä3N(?\Ô´÷xí¬LÙ° 2:pk««©EIr`äÓà6M[ÄwÑ›”KƒŒ9E“Éä÷=h½.ËÄZ›þîÖtsæÈ "ñë]]XÎ*1à¸d”š²kÍÙ-kÖ–P£ÎÊ`#ŸáÏqUkkæùŽä.ÖÊ⺺¹£’MrÏBXã¬vRƒC«*y«ë(Š!Dx\Üw®®£4Øiâ™·V‚úå˜q'¯à9­›®\[ÌÑÉ8‘8¶C]]]SŠ”y8ñMźû56µm<Å­™„±`ïùoy¨Ït˜WŽr£ÕÕäåÇÍQëâÉ)cv­ê*tâ³X­Ûv€dB3úÖy"ÑŒ!î ·³¹„·ysƒØät®®®œ}Óþ@—·&Í.`&GË ¬Y1íŸEcsÌB@ÇR¼‘ò®®­ã´ÊSv‰EâJò­¬Í;*åmø‰ÅkAçšÐúÙ2ñ'à9æ´>¶L¼IøàAçšÐúÙ2ñ'à9æ´>¶L¼Iøà¬nÛ\ÔÕ<º¨TúvñêšÅfPN"ö Dã{fÍŸÔÿÂ*òo2mCÔQÛL^A \ápâCޤ© (J222=¤deù›¤a•–³"±h™S÷[¯ibÅŽ®i‰¼Ö_ŒyŒÈ.Å ÕC\Í17šËâ1‘¯1™Ø¡z¨ @ºFYk0ár+‰—õ?uºö–$÷HÃ+-f.EbÑ2þ§î·^ÒÅ‹\Óy¬¾#ó]Šª†¹šbo5—Äc#^c2 ±BõP @€ tŒ2²ÖaÂäV-/ê~ëuí,IVZÌ8\ŠÅ¢eýOÝn½¥‹:¹¦&óY|F25æ3 »/U s4ÄÞk/ˆÆF¼Ædb…ê €6éee¬Ã…ȬZ&_ÔýÖëÚX“Ý# ¬µ˜p¹‹DËúŸºÝ{K,usLMæ²øŒdkÌfAv(^ªr{XSM§sj)4ðœDDHqÂJ¢Q‘‘‘«iègkn”*«¬Ó2Íi×,ͬ8{êž²„{ÄjÚ[«ŠGû/Ш¯s~™MùŽ]÷‡ æý2›ó»ï ¯s~™MùŽ]÷‡ æý2›ó»ïÊêù7é”ߘåßxroÓ)¿1˾ð+¤a•–³"±h™S÷[¯ibWwÂiE˪TÔ³ºy¢žEhp ¦‘d‚½ýq³fú;?#·¯+ iÍQ@mQI£G‹.pˆpὄ¥-G DDDJÚfgú,ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/01stefanw.jpg000640 001751 001751 00000024127 10546014104 021774 0ustar00fkfk000000 000000 ÿØÿàJFIFddÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄ:!1AQ"aq2‘#B¡±3Rb%C$4r‚ÑñÿÄÿÄ"!1A"Q2aÿÚ ?ù|pŠº×lÈ'GåÈGt’áÊ`”ä; (G)v@ O3tAAû¥øBÿ”A+GMÔ ¢BKû,ÔZvQÈÙÓ`ðB}®_5øî¢z˜{-7jÑHkœ–“­5JÖº¼†ý¶†'uVLÉåýR;~Á :92#Œ|ÞÑûª’ê°2ÃmÇésöë6IJÎþQ£ÓV]^Cak~ùTåËš[êªàXåÝ= '½”¹6—Ò& ¹J¶Bí |vBùH"(-*åÛd Ú ¸¡°á¸¤ÃÆÉ“¶é·ºG‚ƒAIÃp‡å’‹tHî€ÙäACºH!@wòî’$K„À¥Ý!ÊH2®Q­¹BÒD"Dy@o²_ð‘'Ž-Bd}w$*ÓC¶) óh)Új]@£ÚÐÔæ´¬ò™ )X4YDl€V´ĤNÈ3mÅ(·Nn‘hM¥å yC¾Èl~v¤¼¦Õ à¢ˆ5Ý JhÏt‚V‚GþÑå4"8@ÑÝ’„_Ê…!Â#„ -©á€D¦HB ŽÉ­At;¥iy¤€´ªÐ½Ê@¦pœÛ¨ÿtAåGØ­’4öNAh’Ù6ˆHp¡´ŠTˆa(0¿¤lN#Â{qÉýW_Il!oÚ?ò­²Ž[g짆ô¨~<‰E±¹Ü4§¶‘½q =’òq…näïi­RïÝ –Ã)8 Šq@9H%Ý$À¡Ý‘BöBÐ4 ¢Dl$ Zhá"E ;l€¢d% Ø¢HI’®å{RiÑ&‚x…ç±ýÐ k{„@7Âû#`º6€ßtZÒJµí´€ Ø%²UlNqÝ=°P6§ßt=Ê[¡"he k@á8B4Dhú ÀŸ¤@P ö$žS€ñºe¢H!¯; vM&Òêx(ÛÙP4͈á‡u{YÛVÉ ÷M£a)HPü#{ m3#Âiˆ&÷DEîˆF·G ÞÁ \$¥»Å~S„YpFÂÈ« „wÝ=­hà–ÉYqॿ½8ü%gް‰˜â÷?‘±°rÑû¢’Ý-‚Ú¶ÿdGI®pkI%S›*öaFÄ›^.¡¹¥™Li#r³ß+ßˉ œ÷SµLZC-„o²4o@¬ñ°ÝðQ³ñ‹Ö»z”nÌ’Ï û)X5Ê[=$ndƒšS·<ÔÚTz4Rs–š‘åFóWEL°£aOSÙÞÂ{/­n’‚ ¦¿kÝL þJÝ¡UÊwp‡t}¥VœEZ\¤A"€iOk Ú•,ѹò•l¦l^Sƒíh$ iícˆØö§Òì€q»Þ‚»§¼©ÃI„àÁÝ-„lcjÅ)Vßì‘ÀH @ga²=>HI+¤À NÛÂŒÑêå"‡VÅ6¹²—Vۨ䗡¶ƒ:¨n«äOѳ*ä¹À®I´¶©:W?“j4€ZšnœìÔáñR­3ƒI‚–,I^,0®“KwH‡`Ö.•;¾"]¶Ý+’¤®&->W¸‡‡M‘·µè8¾”ÉÈ%Å®hðV¾/¤>2¦ç8ëËcÓ^{V ÓÝêsv?KÖqý#ëÝ¿JÎO¤,E±UáO䇸«Çr0:#ëÚ¨MG…麗¦gĉÍteíüp¹,¼&²Jp¡ÁU.Ñã\ŒÍ¢TB—A›¦‚ Œõ~$ñÞZíˆW)XˆÛ+ع6:^ ‚ §cjï„•9ìô¸þÕQž´%w(þ@Sé¡ÁOh<„ytA°AˆIFš8 ¡ÝŠp#²·G«dßÝ.Ba âÒêQ‚•¤vÚ’ÀHEµÙî|&”ŽÈöA€ît) ÔqZ¥<…Î p¬J6«QÿNàÐ|öJÕãÀåÆ\íÕÈñÉ'e£‰„Óò}tÿ*Uµ|=4ËF¾>Jèô¬V[ci4S(k}¨€[,=/;¹M½›uú>ŸX o˜I ³0œDCu¥†KŽÃ÷\ÙäìâÂXÓá­4{ î™wÀµf(ö;,îN™„:&Ú»é!Üj(lït§jñC,1äFY#AµÊkþŠ‹-®~0©<.Ýì Û„™mß²¼s±ž\QóÆ¿éíKO‘ÁÐ<·È.?3opõ0ƒö¾ªÔ`dÍ!ãb¹œ¿NbÍ+®6î<¶<®|ø6É &ÚB€‚ /k×}Ç5î…Ý'è/;Ö=;./Q šð¸ç+Ÿ.;ÃM«Žþ¸¯¸Y’0±å¤Q îž ŸÐÝÉáiåÐí½3…šì©Û¦ ùÉüLöçà #¢ǖŠJÙÜ9þ•ZYü¤ÓÊ®ì[ÖÎïûB{\HñJ¿¼|F@äÒ–Æ“ƒC”Fê6Mà§uIå1£…Ñ¢ÄÑ{§Wò‚;º ~èAA–þhZ-ÝÔ‘#svÎÝZ‡ÛÔOòž" ¡Bʶ@u ihâÆm‚M4+/Œ{}\Á1ò6=ªÉD÷4~¢{_ XÓqŒ’Ù§¹]v›Z)«›Áq/ iÛ½.¿M‹â9 î›ñãmhBÒ­§5Wƃâ6Z¸Q†Ëk¿ t»ŽÂæšà+02Š8±\g²µt¥¬XÆŽÇ-¡mlªc B2(]ª‰¨¤„8nª¾>›¿!háʬ„y¨ÎΦžÊ›â±uº¿‘`_e\©9Û1¼…Ìk8PäÄöÈÀMr»<ØÁŠ\æ£MªÇ+ t»¸òÜÛËåÇÆéÕ;ZÇc@oSÒƒY†K°Yù OînÍå4XàҶׇláH=€xOa '{{ØûS3*ÿP¯Âˆ¶ï¤&ô{'(Òë$8'ÚÏkIáÊf=Í$8’—Šßda'ÝØì…¾ð=$<”è" ’á1¥Èíëqç„¥˜1½Nu»°ð¨ådÉÒ7 P:WHð\TªF›dêÄöÙKÝ} ïÊ©ì¾ë[GÅvF@kA>TÛÒ°›®‹ÓØ –º‰q]¶ Œn(¬ý+¸° Ýë^ ]Ç “<¶ô8°ÔÚÜ rüFS‰æÕH^V†ù,äm¶¼ =*aØT¿Ìñ`!²H/»‰¨cÎêŒÚ~53$°°°«q½K ZöØR qÊz°ü¥U—p«¹‡Â¼ø]ì Q¥mG ÁUÞêhYÈÿuZ` <(TQÈqÑY´ðo•§=´•˜GJ!× ê˜z¢xú^M—)ÀñkؽD:ÚBóM[£,ƒßuÙÁ^oÉí^"=±föN$ˆÝ·@ÈSƒUŸ×¹î?IïÊ‘°XådÐÀñºÎ'𬷹O´ ;£cj) •âÈÇd¶;öâ9áKÏ+íHé#ªéBw$´P@XQ%’þ6 äÚ#¯±! =“ÛtÇ4·g)îWê%;žJz£h€5ʾÓÑk,“áVöÉs[ˉ ½kÑþƒ”á3?.6ÙMk»9_ÛN>;ÉuE42±ÝRFæƒä# lð½ÃXÑñ3téat,oÂò,Ý6l)dc¿KIxry7åàüha°7ávþ€¸ut×’¹( žW£z[³8ì<#’ê'‡×C{}«·¤Õ*ð ëºÑ‚-ìð¹þ€u5¤j9”èÈczŽëW6;b-(aÇ#€Uc¨Œ·\iÓç{íÇÎÊg:\µÞëšÓä.ç V»äû©òôü,ˆœÖ²3c~ë\rŒr—éÆczÎ\Gt¸6FW ®£Gõ†h§ÓOå`çú7 ä¾"ZãØ•|oL»ÄŸ;žñúùOoHŠH§gTNJ,ˆ¶'……¡C>4Ñ8ø#²érÝý²ÙãméÏä°—ò t_ÊÑ{,ÙLsAØ,¼w[—?”Úsú“ˆ²ì2ñÉ'qÒ¹}kŽ¢ÒnQÇgüîׯô·9µÈ ¾Î°Òë÷þbðIø€ºx{p|‹ôÌÉ/$px¥\»déÞI vUÊéqèæÌÚGßÙB#úO©ñ=¼Or˜^îßÊ“¤";ô[FÞ¢wG¡Î;Ú” FþÕhm…=±(í¿)ÀÐÙØö·è!e$Áãfö m|¦Z €‘º_ðûHÇ©ñ!sn à]ø_Aë9lÇÆEûPìм¯ü¬ÊÎÌ \q û^µ¤ifkËË_úð¹9²ýž—ÅÇXíÎê¸ÑG‹£#¬š#È+…õ†œÆà—µrõígIs±_0cx$r¼ÏÖ6!œŠáeŽå‹äÕŽ'JÂ÷¤gîW¡i˜â8x\o§XL›ñk¹Çpk•òߦ\ý¬ãŸ V V+º¤éo•­7õ…uŸYÒÒ±u AøÏphyúou½+ËS·úOn—ÏÉ·öSžÊÝF>“.§¹;@÷¹bêÞ³ÉÀ–\w@ £4ç4— ciïÇkÝŽê5Âá½E…«Ã‹©C‹=€é—©€š»Úø69]˜L,íÃÎeýWÓ½k–æµÝ>ägŸ¥ÛéZÃr¡kÎÄö\¤t†ãcKp qGºë°0ムª2‡`¹ó’ztñîÎÝN6@sÅlBÓ—å®[b\ý×AÁØç}éF5¬þªdÍíØT25BÂâwUu¼ßeŽ7T¹Ü|£–íøµXÓäËèí[Ô2±åÍÙƒ±YrzŸ$˜Þð_KGSÐß™‚œkž›Ô4ùÌÎÛ¾AZã1ÉÇ–YJèŸ$99u î¸M[Ú†©”è‹ZÒâú Ìy¯ÆœÛ `¼‰£DºÛ8ùr¶íFJ·c4äý4+¬ôæ mÝ®qÿÈ­S7€¢2¸…¶œûµç­S-Ù&‡YFþÔ}Iu’%²©´„‰®Ð¥~ɽ^4›«dm@ D”’‡y)u}¨¯í={ü ˜7f¸€Ç¸u}…îz~\OcK@ |ûþ8>)šÓóiÊöÞš~¬{k@²&æV½^±üzkzŽ|‰!öêšxhì¼ÃÕQS_Öw#uéyùÃ#"^Ú•¶Óö¼÷× ö¥sNÊe»Nws·3¡±‘—†‹®–7|-sÚ#¾f¸;­òꌔgí<^—tûÙt8á ãºç´Óð&–Þ%¸‹PêÂôÕŠJã…e’8ü‹Bn=@ ûq:šllªb«"&ft6œ9fHìŸ.?H®TB*úJ§ñãôÏvžÒòvüRÚ‹§`? L±­vVtÑ™&ß„Ža³1ÐÊîV”s¹‘ÐðªÁGp­¶+a$ìÑ]G-ê)LÎöÜk¨Ñ)˜¸NÇ®ˆI\[)õ¨Ã'cÏgÓG®^‹‘‰&3&t¦¸ -?Kn\·z#øH’ºK²¶O4êC©I<ò~ˆžef-+.Oý¾‘ÿ‘¥¶Ú•¤ËbSÿRV·ñº·ù^ãô)©òŽq<º¨ôlfòÂ%[‹/ÓIèy8èà–Oúq¹ß€¬Å¦eÉÄ.—^ FÁ;¬vOCʹ˜´—^æ7÷W"ôó÷&'ðÐu”º÷F‹jhXŒÝÁÎü•S^ÆÆÅè¢k\M_uµÔwµêwn1Ø”_G=­ÿ‡º›°µˆÛÕÒÇüJúsÓÍŽ f¹®²æÚø÷GE;^Ó¸+è?ðÏÕ‘ê1ãÏ F*‰ä.NiÖãÐøÖz®çP‰¿Ö³$ŠsOò¸?\åf›ÚÂôIæð“$w^Yꆿ=À86°¹ðÞÛrzRÓ`™Æ»*X¾Ö¤ûŽvUöŒzš]Âi Ùt:l@–•‘ b8öZúkˆ«*k|+¦Ã»· ÅŽÖÀ¢ ×nhdukLlV[¾ŒÉÄ®«¥@ÂÐ?P´³u0IFéf¶gºËA®TÛc×k2ãµ÷N ¨‘8—8Z£6|yl}¶M¹^>V¥vY+I ­3xŠÏÆmùò¯îØÓe§%êi:Hh;ØRáä–FÆõ±ò³½Zç»!„êþ#Døƒ¨|©?QŸŽòªºÞ66|D¸±ßºóÝ[Jkž@qØì»üÌw1¤¶öì¹}@7­Ýо;}9ùññ›røðô½åÛž‚\iί)¥ÿkºzyWºu€…ìš\9°˜^Zf‡4AÈ8P¤àž”—­¼í|(ÛöœÞ5Èò£a¥(à Œ!!°O5ö˜~ÐpvìŠiÿd‡ Ë'_ÓÄÐÁd«\ê+qc·½žYÉÒ±ŸnâOŽÞ¹@[þ‹kÝ›l‘ì#»MR·®µÀ‹¾¯CbôÈç×užY~»oÅþž¥‰&Œ·&gÊØ8®g>Û¨Éf»eÓéŸÈ×9ª·ÿ\œv±ÿ ›uן¦ŽI`!méÑ‹²²p…0Wu¹‡Bˆá#FEÔЄBîžå6ÛAðœ"3庸hYÚÓkÌÉGnu&]4Æ£i#ÉUãcY#.ôvµvðhRr6ÙC»™Û«Ñ¹Žm0 Y²ƒ¿u sJÁµ…R*eýG  Ìê`.ÿ”øuCý¹‡C¾øQdÌùPQIí¶ﳨùOJó—ªÜÆ1¼Ž— ÕËÄ Âkì|¼çïÕ#ÔݪÜþ²ÆdA²J݇•R2·TßQc[Øãä+Xô7©`?]ÿ7ËdxÍ%€üÙtѺ¢xQ—ñXß.Ôó#¶»nËõödq^‡”~%y߯Nîa§tš*ø¯ìÇäMá\›åæÊ„ä± —<ÝrRÍ’ë‘ä~Ug—÷%wmãø;ê8í¾©[ûP»U€ƒÒë\ŸW•+& ¬7ÿÅ-éÇ Ãe)À…¢O À죫 ”ö¸U*ýhµöie¡dŽá¦”ÍÆyåMÊA%W´…ð;«ŸÒŠù´ÈKwMäŸJ˜¬cDý‹W°;ÿ!Gÿp…8kŸks^£=N`­—EèV´ÀãÅÏú‰”ZxÝiú+Ûиþ±·å^S|mx.²zžßþlî¹ÝLëÙñatúS.Râ¹Ýu†=~Oü€+Ÿn¾OòÔÅG…­†í¹YX[Ã]éhalQ7ºš#¤Ã$Bkµ¢7®iIÝfcÊ=’/e£¡ÉÐ÷*bý%Ô1¬:—;¡66Q€F÷žÀw]\ƒ¨3*hÃÚÞEvUµù_¦Lä.wLÍ,p5Dp´¢ÊÄ’‹dmŸ+O/LÓõWMÓâÓ,«è&i] ñkJ8Y zc`hy‡â¥#ë5ô®ãÀÆp*X‚ÊåiÉ"ÄdQD ÑÒåé'éI«fH@,g=Ên=4”ÇæºC{žêX;üø[BÜZ>‚”“[QL®#€¤Gô¹‘É|ZÚûz uv\äWvy |;ÇG½]½ÛÓîlвVî× X>²‹ÚÔ¡˜ ˆé%Gþj¾üGCn`¶þï­qØÍ&î.¼rÕzóÃl>pc R÷²ã´Ü²ÓÐîWM-°Êœ¦‘…Ûz Y]Ö¦”ÿ¬ÚðµôçÑ¥®ÛÍuÈwÙHckâp F7vW˜áU|*1¿Æ>6Tš~sAyöC¬…Óáú®9²ú@þÌcäò¹½N%ÐÝfÁŽö¸ îsnÚò|yÍ”ê½gMÕ1s ²!-xª°¡ÉÑôýBgä䱎-ë‡ÿâ—âãNq#a chìnÏ’¨WË‹#dq“¨Ø±Gð´Ö½<ëÁ͇¨¿¯z[36Oé!`PkG+Ì5½!Ðê²C ¦lGÚé"õžK]1” Áééò°ðç9OžSoq²NŽ s¿ï©LÒel2:Ö–^3pñ¤{ÏÍÛ [4lk_‘1­\'¯}@ØÙ+šîv`S7•Òy2˜÷G«µrì¿cŽ–.mÙ³»ýUû(¦‘ÓHémÎ6Jg+¯ã4áË»³<®åîþTNs.%öšSI¥$©¦5¾ð¼´€T r,8Âi`ª!¶é΀®`?é²^û+ Ø); ª žY6@ï²Ð#•ŸšÓî3òˆp&gF;7î”É5ÿ)ùuì°]›ð™Œ ª¹H}/Æ^ÿ•-‚6?Êlm=;¸)*ù¤LTuc¾¹\‹œEÙvYìÛÆáq¹ 锎À­¸ÅkúQ“PŠHœA/išxõ-)²FCƒ›{y^ÃMÚô@ëb';"Aí¿ôß•<ØnyGGÇä×ëMÔ±)‘ƒ‚´ôlá#G•­©á‰:¶Ø®>@ý73­·ÐNëõ_Ö»È+ò´°Ó'+—Ó³„ím9oภåž—2t˜Òw#eu•DùY0¼ž襱@¥¦ütü†|,¬Òæ±÷t¶KÚc§RÊÏ„Þê£|mÇÓ39æG’ý¬¬ÙáNhØR½’ÙôšT2‹OP°­xü{Ž{5Ä’Ö V4Ö´'I[ö*Ú†k0 sŽÔªG?5ʯëÚó0ð !᦭ËÇ5íQúŽYy' lЦ×uy3§xê=7ü¬`¶Ãyl‡vNA[3JiN( ”™IÍü§t”C|,¥+²‰¾)Ý$aÍ£h0€ÝÊE …S<|˜G•?ufýÉAÀÌŽÝŨ±€Ûrå6P&ŽÀ£ŽÒ+`ÒÔNJ’ÇØQÇÔ Ür¥£W`”‰K4uFåÇgGYw]žQØì¹mTrëu¯½ é›T ì¬áÎèÜÂEwP9§ „Àÿh;­SËé}N=O±9×;¸=Õ}kO÷þ+Ͻ;ª;NÔ#šÏH;+Õñò`Õ°Dð‘árç…ÜôíÃ)ÉŽœCôì²ÇßE®×NÎ1®í`ëšg_S«p²tÝFL }©¯§±)ëÊm2éê8S’Ö¬6öšÇ¸×y*Hvê¯)fðÉÔâ8 €×ÐG‘³’#_úNÊ–O\wPU<‚(ؤC`ê{;,ðz¯ÂÔÔm'³:)taw”ÎÈ<’ ìyhûr~®ÇÊA³”•aFáºp‘##Žã…Ékøf ²ö‹÷]k¾”y12VÓÚ>Õctnº-GFãì|vXÄèž[#H!i.Â$@'`¸Ð?"VDzW·†¿á„y°³'Pa-;åFYÌgkÇ}1š~=“Ù@˜„šhÖLÌÈãa0‹Xwɪ!úM +½ßÛ „"Ä×Ô |¡Ã¥Û)âwPåG ´± ,{nL£í>;l޳a1ä77õ5IÄülQB@ëº ¥t7ÂŒ{"\kjH‰Å§‹Uçp§&ÆâŠŠZ ; ØÙ£âkeˆÿ„…t-ê»Xq¸HO!m…úŸbëéÙ2ÏŠMïÊÑ o½îS ­“/лAèî« º ¡°×ò¹øš˺ßÑOöåN^„[•¾ÖHpºwe}¤É¸ÐPä³®\Óqd›Ù=‚Êö¢˜ 6ò³d¦¿nV´ÁŶvúY98ôŠûF"};Ú»Žñ#C}c‚©Æ:­!Sùrªk1—U<ü‡û©vM‰ZÝœbPû©!?©î-þ¤Y¸@5¤AT³p–ÒÒWb­6Ä´;®ÇѾ–—UÈkÞÓíþ¹xöxãrºŽü:ô¯¹ª5ù-ø4ÿ+êONE8¬d`e‡¢úK&†Æ,w¥¶0Œ:¡$WeÍžW+·n<~3Oš"Ý©H(¡£IÒ làˆ)®Ø”J]›h Ó•Ž„üvNÈ(âØƒ=âÁ*6—Z•DáVˆ Ê5‘ ¼ØN”Ÿí›ÙA˜¶ÇÚàT²‘Ð6º<§@¹ÔyDo¸á2Q`™ÔFÊBw «§„CìQ*7“Ût<î±3­¦ÂÜœëPe‚V˜{¸Ï÷E¼nš÷FÍü c'€a²:4¸ îœ"våJÐ:7 Á‡áÆËkFýò°ïÇe¹¢ÿÒ?•9z²7Û²ŠûR»nxR0–«p²Q²î>Gfd°›½‡…¨ÚÉ*)" ÷)cЊxž‚{«C¨ ÷MÆ4ãjÀµ*´!`ßÂí<°YîŸ$’Ÿ€+_L=@Ê–É„ày¢“ÁuÒaCì–ô‹YZ~&^o¶ÆžQ³ô·éú®{-¿ Ý}ém V5Œ‚ä½ £G€ÖŽŸ—•éøma–^U׆>1 Çmld‘Ž’Wcßdd†ÁO].e§Ç"ªÑ;…;ºã¥ì´p#XAß&‹¶u¦“á n»š~2íÁN~Îs“-Òì˜TËÐ=£’ñœéðÚê£[§Ê6)itqäQô þÞçuu*Y: ŽêeÝ?<%£šÓ¯ÎÊ>¢ÁòB÷ÙÙ(Þö³3l;-ü»ª™ øïÝT A±ü&<õ4Ì-ŽÊ³¶ô·•™Àí¸Q¹Ä6‚wmùQ4[÷@9­<Ði ¬pV Èßm—E¦ŠÆjœ½*/3•h‚«îÙjbâ¾Z¡²Êš$¶·ìžÜ&wÄ-¬|˜ÐH·+P²é vL\}¼þÊü:dLߦ֛c'”ðÁÂ[ ðÀÆ kBŸ¢Àì‘ƤöI?IliÓ²ë=#¦Dëxhëò¹¸ØÖ’ºŸGeòƒ+éx]Wiƒ²á²é°ßý°²Ys,-qVn­ôÔà«bFôÒçŽQ‚B×»)¯ú“™hx¿ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/08member_t.jpg000640 001751 001751 00000002031 10546014105 022115 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄ5 57s²TVtu’–±³ÑÓ1A!3Qa‘ÿÄÿÄÿÚ ?¶ÌŸ;DÅÒPê:R˜ª""ˆdD[OýŒÙnö‘XSµÑ²’ÔOÚ56°â4ÄÚ[Æj#?çoø!¢æ˜›ÍeñÈט̂ìP½T*¼žy­­“/~žkCëdËÄŸ>AçšÐúÙ2ñ'à9æ´>¶L¼IøàAçšÐúÙ2ñ'à9æ´>¶L¼Iøà¬nÛ\ÔÕ<º¨TúvñêšÅfPN"ö Dã{fÍŸÔÿÂ*òo2mCÔQÛL^A \ápâCޤ© (J222=¤deù›¤a•–³"±h™S÷[¯ibÅŽ®i‰¼Ö_ŒyŒÈ.Å ÕC\Í17šËâ1‘¯1™Ø¡z¨ @ºFYk0ár+‰—õ?uºö–$÷HÃ+-f.EbÑ2þ§î·^ÒÅ‹\Óy¬¾#ó]Šª†¹šbo5—Äc#^c2 ±BõP @€ tŒ2²ÖaÂäV-/ê~ëuí,IVZÌ8\ŠÅ¢eýOÝn½¥‹:¹¦&óY|F25æ3 »/U s4ÄÞk/ˆÆF¼Ædb…ê €6éee¬Ã…ȬZ&_ÔýÖëÚX“Ý# ¬µ˜p¹‹DËúŸºÝ{K,usLMæ²øŒdkÌfAv(^ªr{XSM§sj)4ðœDDHqÂJ¢Q‘‘‘«iègkn”*«¬Ó2Íi×,ͬ8{êž²„{ÄjÚ[«ŠGû/Ш¯s~™MùŽ]÷‡ æý2›ó»ï ¯s~™MùŽ]÷‡ æý2›ó»ïÊêù7é”ߘåßxroÓ)¿1˾ð+¤a•–³"±h™S÷[¯ibWwÂiE˪TÔ³ºy¢žEhp ¦‘d‚½ýq³fú;?#·¯+ iÍQ@mQI£G‹.pˆpὄ¥-G DDDJÚfgú,ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/08member.jpg000640 001751 001751 00000001644 10546014105 021603 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄÿÄÿÄÿÚ ?•ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/07member_t.jpg000640 001751 001751 00000002031 10546014105 022114 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄ5 57s²TVtu’–±³ÑÓ1A!3Qa‘ÿÄÿÄÿÚ ?¶ÌŸ;DÅÒPê:R˜ª""ˆdD[OýŒÙnö‘XSµÑ²’ÔOÚ56°â4ÄÚ[Æj#?çoø!¢æ˜›ÍeñÈט̂ìP½T*¼žy­­“/~žkCëdËÄŸ>AçšÐúÙ2ñ'à9æ´>¶L¼IøàAçšÐúÙ2ñ'à9æ´>¶L¼Iøà¬nÛ\ÔÕ<º¨TúvñêšÅfPN"ö Dã{fÍŸÔÿÂ*òo2mCÔQÛL^A \ápâCޤ© (J222=¤deù›¤a•–³"±h™S÷[¯ibÅŽ®i‰¼Ö_ŒyŒÈ.Å ÕC\Í17šËâ1‘¯1™Ø¡z¨ @ºFYk0ár+‰—õ?uºö–$÷HÃ+-f.EbÑ2þ§î·^ÒÅ‹\Óy¬¾#ó]Šª†¹šbo5—Äc#^c2 ±BõP @€ tŒ2²ÖaÂäV-/ê~ëuí,IVZÌ8\ŠÅ¢eýOÝn½¥‹:¹¦&óY|F25æ3 »/U s4ÄÞk/ˆÆF¼Ædb…ê €6éee¬Ã…ȬZ&_ÔýÖëÚX“Ý# ¬µ˜p¹‹DËúŸºÝ{K,usLMæ²øŒdkÌfAv(^ªr{XSM§sj)4ðœDDHqÂJ¢Q‘‘‘«iègkn”*«¬Ó2Íi×,ͬ8{êž²„{ÄjÚ[«ŠGû/Ш¯s~™MùŽ]÷‡ æý2›ó»ï ¯s~™MùŽ]÷‡ æý2›ó»ïÊêù7é”ߘåßxroÓ)¿1˾ð+¤a•–³"±h™S÷[¯ibWwÂiE˪TÔ³ºy¢žEhp ¦‘d‚½ýq³fú;?#·¯+ iÍQ@mQI£G‹.pˆpὄ¥-G DDDJÚfgú,ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/20member.jpg000640 001751 001751 00000001644 10546014105 021575 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀ€ "ÿÄÿÄÿÄÿÄÿÚ ?•ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/04rodney.jpg000640 001751 001751 00000157337 10546014105 021643 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC  !"$"$ÿÛCÿÀM€"ÿÄ ÿÄK!1AQ"aq2‘¡#B±ÁÑR$3br%4C‚áS’¢²ÂðñDcs&6eÒÿÄÿÄ5!1A"Qa2q‘Á#¡Ñð3±$BCRáÿÚ ?•x~ŒÔSŠ=§é‘L|/mºi‘ÂÓñùQ¾lôÍÜ~ŒQ6Å%Ð œPþ)?¥#'yúŠK þI ~´ªö¤KœÒ€b™ð-.Æ:æ­g¢irêwìëo PÛW-Éǵ龢Òõý9ï4«––5bŽ6Q€' þ<ÞúzÊÀœ}ªèîOõ§¾Z:í. =ÜÒLX0û þ•Tß‚6Ôw0­®©¬1]ÒÚä®OðsÈ¥$ÖµTee¹o,±þ6µ*<žIuü«HÙe)ŽO˜Tý e¼³û5_CÓ­ê²`G-º àç&±o®ë²ßGm›4AÎLG&š©òáFÀ!vþ¹´˜MNݰqŒ×,Ó^HöqýÓWÔ¾Ò£6ø ÄáqøÖnu­\y’4Öî½Õ Gƒÿ½MDœá³€E{*ΫÜÍ säû9éñÝÐúMgX…£œ¥“DTYÝŸÏéN.z‹Q·'ŠÚRFàTàdf“ž4hÊæÎ)¤lg³{`~à A÷/4×’ }Ñ&éýbïR¸ò§Š$þƒ>‡´~0@9¨¯Gq±€°ÃÛã©`5¡¦›päKQðdw¥;Ò@óJUÒ»6U'µ0êhtk™ÞUâ‰Eë@:òøYèéðî2L|Õ9d£Ë1Fäˆ%«És®FìF,r cq I¨>K+¦I#¸ äQgž;Tk‰!rÛ@Ú w<ŸÊ†ZËæÏ4 ¸y!ÞÙô'<~•ŠnBA›ËHî`3?.Àcò«ZB[ÇvD ¿J¨zzäß\‹fÉ‘§…1銹@ÆhhW ÎÖö‘¤HTœâ·¬žõŠÓJ„L0Ê)B£&—c…&w,1ŠæC<¨Xdb³å1õ¼ŽTcº»„Œýà ‘ ˆX6iX”¨ ÖÕê ¨õz½^®8õz½ZK"Ƥ– nb{ïŸJãëÕê/¼<ÐÞH®z†‰¢8x­Êsí‘ýi—‡¾4tŸYë ¤Ù »KÆæî#Çœ¶zâ,±Ý˜‘ŠJ–O ¤ðJà­#PC=Z²’kjõq,HÎx®gýµµúH.ª’Ý|ðÍ´C]6ëð’ Èæ¹öËÒ’Û®´íEf‘Åå‘7l„(ØãäsD»"|£Ÿ(X´ªsÚ›²œ–Ȧ·‘xÉ`Uq» ‚~”ƒ(nù¬Ž*2qœ(ørq»’Ö°Q[½a†F3X¯n~µ+òD­.#OÈVqžÔ¤(~,¥o,Qgø.ÅqüÞõ5em‰¶Íçfvúf´nô³@ÊÈ9¬‡©9®®,†Û$b¼ª[µ)ås[Åä×$süšÇðü½;‰œóÇʰ‘«G_zY^0…InÃ4QG ƒâ#É>Ÿ#( ˜*sÎF1M!vPÊ­Ã >Tåæ’y–I¤by,{àbËöõ>¤¶{+«KX"b ÷;O§·5ft鈾K±ÍsÿC±vg>¡ÇãR¸:ïWÑd}.Ò+SoK'<óïY¿Å7;”KÍ[ 0y¥å&¨á⦹ +ö >åH¥WŽd>Ï?&qýUë*z|t{ö¾ó5»+NÝ­šPìXñSíRÓº?Ã} ÷›Ë!‰v.ö/ Î1õ'5CõŸPÜõ¯>¡<DÎcŒF„ãò3R~¼ë+vÃO±k4µKWó+ç¶ÐNI….QQþ¥›!!÷¯Ã‚ä|²+[)ÆÇ ëæO±­äS$2*÷uüBÿŠ|`ÈY|#éYO±öz8G$-É<ê+fÃÃopÀ-€?e"EïðãúõÂmŽå~ |ù® ZH¿Þ¦ÁzVn"òdR¥~úŽm2I-ÏõOŒw¥u>#i}1C¶˜MØó ºäò;RvÈŸ¼ž0,êÙü3I+©ž6ÏÞQùÓ‹ˆ SÇpƒ,2*l‡Ø_§ã1õ§ýVç??ˆT–¡w½G¤ôíõµÎ§3Æ“ÂPŒ·ÄJÝLV·a ‚Sæ}jcᦡs©éW-{3M$W.7?}¼`U_Ô:Ž™©uuýÞ)–9¸m¤g ƒúÔçÂ9³§oüªðÈ¿B„Uò?ÔÓ|;ω-2uÏþO„¼}*âLÅaÒâ™.™¿÷S5.ÍE:öÐ]O§°“a€»ó8¦µUí1/9Q½žw[» eb»þ£ýk}nͺ†Ù$P‚„úš‘y^Zˆ&1ÌÅs’€S;–hm^ÜD7`üJ#ð¬{³^ßÐã£b_ßÖqª`ý£y8ô Oø«]‹Œ±ª×Ã쾿d“Nç#Êj±Ô@õ­=ý¿ó35æç<÷¯R&6úVŒ œ3>ôút)bîFÃÏ¥ NÑ“Žþ½¿•z«ßÚ\—Bð§V–ÞO.âíEœN †N7îjHlªuÒ¶³$ð$ñÈŽ’èÊÙHÈ#ð®ꮕ¹Ñ]¥ºˆº"æA`*ý}Mt×ìÅ­Ýë>EÙg“N­VF?}@ ? Øü*èJ2Žè”dÇ7ÀnÙÀ÷Û2f[r#‡\ (ªŸã·’Æx&ØX‚£â´¦-VU$ìÐZ\Y"øäâ¡÷qœœb´KWòÚBÜŒfõf’,uÛ»KxÎÎÕÆ½3‚­$3ÛË$Rp#ç[q•òaÊ.è4†@£9 0)*{yšbéj`cj) b›¥¾ÂÌß­smd;ˆ³‘fŒ•û¥ì}+y²î̱2ŒŒR{ÛÇ_4"¹ÀÏzÔmÏ ÇëK0*9~ŽêHþÖu‰±mËÇ­d…ÈÇ v¬àûʳµ¿Ò*ëA Éï^¬nÿÒ²x®´qêñÆ{V¹ßÆ>ÕW œŒWY)O+;¿‰Ÿ»·Óß5êÆáïYÈÝ·Ö¤á-ÇÌÆxÍ+ZL«ÆÀsëÅa>– W«]ëï[w^=EI&®ØÖà†XàíÄap0Hõ­¹:jÐîÎ$eÉr? úu=‹¦ô›h¶ÎrO4À¸VÁî)dʲÈ0‡âÛÿ7oéV_bÛcŠ#À'Ò“"9,Aö¦ÿbTç>žÔ¼ŽZ,üê%Ê ÄÊ7ap>uº*(Üû ÑNæÀäšßËôš$u‹Iä™.MkƼØÖ°Ã#É‚_™¬´m…[î¯"¤áX°Œw©sò§v¯FcïÀÏ¥2`eiþžI1†=ÿ äqdô _ã!llÜ:oªúÅÁVãp¥1é˹­ ™¢]ÒLJƒíJä´­#œHÇ${Ö3‹smб°;²NsZá¾T´ 3a¹¤nþY׿{çGúa>–f¹¶P ±‘‰î¢:£½%sµ~™#üSžv¦HÿÂNiÔÄÈêýéÁüóC7L®G@D[É£8T8ÿÊ3E# Ç9jf­á ÿÅ‹Š!nÒ}ž&tÚÄ‘õâ³îËMª„Y2åOõ¯JÅÁvP£çƒOÛíÈ­°€>ÜSk…žc^Íïó® u p\ð¡sšôóG=»ÇžO£ºþ³s¤iSʰG.À¤džÌpén¬¹Ôuˆì§ÓLac 'ó¢Qn;ˆrK‚nT˜”©ÎÓÞˆË1{$8äM ¨Ä¿0Tûšs,¢+"|l9_ïU¥VÉDGÅ™ Ç¥Ÿ‹n~•Ù™G”î™±Æ?ZŸø› û6—³hâNÿ…@çRÑÈr’½ûUÑý£X×N”gmIå œ'Ý5mxK&5›¸KUÁù£ýê¬éeh®â r\a¾ucøs1‡©âLòÑÈ¿ßúÕµ¨©W†Hµvúæ¡=c<¯®ÅoÏ–¾¹57‘[vÂ~.ù¨.·*vé€äÊ‘ƒøSÚËöé}™DœßðT’wˆÈÅwåˆöQNU•Üš.ïÝeÆÖò#Øâ¹"kØO[,ÌÓyVð±1ƒ–£oÓ×¶,“éÐL‹µY€ö­m$òN ÌÅ×bÇŽUÅkÕêõ4 k ,„QT‡ŒÑ-ÇÚË!HÄÌÌ}8“<þUxàƒØÕ'âœqÝþÑ~Û+î`YŠŸú›üW#ÏŽsWºŠÖÛ“uf—êÌVVT\ŒäÝ«×rõ:Z´:RÜ$mh`R\Ÿ‡äjeÖz ¬m¯<².YÂ*·Ç¼d†›xwsçé1A&[HƳ5y_¹Tnh#†ÓåƒgÕ5†é»»[Ë©ö6X‹“‚Tû‘QÛ~‹-,Ÿhž ,ß/ƒoíèÄûü¨ÇTÝ8ÖõK[8Xd‰[s…Ç·¦sKèZÒêz:dÌëv"? ô ŸZY9ÓlÑq[S+ޱ:wPõ6­vs-šäEw ʇá8ø[ßê)•ÏŠWìÀ·Ht[ž¿ÿÕ1ê~ª´éý{VÒäµ–{ÝN8Ò7SðÇÜ1ozŠ]¡æ5ø±[(É«}{Ô¥4£ß’OqâtÎ[Î莉 ÿþ«ýT>ëÄ´0²ž…è⣶4ò?úª),RIdл¨™APxö§ö£.¬˜Mâ-ƒÆ¾g@tŽ@ç®3ÿÇL'ñ D9Wðï¥ØzìŽAþ*†L ©m®¹¦ï+8(åBÜ()+;Á-“­ºjA‘áö‚£äÒšlÝeÒnÙ~€ÓOÍ'uþÕ˜zã4’Bz3C¹³”I¤WÑëœô5¸ÝÛmËÿŠe7Pôtƒÿñ‡åtßâ¢Rw#žŠÐ€{C¹…³‚X5~‹R3ÓSnöt”ºG1$ôýÔ`û\ƒQ`Hà­x’{óS¹’ñ}¹é6ÜɤÞ*Œw˜b‘–n•v[_&=¤ƒ®vàƒÜfµ}ÅH¨nÎP3ô´Î¡b¿ƒ©¤ßB%ŠÔ9à’3ý(e´.Ü…ÜE.ñN‘4­q’>u«Á*-qfæ (IŸ:àóþšôë¦*¯>sê”Ù—ƒ“Z2¯—–y zW_à䟖>K}1¿ýã/ŒGûR3ÅfœGrÏÇþÌŠJH£YA¹} &UTöí\(ƒzÆÕÜ’’ ¬@ñ[(€©WظOž”(®6— ó¤ g< Ý‘ø-]l¨À Ejð`ÎAr>†“`TóŽ~T¤vÒIL‘±EûÌj$ù8WáÿQü+;ˆû®ßi)L‘X@6æŠÕpp¼k¾²~f–‘YŸ;³ïMÒ6aqJ @U\}jSàæn#³ÞˆÛŽ#\• Îáëõ¦H›Óèqð€r3RŽ']l—1¹ì%‡Ö“,æM§?¢žG·F¸˜Œ’ä•…ÇÚ$Ç«7ÿ5dE·9…q!íÀ¤õd³ž;œ ZÿsÚ·Õmc#âfÏ~⡺‘e|FúBy wp8ØãAÿ­8Óõ€¿cõ,)ºŸ+DcüÒ®óø‘Å<¶~Ñc„DŽA®œ“ãÁÕp^ö›žÚÃ㎠Ïú{ÓøoÁ? r¿B8¡¶Žˆ°ã€“žá—ÿ\RöŽR@ÈGЭg’û <  ©ÎS­5»»†ÚÕînåH Qñ<‡ô‰lˆîÚHâ¢Þ&HW§Š¼»Œ²ªŒ qëÅLU´ˆ®l„þñÕu}­ã¹i­f¹;bvJàŽ=ªcÒךJk·:e½ìa˜ÅNãÆÓ»ç5Šw´»[›fT1&0G ŸéBtfº×í£É--Êï#ßy9ýiÖ“ÆþŠœR™ÐRÑ#¶Wy¦TÚr2shn¤OØ-­ö»=‡¨8¥–ÒùPn”K‡ŸRsɬ×(º€~"˜ŠØ¤#î™3ùŠ„:ïãµJºÎ\-°pCüG×µEåÃÆFX¯ÇuÈÖ* î‘o¼£Ä0ÐH„þ`Áìù¦v°K$‘ŽY\àŸaF.–2ޱ¨ òà§4â(㉑T(ŽüVc…1ýÜ|5‹f‘;‘÷îÈ?@1ýªT„Òt,KNC€>7•¾¹fÅA–·pª„Q‹™·‘¿É´¬5¥o"mõÍj‘ž}°$ü©”¨©šâ´™£!ò~@àš©uGNi—¿bÔµË ;Þ9eÁ_®;Sßš(´[ëÙ}™”ºÈ³¡ £¿®hv¦qÎ>$tí÷@u47–Î. ÞXöw9Ç<2hLõ'MÝYÉu<ñÛÌ2Le0XûŒk^%]u§ˆÈ—SCo¤@ÒEioŒ(Ææ'¹8þ•ai=¥ÏA-c‘XP¯ö¤uQJ\£wÓäý«R+Þ£êÞ÷Ñéš|dÀΧo'|ù® è]˦úrÛM±YÆC–,@É5ξ$ÙÅÑñ[ÞÚÛ,R‹˜äª6Oè+ :W®z_¨45Õ´íVØ[œH±²7ª°'#~|].½FMdVÿ$ž¼xö¡VÝIÓ÷RyvÚÖŸ3z…¸_óMu®«Ò´õ˜,’\¼ ò9=¹þ¾Ô̧«bQNN¢$1Êó•®jý¤tñ¦uBj0©i¦…gÚÁSŒæ­®¹Õå˜Ço §ñl]·°ÉÆF>˜¹ª×Å;¾¤Ó~×5Û¾¤Œ£aÊñŸÄP=iyæRá àÁ-é²Óì¥ÌMöãgul0’?ÿ—šS¬õ‰,îS›S[»¬mGŒ ëÇzÝ/ÜFçÊ’9W–ãwÒ¶=!c,ëåË,Ë´1/ÙOµgFPNù6œ3%¶ÇÞ iƒªºáRè¡ÄÏœȼÿZëÕ!ŽQFA÷Ê¥®ŸªÊöÍ™]U%TÎèÑŒŽù«'GêM~ÎÞ+h¯Ø™PJãø¤çw##îöÓðÌ¢º1u[“iò\?z«Í?Ä ¥HÖëM·rË»ÌYŒ|n dy8ÎJºw©4Íp´V²ì¸Q¸ÂýÈ÷àO¯ «¡–3t…¥ŠqVÐdö?Cý*œêÈëö¶è¸ø>]fǧÕÄàllƒ÷O…UpØ=Ïíw§Ë´ìµÐËäóŒù Z9:@Æ6Àß¶6Ÿ¨YèwRiÒÍ –¬L‘>ÖBIÿ …øÖoÐæ‡Q»wç²O¸ülYwäò? ên»éÍ;©z~çJÔ¬cº‚ãvQÎryúüëµÞ¼ðÿÄ94ÛkYŽ‘}kæC:弆VȰ3üÃÓ½UŸ eÁ~›4¡4¯†Y–zV‘u‰-î~ÚÛˆU–R@'Я¥2Õ5/¦¯×Nµ·Š)Üí„cÐŽh¡^‹‘yÄö’:ä´_uþx>´öÇ¡î'¿ûuäÓO0äÉ Îk=c^Yè%›$–ÖSýg¤^j½Qk¨ù.«¼Ìä‘ð¦r>¼R—ðŽ  ðµgõLÖí\Gü?‰HÎ>”æïHК&´¸$dl³í*OË"´´¹”aMÔ±¨fáÝ”ÄGÉäò(]Èïòš¼äÑ´«€¬tK/€b0PcߟCøÐž é­P¶Ûö-¥”ag<¢¾Ü/ùSk9 W?…ºc¼µNÿóúÐË Ÿh(±@ùo-=¹X²wÔÜ[ǸíÆãRXT/j»¸ØÎ5H¶ü*ˆ]tÿQàeD1¸ú‚Çû {ïÿNò"½à\&] ^ 0ÛcçµøýE)y`3ÁÅQ¬¥²¬OüI¯ãÿZ·³ÒD8HýGù5 ¾CBÜ–¿01Fšf=%‘ËBƒõ $–Ô£cñ,ñíÍ3«’–ÚúÓGnåùòÕµD·S·É‡-õÅhîÇQ ‚4ÞN;Ö, [ÉšPL€ã?ýü«7j#S“ÚÇÌ‘ïIŒõlô¢lé½<{À­ùŒÑUøNsŠi¦ªÅ§[F ÐS®ê~†·¡[hŹ67ºÔm"—Êžæ8Üw é@¼Jê4鞎»ÕÏœc1@}‹0¡}ZCõÛy¯ôý¦$¹“AÑ4؃43Hí*å‚´2¼™%¦Y“„#/³u­RöïQšòIÛÏ™³#†f/õÏG§-VG°Ôo(ž'hZRU€ãš1mÒ…•u—ËÛà5ÊÚ‘óÆï­ ¹¼ÒJ›#q [¼¬ÌÛîóÇ5¤ëÀ•´Èî©ÓœgŠÞY#s•ø‡ÔSÁ—P²ˆxîS!8É|äsÅ;Ó,ï%Ó­ä³¹…¡Û³‹¡ù8?*'ÒÚ.¥k­ˆ—æaºhH‘XàóŸ™æªËÊ/r²ÜR”%i‡ºîËPñKé–2yâ]Šþ` ¸Ç'<àóŠ«tî›ê=+QÔ4ýB1a,o†ûAÀcž÷«Ó¦ôÆKHÒÂAD{¥Y ÎìüñQ¿ ÑÆ»ow©¢µÝº–X›ñ.A9Èö¥´óq›ÇH¿Q7’*RvÈ×Gté{Ñ%ÝÌ3y\lŒdôsœúU³kn’Æe,Tlb+†OAœrH `rjÐqYÜèWSÚÊe%ƒG!\21u g?r¦¶39ób“íp¶ÂC#!vð¼wïÉ¥5r›¿:x(Á Ú$+sˆDo€0@,»†ÎqŸ¹ P}¨v«¦Zα¬× å­ºØmÑɹC6@ç<çžh¾¯¶šMA.$XÚÕ÷"H$VÆGÞÇ”­Ý²³IoÍ:AqÿÅ|’%^rr=ER©'Â"ÃH¸…îd[‰baÆänÝ¡ˆÀ8ÉÎyõ¤ôÍ7ϳžI#Ú¾QgÚÀdç üÈ?…J.¢†9Cy²Dª¹79,ªÎ‡w=°ó¬ÜÅhn,~ÉIùˆwÈ„e"a€<|F¹ínèµežÝ¶F4½mË…3\Åå“î-™Åòå[8úT‚ Ks%®`­¹w6œÌ8è)y’YNŸ!V.X³·{¨øä8ÊŒzÖmÉÃÃ}(®"!|Ñ»¿vÿ­sm•nUÏŸöGj¢Ö78ã0©‰9EÆ3¹Ç×Êu¹²uŸFÝnÖ²€äü#j±ã$‚s“Í7XÚoY¥a7—Ä„áCp§?Ì=k[Ë1Ÿ5’Αf…QÒ2yŽíœüÔü–JëúïOYêQÉÿxB® }×0ü*!¥êLñßZ×5`b²L†ÖÞQƒæ‰ŽÐ>dòk µ¶é½LIµ¤ä*¨øxO¼?ê8¨]íÔ×Z„ÓJÈìHü})æÜ¢¹3\½¶Ë;¨|Jkˆ-"ÞHIÎ&“#ä*¨u¥t¿¼–id–< ô¦PdäU¹Ò¼Ÿ̯œç¶je'ä£{ítç—I²Kfµ–í—Ô®+7zö¯$]½œVÊN7·8üÍ4îL`Hä¦~8ùRB5`w‚H$ÂcŠ/–·4¸li|óÆ<Ƹóï\òßËùÙ¤ådŒð=N~#N¢çð©,¼wô¥5$ˆ¤þˆ ànþ`=Z4¼ ¶äí‰8Äa9cwÒ˜]–ååUSßôœIæzÈùšAjƒŒ•MP$3ÄÝ!oô&ºxÃ\[ñȿ̣º“òªVYev®à@lüý«¥uhÖM9‘—ròJQ\óÕ­e¬ÜZ·hœ…ÿ§Ò›Ã“r£(ö_h }ÍoüëÃgåšAŒö¨’µÌS)mΤ0sŸ‡Œqø×® ‘ÛÒ†N ÜÑJVrV(9 HçßЊÑ@eb{ÖU2 1"“mbâ„%üš•÷Æ;ÞàÆV?-1…Ã÷5¡íZú|«‘b1N´›G¿Õ-lc8{‰–0sŽIš‚È£>/¬ô¹œecºG9çéSg2Å׺rœÕŸN·$Æ# H<1!N{ÿÌ(9ŠEœî<*óõ©?VÍö«›²›¬£áÇÝH×ÿ¤P H >µVqì-M)Òê§ýÂE›$Ы¤VÖm‘†Wv?J1¬|6’íç|¿ÔЉy×”z‚ßÒ‰¾ Rvˆ·È÷5ÖI:„¤žÎj_!qèW5½iî_-sµ‰ö Šä°e'ï[z ÚWy30íڱߊ¸tyIS‘JÇ+“´ž>•¨Fö¬ˆG8>”UEB¥—9vÅ-ªÍj±+2¤AËmçy~ŸÊ¥’)´{W¶jIHa•9슛_DQ¾Lm»ùiÜR0„0<šdY”ƒÏjV9$ÚUœséDpBBp¸¥mþ6RÜãµ™_#š} ²;…R×Z6Òºtk1Ä$ŸŸ5p‚L`:‘ÜHËÑnÀ%ñ|‹¢ü`™qŒV6;ÚÙèå̹ Û»”ûw¬Øaµm:ÜLí'Ôþi»9XK‘ÁàŸjÛA$kŠ]·$îÊ}² ®ýÉ×d'òHÞfM<§ý@õ9¢ñá"œwRG¸È p%º Æ$”`“íFPIæ‚ØnB€£> ÿjW€âÒ.0ùvâ ßqÈÁö#Šu b\ ) ®%ëk›+’ÓÙAü@¤*È};S¡âbÏdÖ‘(ÆÖ>aâ”Øú ­Ùd[ÈÙe'î©çU'YË%çW^˜Ô¶cSŸÂ‹'ˆö^G•§Àx$KŸíQ¶¼FÔ[TtÂó‰v©ä®~tXÓ‹¶€jºÎRºë[>1mpñÇdÿ&¦¾Ûy}'wq“™î}}â«n Ô"ÔuëËÄ5¸”²«qŽÕbô~¹agÒvúkÇ7œ§sLƒ“VæUEƒ‹²d÷£±îTsøRWþñ!ÿI"‡iÅ­þ¸©oæ©+ÙÓSÛâ«4ª{¶qõ¤¥Â佯‘ñ%Ä‘éÛN>P¶Ø¤Œâ¤Þ"9X,~,‡®_–&¯Çûmãè»ÿg±æiZÁ<†•ÿƒ?Þ—„¹tôÊâh7ºªéš^ ¬ŠêÓ+æ8Å–F¸Ô$pÁÍ-\C¬ÆÞËò)‚_ûœ‘dÏLc'GY£¸Ï™†>ÀÔÆ ˆV<Á3Mzzçþû²³ÃIížiÅÜB+ ±Ïš’N1ü$I¯Ë…$òÕß¹$?*iª>á ƒ,ȇè\f‰¦ç`ǨV¨ÑÁ¨ØÈÊJÇr…¹ïñ¯¥WZ ôYê¸íJg OÈÐz¢Æw*ÎÇnâc„?ý)tê+Œ´‹2ßÚ·cR¦ŒiÚ|‘Ρ;º’á;g`Ïà(G–÷AÓ¦!Vóc¸ôE¾¸†ëZ’ì9Ò?”P¿õ›9:Y-䔼Ç(*¿w½-¤‹s›¯#§Q‚ü[êJ×-¤Y34P· ,‡¹>ø¨5¦—}®õLZNÚ™&Ň×'Ð -©jÐÝ}¾þ)&^Øc+íV?€zlZ>„—»ƒ__ÿGnH_@­=Ÿ7éðð¹*Ói¿S‘·ÐÄx*Ö–¿ïÌ?w Ù»ä)Šøe«Ú¾ëm]ÆFèjðd.KÏq¼Þ•·‘ˆ€Tä{V#×j›ýƯé0u(• ôƴʆAºG_O8‘k¨ôú­½¥½ô΢ ߈ƒé“éVŒ°®íªvzæ™ê7V6<ÉšiX|ƒs¬ZDŸ-“úl R‰ÑtÅÐ×M„…“c‘Œü'w<|À© B‰{uåÅ”f²ªî?ø ñÈíŸJa{²êÄ^@ÛƒÆ[ï…(wEÛžçŠ'} øÌEÐÕÊžd>£žÕ-¶í”ut4ÖY“K¹´Ž&ÖM€l¸1ÍËŒeÁô¬é×);3ÛKð¸Vg—véÔGÅè¹ïëHê—Oo-åÄb2ÈÊêªbH/¸ü#qß·ðȬiâ+Y"¶ªùÇ,H;& ¼°ïîk«ÈXÍïÄæêI7;BÊ Àãâð_þoj P~õˆüxóeŠ/Ø÷$·ëHÝEYx™“~r û­Î¥<Õ­-ìïcòž ‚îìAø[ÉÆ? *NÒþ4gŠY$ÊËÑÉ_ðyª/Å{O³õpñS'ê*üêK ­µoî64r±ÿ†äì2yª{Ÿã–8î‘Au;YÀîjÕÒdR[‘›©Åíäqª*{Àè9?…1“‡ó?J!¨ýݪ~!ÁϽœœcÐÓR^J¢Ò0eÐÖ’ß*Ö³Cay³µ&ÁÊî€çK" îÇ_J-¬X Ob¿Ä¹F”À¹Â¯Ç'à 岯nö¢OûA¥]‡×-˜`“j9б ÕÚCÁH˜ƒøTK Ë]}‡NbÀŸ³cÿ”j$ª¹Éw¦]¨ÊšVšU¶ozŠ Vëy}êßQš«ZAæŠr%º«†³æUÇçC㺂F#!çóÅ ³Ôe¹¼† ‰•æ©!xõ÷Ds&©0$Œ63óaVË¢‡û¨8 "+d`ŽyíPKçsòJ–'½Lµ#²Ÿœ}jë¸á…!š—øCmàÖëÁ°Ü¨R8•ä…Çõh3èp»Š‚­m8jÕÔG³kB>"=+;ÑWƒDø¢£CœC^±Ù€W¹ïI9“qÛÛéSvJ4ûòŒñô¥Ø}äò)+u r~;ÍY‘ÙXÚ¢/‚ ó¸©íŠR4-Èôô¦¢F±Nbc÷s€{š›²Eu9#Q+EáSïœS%ŒªÊÌ€Ù¢v1ÝdøOaœâª/×ìw‰A•;6üXZr.`–mÑðŒÁ‡c>•xD‰¹‹—ÎrkÖ÷-e2Iµ]üK» jO&%\XµÝrvN$¥Ñã 2%Ÿh>õ(ì¸Õ&ÀÊ[²¯à¬BË%¥™W]Ÿ‚§·n? JÌôëÖç.ƒÿ‰ÿÀ¤)×&‡hÍ’«^ÚÆèÍp´Œæp(Ý»Gœ¾àÓm’ÜÜ0ÈÂÃåÍiuºI6§ùÕmۢĩŠHì`cÒ±©ÂÏvp­i!PŠ_R!¬•1T6Ô¸]Y´‘[‡ø[ŸÞD¢Ò4Ïò(*ɲ4Îv—ÏJ5vêÖñ:†gcÞŒ®QJIdLìP=©µ‘+¡$£¢Z|_i¼XÆ0§œú€3Gã¹Oˆ4l  UÙ¾TS‰U’Α¾²³êVîvz’Ǿ*kyqk}25¤É*¶>ëdŒÕMö*HwNĨ4[J½†Öñ$¶™¢v`0‡¾¼R³…ò1µH%âTF-‚C¸ŸSž1Q àKð"°ÀÍN|]V¶œ¶è‡æ;Õz yŽÇ£DãwË?ÂÃÿg]ä`yã#ÓµH›+xüs»Q¿ ~é¼ BŸ8c'¿Ãš“Jvß;å yõ¦µQ½$_Ñ•ŽU®šûè*Á®ä9 î¹”vøyšsÆ@àн,Æ,nPóJ,cEîãq¡“ïßéïYÑj†&þG“jÄäá{Tk¨Ÿt¶²g¦ÏþèïøQ¿3t.¹ÎÖõ¨[êÇJýÖDI#Jg!YˆôûÔA\‰?´gŒˆÌ„œn—Žâ]„´¤ýEF:w_mFïËka1—àää?½ë´^™Ô¤Ò涺»¸U„` ô$š~›ø‰äj+äXË?û»°À;8&…k–íªi7šuÉÂÁ_B{¥VçÆfh<»^B¬[Â?@¦¤ÝÖG¨§¹µ’Á-.¡‰%QÅÖD-´ò@9J, 66äÈÍ,Y‰UØôÕî¡¢5ÊFöÌ`9@Èäv©7Kõlú%ŒZ…¬‰!!ò—p›o\ü©Ï\[ëØuäsŸ¨Ää„—Üýj®ºÕn†¶Ú¤Sì’;Ï18ÝéíÚ´ê¡ò(†yieð]ö^7'ÛÍÞ)ls¹IˆÊÆIø\ûà`qéó©4‘„ÞZ1 “øo¼o6Ò0䓃‘†8’Oj†täWzì­'™1•U# ®HzòH*˜Û³H€²¬¬«µ£8`ñ“¹N ²ýáž00yâ’É¥E©©ò€~nít'šÚ;‰˜¿•q´’#ÀÁQ–È‚9ïP^¡êeµÿu·…ÄL)ele8oÀU¸&´‚^ÝÀQˆQ<¯”hûŒ»ÜÛŒ‘ƒAµh^k;‹+<ˆÏ üJ}Ü}p9TœãÑn7Øß¥oµMkH¿¹ÔWì—Hàˆ·ÃçOúJß"Y »%+,ˆªÌ«÷‘9øyãÌ?•WÝ#6µ¢_kI¬¬è÷ ÑÉS´¶åŽ@nß#SMKR˜#ÃtÒâyÔát¾_ëù-’]•¿äÖV’iDVУ3*‚T1S‡;ˆÆ+Kí"ÆîíâY0Äòãl±$µ{¤ãžõ½Õµ™*óÙ¡ ¥Y¡1w0Æð23ŽÃµ:x|™|Í&îî$ÇÙä"%îÇ#Ò»k'¯õÿA4ÐìÖÕ#ET¸ØT6UÙT²–PpPðÇqÆG¹‚Þ88âÄ{0FI˜xÛ“•ÎF0~¤`Ô”Û3£DÌAm…¤+œaNF}«gó™äB#!¦[kTp*waÀ'n9cÊŽj+ðuɾDØÛMæc:@ÆR²Zyk‘œÎ~f™^•ŽÔ…­ôQõ#X,Š‹4 ²9hCßÎÜriÊÚ=Ì©Æe‘ŽWŸZj F Ì­JÝ—€QxÒ`O/Z1Q¸m÷®$Ô5I5MXÌ@Ä iú‰üù§½6‹h«Õp‹®FSƒå¢îùžhYíE®YŠò3Ú‡Î6Çʸp}ëXÃI¦2xÖáŒàÖ€dÒë  AbI´iãÉt„Ùqþ¯LV±3Þ\¬öÆSoÆ=~U·LÅeu®Ú[jek#–à&ÿ,{ãÔU¨øc¦h=Sii©u5³Y#,ÓÞY¦ôHØ‚Œp}ˆÈ®¸*IFÇ(x*JþU"èí«õÁï$ñô¦_cŸ¯ÜÃââ/4ºH•ŽGèiïN^Õ$ ‚ûP© Éûh¶Ðó¯B®‹¡| ¬mA95ÇlTÇÄöéÚ(ø¿î£½G4Õ·û5ä·ù»!þü¬O£ ¸–åw!µÍÊÊ1Ó ys‡$gÙϽ³!. °,½È÷£=:Û¹BÃ.ÓÛŠ)ôPû êûVÂ|²‘¶¡²[*A+Ö˜ >u÷Þ¢`b¢„f½ƒÚ¼ *¥T†`MX ú[›hì ¼lÓ³çäV¶û7š6Çî*\qè9&”·û:¨,3±À$Ô¥íšû÷‹,-½ŒŽ `=ÀùÔJ\vD3’W«É÷Žkip$#iò!Z!ÜqŒQíµÁǰ çÓÞ¼7‚}ébˆUR÷¤Êàà *òq¡Ú‡wŸJw§ÇçHÑ•°àNÜíu;A#ÞˆEI ‘Èš“‡:}®Õ ±fá5½ `¿Ä\èEz!ÁHÈÇœS’<é>(°>ÔMœ7V\ëIN„¦ÁŽàò)c>øÖ&X“g¨NOãëXºQ*‚‡ØWXÃÑo%ž&âà™'&œŒAÆX•½ðª þµ³ÄÉ'k«ô9©¬·B{Ñ h”4žhR@ÆGjG>97ÀT/HÕøž\ þA5vŸXÔ¤SúŽ\"ê‹/¢åê‡ÓTµÓaic $±Ý¸ý)Ö©a›¿UêmJôàŸâÝù`|‚ÇŠ ÑÖ²Íe8iLÄL6œ’¸ÇåR MÖêô$–Þc`ÿ6=‘VŸùÈŒ]ê¿çÑ­†ÓBÑfž+¿+„¾|œ|†Í“TÖô=1îú_¨¥ÔaA¹ì/_ÎR¾ËŸˆƘjZ†‘¦¬V—·qÄÑ¡ 8‘öÀíøÐûKÍ7Y°šxç6ÞL‰i™PóíšÍj}×· =©òZ¾uM·UôâêQ,pÝ30šÛÌÜÑ‘Æì{@üXPúî—jAÌP; zØþÕCCÔ³tG_ _Gº1/ýæ0ÜJ¾«Ç¿èjÛê®®Ðõ΢·Ô`Õ-¡¶’Ú,<Òª„'%Éîþhe§q’”zexó&šŸh)ÒVFÏSG,\ÅjˆñaÃø“ª¸•ûKá†~Ueu/_ZéÃì}="ê„Ñ4Ij¥”3¼;äŽ8ª÷§ü8ꮦÖ%‰ì¤µ™PM+Ý£Fv“÷ðÇ,=3Nà‹ÇòÔ5‘ÔA\¾ÅW ©àEYþO¿«o8`–$ßE*þ_½¾³h²î nMMü5ðÍz9®nynîg  ª£¿RËG€#‚Qi±ÿˆštz¯I^Û·’2{†^A®nŽ$·Ž0˜íüÝÃníú×Uêº]åõ¯ØÒ)3+"ne8À<“õZ¯GtÊõ"$·íƒ· ÙWpç4΋*Œ>;i¶ÐâYúWX,ˆ´sèÊÕ^Ëkå8ØÁ÷®‘Ôú§utÌ¢D0 ÄN¿8ùv5S_tP©ÄvfBrp0Oèiœ¢×"¹1ÉrDôî.a9!÷ŽßZ–H¡f¸QØÒVÝÔ»ÒAg"6á÷ŒsSŸÿOµénÙ (§hÏ*Œ™`Ÿ$âÃ7×þPâ¯/bEa\[£G.üyrFåCè1Üúb¬Ø`¶–ÜDm&ó‹X@Éÿ\dð=~Âã‘ñU§Uô¯Rô¾‘§kvP e·–XLjûIF\œΉÚk—÷6m;ZH@•¤X œ3Æ»›€ÿœ ¸ç*ÏÏt·.™¥‰mUäžG’NÀ’I'˜R2‘rÄöWFÆO}ªØn dàVb´¶ˆÌ¨‰p –ó2ùæe ÎÕÄ““žÕZšX¾Å<Ú ….ä&÷L“ßi÷èŒ7Ï-”bêÒiÖ27Ní ûÊ}?™¥ÐÂI®ÉWÓÜC)ßqºÏ°ì!ŽHeÁn'#;©…äúmÆËIµXƒ·—÷™ZEÃ6†9Èãµ´’Úò0‚ÊÉ¥QT³s”Sž0;/¿¥bMS‚Ê~í[‰"E_;g ‚AoMýþUb€;yÂoôÛ”‘o"¹Ž!.pÂ&|l­´ä±ì?\ÓMg©á³Ë¨iod}£-3F·`,‡úÓ‚}M»Òç61 ¸–B»Ìec2ð¡ço§ w­5‹vK MžyܘX8܇r‹ŸåUý+£dìåÎ̦¿¥_ÚH‘©8ˆ±XSlƒ'ùGš3Ž{{Ò:×Réºq[™&v‡ÍiBHó1#®óϾf±w§Cym¥¸O:I`.Fö£]¿qO¨o^ù¨w\h1]tò[Ùiñ ï516ù |rr~îº1O‚¼­Æ :#ª¢ê-. ~UµŽšá#ÆÐ¸\¶9<šºõd4黢%—dq5—§ìm—t‚;9þá¿.Ù¨oWë–š))´.¥îùEœýJð*#«kþ®Ò‹‹Ù¢Ñ#8ÏþaQé­ZÄ…O<6G™§á¥O±\š¿ ØZãÄ.¥$¤:eºŽã}Á?ý4ûªºÇQ¶¶•h{nòÚCýfXÂÎFaMEY 6´øÓèZZ¬¾ñ~®‡¥oÚ^¥’h–…P6O¡ïU^š¥lÛ í»Šº:Ö1sÒÚŒA†L'Ö©¦S*3±ì>•l"“¥ÁNIÊKäìNyØ6p{cåM&*盲“N.äWE*[Ì#œp?*Ö i|àò.à¹É “Ú¹¢«¶†)ä”"Ês¸¶9üiÞ܃N¯6yŽ#AçnsøÓLŽOoAb7‰ÊÈ8>†¥G|Ö2ZÜ£,V‘Hƒ‘‘ëÍEƒ¢œ±zQ2Ìê2¥µ¼éH¥˜Êà(Ú79õÀüs\wbZ¸œ]yw”Pœü `~”NÛø];vó'P¿ôë§ô;ýC\´Ó­-gž{·ò¢Š0rì݀ǯʇêvsØÜÏisŽâÙ*žêÀà‘£áQ]5Ƀ x•eÀÇ=©$8%ÏÒP¯ßé²”ö•;È,§=—ò¬Dìg+´i6 Š ²»²­À>Õ”*d^G'ÿZ•ôH¾TN ­´hC¬gË”øHoZè©!PC`ðÝóOíGb;‘Å(2ò0ܱ¨ûäÒð¼ >%á‡5$òŸpî==éÒɾ@Xúp íB£É#eV8$ŒÒ’äúgµ'¨B¶óȪ[ˆâ‘–Fû2°dgÈ$ŸZ­IÑy–P²†þ\à·§5gtÕ®ÎÛO¶µÙíͼû[ìé‡ço˜{‘]ÛjPé2Z%¶ùŽ^y2î¸ á}åDì:ªúÚy.ì’XV– 슻¸Ч2n< i¤”ªU_’MÕš³¥Œzv±¨I¨±0WÞ–ŸòŒñæËãÒšXÍ ž”ÐÊ‚ûO‘Æ`¸l‘ŸT=Õ»öãÜ£c…ûòÙ'œ šÃÜÜ^Ù-4÷m‡p î+óùRSsr´©0xöI6¥.zL>–V¦½³i¯4ÇÊ´¿ I ŸËƒØöùOjcyöS*ß$¬Á˜°(Wð8?Ú˜éÚ·î«K:ââ •6ÎG &{‚Aü»Ôž§õP•,"‡MÕs•›y³è?ÐÞÅ~ùTÎ*T×áœãq›Ü¾»AªÏ&§öHe•cn>ßÞ¶ÔÚÛþ<×ṟÞVòrG¾i”£TÑÄ©=²‚¿ìçŽÄäwçòíA.nd¸—λc.Þ` ? qÈåÃà·W›s6O'8ç¶)—†}5¢ÄË XÛ\í¶WI !Û%·õçpبŽÍ†8#“³ó¥³=Øœ†1­¹T lÔµÐAÜ!K"[‡„˘ÝÞ3ùV,Ћ§ dv¥T“Ç.­{tªÌÏq!W râ) r¨Ù¢áº{~‹+®u5Ò:bçP•š1 !lw ëTrk&F©e4…·1faÏ®Zrò]ô¼A0ub#ü@žÕÏú‡IµíͶŸst"–Ù %aùoŸ½ièÚ¹$¬ÎÕÜ"¤Ë×D×`ºÒ/ ¶Öá[‰­v³ ц#‘Œ­C-õV<Ëö‹“*a€“C#És©ùç~ÇÌ­ã d|éµ….Ÿ¼¦ªÉSªíRÚ‹`²ä9©ëuÑßÈÏ|Ù Ã9ÅTÝ-®]ê=S¦é÷šò@Ó´4‰€N@â¢Ú‰×S\Üm‡Ê!®Sy2``dŽßJ£&=Ïjcd£Í"äñ7Vžn–°ˆÝJò5ép lç'·jeÒÑ\I§ìþ0y­ÛØ–‚Xz·< ¢[«ºÏUhÖV‰p«æ'Âôç°õ©¯Oõíý»Moªh£ìÑÄ^I¡lB_qìpqÅ Á8Å$1‹S'|Yc©‘õBÒÛË(¹µ ÉÅJ¶å\•'îF½Ï­<Ò¬dŠÕ¢(ÁÐI¸yª¤fô!NCPÄ>–Õžâ-NèY;He0UQžvŸB*QcÔ:V©zãE¾‚åÝ|Ùv»sPœdpqÀíŠU©>‡7'É,·¶Xå¶‘<Ýû¢K`O’ßò¸¢ÏæŸ)Þk¦o`$`‹€¢Æö»¡e++BYÙX.En ù:NKè-ü¶™[››wQ#¿ÅðFÐ3Ú©¦Zo¿¯#ÍA#’2Ì«æÀÂB} Oj5‡›dË,ÀªÇ,ЬÀ+²yLV&ÕôÕ@xc”Ç&Ädn–‡Ÿ\q‘Q­k®4+O÷9omc9Q&ÕV„/€8Ê(8ô&¥ETž)Œ6 ³“y,@ЗwI÷¡·3[Kg.ÇV†÷¾ê½XrzC­ºë§2Aqäѹ˜MùP™n{rG#ç@QéZ¬öÑX¸t±.Ù‚+66ŒýÎçm3Ž2m2Œ¹#N-’¯Úá èf ²n’eû£°½P^¥þ¥ÕëöÛ…P{$å gÖ]`‘MÒÚŸÚ"ŽEK)\„'5Sô¯‡:¦‹OõÖ—sj·0H®Âå2`yo¸ñò0)¬­)+31F[[Cí7EÓ-ܺYDdÎK¸ÞÇê[&‹ZÅnåÀ…T•8 WŒRhÊ€}qÜQ a‡ `UooÑ2µäqie*ð(@6ªŒdzÓÓioŽäR–¨¬»Oç5µÉUÇ>•L­ð€ro°‰C6GsÅ ÕÕiå}¾tYYr{ÓP†h² ÖŠ*ˆ]"ùÈqëý¨v¥Z1Î9£Z‚´¢úÇéZ„B»‘ÅZ¤¨”è…jC~‘yÀI‰¾÷•I™Ñ‹®ÑÍ_zÕ¹Uœ ;Z6åÅsÔ±¿˜cÜRyô<ÑÝ3’_/|yø~~”þçW1M"FcwbK·†PÛ¨¡vÖÒÜʶñüo#aTœgèi{›!bÏkt¸¸AʃÂе|8þîÔuu³¼ºµÉ¸R"òT‡ `ýøÏΛ_i60Ψ–ìÒ£*#ŸB3Lôý_Q1He–H‹nh•H ú©£ÚvƒªÜ"K²«7!¤àïA<Øñ«“ £Šsu`þ’µé)µ -º‘µKhUY„Öh²1l ¯ŒŒãÖé7=?išP´2´‰ðM¿né |,Á»aI©F‰Ñöö󮡪^ùò)¦|µ_¡?z½¨ô×R]™4‹I-íçθ=ñÀ'òüiµwy9,hb¬æ¬w.&[{`! »›'Ÿ™«ÃÂÏ 5­©mï5 wF²Õ-ü«›XärCm;CsÏcŠ¢­­.guBÇžþ‚ŽéWÍ¢Ý/Ú.v0•øƒ»Ï¶jxn“ +o4\7Rõ¶¡¨iº,z,/g¨™ÞâiâŠe”©L#;p'ëUg]èz½…Ä’ê±Ç5ÅÑYüôÈvâpÃYêë½2æé®ÒàµË rAÎæ<’sß’h}™ýëu¦Ù=ÊG¼yeÊ•ÛÉÆãž{Õª-rW)7v·¶”Ën¡Œ¹ÚâikËxasR¥Òö,™Ú®9© ü—ú4`-ݼ貼EB‡#Á ûç¥k®ëý?%…ÍŽ ·(……ÝÛ,Nó6í`œ÷ŒWI¾™I‘2q[ħ9íŠÔpÀûS˜Ýe,Xm8ÛÚ‰D Ú¢I, Žù¥EXÜ« Ã…úS8B«€ç–ïŠrª¸*ƒëEg ÄŘÞŸÂP2î_JgjŠdT$Œö4õ?3ø`ÑH/4hnn¦˜Çsñ¹'j;ý)™éë%|ɯqŒcó­týsQ‘eŒ_Nª€^·žfffº3HÄI;1þi nHySä×÷™C»P@ƒÐ¨Íº´Ó!r?x1>ÁÒºwý¤7ÆÆê#°³{©˜e™•HøGΣÇNˆFì^F àf…n]³¹o„kÍ”qa‹Ì=$ R=ZH‘ÒÕ%aƒµÉ&œ[~íŽÆt¸Œ´Å×Ë%rk}3MŠê)ç–O%"C´çŒ/õ扥äœrü]1ÀK6Óíî€åNK6I9öô­lµ?²Î·6ò±Úy$ñß±ùf›@Yn”Û¿— ¨bN>U&èÝ&ÏNê y¥E¸Œ–#„¯Òªžl{\KðáÏ"œx£n±csÓ¶ž›rÒÅvÆ PzMïš'çš§tÞ§w’ÝÜÃoãÏ¥Xzæƒg¤hVöÖêËoûÎYc^øÝcðàÐÛ´0襎˜ò>dÿé@²m¥Œ©æ{²v¸¢3¥ô½ ˆ´ó4¼d’{QíÖÕåyl¡X#€r=i›LWCiW»»*ÆŠhp”ÓâR¤±85VIÊK–]‡\<‚GÇ3çëD:nKk zÂâæäEÜG—‘€QßÔñíCRÝœdŸ"j7â-ôÖÚmµŒ[±pÛNª¨EÎT[—&È7ôM|m×a[Y4û˜.<ËX\2” ¤ääqë\ízòI<®[tŒÜ²úœòhæ£<~BYÁ/š~)XžþÀzP™l/ H®>Îê’!#ïãδñbŽ%Çf.|ÒÊÿëk[KFógÔ HŠ!óÝO¶=ëÐê«%ü_kOkæ‚éç¸ö®—d×;!œy,„–~à‘§ÓØèö¯#4ñ;J’ß·©«w!oiÝ‘›Ü5ä¢0®ÈAæn!sÀϽ=ºµfšÚ;H8»ÙäñÈnÄSy!3„)5N–ùÖ»Ñ ò¯”7C†ÉV£‹Tê>›Õºqá‹Y´kIæBâ'?àãdâ™é®~Ï(,ÛŽ6ý}é «—¹‹t½½Y‰É¥,[k¯cõìhB:§ÁIÅΉm,… ‹p„–9áñý*׎h²*ùxb yæ©/o^çKœ¡!bnENúTÔ,u[[‹—•0?`ÏÎN=±TçÛ4ÿ%øSɨãéRæ(„…¶aòxÎøª·L´Y-­äþ>[ócÍÓnõ¯öTÔuké'& HTmEÚsùÒú^ž±é)Æøâ׳¤ªf”_ÎLmÖ­’¶º½¼+Aã8ê¿’Æx§‘ľiÝÀÀíøÔï©Iß+œ—žVa·žŒTNp®Ì_9'á+È­¯N…ÆRûfªd©ÆHÉy#¶Ë V|É÷Àô¢Ö¯;G¶åUٲȄàœ{ñY†I„!]hî{ÛÊŠL ã&23øëZ‘uÁ’Ýž–iàXdh®-•Š‘Ç¾jµê8"o+Få˰,Hïéž;Õ—sq©f2²äcrƒcZꔚsÜ%®'a•@·ŸÈ Ž>‰‡" , öˆ’L~•énY®žâp›#€Æî†ci÷£š¥«-É q·ø`äœÔ{¨­>Ù¶YH¸Pm¨/Z»Á1åö m O¼…‚C$‘ËC(eõ"tÔ:…¦Ÿ­C¢JÏ<°ª4‡‚ÄG¨8ùÕ“ tŸH/H=ÕïY ;½‹æZ¨‡=ÈíœÓe³[D†ÞÝV,”Ý Æñîp)9à†YüU}±µ«ÉŽ ·kè‹ôõÖ¹mªéö·3jŒZ`$WrÑ”ô úSíW¯zžÿA´ÓÆ³Э°ø Û@Éý¨Ó$N¬¹!—î`@¥º‡¦5{ËØíõ+ûË‹8‰1)—pE!Oö<ŒÒÙ=;ä¶ËúŒáõeË”?¡‡\7ý#ªÛ^Í%ÅÆc|e\qœ÷Ǫ .Ÿw; \ç¸SßëW=ž™m¤ÞÈZÎM€FÌò;a}n"¹y#„=¬”`¸CíøÕŸú~ä“`¯V­Î1+ý#B–Ynàa$ŸÃ ðxÈùÿš”tï‡_oÔÖBçKرLŽÒZ®rN}M-}‘?…¼wÚ¤óÏ¥^ý3#O XÈòv…A9îhòâŽ8ÅGÀ¬sË,¤åäkÖR¢tž®$buÉdŒTÏBêÍ7¨g3«ËH,!ò&Xã$«F'åƒUç‰Rˆú[QnT}h?ì“Ô³³ÝYÓ3yR[˽ØÄ£aŽLgÜ*~´Žhî4´ÓÛ`='«4]JávLó¶Ñ˜š2üñR#vÂPͬkÙw>õè-&Þuº×›KM9®'lÄ‹ð…S´=ñŸÆ¬™l'òí­¼È¢ 1Û/ÞrÇò}jÕ§Œ¢¾Å'’¤ï ^*c{) x ñÿæ›¶¥1ÔŒñÍIŸ@·rÒ½¬D71 ’àÃsùÓ¾¢ºÑ¬¦pM¬8Q,Üd€xà{ŠÓJèv4D èY>!´ÎxÅ{t—7—g¢©l~U%ÓãÑÒî+‰"‹ÈRAöe?ÛåE5>U‚ÔÄÊ•|ØžBÏäãÄQ~™§L…•4Ú+Ùmo^f’Ki€ÎTåCµ=K÷tM4Þ ‚Oý*y©Z±·)5Û2îÎÕU\š„jÚlf)T+ìÛ8ÈµŽ¼½øŸ¨]^B¾LÓ*øL|vöàS~·Ðjïk£^Ü]i1€-æ‘6íÏ¥iÐÜ¢S£ôwCéV1ê}MÖ+pø]¶:HógÜFpÌà"(÷äÔ^ütó_Kp°_^G¿ø1yƒîúnaŒþS]:ÿM#iÞL£Ó¿© Ž¿¨ÛÄEŸHÅ ûª),Óœ[Tßù¤_ŽnÛÿA{!©M£\Åc¢Ec,›99añzwþôcLéÝ[R‹ËÕõ¶²l3€—Âð¨P>ÆËÕRàØ% ÿ×ñSiµ^£žbÒh@9ÆAr=>´š”¥*qI)±§I©6ÿ¡(é} ÇMê­1§¾¸ÔƒHPÆøØRsƒÅN:«¯úw@-—Ësp£á‚Øï?LýßΨÝ~n¤»¶@úwÙ–6ÈhÉÉýhRè·†4É$lç ÷4Þ9Æ0[¥ÿìQ’”­"MÖ>!¿R*Z5¤vð C¨gËq²Ô5&ó/ÒIzWJ³UÖä‰öºCy¹à 'Ò]6uÓq'—#ÇíE‰ÕNN›ŒaIϵ0©ò/$ßcž½¿ŸOêË9´«’d´†‘6w2Œ†¨ßSj—î§.¥pòË{9Ý9~rÞ§Š¿z ô}/L°ëmS¨ôÁk£Ü"\Û¬e¼Èßù îçŒ>t+ÄûΑ´U‹¦4ž˜w‰ ÌŒ­,ï¼ã † 1Ûžõj*‚“Ýr(È­nL$ù\‘»…çõ(Ò"+mÇŸ•_Ý×¾k=Õý7o¦ßo2[uîçÕNsœÔ~>˜éO\”tOVé·Ä‡òí5cti+µ’ÒU Ð689äTÏ¥îWVžM"Þ$ÔdFYIÚ»±¼úTs¬´=C§õ‹­#Pã¹¶s«‚ Ÿ§±¦mô*®ƒ6ºYÖ4¶ÔçLªå%tŒŒ¿±=³œóò Ô£½‘J° ã“’›xiªÞEo©hªèb .óëŽÀzœâ¢ºÍ½ÂÝÈf]²#aÔðsG—ƒš¥b:M¼w71ÄàrOÏŸí^¾³–ÚíÑU•3ß?Ž?Z)ÓzÍr.1–9qð0ÿN~c"¶×mɺþ"[ªü?õ÷ö¨ýÇP.!nHÑŠû±¥C¹*"íeî})¹òòrGÝõ¥ 9LzûQWZ7d%HÎAœÚ;ññôÍäzš{N6 gñRŽ éößdÔEÝŲÍòñ9íښ꬚ž¢ÐXl¼œ–òI{`Óû öŠhŸ1¸ažÙu•ÌZRßjŸgŽÜÜ€d…€Ú0¸ìɤqÊøcycµZ$~íÓzvâxþÍFÚîÊhOp6nGúpߥA I焬I)€Lò{­LúQS\ÔnÝl¢Ó­,ìç¸U_ˆÈDxQ–äþеkÝ.î)mcþíÆ(Ë(>£q㿵L•óc«YK4l@íGzpu4ò(eÚõŒE6ÂClÚvŒTÏ¢Ö4Ùæ¹h—$V’³åŠK–k¬±|}kÍÔ:&ÒV–ÚåUÀÿK úT[¨6Ü\Ãj®Q—-ØñŠši³@¶×¶O"í‘íâ ž2bsýª ¬ÛßEu%Ò¢4VÌT÷@H4KŽŠ·y`é xÚÖÃvâN{w9æ¥0C$0¡^1M4y ¹3™WwٗΉ”rÊF?:zš½‹ÀÏ*Nª‡‘Š®MÝÁ¦­ ÞÝ‹+)¯.[lQ.XÿAUGRêók’Ü\Jé†1ÆÑþh‡^ëÓßßy1+%¼MˆãÏ Þ¤þ¨­ÃwfîsN`ÂãË35Zqí] ý²+bE°ã9ø†y÷§V·Ú¾¥~Ÿfg–d \}±ÅP_áÏêOáÞ’u}mŠ+æ7Â#w¸¦¥I[ßH`²éóJ÷:Ž«rÓHrëYÁÏ<šuý0˜/ü§ýNØ —¤O«I vàׄDÚ<êHU cڮœÛ|$ÿ’©+í“-7Qéxä_&%Sí"gúÑintMFÜ­»AÂ÷òÕW5WäƒßšÀ$ƒƒî)¸ë’\ãD{’I©A ¼®ÉÒ‰¾ø+ÿ¥cBeqèÿҙÃqq¢g s‚is"\Äñ/b*©N{¢¹:1k‚åðªtÍ&-E5khŒÝ·ãÛ—ëþ¼Ôï5h‡M^m± 5À‡né[¸Éç"«¯zbç©n§Ó–X­äŽ##K"“ˆýqŠ•^xS¯5Ü6Z%Ûjø¥Â0ò¬Ì¹qoJo®G°â˵Ê+²máWêšßFõ5–¯t÷/lˆQ›vÙù“V¸»D·— $qÇöªŸ£º\èÍQMaàj2[B±Å `Š?…Ošy!$wá)óÞ•Ô4Ú®‡4ñ{^îÆ]Q?•{±%™bó Ïú½(dg‹Éï“ZÞ]-î¿sæ:…_á ¸QÞœGe`¸ s^‡I‹Û¢û<Þ»#ÉžOëà>c`擈˱¾ W$¸Ž)ÝÂ(·n­”˜ÆÓÃzëMEX˜²ÈÎÞ[ÛÜíBº£¨.,ŒöÐ#0’Š/‹s“ÇãN¤•.77+ÅFîìnn5¨§È*‡ŒœóDãôL$» J"•RQFdnwŽ‘îDxØsÁ?Ì¿*Ùy™Pvž*#¯ö‰ M„ÇSƒF¸!ô²xã0±î)Ô·­ °)) 6rNsL-¥f‰>ÃJܘädp®}T¶YIòR¶¹…ðߎEÎWÒ¥×ÚŸÚ.\F‘åIퟆ,Ueg¹yp‚ÊÇzîÇÿTê{î ”ÄtWÁ„ÿŠl¶µß"[¹™¤BÌÙ悽º9y Ý¿,Èì¹>çšÖˆ®f!£!GÝ!©ü‰ªYWø©i$€¶˜ú) {iží#ïV‡…Ó<ý$F-äÍ$`úŒGõªÏPÚ  §>äçó©÷ƒÓ7îF 1z{üãSJêÄgOØCÄÛF~Ö†õ€¶XüÅPõÏAêvE Š]¤íî ”àIŒjõñŠo+Ãhœ€ñSëõÍî u¶[vÁÝÈ4‹IöhBTtÍ„wwÑÛÝéÖmfÄJaÇ Ãp׌Ôêɼëhã[‘$ÊãâãÔÔ_¥K NºHKÄö±gÉð “ ³¼À™Š°ìG¯„R\ K#“ärå``·6ÀŸB£Ö&‹B—SŸ|1I!‘3¹ +{hn#;dvž!÷YyÇÈÓÑd:½Ì±4M‹c¹çòÇåRâ™ÍÐîö+Ww-ƒÆœ"ãÞ™êw‚‚Zi¸…p•üè¥ÂyŠù’éŒ`Óm¹lž2y5-_ù¤‘’úIóæíÿ ~”?Q‰%¶œç—àÎör>Cn*_,Iœ Ÿ¹ ·¶åüÝ¥Ÿ8šê²T×”swŒ:]¬ZÍ›A ‹=ë:ƒs’0øÓ~ˆ¹²Óc¿êi½»‚2Øaž`úç”gÇ)f·ê #Ï]ÉnXœw-»?ž%mªé}G¥O>µréafê[xعýqÍ+5SmãwÈÇXèZ’öðé…Åã2î’AããÛ>˜ èÒùm4ww+l£–Y 9ù ö©Qõ@ÖíÙ~ÐÒÞÀ™aºi˜zçÐP[¤5m> %žeyNËQ‘·5SÚîÑb»áŠêZVé9m«ÍmÉcËÞbƒ€yÆ*>½K¯!ÀºrBçâA“øÑo©:ëM²^žÔ/µ8mì÷íåv]ŠØ$í=â£7Z­Ìè‰stüjcýÑ_ÐgÜ”_űĽY¬ªï󤚞±rízÅš4øZE_ML¼5ðÂ÷¯¬u]JÛW±³²Ó`K5ÑØNÐ=OšæïE´t¶¼³š+ÈÙ pFÇj`›QŠàéåÈãmðÁZ}ôð<æ6enäQޜ깴í2çHÓôËidºž9Vy4±²†g X‚j5«Ü…žA²0&ö;G55Õ“§ôÒçA’5»ùS«IæLÅygã„SØÆŽSŒU؃i¿¢wiÖV=1¡G%äZuØ•â’- ü`” (=‡8ÛßœúUW>«#]Í­Û7Øn^ἨíñˆËz—ÇY’Ç÷šËnhFRÅŠär¬Ô9©æ…¨êÚô Ñin>èæž/<ª”ÚC3|$g$zÔeË-ót¿<¹½¨­¡™|ÒdyÎ8çš”õ”ºvŸ«Eo¢Ì—Ó[[ËÉ!fV1(uçþ`Ù2Óü(··'PêÍbÚØ¹ÞñÆÂ5÷#?à}(™Ôü1é±äÚ®¤^挟®+''­ã—Ãe“ø\QØz|ãòÉ%çýŠšÛKÕ§•ž;9Û#‰ÂJº0êPj?fÖ]6 ÖÙ~%Bxu>¤wü(æ¡âŽŠeއ$Üpd”ù W¥úŠÓªµTÓ&éáæÆÙ O¥ ×jàœòᨯÏ%’Òà—Æ9-¿À«t»ë^¿¹ýñ«ÏvìÀÅpîXË_á±olqRÝSK¾×´'·e±·´šÖÜÅià,è¡w¼`9úÔs¯ô[Í&ÌËÓµ¨ÙÙȪ;•Nñ4B.ŽØ‡Ôïc»° œ}IàS›þ©ÖïY'1´ö÷¨Ô¶³\ݼšâtå™ZNÿ\¥ÙIp½—@…¼«+‹‰Øq…Á-§­”.n šå?š$˜FqF< †jº„²Ü4t~TkÆ Æ™”¼•ŠÎpÞ…ŸŸÂ¬Xìz•­­tÍ·EIe•k&Ô¼F’:f¸-å•ãÐFXâ i­i‘Êq=ÕÓg•#éŒâ¢rC7{¶1’~¸¯‹pf9=è£]•oe…o«ióZ@1‹uËHL‡oð°¸ðA5¥Þ±§E-ÜbäËŒ6©9Æïò*ZþúÜãÜEj§jž|µõôíZYܱ·žHíÍF\^çeØs¼] jjúž§5ÄjP9ïÀæ›I¦ÝDÓªn#>¸ü+vÔ@R-×óštï#‚îIc’jئ‘LÚ“³×q…˜¢H²ØŽM<#š+^«·šg ðMAÌq÷ó9÷¥á’HdŠR{]8î‹EN6©:Æ'©uL‡v俙鑱0žÏ=ýG4…ÕÇžY¥Vó·çÌÝÁØ¥4Y1¨DX¤í<ûÔÑÍThk'Ý2úšÔrp+yÐÅrÈyT$b±æQRJ¦om–UV`ŠHeùŸ•IµÞŒ×zsF³×/m€´½o÷g'þ Æwm<€j?l›IÁÎ}=ë«i>ŸWðk§5Hmʽ¬E#(Ud<{sùÕS›‹HIÇ¢ ð{\1k}ªÅbICB.aX>òšèOcw–KéT:_)r2G<àýq\Å¥u%®…þï-™¿ŽýHO‰dQ‚ö ãÓþjvZ‡JX^BŠ<´Äˆ;¤ å…)ªÇòrf¦—-ÇgäßÄé#Æ—ž%»‹Óý1¶¡¨§SʰØÍüR¸ ¨Çr(߈Ò¨èПåódÿàÀÿæ¡Aow-ÅåàÜ–èÒ"ún#U5y"Ê{qÉøä  §™bn•‘&ŠÚåc ’ÿÛçIÚÂÄ(ãÖ–€2¡ôÍz´©-òƳŽX¬Ô5«½â6…ê„v'8¬)jÔ¦£_á6kGb›‘ОO5ÇEèòBFæ²…Šçƒ„ÌQË«»Pï¡eä±ÉއĊ¯< »–ߣ´Ë{•l€Á2~èÞH½3VeÓË»ZPú†QŸ5´¹1¥jM›ék ¡ç|l¹U'8ükyç´KÉä¸-*ŸQÀÁþô [DIYà·’Ûq AŸlЭkP“íBᢒde1@p9Éüè½¾lžhœ]^X†Û ªXú(íI¡/ý"€é×W︂Á0ɹI úQh®u ŠóØ.ÆU«¤¨­¶Ç×/(.îH ×hG˜ݨ–ùŠîqôÎ)­Ô/Âà=†(CôÊ7Ç}"¡ äËÈ$Ü  g‘š¦tÝ*)çE¸–H l²Áük¥|_‡wEß¶©@λ½>UÌcªµP Q~ ÿšW7±¼*ãH²´«­'B¶>_•`HÆãùòi¯Uk³j–;9VÝ#Ê YÈì?Ú«é:®úLŠ,Ø,õ¥OW\4a%L¨îƒøjžË”_‚WÖWýiªAÔýݪÁv·$+'–Š6³Ü1øP{=Jº‘®Å¼ÆÅAÚ]¬ù?{¸þ”*¨DFSh’]™¹aíÛéùS×ë’ÐK²ŒQ›p'ž2¼~⺒è9'._cÍTÛéúcGb$Š0¸dIXù㱨m’HJÜÜÀg‹qB»ö€Øù{UÒ/Ӻ݆¥s­j°h«on^åWºô.;™ Ö—ýNË3ØÞßkSnH¢v[[Fls#|¸ “¶tSK’1wq¾ÂÞÖ)¢Œ°aŸ–9Å)£iój7~(Õ9i$o„ïøQþ”è¦êK¨¾Í¦Ü%¡`$¹uÂF§ùld|³] ѾôN”°ÛDbÖµ)~7¦'Ucÿ³_¿×?JKQ¬Ç‡†ùúJßô-†9IõýŠÊã¢t#æ=´½Czpf>\ é<ž}ø¢Qõw_u}‡@¶kH?–=>  ú±W}ÿFx]ÑZ›ÛëhÑ_¡ÞÑÝ] =xEøWéŠVü9Ó¡ò­õض/þ½³ãÿ” ÀÔê®[¡¦–I}Ë¥ü'Âÿ$iàÃÅK"ŠüvT:?…g«´³ë²Çš »ÝÃÁW9>˜8©&Ÿà®…e}cS¹»aÜ"ù@zýhõߌý†A šŒ¹R¸H‚?Q«¯úQ®·ÃÓ×s¹à³¸¨©Óê}O3k.'øQÚ¿Õÿ±dñi!SMþþk~”è "TŠ="ø|ªÒd‘žçŽÔ´ÚÿMéð:@‹Œ¶+p‡oËš€j^,èâL/H#ú‚÷-ÇéO:#«ô¾¨×'LÁjfFÄбb0=IíJj}6{%—4fÒû’ÿÇ#8µPÞ–7èÅ:Ϩt-FÝì’Ww–3´²üª•Ô¬¥ó/¡“èjòêN˜Ñìck¨Ád Ä´€ŽÇåTïXm‹Q‡ 2öèÍéÎ+WÐçŠÚÅuùõ\spO%_àö™å’4f,#Tn#%Ô¯îuM&ÖÚH­„Út[¨ØØÏósñþB¢hyÝïO–9V!r-KÂÙ@Åp_ŽN}kÔpèÀº%oÕnÖ6W^r‹»hÖ.Wâ rqÈÇ8ùRVÝê3êæýîy Ë”ÁÝœîÏnÿ*Y¤ <àJ#ܪ6FÏæý(ÇUhñé7â8Y䲑¶òúIŽ}ÆpG¸¨”RD%cžµ†Ì_£i÷×W±<Èd›•ˆåaïúP½>r÷±¥Üìñ+Ïí’Œ–‡ (ãŒÖŽí!hOÖ¡.‘Òvì#Ô"Ý U“Î9#'ᦶó=®á FуȘܕ2 Å,͈vEןƬè~ W%Î6pyB-«7œ ù ‚¼9ÏnÇ·­4µ„;ÄAøÓ¬®q†Àô5$«£D¼U½A¥|´Æ6ð~tŽ•qÕ7Vo=¶›qm»‘X€}©+ÍC[ÿ§ÝFG0çôÅfm›ði¨ãÿô=Š(Kí( =¹§›åɨä:ÜvŽÆ{@ÛÖVLœý3Å<G¦-¿À?Ëñ ~´× 0ª<´ÐkL€}³h”°ˆ\ò8=ëoaht­ÄÅ<ëbò`ýãÇ4HOöÐ.@F.Ž8HxŸw[èšU¢ù³ÇkºMƒ<¶d{"µK²½GxX„lr}+Wy“¼î÷Í¢T;Bé»ÓŠykÒï$,÷7„{ š'©ÅË §jr:PçÁ\Tò}M(žR†2ÀGrÃnŽU˧šA&pqG‡ÎïUˆn;S¸ç¾)Šd‹Œšé9¶œþæqº0M4ÐA6¢A÷@94îá—Ê+žsVD¢La*(‰‘¿ˆà©9 0²°Çœò8ŠÝ±6œκÓÖ¬¦Ü6êþj‚™N1ùùTdɶIŽ;“C#‰«—ùzQ­:HU7´Ñ“züA”cÚŠX²ù‹Ï­•瑊Æ`}ê'wá÷Tuf°OÚOpbRet8TöSó>•0¾àݱ“NzƉ<7KÛc¥E~·§x9*èÊ8íÜ}i]_Ýè”\ÖçEGÕýÖ:õ-Ô^#I×}Ss¬u\äéÑÂóAc;ñ…çÜüª+>®èÙëËlR9ÆàTîØOe#¸â³øºJ«Éн7dÖ‘Ikm¹_©çüÔÊÊåÚK¼±}ô,ûVxCÔW¼ý­|¹¢Tú‘ÈÍYDÑ‚ñag_SØü©¸sgå_!ÔæeŠ”ù;dPûÖÂî,êØÇÝì²;o“(øÁ_B}é•ʇÜÍè0*ØÝr ߺ€ãóÃ}Õ88ü(ÕµÜò0oݹæ9G#ò ZV"¿ç×{c¿ =2´Åæ¨? g ¿J»K+ÅVxù>ئ®ÅѶ>”ª@UG“$…}¤l‘Y*ÿ$P¦A|C¶’~’ÕWrü03|_JãYˆ.p~ß…wSÚ+P·Ù»Ï·pF~UÄú´& ¹#'…vP=°i|ãZ#JÒ¼{ׇ~N©ÅP4‘êÊŠô»"ìžÀÎkDÎß‹½qĂ淋yúdõE¾‘vºIŸÊû[ ȯþ’qÞ€Äe÷î;³sëDà×uˆt—ÑâÔo#Ó¥“{Û,¤D[ýDg£>ôSõ†ª¶š-„“~)±õ;vúÔQ f›u­ê—«n5;Þ˜»²¨úÃð©wNé¶–wi“Ä+{€Ùܰ˕#ð«;Uð>n„Ó´Î¥·a­]ÛÌ$½¶’ ÑdöÂ’3ïULjý;f5ÍL[é÷öš”*n.¢GŒÃ8ìW'·&†QmT]qÈSý–è}BSq¨x·9˱²ÇæZ‹Xô7…ˆ@“«ÌÀóƒ: þ•Nilš…ÚÃHê~ó"’V±q [™ Šg*¿{ Wâ¸ò•ìh©ÔÁY[yY™‰n{g9ü*;ªÎC0%·³3ßšÛeëÛŒCö:ͦ…x\M ʪ/dc½Ñn'ŸYÜ69bÙ¡oB-áÜ9r dz{Óþž`·Ê049VÜr ´’rÍù'-o=¬¥çŸ½[Á¦K3• PsœÑ©ýžÊ2DCáÐk6âVË´œú×Y25Â>³K Ý/ê2×´©m´ÙdÜ «yFù3؃ÍMuÞ¡¶–á2nÜ0lÔ68¦ˆ·ŠI9;Pœ ÚôØÎ1{ûæB;+c&“'¤7Ú=kKƒù¦ÖÚ ÝÔm$pìý Q“K—hº9c/ »iÚ' ª§ŸQXV-+mVBÇ šsq¥^ÛÊb‘HîK[ĉf…RIý V±Iö¨=ñð?Ñ´d¾†GšibT‡wv ŸÃ4ÒâÄAp& w0Áç·éN-o®lŒi‡lŸ ¤ú‚sëÛš= h0ÝõEÕ¥ÃÏ»!thTHÀãŒü¨]hÛ‡‰“Íe8<žäû×`xq¹ºSN“v7[)Úx?w8ýk•uýëF(תJJO•&qž{WIø%®Xë)mgmtóÝØGܬ‘…e¶>Xéjn)hä“kì$?Uëóã*.ŠžÁT V9U´ß1fsæž[`*äw„ZÝÉç놽Ԭ?æÅm'µ- þ!{`S¾—‰¹NOøõœŸCüú*¢FòÉê1K߸H à À×HlÄùPi¯Ê¬|¯@Ü ×JÙ‚ ¼•ÞB  ú¼sjš†Óp¿m4äs„dþTBîCid9rÒˆø7b÷ú÷TÏDäÛsŒ ÷ö¨ÊÚ[KpÅIßÑgYÚÃge¼ µ#@ª ¤õ–‰\20?0¤ÿjqAºÒqLê,a*03Ë£·>¦”Ëû[„wI/ÉKýµ“©gB¤ ãúE%Õ ¤Fѳ݉ÚÇ‘Zëö÷v}T× ذÄd vl‘Øý+~¦ò›MŽä2äH?zÓ§»OÂ(Ö³Jº¶9éæfÒ˜Ž)kÂW_qö¦Zà *Xã\í“éY‘¤!Ï–sZ1“>HFöfŠdc¼F…ŠöäŒùÑ NÆI¼7éÍ[nd±“È™Iì ŸéL iŽ}»šâî(O¦yÔãM´ûg‡Ú¾œ{Ãq>Gl‚+;Q¬ê/³OO¦Ý§yÝ¡·+Ɖ”¡Èî>tJÙ¼¹Æh]”¢àGsƒ•EWÉî@Áþ”ñ¥Q†ûÆŸ´Ò£=Çm†5"Íd¼*«ëá#[ÆÑ3G"ÎÃp<‘þjËÖ®-27Æ2¹?Z‚uCii¤´·ÓÎ.‹"(Ôm`q’Äö+w§_ÙÛ¹7FÀqŒ>­ì&Òµ?°éÿ RÆÕ>ñeíYîëƒIrÀ]²hÝla”®&GG ~Û¾~ÕÛ“Þ£¿ÌÕ/—w§Kûʼni<Õl’¡N*ã¶•e°K˜ý@o˜ÆÕP¶xÔ¬Ý×wÅœö¤&\åséšq$€¶>,g4™œ“íWűwÀ÷÷Igycr\)YU?ÌéRu3G  óª×ÆyE¯L-äYV¶–x>ªÙÿ5=é{”Ô4ôòÎàQeˆû©¿:­öÑ.5L6Aa¿ ñàsó¬[J<Â÷Èíí[ÊR4ø‡&¹pvÐEØYœ ?|íÛ"¸‹¬ÐÃÔ°2m);©w è0„ãâ¸ãÆ›&´ñW*ŸÃ3nǶjŒË‹ÁÛ!€qÞµ­²GcåYÛžæ•OìÒ½[2•î1^b¤›.Ù»ÂÛ_µ Ë›íDÁm§“9U$è®’Õú”*CnñZÄA–áþ\s‚Owgx¢Ycek¦ØéÍy±ZúÞ«Y¢+ʆÁõ¥úR>™Ð¬uÝ{]‰5/´<ÚtvQ7&õ˜œ€F;Q=[£-,úu,-ˇN$ÿ9#'`ùÇ¥®úmºš(¼÷ÓmK9v|g(øàúcÒºKtiƒR´Uz•Ôïpäo\¹ÎF=}E!»H¸#þš°uþ†E¾™mZçËGl%Ÿv¡gò_Æ£×)ynëº6\œ'ðÉüš„ÓèÖÀ·„²Œ²œ~Õy#š9s£\¤òÃåE#c*<|óÚƒ¼j›·66T„hCd…nÞ´¬ƒ®Õa äzg5›D3 „U.yæ’PY Î2+®ˆn‡–f“îsÜ ˜OÑaeÒiÔGOºýË*¬ÂhÜÈÜ}F½ µY¼›[RÆyBbºÇHNx§èÐIåïò-YGãs7ô¬Uõ\š<ø0ãVòJŸáycz=,sFsŸIä•É.“Üs‘ï[Š^ô"Ül@õ±åg‘Ú·cʳ:]’î–º}cFn“[YnçšE’ÃiÁ”áX}Ÿ˜ÍGo¬î4ûùìn!1O†9QŽ °¯hÓIe©CsnÅ%W wÈíSêmm­Ïqfoîã r°cá#¸cñQ¹&OBÉ“áXÜ,Ö'‚y­ä'ÂAùŠÔ+ŽOj%$ÈXC—SæF1î{ÒÑÛ“3éßÐæ‹hPqƒéŽ)Ä nSwÌÑ·Ñ­tûç}MÆÂAò"_1Ï×ÐQkKKKöç TVe ·Ðc…XÍnú$¶öså˜åÑV'ß&“ˈ-Ñ1ò.px>õšÒ57µi ´ö7784ÛÅf*¬­ÿÒ1AºÏN–Õ­e0\IJǔYTyôÇ,èNÊËZóµTÆrÄ“Žõ¿\Z´:9¿¸Xn@*-¥FË&dc·¿¶(±¤Fh6¿fr Žù´aüÅxœ«/µ:Ó…³¾ëÄsîQ¹ƒKÒÚqi|ÏŸä‘pjö¬R-§hgcgÔ:äñYZGw}!lqF[h$÷ÇÐÔëJðÄZ$”hWˆî™`ýjúý†´å]3©.Ö$¹Y¢U—$)FਮŽÞáo$–yÉHþ 9Èc÷‰ÓÚ©ªý¨rSrç$›uåŸ/5ŽœN¥>Ÿz Ïo!Žm |,8#"žA¥XÇnY®g@øÙ´÷úÔÃÇ,éþ)õ%˜•‹ÂAŽ@?‡z®ÏÚ&D|Âc#hQL'B“âL1¬XY¯HyË#…½hñÿ.ÞçQXá*Ãs*Eª;”}Ǽçò pÃ6c™U$@Ãá'¿åS&˜ üÂÎÁ9b¶HÝœ*.\ž)ÛZÝÉ‚`—889ãó£#§O&¹lòÆÈ‘¶ö—Ôc°ùUY2,qr}"Ìxå–JížÂò 6ÉnÉ(ÊrGÏŠôrÀ–‘™˜wÍ_°'NÚÛÇ 8·“Ȥy’;$úœwñ'¥ô‹}JÒ^›¸ ͶZ6Ïðäܹöõ¤t~± ÙV5¯§áÿ°þ«ÑréñûÚ]ÿ™šæõÐÎò™ñÈçêÒ厒²$¢#ç’úT÷¢|'Ö:‹¢õ=ZÒâ´YËå5º·ÆÿeÆ{ç8ùb«î¡Óoti_IÔme†ê"Tq‚¤ú|þµ¹ú©§Ë³ÚòŒ\K$’ ‡‘e8áOo­ –{…º»î?ŽÔ•—€NG½lòLʬT`úâ£.xä_L%kà%o«§×?¥¡YmíQ2¦âŒœäò~¹£‘E,ÛaA1Æ1Núlvcmùb>§—~d¾‘‹;Ѩð«¶Þƽ«0{Ç9 ±¶"üéI>Ïf¾^i3ܞƚÚÀó¹”îf#õÍ>ÕrŒá¿Ù&Ôg·Ó¢ãÝîþTxþ•htö›“¡ÛØÛ¯ÁçêHäÔOÃ…]Gªou—ÇÙ­¬eKq`2SSuM6hMBÔü?ûAYñΧ–M¾85}‡ QUÈæ/½øS~Ú Ø!³žàÛ¤“ǽòÚ6Ë*?:P^[,—0?þEÿ5ñFIoú{ìw1Â÷2¢‹´“ŒQå”\XÝ!¿SÛiñëRÃ"ÚépÌ¥›€Ìûޝ«ëá ÏO™SƒÊ“ÍDuîêeŽææïx¼’)PÁ{=~U#‘шUÚXƒ·©Ç­‚K”€ÖFVäüšh×+i)Yð¥­hÌ’”í.0¿:ŽÄ&3˜Õw¿ãŽÞ”j؈¡. ØrÎÞŸ!Z±¿d¢J¼;¶´¼êýȹˆ£=Ñb>öÃóþ¦¬.Ó"‡_ÕôégI’[Ô”í\`JŠYOÐçò®tÕ5-CJê>ÚI³%¢¬q© 2—fàAwxªj:ÚGw¨–2µâʉ,v äŸjÈÔ5,²~yF¾Ÿtq%ᮬÑONu>£¤¹ØÐܳFOÝ’7åAÿïÒ„´q‘ñ1Ûü wZ±ÿio±õôW†"°ÞÙÎyÉ\äï‚*¹ŽHá°òTn–=)ý4Ô±$¼ j"ÖFþÏk²²ÛAk¹œ¦['×¶B颽º+dpÄ0ÚÀcäjà¡{¢uv¡£ê“íQ¬ÿrÇŒŸÇ5D¤ýÞ:.i{7çûnÂêÜMð}Aæ´—ÌÏ’œw;øÅ4&{u’kHÆ6ï07ÝçÕMeî„Öa×xiÖ$¯Ö¬)NћɔÉDƒµ®Mý£m ¯ˆ×œK ?×½uM°E»T fõ5ÎßµDP¶·¤_,,“K,™9ìÄÿz«2¸Ùvò¢•™ƒ0 æµÈ÷­¦Õ|æÛµ¹<þT•(:­ö(O&“wPØÍlÇ*d$¥€L{q\MúrKh ºK»˜J¹ØÊpß,ŽYhv½sá|rÛº6· 8…¶w¹…›àÛóUÐé×/.¨¸ûİUÐìÚ›%´bÞæ”L æ&ìYq‚1Áô¢¯V“à“t7+j¢÷¬YDÚM’J<:Cÿ< £â>•iÉc •ªÚÚ[¥¬p†%SƒÜÜÇŸV½8°ë½ï§`Ô//£…”…F’8Æ~á?ëø˜ûŠ[P×fXm A6…>YÏbœ—b}O:l±qÉê?>hŒu¹º–cåÄJ´¬x&4äñŸ‰'åTÏQèRY=øŒË8ÿ „ S#ÓûàÕè5 º©bÓõh.¬žyDvínK\Ë `0¥sì£ëP^¡Õí4þ¨4ýSs$Mo w`I¸åžË–äúÔdAÒõY]­!±½žéIŒï ÉÊc·½/zòž¢Š=7͆2BbxÌÒ¦UC3qÈÈíéVçKu  Ó÷0Gc!×ášu(rË,ª|¸ç?é•Ô?{[õ>«¬÷¥›dϸòˆƒâÛîx©ixÊ×ýÃý&ÚÑ_\{‹ÉNÙã—)’¹<ú“€Éó ¿ÍTç‹24­]î-¡Sm.2.¶C¨üÅt7PE™qÚFðé×9khÉ;­ùÜÐsÎPÈO ƒPž±µƒWÒ§´‘Áb7;sñ>Mÿ&,**κàç;)WH^!(<Ûù³éY1ºÜ¦VGVÃ+ >Ø¢:¬6—Riq¬ DÞb•O?#íÅY'7fYNé3’Xä“ó5 ‰Y2v‰5üz.­§ßGM-¼©(þëmlóV‰¾1Ç×Öv³iFÌY‰â]êÒ2žGÖªG‘çÄ’à·¦)Rîúsš§.‡|ÐÏ%ò‡Où§&8J鞺tw‹‘–^0>˜­QAQñpÝþT¢„$2Äz×aþPqN%E ؼR}šExYYãpÈýjUÒ7Ú~£®ÅiÔh>Ë2ùE¢Â´e¸ 1Üç­CÔ9#Šuœç·å\Õêmó§µÛ­ùÍ·¨npëèÃäF(CÇ´Ïj±uW¬ü>‹S¤Õú}WDrÓZç‡>åI…Adb¬„žj}er†À#KBÌ[$··4ŒryIÛâõ¥c™_癩8ïDÎà(ÖÊ.RhFQv ùÓ¤möKFfQ€Å}3šA5 r>£úö4òÖîƒdÈßù«-·f”)!k8ôÔˆy­"18LŠÕzx¸±UÓ¤yFs´ ¿ÞÙ[yÌÌŠdaÈE\戢Øjztº]ÝŠÇ)„›y R²+“O¸¤rz„!.ýšøý76l\µÊáLv÷ªxµ~)ÅÔ­D:;‹#Yß_ÙÍä[@d›%X_±â–Õ­õÉ!‚âþ ±¾DDÆà;âµT¯É‡µ¿ ¼N꾌[?§®P™2îI9îjÁÔúïĽedƒSê˘"aƒ/UHt/Tuéq¡i3Äû·ªaAÆF{ŒƒV͇Ýyz€½ nšRξ8¤õxu ¯g¯,ßôW§ã„¿Yvº«þßÜ…\èjÏw©]ÝÞ\NÛ¦–GÉã5ê ?ìzä‘G¸*>ÕÒ?á^¯wo$ú½õþšÑJc –J#“Ž\3Ÿ¥4ñ3Áh´NœõµÍÙ#mÜ·³2º±ÿ†S’äQè4Ú•‘,’»é~@õ­¦å¡¥†ÖÝWÕœív‹þƆ|óxw~ )‡¦¤­ÒO4`ÜAϽ×ln4ý>KYYš/8: ½Îvš9evuSŠÒš©QæÔ¯‘ÙÔîX¨Û+¶;$Ô§Ãk˜n5‰ìî•!3GÃÈØÚ}J‹iˆÄËs&HxúÖ`ŽK‡´­ §âB~T¦«¿ŠXî¬{E¨Z|ÑË]Aâ®»Ó§HÒ£Ó.`–tŒ$›1”qÚ©®¯Õì.!Óìñ™Rãvøää!ᇵ º‹Z~쬸䴹žˆ³iú¬wW ’H<­dú_¢-\îšZ¯Y÷q¼¹é·ê&]ä­…ÌRÿù\ûã€OµHÿjî…ŽÞk>§Ó%´ºûÒ)$pTçÔ`ñPÍhi±é–â(üã>°ÉLüUxÉ5¥÷ƒºn—-»_XÇ"ŜIJÆÒ ãŸ…xÏÒ·[£«96~”Ô—!¬§b6øÐ•Áíž8¤äÑ5tÉ’kI•ã•BG°–ÉR}Ò» ûW讌ŽKÈ9.| Öчl‚ƒ–ì3QN¶ñ’™ˆ\ÚôÁÊ oIP;cžÄ~Û•Ólå»í^·°•ö™w ¡qK,L«œgh&𨼖ÒyÊÛ{Z›ø¯âPxƒ-²êÛÛÛZå ¶·V¥sžçf¡0ÛHÈòHêÀÛžI=€©\v±”Éb¡•ÎÔ±³ÜþtD'™»øàJ3âP L‹Â0sëšt•³ßjVÖ‘©a¼6¨š··À2{y-¾ž´{{+Ynl¢$ÿ†NPãÔÔšìÜFˆã>b‚_w'çH[[À–Ïþ1–ÿW›Cä®ÂLÀ°Ø=TŠÒŒ8¤º2'')6ÌÛéí!W•WäãÒ†õÚÁem¦Ù±WòˆcÐäš]Í ¥“O$Œ!ˆp}GµRýU'PõVº/4Ý>y--leóô5N|• ¾Y~—쉾‘{Gy£ôv‡•åÜgJž=ÙÏ™)ÇûUº„fÕ£S|NÉÍ?}'^±—KÔÀòHæ6` >”"}3Vy67ˆ§?øl8¬¬8TSÜÍŒÙÕôámÒ3}uƒ¿ Ùö?=]e"´ &¯2Ë#av.=ãÍEã´¼i’# ɹÔco„@÷«E|?Kxb‹ì«+ÅìÞáI`Å·n {‚8®ÉëýŒü¢#eåM,é{re€mŒ•Èö;ýˆJ£»99$cÖ¬N·²Ð´ Øum!.$RÈG@G#qýîÀóUí¼Î·10Qä¶29>â™ôÉ7’qqªóö!ªRQR”¬o§Kå'—0-7¦Å8ž´ >TÿK ) !s´±È>õ‰â!Y¥s´zûVâ_Fvâ/6¬u¨ÑÛZ»¤E@™NÔ_LgÓiþÎwÛu¯NÝ[²Ê“Í3Ë‘ñí8ÿìоմ6ºÒµ«ÈÑe(ЮℓÜççíP—¾¼›U‹^Ò>ÝZ^K ÷(pª¸øåãžkÏæ÷Vy*Uá¯îláÙí§gWxÏ¢éÚßA^Mž¦„[Ý_<ye> ·éOÎÅ2*»–P>æGÄ¿/§ù§ÜP…•‡rºôÔI&.€Yˆÿ‡…À5Ut>§öN·Ó5­kíx”G&òI*A¿2*àñã÷lý8eÔÍÛÁo2†­#•ïÏ|W=Í.‚¬M¿»Ü\@¤ƒžÙSïƒøRY$”ØÔÂŽÒеqmöiÕ|ØGü@;cÜÓÅ•ŽVîÝ¡õ,£+úT7¦õÕºGKê+&,²Â¯)^LSµÀQÚ¤õ›5š;]ó#m‘Cã? xíå‰âP»û7cToíf·k¬Êó¤Á#<óW5Íý¾¥(,>5`O®*²ñ¯@¶ŠeÕn VvÈD¬Ò2rü!yà÷ªr¯‹/ÂÒ‘Ï7ZHŠÇíis˜’˜ç„¶1ꨬÛiÖ³éï"Þíº…HŒd«&9b݆õ£tóÏ0q§ÈßË™GÅKÇÒòqmimp„÷I”⓺O°TzU­½Ì -ÏœŠÀÈ#ǵ×/-¯¯7[iðØÅE\dŒwúžõ¬¶%ÃZ\$:F\“*1éÁ¬[Ú-µŠjr-¼$ q™!”d’ƒâ7 Û"¥»|3{-2K‹ie’æf‘Z98nä)ôŸ4sMè½n] mwM·¹¼Òã“Ëyã\oôíîO°ëݪÁSÇRÀº•…Ô¡nDêÍ&ÓÁeeþj¿ú×\<6ÔõÍÚêÑâ 4 ùJT¨À??ZžIQMœÿ¥Ûë']³°ýÈ÷ÓÛMæ=³FwHn+†à.;É£Éâ6¥i«GLCJ­Ú‡m°©î£'ÿ/¥émcý£ÕÏSu?QÙi·6KØA„-Ä!+(çâ;‡Ïšª5]JçSÕnïnLfYæy¤ò×bå¿Ò¾ƒåA¾åE›~*Dã¨úê^¢}*îKưÔ4ùDð9PÜä°ÇÝlÆ´n·´›Mµ=5=^ ËË‚2>ðàPGo\š­nÞQ°²e¹ùšVÒ+«§)nãjX÷{±Ço­ä¯uø.n˜êí©õôZ†âÜ>D„' –|ýîÙÅt:‡Iô´z½˜kËë»gä¸pòD_„“÷FHÀ®k¹á^x¤ÎFÑÇþµgxqÔvºÝ”‘õýÃEc ¸¸PùÝeR£ÿx¸Šh´›©#êÝsU´kY£²»X.•IÓ)'¶}?Pm^ií'’Öe1M •*O ˆòÏÆ>dJe×¾1JúT½;Ñöé9“g ºY‚ž J‚Ýõö¥gsªÞj^K)”ß ã:•*&¯‘=vßS¹KΧ·……´Ëh׌YI;}ÿµD£Uã{mî?½Öz†î•Ó4;}>_±É,·¤þõ#0Ã0'Ú@|ÉUBä–àÐ'aN)Fä–‰A’ノ k,¡¶  gÖ­ý/N²m*Ò `I j¬Ø=GbŒ3ù«z²ÔÚk·Q„ “0‚ñKéu«,å ªãj*LKH³šûS¶°¶òÞk™’$'’Àcõ¬j)qe=œñŸ6 oÿP84ÞÆâ{;ÈnmÎÉã‘^6ö`r+:ìú†¡q}<…å™Ë¹Æ9=éÕ'`žGwR6î>“’||'•i”!Ôž=¨ìV³Z[Ía;’qðü°}ûÑ&Π·‡Fz^ŽåÏ™jÿù„ò$¸aøŠ'ÖZè}E,vŽa: ›qÄ¿ÝüAÈ#åP¥GÑÄ!õ«E”ugFÉ¢9Ρ¥ƒu§·ó<_ø±~ÇãQåQ è‹Ë4Lû ;ŽÔÖ6bãï.=*C¥MØ´ÒD[yÃÙÏcôꉡ»m؀ðh΢ԓDѶ|v 8Ni´3¡1ÊÙ…ÁÏÂM;º×­£O(m/þ_΂]õŒq;*äéî>µe“àÜœñ"Äð›VéþšÔµ'Öüµ·’ؤG?1øñU¶©­¢jr\E"FB!ÿú~€þ ×µiµEî"SÀšen[pÞKgÐÒ˜½sË+wº¸ñÀÆO[%ÕmS‰59î2é$&UpXŸíF­î¥êm[IÑE¥Ì‘ Did¼…Î1éÚ„ôæ“orY•‚dya[¦]–ºG‰Ý=œQ8¯Hp„û ©>Y̶×Oéñt–‹umeol°Ë,!£Œ.Å+»Ð|«“¬ôϵ‚Åk­ÜŸZêÚï¯,5>—Ót(¬ÝMÍÜŽ%v^<¢èÃç–ó®S·ÔÒš#b忆Aì{RòNQ¸`ö£“ü_£Kë1¦idhš;†fóùFÇNžhZy¼øàSˆÙGaNµó4 L’*c$åŽ{“Ké1É,‘ZA,…†T7 ÏëMáź ¿2|ªò6t–ÙÆY¥·?yÊå‡×åZ]YI,¦8TÊHB)o^;T£LÓ$¸¹¸XP¯/#  ž*Êè=Gý›Ðn§:~™.-㉦i¿Š;ßàäü…S'H±'DC¥-åÑ4U~ ·0Ï¿ýÝAgOô•?tSßßÜÖïogªÝÚZ±$Gàó#üègZkn³ªEy¤4Æ"…~8Ê úgŸÎ¡ókìCµ“H¨v®Ì‡ç×åEjÊ¥hž­ö¥ax—Z–¢. v_5®œ¶ý¼ .A#Ÿ¥Y]¥hþ(YÍ+]Ki@²Ü´~[Fލ£ œàe,U©Á¡a5¼ðÇp1¼ÂÄáöàíÊóÏÊ¡öýC{ÓzÔÚU´bPÑÐWø˜t{£ØZé¶1YØÄª‘ç'ýGÜÔÄŽ¦—§´ût…Síw—%ÆAQèqé@-¼bÕbK¦iò{®áýÍgj_ξ-"¨;/¼³Î3Æ=)HØ…o‡v®j¡ƒÆŸñ´H±íÄj5¥x»as,p äÉ#TIÔ–'€/ÏÐÓIŽübÖ“KÐ…ŒL‘Þ^+胒Þý…RwE›^^2¸øJÝ8ÛÏ~ýêàëϺ“©õ©5D»Ó•TG JIqÛ8À>õ¼ð‡ª£É,¦Çú'ÐÑqEqo /Jë]C­Jútš•ëç·ÌXmüjD‘ˆLï´lËÎ1ÏaMúo£úŸ¦õ¨u+Ý<Åk|÷È`PüÉmêÝ c'G^jë¨ù× ¹‰m@ò F=óòâ™ÓJ1U|²D%'ø!>ëuvŽ=ÇÊ•¾•VîÛÙ‡üÓm9wÀNv„o„Ô½Â(r7qZÔ¢dÓlikáÍ—VDú½Åô¶¬NÅT@HÛÇsZÃá\¶v­o§õ-ÔH_qC O¹°*™ô;OþÏÄËÞF?{½(ò£²ä°Ç©ã5…‘üÛ7a±"§½ðïYŽÙ¬ÚÌ6‘™-À<¤aBm`†Ž?¹Jµ5 I&` PAɪÚîÙìa6š dô“Æi­{ÚÖCàŸÐâÝ €ÊÄ#ëIjW>TÐ\ÿ…w >ÜéZÛ²]ä†ÈÚE1ñš.fC†Ü¯»×;«C;¬m™øbýÄÔ´Ñ©ôçSCq¨V… ¹vÿÂWd“!ü3ô¡ž [ÛíLÔ!¸V²uFYr`Þ= üêEÒ”7vv:áQ=¼ð=µü¥Xa×§³î*¸Ô´9ºÄ{=Ê×›Ò[[…$¥Å³ÿ0ÿ˸\ç¶+vݳj5\GBCyuàoV@nb… ¹Û4 §9h˜g$ñôÅWž]Úǧ\Ø~í‘/eÌnÊ‘¾`'?<ÕëÔº ´^õ :l-xº´ö×dFê8$òNG8"¢zd 7Nh¤¸F‚,Ç,E1$¨< AŽ0E*Y*Ô+ƒAhËMÁ‹!}Í?¶/(/ xåèµ14 ÉŒç×éOî¼Ï³$q¨2IÛä=ëLËŠ¶@üddnоÚÁ^"¬YJò3úæËË[I$—ÈÎyøÿ5Ô>*ÛCmÑú–ôÞÜ3ܨï\ßu¦éżËu¸ŽQ¦±ý %š·a.Ù¯ZX´‹ý çIÑJª õ«OTŽÞ9k&–HT¯Þ¹çÁ(m:½-ÊLг)'j·ÈœŠè{÷X\–xýóUø_ħ"©ŒZÝL¡­Äé÷· ¥1ë:n¤éùôÔ“Ê2FʪÉ÷¥Ha6wÆA*yùÒ‚"%bhíE4˜'ê\iÚÓZ]'˜¶Ò4m$¨ àãñ£½{ÓiÛVI"˳mìÛ´àa}jw⟇š¶§ÖúœºSD»«ª“Œ?®j qá¿Q[|2ÍeÿšàéšÌm&ÐüZk‘^™Ñt~¢ê Ë;KÙm-Jn†I §8Ëç¼ýy§Þ)èz‡FÞÅÒ³j6×ñÙ(håH”æ…b¤ŽOsÎhe·Gß[a³y”ç+t˜Û霑ìi îž×®‹¹nöÌ3¬¤Ø`×]’šLצµ_±õ›},IpÜFòÆyF\ò§Üc9Õuu&¬Ú2ÞÉ Åw¢k+•/å¨9òÓâ#ŽÀŒvÅTZR\ôüN¶HíÅÄŠnc¸¶YQl•V¿LêN¯¤ÞXÇm³FìX+0·#Ÿ7É,WûÓSº•×%rÚ2êqj²è×]%«ù¢-Œ BIç‘Î=ª8ÑJ³±‘Û#¾uihóÇa®™z+¨ Ô-eÊŸO¹o%¦ÎWáWôç_zõĶzN£w¦ßÁsaÇÒ¦š‹g/MÜÝMy*Ý[¼f(L;–Ps“»Ó~µÑ/-­à¹Šh·‰QvŸT`ÅYâ#ZÚßè6ZFŒ‹©Ûy<–À@ 0bIš6­ªù øÁáØÐ,tIà]±^®P§!¸S€~{¸ú‹Åc«tž½o%ݬ°¶Ààa[ßÔV¿Ö¶ýYàþŸ¥]¾ŠT!ÝÅ8ùU'Tu¡¬M\Ë$ ìL¿}(bšDªKžÂú¥°³ÞÖï öwżè£lîÁöíRN¬è-$úÊêzx¬s¬Ip¥ÊH7°9\Uîm|‰b I°íÇ£ÒK&›4baå¢ʃÝ@£nŽUäuy°%0ùW²¾Ý© d·¶ìQý¡lìÖ;¾ ¾Ž3!Ê@n?,ŸÂŒutRï¬5¸làA•²µ`P;Ó-+[Òe¹¸´Òéb8Àsa¤qìà}k&Z‡_ø`¾dÁagÓ‘e¤Óç¶ ‰½VGÿË„|ÍEt>Ÿ¾Õ/OØí·ÃÛˆ$þ‘ŽI©&«¤hö“}¾óWêÇ,¹'Ò…Gך®Ÿq¿Du° ð¨T 1ïÏ­y$¾!Ê¡Ù${§M»ÂbhÂü `g£4;¨u(×ZŠ[7 5¾Ö.6²œñô PÿÿQõ«¨ß[éw¬Gß–ÑCËêâQžxÛËGÀ稦1ã¦ÜŠe•Õ#³¼뎢Õukþ¥¹×'k‹iU{/.Ú']¸dí»‚9ùÕÍþѤî±ÙÙ]ÊÄàgñ9õ®Jèß:;Bé2Xu Û‹«‰çż[|¡* Xž0WÒ¬ zÃ\ë 5¯:rÆÎÚ›}óÈά¨™ œñÏ¡«®)©rÑjô×ZÏÕ|·ÚE¬qÃò[±™‰`ñ¶ÖãZÓPÖ¯ÛK“P]Qg„º€ªFõ Ïo‹>Ø5ѺCUÒ,îmíú˜ÙÅq<—SGeb¤»±Ü~) ÆHô¨:Ý7áBj6»Ô0Ê.#R²\…UYX—ÌhÎhZæ€÷)ðF|{éÍ"ÏHQµ±dŽK[™¦¹™ÚIågBqláŸá÷Ås½Š®â•£0Ø^ù§š”—3ÎÒjwd÷gŸßâ>ô´R˜Ö1 ^H#4h‡Ï`ÍNBº´§qÎݹÏ4K¦¡†%yžtŒðq÷ïý(=â4šÔ…”89=þ”çH¸AæE=¶öʈ—?xûU©µÐÒsäžôUµ„“OëÀÅÐ2:¹¼wùâu‹Øèý"°±AéhRT·Æ¼ÉÆ9# ÒîõT¿D²´‚vD¬dào'ùâ§zHuu欇_‚Ú5ŠÞ7’F Ðpr9ã$~t¼—%êH¯NŸs»Á`Å#ˆÉ0ƒÃv<JöŸ¬YEÿ¶Fd^9|ò÷©†‹§]ÛY_ÊŽ·<ÏñdãbcžjÕzUƒÛ$âÜEu4Ûw)Á×µ[K‚‡IV…qrî—šXµ»*Ôû@¹sKê:ÍäV7?¼ºF;¨Ÿ{¼Ó(†Ç£pWžp WÝ 5ßWYiÒOunò¶]ÒB /§ãIêÚÍæ‘Õ—v_ošîÒ Z520;õ“%*4“÷PÑnuxî!YÞQ ßø£Œ—ÿ§¿=êSá×St¦“`«¨ÜJ/‰ÀXèüMU·×fæùç$1³#Œ`° a[c`ö¨ì”t­·Zô<˜DÔmÁaÁ’ý 5¾m Q¸ŽêÖHÚCÀêAýjéûu¹Ôíbq!/"®Å\’3èvdžö}=§ø]{q&…iyìx¤…$wf!Gy?.2}*ì2†?“ì£,%“âWo<ÐÚ¤JñHªƒ.®>.99õìi+VŒ»%Àh²@\öb}3éVo]AÒ/à…÷QYhÐiÒ,~\FÝ(Â\0ãƒüÝê¦{i¼»H"™÷êGe¶ÕÇóúMÇQE¿¡)éå$Tž9Ü4^¶Aˆ[(Bm ÆO'ñ¨Ç'p~}«­lºgM[%ìà»ròÏf‘rN)ÒtOL»¥Ð¬wàãúVtò&Ü(Ãj£’-¢pNôfõ?Ö­¯ºiõ-MõyÆØ-äd{çè?­[Wþô½Œ÷÷Ú%¬[FÒJUÙ0ù¤ôoµ^i­:zÖÅ4ß´HñE4;Ùçœ÷Å÷%ÁO“£ÊNˆ¹bÞä:F]Ì@|ž;¤í¼xÖ×þñ¤érœs³rŸëO£ñê6Ú.ºe ’—Mýè\d¹ ÓE¿£I§¡µµÔ%XÌû’Ú6ÀWnädñ“íC|Eðß_Ž[G¢n ·³¹ˆ­í,‘.9,žÄàåqŠ®Ç‹/­GömO¦nŠ+‰T¤ã*ÃÔàüóR[O4û[‚ÛPÖ–5Œª-Ì1Nȸä$άÆä¹¢RâÈ.•dt”²IÃqÛÞ”š`¯¹¦Zd­¨=Äñ4§ÍbÈÍRÊÇ‚Bä VöÒ4‹&^ãÞ½ Å3 "Û6ˆGUÃÔ<Ïue¨N¶³¹!aƒFsÈÚ>´ÏGë¡\ÿÛZ€Ç#ýêN±«O¦õ½#FŠâ}S§Ó\Í´‘$R^2ØÆÒsŽÜÕRý+ÔbâI!Ñ.Ö&bTÉÚ ÎÈV6¢;r?ɯ§žè!å׈UzåÛèÄ6?1Gôëí[KKûéÚIçÉ9ì;TÿBÖár&ÒîÐŽùˆÔã¡ÿ¢Gkt¥%VÜŽW>õv|ùW{8²ù’ ·‚˜x€?þß¹ÜÙòü³ÏÖŠiø—Peîª=*=â%ìPh×6ò·ñgÀE€æŸÔRÄìG~êøsÕqhÚŒ–wìL¼o‹øLxþE[×6V§MJÖaûn‹!ilîáÁ{6nï ‚§ÕO¹¦Øs‘ùf¬ Š•Úiz¥¥ŒLo¼ý: VO-/YÔÀ!H'ÿŠŽ¤˜9yƒþv0‘ B6g/¸r¿‚2&ó]À8øy‡Fްy¤òüœzÓµòü¤fVw<{V”º2ã@ΫÜ[´6ÑÞF90°áÀÚ}ǹOTžkRòêkhm^i[›0qµTpÖºÉã_)|mó? 8®Uë™­íú·T[vVˆ\ȑ㰳Kçð7ÝŽ|<Õ£Ñ:ÓN»eO$I²Lã&ºõímM¬r„RÛA,÷®ŠR·¼ÆÈnO¿µvgƒ:ûuCYÉ9ÍÌ_˜÷Ý´c5§|š5É ÄŠÐßJÒàˆág úñÍ’IAU~F˜]”v“g9« uý¤'ÔôÝ~ÎâÎîâÝ.!äG#.JúœUc¢ê}I¨Þ +]Zñ‰ é—<}k£üO¶Šâêͤ‚9ÿ†p$wŸJƒO Y9ߤ¿«"à˜?*O-n¡üJãeAª¦«m¨MìòµÌ*weÉãÿ¿ëGt;î©éuƒU¶}•Ài9V_r1Á¡ýT×úf¯qi¨H÷Q¼¦nr±¦W=O¬\i§O–ì›fER†%äŸÒ«-¢W¬u­¯P’ç§-e“wÆžfÒGº¶2>„še¦Mk ÓŸê "i“Ê’ÚéÌa”÷MêpWäj·E xŽ5†”Hìï’IÍBIÕòH/¡Öô™Ýæ‚DŠSñ•ø£”Ø#‚+}w\³Ô^; F‚GûC:–y¹£ŒzS>ž×n¬&0­ô‘ÂÀîM¡ÔŸ@U¸Å+yªhº†ZëKû%ÁàËfpæTñùb¤Š¾ ºRk1©¸ÔÌð˜'‘"‡V?tü\§­[ZÝte¿T>«çuû=½Õ¤ì£l1`I#ŒqÀ sñdb—ÑšÚÚíšw8^‘Å{2ådš=­ßŽsRˆjÕ€ø`+ušP¥|× {ÇžIi OÙ\ÄÀ¿ÝlñL¯ x_Ê%XŸT9eQSC¶¾µ$cul8ÚG½( )¨ªtq•;rGïNô{…·¸Wb2Xg&™°Ê‘Z`#>”Iœ¹¼¸´¹clä!9Oý)œóN@ÁõÅhÏn¨Ü<|‚=kXÉ-§ŽôDìV7‘b•ÊÆÄnÀ扙¢†æHíÝŒ}¹ã4*Ñ̬@äÓ€­æ#¹×.N»»šñÚy·Éè]›šÍ”Ö Hn|ÆÊ¹«êï‘’à‹¸ƒrBÎÇúÐæðKF’LŨßBTg§ŠÉÃmöS7VyÓ à¹¶*Üy>oñáL æ‘ †ÞG™¸DX¹öâ­¸ðËJéÍ1¯/º FpLQ4 ¼§‡ù­<1ë‚é¨Q¦Óõ¨ìË\Éqô(—àíÍzsÃ^Îâ=KXСÔ3ìçËr=ûúÔGX†hu+ –±yÅ–&;¼¾~îGÐ6~-t=ÈĺŒÐH}%¶#úqQN¦¿éMBêK\Ó$œºLåo”Â&EÃgŒzÓÑ  #Œ1àçµ4Õ más}xQVM¬XæüiêÁ4³X#€¥æ|zðM9Ñà€ß^DóDèÇ%‡®hÿÙ!Òm±ŠðªØpJç9öô­\8“Òî(rk% o¬ç·¿»¹¶¸xš;âײ±<~¯Þ•ÔÚóA´×n<éËÙˆ.]xbðߘª…§Óíõ t]ÙC0K -+.K… €>‡ó©¿NuåœpÃÓ'·‹&5E\&;g9¬©G↓I¬5=WV¸{+VhÝÙÊD¬ÍñwíU§ZYÜ®¥§Z´.!Üí„åÁØŠ¸úãU›Ã…ýém1·{˜C F݆ÿI ØóT~•ÔÚ–­=ý÷à `º ¨ ÎNKô µ I7ÈOÝÝh}w§j·6ŽÉ1o7( …>§ÖÝxM­ë¬u¸.íÊ^±¸HÝX2«€~x5#²Ñ4þ»Ô£†÷QËYÚî>KŒœ`æ­í.ÃìÖðÚDKy1¬|ü€ŸJè»VÂÉQΩà¿Y,¤C³°í‰E`x1ױ͡M2úåV$ý3]m¤iÆþ&ÌÒoÔ:wGtÝÆ·¨á„@­´Cšl|(=½Éù|ê©ejTŠš~qðÇ¢ît^®[ž¤¸H»Ó\[[JÊ&–A’¡W<ö®±Ð¬–Ó«tö±Ó µ]JÀˬL¨Û¤*BD²_$Œ‘Ž}k˜|Ò5o|[:Þ®Ë$6Íö»©1Âú$cåòö®‹›ª_NêN¥óì¥Ôí­.má0DBý™í+–# m'÷£wä$¿¼%ê9µh­WDÓ$‘[Ê3`¹‘߀$íÀÈù5[§OÚØêS‰çžk˜¸†I¿d?ðãe)Û½:ñ*ÿSöm»Ôfœ}¿Sþà©ÀÌÒçáã·5ËZ[jö]6º}¶§}k%½Ï™o$NFèÛï«~„~5Á ޏ°ÓË÷‡áFa±p ŒóŸjãë_úþ׈z“P`N—kþƒR®•ñoÄýKV´Òmu8®n.¦XcI,âl1=ÏÀ8ªå#¼“?Ú«JÐáéhg+5éó.°yXáOýGúW4 [¡ç ì^«ðcBê‹öÕõ›½JMNU_:T”m.ÕÚ@ç£7³WO• i­ê1qÙ¢Cý¨±Î+‹M3—”숨’s»×éH™2~ Çé]wû5–r¶½JâKcý ¹ýœ5Äȶ×4çùu'ó«Xý•òR:}à…÷*± v4æçUãa¹ãV•ÇìõÖ‘1ÜižœŸÒ£]Wá—SôÌQÜêñÚERå\¿ÌsE±§L(&Ý F›®êÖöæ ƒ EòÏÄ~!þjYÑÚ«ê×ñ[jš«i¶®‰Wz©†ÑÉϾhf‰¢´ÀÂbarìIb>T­–ž«$€4{ñ…àŸ|úU/_? }z|%û£Ù<èý$OÔö±=Ì &9û+ï  ýâ}[ÓX;AÊñôªçÀ&µ´¿¿Šâkh¤šÑ—!y 2?\"Ý%Ç$Lq…ØÀÑfÔ<ܱ%a–ØôD®lÐö5Lëmos«ÞO Xƒ9ÜxP½tEÖœù!”îõ㚢üNÐnô‰ZPmîY„ ãNCŽß•ŸU RkÁÓÀóµè¡Ë ,Ëe!¸œŸ„Q/te]]NíÝ.bp¡È OÜçåA5/·[Þn·wP˸llcÓ°íô¦Ú•ÍÍÎ,7Q<®²†I cøw¦eê>ìiǰ§¼N÷tG#l8'O­î> ªW¹=7ª‘µHõ'¸¬ñŒÒå„#I÷ƒœEôÙì¯à’Þw«ÜB±# zT>™¡«88î éû«ÙµXRM+H¡±ÏŠ-&D©£¯´OýÒÔ_Û´7^P´ž=GoÄQkyT’ðÄ\·Ïú Óz‚ÞØCpÈÊîŠÜòyäýE·KÈŒ·uÅi9\m.<‘^½¼½ƒL½…&[i áÔr˜Rkž4_µý^}pâÕ$bPÊ gçïcçWïVÊ'‘92ÜÝËåªÿ¤!ËgåŠf!‘»1àR𙫤?¦…FÙKOá6­ï]B“•"®/ã—Cµ¸ÒîeX&Rå; àóéÅ+ ºÆÓSÔ©§})mZýáÈY¡Š'¸!?J¯ªH<ñ[gÌ™? 1'Gµ Ô·ÇnÄEžy#¹­ô›Ï:ÐüGø? ÁçŠô®³·ÂÁôÍ8"W¾&ßZYÅas},vŠû‘|æÚðj ûïLcˆõ.xÿ¼-ý«A¦¤bìŽé5Í à`v¤³*˜þ'ðE«âM…–©£ «{È$¹·É\:œŽ8ã¿jªÌ3ÿ<2ƒìTÖRi"edl!‡>£µ]½+%ž¿¡C~°GæåÌ6Ž$¿Nh QGÈ’ !°¶?õ­Aãóë‘WÕ×O[HpÚl ï•Æã¥ôüdé6Ãß 3Pu¦ÒNväûŠØprN1ïVáé}ýí<ì2?¥ »é]-IÛfÃØ kˆ¡—N´qtãXØËo5œ¤¸ýÒ~´Âm¨Tòm˜)Î8äþpÙ¾§¸ÑÚO7Ù+d|ÅGZjQe%‚eàœãó®9¤¶÷î¹íI·i%Ëi‹ßÞßLêSæk/Ýó‰Å5‡­.Šì’Ò£L{pwc“Z#±qÎ>ƒaºrø9_)O>X›A¿‰°-êjÞ*¦#k4R’—%<#šNöÑ q· ‡±©Äz=ó0ÝnçR )D>EÜT}Ö ¿_zæérH[HÒ£*+²8# óE'+Éà2÷¦æ|ã!j7/ ¶³6v‰dbwºcNM¢$JÌF\dãÒ‘KŒÀ?JQ_¦j7;#hâ"UÈmÞ•‡ˆ)AÆ01éJ«| f·\ãZ5+êé#œÆ0™^Ùô¨ˆþ&éý2­a`a¾ÕBàíoáÂ}3Žä{T3įn/^]7§ ö–¬»à€%—ä?Ò*¡¸fviNæmÌIîi%®ËÂC®ê:íûßjRË<Ÿ|³?Ø –8¬}EyN[bitG&®Îd ¼‘íYÏó‘YÛ["ŽrÀ}h©]“bnÒ¸ìß4ëM²Ô5ŵ¶ŽYfoøh ŸÇéDzk@¾×ïÒËN€ÌìpÌ; ÷?*èoú&æ¬ÁTß8ÿx¸>þÃ=¿ 곊w¨:.÷¥,¬§½¸WšäeãUâ3ŽÙ Ö‹$«ç–8=”ÕÓã¶þœ·˜såÜ “éU.„{Q_‚E¶0+ [ËÚÃÙ¬³àÁÇ¥j$"MÒ.xãüWUyî…­óHÑ™±€˜8ÁÉ­e¾i–GÁ,G¯ø¦wÓ*J ‚§#b›Msu<»^Fw]üã=éÜÚÆñ²©¯•“V¼‚þú1EMKOT!¿ö‰Ž~¼Q‡OÔínîìòÎ×qmœ(aÆ}Î*¼·¼{Ëtà\ZIºŽ1ê(ùÕ/§µ´dË"mF7­&Ý6‹ zŸY»êf÷X½ºžO2åŒq;e#œ`víO|6Ó4ë­GP°Ö."ŽÎæÔ¦ÿ4.ÓèsQ«vòìldƒ.*{;%»*»|N}hILénˆé^”éû·ºÑ®L“LžS;ܬ™\ç¶jÇѬÃ38F>¸“\*/.ÆÕIp¨Qþ(¶Ÿ­ëvîÛR¼€ýœî¹ü3C$ßYÞ’ÖÑ®®¥±D¥ÚYÎNx®Cñ¯®æëލ_³³G¤Ù3%”.ü2çˆõf#?J·|é-oVéù5~¯¾½¾²¿R¶ö33£F8,ÃëÚ¬ ü"ðöåËËÓ6È[ùNéÈÇl7 U0j2ùš@ÏÙgI³Ð¼(¶ÔŽ ^³ÜÌév#%Tp2Àj7ÖÝL—>/Y˜z_W~œ2ùwó5œÙ¹g]­ ~¿,ñš“kZÏQxsÓ«¥ôÇM¸¢p¶ ‰]ʺ“¹ˆ9Ç=±L[Çî¨Oòæè¨Ú醘˜nÙÚG÷«b·r‚Ivƒ´ÍÖš<»m&56²Ko ? ]ª$\ ‘À® tcŽAR9ôÅv~¡ûãÆN‹IÔ,äЦy·R˜ÎÂÈßEùãš­îÿfMIP}—©¬Û ÇŽÔ*IvCipPPÛ&ü‰D›ÝS+¢e.Š3\^umø8‡ø$§v#âqïŽÕÕ|ê}Â}BëUÑÅ­´~lïºD(ƒ×”ïVÿExáfÓ:v‘g®­¬6ð…Q-¼‰¹ÞnWÔ×Nv©ÚೊF6á{(ïÿß?`€A•³ñ¡/èz³Iú4ûOê(…¿SôÍÁÛoÔ\ŒxP·‘ò÷ªÉvE:ùKZInæ²—VÎ@ŠêÞLåúNR)HɈùQI…|u‹Ë]/O¹½œü6ë’ ÆO ük™zËXÖµýl_jDdeb„sÆ*øñ«OÕïºT[éQotºG™…Ü›N犢5mNkz•¬6÷ñòÐÊ<·Aï“Ü•U,s}é2c…îì&™d`ÿcü¨©ij$S:,ðz}©ëZzÇçKwb>ìy'éšj²µõä·B±žg;E[§Ó´÷H-N¥> -ªjz¹g‡î†çÿJio©ßÀÙ†êå1þ™Hþ˜¤D6ÿ– mÅ'&ävT<ŠqÆ/Á˜ÜןûaÔÖϘµÝN?`.¤ÇåºhK¯k7I«©ÝÝ@¹*%rØ8¨DêÎ~> J:Ýîõû[O9Tl’F#·Ã7öªòAmt‹ðÏl”‰Lú|rN’Á–ìÀ4rÀ|½?:S¥ôÍ>MpXk¬ä¸òä ç±ùR÷¢f‘v* À*rp*Elnäf%ð7åIà­fÆm;f¼ñÜK”xÐÓ&VÊê<Œ.å€Ç¾æšKû>ôs¶å–þ3é‰sάÏç}K£´›ÉkTÜÞäpjA匀ÂÞþÌ¥G>_~ÎZÈZ-Zü7¦UHÅCú·ÃkN€¸ƒTÓõ ›ûë2³˜¸‰¼ÌwqÏç]GÔÚŽ™ ij𤯓…d8áTz·Ê¹gÄŽ©Ôzµ^ÝOîû ìï Ë“1ÎAsÜã°®ÞËqa”ùC~›ñW¨-%¹sgdÐM1}„°dŸ„cëDµ5ÀÙtëA¸`—,øù€}*½D«,ì¹bÝÔºì7 Oxö«=ü‹‚èéñµÊ$5ÖÎúÝî·Õ7SšˆéD\磰©–ŸâD•Mt > ©Jd&K1d#‡¦=ª&ÌU¾‡’85d$ä¬ ‘Œ#ª-º×¢&%S©í#ùÁÚ±¤õ?O[uušC­Ù^Zê15¬‹™ÃŽ2G¦[á®W,IÉ$ýI£ÞèÓõWiÚ=¬‰ ÜÍ´98#9ϽR²™µµÙØÑÉ&s”]ÐîÚØwëïN.'µ@%Š`ÂNF"™hVw?`û,²¹¸¶ÄA‹gz€OΔ}6]Ç~ÞxcŒ=¾U£Å¥qãü3jýZÈ6³,„{z\Ï-³ÅÝN}«µ®ôØ74sGð2r‡â¨ÄÝ=¥4–Vò8lb_ñKjTÐæžNIÄä²™eÏÿŠøUª}‡Wû“ùv— 7¢¸ìßÚ¯¸º;@qüM"Õ³ÿñN-ü>é©%tkŽFå#ð4«šEÕ/eÓæàI‘é´ö÷¤¤Ón8cújâ§Pu¯Du!·µÔã{¥ó-|ËhÛjŽë¹¨ÊxÃÕ£á’K#¾ëaB­òƒ²É“I¸-’䟒M&Óv]HaÛŠƒµ³ÄöZtŸHJÿCJÇâÄÀ†—Bµ÷ûì*S‘ÄžãMníaôªã¯zií êÑ2ÄÜJ»{z•mB ý>¡úfíùÒ:‡‰z]ý«Á>Œì².ñ¦åôAR“Î }ýë5;Ñ:ú–ÆMKE»¶ò÷°1JHhϱÅ+'„ÝH«•–É·šÅM E^þþnjk/†]OƒüÒQŠj½Ô0³nÓ¼Ö<|+­ˆö—$¶Ó¬ñ¶ óǨ«#D¼]V×Í€n‘GƫޢŸìP[¶Ùô›¿.¡¢Z-Pi7>t71•ço—Ãj‡%G'd²9¦ø¼³ŸZÛìˆ[n0~}¨ÆŸwi=´rÊÕÛ‚’¶ÆÏÈô­ÇÙ\Äÿ Ã?Ö‡{:Wà›"¬|½¼÷æ±ö}¼1õ¢òÁ 9#ò8þô‹[®ãµ6®rl­|Y êmIþómó?œÅFç³’%ˆÌù‹¹A>™Çö«:kr½þ¦H úΉöÔ  ÀGƒd&ˆl.1N–"¬ËíKù[K²X„gåy$ôÙTIL ”aì} …<×tÜGÃß½+ojŸº#`Hf™ãsþ¬rËÚ‹ÜXC*Ø‹i V(êÛû,Òj/nÖsÉmåÄ2ÒF>/¡¯ið£³; ³‘“ôµÁòì§™~ô‡iúP˳€ò²­Š,$ìÍÉùÐ-EO”ðw5¨(óz(À ÷($HÔ’>#ڄ὚wóÏlø áÔ½iÔBæê7]"̇¸oý£zF>¾µ^h¶{èm¼Ò¾lŠ›¶çŽ3øf»» ô ?¥:rÛEÒâ †w?zY Îß: Ž¢Ct³¶H-Ö(ÕR4*(Àvî0yÅ'JCëK]²¤f[t™q"«®1†šO-»ì‘ƒò¢)÷iÈ¢M“Ø>;U"áGaŽÕ“Æ3ÇzzÎSµ5¼Ÿd3JɻʉäÀ8ݵsƒPbs¿ígÖ+m¦ÃÑv²#I1¤wTqæVÊ–Ve99ÁÇ&ë­bë_êÛíNøîšîgf?é ÀåŠJQ¾´Ö,n1KìéJ†_ml`!aîrk&é¶äŒjQ¢\ž)/%w~5nÊ!dǨ8UòätÀôb)Ì=[¯Ù€¶º¾ ƒwd¹p?,ИàF ½yà]BŒ÷¨ö“#ÜvM,@` _"Qá¾ÊÂçÀϧS·E¸ˆÿÉpøþ††MûÇÜ%f`¡‚ìúÕq †Þ &ÈÊpVû0í¢ïÔäQ«;cÃ.¥èí¢ôÍ.ã¬tV¹†2}¬asõÇõ©„]OÓ ÅÔZT«êÉt‡@ ®´F(€È{Ñ.XáR³±ÐQí~Eœ¢ü‡Š_¨u_SÍ=¼çì–ÎÐÚ&>¾®õ>ýê~¤W |ÚÑ5‹¡½NÓ‚TqÚ–¸¼™ðäÌv“PðÉÃ4TFn®…K0§»}áL.µ&2°_…q÷ÈÎk |ð÷Gê;4ê-ešëÉ–EKfQ°€@ø½ûÕ½?‡},n²ô¶’ØlöqÚ£t!ßeÎå×G Ï}’cYÞj"6âBøWz^øIáÜŠ»º^ÉwäÜþ†…]øáÌ ŸÜÍÿÓÇ÷£÷ U¹œBé‰ ±2ëŠ!¡ê¤kÚ…™&x:ãWZÜøÐ¤¤ñÓr¸¡·ÿ³ÏF¥»M榇i8óþÕ>ìHÝanƒêÍ?]ÓaÕ`“ÆhóŽ9#š’}®¦1Å"gÊæ-nÉúWYž×J½¹ˆF?â+çØÛô¦ã®º²Ä©‹[¹o3¾ð§·áM-LR¢·¥mÚeÿÖ:ÑÒíÂYyW:­Áòí`-÷¿ÔÍÿ*÷?ZÓLŽU¶A4«4¡™ ìížâ«õ+[]ÔïuY%½¹x‘RI%ycÕÅkb£ ¼íÿHÏùªsdÝÉv8(*C«Hª°áïOÂÀ¬CŠU‰Ýî)t+æà¢Ÿ­(Ý–Oz@õ7HÜ-º)¾³>t}ìŒ~"¹&H6þ"a‰9ùsŒWyL¦%lF9{×(øã¡Yè½uqoh1ª&Æ1‚Ü‘Wáåí+Ýŕ؉ LÞjFW’äý)]Ž2p}è8•aí!mç·jc`.C ÍðÆ7zœq[)ã 2çœK¤+æ/Öœdf$Ô(“¼нEwӚȚ2Ëo/Ã8'#ù€÷ë¡ô[Á©Ø­Ìr†WPW’>•Í yŠ¿¸Çã]×w‰ö°°º{“þï90£~<Ì~µÑ‡vW¿^ëúùô<üS÷¢¼‘ZìªjVª /í¦yFŠU¨M¼ÿ<Ó­ZEÔ.ˆ²ÿ„´¤Q®#)þϾ*}“ÚÊÖÉ%Þ /&•¥½!:fW =±Q¬3O éÆêîÒt…—^óЛ³Ÿ¹»¾ZÕ½?`—]ÎD2/ì¡¥]­’Ú ƒ?öe“Ìó3Î=³SÌö.–gSû#hÞt'Gد¿v8ßþ4湸ºs¨{Ë'¶3¢hâXÇÛÚÇZzËqc/Û7zŒ·m7ÌCö:Û“õü¯¿ä^·Ï8¼V¹ð˜}žO³(y^Vî3SZ˜Ööèikf×fe:Ébøg;çP§†Ý´¡{yp’Å+¶¼e÷7ÜÍ[X罸X„·šrÙN‡í£ÿ‰ËúçÒ²}¯Ãôù†…dXÑv³ˆOÏóùžfïOLÕÙ¶›VÔ…§Ú„Íý’ªÏ†xÝQ¥ÕÃÛ.¦m.Ó÷%?°÷G“óýüU¥ÚOåoº¿“7ïr‡û?+ÓÛ>¿×õß®Áý_©FQv^´ÿ„ ÁÚ—Ø#ÏjEF;ųÇH/7ö¡;ËÇ;Ï5 ‚âHOûUÔOHçYÊþóæû¹©Œó\J×+ÕªÚ4‹ö?}· ÁÇzŸ&ÿ¯ëî ÿ_×áØªãO6–¢ð[ 4O*_y~Ù§\o7‘¼ëf7ãúÔÿ[ÿ_ð¿¯ëò-HmÄö£S6¡EÀþÉ[-òq»üi¬Ò}§x[3â±m™,G»¿øTždöW*]nïôã òìü§§lzS<™¾Î4ϵ]‰VßößÉÏÍ÷wzö¡wÿ/ëüÅý^]ÆFmÖ[³¦‹VFœÿk—gÊüŸ6ßñªEt±¤,RUð”žT›ßÌ2oà}3Z2M5ôìP^iâÊ™0ƒûC ÓÜJ¦/¤ŸÚÍizðI/öÄ&3¿ïãúÕ%wÿúûú©nw®­¿´E¬w‰3ÿewügߥ6$ûK¼)hÞ)ò#yå¬{ºŠqK‹…ŠI//Þòg)qµØ2¼lg¥*Gs/üKâîâ†7:ÎÔÄ£w+ŸZK×úþºu'K_Õ‚Ûìj.—O6Ϧ<²ÿiHÒ¾äls¶™'Ø Œ1\¼ áà!û$âfÞ㹖ðËt°ÝÙCk$©-™‰¼ãïÞœÓ5¼I}%½Õżâ%M¦mÏ÷±Miÿý}àÿ¯ë¹ðíÖú…ÏŠt1©AmÐûJF–ò³f˵ˆ= æ¾}ÐÜÛ]Ú¡?(‘sìs_C~ÞV—Zgˆn´’ªî~ˆþÁwI?Á}Ol{ ø‚ô19NOé_Bë³éW±·Ýh]OýòkæŸø'ÅÇŸðOV'’oñ?€Æ™¢éZµ–fY¡u=Lqø‘õ¨tk ­ {ˆå…ÂÚ:‰€ ùc=¯^¾õÚx3XÒµ‹§5•üSêM¨[ªŽ+¸pã?+0ØSøWˆ§%6š¿õý}çë¸\Ƥ¨Nmy[[n›\¿ªûCÒ.æŽÁnÙâB3÷”èk{ÁÝx\’-»d^1Á&¹ïëú&›¡ [½^ÃÊ…ZÙL“(2&âU¾„T_µKk¯xš 9â¹¶·r©,-¹nàƒß®8®œ)S•量íWùŸŠå¯¥¹vìÕÏ`@Î9¯ÿnu¦¶†ÄÆWìú¢Iá³kœþ¤WØŒÀc¯ˆ?n-c횣Ù„Ûj19 `á­GS_aƒJSië§ê‹¨Úq’[?ÑŸ,Ë(h™³Ðþú‹áiå¼ðî†÷Éö'ŠÞ³*]cíÉðæ¿*ÌÛVMÙÚ ’zWêOƒüÛ xu59úyí¡6r%¯þåqœ:Ã6VŒèáåÍ‘´g›&ðC_È ÚgÚ¾P›¾ö?®+åÛÜÛÛx_@ò¯^yeÔf2Fóï¶Áòã¶+ê&†wœÛ¤‘/ˆVߨ5§ÈÉ»•ôϵ|Ÿûx]iÓh>–Í Ë{qç1€Çæ6ÕÉê yxQßåAšüÿÔ pppéŒWè7ìà*19ߪ]6qÇðŠúÜѳ´|¶·ZçÒFB¬¸'p玕ñEçîü7oãÈÐK§j3M ɰæBYˆeaÑ€'ކ¾Ï•·!Æ2"¾;ÐÜ…í_m%ÍVê-®ïGú~gd%/`á:ªúi¾w¿å±åúŸíGák_Zh^›Z½pWžÎˆ™¿wŽ›2sœu>ÕìÞñGÄx^Öòo Gá_ùe¼íJrÌTc"â¼Nóö™øuáŸ]Aáÿ É©ê-¦”y¬Ð¦@›&-¸gæÝ× ¯iøsãˆ?¼;o¨ÿÂ'…|/µ˜Ë}9,ê:lCåSQ¶žóýd:jÒOÝÿ·´_ûiè‹¡êVwv«¨ê"í2Ûòž:~¸§ø×Jh5{8­nÔÀ–¨«–>­ØTréwö·6‚÷P†â9 9•“æ*r>ïOz—ÆV6ñ^i©i¨H°­°Uòß3gžÞ•æN.¿+_?ëò=y¦½ôý#eù´³^%Ñ–ìÅ&bM¹FoÞ`„9ì3Šéf[¡zц³56¹ûOÙŸÊïééœvÍrú$³Ã¬h>Ñp|°˜’E^70-î@çðÒIl£L:h¾¸:9¼AöÕÜæ«-éø×niý_.§›‹ÒKÓõ^û`ÒÖÖ->9äâÉnù‘¶rS×õÍ@gÓH‚[¤·ob°@¶®eY7u#¯_n*äÍ5íÜ\}£O{)Ým [µS2:ÓæîmM-g¸Õ'Š$“@ûZ·\ýð?Îk{-ý?¯ø=699˜j˨}ŠO0Ÿû*XíßËHûü?:}®æÔ®WMI¯î„êòÉìtÇ;OB• †[T{(..omnÞssª}±wXd¨=±úP"{ÅK)nnl,m ¨.Ó7çtžù¬šþ´ü¿O™W!†M èwk°ðpI¾×‘'šÒnç®3íW'–Î?°¶ª¶¯§´ñÿbˆâ“r¼oôíéMóî¦Î©-­ÅµôQÌ‘h_kM· ¿ŽÿZ´’\XÜ´ðÇq¨M}4b{F¹B4ì§P;cÒ§úÝ~¯ÈwÔn'[в}‰¼eöcµÄOåy[ÿ.³V-ͧ›x4Ñh°ùÍý²“³æÛëßš¬–ïŸöZÞ]IfгíI¹ÿ¹»ôý)÷š‡–²^^Í>m¦ÈîK¨Ñ/US%˜ž1žk¿­?¯—MÂý¿¯ë¡M¤aFóøDDqù8Wó<ÍüqéøqF§«ÚÙÝÃ&©%œz2)„rTÛüd~ZøïâÏü;KÓ®¥Àð©ŒL’êX6P?z(ÇúÓÇÞ8ZùgZý©©öS¤4ðbI¸6ß—¥ -ȼQ3X}•Ì8ü¯+wóÇl×åO…hOøVu}?Äú…¦Âd®X{­‘ëÚ½ÿÀ¶/‰ï4™ì5)¤Ì›~ÖŠåA9!e\ã8þ%Ǹ¡bé'ï]_Õû“ý‡^Á’—áÿñ>ßÓî`’æïû$Ú ÏüO Šüœì?Ÿ<Õ´io Ž-‚<ŒÛ'›æoôëŒöÅqÿþ.h¿ …ôëÛÍ&óOKØO4k=ëytãéÚ»¨Üc«‹Ã!¶ ÿá’>üoÇõ®Å+5¶¿?Éýž«N¥ºuR]ÿ×bÅäÑ­ÝŸö¿ØÄßh?Øa7üÇg˸þ\Ô <¿n‘¡[ñ·Ù“íKˆ„[¿.³R…¸±¸e{©û†Ì›ã'L%;zc==¿:­mq%¯ö7Úï X­ãaâ/53/Ï÷7~•ªŠþ­ù~w1½‹×6 öÁ¤›6ÓÍÄ¿ÛLï&ä;yÛùˆÍ¥ ¸6‹àãFÒewó]ÝãS$·7Ó´â Ý,XM ûòÇö–®;çúÓ#¹žÞÜjÆÒúå'Š(×A_,ý›æûøíõïK“Mûu_ŸëÓ`L»=É7ði õÀÒÿdÆŽû]qÆï~ŸZžÞg’=ªÙ¿ˆÙ!ñb&{Tb;› ‘žòþK·™“S"2,F8_lSã†êèýno-dµòZMTªbóý{Ö;Yÿ_×uó‡Ã?·4Zb_ø}ôY ›Nk›¦’Hæga>Wzzõ¯štù\\Dr,;g½}=ûwÝ›ù<7z-n´È…ÅÔ?c¹W, æQŽ»ºWË:HýòüDcæÆM}þ ~â?ðçÉâÝ«³ô/þ ß o‚ZÀ î_]g< uôüÈ%…Ó$nR¹ôÈÅ|¹ÿò‘Ûàæº²àí×îúl޾¤201ë_޼q3™ô4_¸™áþø3¯øwSh¯àÑõÝ% žY’FŠc“òùOOL÷®ÂÛÀÙ“á}<ŽOÚ úýÏóšïÈzŠ‘_®iV•YsNLö*f5æîßæ¿SÏî¾\Oeq¿‡ôi^6D›Ìså±7 ؜Յ u_ê:†£«ê¶÷×q$+8ŠF –9ç&»´$œçÖ¬ÅÐŽ:f½ ;j.*NÏô9*c«J›z?ŸçrmáàŸÂ¾ý·Ybø¨mr­+Z¹EÉénFkï·BŽ;šüñýµ¤'âÆ²8ÝiŒž¿èõïåîõÜ_gù£Ã¯ð\ùæYr­ŽÃ­~¢|;û5¯ƒ´UÓ':…œö±«¦¼ÝöoÜŒàÿNÕù]:2+ý:s_©Ÿ fŠóÀšÆŸlöYF.íe³Ú×É\à}k<éZ0~gf\ÊFóÁlÚjÙ¼æ#ŒÇ¨ý³æ‘‹p¹ôükåOÛúòò}Âéwf-Ü܈Ǜ¼È ( ÇC_V<‘CeÍÄ2M¢È"K}=lòñ¶zšù7öý†ö O G{t—LÒܼ{"òö®Wjç½xÙ}ž*¯òþ½Nºï÷Rô×ùþÄ—K•`@¥~Šþ«ìýdØ?>£tß{ý¡þùãv€DäãæãŠý!ý…àÛû;hÍÙ®îÎ?í¡ÿ úœÚ\¸kù£æ°‘½SÛÚXÎÀž™¯™Ïìïâ«_Ü4öZ~¹á¹.¤™áŸg’Ec‘Û‚ ûWÕ>^Xÿ/Z†x‡'$ú×Â:¶wG×àqÕðꃷ2³ÿÙùž ü.¿ðÓO£xB==¤B²ˆ5»ý íéYz¯À¹µ‹äÔ.¼k,åeÜ$Õr¯#ô|ã ƒÏWÑe6ñŒ{Ò…* ©ãß„ê]«1ÇÕççëß[þgÇ¿ðÍÿ?çÇHÿÀ¿þµö”º*(öïúg¿þ´f_̾ãâ‹mWâ?‡ü £iž>ø©£éWí ë«y³#ùîdo+Ë+´ü±¤cø{ÖG¼à+ [ZÔgñ^­âYäÒ)­b€ù-›¼g9Œô&½v‡> °¶µ’? ÛM‘¤Y\I5Ì$lÇ’9ë€y­ù§;«;z¿Õ¿ÈÎt•+I$µÞ[~Ÿ™ÙϤj–SÚÉw¨Ú‹wÛ!"0d*NËÐÏ «~.²°š]1mek›slÊ…jœ;ÐsÏ›u¢j¶æÕîµ[[x™VVX" 3{ö«OÄØÍ“öK™¦¶È¡¶rH“Éé\µ)rKà·ÏóœÒ‹ö—ßhÙlü‹Z³Eªør;w…eP”2mØ·é‘]§I£Os°_G‚]4Ø‘+Í¿–ëÛÌi[Ç{ ¯Ÿ*C¿ævœ.?yžÝÉÀúWaq=×ÚÍü¶ëˆR RßF¸Žh÷ýücúWvöþ¿¯òÜó1ß_×VGr"ŠòÀêQÇu$÷ûÇfØ´Ýþƒ§Zl0ܶ£%¬/nž1[hÍ΢ÖgÉx÷t¡8üªh¤{k©þÛÙ.î3ªÿ ãåó·=1øUEŠØèë§5ëÇá˜áF]‡Ï+ïû…ºã>õ»MÿKúù}­Î%±$fÊ[{é,!Ž '½¼–M¾åñÕí6IlE¥Æ¡SxnV·]¢Ø·™ú·§¿¥Xši®/b¹¼Ce}i,˧X­øQ~6ýæÉãÖˆnn­îä¼µ„ÝëW+Ýé-~ Ù§÷”vÇÐTÛúÓóýzlUÿ«„«qü0^½¤Þ,’9ÚÙ?•yàœgõ5®é/ncÓÚßVŠXޱ<–ŒuÛó=ÿ ÕHÖ(,®,mïe»Ñf[‡ºÖ[Qí[9*PÖ¤­À‚Þêâ[ Y`67É|Ôožùôç­.Wý/Óôù…ô³iM¡K4qEƒMhmJeß÷€ôϵ~j~ݵÝÇÄÝrçÀÞ½ƒþ *rúÕ 5ãÀzùkÏûÇ“Æ+èßÛ«öŠ†Þ %¥ÍÆãMzÖKf²Šã|vV,Ä4Ä7¿*½ñ¸öùcrÑmÂf(˜rÍ×h䟩ª„9¥ªþ¿_^¿!¹û4Ÿ_ëQ<Ź}­;ë#“Àžæ£·»š+Ñd·D*8Ö³]Ü«j±Â§§×Þ»x>ãSÕa‰CÇlnaØu8®¹ÁAk× ¨Öœ¦’z—tØnõ•„[™¥a»”ÜzwÝé>ÕSîéÏ!n62mëß5ëÞø_™£K FKÙd«¼ªÇ¿Nqô®™™Å±„܈¤Qò£Âß8#û®Gá^l°¼ÿ‡ÝaéÉEJ[Ÿ9Üé”R;ýžH¢;¤Û…÷?Jè|);Ç{ù ‹*å žØ`:óô®ãÄ1Ýxªq§%°½–È„([hfm½OÔóU4oƒš•åÜÒ.©ˆ¢¤™‰Xš@3å¢N2OL×5Á[å¤5=*%Niž™«Þh×vz¬ÑÃs5¦^D0èO÷Àïž„~õÁŸÚ/Jñ”Kg=ÔøõÚEª_&a¹pÚŒbLddðqž¦¼wáOÃñ®›w¤ÞyÐêÂÎ’+GÚ:=½ûg5âž$Ñõ_ƒþ+¶v·‘´Éæ(’•åHê=²=zפðõ}œ—SÕÍp´37JóµëåêÔ ´˜Þ6¶«hnë¾lN Ÿ6Ï^ý*¬£G:_jŽÛþseŒC'œ%ßÜõ¸®àïŽWÆZ,71‹#˜íÖp$¾ù:0?xñ‚+ÒÅÅÌ`jÂÊîâîXbGÐá À7¬Å}$f¤“_×õÑôØüš½ áê:sÝ ™Ô­µÖɵ:_ìVŠ7Ú«·ÿ¥:ÐÌ5 ¾Çöñ˜Š·³$‚//<í÷Æ;ñSšÆV´K›­J+Éf2êá ÓŽÞ@=±úSÖY­Æ–nïmmí–^ûBn»ç;7wëøÒoúÿúuÜæÒÃ`m0Ø]4ZÂ6^íVq pØço·ó§Mý™öD¿û*øl5¹Ò™Lža“¶ãØ*Ý]]¿ö„–÷¶RÛ Õtq,x¾Çñc½H%¹³e¼û5åó^4t­ñ‘a‘÷±íúÔ%oø×õùúŸ~Þ$—žmXZ®ºqåÚ;-²6ç>õò½ƒˆd‚¤ ú³öñŠk¼/e%ÅΪEÅÄ£T™‘”ç$ýÜgñ¯’£l8åãŒwëï°ZЉñx×lC>Äý¿iü(ø}¯hÞ,Ö$Óu5‰.R%´–PÈQ ¨=Áâ¾€ÿ†Ûø7À_ÎùÎ6éÓÿñ5ùmy$[ÜJÀ¾•`kRªÌÜ qþy¯2¶MFµGRMÝ´ó¥cô¡ÿmÏ„›‡ˆo$^˜]6bôOøn„€®¦Ùùt™¸ý+ó]µ‰†@ž@A°EK¿qæ…’ix<çÍgý‰†]Y²Ç·º?JöÛøPP²êZ³3¤MŸåV¡ý¶~²î[ýcè4‰²xúWæ°Ö/ )[©—ßÍ9­u{µmÍÁã“æ·?­o ¦„6¸¥‹o¡ú8¿¶ÏÃIš4üAór Ñ¥æ¾Bý¦üqcñâ>«¬i©x4ëƒÂn 0ÈÅbÚß)ç¯$“Z» 3wpTp ™¸ýj A® ¥‘òr7±<ýk¾Ž–|ñ»vþ¿# Öu¶+Ýñçqàq“Œvõ¯Ô¯‡sÜ]ø/—œQZkéÉö+8®ÎÙÇ’¼‘ë­~TÍ8’G,Ä|¤cÔWê·Ã¸.­ü ákK«‰oõôÈÞßRû2•·SàÛágO܇«ü[.ÕHè#’X¶Ž9õ‰»±7gd ÜOjùöóK { Gexn”Éw#Hó™B’Ë•ëǦ+ìŠ{‰žÚÞg¶Ô òÍóZ ·* øËþ yo(ðsZÚÉe[¬Æðùmã-ïšñ2çþÕWù?ëÈô1 ÷3ôþ¿à^º„~Ü8ç8õ¯´ÿeïÚ«áïÂÚ/‡õû½BÛU·’v–8´ù%\<…”†ƒ_I"¹fÈÎzg4=û…eeøwûlFº~ʦÇÉÓ­ìgÌ‘úS7ííðŽ&?éºÌŒ;®•&*‹þß¿ $ßêãœ é’ ×æÛÞɇýãHcÍB÷ŽP >¼×‘ýƒG£:¿´í¯/ãÿý#—öüøJ Ÿ·j‡'þÍpiçöþøDŠâe©çÐé¯_šMtÇnXàtô¨¤¸1,@ëžÕœ²?Íý}å¬×ûŸ‰úWÿøIÿ?š¯þ 墿1ÿµ¡ÿŸý ŠÏý_Ãÿ7õ÷ûR_óíÿ_#ô£OЮ|C¢Czð}“Ri%Y-5y¥*àeTpÇ“œjΑáë› oæ×5û+-:+6 uQ6rÌÜ‘·¯NÕÃøßâÄ?¥ö³t,d–úâ)`½&ÙͲòÚ(c\’Nñ“ǵá/„ºÅž½¬êzö§ek¦ßZ],ö®§"3Œîc€A=kÂöt£&ç$´íÏü¼©ˆ«*O‘õÛoëÈÔÐþ*øCµº>¼¶ÔïØÍoû‰2£…y;sÔ _øïÅ>9ðî³u¤øJ};KÒf14w²¼‚AÔ‘÷W=ûÖ‚çøGðèÞMá³aª7ÉjŸi—$c™>UÏû"´ü'ñcÄ~=Òµ§ðß„.ãÓ4["s;n2Jªá:à“NqNM(Iú»_òüŽjwQæ|©Ýjÿ_øs¨¹ÒüHÿgšóY³°¶–5—ìÚ|aî#!AŽxÈ­ǦÍa¤4hx̹¸—ÊÉÜ3œòz×-&“â‹ñm6¡®Ack$B_ìý" f_÷Ü1Î9ïÖº/ÚÙË¥è“ÇÅ 4êZøæL‚„Ö¹jRPir¥èï÷ÔfÜ¢ùÛÕ쬶{´±ûN‰4Q$ð,å|»xL…†ñëîkº¼‚î ç½ÃÏâ ¢•­õ¯±©KtÝÂg×Ú¸=Uè¯g$fçíD"ÊþZçrñ×Ú»ˆôÏìË»{i o 8µ ÃrþdRîUöö®Œ:ÑÝiéý|»ìy˜ï|ÿ2ÌQKqw2°Ñî†áp’ u•K,7 pp0ræ¾î°{‰îe‚ÕíÇŒ’ÅåóÚ°ŽHÃréž+óÀvRøoö©½Ñ­]­ã7ïq £lÇ*oÎ{`1ü«ôòÖ8®´k}:KÙm´(¡á×Vô¸}ÙÚO¦sÆk¯ I]þ{í×ä|zÓÄ_®ÏäÉmšÂho[JŽÞ9fþØŠKW 3c£ùzÓd:XÒí¥¾Žð›ˆ?³­ÖÕüÄ—<™ö«³µÅÝÜWWQI§ßÚI8³ÓRô~ýæûzÓbžîÖG¿ŽÞ{½Fá`[Ý©[5ÏÞ·¯jêZïÏõé±ón«n—æÊ_•›û2UÄI`Çÿ¯Í:Ùµ±¦›%×ѡĒBá1ÎÃëNXEµ¼¶\Ü^i·á§ÖÚõI´=ÔߥL°5Ñ‚Òi®l­lä€ÛjkPÚ ÂŸ\úVmÿZwíú|ÊZŸ)~Ôÿ Gt>ãÃzv›á2i®&k”•dóÙ¶°Æ =°¯¸ý–üG§8Ýkš%¼Z‹ªYÈd”‰Iô òúsÞ¿Fnô8µYƱw§\ B;i"7IåÈ¥þù^‡=sŠÀšu¥Ü’¥•Ö¥%ôêe‰îQ†™òc*Lgµ{ô³hR‚„“ºó_Ÿë·Ců—º³sºüOÎÇý–üR5vÒŽ«¤6²°}§ì>t™Ùœ ¶Ý¾øÏJe¿ìËâß·µ¦¿¡ËŸ#E{ ’P°RK§Ì8Çúÿ ×H}ÿ†fÕíì“Q¹ñV…ƒ8O³êçm˜à M¹!³žj¾§û0x‹J™,ï5ý bs'ØìCÈZéSÁ±žÙ¯¿ÿá°·S}%µåݜɦ†ËKBb?ZźøQlÓ=¤·Ú…åÍÇŸ$ÈÉÓóü ÇÒªYÆý¯ëçÓRc—Ö{µøŸAû3ë÷÷a´×ô‹­Z#ÛlP¾ëUoâ'8ÈÎ+ôÁZNáÏéšM…Ô7ž·´0Þ_›†ÜTG±Åd[ü'·ûDp[__XßYKnójÆ8ó¨>é8äzú×gö_¶EmumeJ¯¤ù)™Î~þ+ÃÌq”ñJ*›Ñ_×n§±ƒ¡*)©[_ëþñAlð[ÃzðÁ¥£ÃýŸ2ܰy›úb¾eý³>ë?æðâ[Ýi¶zí´¸Òžfg7Œ2`Pz×Óîdµ–9¦K‹Øn¥`µ©ûËÔý+_ð‚ëêšeÍÅËjâ’-y-Ó÷*[îÓÚ¼ü%XЭ’éþ_ׯ©ÓZÒ›‚ëëýzùì~rÃ/øŽêsž¹¡ÞM‚;äIX}‡#$¾GAÏ" oÙƒY)öÁâmûG¼êþkù çnÞ™Îkô5>é—25”wZkÛN û Tÿ‰žŸ¨?Ö¨¿Ãmt· ÃáÖ€ ðè´B|Âÿë1×9ç>õõqÎ0îÖ¿Nß×§â|óËj÷_‰ð ý‘üP²˜.uÝÊYœÇb’Ü6oˆN:G'ÖªÉû&ø¬Db†úÒ ™´q; „BØÉãøô¯Ð›Ÿ†:}½ü1Þ­BâæWm6e³BºhÙ€8ôãƒéU—áJI+ØC{qŠÚ?;Ä d›eMßt™Ç…iÚ‡Vþïëç×±›Ë*ùŸïû%ø²Imu}ú8ÜÅw,7Gm›“ædqUÏì¡âq+JúÖƒ’È®š«Ýo!'Tã9ÏúÃ-6y.®tÿ?N°·žQªZµ€Î vò@=·­D>hK¥Çssm4¾š8VßDûÏ ›¾ùï×ô4Þm‡Þïúþ´üF²Ê·ÙÃxïþ{i?øŠýÿ…Kmÿ?)ÿ€üh®íŠ^pÿ³çåøŸ/øâw¾&ør}RÇIKÆ£%ŠÛ´(©‘+I'-ýß”u«àÏ„>.¹ñ…æ¡«k .“sÄsApæF(кõ< g9ÏjÖðÏŽêŽyÁëé]Þ§æ ^x,›Å,·HeŽO(EÛ½z8x§ý_ðÛ6;I/˜Ç–kY!º–ÞïPKùâö~Ldéd§ŽØþ•V÷BA¤»Æ¿û)ø—ÊnÝÿs>½©-‘Æ¡v4¿± gÌ„ëÆT!BŸ7—YÐÿbËáò©öeøz"o3‰|ÿ8IØuÆ{Wm»_×NýO:ÿ×õý3X,·2Í,ÞiðØ\8º·kxó«â>£×5¼–-.Nm:òëK¸H ì±—µmØÞ}»ÔwÂ'½Óίö´ ‚|:±™@?»ù|ÏÓ­>+‹‘{"Z¦ž|lÐÂרÆO$E»½³Œqž*”zÿ_ðÝßOB¯ëúò$kKÛYÖÆâæêûS¼7 m¬ hȰáIè1_%ÿÁJüJ4‚6š“/öÞ§¹ÔdQo„Q3uÁe¯ª­£Ò’Êþ=)­[ÃF[ƒ¬É+Ëæ,˜ä/·ó¯Î/ø)gäÖüo£xZÂD>Ñ4¨d²XÉ%üѽ™‰ç8UéGTŸ_+^Ÿ=ÂöMöÿ†ýO‰à¶žú}°FÒ»s…5bÖYÄrïI`¡a_jxoölÒtß èóCn5î%’ÝIyduÞ àv-þí|ÕâÏÍiz÷[$ 쥓ø†âvçÜõ?ZÖ®!Åòµ¡ßW*jmêzßìç§.¡}pì…^›É$ó»¡cþx¯¬|=§K"'ålç<†kÂeÏ=¶•rÓBc•YCåOLqøšú6XZ "¨¥wdqÐ=?Î+$í}^>Ï‘©ê–Ö §ŽÞùžYX(ëÇ'ùW#qñŸÃ6𧨆©½³ƒ(ŒùDôÀ8þ•_ÅúN™5Ú>¡ A$,­…Û“\6£âO†WE´Ëû¨¼{UÕÑ =ˆæ®:ìMzÒ‚÷Z^§½ø_ÆÚ^½(K{¨dœô Ãæô­gLVHØ)$“Œžçç¥|‹ËH¯ã¸ðwˆå•Nùeö¯ <â-jD[ U%¸!éŸ'øx÷úÖÐŒd𵉡Ѝ߼©¯1~öÞ «M5½äJEœa†ÇnkŸ×µ«-)d2LŠÙ ÁŽÝ¹èMrvŸü;k¨½ÔÒ)”ž:ó±”R¦Ýö>› Œ„j%.¤¾ðÍ¿ü6>ŸªOû[}o§ŒÃæy¢0èWorF}×bÖ«áûmBæÚI¼54p‹M(Y~ò'ï0õÏç_&ü=Ò4¯üfÑu»{Øçœé~VŸ”ªÜ\ Y¶;mÆkëËG¸‚àÜÚAÇŠšïM7MåC~ð=+ƒ Í*i¿ëúïÓæ|r¬K¶ïRiๆúÞæK½jg˜é—©cû»UÇ¿úô°Cu=üÖ¶RGˆaX£¨Ie„¸¸^yü=?(¡ŽÎ+k»{ …¹Ñg’vÔ¯žøïµlrÔ¬övÖw—+i¡Â`þÏÔø‡º~ÊǽtµÝ~ úùuÜùt61e&—=Å¥²Åá¨üñ{`ÖGÌšLõQßµY‘-¢[Y/áŽ}2iaMºYÛ6Þ RË5Ä—Ky<)o¯ÃÂ×IŸ$韼GzšÑ¤†öi¬ÇÛ¯®%uf½ùl†Þª?„±—{~_Ÿëò.ÿ×õý1¾MÒÞy/%»øÀÛ9Kÿ±‘ÝÏLãüúÚ¶Xž{³§­¼.“cWgµaçüŸ6Ï^þµMb·Q±[Ù„a,u³}ó‡ß÷7zgÞ¯¶n. 7,öfÚoô·ƒý?1Ÿ\ñëY4ÿ>Ÿ×ÝÓr¿¯ëúУÿÑ¢¬’EøLÆ¢;_³8”I¿®:õö«“D©{h5!k-ñšC¤²@øŒmà7éMK‹• ~¶Í.¬ðÆ¢‹°V5ß÷°<â¤@m^X­¦šöÖæYZêðÝ®lNÞ@ôÇéKé_ç°ïý_Ó#‰&ûS-¹µÿ„¤CÚ&10ŒÇ» ÷éIoö%K£`¶ñèþdßÚaãpìøä¯ëõ§4B[±kÉíìcHZ=cíKºvÏÝÏëR™g¹™.åŠ{+«v˜E§‹…ÅàÅŽõ=ÿà_äþ¿¯Ã±RQ¦®—»X?áaÙc3y=ÿÕì1¼€_‹C­æo°GضïóÍ1&žkÔ‚{»‰Ö—K3¡[Aýì{T°#ÚÄmââòÞo9äÕLèM±ÏÝÏl~•J÷ÿ†þ¿ÌRz_ׯ~€d¶J–ÐëŠ"ÅÕ‚ìïŠÍ_ìÕÓ® ¨¶ÿ„e¼ãzd¿~yǶjüâK¢-ž{‹ xLzœ€Þ}ß|þµ Ü\K¾k[ˆgŽ9ThÞjbq»ï‘ßüþ)»¿ø?×ü£¢þ¿¯NÝH¦B+D¿û0Ò|ÈN•³~æ`¼n¤‘æ7Šó-Ÿü%K ŸfMÏåùyïþêÒ¼ö×aÅÿÚ¥u°t?`ùzûb«fHž.î]^íã"f?›îgðÆjS¿õýÁþ¿¯Ï¸¶ÒF·—O§ý•îZd]\Èï„9ÙúÕ7PÐLeíÇ„"MÁ‘ĆMý=qšÒýõä¤uaöIÇÌ gPÂ~¹ô÷ªæy£µ]I¬îÙOìG•;þþ(¿õuý嘆 —vcPÑÍäé“8ó@N7~•yæéî!K7ñp·EžÕ§)c/Ô¥\ešÒíaf¹Ôêi.¶¡ËÓÛ]aºž6Ó’îêÞââfÖʦ'¾à?¥T[ÓåýÀë¹›ÛúïùÅöhšìéÏm.™4ÓZá®›t/·æÛéU.cÓ[FŠÖîX`ðª¬&ÒùnÜI+îàéšÑ/%ÑkÈí­^o7Mò“7ĽŽù¨&™­!ŽþkKËËŸ%"Ñ–&Г÷ˆíõ­c£Vòëý|ŸA?ëúî´“^[˨Ƕ³ÌtË4¼m· ‚Þ´ûW•ofº´Žº@·ºy¼>]ºxÔ=½Í¬Ëe5ÍÅõåÉàÕŒ ¶ÈvR{b¤‚+««‰--渳¿µ0ý§S{dÅðÆJƒïKNÿŸËË~¡¡gÍÑ¿è*ßøÿ×¢ªÿoØÿз{ÿ€£üh®gä¾óK?êÇŠ¿ÆÏ Ý´ÐøJÚÿÇ71H#'NŒ¥²·ßÉ…`;•­øy~%xŸ^µ’óQÓü+¢–`Ú~•Ÿu"ía†þï8û£µVñ/Ä|4µ¸‚ãSŠêæÐ¬Riº* ‰!f8UmŸ*g ÜGÒ²´¯‰ŸüYâ/ xjÏAðä—1ýªÿTc%ËDHݰt ŒŽ‡žõP…Úp¼åú„¾¥Ë:WÀOx6?í­rSwsòjþ%½3;ßt‡èaÞ~Ñþ·¼»Ó<)iyã BÑ„¶0˜­ãr8Èäcû£ÏIû?ØYÝ>¿ñ+Æ—Þ ¸fó]bïˉ@Î<ãÑGáY¶Ÿ¼¦Þ^h¼5.½}o IfK³Û—#;³ïõ8©Pö]¹þè‹þfw6ÚçÄ̆ibðæ˜èKÚi‘80Òžz`ñŠÚ¾·µ±ð¥³ê“«y¥B£™]Ɉ}æ'’qÖ¸Ë=;Æ41O®ê­mc’Ï£é‹ä@«ž7ÉÔñïÖºëÃacàõ[•…­íobH-´ôÞÛš7À''q8êkW -¦æéYèžëúþ‘CÕ!ŸLw±±’ŠòH^ 'cõ¯L»G‡Ï²†ææêÞíçkWíi»M8@{cô¯-Ó5[CJ•e²M?mÝ·ÙÄ¿¼|’~bq^“!†å/¤³¶èðI0ÕmÄï¼}S×5݇M&ßõý~{ž6b­%§ÐðÁk-ÝÖŸig4 oª ¤S;xR{äçŽõÝ]J?µÊæ+Ä‚H×Ã"âLqoáIé»ÜÖ¿×Ïþày?×õýh]Œ\ÚO"¤—š—ö…Á2»O:Fcè=1ý(K&œš0Ô/-íâŠ)ÄÂxópw«ÏΫ[ƳÝ_.š±Zˆn3®ù¶-þ˜<³Ÿ/×<ôëüë—ÒÃ0ÜÜÛÆÞ1ÇökbþzK¿ï9Æ}©¥ÃþÏ·Nàîj´·7s Ç‚ïLk'SJƧòýâ;çú×åwü"GÔÿik±å=£Í§éåí%*>ϘÚqÇŸÆ¿S.‘áÔíRû<úäÏ1ÑgŽÍö[¡Qç<~=kòGþ úíAâÔeŠKæ¶²’G·Q¿r¼ztæ³Qrœy_?ëÔ¥eß—æ·|#.{u$²Cwr¢ØÃrAãÏéRÓ“ÐΛ÷t9ÿü;Ó5XdûJ}¦áFQ‰Ò¼#ÅŸômVÖå"±’ÊõÓËfµm¢HòÒTŒ€xÁ¯«¿²d¼qÈgãž ëœ× ¯ø~H&l†VfÆ}éû++n\Gh6@8žõô‡„õ¸4û&‚eóK ÆãÈþ•€¾šA›ˆ Î@ßíÅhÜÙEbqgeù›w\Žæ¥ÉÞýI¡§M*knÇŠ|bÖ-´-vH5˜æ¶´”«£Å?˜ìJ¢€ç¯å^7™àÞM4Ú®±fæc ‹°QL«üˆàÿ³Ö¾øÑ¢[x«IÓ¥–(çx¤1²>v·R¹Ç?NÕâpü5PÓŸÃè—ÚÏqç˜`%Ô¿Bç#'õ¬c4ãy­u8qøËËM&´µïêçÓÿ°W‡oôí[Q7÷p’ÛO¿²-£mËHsÓ¨ýkí(-¯'ݦÃs=¾§p¼Úë[¦Û‘žTþ•à²×†¢ðž…ªivÓÚOají±4ÌâFŒD 2c±Sïœ×·1ÒÛIµŽìÀ¾Q°’6“ÎiwöÎ~ŸË’Š÷Kú¿çå³< Ñ¿¬¸¾‰/ÀÕY>Õ·¶ö×6VÏ:Ýij»¯xzÿJ‹8໺µšûL¸h×LKE-hØûÇÛùÔ3™R·mHY§‰Ð\ .(ä“Ëtí»ðüém“Sº—KSøŒV‰æ“Ë1É_CÊ©/ëçß·ŸG¡åt'kK¨ç3\Kq­I­³öEÛ“Âg¦qùf¬A—³Ãh^ÎâÖXÿ´.ÌbùvrëY¦šš4öö²@þ t˜Þ^<ïæ¤¥¹ íœ}Ù »›Ô^m#ž?ìVŽåÁ¸;8ßëž+)+ÿÃ~ü¾eíý_ðóí†Œ×æÒUðï“´èæÈy»÷ýïëW¥F·¼/U®ÞæbtÒ¶CCg½1ÇåùS&ðܬV§Æ"×OûSù^Vÿ½ŠšŠ)nÆœðÏo<îuy퉵;>mž˜çòü²iïý]ŸÈ«ÿ_×ôÇ%½Ô—/eêž#ŽÌÚ£Z’&ïº;gFðΗ3ÙB-´È%˜j6ÒY×'•Ç¥UÛ`txmg¹Hü0« [jBñ¼Édß÷IôÏj·q,’_A5êÇm¬Âg}’^—Kެ;Ѫv·áý|×Aÿ_×õ¡5œZ}¼×Vþg‡ä‹;hwÄùê_óÖy’T¿Š Ɔo:ÌÖ7+j|¸“°cÓÿ×L‚âU»k›X£¹ÖåXóOûYÙnŸÞô¨£ŽÞ+9í-®šãF”N÷:™¼ËÛ¶yP~µþ­ýÁ}ÿ¯ëñ,[‰'¼¸ŽÅ¡‡ZŒÃý£q%± 2ã§Ö’ ,Ž“5Ų,~ 0¹µ6¬Û<:â™1Šá`¶¼¬´è%ƒìWÉ{†¼lp ïš‘§žGK¹âkqÃ0‡I[°UÝ÷ˆÿëR]ýz_ðÿ¯ëú±ÁµHí_QŽ)4™$€i°¥³o‰±ü~”“%ÏÚÖ)^ÕüUäHÖ÷ݼµwB}zþtøå–Úòi¬Óí×—Ä·Öv±y v#𪻠M2K¾‘´'‰ÝµÃz7£—û™ôü{Гoúíýz”¿¯ëôêY¶Ä——GMñ\Ç2]Þ\';?Z¥0èfEŽ!àöˆîƒÈ5¥ßéׯ·j½6ë©àûSË`-n²)xÔ0œg×·­W[«¬ E­µ³„:ºRKýü\R[Ã_ä5ý_Õ¶%¸HÖæÑu!k$Í9:8H_|»ÏåQÄ. ë,&ÏþñnŸh•â(Å» íœT˺ÖiR gÔ-î¦Ý\µÚŸ°|¼ééPDÖ1é­wqk§D´:×Ú×uÁÝ÷wu¦¿­¿/Ó©?×õþ_1c{.ñôõ¶]Í›û_zɽ›o;Z©0Ò—G¶[án<*Þ@Ó«‰<ÌœnŸÒ®Í=ÅÅÂÝÉ ÖWVÍ8‹K[„øcïc¿ô¦›‹›söØíg¿¹¸û:ͤ}¡²ÿkç5¼z|º¯ëçÓb^Œ†ëtš¹ÔÏþdYÿ³ž_—Ûw¾)¶Å¿µ._KoâB`MUdi<°˜ço½?Ë’$°KË››yÖwmu¦BmN~à?†=©é÷l¶=æž–rÄEÿ˜™Ôp½®jõ_ןoÓæMÊq6ºDédöÇÂ,³µüÅßÌÎÞøÍZd´’;Hu#m“AýñÊûä;xÞ{Ñö«‰í†¦lîàò¢•á ïþloÅX_>Îçy[½Mo'LA˜ÈÓ>_ÓÒ¥ÿZù÷ïçòkí>+ÿŸ-?þÿð¢±?á½ÿ¡òoûî:*y£Ûð£åøŸÎ5-5ï—h‡Ê|U4ŽÌéiÖמw…%Žss­=ùó`“)“ÐgêëY^Ê>Éì¶Wðù-q®yq§ûÉŒçô¨Ö¹æG¶ÒÕ%I¼_ýsJ—w‘Lu¶Yhuxº•ô1ºªÙÜyÏä×|.b³ŠÖpžI¨®#Âñ«£3¦NrN1Ï¡ÿ>µ­uñk–Û2©³õ¸ë[¤Ö§"•ÚŠ=ßÅh‰/–¤¨ä»Ÿ\ךëž,Ô|[¬•ƒyŒI1áT{‘Þ¹øšUÕ–Å®0Ÿ0c$ôµI£]]C $£¡þ%•[¯Ò´MËMŽØT=—½Ü×ÛÉ«N³ê‰Dÿ( ä~UÑéz$ú›‘o2OÕšO09ä×$ú,¯h÷WPf sОØ÷®+^ñv££—M"eãÆU‡®;f‰ÓQ÷™ÕcÙoˆì%Õ/ÝNÑn|Ìàë<ý›§[¼ˆˆ“‘µ¤+Œÿ§zò?ø‹Rñ_ˆEÅìñBË¡ã§=«­Ö¯ßGJŒ1ƒŽ‡é^mJÒÔö(┚“ô>ø¢]¥…Ƶ8»ÓÚ+™Ä:pt © AƒŽ§€°¯PŽêâ]Kì·Wop–èt é‹ OßÇùÿ7á.‘{ÿ^‹&©WZ¢«6™t–Ä¥¢”|Â\þ¢»8´íE%2Ú%¼>#)½Ôdµo"áù•yäŠÂšQ¦•úyÿVï×¶‡æ…GWRO»$0MfÄÞ]_}§í ý´?Ð?ÙÏoéOH®o%‹su§›G€ÿkþ&CÛžÿNõzTQÛK •€·ðü†s}c%£yÓ¹?yp{zÒ¾—ˆ#ÔlÒçFI!:e´V¯æ[°™;€;šm}ÿ×Êÿ…¼Î"Hî&šÔ¥Õ¼1Å*ª~øîûøþµi{YÃÉö»ñ{:¡ÙþÍù:ã¶==³UËQi>Ó,VÏâÅ‚E‚ñ`³¢à1éœgŒÔðÛJ“ÌöÐÅ$²ƒ«¼ÑH£g&#ÜuéXµ§õßòüoäUÿ¯ëúb%µÛGý–/®Eø·W>!1¦oû›º{U¨Þ[©æ–(®¬b³•Äöæÿ‰‰ Ôÿýz tË&ÒÉôð<&!R–ë¿iów÷\d®Ik$·±É³ßA$ŸÙ&%".Ï—Í=¿†¯uúZ÷[uE_úþ¿¤DnE½œzŒ–—WlÉ Å¢-ºn·;¾ù‡ãR=­Õ½ÂZÜ\M}}pgkmMmÓm˜Ç žØ¨£µ½Žáîímíá'’8ùäY¾Ìó°ô'ñâ’;+x-nmì Q Lg:“Ín?ÜɘëR×Uý];õ-_×õrÊCwqrÖ–óKm¨ÛùëR’Ùvݯu_éPyÑÍa5ìV—úDbu¸ÒM ßrùûÀœb•졞(-¯¡Q¢@ð6œñ¼žk>?ÓñéN‘/^u»¹··'ŽVÖ$‘ü‚›¸Üzgã½Gõý~½ºõýZ­§‘5äßXÜ˲²[@M™ÛÁ>˜¤tºI“N–w—]{y^]mG—îû¹éœ?z I ½š}>^þâx¿µ’¾ÈÀN|¼ÿ1TþÏm”öH«ÿ›@í%ËK'Ú…úŒãÚ•´þ¿¯óêRþ¿¯Ó©n–îîâ;k+‹ISûFâK1‹Ñ³¾¹þ¾õTÍnš9½6r¯†Ú"­¤}ˆy­!“ïãò« –âÚ-IÞ.û'Êó.0öè9?þ¸w^‰ ÷ÙíÛņØ#Yyïäy^g_LãµR_×õýD×õýi±b`Ö·ðG¨¥És9:aK.,†Î}8üª5‚î[“f“ªø¡-ѤÕMŸîÞ2ü¨=3ŠX„vÓ] 8¥Í­ÍćT–K— nvs³õäUo³Ú*=>wò|0±Dmõºq3É¿îžøÍ´íÓúûºî×õþ_2t’#º¸±‡ìÚlMý§nÖGuÓç`ïQNö‘iöóß[ùÞ›ÈZzÙ$.OV©'–â{Èno!ŽÛY·3ý‚Í.ÛeÊã‚üw÷¦Ãq=½ä×V0Çy¬N`Kû'»>]ªã’¼cŠ#_¯ëÓaký_ˆ—qÜG ½ãC7‰]'}>õlÏ—g€Ç±ÿ&ˆÓ^Üǧ4kp¼#U¹–Ͷ\.ÞBõªKhté졺i<=2ÌnuV¼>d/»î¯|f:G9¶·½’KKYâ:uÌwÇ}ñ Æïþ½tF:Àý?O™“×õý"¸m;ûk˜¡‰<åIö‹3hâg—wP:õÅZm¢’Èj±Ã-Œ“Æth£´|Àvq¿Óu¦›Ã/ö‹ÛøHVÝ‘tA{û¢›þùëŽjÔ=¥ÜÏg¾ý®îö†ëÀFŸòs·“ÄWM$ag‘ VñÆX ꃇ¡;GJÀð—Ã/j7Z¯‰þ)ø²+褷x]ö[ÚFÀd«"Œ £Œõ9­M;âç…ô[èü9à]. Fú!Ë»ÀÑÛlÞ ìæ~8ÉãëZF›¨ù»ì´H윔 Û|¨£âO„>*ñ‹µ½{Ǿ3‘4(/&k[R­âÜŠ01Ðêk#Jø›á=+Äz‡‡¾øaüC¯D©-Ö¥$>]¾ñ³3:³‰ªü.ñßÅo‰ž Öõ}róQðý¥Äò)y¼¨,âó«}ÄLc2~µÙüðž¨ßø¢8¬íôý.(ͬÞ;®æ b„s;€>]ß*ç$q]Vrk™è¯¢Ûï0Ž)B>ê³Ó}^¾E›{Dñ+Y\O®ø‰ç2E2´VÉòíM€aÊĕ㠯Añ/†õ_Ük\Vi.í£ŽÆÀŠÞ5ÞÁ@ÆÕã'ž•j-KMð?…#Œ´z=¡ÊÍ©jŽ{’Ĩ:Œí^~·ˆ¿µü;­>•opd3Û¿Ú/—ç?3©ù;ž3\³šºŒ6]¿Ìï„dß3ï××ð^F“àí_V³žÊö{}+M¸EU´²s»Ôîvᛎ8À潡þøzxY·*ÇÏ“Æ:Ÿš¹Ï…º4¶¶þ)½¿Ÿí,ÖÁb,˜‘072¶{ñ‘^Kñçãˆn —O®‡gqbºŽ—¨!mÅ”$1ßÎ1޾ս u%;^×_שæf‹É¨ëgú#ÛcøEá;Ù¥Xo#™ãmލùØÜp~n¼Ž)¶¿|%y{{„•Uš"ÈN7)ýØà~UóÃþÍþ§â+Íy4Ý©Mu¥»!µ»`<ØåQÁÆÌ©Ö°|'ñ·TðlÚ–™¡jWÞ¬ÊÁ懄Ì͇³w=+Ðö¿'6§‘íæ£Ï­«í¼ ðþòê8!Õ-å¸rã 6ì2ýå?7ÊÃ5²¿<8FVQóv CèYô¯–‡‚/îõ[ÏÁ©¾–÷ïõÔ÷Q³w•‘–éž•¯áíjß_ø×ǺE¡hð™'¿’V•îævGmŽ­€WG ê²Ž¼³ØÛý¢6rM&}{ðÂzn›syyžŸl†Y®g”ÇH¿y™‹às_™ÿ·§Ä†Þ2Öü;kðï]_%˜ŸûBêdXCåBlgûüäqÒ¸¿Úö›Ö~2ßêvvwÚ•¿†.®ÍÃY]H£xùhU8Ú™(†êÖr·Ööš’Û ß2´W ÉÇï# ±ëÉÉ÷Åy7Šmõ=c[Ž9u+ùôã"ºÙMy$ȯ¾7t<ŸÎ¦µàž¦QÃã)Ôçæ½7½Òгüþ‡cðÖÞHuAwHÖÀîÙäç]ΨŸð’ø†ÛKó„1»y“¹ÿ–QËÌî}ªµž©eá? ä^éT"Á ãZò/øö-GG¼µ³[VëS¥Ä¶21ínçø{ä{W%véÖ;ÛÆÜÞˆý5ð‡Àû ?ØÇ¥x£Ë)q(÷o§kþм0ÖƒSñDÚrÎÆ8Z{éP;ȶÿª¾}ýŸ~3Üü=ðV¥еJkhFÓ¯bf¸%^#Ý’yí\¿‹>5j‘>ÖÖsnø‰Ù6à 1åöó’;\˜ºßSVœ¯nǃ–à19­Nhû©ßWýj}_qàí&Ý•‰'±ƒý¡/r9Àùý¿Jø_IJYØI ¾Ôµ zîG ¶žc"ϱÎ;àV–•ñÏD¹É—PeýìxÄJ{3œíü2}ëÅžg:káyõ”xfFÓ¯·‘öµ”^¿¿þηø‹ —½ªkl7û¥¹ýk¨‡áŸ›óEâ=BLq”¿ì9ÿ8¯„õ ør÷Äzeæ¼c´YÓ΋H³æbrAfê=‡RNOJ±£xÛÆß uc¨xwW‘m'˜³h¹ûDÃÑC$ƒÛ²§š¦íQ4V'„ë$Þ­üšýWùtÙŸ_fGØ3¨HAqÕG¡ëÅX_†×`|ž Ô¶œÿËä•ò×ÛõøŽ_é7ðiúä—:kÈb·YSn$„€G®OZï4_ƺç‹ôí>òêícF3HÜ¡ŽÚ5;œºýòÇÇW»J0­OšDûù ‰Ãâðu]:ðiüko‡:êGÐ}µøý)Ëð÷R/ŸøHµ<çŒ]¿øW¥üFµ·ø›;j^4Òí4/³„Óô‰$)uu)¤Ïx;pqÍ^øÑñn×ÀšÎ?´%šñ<€ºdk4ÖÎÈv–\¹çý“B¥UÉEnÎiNPºžŸ#¡Õ•Ž”ãá/‚ü%7œu%¢çÿ¯œüWã|P¸ÑõÍoìõ Öw6³>ÝA µ;3Ôö=ºU÷øŸñ'O‚ÃG.¬ïÝc…Ü d¸•ˆ]ªä…Ïz k›·õýj_µ“\Ê:>¶=ðøWÅ»²¾(¹ëÜEÿÄ}j3áŸÿ#4 8H¿øšæõ?kÐø»Ãšu¾µ¦Úi1€u«ýFî4› äE¶±èJôÏjì|oñMðN…&¹y?—¦À ‘ÄF@3Ѱ>b¿JÊ4祺í NRNÍ~qðßsLjŸaäƒ?üM/ü#~3Ø øˆ§«ÛÀp8öâ¾zøGûHø£]ø¡ŠÚý–¿¢ê3ÜHâ?"K(Ðg9laz»è9«ÿ?k[}#W×ü a§]ß]½°¶]VÆá$ŒÈàpÛ¶äÕè¬wSÙÅ]Úû[t±pårÒÉžû…üpÍm, m¡Ý®)cðÿÈ:Ô|ðÄZÁó}Gùë^û!üS»‹Â+á½uo…ÌW,¦êâbë󪫸ïÆF=º×¿üAø¡¤|7ÓçS2«ß%ºo1ªãïg§ZŒF­œ_¶Kí#Ík|ˆgðÿŒMºÄº¼ ƒ¦Î"¿\zÕVѼi#‡:­»²}Ök8²>‡6ÿ ìø øÑ\ü4vÿ@‹ßü ƒüh©öíùí—‘òO‚5O‰ŽÒh¢Ómð–h"ÂtMŒCol¶V­øNÐ4ˆZ>‹§Bú¾ g‡Ë»ŒoVpÉÿ8íë^ÏðvËSÓ|)ªiZÂ>§§_7˜ºUÂ,pìhÀo´°æ@HÆä’k‘Õ~,x_áï‹¡Ñ|%áÙ{ã]WÂ6zkÙ$>]´q5È|ȃ#hP3Éús]µa9KšÝ‰ éáãìyîÖ÷Õ’xŸÆ>'×´­CÂgL…õ[(~Ì÷‘¶SÊSð8çýkãÚãŒß§Ð¼/§ÈÀÚÛ,NJ\Ü|ÛŒuè=³ë]ÆÏ:¦‹ªkvVº‘:½ÒÉmvm\à(Þ{¶ÜñÛ½|»9À 2q[ÑÃò»Éjxy†>hÆ• º„-ˆÈ$㸧K»w¦ÑÏQQ û»FM–õ8è+Ñ<£2I#œÖ†‡«ÞxwS·Ô,'k{ˆ[r8ëô#¸õE£(C`í=Í.Fïz,нµG×ÿ>+Ãâ½:¸›É¼„,W6äçiìÃÕOc^§mâˆÞ5<å~R[œ_­|áO]ø_WŽöÐëÃFIÄ‹ÝO±ý+ê øª/i_Ù6c”l1¶2‡ø”ú\S¥Ëª>‡ Œu—,Þ§¸Å®¥Å²¶<Õ]݆;~>´ÛÛ÷Õ¢ˆ°Ê‡#Ô{þC¥yF—ãY4{¥†ç"-û’SÑO¡¯HÑüeb°LÊ"Ê£Äc?çò©”ï}^î8K¡ÉßÅw¦ÌìI ç8ëŸÖ¹-jéCý º•æÉàž+ÒuB6Óe”˜ÄŒ8ãõýkçOŠþ5‹CÓ'‚ÙÕ§”â0}O¯°ÆkŽjW²;ñ8šti¹¶s_>'\_Ê4‹K‚%+µÛ Hû£ý¢:žÃ¹-E°‘‡Š ¿Âpw ãäf|æbÒ˳rIõ5Ýx[ÄuØHµY êqÛŽHÿkùæ±ÅBTaÍw×ÔøÌ=uŒ¯ûÉY-[ðÏŠu›Ý$ Í}}2,6ѹ'Ê\}æbxP9çô­ xšÛI¼X–E¾1¿hSò3ç’§ºQ×ËêZ¼ÚdpÙMu,(Jäœ àä¯_jÐѼ7p¶–© m¹¸ã!xsÉׯ>þõâ8IÉNJíw>žž%ëJ”·ÞǪé±[xžcs4¨¯‚°@£G©Ç¯§çÖ¤ºøý‹—0ïi\eä‘zwÈQ׎‚µüáI´ý=WI‹}ÑÀ̤.Ovvì èš'¯_?ÛÜÄ7œúOç]U0±¨®ã¯SÖ¡]áÒ|Þ‡ÎúV‘®ê»]Ù­ÂÊàÄ³Ê ÔõÇ«ŸAÐõM.+¿Çe§\Û4·ÂYÐüÄçIàþF½ÇGðÓY[FðiÑIrÃ÷qž!êOAüÍ*x6k©É¹Ô&`÷R€ÑTâO/¾Èú\>kîÏ"Õí/ìµIÙd·?+f<…€Hǧò¯UøUãK¯ªx-¯ãе[«¡(ÔÖ"ò̘‘H<1 @í“Èæ¶>Ãar…š5ŽVPFW©=y÷¯ø¥§ÝøPƒR°sQËæ!F ©ÏÝÈéÜ¥N_Tš u³*^î’[z÷>§øi¨ü7Ñõ­wÃ&åoõ»{–½iõ«DI6TmgÈ}¸-Ørzb¼s⇀u«o‰µ¯ˆmõÇ·²m]g1íšþ"Çä­…r2:(ZÌ×|#{æYø—Bµ“^7Ú|@Û\¹i`V!ÝÓiÓ‚¯=+jñ† ÷Šu[ FÔÙÆm4ˆ·+J!Ÿb<™;U@8×ÞS‚¥mNwmY­7ÛúùŸŒWöµªÊ5ûÞúôþ¿# %Òìt‹ë²¿GHŠÞF„[["üÐ2!¹õ=+•ñ熯uÐ|_Ö¥â3mtVáDwŽJa]pÜ€võÀéQèúΩu>•yk{g£è)ý±÷¶¬Â;€x‡º»~n§Ú½Še«ÆWkF¿¯éì|î*µ\TÚ«ÖÖ%Ûúêgx~ú¿êmÛZy“ÿ¥\$+,Ö’y„ù8ûØ c g8â¼ÿSÕt¨¼W·áC{c}ÈeÈ”¸ýc»Œ!ô\õ?šO‰´ÏëmÑIõa×:|„b;Œ–\ìá28ÊxÂz—Ãkyµ;Y.¥ž4{‰Ý®áí‘‘ø]ô*F»ß·õÐóñrö°Š4’VæßEÕvg[àŸˆ^$¾ðü2iš!]BÞõn漃Fö$ÈŒ2Ò çrá@ìkÓµý[Xñwö0rk°žóO:¯£é\¤v²áµ ÑÊ7«Hù'SX ¾4À±x‚ bdŒËä0‘Ww–ŠØØ6ôÆáÅyxŠ’ºqšþ¿¯ó>›†7RÍé¦Þ¾§!ÿ ç£ÿÏCÿ~šŠõŸøZzWüó»ÿÀwÿâh®¬b{?T£ÿ>£ø‡O¾&^Ë&«§Eá? •Ä:TLZêáYOÏ$Aä};×s¤hÞøUze…“_k’ eÒôôs/£HÇ„_öœè mÚZx‹Åp„Ñ¢—úCu ”nœv1Fxˆï6[ØWE¦xÃß 4InîæƒM¶fÝ5Ôò{‰?Úc–‘Ï ÉôYéʶí»ùÿWô8£.]Ù‘ªü?Ôüq¬ÜŸÝÐÄÅ¡ÐìÉHHà´8æVöû¾Õ¹qw¦x8ǤØY‹ÝH ò´» £Ê\ðd8Ûû·'°4ûëÝÅ× —»ÃšFŒoJâö|¨8E#q“—ôÛVôí'Mð”cÓ-<ëÇ;ÌjrîOW‘ÎOü ‰'µyó“ÙýÝ>Õý¢Oîÿ3=¼=6¢«⋘^NøìP•µ·=Ž.ÞíŸ`*ÅÄrê±Kµ—¤¨ó%¸ÎÉÜz¨?ttäóJMNê ×:¬éqv€Ê°)Û =OOý˜óô¯ ñ—Ç[gðî«}§Ng™Á¶°¢Ýo4ÝŒðUzîädcšªjRwí÷|”%4”à^eo‰ß¬ü1eq¢é >×*4qAË’x/!þÏ~MyåÿÅM6Ââ×FKÖÖ5{\C§ØÏ0¶vPHy8PÀã<õ¯ñÄx<34ñÄÍ}ªÈKÉ#·ÌsüNÇî¯>•ÊËwâOjÒ Ÿ_éZ6¤"ûU–;Ç )#$ää“÷ºã5é*ÒÃü»ùÊgÈîí½±w^êz:õ£Á©Ã> ùqHÎ9 äÆÖ¥|áñÿö«¸ðÍõ÷…|¨ÛϨåÝëve¶@ÜîH²pÎ:èq“Íx÷‹¾;ëz„¦ð†õ)áÑbv‰æ–G“˜‘»!',z±ïÖ¼[;1“šúJUiÆRV¿•ŒÇ×*²¥EÞÏtïþW$»¹{©7<)$³4„’ÌO,Iä’jŒÜ¸<‘S–ÚHûô¨¤ecŠîJÇ‚ž£a$FݲxÏô¥#iïíR>ß” :‘Ša¾žµC¹$r¤7â ëïUÝ66;zÓÑH údS’05W¾à•ž„‹–_B=+·økãWðÆ©²Gcœ…•sÀn¿¥p«òŽçñ¢7(Ù#ƒÁúTÉ]X¨· sG¡õ”³Ûê¶ûXqÆ~£éY& Ý6BÖó¼c¨ØÙSŸcڹñ„áf#P±ÂLŒ8’2>I1ÜõÜ{×aqdÛpªìçŒÍy5[ƒw>Ó o8õ05¯êpÚ1¹¼Q!ÎÔäÖ¼Ä:ôþ"ÔæbBDhNvñ¯³~|/Ðüqñ?OÐüUÝYßÚÝ*Z¨ëû¼~™õA_xûÁ÷>ñLj<3xÁî´mB}>WÆÑHSpúàƯ /ÞÏäy¹¥GNj…ú]ÿ_Öæ,.pG5Óø*ÚÞi®­®g0JÊ<‡êž}ˆÏé\¨Ü3çoZÒ‚ÖicI Wpd1g×Ó§9Á­ñ‹W‘ãS”¹­×<-y öZ¥ÉPÂÞLÇO—…½ËCµM±\?,ÛS$ò{íóÃÝ:ÿNÔï´{ûYì¾Ðê$¸R…€ ÍA¯§¼ êwQªÃ*¤Œ`ädûšòà®íýu>·œ^§£øfÕíš)·qÚI=M{Oƒ‘X‘ñÆsÆ+Ì$Óï"HÉc<ä™rGå[PxšÓÂv±Üë$‹NfèNÈ—ðÏÖ´•š±ìI¹@öáLX´h€yçµfjšJM½ÐO'=ùþ•æžñè×XImâHõ{"øz`Œ~µÜk„–z[O6 x%~•Âá(Y³YBI)nrZ„RZ°í€Å±»îûÿ*ò_‰7qÞé½á ²#Ÿ˜zzì5êŒ 6Ño7}ÐÞ€ö¯ø›u~m¥ŽöÓìÒl;<¹ƒq÷xé\تPtÛ>“ ^p•›¹ôWà ZþËà÷†§ºµÙl#æßÞ9PyíʺÍ]®£³û^¡¥ÆÖÑD¨ZGˆ¨FÆïþá_ þ2ÝÛøgDÑWNóÚÁc–OµÆ‚¯^yö®’óöˆ¿Ž;Ã>‚~ËtG7Ж¹# ›3ƒ‘×úW£ 2v²Wý?ÌøzÕ ¤Û½›g§ù·~„^ 4ÚÛG›|M…?tžrO¿\Q=Íæ™e%ÌúRÛÚa&i?tTŠØÝÇ··­y„ß´V¤ËxbI/';~Ì/àwUÚ.Jío¿jrþÐדOhm-¬Q¨šìÞAä®á÷rWæ?/aÚ´XjÝÅëKM_Üv^9ø…oðÛÁ’ëúí›Øèv­ žl1¤¤8Bª­’zþæ¼âÚá_Äåλ¥\H®&ßH°H‡ ,Œ?!é_<þØ´Eߎ|9§h1XM¥Á™Yftf‘˜mVq€ªƒÝ³_}\r9ô"®4Uå£ò9Þ=ó~ïcöOìkZ\÷ðéi.Ÿp«5Äö>S$Š îÊç8ééRY9Ñ4Ó4<ñX¤%Áp¥6ÆIËôÉ?­~€dÒ–&p¸<ÃôçŸÆ¾Ñà£:¶´KMgÚ« ®ÍÑÄöçn1 •éí^“ ÁE<-q¦Gk«øoTÓ6¦Í–‰ ÄDcÁ*qõ½”Ú³[mèj±4SºvùP¦³)´¶»]AŠQÙ)êü`Uyîä»Ó!ߥ]¾ž¤VØÛ 7ÍÈç¿­xe—íÓðúúÅ-"7*Œ¾RÃ=¬i´{‚ÛqÉ®¾ÃöÓ5 g´²Òç½²¶ˆ+Op¼ »r"LtíZ*ÝEnKÆPÙËð;}ÆÏC€\ØhS¤ <Ó"ÀJ0T±ÝÈSŒëZ_h¶»µ¸•´¥µºBÒæÝŠ8 œõè?Jó«ÚÂ-Ý[@Õ"¶;a†#`¿¾ ‘…Ì˵rßãý„ ”š¨WÉÛä-ˆ"4$œÂŒžþµr¥QýoÝ™ÇBÖRüF·ÕÔÙH`ÒîE¤ÃÍgX$ÛŸ˜ñŽ9£_¶³ñ®’#ºÒîšÑÁuš‘Cã?1 àœ|¹ô5ÂZ~к<LðŤê1ØZ+DÒý‹l,åA߆ëÐg­KiûCèöU Ò5X­çýÔ6cO!Üž#ß§=ýkžT$µŒ†ñÅÒ‹¼gfަÏAÒ- ó´Ý.hGÙ¾Ê.!‚Lùc®;ê@Éãšv—á; MŽòËG—ì¬û·µ±>iç?ÃÈÀõ®oLý¢4*hô›]6ü<( Œiä¤A²Hc»¯9­o|~Ò­ÿ‘(¯cÿ…!àÿúûìÑ^7×ðýŸõó;¿wÝýßðL=ÇIe~úF‡iý»®Ç÷àGÛ©=âOáÿpe ëUô?5®øŠåµ­eT²Èɲ@z‹xúF=O,{šñÙ#ãXñ¼Úï…n,´«9ôÔIËir%™Ù—oÌijœg9ÉçÓ5ô ö¯m¦¯ú@ó\Œù zàu>ßZä”ÓV§ÿ'JtgÈ÷òÔØÔž_2X¡"Ö87-ôè£úŸÈ×›üDøµáß…š÷——©gÎÎéî_ÑV>ÿʼóö“ý¦"øfÚn•o¥]ê~2Õ‡ú±¶>gb È'å ¼’§Ü×#ðàÅ÷~1Üx›âbS\Ótå’"äæILƒ§Ýàt_^¹®š×›[%¹ÇSK GÚKWm‘¡¤øwÅ´®­æøÀ ƒ›bêüáŽfnª »ß5/íQ¡ÚøSàå‚é0EfËym{xÆà mò ìý}ké .É,¼=,H bêlÚñ¯ý¦~,hÞÐ4-màÖŽŽ¸¯eÕïQ䱕™£íiʲÊSž£˜©¿à¦þ·ñðóâ-•ÄsA:ɤ±^<Å`n#uöËJíÇ­saäéÆ:i}~wým÷yÍá×þX^$úÈFŠ[{¸à@>bÃhb"*ËøXÏ£kwVs†Å9(Ûxeëž}AVWÃÿˆºˆøy‘¬Äúv¨®°EqpB‰ÕTªËƒÎv1R;•w®³ÅzÏ„ŸJ¾vCo$f8H<*­êÝyú×ù‘÷ÜÊêqØ÷û !¿Ó®ÐpÄŸ”“\wÿgÏ ü@ž+íbmM¦…‘ã0°hþSŸ¸r¸õãš³à­@7‡à}¥Ø¨³€¤ûz×±im›ioç]T]˸ýâ{cÞ¢¤œOMR&»3È>|1_@šd %æŸoÁdœ(rÎåÆBá-ÀèÅu?®/áüÖÖ{žá«¹<…Àæµío®!›YDY”aFHrN+“Õ~#hÚ>‘qc2jRÏ 8kˆ6«g#ùöë\u±kDtÐËãí6Ñ>ŸyàÇÂíoÄÆ›{câ%¾ÐÆåm)¤’ܪáxãzžwçšžËÀš¾£Áe¯]‹´·b‰r ,Q²IûÄg­}àïÙ·‚í5geÈ\•ç·r>•Èø÷RþЊÚ-:{èåQ*@Ýó TWª§h(ïúØéÁàá T«Í~]÷é‘é~ο<1ðæÛ]¼‰œˆCÇt×EVF#¤sÉ­¯…ß²§ƒüMà]+Uñq¯n&¸e¹`_q;r;evœ{×/¤i1é—S›ÂâöîÙ tâx`‘z²ÄÀ}Êšö‡?¼Sâ/ é÷Siq,ìŸ6cÙŸCÒ´… J—ñùŸŒÅÂ4Ú¦›÷·jß$µþºíûü.hVì»áÊ¢í°§Úªj±çÂ*+RòÞúÞÞÖšyÚí±H¥˜ôì¯Joø#bt¨˜uϵó'íóûDk~ø+&‚ðEawâV{vtûÿeP?Þ&4ú3VÊ–+þ~ž2Æ'öþGå—Å+ëOâ»q¤y±é“ÞK=¼SH\ÆŒr'“…À>ù®h|ÝAÇçõ¨üÆžGy9w%ãÖ¤ˆ`ªòFy&½&¬”N7+·&.ÐGBN:š>áÆr=ø«×6-mŸ´X\Ûc©¯ëþ5^D€!1OæÇ–êTš‹ÜÏšåfËãp>ô¨ON}iìõê3ýi„ƒ“úZÑyãYTƒŒQI ²Ú¶ø%’ƒ?¥ 1Fáþy¦ç>ÜóšÝ]¡%‡Ä¯iÅ-z÷j€£Í”¾Ð@ÉJû#öðt¿´ö«â{›ëH4[h¥:¶Ÿ&Ä•¤r2!à± ÌþïJøDŽ+õ+þ ƒ}ªxáN±o'‡Ë[êWk¨ЄI!*5÷P«‘þñõ¬±¨©µMÚOoÔÖšJ\öV[è¿­Ïjÿ† ðÃ@b'Öü£’ŠBz•¦xüªýƒ|>¡ñn¹æ¡ùeܾgL}î§Ž1é^çÄ)t‰ÇáÖ§°v•2÷éÒ¼fñßÌu¬U5öWþ¿Èùü~ÁÚrž+ÕÕ¢Ú¡23É÷¬{ödÑþisX¦¡s¬Í©©wwÜ>Ÿ*À¦6±$0ükèy~#° &¦Úó?‰_ôË­kO³žÙÖTùL}X@þU„Þ9+JG±—Õ…lB‹÷Ù#ÿ…‹ñþ|—þû¢¾‹ÿ…[àÿú—þÿ7øÑWûÏåõò;?´rÿä—áþgå'‰í¬>xŸ@¹ðݯöqŠ8nŽH,n#™ÀêJúƒEø×iñ2ûT–ÎÆYlb+²˜ÙEàc–%•tÀê ¯š>2õ- K½TÿJ‚g†Lgæd3\E§ŠïþÏnRy#1¢ªíbÀÇjóébV¯;Ï¡«ƒXÚ^ÏŸ–Úmÿ ~€|ð|¾/ø“}âÛ-Þ­“A¦É,cý!´Œcå ô¯Y _¾)ŒFAm9’|Á_|3ý¬<{ðÂé%±ÔcÔ¢Úcòu8|õ+è ýl럶Œ¼E¬jZ­µÂh·×öÿe•´È¼²Ñá I#§Qƒ^Í\⌔\bÒKo‘òTø[í*'8µ-ž½ÓÚÇÔßÿh-/ág‡õ 2ÂHu?½ÌÆ;væ0\üó‘ßÒ>­ß¿>ØàÀªkž$¾Ö˜—i ±,Ù8ÉîMc+¬dy‰ÀÈúšù*Õ%^WžËd~ÁÑË©¸ÑÖOy?Ó²9?ˆ×’E§Ã ¢y öý|WŸï=ÉÎ:zWOñ÷í:¤1îÜ"NxÈœ×,~FÎ}îWOÙá£~ºŸ‘çÕý¾aRÏE§Ýÿâõ zpàa@ç9ïQ˜òsN^ ¿¥{΋ž_z”§Ê03ÉïÅ@1Ò§Ù‚ç#Ÿzh— ¹NzPz`ç×8¦• Ügv;Šq““°ž¹þ”@ë€OÆš§n21žA=ªV*AµDàôÀ5=M¡Œž¹=½é‡œçÝiÊØÓØR:íÍ2‘ÚÒx{Z†ñí#Ô!’[i¾ìˆÃdr9Ú½Sö\×µÑûHø.ÏÂ÷siK¬ë–ÖsÚDÄÃ5³Ê<È¥NŽ›7 ­;WŒããÚ¯x{\Ô<1­ØêÚ]ôÚn©e*ÜZÞ@å^åYHèA©inÍúhÏÜÏþÉ_ u+¹'‹E’Ño5­-ïdŽç  qü$WÉ?ðT‡¯¡|(øusaÙ4]+QžÆ+AF²D»_rJ“’ké¿Ùö¬·ý¥¾ ‹Ÿ³ZøÓIT‡Z²Qäð·1ùæøéü-‘é\‡ü7íâ¿Ù»Äí&eº²ßEÇO)8ôwW°½¹W™pÆVrpÄI¾›÷?ùx#Õ¨/&´™$‚V†hÎC¡ÁºÔ.›HçÐÓFtç©®Ë'£2¾·%¹»ºžQ#ÜHÒ!Èbä‘ôçŠî|'ñ#X¿Öôë-_R¹»¶2"Ä×–ãû ô½pŒÜð1øäTE™YJýäl©«žxxIhŽºXª±ú…à(þÛáÛicÝä(RíþzW­ÛAåi/p_ÄÎO þ«åÙ·â:jÞ¶²¹ÆÒB6ïà7¾—Ñæ·žÑ4íÅc,ˆ9\üØôãù×]]]¨ak*”âÓ<ëXý¢ ð’l®¼%¬Ü\Ü~û~ÔHçÜxdbzcŒuÅpÞ#øá¥_À^M2Ak#Þd–‰}Nà É$qé_Sëz&™®éÍmu§Å-šŸÝ!Œ>ÁÛ¯óï^¬ü ðé»( ˱eŽ^Š}½ZÅ$àíÿ vájÑmÊW‹ëÖçm¡ø‘ï~Ëz™ÌBFøÚìîO­yLJŒZßaŽöú:Ý"fóæ¹6ê2pê Àæ»êÐGáH´Û@«å%@äqÐýq\7Ãÿ ?Œ|Z’=¼ [Û̳êW˜ÖP>eÀË0öç­ròÆu5Øè©VX|I-¹õ¿ƒÀ»ð†a©ÝiVZZÄŽ–6Á¼ÇglŒËœœóžyä×§YxŸI³¶Ž([NŠ$ vûµâz_ƒ´¨áÓ¿¶¦+1>‹w êuåäõÏ¿­^}1ZóûDiÑ7ŒþÆððÔ›Éù¸ó1ôükÔŽŒ]Ó×ÏïíÔü’½Jµdïmú_‰ìcÅúkȨZÀ³$Á'§¥~@ÁI~6Áñ[ãtÚn˜ñ>¡GýÛ¶RBŒL®=A°ú ¯¸~6x‹HøKðÏźîVid’ÚáßTrtû¹dk~³qýÚü›ð×€üUñŸÅWpøkJºÖ.ç‘ãHÓ gs€¹äòy$ÖžÎ?Þ¹h»éý“3§N­IªpÛ迯êǪ:{c“]_ýë!W+˜¬ÐÌDZnŠ??å^ƒ­þÇü?lnëzw2ØÜÇ+ø9üªO‡~—Ú#‹ëy-/n\´‘H¥]@à)¦= *ué×»’cÇáq8^´oµ×ê]¾t°š(Å„—É™%‰€9úw¬[¹¼%©+3d —–ÆÏûÝ+¢rG‘Æ{çòªÆr;‰P·+$y} urö>o™-NJO‡º-ðc<ÑñœÃ ‘>¸¬;ï†Wq1÷‘OÎ6Ê¥ú×suá=6MÎÖ‹¼á홢>Ý*_/‡¼=4£%¢ËŒÈÛ‹9àrzžÿ…S‹¶Æ¯6Ò‹½ûž9>mŒ¶ïVL4ŠsÓ#ôÆj¹9œä÷§‘É$õÏ­ ' úÕ¥d{Mð×ÁÿðøûCÐ~ìWw 'mávÄ>iI þ$Wïo¿ è¾ð6—¦ZX¥¼i¹A2q02`ü+ò_öø:> xèê—z}Õå”s­§™lê¿gÞò°=@ùGç_© áw†ÁôOí]Hf(ñ+þc#8é^}hF¥OzV¶Ÿ«×ÈïnP  ’÷µ~‹Eúžœ/tã‘å)ÿ¶©þ4ûy´û‡‰6¯'2'ø×˜Oáãy Ø}KOþÌ’XÚÐù[µ5Uê¾ÄÕQ§5°]eÓTš;”…‡ÐE¾Ô±Ávïÿë®oe“0Q¶_×ÈôÿøZÂí­no--î¬o:+ Ž8Ï¥|ÙñþÇMÔFÙeäăœ…8çõõ—ËfÁ g Ue »Ã+(ë±³ÆjÌ®£ O8;[“FvÆWÕ×…WnF2sœƒUdc"eÛåÎ1ý?J‚kƒ“‚:?:¡«jÂÒÊr­´*’;’{søÖôé9ÉF+VeWp”æôHâ5«±uª]L#qè8ª2½6Ò’2r=E9c‘Îx¯Ò)AB +¡ø]ZŽ¥GR[·q¡v¬§è{QëØqJq¼t úÒ\t­Œ‡¯9ã'Ö¬¼º ÁÆyîxªÑ|ÇúUÌþáºþDUÆÖ1–Œ‚eÚÙä‚8 j#ûÀðÙëššAÏñš€ï×Ú¥èÊŽÃd%[w¥_™Š“Œô¢BXÜØšŒuÁÉaÐç¥I®â²Œ}iW8Úy"¤¦ÞQОµOÏ^´Ò1M©õô©Cò¹9ëQr Ò•ËLõ¯Ù«öƒ¿ýŸþ1é~/‚ÜM§ Ûj–ÿ(¸µ| Ú½·(¯ÑŸÛ£ã^™¤~Í7†‡{ ì^+Š+M6uYa¸]Í"ƒÜDèH¯È¶]£€xïé]ïˆ~+jÞ.øcà¯]þÏðÄ—nìäïóYG°@GûÔ×»ðÿ_Ö¦U ¤Óûþ_ðmò8vùTuçÞ›ìáV"´šþþ [hüë‰bŠ4êìÇÄ××zWüWÆw±G Þ ÓŽ¢Ñykh"€Fá‰1´‚9 Ðöê(Œ[WE9EZïsåøWYñ…á³Ñt»½Rä)vŽÒ"ìrIÇN=ké…ÿ°®½®iWÞ::§ƒÌ6véf²Lìã*ûëŽNÓÀ'+ì߆_³•ŸÁŸ†údv¦M>ßËßKwt¶²ê37È„¡Ë*‚åÈÜÛxšëµ}ܴͥÖÓîXá»¶Q4qÉ UÀrÅüÀFÀAR¤}ÓT¹”á)Å8mÿ ê|±áŸ…Ðx8|?|Âo³. ½µm² Éõ •aÁÏÖ»ë+½CJ‘P‰µE#eå´DH½†øùý+¾“Ãoˆ/\]iå½âÈöZWÏ5À™‚²…È$Æîn'·áo…ëq®[Ù¥ä¢6Id2ˆÄ±ªBI‘ÒE>U Ø'9ד:»=³Âf…$Þ–^¿•þgƹô‹aoqkæ*’H‡${«`Šæõ‰ƒTŸ6€Ãpù]ØËO8Q’ÇšúKðÿ„æ0Nöº¯Šl Èßl³U #ª¨è@mÌXýÓÁ_qW¬ü7áËm.ËOÕÓJÓ…ã´’ËÛ62KD" nHÊìÏñA®IPŒcÍ)Yµ<áYÆ•iyo×§•¼ðÃÛ¯ÞX5õœ‘i“ªË w¬×™lt^c^¹Îb9¯mð¯Ã}7Âq›«D[;LB°[4;’9UÓ¶H<ç5»¦x^ƽ›IÝ¢ .᳸–Híå$ù…wìbÇh8$ÛŠ½gªO¬_ꈶm",N3§3ùÆ€òãE?+JÅ›vÒ¤ ½slj¡í¥ËIh·×ÐÂYÞS–¦ßw®å=JÍc˜Ù!p"f² ¤žyÆ(:Uî«dÛݾŸ«\Ãû­a£BÛwäĤŽxV÷À¯-¼òÝ]#ÙMei u†HÜm™7(‚¡9ÎFx>”Z[®¥0I¬Ù–YV2e?2F›Œlàs¸äã‚{וJµL=K/Ä+S§‰§wm:«ŸŸðR¯Š¯öwÃË 6]6àJooATSu4ƒdRaOtÞyþýz'ìóà›/„º¿„–“¬qÜÝܨæâVP]ÉïŒí¶+Ѿ:h^Õ5øg×|;oq«iwQÞG}w‰Œª£‘Ÿ0p¸ÉǼæÛNñoŒu+½O@²R-ó{mîc{”ݵ•r0Kã ùkÒnXº|¼ºoëýl{Y^–Yˆ¯$¹Òµô²ÿƒsÓ?µ"¼µÔnYG“otÖÎãjä>™ÎkÆ?h¯‡pjZ¥®ÚG¿Ó‚y²GÖXÎ3»ÔõçØæqñJ&‹\ÓšÒõ¯¯ˆg³‚ÙH0²y«“§|õ¡ñGÅpZxGÅRHÑĦÆ80?売äEyô°Ò¦ý¥7ª>—Fl<éU³‹Zõ¶Ö›OÈù ¦x ²Ã$Àuòñ•÷Å=u]5YVåþÊÙãícÉôÉâš>t, ¹RO#¶jX~hÿ|‡efÞ§ð=«í9_CùÉlñDŒ«nþt{ónVúþ•åµ6â×NC…ŒyÒ`÷<(ü¹ükÑç–;[wrÊ¢–8áQ^œ×^ªê«jW7mÖi è;~€U¥ÜêÂGš|ÝOƒÁ4åS&ØÑ Èì¨êIàMQ–>¿Zô^±ñŸÄí*ËTŸìÚtmæË)$r8A‘ܱ‘¢rä‹—cÝ¥MÕš‚êÏÓÏØwá’xá€þΉ-®#u‹\{»F&äl,þYôÜÄqè+Þ&¹ÒLJVk‹tº"Ãeö9 ÂËæu#Ò¢Ñ,£Ñ¬4M6çÊÓΞÛtx¡¾lj EÕýI÷õ«PÝ]¥Ü·[G?Š^VëE7Äà {¾ø½;w¯27üº¯ëçÓc¶´ã9¶–=‹þ’í¤:­¬z˜µ}ušvÑ$ŠÕü¸#ÛÀ“šdÜ>«rºq¶_ƶãT¸’ÞA Çßgcj©ªjúg‡&]*m@-Žªn$¸¹žùÌ,@bLdŒñÇ^q\ÅÇÅo Ï,zTój±i¶2Bm/íüÃ%Û'Q'ž9®'‰¢´s×åß·é×sίÂat¯V1õi_¡à´^£k&­¥:iÐÝܲîR88<Fw^د7±¹Žô¼›ÄR·«`g¿³é^ÏâŸi¼G©jZtš>¯mjðù7÷A ºX £%q¸`À÷¾„Ðþø'PÐ-$ú¡qF¦hm£—?(êËùæ²¥RdÔd¯Úÿ×cíaG Jœ^­¤ôièÕÓÑìï¡ðþÈé—ýü¢¾íÿ…Yà_ú´Ÿü_ð¢»=›ó3þÚ¥ü¯ïGçq¥ÍÂÜŽÈ#7Ö¼_Äë§so$X +àc§÷ÁÞÒ¥Õ1î¥#4vgï¬H9gô$úæ¾ÅÐ<ch'ƒLÓãÚàGö;e !Ü8¯žm]ûÞ/ðÅŽ¡•rÚ[Na?z=Ó0Á÷ù+\}b Ú+þðNŒÞ´c‚ž¾ó²ûísç„'æ8É=iài±€TŒãµ>0I8¯³GåÌaûÜg'ÔÓ¢aÈõàæ†L(-À=)UY9ÚA òE„°GŒœàéŽ*y" !·BJ¯Nj´i–,I?SúUûn uíŒâ·‚OFa7mH^îT8~Áâ –Í¢ãuÍY¸¹ GÕrUr;gµ)¥p‹}¥R༓ҫÛ°@õÅ[| ;rGL°þµ‹æ.3úŠÅé©ÑF ÎsÏ|úTŽ£<‚3€Ã¹÷©Ã©LŒ\Ò)èIo†R½?Æ¡•Lp >6òäÞÕ=Ô+,@nËþµ“Ñù)N1ÏLú˜¯îUS#Žy¨ &N8 Uû )o®b´·MÓNÂ4QÆKpj®ô´G§þÉž¸ñwíà›X-!½h¯ÖãʹÿTvÃwldwã±ÆkõßÄ$zÅ´ñ[ÇŸhmmc´Ó³lÞlŒ*¹deÑñÎkäØËögÕ¾ÜÞj^"ÓnƵ:®mì’9žÃ+*²7ÊÁŽ3’'Ž>ÐÐnlõZt;mKU¹½3G,ä·–W–ÏÈ‚ª“ƒ·qn¸´oÙµê×Ýú¯4ä¶üíùu×µöLÜÓ¥“Q³GK{]PCx¶°Þj·!çÔlƒlRmv#¶ð3Ž¢Ó?µ|3|f±—¯}xm®´›ÈVéU±º@øùô`ÛŠÉéUåK>ÛO7—¶z<ÞEͶ‘ .„ÚD`9Û³i`Ieیւä¹Ö4ã%ÄÍmq%”ÉrZ…›O²7”ù²>Vg#çRÀ\×/%ïååývþ¬tE{¼÷¶½o}þï7½¿žÑ<#cuã 5k¹áÓô I&µ‚ûSEK‰%s¾XÑ‹2´ ·`Ž`ø“\ÔBÃw5ÎKâdñ>­>“`ˆ<1¦Ü°´† ¸˜œ4ìzœô\ô\g’Mwö6âÆOº£ï!õÅxìMEîÒÑ_q÷Ùn•5ø…Í'²{/=z÷é~æ+i×in¹¼Ôv³2›Ç.ÜöÃp3ÏëUuZǧ²[À¾qÁ%-Ž@þUÒ¡k‰ £˜ÔY—¯q}"°%cA¸–çÐWÎÉNO—«þºeK*oÝÑ"ǯõ;),5kù'‡”’Ý€x߃ÃŒzúÕ¤ø™®M{mßÞÌ g‰bAŒHP:|ç«›ñ iofXѤl+¼F:ûöñ“\\eÛÚËs,J>è,yþ_9R«r_›·ÜtÆŽ´y©Á?+-?«Ô/¼I¬ÜE%…åØŽÙ³µÉ ‡§ Åtžø¡©é^"X|W{nÖÒ¡Ä’)R% 6r¼m$œäqƒ\½•ÄñKœ^8›™"R ŒÇŒæsZ—Þ—¤i²I ¬ ,Ÿ0žE¸úàsè;Vj^ê¿¢ÿ2kBœ¡ìjAY螉¯™Òø¸i&°¹»Õ?²µO´ªÛ=Ùˆù(_zˆ–5%— †,r621\æ™áñ¹¡˜á–xÒV?²3Í=̹ÞybÈQdAòÙØG5æÚ‡ÅýSO¾ºžÎâéÂÍçÈð®áæp0w;ñ^á-tjZ͆›â„†+ÙI•.tYd"RŒe6Ï"Ÿ—Ëpêê1ÛŽàWÖenRƒ‹V¶¿™ùÿa*`ýœÔ¯unÖ_×ùhmxÃÁwŽ-ÞQßÃÞ º³;§âãT< |¥T°Y·ŽH¯ƒá¾µ¡üOðõ¿Œ!´Õô»MVGû3ÇòÈ< Y^sÏWÐòÝéVÎ.m¬d–ßS¶ŠæíçQ,W3Ãó$—XÓw!F ã5KÄŸ-ôÛi_Ï2iVÚ›¾ãn×n\þïiËÛº ‹€Àçœs^ŒèÆmJÚþ¿ëýv< gˆÂÑtSnV·ÊÚ=÷ÒÞ]:|5ûMü“àŒ£K7–ëÃZ˜y4Û’>dÚFø$ãБÏñ­xávÚApËÐñÍzwí›ûhXüPÐíüá»S ²ÔVþmiÎ~uF]‘®8ÎyP­|¹iñOQˆm»Š µÇ-÷ü*is+ßdôôþ¾óÀÅá%ÏxoÕyþGsâï,øsS2Lb‰aÁt#súõ<}+ÄŽqƒÇ񼧿Ö?é¶ööð<dó% sž00:äxÇoZÚ+wbð´å{ÝG)ÆkíÏØ—Þ&ð/ƒeñM—†YƒWºÊÏ$ ®InG¨¯ˆXœmÒ½oAý ~"x?E±Ót¿jVZ}¬B(-ãe ŽÀc¥EZr¨´Iúþ­‡ÄÓÃOškt×ß¿à~¯\üxÒ´jº–¥oªG¨µÔ±é¶—ö±¬Ð¶ÕCŒ‚ŠX|Ç+˼Yñ§Ä³b}UtiŒ+äOkY®#ÇÊÎøÉ'$㱯—¾|KÖ¾(Ú뚇‰u;KYÓdŠH¦¹“>|nv˜Âú¯P@g=+¹ø—­¸"æîúöC€Jw*¢ŽŽÚ¾N¶®#,ä¬íä­mß;ŸœËŽÅ¬&N–ÖüyŸËDº÷­¼*^]\Ü_O¼ev’f‘~ebÇ® 'Óš­eûTiºœoöƒ,²Ëól{rY›q'Üçµ|íâ 7ñ>®³Ý®¥ieÁvì<Å'ï–ÇÈ3œðN^ñ“‡ë¥XxcÇMñ,Q—¾Ö.g’íNï¸#\l'ïãTUÀQ…YB“¼V‰íEýhzPà¯ÙFXš““z»>¾–>„пhÓ^¶»‡Ë‚â8¤ŠîàpÁ³…#Y°CÍ^Ñþ Z›uff³8ÕlˆxšMòä!ç8Ër8?JøkÄ—Þ*žQ¨^ê7º¥áoÞ‰­Ûv8#‘øW·þϾ;Æú6§¶w–‘«omÀH„ã#=ùt¬e—¨ÁÔMYo÷ú3pärú_XÀT›PÙIê–Ú5òÓËNǽÿÃMxŸþ€–÷îoþ9ERÿ„fùïqùð¢¼e‡óûßùžúË™ÿÏÉ}ìð þk;„~âáÑ‚Œ`†=?:Ìø«uæ &þ-ÆXWh”Œd©ÊþX­›KÅî³l:‡Yã'’ÙP=óYþ6n<"ýç‘ “Óé^ŒàèÖ”GúŸÕ¸yûl,'ä~‘ü Ô­õh÷¶J±[^[Gt(ýä;û{šèõ¯ èÚ¿í) Ï}¥Z]H¶24°©ÚÛq»§&¼SöñkþðlîÙ’Ú°~§"ê3øm¯zÔ¿uûBøpôó,åúáOåÍ}µY{UJoª¿àÏÉ¡B½ziìšû™¥a¥ØéWž,¶PZ)qƒ AÜ•ù‹ÿ5³xþ,xjïItÉb 9ÁK‡$ãâ¿Pâµ?Îâÿb¿0¿à¦ºßñ7ÚVÑþ‹g5Ã7ýu“ðÂθ¨ÿóýOQûÔfßhþ‡Ç©Œr:ö©‚ùcäÁ>­Ï½6°!!—cïR”3É`_Zúìx2z‘`>%‰Á-Ö•ÈÈì}=¨LŽý…+Œ@Ž´ÄH‹…'ïsŽ)P”#'4øpSÏJd©´dôëëZYÚèÎ÷v%™Id –ÏJªB† ç¡õ«>`’/›œt>•_wcœv¢Zìì1˜¨Á)éPȦ<2çµ;(äAèGõ¦gË9ê+Chè@à 0Û½`9¿T­?7Pq;T;¶JCžµ75Z¢@;tFM]Ø_¡Î@>œÕ'»rqš³ …QO÷OOZ™+¢JsD°\…eÜ3ú×Ú?±Oì­gâë½?Æž4ԤѢ}“èö/nÜÄdòÌÌ2AÎ# u!¹ÏÇð%ºêöFâ3qeö˜üÈ‘¹xË€Ê1Ï#"¿h,lôý Tk/ Ãe£ñ‡m¬'7SÛÅeÍ´ÛA ±†ÜøØùbåeÁäÕsm-ßåÎ>µ­§[,Å[HÇú±É¯"xúé;E--×þîRÈpT¦ªNmÛ²K¯]ý:O€ü-u¢ZF&‰–䓽— œà}?¡®‡QÖ^Êê§¡YäÙ,1–ã éî#2O )¯ñ1:× ®x\ØøÍ¯n¥k‰$_ÜE9ù#é˜êO¹ö¯25%Søš[F$üìvQo’ ËÂõÜqôª7¯+ŵ@ؼÏ ;Ó­¯K6…²IùNN{àÔÒE%¥åd?çé]4é%­£q“‰‘wn³Ü¢ÈUÈû¡º Çz¡q¬.‹mqƒ§'È\}ñ[-‡d WŽIƧ<Ö‰d÷Ú„—n‚Í2>r$nʿ̟¥i,ñ3Q„nüÍã˜QÁЕJòå„UØXø{Äž"atÖ¯e |щ†×n;Èã<šÒÔü>¡¦ˆö*]Æ E̤FbÁzç¿5bË‹FY\K峓í,βw g${ÓߥmÚjóëV´D¸•p7“WL’Gç€:×Ô>QÖsû´_×ÌüÉøƒV¤­‡¤•¶¾¯úùtê¶réîú„ÙÛÏÒÚÚFc$2vÏlֽ熮ơeug¨Kauk,±¼°œ-ævi##î9âž59C-¹f',Còˆ ž2J­¯øæÃA°’{‰V0ïœrI죹ÿí¡”Æ‹Nš<|o×ÅûÕÚû³E¨Yj2Ksqkv’3¤óÞÉ´Í vH¨˜0@ÚN8-Á5çþ-ðׇüam,ÅíÝÍõŲÙÜ\è’5˜™^[RÊÃZ¨š–­ãÇû\ÎúO‡£fS)O9ô·¦y>µ±áo©Öà³Ò´ûh¬G®dã©.yÿëšöc—F|þóëÑz-<ú´çS|‰öWðÂh¿±ßÂ褎K/†k:( %Ö/çp}>RÃ?LW¢é_³÷Ã2Ð,ž ð¬IŒM*69÷-’k©¾ñÂðJIÆñËNc†žk–3HR Né}úíLp±’øR^K_ÄÎxéF_¤üÞŸr8ï~É?lÝNØ;1_(üqÿ‚z^ø^ÖãUø©Ï­ÚĦGÒ5 t©òÜ|²cÓ‚}ëïÝ?U·8„¶A]ü çŸóô­„EÕm·ù%€ÇƒœöôþUäÖÁ[Zz]¿¦{ø\ÖúT×úüÄχ^ >0ñ|zMÆ­_3†ßD·G¹…9 £9Î~•éZ¯ÁÏ èÚl×·v­#¶,n>ÑáØ•TüÇy| O×Þ^4ý‘müQñONño‚/l<â nþÑz×(þMÔ˜\/MÇûŒõ5å¿¶ÇÅI5ïÙÒÑ4FDžã^mYŠzKÿ6žBï@Þãnz×—Z¬¨Å&µÙùl“ô>Ž„iâ’~ê×ðnÞºðËÀxsKÒüC ë§íÓÁ¡å„Ž]¼’°Éî á…z:j²êÖð^[Êê“(;s‚?Ï#ð¯›þ |G_ë¢ÏQfm2áŠ>O1“ÜzzýG½}3 év°-Ý­žù•÷]#9è™ùÿRF5œRærg³…qäJ>¿£5,u£‹x¼äŒ.ç-ß§55ãËm ,E»eÔp¹íŸÖ¢µ²™ ûI‚GmÅY"Œ±ÀïéSêÖj–fÎU»†'2’Œõî0yìkJ°‹WŠ=:S”z²æŸáûBe¹½½°‚R>óN®Àvàjõ‹]ë^þÁÖ/­õ±Âe[(¾Ð¨§ µÔðG@zãŠðß øÅ’ÞIn¾ðlj4Õæ;çit÷oc’TŸ¥w^±½ðn£æEðîæÊí_ÎÓ/£™C/FaÈÉÁ÷¯¥J°vüŽõ 5•çú§¿Üt¿ð‚øgûÚçæ¿áEmÂàñ_ý ^'ÿ¿ñTW=nÏðÿ"ý„?•~?ä|’Ãì¾!¶—fÏ´FT:ÇéU"Ô´dˆþÇ9Œ+‘†.V¸Æc´czu£«p¸µŠçžØbœ?\j_!08çÖœ¥C®?J‰"ƒ‚~öx¡$݃€[¦zèODŒ$/ Ê©`Ñ֣ä€AÀ<*Ò–'å#Ž@aÅV–0¬rv¶9γ”mª..ú2>;FL‘ÎW×µ&ð;žzÖ2»ØÝ!ÈŒœm'=‰ªÓ®Ù;œž3VÑÒN7dôëL¼]Ȭ §Ö\ÖzšGr7?8Á9©¬¶ù»® “éïUÃeóŸóÍHãÔ}OvÐèßô+}wã7ƒíï­ç¸Ó­µïo’ÞÂÖçJØô 'Ú¾ðøã}KYÒôk‰_^/â HªíYÚYB¸îª£8þó“ØWçÏízmÆúMôbfsk,ÈÁqªbpsÆnAíšû+ZÔãÃ^×¾Ñöˆ³ÿ²¥ gd°¹ÂŸL£©üû ™[Ø;wWôÿ‡±Õ—ÙcbåÛO_ëô:ÛH¢†ÏBqÓ¯+Ó<{ia¦4ŒÂe°§Óžëï|K¦–÷Wˆ ˆng' W)e¯x¿Ç饤Ún†N<ï¹,ÊxÏb£õ¯½£§sô:3svGÖ:_‹l5ÙZk+ˆç€HºžÏPÜûž¾•ÛE¨Ùi‚,âÚVa–à1÷'žÕòç…|.…l¢æÓÙÈÂ6Øà“’÷¯]ðÿˆŸû3ìzìky ˜Ò}¸R>ë~†¸ªSçJÛq§Ñ½ï[ñž°{FslsûÈ—ƒÝ‚òWÜs\†¹âøôÛ»Ÿþ&Lª¹’„äo^{v¹¹uMCÁw£C¿’mCJ ÉiCL®ÕoâÚ;œt®R¸“UÕæ²Ð\+Æfx$b]½›¯õ­!Cï;irSOïò·èÿØü7®Ãz¾kºù‘p&>bŸºÜt$u«T™ m…#ŒX–Ûü=kÓ¯lôÝ6ÝnB›NÝÛF Ÿ¯©ë[òj°G¦ÉŸìÚr®æœð\z&y?Zô(á'9(Á]Ÿ3™æti©V›å‰£|±:4“Î#0dfÀ-íŸ_å\åÇ‰Ž©uµ¢bÕ>UTé×ÿ­\Œ¾!½ñÅüVÖ1´ vÇ/QØšï´ÿ àÙnº1¡Q“$¼F¹ê1Üý+ï°xXÞzÍŸ„fù¾':©ÉMòÑ_Ö¾‘ Y.ÑRF)?3†oöPu?_ʶíô¦³0Ëí0GÊNª˜²þ=ø¬‹MZóR•Žbn$?+jW„$kþî{}*?øG>×<’kšî÷b•m¸]Žïâ«Ö«OÑÜÀø‡®-®Ÿ¥¿È¯û¸ÑG£¶1þO5gá´$’o1°«Îïøÿ*æ~!FhòÆK/ž«¹2FÖà“Ÿ§é]Oèd‰d™Nè–7Bs¬Œ~ oV6¤”L°Òæ¬ç-ìuwR ‘!vÿ_þ½&n%VeÁ*øçµD×Kª¨Û““ž3õöõúTþsù~o™ ,{ÿ!ü«‘Å­ŽèÍKKšVlr\‘—'¢+ã=óý+nÚâhÜ¢·$޼t÷Ç5ËÚÁ-²¬€3–f'?Ãó­M?P™€KíýH<àþË8·®ç¡JJ)+Xé“íç(å\d¨ú×Â?¶ÇìÃ{i¦ê~1ð`¹m:{±¨ëzgpó°ÀÝÆ;œ1Ü=óÓ§Üv÷Òg*\}ì!éÏëNDK²á’'ɲ•UƒÓúÓúÿ&~®Û|5¸•¢iþjw1DÜÖvžO HÆIè+¦µðe”¦-ÿ õK2›ÿ5 ÿ¾+òMüS®©9×µ0Hí©IÏå[:v±ã)ô›NÏV×^Æß;æMjD € ãp'‚: ô!)Îê½»_o¸æž)|S—ÞÿÎGê­Ï€o5 6·€î"xò潕ð¿LÖµŸ„?³ãb~èêeΡ0:üàWãõÏüM3>"ÖÈéójÓ0?øõg\ëz•×3ß_NOüõ¼‘¹üMsºùkíäÕ¹Ÿõó?d?°!ÿ¡KÃø7?ãE~4ý¶ïþ~îð!¿ÆŠ~Ú]¿1{WüÏúùŸxü>ð²øº]gODóé÷[ûB*~¹¼§Wœ%öŸvˆÁåUc¸ð09ýM}1û%éâóâc‰WrÈí RAÆèŸ"¾bø‹c>‡âOJ‘жqn#n6!ÇéŠùœù5*sî­áú—ö´»Yþð$ñ–xÌE&èm®f@[Œ€N3Iâ‡:—‡m£»IDöŽv‡ÇCèGZÓø—Ž{;ôÊñ‚@àËõ¯¡~ ü.Õü¦x>âçÉÔ´ýOì÷ö·V™d’)?0#޼ƒ\0©?cÄôeN¼¡'fö>7¸b£²Ùþ^Õ!ù÷`ã¹Í}I¯|мK \BÒ铎BFyë´ôü+Âþ+x×áö¿•k}%ù6©<"*Xœ(ǰÏã^Æ´'S—©ãføjÔèóOk­N<>?uO{Õ‚¥W#9ü¹ªmÈ<Õ¨e2AŒ ©çM}2±ñV‚ñÓ½G·ŽI4­ógo^£R  I‹î_™wÇZF“ÊÆHooJgE8t¦È°=³UvBHíØ¼ø¨ËÌí–^GµYXÊŽ`ŸóšyyÃ/­cæKdPguaŸQMO-‰à©ÏÔUÉA?OLqUš Ã`žâ¥«ÆW£cÏú©éN[‡Æ×ÉB1ŠcDPü¤ƒõ H܇ç=ÅdÑjÄ@”$g¾9©Á ¦Hð3øúRÆ®äBÍØ(¦ÚJìÓ•ÉèL$ÛU9ïŸJú àOÅõ“ÂÞ&ð¿‰Ͳx…í­ã02Çp¹ …ÏÌJœsµ³ü"¼“Âÿ |Aây#6Ú|©re”lP=rzþô/À0iA,î³Þ±ùÞCÂlW‘[1… Æówõsè°9'(ÎIÅ-o×ä;ÀþÔü{¨Åu«4ße‚@`²w¤~äwlc“_MxwÁÙpbÖÞcŒñR^ù8ÏÍÚ¢ð焆‰k BvIŽv4¬QsìAþuÚÙ,Ñ¢CsfÈ#û¤öÏ?¥x Rœ®ÝÏÑTiá©rE´ÝÔ#O$a(8ÊØóÏ^õr[[9£¸¶–Øé¼Ä ù¶÷³ÓžüUwš+ó, Û[H¥¤IqµzàƒÛ¸úÖ>±âímd•.^Ýþ\8$ýUêC¥Ï¥OxÌ¿Ñá¶¾Yç¹["îŽÖYAòÛûÃ=¯|W1?‹%Ô¼E› Z#Þ]~ïs ¤ªœ³3tw>˜ë…׫xm¦xÕÛ÷erI8ùPwÉôï^—ðÛçÃM{×0ºÖ]µ ¿%¼ûµú[¶¾eÌ[b…"·BWlGJÍÖnÖÅÄ‚7•ÁùBã«ÏuêMµN?;ë÷ÿ•]`èÒŠ•yz.‹å®¾¥‹P¾M±N°À¼Ô`:ñ®sWðåî‘’Ê‹"/.Á·Ÿëü«r×]¿¾(Öúk2c$3`ýzU¸YŸͲ‚N¯^:Öð¯V“´œ}.qÖÁáñpRo½/ñ=î«=ŒÖ—QÇP,QÂÎHg=}jo^jRÝC¶ß{NV@AÆâÊp@Œ€kÔφà‚cs%…’2.ähÆï~Õåž=ñp¹Öü›;d»´‹ÎiQö¼ErgÁä`õ»ib#UòE|Ï*¾ tiº’–Å_é÷þ ñUžŸ%ÁŠÕ§ "8Ð` ¸?1'q9’fº½ÚËH³‚Æ É`Í’‡æ•˜òO¾qϾ1\EÃIªk3]1xÄ6É0•8ØæÎO`A>Õ.âËmzõ+yMm2Ç:DpªÙ\î°§QÚºd¾ËèpEòÆéo¹é‚âæS…š¹ ;É,˜XøõéíõúWA h¶p,×R­Å܇!w’#'û£×žµËÁ?•1ÿ¤C+¬‰<·<à{u#½2ßZº¹ºº¼u>Zü‹·ªÉÜ:ƒÏã\u!)®X»#¿Vœ<ÕÚûAk[o3{eœgZ„k6Vð¼p#×ÄAâ×¾»ûñËË[»7€yâ”°IðËÊ€¦RxÿŠ?¥rÇþÛ;瘧ü4tÐë\Ï±Š…<“Âà}==Ík=õ¬Hæã^NqÆ+‚ñŠl<eö‹÷pçýU¬ æO{죾?¾p£½|÷¬übñ¯Ä=nîÅåÂÞ‰XE§éLßj¸ F÷<6ÓœÐ3Ö³åJŠ=ÿ%çý\郩?Z¨­Úýßeý%æ})⟊~ðØžÓVÕm¦ºØV[%áö‘†±†*0оý«~ xOLFñ·­ü­.IBjZj—ŒZ;ò’* £Œt§¾°°Òlχ ‡MŠÞÖÆæ#¶‹æ’pw1$·'/ÉÏ~µçü/yâëº-­¹KÛÛxíãiÎÕdóU›Œòäzf³ÅåôcFU“÷’Óäte¹½j˜ˆa­¤š__‘ùôD(¸2BÄœ(îæ½ÚïöFñ” ¹,"˜u>\ñ·½«ëökñœI˜´Û±‚Ñ9±ù=|k«.ߊ?KY÷ŸÝ#ÈÊÛíÉ ^\ú}k¹Ðþ|Añ ²Ï§ø\¸ñ¶o²HˆsÈÃ6¦¯ÃÙ4½Bu9N˜ûÎè¤B&P§¨Qž¤`÷]âŠÙÀ¢ó^×µ9„BÞ×þ&®‘ÇØQŒûâ¸*f åëýv>‹Âõ±PöŽ^ïOéžIÿ Éñ?þ„mGþú_þ.ŠõïøYÚ¯ý WŸøÿãEsÿjC³ûÑì©U?œúKöE²6~-Ó®Žéuu@çÃcƒ^Cûex]ü3ñÛÄʨV+¹"¾Œª÷uÃ~¢½·önhín<',kˆßX@Œ’£ùÕø(v€ ñ橪Üi˜b?ˆ£ç–k¯;‚ú²}¬ÿ/ó>?#ªÖ`áÒI¯»_Ðø£Çÿkð¸mŒ­ gž;çðÍ}Åû7xš|$ø'sp±ÜɧÉ&p²¨`|™züŒ•ñƱj·Þ¼‰ÆnF=y~uëß°‰äÝhRÈ[ì:Ý¥ü1v_3÷n@÷(¹¯,•ôóGÓf°Væò“_©õÿ‰¿fox“Å·Pi²Ë¡,¨²ùVê=ìHÈSÐWäoÆíJKâ׊¾Í;\Z[ßIeo+ Ç 1†Ç¾Òý¿ñž­ÿ²ø·XÃC¸»ý¨ã‘‡ê~´¯rLÒÒHw¹=I<ŸÔš÷°pµm/éÿÃ#ŠÅV«B4ç+­-ò_ðF`†éSBûwÑÇËQ°^ÝiŒH'Ö½ÃÇø‹xÊÿ:iÈÇN)ˆûÆrsÔŠ˜'ÉÌž›Šr@1JpÄç íëAMààŠi“Î çJwd‡g“øâ•r¹…V%Áû™Ôõ““”aì)ÜGôàd÷ÍDHÆ@ííJÓ'åfµ7vGyåj[)&}M÷è:f—;œûši$’ fOQÚ²rìh—s±øyð¾ëâÌ¢hm` K9\ŒžÃÔãúWÑ~ø¢xyc²»‘üR)·¯°ü:VÇìÅáѾÙ]Ì­×L×*BçŽWð>¶l¬vŒ,q<²‚O,A?NkÉÉ'*˜™Éÿ+üÑö¼gJrºP‚·¼—àÏ$ø‡£jÿ þ)[øßG¹k[ÍfÉ^t|‹‚¿»txÏpF:ñŠç>6üU×þ0 (_ Ûiq1’>ሞsǘI€8çóÍzg• Ã*yŸt«dþC5Ý<‡óIE¾ÚßñVüNŠ9Þ ÚœÒJ×Òßvÿ…Ï òüMÿ=×ÿ¢½§û Oþûßü(¯?û+2ÿŸQû×ùžöÎ þ‚'÷ÈúàEÌ–cÂþ|F25¸¶ã§3ÅvÿðP_¶©¢è÷ˆ‡u­´­‘Üg‘ù\¯Á jsMgªÞÌaÒíîVî\žU`Ù‹3ë]GÆß|R†îÕw\B°´iKÐcæÀþuјbc^²ŠÖßä|]€©Gí®UÆÿæ|o(É¥%>¾EÜ@ò›€;ðkðµs…+îŸÁB|;âøÃ§ÂºŸÙõ>âʳzŽê^2ªYv㌀ká–F 9Æ3ë_W—)·9N6½¿7þgÂc¡ Q„#+µÐ†AïïAäœq@ù#Þ‚sž„}kܤô#Ê ÀNkÐÿgÿ¿Ä/Š=†ÂmmäûmÑ8Ž>qø¶ÑøÖsi+³zQu& ºŸrü=ðýφü¦XÛ=»ºAlOPªXßô®ä%´q+´þéeû§=íP½´&±ÿz 'faÐÖ©´òDŒ˜ÙfåïÏs_'8óI³õØÍB +¡¡ÌfiUd‘øzwÅQ]D0p]‚ m¼ŽØìZ©=éŽÆBw¦Ù6.ÜçwaüëXÖ„;.™3¹G%²@úP g*Œ½â-z+X£mìådËzà÷ÿ=ëļgâéoX™7ç ÔÕ¯xäÄeŠ2&¦Õ@8 ë_8üEøˆÖï6a.û—g˜í=ÔWm894’Ôñ1x¨Ò‰©ªxÆ×\ñe¦ŠŽÙG˜’®áITÈí‘ɯ5ð}ÀºñU‘žëÍoNæ±ínå°™n!}“.H~§‘ƒú[_àâH2#Gn;qü릦ÙFso¢ûÕÿà7C¬ã·üíÿû#ö~×-¦­¥©1ê%ÄöïÃ88B¿ÁÈìkÝÆ¾”ø-ñžÓâ‡&ðoŠ/mâñ lZÂöõÖ!tHàyŠIéÔ{×ÑdÙ½)Æ:ºIlûùzŸÄ5ZUg˜ÒÖ.Ü˪îýîK‘=Þ£*¦Ýœòp¤’Æzžq^®öñÚGfP1€åzW?3ù×k->Œ_^¹‚o±º}“S‰cÞÖ“¯ +»}2C^­©]‹ÛLˆÙe—=Ná£ë_VÓægÃNQqŠON¾EÏ nÕ5Y.¤‰‹@TB‡aë‘õÿ ôKŸ)¾`|ÎA sÏÐýk€ð<Íqg,‰ùÛq`^:ú~UØÁ ,¸RÇn÷m«úšójÅE³Û¦ù”b´¶Äž$²[¢dE.äe”7Qé^kŽÕ¼5 ¹,?Öwü?*讵»m¬^T,‘¶a¸ŽrG<õæ©[ÝyñM<ÂqƒŽœã¿­rÓ”âïtzu)BPQ¬š~ÖÇ3Ÿ%™/ ŽÑu¸õÅgkþmNIõ=5Ôjj˜xÀ”Ž€ûãŒþÛ›Yap128ùËCg¡Àéô¢öÊÆX—b\Ã1e ,d¨á³‚zíÏ·J×£‰¥Ë%¯Brú•²ìJ©JVO~Ö>h—Äͯ¼Ö³éö÷,¬VH¤Pàƒ‘GCPèþ²–áƒÛêº^ ýä2oUöäpk³ñÔú>“â™áÖlRÊòBÒ ÕŒnÀž ã“ÿÖ÷©"±Ò¨\AâY¬Ä62Mp&óåV4Ç,Îðó~Í·>‡îkFt£8m#_^Ý̦×\@õw(§% ¡w¡_hrNu6ƒM˜þöá|hýOe<ãŒëV¼E¥ÞèÚ‰6÷v—ø$ùRþé8?e?ÅH¬Zê7>TuŒœHƒÐƒÛô®Ú8™`ê*”ú}Ça—ÒÍpòÃUÙýé÷^~§ká+ÿ& =9w-Ôñº;²%bÿh©b}6Þ½vˆÑp_8ëê=M|‰à_Šº]÷ÄÈ4-EºXà*¯eV=ÙØ?ÝbqìÀv¯¨¦¿-#Ü’(ÀÁC“\ù†&XÚΪÛúþ¿Érºyv PZ´ÝÚêï¿ÝoMŒŸˆ#i3Ê¿(Q’s’ùÍx.›!½H¬£‘Ö90×W ¯RI쫜œ×qñGÅ£NÓ/JÂV“’¹ŸJñËín=ZѬ4åk]8ª‰²²^È.3ò <„üMo—f”rÈÔœõ“IEwß~ÉhqgÙ#=– CH&Ü¥ÙioVîíø—5BÓÅZ­­’ê¿bÑ4øÞ+kËü!pIfŽ€±Æ<5Ñèú…,]ZßP´Õ.GGšâ7ÿ² â¸‹ktUa´pO\ÔwZ…Û5¥Á<$CqükÉ¡™rÕ•z´ÔäÝî÷ýRò²>º92£‡†7EZßÕž½MÍwO·Ò/åi´Ø¯mgù•Ã263ü,ð¬È×Fœ¹ó¯lä\ H¤Û¸ û‘T!Ð!± ¶r\X~ä/·þùbGéWc³¸$´’År˜çÍ„?ŠãùWØÒâj2Ò¬eòkúù7[‡q Þ—+_wõ÷›Pè6šÏZ¶—bîT˜”cì?úõÔ'ÀÞYÅue¢®¡È …ä3>Ò3ʆÜ;šóßìø¤“ ›9êŒqSÛI-‹+[ÌÑJ‡†Súú׫O3ÃÖþuóÓó±åUËqT~*/å¯ås¯ÿ†rñ¯ý  ÿ¾øÑY?ðŸø“þƒ7ÿ÷ýè®­KþGúùœ_U©ÿ>ßÜÏ¥u OìöéöG ±'™ àt(ô­O ê^Òïî&U–îæ&G÷A ø÷®KL³ûEº%”"bÉ©.£šúî*Ô–¸”rç‘÷c_ŽÎò¼WSïU88¥-Œüi—ã½]c¤“ù¡‡B[“ú“^sñ^ÉM…­êd¸ažüc×ñ¯£j?ÁáMoHšÍC$m¶2]ºî?\šðZ6©¤Ïw팲àzzzWEû:ÉùØ¥íhÉ.§†\ñ3€1ÉàTŒ PjÄšeÅÉy`¶–h£PdhаNܑӥDSã½~‘BJPV?*ÄÅÂVbd‘ƒÈ”Þ¸äÓÈÚ F\ƒNEu³à“œbšxéÇ~iD¬¼qéÍ8…gÆqšmÈ·¯~9Å\IFñû«Ø~þU5äk Ž>ê[,zçù×=¬k1éñf@aÊ“÷±Àü1šñùm±õœýXícSþÎ„Çæ†ÕcÉ8õú~Uä<ø‡æ[´‹ÈH¹ÿµãï‰k5Ì‘A2³üÛ¥‘°¨£©>ŸýjùûÅŸåÔ’[=5Ý!“‰.Xüòzíþè5­:rªù`y8¼li+\ÙñïÄo(½Ž™qæ]6D÷Jr©œ|¨}}ëÌï’sÉ'’iBãœÒÇÒ½Ú4£IYn|mjò­+±Ž>SÖºŸ‡S MZæcÎ-ŠŒVË\€r{WqðóKId¿2åp¨ çÖ¸sª&z™^xšÑŒ­Ò{ÉšÕÂG¾BÞ:{û×yc{rîþl… ù€ééÍzu²Áo)MíŽ8ÍRÔæK+V>Hº*çŠó0T¡RŸ´nÖ;ó(ÔÃÔöiÜ›ágí'âß…—QÛ_ñ‡æ_&çO¾cæ<}>IO*Glävé×ÚtÎ"‚'†ê)8xe\ª#ûãiëÚ¿>ý©+I91Æ9Éí^¹ûë6z_ŇÑîþǪF’ªÍæIy€Úðé_U•ãë*‘¥U·h¯ý|Î2¼4éË¥8êíÕÀÜûÃ@¿_ iÖV±)mNdÜHxIûî'‘ÀïÏa]5¢,ÙžîcutFL²`éÛð¯ÓüW³âÍbòÞ{‰[¹ •(ê€íPTò …z%ް²"þð²ã±éÅxÙÅz¸‰J7Ñt?Hᜫ„í¯RJí½õè»|íRÕ.m[;Y¢‘ý+Â~ Ûëš­dþñ¡áäy H–Å%ˆðq˜¤HÏÓ­{Jj×¶ûYg¦æÃ?úÕæþ:ÓþÛuo e|I¹Xs»œW•NT±”ã}ä¯ésë3|419f"3WjkMšNÍŽŸñ⎓*G.£áýrW̾Ód¶pxêab=ñ_Jê¢øßãI¡Íàý IÿY·/–}˜·ø÷渋(Æù6¤“”s€xëZÍ<7&! +G«6່°5û‹ÂQZÅ?ÄþCxúéê×ÝþV.|sƒHøÕð¦÷UÑ 68ðý¼— §Ü¹3í\3§Ê@” V\§Jüù¹øƒâ»Û¸'þ׺WÄl Ïb}ó¡kVÖ3ÓnÒE‰-‹Üù͆Rˆ¬Ò©ÈÁCŸ\WÇ‘ÙYj3ë—©h–žx’æ#, È(ö Hü~uÄTiàëÂQÞKoN¿?Ðýw„1•ñØj¨Ý Õ¾wÓåoÄætïø®9üÉõ›‰Éê.™ŸÎ©ø»ÄºÆ¼.ïDýXGãŠßš>T${A<äsT®to1Õ1‘“ÆE|‚Ä6îö?Eöw-ΧöV·x|u=Þ2±Ga‡PÌßýjý°¶–òÔHw0qžGÝü+óßà–³‡ãÈôéEö»ˆ¼²Nq¯5úKáø`K[H·.öÀoÓßé^ššpS:ðQöqpÜðß‹^žëMº„—BQˆ={gò¯Ÿt»ù#ÌN7Î ¿b8?¨¯·|_¦ÛÝ$‘±ó|°CôüsO^ÕòÇÅ¿ŸÞ bÅwÛJÁgSÕ<óõ¯;OÚ%R£×£?bí²f]´ÛÔe°qÕy¶•ʱ9=‘¢Ê³F»0sÁ&¶„eaÚÈÙÎ}}q\±lôô’ºw*´ŽøÉÇ9Î9¤ó(ù‹öÀ­7²5Ú€JAÆ«€¬Ã¨Æã[óÈîfïèªXƒÜELŽG# GlÕÓo½†±©UÌpIïŽ)ótAìÞí”þÑ7üò˜¢´ÿqêß÷ÒÑSÍäËö~gÑŸÚK§é6bw©KüLGò×xc@M Ô¼² ¯gç”w?ݰþøyâÆ­¨m–å$ ¸"$1îGZí™CÈ ŒçŽ gRiɤ|Œ¶±áµŸ†Eÿ€ÅôHD¶R¬™=qÐþ‡ô¯‹^RñùYÚH+Éõ¯Ò_ˆÚü$~ Öl]G–öÎ3Ô/ÊFs_›÷O –-¹¢m¤zqý+ʨ­;¾§¥IóÒK¶‡œø~þ_Üx–ÄÉå¥Í”Ñ‘Û nýEq €‡åÁ®¿âM±µ×šDVhÁqþx®ENc=«îò×ÏOÚw±ùÆjœ*ªoeq»3J“Ç^¦šÏ°÷§òxƽ{G†Æ¼yúÓž‡§lÔÀç“×Ö˜ËÜŠ.4ú¨9Z<•É9ö§)È9ã¾MFÄ|§‘ìM‹Pù7nmÝ6·@h2á'ø±ý*¤ Ï pük§Ñ<¯x†æ8¬4ɦ€VB6¦C¸ñŠW±<»%sœU ŒuîM}kû1þÊfý¬ü_ã‹B–YØi¦cÁY&“¸^ýøëÔ|ý—t ˳â‹ZÖÓl‘D@k[cêøØzž¥}5öï´ ó¢å1É$šä«U%hŸCƒË$ß´¬¾_æT¹ƒ÷Ø”×®pONüVUÅÉ€ÈG Ï ß0zúfAl{c§5åÞ9ñ¼vR=ªÅJrý8ý+ÍjûV½Å¨ÿxÎ=H,gï3„zc·JùÛâ‡Æ³1!óvñc¦Gá\ÇÄ¿RI4¶6 .'S‡ýÅ=}~Ÿx¥ÕÜ×÷/=Ô¯<ÎrÎç&´¥‡uuÙ31P÷)î_ÖüIw¯9±Krså)áˆè[ÔÖVAúRî#”Lƒ^´)Æœyb´>bsuä¯qïHy”ž˜é@98ÅhA, ^dŽ{q^…àc¼W`£å¥qžã¯Ö¸/:ô0O­z'…md‹MWS{±ËÉÿ ù<Ú¢w¡÷ü;K–Õ=Ëõ;!ƒ+"«2ãpÊÿZ]³V‰AVÛëŽ*ÞvÑ8è2:Á­~«wÞ¯o_­e€ª•ÑÌð¾Þ¢ižm¬È ˆÅÁÇ'µbxc_¿ðG‰´Í{K˜Á©i·)s‡ø][ b2Ö» sJ/+”p1ü gÆßÚì z ½húËu/±áK-q‡,ã£>äÔüw®íþ!èQÄ4BÚ¾KbØnqµ’E¯Ì1“Ç*{×I/‰¼Ï<ð|±æ?=ONµùùáéµÝˤêw:T¦&GšÞB›ÐðQ‡FЂ+Ø> |\Ô5-R? k2´±^•Xo™pW$8ÃùשˆÄÓÅ>e7¿fû®Å䱫ŠÃN\Ñ_ ê—gÞÝà}£àû!{eŌӗ%‡Uñ…ävz…½ºŽ@ß’9R§ï~u.ÛÛ=6ƶ¶»Ž•¯U÷¤‘ŽÄsÈ®OÄ"‚íp³G}¨ÍÃI*v@>¤×/Õa»ÜýU¹U·îqþ/†êÙRù5ŠÒåȉc¶–g©R±«`@j̰Ónîeã°ñ&²[¶ÚSÇ´çšR£w z΃áë«o 1ŠW$©èz‘ô¯\ðnŸqªøvØô„’G/ ! ]éÁÈQÖ¾—ýbÄáé%Q]÷VüoþGãŸàWˆÃ¶ Þ±ogååó>TÖ>üXñÕ´ÚváHü5£Ý0’u¼Õ Iné¿,6©êQF3×8©tÿØ⌱™.N…c“q©)Àÿ€ƒÅ}W§\ø®=Fæ Ÿ%¼1' Uô8î1ÔWa¡ø§[µÓE—‰¬ìMÄ› ½·ù¢‰sò«žÝ°ý«â±øŠ¸ªÞÚ£¼ŸþZX÷ð©åÔ>­†„TW­ßžú¿ÄøæÇþ Ýâ«Ù”\ø»ÃP;s²%™±ìŠùßã?à sà·‰fмCdð¸Ë[ÝD¤Åui#nãÛ¨èkõ#ÄžÖí/c™­b›Mf˜w,,3Ô‚=ûƒLñ·ü9ñËÂ’øKÆ–áß­¥ú¨Y — ‡³{tn†¼¹4ík~'­ G,¯7x¾Ý?ÏÌücÓuHô~ÓU¹{;„›v ¯Òß„þ'²ñ/†-ZÞ8oMÈÁšVÈŽØé_&|jýšu‚>#“KÖaš}É?aÔâ\Er€ÿã¬3ÊžGÒ¹/øƒÆ õÃZŸ“e +%¥Ðß {ØûŠê¥Š¥/r{M‡ÃNœ}¤=èË·æ}Ó.£%½“ßG5ݽÒE+ÃÈŒHîyã9>Ù¬/h¶æ•wi,*ëróY°#æÀ’L÷Ûëé_x‹Å~;ÕuÙï__º¶¼y‘,¥ò£L Ð×BÞ5ñÆ©¢i–ZŠnžÒÞ&bˆˆÛŸ¼Y‡,NNIë]J½«£j“•[©Sµº–ìÛË$~h"7+¸zƒŠéìµ9vU™zýk‘Ò¡eUÃ…OZé-LÀ²ê®XÉZÌä¥ ÇTΊÚñˆ\¦:‘Ívø}âo‰SÃáÍ]KÉ M"2¤qç¡gb¯;k™ÀÆâØOSÇJÞð'ÇÝSà'Œ,5»t’ëL“÷z…˜8ç‘χU>¾ÄÐÚêvU«R›§¬—s×Oì¥ñ9²?°íÔäòÚ„8þuÜx#öHûF’çÆSßè:§ÚZ8ã´–âhö‚®<çp ú úƒÁ^2Ðþ$øWLñ‡oÓSÒ5„ÐMQê¬:†SÁ¡Š­®d&¶‰KG…óðοĸ#¸éMÊJ-n|\ã(ÛH¿%þmžÿ _¢ÐÉ©ÿ߈è¯kÿ…áú ä'ÿ +¯ê•»~ð;û_üïî_äx†…3ý†Ú/º˜äç·ùþUÖE 2*« áGÞ5Åé£2 „ã; wÏ­?ƾ9´ðFŠógÏ»a¶W;™ÏAïšÒ®]¹Wæj(ÊøÍãµÐt™4->DKë¸ÛΔœù1ã ÇúZøÄ›-/®’0á7îºOSõ¯wñ.«s­_\}®fžáØI}2ò íû/ó¯ø…iåjM+)ÚÜ8vü±\ª”âüÏK;7ywÄK_´h–·@èØ?OòEyºòOç^Ë©Ú SÃ÷Q¿Íòüƒ¿ùé^2c(@<ë^æK;ÂPì|¦}NÓŒû‰·±Î)qÏ|öÏZVËGäi¹×®x¯§>P]Äòy¦’I8¥‘ǾhÁJ4àŽ[ò¡ÀÎ(ä¼R²8V Çjc´“éŽõèŸ þ(·„™,µ,Ú~s‘òÖç<ñÝ}»WäŠ7ÓŒÔN jÌè£Vtd§ô'áßÄ+{í6+ˆ%[›Y䙕ݴÚUÀòœæ[I×t2}Gcî0kØWö¸g² '†ØO·Šï“ÿ|äW©[¡ô´³HÊ>ò³>ˆøñb=&ÎæâêT²T–‘ßxéþ}kä/‰?.¼R^ÏL2[Z‡¸sûÉ3éýÑú×-㿈ڷ®•ï™`µŒæ+HIاԓËs\« ôÏêáAo#ÍÄæ©îÁÙ zžýé9¤Ç<õ£¡ï]–±ã‹‘Ïõ¤¥žs@ÏÐ:p(Ǹ$€9'°®ŽÇÂ’”ŽK‚ ŒÞõ¤)ʦ‘F+BмØÏ @1Ï?^§áûº=˜0>RóžçŸë\ƒ‹N•¸ #>ôäWªø3^ÓïtÈU$U¸Ž5Y!cÈ8Çã_žfr”êI­®~¯‘¨Âœ"Ý›Am¦M¹Fàg#=»ÖÌ:\›F#p}1CßÛïu·g©è?Î*Í®¥ç<rá*%£=êôbÝÌ[½µÃŸ)ÜÐŽÕ›sáº*ÒZlÏñgé]q»_1É#à`æ¯I=»Ä¤¨f#tª¢ç'$ÄÕ>Uyˆü2Ö‹¤l!TçÕÏ‚:i‹âŽ‘þç¦$&>î6ï]^ éq»z—Q‘ŸZâµË×Ò/ ¾Óf’Îê Ѭ¬:YÓÄÉV´—S)àhÒ‚©}­>«o¤E0‹OžÅÔ+¥Æà‘¹ÉÀçó¬m íÒôK*G ÄÝ” «Üâ¾P?´§‰Þ*îu ÆšbpqÓrŽÃÒ³ì¾"ø·ÄW=ƱjH9 ­ØŠý9ýš?h¨¾2i¥jM§¬"â¡þ!ÿ-£÷—±ç¡ãÍ©‰Ž&.6±Ç˜á«Ñ ¦—¹}{ÿÃLï¯`¶ÑŠÛ,sKœ`Œ|ÏCšÃ]-`žâ1e>KÛÉÈ ôÉÆ¡ï^¥wg©dѱxÁä2ðÈ}k‡×|7®ÜB«”ºhI²îYWÐú„ Šò嫱óT仚>–{h„ö¤é»v gg·^•¾ú-¬2ª x¤ÈÎÖùŽ?\/‡ìuD#ŸÃs¤”…Ú¿Œþ~"½KµxàòçRU>æHbqMG_x‰¾Yy^g-ñáæñ#ÃWZN½f—VR`Ýáê¬=‘_|Wø!{ðw^6÷P5æ“>ZÎÿÊdÝoî¸ã#ñWé<¶¨PîÞAS·#?γ|Yà­+Ǻ%Ö«Ù}¦Êå0K}ô=˜Ì:ƒJtùµŽç»–fÒËåikºíæ¿­OÉ‹û{Xä2 tÝxQœþ\S"H¦>Bë°W ü|øU«üñ{é:œ~m„àËax u?£@#ükÍ`ÖbÀS^:Vt4›Lýµzu鯤âúš¶–À¾룚نÑÝîÕ{ð+ =aH°PÃ'=Eié– ÔýÕ9Èö®™„\l_KIwVnÄ VO‹4FÕt©WÉù“æÀç·8­EÔVó1 ¼üÕ^}u$F ‘ØŸj‰EÍ4_4#¹¯û|bñWÂ_ˆ:Ÿ…¢±}cÂ÷Ñ=ýÕš7ïmÚ0–ðX‚OâÀî+ôgMñ}‡Ä/ï êP\E'ÊehË4L:«¡ÁVÁ¯Œÿa¿‡öþ'ñ—Žu)“)i§Åkä4’?¤­zõíµ÷¼Uý­¤Mig«T¸µ–r‘j1öŽQ·‚…ú‚{Šö0¸Xã(FÎÕ㮟‘ù^q8aq³QWŽŸ•õ;ÿøTgþ{Ùàÿ⨬øh]{þ‰Õ—þ±ñW_ÔñÇ‹õØyä¥k˜­´Ûk‹¹@·²w³d cÖ¾Røƒãy<[â)µ8òF`Óbô\á¥>þ•Ù|wø¢u™çÐlç ¥Ú實Cç´kõ¯ ²ˆÈ“\ÈBÊÊBqµð¯¸ý¬0ôä—4÷g¿C èâò¢Úà§''ýcrsŸÀŠã~#Øy¶BP¤•9B+µm ¹ƒÓ?üP÷Õ`x®Ü\iÎ8çŽãàGåWЧÍFQGVvª›<~ÏkH¨ü¬­°î1^Iâ[¥k—vÇ¢¶TûkÖ"+§' «g­qtó±èæ;ˆÇà¸2м˜žWö‘ËžRçÃ)ÿ+ÿ€pç¯Ö‚ppyíI ÚÃ4ÐÙ8'ñ¯¹> úœã&ÙÎzRoóÉ¥â€è1øR»Ž˜éïLϱ=¨9ÏJaÄ€N:ûÑ@ÍEƒÿë¥è)ŽÃ‰\y£ŽËF? 0§½'OlRà‚yúQŒõüéÁr=F:ô€inÙÏ­4±zÓ€3ÛÒ¬YiÓ_¾Ø×8-ÐÆœS“²”b®ÊÊ œ($žÂ¯[iFfýôžRöùKùWKc¡¥ž6(vÆKMh}Š;Tãø@ÇÌ}«Ð†ï#É©IÚVŸ ÚYÏæ~òå”dO—ëŠÚ®ûXžŽ¸þµUÔHÅ\0¤Ó¾È0Ü`tÏN+¾1äVŠ<Ê’uç-Nf-Ná<’‚§‚ry«pϲ‰b k8볡úzV-嵯tèÙ“•$p¦ƒVˆ‘æ!C܃šøNp“´OÓp˜øºqMÝ[3·ÓüQ«Z(O0L£®ó¸ÿoÙüA’"k~€ŒúלÛÞÛ Ì¥ùêqδmµ •ÀŽ`@û¸n•áO“¿-ŸÜ}=}Õ¹Ú_&zm¯Äm=×÷ÆðÿíÝmÿµœº§ƒ5 mP-×Ù.¢ŽÙÜud,wx8#ŒÖ\ßðP™]ȵøx¼œ~ÿZ\þJ‡ŠùiÞÎxźÛhêÀœí× sî=+OIðƒJþdf™3¶réâ(~nÝÓõŒ+zÔKäÿùæÞKJ/ýÞOçÿÛ#Þ¯¿o3²x'B·ÉàÍy<œþ +Uý¶~+]l`ð¶–2¶Ìßøô˜®;Eøo¨ÈãÏÑ™#o‘®Ùò?õÖé¿‹‚nü5«‚BëY0öÁÝRñHÿËØýí~ˆµ—á µ ×­Ÿç&s—_µgÆEÛwbµcm†xú ¬SñÏâ¥öásñ'ÅÏ" b„ûå+Õìþ é;•¥ðÇŠäPtK»>½È!ëJçà…8ÊøgÇ‘NrIW´pzðpøZÊX¬;ÑUÞÿÈÖ4ðt÷Ãþÿ3æêúNj×5­WY¹E*$ÔîL쀞‹žt< æE“,`y[×8 Îq_^]üð´·9]Ƕð\§‘lü㟛wôª·?³ß…Zé§øý"ÛÄb¶,Þ®W: |ÞÖ?{ÿ#ÓXÚ* §$—’ÿ3å+X¤VÈ‹†ç5¿§Û£ ’) y\t¯mo€úÛñ™ñ`ä©:M¾3õßÒ¤´øA¦1ŸIñ¼+œ(]&,ãÔüÕÐêÑòò?x¡‰‚û2ûº´ *—e›#9jrZe$Hî¯[Õ¾Ù[•6¶-f¬ÚBŒûê©[ü<ÓâC$Ñø–#ƒ•þËQŽ;óëG´§o}æþÖ-ÝF_s øOûGê_­u+M7Á–ºäZ¤é-ÕÃÞ5»FJ…)ÏRsï]Ƴû\øXž+½_Àš´7,öµ¹‰¹ÿŸjóÝOÁº0ŒŸÛ§# 8†^kƒ×|9¡ ú}^ n‚G³ÃÖºð¸Ïa.hÍ}烘å|mê8K™ÿ‰×ÿ Að‹þ…/ä·ÿE|áÿÿ€?èdÖ?ðŠõ¶«:û×ù+þ®SþG÷ËüÍë‡7—Ú)7Ãy¹žSÕ‰ïíZª«É\÷'O\þ*AXè¨XˆÏFUN‡'ªŸÌÖÛáä-È9sÿ}ý˜}kѵ·3ƒ¾¨®ß6A;²pNqÏOþ$þuCPQ5¤«ÝÇåŸþ(~zB_»ýïÃÿ¾OéU'<ÇæçŒwÿõƒùÖM]XéNÚž'«@`½UI;³ôæ²|a¤[·.9žÐy‹ëŒóýk­ñe·ÙõW œ2çÿ¯Tô¢'™íæÁYãdÁ÷ñ±”¨VN;ÅžôéF½)B[I?²–ÇÖ£Ç~qWµ[#§êwv§ ÄåGGoÒ©p½«ôÊsSŠ’ÙŸ“N.œœèB£ ëŸÊ‚xÇU6zmã'šÐ‘Üò0}0€O4â (¨é@„ ž†šN8#֕ϨïArÃû«@ÆcwZxn@ÞõÔ‡‘×ð còN¥ù8SÉÇJê¼)áOí|ûÅ+à„a÷þ¾Õ¥:n¤¹baZ´0ðçžÆ^‹áËUÕxí‡WÇ_a]œl6°ˆ!"ûg>¦µ¡ŒFÄ Š£î•è1Ø{RÅlÓ»eŽIþ p;×µFŒií¹òØŒl뻽)A *4‡Jtã’j—ryޏ`8Rzñ­¨–BK”p´‹•#9=s]"©×©P[n{}©ZŒ±èsW¼µ]œn>ã€)òCòYsŽüP/hb]Ú$Ñùr*ȇø[¥a\xBÞ^aw„÷nQþص»?o½Dö¨{m_Ry?…e:PŸÄŽªX©Òø?›ÂwŠ@ˆ¤Ã¶äk×¾ |;Óuk’ëyk¸®Õb}åYW`<`ôÎkìy9O¡>ßçê ’H<+«# î¹\à²?¾g;ÞÎ7½Ñ÷|/Œ–'1*‰5gùò|ÒnRO.æòØrF$W ÏE`j?&ƒZë;ò2Ðã¨5ëvƒzç .pç<Ö}Ê“r#2`cŒzüïÛÎ=O×¥‚¡%ðžeeðãÅ¥6Zjp:qÇœSVºøoã›4wû(œŽwGp¬Oë^¹£CåÈØ9P ã½n¥ãd àõéÅT+É«´ˆ–“[³åI[ÄNòK¦ê1‘ÔùÈU‹?ÞY`OÖàIu¯k‚êyce«&pB’0z‘ÅZ2F2Žp[œ×5:‹á<(aêR~ìÿø'‘迬üß/SŒ´{†I'ÖâøïÁe":¤¤º²¬‘° {`ö®öi¡ #Eo¹—%ŒKŸ¯"«6“¤Î˜¸Ó­®: $(2}Î?ȬÔi)^}ßäu§ˆQq“Nýïþgoã<ÊòéPIÆ7.}ú×O£|Jøk ²ÜèeCc5F*I¼1¡]]:-‰]¤äŒd}:œUiþø~çå]Û,xdLq]?X…µWÿ·bÿC“ØW‹¼_þM%úÖ‡ãï„7ÊŸh±Ô-Ù[k4zÛ&Aú©®çBñÁø„4}@ñ 7¦>+ÁGÂï±"M!ãœ3ŸÎ«Ëð›Ãñ9WÓŸ Ÿ»#VR•7¯*ÿÀ"n¥ˆŠÕ¿ü4})ÿ §Àé$Eaã·pß_¶qœúÑÛkŸ®’-ºßŽQ€ä6­jyú×É ðÃ2&ãk2dgh™²*)þxhe‚៴²~Êû/ü{\Jë/ü/ò>Å“[øA‚ÄÞ;€’¶Z¿þÍYÚµÏÃm¼iãÈÃgk#Ú·'×çòøU¡Føhï×ùø#Ê¢ÿ…Q£¸;Mösœùäøã›Tv²ÿÀKŠZÞ_øÿ#êË=WÁV·7òxÏÇ " Û9>¡‡™Ç×5›k®ø~âö¾:ñc—8ÅÄq‚¾%¯—Ç­&QÄš‰ÆrLàtôâ£o…zb ÿM¿ zm˜…G&|Ià?ðKúî2ú9àð§µÍ_NµŠIuË€ª0 õ/Ú²àÖ,g€H¾)Õ1ϘPøï¯šÏÂëbÞ_Ú¯ØcŒJ9ý(…ÖŠ2.u@ù€cùSqÃj¬¿ðø ±ØÔþ×þ¿ÈúR]^Éíøñ þÕY×'ÛïW9qsg!lëWRÇž7•ãó5áÿð­´Á÷Z#sŸÊü5Ó"EÞ N8Ý(Çò©qÂîí÷Á+ëØÇ¥Ÿþÿ÷±éÿóüßšÿâðªì¿çîïþÿõ¨¥ËCËÿægõ¬Gò?ü þïÖ, {mS€3ü œÉÇênÎKUŽÏ©äÁuÿþ\ü6ÕôÙ’ÂæÏBÕì⺳’y|Òä¨üÀ Û$Úz G¥r,0x,9ÉèO_É€üëì*-u>Z‡»? gØÈ‘?•U!A=rôùUÆù›+‘˜?~{‡ãU¥PzäŒÿ>˜¬Ø:ñý¨°Íƒ´¹Ç¯A\½¡dÔ­xçpý+¿ñÅ·™¦™û¹==ÿýuçi!&9PŒìzæ¾GZòó=úôÑÁü^Ò ‡‰„àa.⎠é\)ƒØ×¯|fŒ^iZuÊÆA·‘‘›ùXqøgypqœý+ìòª¾Ó -Ïsz^Ç?=~ò2yáÇ'ÚžpE*ñ’8ü+Ø‹Ut=„™VuVuã¥]‹J½’ "Œ£É†# ŽpqúŠÒ+k!7dîy¤­k f22åq‚}*ë_yà4lê<úúúó9ifh%ðqŒÒ¨5üˆû¼¹¥‘°~çÖ…¹™—ìÙ™dL1ºòÇÏÏLU}Aÿ:'ûb›_ù¦+%™k‚\ôàd¨¬ÿ+ϸm³CÛiª_Û34o:ÇsQåM¨_šOCMœÊÁŠÍ7œFÌ'úŽ;úаÝÍ ç0i~íöl_óÜß þ4W7æêŸôŸþüÑKêùÿµáÿ>ŸÞÔÛ{þI·Ã¿¡ÿÒHëäáoøóZ(¯¯—ñçÑþÿëãÿ¡Õ÷üö4Q\§jÝœçŽ?ä?ãýkËáê~£úQE|¾?øÏÐöp¿Â ø™ÿ"TÿUþk^"ÿëVŠ+è²?àK×ôGÉqûÌ}?V(ûÆ“»QE} >\Uûæ®YÇÄ_éEqø‘•M˜ËÿõÑý*_¨¢Š'»* ,ÙÇô_õÑz¬?ò_ú䘢Šõ°;?Sç³MãèÿA4Ïøú›êjÌßò›þ»åEê-ÿ|_¹ûŸû)®¢óþ=®¿ëŠÿ*(­cñµ6G:×Üÿ¾•cNþ/©þtQZ-¿®ä½„ñÜ?‡ò¬—ÿ­#ýÏñ¢Š‰üF´¾ó'ò¸ÿtÿ:«}ÿ²þ?Ί+9ìiò5ÇÝÿ×aðïþ=5OúéWÏqû„½Qöœÿ#¨zKò:èßîÿgÃÿ2×3üÍWä‘ÙÑosgFûãè¿ÈV†ŸÒãýÓüUSø—©3ø$xUçúþàþf²%êŸ_éEûŒÏäxuõ+õP}i·?v?÷ÿŠ([£eñÏ÷$ÿy¿­y·Š¿ä8ëšÿ*(®<_ðþg­•ÿúÿÀ>”ŸÂ¿Z(¯ú•°§ï ïüÿ 4ÿ®ü袼¼Ëø&ô>4u¨ü©{¯ô¢Šùèmò=W¹/ü¶o÷Gô« üïÿJ(«‡ðþh§ñ :Çù "ÿ]øŸëE¢ø™e “ï÷¿¥X±ÿRë‹ÿ*(¨[‡ÙDQEj#ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/06member_t.jpg000640 001751 001751 00000002031 10546014105 022113 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄ5 57s²TVtu’–±³ÑÓ1A!3Qa‘ÿÄÿÄÿÚ ?¶ÌŸ;DÅÒPê:R˜ª""ˆdD[OýŒÙnö‘XSµÑ²’ÔOÚ56°â4ÄÚ[Æj#?çoø!¢æ˜›ÍeñÈט̂ìP½T*¼žy­­“/~žkCëdËÄŸ>AçšÐúÙ2ñ'à9æ´>¶L¼IøàAçšÐúÙ2ñ'à9æ´>¶L¼Iøà¬nÛ\ÔÕ<º¨TúvñêšÅfPN"ö Dã{fÍŸÔÿÂ*òo2mCÔQÛL^A \ápâCޤ© (J222=¤deù›¤a•–³"±h™S÷[¯ibÅŽ®i‰¼Ö_ŒyŒÈ.Å ÕC\Í17šËâ1‘¯1™Ø¡z¨ @ºFYk0ár+‰—õ?uºö–$÷HÃ+-f.EbÑ2þ§î·^ÒÅ‹\Óy¬¾#ó]Šª†¹šbo5—Äc#^c2 ±BõP @€ tŒ2²ÖaÂäV-/ê~ëuí,IVZÌ8\ŠÅ¢eýOÝn½¥‹:¹¦&óY|F25æ3 »/U s4ÄÞk/ˆÆF¼Ædb…ê €6éee¬Ã…ȬZ&_ÔýÖëÚX“Ý# ¬µ˜p¹‹DËúŸºÝ{K,usLMæ²øŒdkÌfAv(^ªr{XSM§sj)4ðœDDHqÂJ¢Q‘‘‘«iègkn”*«¬Ó2Íi×,ͬ8{êž²„{ÄjÚ[«ŠGû/Ш¯s~™MùŽ]÷‡ æý2›ó»ï ¯s~™MùŽ]÷‡ æý2›ó»ïÊêù7é”ߘåßxroÓ)¿1˾ð+¤a•–³"±h™S÷[¯ibWwÂiE˪TÔ³ºy¢žEhp ¦‘d‚½ýq³fú;?#·¯+ iÍQ@mQI£G‹.pˆpὄ¥-G DDDJÚfgú,ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/20member_t.jpg000640 001751 001751 00000002031 10546014105 022107 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿÛC   %# , #&')*)-0-(0%()(ÿÛC   (((((((((((((((((((((((((((((((((((((((((((((((((((ÿÀPP"ÿÄÿÄ5 57s²TVtu’–±³ÑÓ1A!3Qa‘ÿÄÿÄÿÚ ?¶ÌŸ;DÅÒPê:R˜ª""ˆdD[OýŒÙnö‘XSµÑ²’ÔOÚ56°â4ÄÚ[Æj#?çoø!¢æ˜›ÍeñÈט̂ìP½T*¼žy­­“/~žkCëdËÄŸ>AçšÐúÙ2ñ'à9æ´>¶L¼IøàAçšÐúÙ2ñ'à9æ´>¶L¼Iøà¬nÛ\ÔÕ<º¨TúvñêšÅfPN"ö Dã{fÍŸÔÿÂ*òo2mCÔQÛL^A \ápâCޤ© (J222=¤deù›¤a•–³"±h™S÷[¯ibÅŽ®i‰¼Ö_ŒyŒÈ.Å ÕC\Í17šËâ1‘¯1™Ø¡z¨ @ºFYk0ár+‰—õ?uºö–$÷HÃ+-f.EbÑ2þ§î·^ÒÅ‹\Óy¬¾#ó]Šª†¹šbo5—Äc#^c2 ±BõP @€ tŒ2²ÖaÂäV-/ê~ëuí,IVZÌ8\ŠÅ¢eýOÝn½¥‹:¹¦&óY|F25æ3 »/U s4ÄÞk/ˆÆF¼Ædb…ê €6éee¬Ã…ȬZ&_ÔýÖëÚX“Ý# ¬µ˜p¹‹DËúŸºÝ{K,usLMæ²øŒdkÌfAv(^ªr{XSM§sj)4ðœDDHqÂJ¢Q‘‘‘«iègkn”*«¬Ó2Íi×,ͬ8{êž²„{ÄjÚ[«ŠGû/Ш¯s~™MùŽ]÷‡ æý2›ó»ï ¯s~™MùŽ]÷‡ æý2›ó»ïÊêù7é”ߘåßxroÓ)¿1˾ð+¤a•–³"±h™S÷[¯ibWwÂiE˪TÔ³ºy¢žEhp ¦‘d‚½ýq³fú;?#·¯+ iÍQ@mQI£G‹.pˆpὄ¥-G DDDJÚfgú,ÿÙprivoxy-3.0.21-stable/./doc/webserver/team/05david_t.jpg000640 001751 001751 00000007556 10546014105 021753 0ustar00fkfk000000 000000 ÿØÿàJFIFÿÛC     ÿÛC   ÿÀPP"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?õhufÖ¾"éú„I$¶þDÈn  •CŒ·9àô'§5캸¶¸p'jñí9µyÚÚæê&ÚSzù¸_˜§%A$žOð±úWªxfbl. ?7Ÿ§¾]>zŠçÔTŠ…'cª·¸;€ïé_3øÿþ #à? xÂçÃZâûëYZ§±*–åÔá–7 —ÁÈÜ8àžµ×~Ô~,Õ¼-ðÅ—ʺíä ¦ißgÿXn.$XT'ûXfÁíŒö¯†eÿiþð–³âŸiì“›†³>pù£ ÃIïžÝk¡áÔ•Û3ÂCÛUQkÝê}ñð‡ö¬ð·Å¹œÜèz©cØê{UÀÉT`pN9Ç«Øm/ÛxÈã>µð|×z~y4¶²žól–3Λ%‘¶èÈ-ÎàÜpNAÆy¯¸-GŽ6~¨-Æ9Ç?­s*n Ægnc†¥ABt^’è|éû8x›EÒþ$|t°Õõí;CZ˜X_Pž8ÃbyÉ»ÝFG½{†¡ãxwÀ>(M?ÆÚ%ã6‘s½¬Wn.QÈÆ’I8Àë±ßÃßkWúµìæöþáîge»`¥Ü’ÄÃ4Ëoسáżrm†ÿ Û›¦àþuë9`åYV”Ýý˜„±p¤è%î¶yƽpÒÁ>‡''juÿ§Ó]õýŸÃßx3ÁI¨üEдél4K['ûB$rˆ—æÎðASTŒz×ysðGÃW? áë¥ÁЃ`JD„‰|ß½œýã^g7ì5ðÊFÁ¶¾ç¿Úßük,>"„åoy½»ªô楧¥ŽcWñ\³µ”rÜódËN7’`dûë^µàýTG§]‰£–,\,`ºmŠ8Éö®Â_ ç·†9î${fD]ÒLÀΊ!‡)äá0=ãäÿ>&x#Ãz̰_k=¾›Z<±(Ä›HËȸG#9ç£{U³ÜªÜ¨»ž™û\x£MÓ~C6¬šp¶×tÛˆ¦böŽåK(ù°¤“Ž€Ú¼ßKñ$0øzî[‹hî`ºb¾^ì"–çy>œç>‚¿?¾,|MÔ~)ø¢]Fì˜l¢ÌvvjÈ#Ï`8Üx,{ñØ ôM:ü9væôB¹´~bŠ9> t>ƒ…{¿Vå3g2*žË£{ŸPXi>½ãŸ hwš{/Ø. ž…‡”ÆYÜ`AÆJ÷ÇöÈñN›цKØ£œHc1»€Áó÷pO_nµøíãÿˆº¤_­­-í¯4‹Dh¯?¼™ÙCG)ÚàüO¾°øQðâÃÄz}ŒÚþ¹$z…Òï‡æÚ×Cã;ÀêxúžkÇÄÓ¨áèðù…NYÊÊ:]#ï(oD,‚GEêÊ„Î9Àõâœ×¸F;dÚ¬Q›Ël'sÛ­|…¦x‹OÆ­¡/ˆí­4ÈV‘†ù>mØÞ  8 ö ®+Zø×ðóáÍÌÕ¼jó̲ó+¤Ïl<܆ÑÑ“žÊœÖPÃsÚúöò.Èó"´ºXä(HS—ýÅÎå;¹Ï­oh·Zm¶‚šcøÒÊÿ7Ïvž}øŒ3ÈbÀY›=zƒŒt­ã„´9›Ô唹ª(ÅéÜóÝ?ö»¶ÓíIñu®¡®(–-Ú8âÕ_ª½ÙêxÚpRFH< ø¿ã×ÄýWâ_îoõ P+;N- ]ÄïËm_ Q“ÉÅ}%ð“ö|³øýâ-WÍ×C¹µŽÔ›DŒ29eb9ìPö={WÉÿ|?†>&ø·F‚C$n«se“ËŒ€þKU–Ñœª©Ïd´:s|FR¢½æÕý7ÐåˆýØ'Œô©4­N]V´Ô PÒÛJ³"±À%N@>ÜsOdäUT¼ Ý }L•‰§&Ñô?í;­èŸþx³áæ¦Ú•­÷‡­o-„ê¦æ ÖyÔÃ*'‘†Í½Â޽OÔ?¼K®\|)Ž=gMÃþ'ˆ;Çk©ÛIªœíØ0Ì¡•ý qŸðO„zg‡,ÏÄÜÙÉwªÄÖúEƒF²ÉI.^|•%£ `pªyŠúîi‡ö„ò °G6^#(PKx$ò<rkÇÆJ”!n§×äßY•W6½×»{>ÚŸéú¯ˆ¯4ÆÓôÔŒÏÛ‘h’ÞJScŸœƒÁ?¥~wüiøuâÿøßZø‘ã[amŠnMÍ”qÝ#¼Gîá“hù"T\c¨=Áú#m¯ëÒÏ<+~%8dEº„`F`[Ó85ç~YüCðçö6‹e¬DÑ´š•ija Ãs$qÈÊrxä’+SU /MÑ–u‰ÁSrs¬œÞÉ5£]Ï̹>O«øïHð¦’Íy©jwZÆŒÚò>Õä{“é_´º†£¥ü&øQ¦hÖÖ®l´Ë;}" ±ÊÊb%r$·#8ïê+óƒPøãÿÙ‡â\_n¥Ð5 .ȉ¡ÕÚGò#yaÚ†á(V$ÆãÎÓaoüGñ&½gmâ©à¶k¥‘¬ÌÞT}r¬„`N8cÝâá5î¨ÞÇ‘„F£:Qçêõ·Èò={á7ˆüMñ#úo†næÓõéôÔÔ´é#”Å#3¨}¨À‚Ä~Sô¯˜`À™‰dƒ?¡vç¹'Ð׫^£„–ç‚êõãN[uô=göðGŠ4/YGâ›Ñ¤ZØDÈ‘ZLUÞ=Å”Hã # yã>þ¹áŸÜxç^–çNº–[Rm⸜å]ð7w¿rN95ò¯í ûL©†ørád“;f¹ŒåSÔZoÀŽðãGÑ4ífÊY´™çYÚòâg?6õ'çN‡9ÈÇ~•Ç€PöÊx¾»Ös^­<+¡–_ݵûÛ®½Ïºot¥Ð-——fsÍÍÊîWldîçNƒ¥qÞñ®’ÚÌ…îqö¥UÂíGO œàœ’®§Xñ•œ>·˜Áý¢–ç‘JA“†až1œõ¯šþ,üWÑ|®$znƒ5ݽäUŠ;¸ãÄ(¾¤ý8Å}4³(Ò¤çbŸ‘ðT²¬WT±„åhõ¿©ô'Ä?x{XðUΫèoâT‰’[gù€@¥Œ„•*+·-œ_j:§Œü©K¦h?µ‹ ÚÜyßd¹¦ŠÜ· ±U°;‚àñšúS]ñŽ©â‚¾×£²Ž {¤&å¡}ÆrœôÈÈÛ“Þ¸‡—r²ýš§&ݪGàAýkç±ú‰òß“Î×ô>ÿ+áºØXsOßVZ^Úõÿ#ÑÿkmFÎóÁx^;p×zt«=Ì…³åR»sݰûŽ}«óŽâ'·žX¤¼F(Ùõ¾äñf“|¶ºžŸªC4:ˆó#¹ŽãýbÉÎw{æ¾:ø§ »¨ncY°=O ú‚ópqT1Ÿó/ÅfiÖÃÆ¯gù™ÞÔì´vÎëRÓ“W°Š@ÓY<…ª:ŒŽkÙ>3~Ô—ž;Ó-ô? Z7‡ô8¢XÙPÝ” P§€qÇé^ËÓŒû×oáOµÜKut¡²7$=p=XOξŠ=¼’Hùiãþ¥I»Ù?¼ä¬ô¹®•ÀŽù™ßoZö)´gCO7ꉴ`H›JñÏZÊ::meR¬6áº}+À~ÒÌz™¸² °o“ïgn¿JâÎ0n¥¤S¿†óxWÄýQÁ>Ñ\ô‡n|jþ»†óÄË5Êɲ]¢§’&s“÷=Zû“Âþ#ø5'‡tù$Ô4K{;û`.ôëèn#;vºº$Œä ŽÆ¿9ý‡ñ‡Åˆ‘g×Y‘—iÙFGá\¼³OTÿò;ž; *>ÊO¥¯usÿÙprivoxy-3.0.21-stable/./doc/webserver/team/03andreas_t.jpg000640 001751 001751 00000003546 10546014105 022272 0ustar00fkfk000000 000000 ÿØÿàJFIF``ÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀPP"ÿÄÿÄE  !1AQa±46qsu³Ã23V‘”ÁÒ"#%BRƒÑEcd„¡£²áðÿÄÿÄ!!1AQ"¡ÿÚ ?Q™.J&¾”Èu)K„@ç¶Ž6cÉ^‹N¯¥Ö´j¶‹^Ä_þéoIôªï4WµÕi87oOðê+¢Q“Ã2ýbžúçæ®ÆpÌ¿X±o¾¹ù«8®TõÕ¤+HÅ_€í¡l”¶h×s?2â‰óÎsóWÈgìiFÃ3âžÙ®ÿZ–Œr¾Š ~ýÈï®]ʸ‹W# ].5_4é®Ëƒ9f5$)9 óœüÕÉΗë-÷×?5dfNé·<Ò®é/§Fñe"­°nZìUÙ¶bÆçf9 LÆq ¦"”ô¥­ ëFûÚ~ÚÞfŒJ{Oy™Ò[u¸/) Cª Jƒd‚7Æ‹vTošdðKÿš)#6ùŽú¾G»U:*_›ãÒ}*»ÍmZN üÿ‡K3|zO¥Wy¢-´ÌÿA˜pòÞyUÌ #e¡FË(¹ß½~5›èZUÔkW”qÛ9`TI¥ò>0Në‘/ ‚i$mUÌQÑüá~Ú‘†b^RZ’•õV„Æ ké…­Æô¦Ÿ³ShÉãØ3㯥i ÝÌp¢©ØpÃÞSm¦ÉÔ oÔxÓ&&ó-’Ñ’Ù]¾n­ô]™^N€7j¾¯h¢ám= |©—;Eý”’Œß!³óŒ«ýÆé+6ùŽú¾G»Uìµ(Vhè«À”5­h¤LÛäf;êùíTôtfæøôŸJ®óD;iùüÇÃ¥é¾='Ò«¼ÑÙÿ°ÿŸðë«¢Pm„áÃÄ™Œ²BVI6ã¸oô«Ppf™y©ni[JÔŽãt!\Eû8ûj^ %1q¸o)Z@]¯ÚE‡}!`6é%4° ÞW-Üi[¦‡¾ä9ÈSw¾’ ‹²såÅNkcé aIB’²Øã ^¹ãz'î9„Ôìj[_¤åüüE\TuôeAªùv0IÎ2÷Ÿ_¼n—3o‘˜ï«ä{µP¶È±8Xvm”þ!2'>H:r,+ÅLÔvzºˆ&¦†hâs™-KËbk±Õäw.gkã;Ô\Oe¦–ýÞ’ã!Ž]4&Dí¿w!¿ýz ë9ÎF:å;ñßáÞ¹× ]8¢ýÅ÷ȽpØm¶»‹™ÊìÌ.‘šÞ€7¯U—ÒmƱ•µñq5¿•#…-­ÔLÑÓT˜ØŸŸ_ƒµÿgŠ×Ù¯–î  íÖºŽ}6²ÍzÏhc#÷…ç‡î¾½áú §/–jb,ë¡Ýà|ˆ?Ú¹hãž%>èî͸‡\d»ögHaxô§ÇQ× ì˜ß ÝŸÕ@­—~"¶úE‹‡ï+à«£5,1ÓˆÄG}†7#-=sº,ßH÷ˆÍo¨¶Tr%šá;C]–¿#½¡ÿ ޾[(wßn6¾+áJ*žU=}CÙS†»X˜ ‘ÔôÇU oñ»ÈÊûÕ5ž¥•¶¶„ˆKï”ïìùAØñ¾;üþ«žqçÔZ/Vë=5Æ\sÅÚ'¯u9¨ÐÜYƒœé=ÝýUx+‹+8÷‹7­¢¨¨‚-T—8©´jcQØÝ®ÆÝ>¡Ð¿TX¶Øjé­ÐÁ]]ÛjX?iQËóŽ‘°Ûe """ """ """ """ """ """ """ """ """ """ """ """ q‡ þ+¶ÒÒvÎËÈ«eN®^½ZC†ž£÷_%^0áÅvêZA[Ù m©åëÉhpÆ21ïyôRA©áŽÑÇtœL+4özSOÙ¹YÕ»Žugo{ùiG£êÚ'ÔÁeâŠËe¶¦S+écˆ8´žº$È-ýr" 4”â’’vÉ,¢& &ysݲãÔ“Ô¨u£zH8&N¬®}K æxê-Ñ»OïèJ›¢¯‚g†ùMv½_&»TѰ²>ÆØÛ$íw­c=éá*[»ç‘qÜîÏïa¥º4êóë“ò]Eo\-mû×–‹Ä¶«“¢äÍ#al­•›ukŽ3° ^iø†Ÿ„..Ñ$²Wê’¢®Q©Ï”à‡ãÈ€qŸÔ©b ç•^Š©ê8B†Æ.e²ÒÔ>gUr2dÕœ:¶ÛHΫÑo®¼Âãõ0Õvx¬%òõsÎFœhð=T•D©8'²SñLBã¬ßŸ+µr1ÈÖ:jö½ÿ%âî£áÞáø*%¸:ksÝɺQÀ$êÕí°»§†Ú|ðzªyÉÂGÂmuãÒlZk•UÞ(œ*+æ§ä°¿pÖ`Œ·Ž¢§œ_Ê­Ô”³²öz¦TêåkÕ¤8iÆGÅÕHJ£‚D÷¾"¸úÃH¼PšN_#<œÆÖjÎ}¯w8Û¯UjOGñIÛX¹Ke­Úé«¢Œ×g'-$íÓl÷)’ ‰SðuÁñׯܫ&©‹”×B{3bß:ƒq«a¿ÏÅcÛ¸xït+Åúk™·ŒR±Ô툎á­À’ü`uꦨƒ[³AÄ6*«UKÞȪ=¦lZAêÊ)£ºá_e«¬âiªÝi{9,u3ZÞXǰvÇlj9îðSÔAáÎõÊõWÛ9þ´«5:yZ9YsŽ=ãŸ{®Ý˜z?®£}L^(¬¶[je2¾’8A-që¡ùËzw)Ê ³IN))!§l’Ê"``’g—=ØÛ.=I=J‚3ÑoÒØ}r£Ü;hŸ³uÃKtéÕ·\ç'äº Ôð¸¨ãºN&íz{=!¦ìü¬êÉyάíïøw/|[Ã0ñe—°MPúw²VÍÌ´<úõ[ÔAü[Qz´]®/²§9äãVþA”‹œÿ‹Ï¢sŸñ}e"Åç?âû'9ÿÙR,^sþ/²sŸñ}e"Åç?âû'9ÿÙR,^sþ/²sŸñ}e"Åç?âû'9ÿÙR+JçH9 ÿr" """ """ """ """ """ """ """ """ """ """ "" Y¿zUµø\÷’Ýyìïñ(,¢½ÙßâÕNÎï ´Š÷gxêB§g‹PZE{³¿Åªþ-AiÞÎÿ§g‹PZE{³¿Ä*vwx´„†öÛ‡qâJ'­(i¢uºö¶BؤÈ.{Ç?l,©x¦âïFÔå“IOYOVË}|àeбÌû#>$®Ik§ ŒÅGOέº@yd+ÀÐ.fëK«8“â ¬©¤õuEh6Hâ% ¶4üŠõU=Lj8kˆ8¢ÒÉ›SQ)¨Üó 2÷ä“'Ÿ²t¬Ž¹ñÊ.y@mmâ»[¸o–-‚Šo[èýØnÙó3·39Î}¬g;,[ ÒÞi™qŽcÃÕÖX›9ö@íŸi¥Ü¼ôn@ÝMéÕcQÖÇZjyM~˜'tq-8Çp'̵Ï)¨‚Ñp/ìü*$¨©yI¤Nòòâ ¾ò©§šŽ^"’-ä|mŽ2‡LG´Üwçxæ2;¯ÁG%b“†ª$-¶ÆæS9àã#r@>ðÀ9éœä;Øü–³×Tÿ‰}CË›µv>Û¯Fz1ž¹Îý1¹Pim¢‹Ñ¥ŠZ wG Gb–êøæ>ŸN^IÑ?£sÝ•îË-ŽJ•SÚd§ŽÝŒ½ïˆ 1+us¤:‘¶utÝHÆA8®¾†ª÷l§š: )Jꈪî2“FâHÀ ËÞFÉèvê£vé«ÝÁUq±Óº‚.#ÑPؘöé¢öKƒ[’æ·pq¹Â¡t»ÒYûksšj꣤„ç2?§ÈlNVLÉ77™M,$,o4´óþ¸Òã±óü@\¿‰©øjF[&¶ÒÂëlº^Ñ3XÓHØÜÌ >èo²Ý}ÙÆrzxok;ÿ$OÙKëNul·_Mü3Žì ë=øAãÝâ¹Wgâ³`åþõºùö§K¿wg:zéïëºY© ¶^}II…õÖù{Qñ\üpã·‡A¶À:=s䎂WÃ’Väµ…ÚuÓžåüGNxDßÌD3‘Ì0ç'WN^HÜêözuRY¿qŒî:õèTZêÿú›³Hm=¯ÖœÒßcyYéûì»$”W *jja´‘Ë#/Š*®d‘—7$=ºFŸ-Î@ÎËÔ7›eHœÁq£”@ ›—;]Ë©vߪ…],·[…wEG ¬}dT‚žGÖÎÏi­wCÓO\dî³m”-«»ÛËÙy‘”ôò²VÕÓÅOMs4˜Î˜›¯®ÚN6(%â²™ÒŨ„É+ ‘°<öŒeÍãq¸XÏ O[e‚fK ¬ÌppÚZpw`¨0¡¾ÑÀnQÑUI]fsh)Y “4@HÝcÄq’GÀ¦6«{-WËE=ª¥„÷¸ë¦ËÌä •¢"" """ """ """ """ """ """ """ """ """ """ """ ""_ÔõúªŽ¹Î¹fŠ ²20\ Ü.' ÷’@ ß~»òLlFð%Ò:6½¥ìÁsAÉnzdyàý·ÐK¶s܃]Gd¦¡¾].ÑI1žåÊç5Äio-¥£N;޹ÎëcãóçÕyŠHç…“BöÉÚǴ审¼/HÿÛžôÏø*ÌutÓTÍMD2OžlLG¨eº€ÜdtÏUyþªŽiÄyŽ£ë•S·]¾{" e¦+ghxžzŠŠ™“Ï9n¹£:@À¿Ågãcãýéãä¼2h¤tŽV<Æí p:]€p|ÛÌ ¸O]Ïê©ã× ÌutÓTOODOžŸO:&<G¨djFFã=UìŒg; tèwñÇ_šm¾Ãñ¿ö,jk…d“GKYO;àv™[¡Æ3¾ÎÁØìz¬œ wçc¾z'Éxšh©á|ÓHÈ¢¥Ï{ÜÖÔ’zâ*ºiÄfˆ¤Æ%Œ±àëaÆ1Ôn7óA9úä*`};Ó.©ƒœct ¼Ïü$=þ}OŠñ$±Äd‘Œpku8 DôÄù/õtÕ|ÞÍQÜ©œ§‡hxêÓŽ„g¢ ßMºñýÈ|†ßãæŸ¢ ¯z¦ÝÃw" ŸöÞÊ=<òël󚃒cŽzmÕj¿Ê_û²Õþå/ü…º¬¨”2Îç9¬/sš :@$ì7=:,x„Úýf+cäóù¹8ÑYñèƒü¥9ͶÕÿ©Iÿ#ù J¹7Û ­ý©ÿeCíüMÄ—;1¾SÓÕ†™œN{+)´éÒç=âPì» ‘¶:ô1K­}`iíŒB_¨û$ŒànIÏS¶z k_¶I*Ÿ;¨‡·/9Ñ "sööv‚{ýÒ‚ St¨áÎ ô…w†I*%§eˆÞÖé%íÃIÀ ÎÈë“‚$wYQ['¤žöʹkàd10±Œ‘’Hñ¶– Yß$c©[×X­¯¬­} tÕ±ªu9ų4 ægI l2!Y¥á‹=ÑK +ù‘csç‘ú4‚Öê' 8oNüdÚYï¼_ÄVŠ[Ça¢¶COÙcmH‘óHç1Ÿ Iq-o“HÆ6UoÚᆅR5ž¯É¤ÃÜ ¸s¾IÏ~PGí¼E_q6ky˜E]åuÙÁ:²áÓ[‹HÆøÎˆîuñ3‡¨©e4³q DõrÕ:6‘Ì ÀE¥­çÝèVê×õ7ªë”4í©»a“EO#‹f€Ðü5Ù;’@F:em+­4*Héj©Ãâ‰Áц’à \Ò O˜þytÛ­g Üý \µŠêªfÑH怖–‚qŽ€ï€3ƒÑHmÕ|BnttÕ/¯VE ’j“F×FíkâlnqvýÎùê·t\3f·º¸ÁDÒkÀ\׺Nv2v²|NvÜ“óU áËU¶¡“ÓS¼K qºYŸ'-§ q È ˆâ§NæµïÔØ›Œwd—ç=صÜ_}¤±q{ELÌ©µ>”ÓMS "`%xÈx`,;tÛ¼÷©»8FÇºŽ‚:'GœúcÒ6H‹‰.-;PÉ'½z‡…,pC]-ì-¯kT÷?›§8$“×ruuÎýÁo‹.õ¾¹¾Ú;FhG ÔT˜´·÷ºœÜçé¶3…®áeüqbi—„éÝ£K1Mnw8ϵ×9ïDz¦Qð}Š*$mÜúŠGQJ÷ÔHç>P’ãà7ê’¼Þ´²Zic§|RSRv(ŸDsaÆ4d8gA;ƒƒ± ×ñ Öh®ôvêJêˆät.™ðQR¶j‚Üà;/Œns¹žê=KÆW‰8qáä ç_½PÉ夯 [šÓ¤¸gg eUÖÊÙiæš)¹ôñrc•R²]ísÚàç™9$¯0pµ’žÛSnŽß£©“,G$à C|´û#¡ê2‚Ætµí¨°ÓO~’¡ÂùIËÒÈ„±ëÜ1±iÓ¶]ì=þ-»2ßqxÝ<œLûU<²DÜSÆHÁÀƬo×Çrz)[øNË-/g’–G´ÌÚƒ#ª$2ó0×s5kÈ»°¯³Š:êCDÃuCªjâ\+°K·;ÓÆÀ Wß.¶zÛõ©Õ¦­ÔöY.4ÕO‰|nn—´5Ûàdm±Îr­Úow¨î\"ÊËkŽùG$“Fè˜Á›d¥ óƒœøŒ „¦µCIYLÚg9•¬1TºI¤{äi`½Î.#Ž»w/L°Û-ªVÓûTf*3­ß²kšG_kÙoŸíA²ÿðNôîƒÅF 9Î1¨uùÍÄg‚ptšîý±Cûß§ÿ-t lt4bIc¨x2<“8lwÒÆ“>ˆ]­b¯¶z¶ãÚL|®w©ªuéÎtç—œg|g¯è‚-t½]¨kxòJ)¦‘ô‘QšhœK›¦{nkNÃ.éܳ(_ë qq×SÊ‹¬Õ/”hÚFf6†q¸ ã[Ö]­‘Ï=C-×ÏQ4³T‡I¨ò²ìj–²ÉA$’QYëi¤“ßtV:†üÈ‹t8øž¾™ô·Jª‰»5®6Ñ\#.8|úd$x‡2<ñ©UŽ škµŠ*Ùd’«ÕUN™Ò8“¬ÉNHÜ“€I~{5ÖWÅ4.³Öº9¤æÈÃd¨Ãß×Q¬l7òW¨ª›pâÊIমl1PÔ±òOE,-ÔçÀ@ËÚ'KŽÞ5¾’„„ðø‰ìd†÷Jç·SZt»ŒŒ,Œø­åWXæ.¸WQMn†•Ñ8ºGm×líÕ»õUªz—QÜmµ5Ív=W5DaÚF-ai ãâ¶ðÝ C*)8~zyÙ2Å`Žnv8"/PAoÓÍsôe]t¸Ü*ÊJ³´¦c¡„J—œ³^x%_ãI¦©‡Žá–¦wCJës ‹œí .; 9Î1ŒàõM*%áêÉŸ5UЦid^ùl3½ÎlI‹=F@®¾¾ÊóR_h­qª —Yj30hÀýŸµŽì Ì´ÆØ¸¢á ÜÖ[¨Ú Ü\H¨¸îO̓⤠5Ãæ9o× i©*)éEK\ÚI)ǰé‰kCÚÝ€sz €¤¨ˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆá:ÿ>å©»M+«í40É#5G6RÇžTm.?¡v€|œ£ƒÒm¹Ñº±¦‹°6^_µ\ÁRá«N¶ÁŒéïÆ Hçç·Í: žž*ÖZø—Œ§»êÛdtü¸™!%š›ì†#%ùÉ$ìp¡¸ÜTÞî°Z«e©µvI…6ªW2~`tŽöZÇ#Ô[Ó#~¨$˜Oú¨ŒGqŽíq°PÚkíÂ$¨š¬´Íª0íÁk޳¾2wÁ$Žóøåµ.áÑh·šÏ]‰L\ɹ\£µa§Ì:i8Ê r(aâ¾Ãw½ó­ÒA} +$íÏ{ÙY»ÚÂ0ÐÜîêz-•Ó‹©íUS<.4¶Êxåžv¿~cÎoy#9ÛPA!OШí?U6ïKk¹[GS_ å¤ÅG1¯,st.ŽjÍÔ\*{%þ±¯5°I.†S8{£^ŸkYÓ§Änp‚Q„ñòQên*Žº’Å%5)|×W‘É/ýÈh&RN7ÐFžƒ'……AÄrÃtµRÉæmò¢²X¤|§Gö01¸sZØÜ“º wDÁð?E “Ò,±FöÝg¶²iêtB9A§SäÒtg`ç e]Å‘Zøn­Âùål „ÌÇ5Ïq8<Ìéѱ$œl:e#Ä}QD ã¸$†è4QÍQEBúàÚ*æÏŒ`܆.ÎíïÊÜpíÖ®õk†áQA$U2XZÚŽcˆpÎþÈÇwŽsÝŒ ÚãìÙîQkïMe5o}8§¤n­U5­†IöÉå3WLnFNÁ^wŠª‹m%ªµU×Q àÉeå68N0\í.9$ã}Hü|º¢çuÜKwoV6¦’Hhbáé«DjœÇAps[âá¤`ìÓ¨û+uKÅ.š+5¶Þéë«-Ì­1OTCaˆ€©Hsœr@žþ¨%Iß…Ÿ®’ª c䪚èÛT´Î”1ÑK¾wÁp:`oºÚÙ/ò\îWKeM¥­¶¾13Y/1„=ºšZìàz€ƒvˆˆ‰Þ‚.2ý Xßà Ïj?æÙ÷þi] U4Á3C¢“Ø{Ox åsöÔTŽü7Ìp¸v¯Tjö¿3Ïî}¯ŸÑ@íGº6–šv£þmŸæ¹üœEUqc›m¥l6¨èÚÎLz_6¶`5îÉÈ l<Öuþõ=TtΦ2¾xd-“ÕÕ02ž@Ü´=ÒÓÓ ·~íÐL»S¾óúÿ5‚úùÏQR”u2¹šFîcá 9ê0á±ÆýV5tÕÖ¶É ,¢¨¥«ç1LZ÷|¿dðG]Æëce«ª¸^,••ŒdsÔZê¦sZÀt”å ä“8ïñA*–c…¡ Œç¿õ^;Qÿ6Ï¿óPÏIÍcâ±6JnÒÇ^iƒ ÃO4iw³í7é¹u°³RQÁXçSp·ªžcÓÏåS c#Ùý›ÜïAn£{Z×;]FH8çlŸ™RD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@@ˆƒ Õú¯Bâ÷‡Sò#O»—eç>zYþêÒÒp¥]¶”Û­÷—ÓZùÆQaÌÌÚ‹.¡†“ž­'ïRGLÖ;ç´3ÁÈ#u¼Op¸_¤©ª.¤¼Ã %„GíFøÀ s]žƒ®1¹ÇA±ÈoÜj*)d¸ÞMS)ݲ$ :pÖrýA‡WM±Öó´3ÁÈjàäª[MæN=⪚Z—PE3iXÉ¥¤/d¿²ÁsZ54÷ä“‘Ñléø.–†³†ä£œÇ“µ±9šŒÜÖà’ìŒåÛ ÉîR.ÐÏ'hgƒibáh}mÄ5u3ó¡½GOƒF45‘–òs|±æ±éx*˜p]ŽáW%Y¬quEV×½Ûi8ÎØ `ï÷T‹´3ÁÉÚàä(8n­×:[•Æèʺº()ùlapÞᨗÀë€:‹t<'êªÊ{” \ ÍÂgD]ÛC· ´gÝÆp6ß*CÚàäí ðr}ŠÃ$·KíÎ},5â·ŠˆKLZÀtÐì7ÁÇ»ò[Jî¾É=X¥¨³µÌ¦s¢æ0µÌ psC›Ü0vÂÞv†x;桞A¢àºÛ}=Ka¾s$¨¯š²VÍH¢@dŒÔ5{¹È#sÑ\‹€é#áÿVŠÉ;k}aDlkD3ç ±›€Ñðü÷ïR~ÐÏ*‰ÚNr $ö…}Ê…ãšêº7Ò1°ÀcŠ-@‚ýĹÛõÈé²Vmº¦Ûe¶[©j¢"Ž8¡’I!'šÆ7IÒ†— òqæ³EC@äí ï:®’Yo-Šç!º½ï™Ï¤NÍC¬»fùp3‚T\%-­UTÃp  e½Òɸæˆï3P#pHþyR>{AÁk²©Ú{œ‚+UÁÔT¾£×¾Y­3['|ñks„…ÎÔpÓ‡;¦ãc".’Öªš ƒa¸PP6Þédƒ\sÆÐ:³ hdaß<©hgƒ“´3ÁÈ#àh… ¾ëßÍ‚î˵DÒG¨ÔJ3¨`Œäxãëin°ú¿‰/W~ÓÌõŸ#ö\¼rùl-÷³íg9èÌT0ôñNÐÏ ºŠß=¿ •;C<‚ê+]¡žNÐÏ õQûƒþ°þ´ ¢üDo`ÉÚL\­±ŒêÓìç=Òºšßs€A_E \AÚÄu6F‡`Œà÷àŸªÀü3Âÿèí¯þ ?äƒü3n–²ó<âI…ݱ6¦94KFœFǼ­ÅGUOPúúê§S0²ÔHÒ"©h$ã½Ù;•‘øg…ÿÑÛ_üÉ? ð¿ú;kÿ‚ù ÕMÁ6™­× '>¡±VÔö—‘ ‡9ÒÃe»¸cóÖÈ47ŒmÍ` u^Û™OöþKßá®ÿGmðQÿ%“Ek³[ftÔ6š:YÒ×: vFHÎpH6¨1ø’ÉðÓ2Z‰éßIQTR@[©²5¾Ï¼#~˜^)­ÕPT6I/uõ1Œƒ¬€5Û`gLm;y‘We°×Ôº¦²ÍAQPük–ZV=ÎÀÀÜŒô~ŠÏážÿGmðQÿ$zþ¶×PÔ[û]tÈe4°½‚6¿V¬·-$ ÷dÎÝúî¶Ü]z52T[ˆøx¼ tí·Mó•±ü3Âÿèí¯þ ?䟆xcýµÿÁÇüx´±ÑñMÁ‘ò9¶ê0dçúÎù>C @µöëu®Úé¶ÝKFeƾD ^3Œéã'궈€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ1fýéVÕÉ¿zU´D@DDD@DDD@QH•U| r¨¥žX'g+L‘<µÍ̬yd~ªNµl5,Œ’J¼ MÜÌ~÷o>XXÓzE†¸fÄÉ鿏WÔQ2g—Í‚Ó%ÄI ©-ß„ýmz©¸vÑžÕ%»G+VeÇ^uo]>ë^•Zd·Þ$¢¹[é…(«l x’?Â~›íæ‚õ£‹ÝÄ-5ÒÑltõqH#4O±œå¿×;{®Îq¾0¤ì.1´¹ºI-ÏCáú-%=’ãGï §¿Tö÷»Y¯‚bÒHÈ qÀÇvV퀵v§wŠ ¢&È?|Õ”±aýëVR" """ """ """ """ """ """ """ """ """ """ "&ýÝP?ÆUNÝvù•¦»ÿI»YíãpfuTƒ?ÕˆmÿätEF)8îãp¢7J* %¥2‘$VÚ™$aÚK„Í0í‰Æî'=úª÷õû®lëýgñ/\êæ0Q²“D8nöþÍ — jö¶ÜœŒt2ú»ý-ž³¶š>hÊi)šæòæ‘ÁaÇPËÔ1Ó A'§–ùé… ¤¹Þݼpý¦;tT–h)Û ª#{œíQ €ñ×qÓ ´Þ7¸]¾¨‚–/]¶£™ÚšçòŒ@gHÈί˜ÇN¨'jžwP)8†²Ýzâg¶†Þ}XúVO;›$ñ9Ÿ´q:·-·=#|ål.übûX¾V2ç·Úà‰¤‚uKPòhvq¤5ÌÎÙö¼K¾ªŸ¯ÝEã½]¨8‚Ýh»6ϹC+ ’š74DøÛ©Íp.:†¼ sŽcÛx’óuºOfŽ (®ݾGeѸ‹–³ílãŸtm¹(&vë·ÍEh8ªªãŠ(!‰µÕ’?¶ÆàH€E‘.ÙØëÃ[Ÿ‹88Xt÷ªšXíPÐÇoâ*©ê,À–2&AÄ Œ ÆOz ¿Cƒ×ÁQs*KÝG^øúëpŠ9§¦9e>XÇ’ÂÖàéÎ[‘¾2z©ºÿx©¸CG,:Loý¿ªªae4¹n³&9Ûœí¶r‚\¨¹\d´ðº¼MmŽªáS'6ª¨N︪gd7"NUO¤ „.$™±RÍUh4ܹ]O$QÊÙ\ñ¸‡ ³ß¾Çpƒ£ýU3¶T#‹ou¶ûa,€Òþ¨¬ÖAÖ©ÌÆsŒcË9Z¾–¼ñŽ#TÞËøV EŽØe£âÆ­X:±ÐcötÏ×î˜>k™ñW4z@¯–¦:*ºz.–²jªböe®#p]ï Ýðû8Ï´µõu•×¾²—“G+¸LÖà ‹ÛÔZÀ p2s¶Ç~„:ßë÷O¯ò\òÝÅ5´vî²ÄCêæ´EW-Obš 6=šÁËŒ—wFF2ʯâûÍ=šß4vè㬨¼2Ýý*žX™#\ 5®ÒàÝsƒ¨o„”Vi[RÚf6²X¥¨û⌱®Üã .qc¼ÿr¼€ˆè-ÔÎÚjY'sÙí9ïÆÜIÏ@±½`;7hçÅÈѯ›ìéÓŒêÏLc|¬Š¦6JW1íkšã‚2Åsé=Kø?[»Gmì9Î]ÙqÌÕÿ”tüÐN©îðUÉ#)«)§|mkžØœÇ‡ ´œtnÓù‰;Oåû Óp5¶ŽÝj¤¥«­†K[¤u-S^Þcy„—g--9Ï{{‚µ:+»*e«ªõ³bFiA$³:\'§M†0¤£òïþ²vŸË›GÏÑÉWYUSr¸ÔÔUÛŸn’Ida<§w€púwõ$«ðp•%%e]%ed–ámcÚXuD²H-#P8vÛd ädÏiü§ê§òÿ =_ Q×ÖÏYSUTùê-n¶Jì°jÇ%ø ƲOQ·’¶Î ¶6F¸ËPð-ÌZ猽Lsté;lÎÆ2z«öž·Z.0ÖG-}K©šæÒÇU?2:|õÐÜmžè5þ‹ê+ë8A“ÖÊ&/šC…ÎsÈÎúÉóÏNà¡TÖ_Z_xŠQÂôt¼ïYvn_´}9ßÇ>kªpÿ ÓðÝ$´´/ªt”ÈÖLýA™în1üÊ÷háø,²ÜLéÞkªS/3qÜ ·øÊ?6šŠóWn††(Ä<+3Y&·™Á¬gV’<Ësæ±O]l–µY-&¶²[ls¸žü3vìÖ`ž‡å·ŠœÜ¸N’çtšá;ª[,Ö÷ÛÜØÈ å»9# ïhï•UÀ–úŠ;| š¾šk|\˜*éåÑ6œt.éôAjÏxâß MPÛdvû»$å²:èäl/Á»ö0HïÜ);5hn¼jÀÕŒãôû­4%KGÃÒY觯¤dŽÖú˜%Ó9vA.׎§;tÊÝ2'±np1“¹(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢(½hÂ~‰¡ÿ ú ò‹Ö‡ü'èšðŸ¢P~ù«)cB× A €²P?Lù";ïÛ¸vãm¤¯æƒq{™¡ µšt伓=¡ÓõYU·ºj+Ý®Ó$rº{—7’ö´Ž[u[äl{”o‹)a®ãÞ¥©‰²Ã3+ØøÜ܇4Â6ZfšÚ/I<)e­æIØ{a§ªvü豓ÞöésOÈôC99Ïß»üe3¶s·Írxl¯ñïoÀëÏÏ7ëÊå÷û½VeÒßI[}ôS<-’JZ($ÎßCû3ˆpð ·cóß êyÇzާ2¹eKêê¤áiî•TÑÚe³Fó5ÂKNjH™¶Œ–ãÇö„¿‚Ú#²ÍË«5ƦNÎá¢`fÞÌmsÜK3œoßÓ ’o柯^›õ\¢Ç-=ºýoäh¹ÔIXøß!†áueÕ$=8ÛXp 9¥ã^iÍëÖµ]ƒæó3ìr±¾ucV;±°ƒ±ç®N0Ÿ¯ÝskÛ.N¼X½{QI«@™õÐi…fÚõ€ö4gÛ ðº†Ô³‚£ìµSÔÛ á¼÷Aâ £ÕûFÄ5¹Ü¼ôÁèNØG¨šXyB:i§2HÖ;–Z9`õyÔFÃË'Éji8–;•mU= ¶º¢:j£I=CyMŽ7{g<8†ç¸oÝ• ½›'6ÊÛ?¢~#¡.tvg?—µl5clã©ÊÓAIMO§³ÓE xȇ-¸c3¥»tQÀîÉAÙüÁùcqš®þk“×Ä_wâ/_VÑSÕv‡>×Fù¦0ãö}ÂFàù4g9$­ÅÁ­AdüLþeœ[1®­šc5y2‚H-Î'r@ݶÏ{¦½vþÌəث$¢“šÐܽ˜É'#q×u³Ïš‚z/‹eû³käz¬Zt³Ns¾p§H+Ÿ4Ïš¢ ®|Ó>jˆ‚¹óLùª" çÍ3樈+Ÿ4Ïš¢ ®|Ó>jˆ‚¹óLùª" çÍ3樈+Ÿ4Ïš¢ ®|Ó>jˆ‚ªˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€éÿ_ñöODžO_Õ2|wóÊ" íŸ/ñ÷TÉñÝüÿRµ¶‹%5”ךi&y­¬’²NkÒ÷ã ÞªÙ"ÇèÝrˆßýÉÝýß$D ±€r;r"y(ˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆƒÿÙprivoxy-3.0.21-stable/./doc/webserver/images/proxy_setup.jpg000640 001751 001751 00000100773 10546014104 023106 0ustar00fkfk000000 000000 ÿØÿàJFIFooÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÅ?"ÿÄÿÄT  !1AQTU“Ò"4aqs‘”Ñ2R’²#36Sr¡¤³ÃáB•±ã5ÁÓ$Cbt‚¢ð7uEc£ñÿÄÿÄÿÚ ?êJŒW¤”ÅQ[R K_ KUxtQ;Çžøb{ƒhÀ/`ul×ßê6xw ë*NÕ©áÜ'¬©;V­´qÔÔÁKƒš³LÛÌèáŒm|¢ö¹µ‡8R…~±§–N)¨³DÈÜïEˆú„xw ë*NÕ©áÜ'¬©;V¯F'„“R èX)¥J^ÈÚëkŸ_¼e¹ÕXsÆ¹Ô tÎÀ[.o8ç”<;„õ•'jÔðîÖT«VöÕaÎ’XÚêøA246;° ÷Ÿjõ•6W3ˆ¸DHµ‘œ„oMGðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«SøOYRv­S¶pôz~Å¿$ÙÃÑéûüAðîÖT«U…´œH"àû•/ #àž(æC ]Åž.ØšïRè«|à{(ÿPUKŒa°J覯¦ŽF›9®ÂzÊ“µjèìç  ¬„RUQSNñй¡ÒÄ×61ir®5ŽpƒµÂ‡~IRX$ÙÉNÛå7±Ñ¾‚ƒ‰ðîÖT«SøOYRv­_KÂé¸3añWá´˜eU,¿BXàa÷)žÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù(¢“ƒgv(°î<ØAƒ‹·0Œ¸´;vë‚|ËøOYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉÊ<;„õ•'jÔðîÖT«WÕüƒõUóäžÁúª‡áÙòAòá=eIÚµ<;„õ•'jÕõ`ýUCðìù'€°~ª¡øv||£Ã¸OYRv­Oá=eIÚµ}_ÀX?UPü;>Ià,ª¨~Ÿ$(ðîÖT«SøOYRv­_WðÕT?Ï’x ꪇgÉ͘öÉ$cƒ˜ö‡5ÀÜ8Ä,–ºfµ”Tíh he€À •±VaÄ k$€-E¿öfVkŽ‚S„ø½DBXÜÚ2ç3~Pmë(6ÈÌNŽ®¹Ô-¥ž*£´fÒ\†92†ë¡¸òAU؆ ŠN‘M1¢’cc‹îâëùå7n€ÊÜðKƒå³[‡Tì'H)êâ׿¿%ŹyýJ®l?ƒpãqanÃA‘á§hä´¸<†Ÿ*÷"7rs ÂL±óm$m„†6V>"àac”ÛÃ뺯Äb‡T›*%Sb cžçÊ·¿S{ßBI*üà,4ôÁíÅ»Sp„ïÜ,W‡àÈò)²Fì¯vØÙ§˜›èPWø­ÔœWcAÆž¦&NÇùR™úi{ÜïÕH¬‚𒂆ŽFGZÙj∆¶3x÷ jìºhlÒ¤¿àÌQ2Y ¦doú/tÄzõY;ƒœl‚7RÀw4Ènt¾ëó »Ú3ë·Þ›F}vûÕ0 É•S:0l^Ù‰ó^ëÇ`\lL•Ð҈ߣf6w¨ßTÛF}vûÓhÏ®ßz£ñwƒœc‹ñj}µ¯³ÚœÞëÝmñSêö}ç|Ð[íõÛïM£>»}ê£ÅL«Ù÷óO0>¯gÞw;џ]¾ôÚ3ë·Þª»}ê£ÅL«Ù÷óO0>¯gÞwÍ.{±@Òx»¹WI[çÙGø¹ãÁ< Àƒ‡FAЂçkû×E]ç#ÙÇø /û0ó~ÿûw&%U‰»ö½ŠŒÃk^pšq+k¥sžKZÍ7V¿öaæü#ÿöîþLK¸ð6¡ÕÄîhk¤ ‹FàNû øì<ÅðŠîpbL^£ mt¸œõLÂf1´4åxcN›®@6ÒúY8Iˆ‰íÃqþâ|ðú†˜*O·%€¹÷½æpuÅ…÷Xk{ý‰ôðIKšAû'ñšÂ4ƒöOâ+4K‡7†ÃØ@sb¤p¸¸¸Út©pÖ—ðǤøé ®^_ÉPé+[OKš}¼¦‹KŸ—/+…€Ð.R|¾aWZ*ee[ªDñÀ yB.K/ôG:ë§‚‘‘m)1jjÒÙȘAmÁסs°ðŽ)fÅ`tŽZîk\<Æ\Ón}ûi΃œ¯Ãê*0Jù›ENÆE.!3ª3ygY[–ÖþÖNªÀ+*j¸À §Š6> `‚¡Ñ™ZÖÈÒs6ÖúbÃÿ.«¢n-BgŽõ12¡ík¶EÞP¸¸^I‹Q#••P;j×:,ÒX<7ék®ä“à•€PŠH,‰’Üm#˜ç8K¥kɽ씘dx5Sd†<úéØç¿Êk Mɱ<ã•^Å‹aóLèc¬Ò4Z.ßî±Qäá ©mdrDdŽ;Æàu{€Õ­ý@ ¦¦ÀkÍQ5Ô®4ä6GGäˆÜòE˜ÆñNEºl"¶Ÿª­§¡¥ªcó£‘ùvwk,wn%¦öW1cXdí•ÑWÓ¼DyH&ÀŸEôR ž*˜[4/kãvç7qäAÍÐà3Á‰m*i[!6VÍTcl‚+ÛB ¾ÅÔ" """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚½´4!Ïq £{Þâç¾Jv=Î>’A+Þ'CÕÔ unUÕx»)ëE4µ5u6d¾Cy .pò ßDøWP|$}Ôât=]Að‘÷Vš\R’®’*†É³ÜMä8¡i” ÏFe`y6 .<»cÄèzºƒá#î§¡êꄺ£Qbôõ°¾vƒ-s›´‘ì±³‹yyG-”ÖÈÇÛ+ÚëÞÖ7A¯‰ÐõuÂGÝN'CÕÔ ue·†íV]Â톺_O±{ÑNÒè¤dıÀ„q:® øHû©Äèzºƒá#îªï³hÜÔ§uI¥6afpó 8¸ákÛ”+UÓ2ùê"mÞ¿ûbÄèzºƒá#î§¡êꄺ²3 XîfÎïzÅ•P–Åíò´9¬sÛ›^M 캡êꄺœN‡«¨>>êËoÛcµf×~LÃ7¹j}},UFšIØÉD{B×Y·µýè3ât=]Að‘÷S‰ÐõuÂGÝ[öÈÀö89§qi¸*¾ƒ¥Äf«Ž0öqbC!mœœÒábt»¾È&q:® øHû©Äèzºƒá#Ê×qˆr¸Ù§8±>…–Þ#1‡jͨ×&a›Üƒ'CÕÔ u8WP|$}Õ“'†G=¬•Žs>·×̽Šh§itR2FƒbXàEÐaÄèzºƒá#î§¡êꄺ¢ÃPO1Ž9Ú@»É·k˹å¸*c§‰’67ÊÆ½ßE¥Àê1ât=]Að‘÷S‰ÐõuÂGÝ^MY=D0Épe!ÚXe7X͈RSÇžJˆÃvŠá׳Ül¼ Ï‰ÐõuÂGÝN'CÕÔ ud* /{DÑ—0]Ã0»}|ËUNÐIž Ênñ¿™‰ÐõuÂGÝN'CÕÔ udéâd­Ò±²;è´¸}AaKWlN–žA#÷FHúÍ%¤{ÂxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷VäA§‰ÐõuÂGÝN'CÕÔ unDxWP|$}Ôât=]Að‘÷Vä@òCÆ28ØÆ†µ‘°1­ DDI‡’8_Œ9®-sb¥p#¡ íRaÿ¥Ø×°¥þ¢š³¯Ä#luUN’6»8nF lG ë”ĸ?=fU 5;·M$°JÓ`Üú»MAÄ.a7æ$ý“þˆ9š®â2UI$SE—m­Í<€g’X]KI¾»÷-Þ-Ëš¼š–F¾:f—¸ˆÚ÷ºþ²¹[b¼Gª«`k;å 'BZÒmû”IøEA·¦Š–²šgJ÷å“1cDo~kK@ûPPÁK[4°á‘66šxjÉ„f\Í!¥Äè ȸ¾ý—pop” k^ÈZÖ:¢I2ìåÞḀwm7«ÃвX¢|ÎÎòÖælO,pëY¤‚ ‰QÎJ~ar°™$–6BÇÁ òËqËf‚G-¿rŒàõt°²:§Q5°ÒŠhö-w–3µÄºû´`°×Ru]>å’²‡©dTñÅR÷K$01À¶2âKEΟòTõ|¬‚’ž:9V")aœÆÆ–µÍ~[µ€›F·úK±D‰Ãq ÔVŒÌ’”ã ß3¹,oþ|·áøÐb¦jšBé ªvL§P2_’ö¶í/uÓ¢VªŽz€è!u+ îfbydhËéx'qçSð >¦ŠZ×Ïcf,,ÌÈÄš Æ0Fëhûò+´AÍÐ`%•“>¢ŽÁÆw±¾yœö›ry$±FƒõjZHŒ-â΋ –K™Ûùrò®rpv¡”µqº‘©Ð͜՗5åÀfò^ãxÑZœ9´°ì›I²`Ê4}ù½Ú«¤AÉÇ€TqÖ>ª•ÓþN ²¶­Ì¹­À¿VÞâ÷º¼ÁéEK42@ÆU3À!ítŽp6õ,y•‚ eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"X:/`ß’eƒ¡Òö ù" eƒ¡Òö ù&X:/`ß’"-Åi¬¼-܈Ï5¥ö-DI‡þ—c^—úŠíRaÿ¥Ø×°¥þ¢ µ„ß™“öOú,Öþeÿ²PE­Ãã®Âª)XÌð: ðÛåÌÜ·äºbX„ÚìöOs¾ïš7³Ÿÿ=þůÄI‚ÕÔÁ,N–wÈÀMîC †žå"ºµ´0¶GC<ÅÏ k!fbIýÀzIdœ‘õtò²­±¶-™%±!ʶ`à,mÊÒu:î´jÚ+bf(ÆÓÖ=ÆVqk¸4¼¸†»6†Î"ä{?ÃÐ8ÄȩꦖF¼ˆã`%¹àMì,O?©`ÎQJö˜£©’>(ÄíˆìóI—(¿þàok}º Œá“øjJ]¬•5EñÈÆþd¹Äæ:îŸZ¼¦§Ž––xšL h€ ¸­3¡§”m2Ôy7>H$è= *á%6Ff¥¬d²–ì t_”“6ë éË|ÖµÐ\¢¤¨áVM $—hÇ=ï`ŽL±ºì¶o¦@БË˦‹søAJኦ¡’Al­q³IÎã¸È-QI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^ âxŽ!&z‰ß³† ëfu¯¿ S£ó8=rÿ5ê5M5•rÊ÷Æêi¶­s'qXé¨$}º Õ†;šY£¯¤§`™Ä°K™®ô@:/+ëjiê)©éiâšIË¿;1Œ44_xk¿Ñ]g§§ŠA$¯CÈÊ9tå*“¥ª–ª’¦Ãžû¶[؇ r  \96SÍ»9Z^K~}ØrŒÚP7msðÞ±l¢©®c‰ -ß@t°Ôj5Ü¡¿¨Ûyªg|Εà%£bøÃ[Ëþ uô¬+pNp÷¶*)ø¬GSÚo—QÌnßÞ‚tØö ž×UÆç1™Ènºq¨ÓQ»d1Š!†Ó×K0Š€Óq©$\ sªèð\BœÉOMQI$¯cß–8°4µ£p(õ Û­ïÃ+ؤ§ã4%¿M¤±þAaô ÐHf;…¾¢:v×De€Öß”ÞÀó‡U²I'¢6ÇNü²I#²¡žíÓ_ݸý»ÛŽaŽ€Ì+#ȳ7¸9­šÖß{kéTópjº¢9µ°:GJ&l·¼DÖjÑ¥®Ð}D©àõo¯mm\´ûAPÙK"iÊØÞÁ©Þnûýˆ,dÄ©£Ã%ÄóÁòZ5Óx·:ÓKŽá•“2jãtÏ3–öÞ»È0çŒ>¾›hÛÔºWo£žêºƒÄ)䥎iéM4©s—8[s¥sµæ² •øý-c©^Ñ‚'<¸Ù¡¯~KßѾÊIŨ0¨ã Ù—e½ïÍk]F®Âe«Ä„âHÄDC™®÷Ž\ÿ¼lCƒïª©’qÅe½^ÜEQf²ldO“{ ³ªÄcƒ ›ˆ ™NmšÃuùž Ûº4Ã#Ih¹±ǯеI†ð~\9‚L‘9€D̬iu÷·íX %Â0Ñ#oÇQ6Þ3^Þ´Ópƒ¨¤¥¨ÛìÅDbFµàÝ ýn@·IŒáÑ>F>®6º#•÷?DÜ MÈÓÒ©"༬Øm£ÃjrÓGNã<%Ź.›}÷všò«Ga1=™ÙåÖ¶¨éÈ ½z qzL*8ÃveÙF†÷æµ®¼ƒ¤©Ä //~ÄM˜ I#>Š»àûꪤ¨–kÕm„Uæa&FAôÝ—¿¥K Ã$£¬l­ì‹‹ˆŒp³(kƒË´ÞQAhˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¬&üÄŸ²Ñf°›ó~ÉÿDjé[]†OF÷²x]sw€ákz®¬À¤Ä"‰••î˜E(•ôñW7PEŽŽýÁoÅ+6[QœÙ¢¥|‘»&ç¢ÜÊ=N5#*¨[Åj©â|¯ÚºXÀhŠGXju»Aûm°p—´Å3ÞÖ ZÐàâ4”~õP0*ÚI©èiPê6ÏO#žùcÙÚ,·'üyŽ@2Ú× ÝJ$}]#Ý5E;ƒ¢-|‘œ®k¤kN¤Zö+tœ'ŽešŠ¡”ÙæŒM¡Ñf$Xêëzfþ²FˆY9‘±ÆlÀö¹§’çéiu]7㬣’SQm›OQkØ`Òu Ü‹‚y@Sâá –<áõMHÈÚÂÒ3’‰›^mìs~€KS™”õ/kc‹;Ú$y 'Kn} ‡‡àµ†êf¨š’µ²Ìë‚Ù d„]®Ó-ü–7[z•ˆðz,LDÙç{ƒ˜±¥úÝ®µÚ}"ÜŠ.Â&Ôº©ô¹¢{bœH°µ«ßA‚i†R[OÒ§VÞ ö»—R »‘B‹œƒ‘ŽŽ'Å5ML²:8ãfV´þRP5ä³c7õs­µü(‡ {W…Û#,‚Iãih7qÐÚÈ/‘sáTÔ‰é¥9&tPGiÚþl6÷ÜIs uÜ¥ yù„'œUƒNaÌÝLàÞöµ\¢¢ªá44´¬•ÐyNÚÇÊÈü¦8µÍÄn]±ÙØ×e-¸ÎÞ=h2Rk¼ä{8ÿQ”šï9Î?ÀFÌàõËü×¢GæpzåþkÕ>?Q3,R>ÕO³|Ìаe&À$IåÜ‚á=ÀˆSO[S5.#@^ÖÓÔÍ£-¼¡˜f×v§Ô³á Tô•xlñLöC’v4Ø>0kú%ßûP_"å1SO‰âÕaΖșO œrfÚ9„‹u#r)tü ©ª,† HÝPj³9Ìh´bKùMµœä*šLeÕ.‘®€5ÑÄ÷ºÎ¸Ìǹ„ 7]§_J€þ½’³þìÝ–H\ò ÉxÂÍÊ,7‘½JŠšBZnbϼϧ’­á®vðÉ$³oÉ i“ÄbÄY@ü>¼¯nC·òr¹’:çMàÆA_¢ç ÆñJˆàspêqÆ£{éÁ¨:–ê¼.9®°‡…–—Žñû¤ñ—Ñ–’_-œÖX¶ÞIÌæ¿z‘memdu”´t´ðÉ4±¾GºI ZÀÜ î\9 ^UÔ'uBŽye†7²|ÎÌÀãrµ‰c¬AæçAТåkñŒFl~B:yj©„ð–N뵡ч@ÐþPZÞË?*⦮}= dŽ…“I)’ Üå’F€Ûƒú²uÜ4:tUŽÅKb‘ûäV²–Ù·ÝÍnoþ[½ ¸AVÚ j“G xËívq°’CZO''>¶AÑ"åOªdx¨1)’+±¯-v~1³'p6ÐèwÔ­þ0×Ed¨ÃãZaQY5î35¥®¸>[O(Þƒ£E†²yª*)ªbŽ9¡ qÙ¼¹¤:öÞº9žkKìZˆÏ5¥ö-DI‡þ—c^—úŠíRaÿ¥Ø×°¥þ¢ µ„¿™앚ÂoÌÉû%ºŠhëh%¥šû9¢1¾ÆÆÄXÿªòªŽÃØž^Ñ{\–9†ÿcŠÕU4§ Ÿ`íŒÛlå‘¶k—B}®zŸ— .uIÄCi\M%\¡í™í-»™&ëùGA¾÷°² ¸p8"¦â–!”1²Ë|®} o¹Q à̶I¤¼• ŽÌmí@çÊëz.l‡ÄXê¦YMQ4Mó†[äjFqpmè%`Îb.¦u32eŠ76B\KçF\ yHÚsŒXLQÆÆÉQS9cØöºi.F]Ãw¤úO:‘QGLÔҽϽ;Ìh:”·_°•WE‰â5x–š)j)$Ÿ(›;ô1ÚþHâä<¾…S‹Ôb»©§ãצ¹&e@DÐÈÜIf·ä‘mEÐ]W`b¦¾˜¦–?ˉeÊûhžÀ[¦ý[{é¢ŒÞ Á¶ž7MP)$…‘¹¢sš_-î~~{—òsžE²Ln»ŒìiðèžTêXÜúŒ·sAqqòM†VŸMù9T:ŽËMH÷? &«fó8˜,Œ²F ékƒmG2 98=G!kšù㑎ÎÉ#’ÎaÌç\}÷ y Ôx-Dc’1=`d±l¦mes®ãkÞïvëoZ$áFx$¨£¦ŽZf¼µ•”†>Íü-qô¸ä7#—3HdŒÃJ$’h©Ë[Æ_ÊðÓ&ñ¾þ„äàÝÁûIj\_®m¥‹]fy@¡¼m>°·Ó`ÔôÒ6]¤ÒÌ&3%}Ëœ[“_FSk ÃÕŽª––<:7ÍL×:¢ÕhÄß(›ò€4Þ®(ê8Ý =N\»XÛ&[Þײs`°KNèÓÇÝ#žÖ¸ý£‹œ ‚.ãȧà tðG MËm cy€fˆ Mwœgà 2“]ç#ÙÇøÑùœ¹šôs±ÅŒyaÌÜìóؤ~g®_æ½o’­ïˆÄÖ²(ÜAsX-˜×P§¤‚¥Í3DÙ2µÍÂâÎ"Ü· r ƒ&A$;'Afåkn×¹§Éva¨7¾bM÷Ý)pj 9ŒÐA–BìåÅî7v\¥Úäo;Ï*œˆ Kƒaó´6J{¶î$¸f%αò$›V¹x=…Íq%3‹Hh-Ú¼7É4Úö¸XïÑo~/†Æ÷1ø…#^ÒCšéš<ÇTn/†>ùqGX\Úv›}è1«Ã#›¬Ãá´M¨ŽVÜÜÙÒ^çÓ«‰^Sà¸u$ûhišÙs‡‡æ$‚Z¹Üˆp¾I§¬¦«4ÕÌ¡1¼:ÞåÄ(…O5”â{åÙm[šüÖ½ÐCñoü­¨À5Ì =À¸ÝÁ¢þH'}­uNF'M=ÚÚx§ãOR_0nV›ÞÀo`5 +tA ¿ ¢Äòq¸3–¸9Íp"í ØòËLÂijðQG›|¡¤†´‘bZÛØ®ÕšÅä†8àŸ†Ñ¾8˜èlQl˜.teÚmÿÁ¾åQ‹ð^‚9”ôTuDX¤ÕõŽT\¡`Íq»U“pÚ&V:±´Š—ºPÁ˜›[¨..žš8çÂêàæÈq …™*wŽšX k¦—3Ä@’Ȉ>¿+—‘W·„5ÒGQ)­¦…Ð:(Äg•&cbíüºnV”Š" )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耱’FCä‘ídlÎsƒ@ÞIY(ØŒÕa•TÓI³ŽhŸp2‡ __Z´˜Ý=`‰í†¦8&6ŠicÊÇßuµ¾¼—ús…f¸úúšìN:PÈ-k$`–V×4E”;\¯¹¾ÿ)»¯Ë`b¿ šš‚G7 -ðÃ(ÛûÄ»VØÝ„5ò•ånÑhú˜ÙU3‰ÚJ×9ºifÚÿˆ-Ë“¢àø—3M„2›9íJ÷1ÍÍf Å%ºØé¯Ñëe¢£ªšZn7E=Dm§ÙDz–0`x{ü½ÀµÍÕºŒ›· ìÕT¸õ<2HOU²Š]“çÝuÀä7¶»ì½Ã°ÆÓâ5õrÀÝ´³ œ„ævM›ly5iæ½½JÃkïAxµ¶xPøÁ•ŒkÜÞ`â@?üO¹qtܬO…¸P¦›ˆIDÂvž7)"θ7;œnëšÊö "ž‹ª–*=„´Ð´:60]í{˯r õa¿-·Ü2~mÞ¢¹\ƒôø%-UI«|Ò\áY+o©ä°]TŸ›¨ªŽ ~ŒPþÁüE>)á?V¯ã¦ï§ŠxOÕ«øé»êíRx§„ýZ¿Ž›¾ºÁ-%17+IÞw“©>’µ)5B—ØÄPFgšÒû¢3Íi}‹QRPp·ö4»‡´Wj› ~φx¬„Ê77Ø”od‘ØÉ ¬ØÆæ‹ý¡Ež¾ŽšfÅ=\Hÿ¢É$ .äÐ9ïkYXÖ×b5F¦´TRØÀ`†ÿ„ tõZÞ›ñ²TáToÆ¢Å`¦g—æuLdZ0Í÷ņãÈ.ƒ¬Zß2Db|LtgRÂÐG>åȳªŽ²8MUE$íšš8p×·h]šÜ丂]k¾îÃ&ª]'„ªëiÛ&'PÈæeKœÖ1ƒ.IZÖvèlNºß÷ ¿4nnWR@FšÇ&{ÄéKØþ-vì‚í¶ës.:|bµ”®/Å&Š¡”Ë !Æy‹¤O“©vV‹ Q¸­Ø^+[PÆÛ’j‡QI%LO§Ò–`E›`Û‹á”Üœ·AÖŠZv½ïDñg¸0]ÃÓÎÓÁN‚âxcCoî\ƒqzá†×9•ÎsYÕ««§ã3ÚaNÇfç–Èáp4侺  ‹‚ªäá†3<Žx‘ÑeŽ KÁ ´Y¦äZöšî7O°¾/·mKF¼9‘=ÙƒŽQk Mô j9l‚ÉŒdl cZÖ´X5¢À/\c6ÕGm}3ËC^]e³ç¤Øa¥õßÌyŠß'æŸû%U ¸-†ÑÅGøxd#(Í3ïé¿”¤xéÁ¾‘†öÏï*\«‰ðs ¤Ú‰äºM,˾Úë~], YY[Kˆ5¢Š—Šºhá`/ü¬¡ÖÌæÈÛî¼Å*q b­˜ÇONhéåŽ ‹Ïà$n°g¼ójütàßHÃ{g÷“ÇN ôŒ7¶yhÄjgŠ ÁEOLçÇ šMµÀµì·.…{]ˆ2Ÿ ж 33eÈFCˆÕ×>žK Ýã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÉã§úFÛ?¼¦l£ý[}ɲõm÷ ‡ã§úFÛ?¼ž:po¤a½³ûÊfÊ?Õ·Ü›(ÿVßr~:po¤a½³ûÊM pZ¬BžÐKTù‰Œ‘î%×ÒÃ2ÏeêÛîR°ØØÜR†4³5ÒhD\óñڸșÂ`kM.Ï9´1Ür¥í̃¡EU 0‰™+ÙV2G¦.tnÌÅÍ$YÀVÜ,©±ºjºé颎¢ÑDÉ3ºž@ç .Ý~ŽýÆþ‚‚ÉÖ, è-ª©¢á7°Ú8¨â¨ÃÃ!FiŸMü¥k'æßê+‹¥ÅÆÁÌ!¡´¬Ç+ŒÕ7 ·9nó}=GzŸÇN ôŒ7¶y(â£7Hòi%°ê-å{^Å^ÚxÙW%Hk#ù\Gâ+já©êª¸ÓãÄ#Æ NÆÚq9.»#-»¿8A;K\èt6Ð+L£›âuq,[g]w9ÒjÖ¸·B[åè4Õºh ÊŒFŽ’x¡¨¨drJ@c\wßAïYUÖSÐÁ¶ª™±G˜73ŽòM€åqü$‚µ¸ÄõÑ2¦YcÙ2FA#á™Ùž[¡!Îu?áݪè1Æ2L>™òÇWvOÄ”­»áw×Ëcq­ˆ±ÐO¤®¦¯ÒRÌÙZ×»/!æ<ÊBã'~&úc¬ÂÕ0KW‘É+vdæ4‡èðÝE´ä²ô¾¦Ž2üj¤6œqMƒÌÏÎï¤.u'çIÔët’ÁóGƒ^ðÒEõÓ”ù…Î>ª»%5+Y[·eEA™Â7å É1`͸Yk_P7(Ø…Oƒéã{±˜êq,çi!q“i#wfÐ[—Dz* jɱ ¨'|†ÅÚçL¦÷'üG&KúIܯÐI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DDAãŽV“bl/`5\à’1‚ŇlqÉ–§~¹\»ì]" .ʺ¦§=öáƒ-­—(#þj,¸@—ª£t ¶¢gJIeÀÙ­kë̬ÑšzJj@áMO!Ú‘oîQi°zX*&¨|0É<“:Q!ˆfmù/¿E`ˆ)߃NÆÂúZÆG4ULøs´‰âZEÁÓ6ðF弞'RNkÚùè³>˜?ÆòL¤€íC OJèQpé©iªê\×C%Lד7ÊŽèÆí[•䟚ì•’ñÄ8‘päöIÆø+…·>M›Û.ëß+ɲ’pjË‰ŠŠgç- lÔî{â`±ÙÀ77·/*QðÖ’7Ña8“©­hË$`m†š ËxßTb½¬}ä  t5õµ†VºJŒ­g|†´hºêIäÞ£O„O-[Ü*£m,ÒG5D[\÷°pìÞH9Y¥Ñô•·Æ¼oª1^Ö>òx×õF+ÚÇÞAnWQ.Úž²e|n†Bè Áa7m†ab.uÖ÷Ü·O‡m°ÓBÙ"g-ËZÛhu×vý7­~5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò $U¾5ã}QŠö±÷“Ƽoª1^Ö>ò %'ÿ‰Òûf¨Tž5ã}QŠö±÷”œ;„8Õv#OJê FœK fÖI[•—å6q($ªú,–‘ï”à •šIvÛ 3¼º×ß 6û‚ ãèðÙª#e Õ5F8éIN_@èÃm«ÜM‰³4·ï]™¸¤Õ‘ÌÀ%‚8‹6,sïq¼<‹[›Ô¦¢ düÛýEr¸F=f„ÕRÔÅ ÐÃ4•ƒjÒ×t¸±òF·ç««q„‘qmÊž†Œ´‘¾ ÄMkFY#l4ÐfA¾— m#0Ö2b[CŒ]º¾íúnܼªÂU'¦ W47Fƒ’Í·.õïxßTb½¬}äñ¯êŒWµ¼ƒÌ3 šŽ¦¦ª¦¢)§±°ì Ù45€ÛK’O”u¿0äW•B—ØÄU'xßTb½¬}åjé*'†žzœâIbÈ÷]Ì:ƒy­/±j#<֗ص& á~2Ö´¹ÎŠ• Rv€+µK†¸ÇÃ^F€K#¤xÚö/(:ZÌ.¾‚6ÉUHè£s²°ëby æU2bt±âqáî{¸ÌÌÖä$[Ê·•k ïr³¨ž‘ñlépšz2燽ñÈIuÓw¥qU8f%4õX«•µM’8]NLŽl~K@v}Äßâ<è:‡ÔEñ@çZIo[}·­«†§Á%¬|0ˇÕÓÔº–xêjäv`dvç+S(snÑož“ª¡e]] ÛÕTFf…±¹Û623½¢AqŸ’ö×qAÙ-ÔTôŽ™ÐDéžd‘ÛËœyI\æ†TÕI1JWìámCr:íf²4²ÍÌt˺äÚÊ5&!aªÃª¦Ä¤ØÚ©ÓY±·fÜÚßBuŵ'Òƒ³Z¢¨ŠwÌÈÝwBý›ôÜë[Üุ0š¦P1Iv|nº6 ,à]l€n;Îëó«î Òñh+òÑËI•|QÊ|¬¹Z/¼Ø ‡" ´D@DD)(©è!0ÓD#aqyR\MÉ$êIç+z"" )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆƒ”55´Ø‹Ÿ]WYãƒg#Z$¦|EùC …Øuîµ­ÈJzŠÚzøü!WY †¦ÁùD”Ó1Î 4$îúV7çR‚Õ ‡IÄ©2>]³â㲘Ëï|Ù2å½õÝ¿UcA ¹Û™D†A¥qŒ:÷¸a9FºîA³šJœ‚yž_,”ìsÜyIh¹TÕVIQWŦğVÊÌ‘²8¯PF„‘–Ö½õº¿¢Âi°òÞ.úÆ7#Xú‡½†“e&x©ö›6Ûhó#µ½Üw”¬’vÅO†5ûI厒 4ˆsšlÝ=wä¶§WŒ“¸SFÜ:Õ5aÍ‚ÎiH•¤€@ ›òúôVS`ÔSÄÆ9nI_3Žkš÷\C¾¥ÅiÃã…¬Š'·fÖ¶;Lñ—)Ì,opIÞF§–è2¡Æ‰HæRÆ×:8˜ùs>Á®q>NíàO­¼úXÉù§þÉU¸Fhi'lÎnÞ¦wTLa.kshÝo`›zU”šÆïQAËasUCÁœÐJÆFé˜ÉAmÜàdµ¾œ·ÑI­–£Ã톟õXÝÅ£ŽñEø¶†ÆÄùV7ß—ÒUŽTx·‡ÃW Zøí k¥h!ÁÄŽ_R—âËE|•­22i^×É’°µ®- ´:Ç@ ”Òp‘Óâ5;:q¶©Ï¸9¯‘ƒM7}sé…]EO¬«mL¬mT4í¤dxpa%Ü·ü¯ÿé] x#¢–¢F4ÔéP,-®šs-2pf9kYVö“+2鯼—e½‹›šÄ‹ï?òAW‰™ç®}Õ¿4âÑö­ù ŒŠO¨æµoÍ8…G4}«~h#"“Ä*9£í[óN!QÍjßšȤñ ŽhûVüÓˆTsGÚ·æ‚2)Õ¿4âÑö­ù ŒŠO¨æµoÍ8…G4}«~h#)8üN—Û3ýBq ŽhûVüÖú*Ib¯§‘û0ÆÊ×8í[ Ö‚½rMª¬šriæÄŸR1°´Eù”ƒwkC{®µj‚ž*hÜÈ›•®{¤"÷òœââ}ä ¢g §âœjl1ÌŠZGÕÓÚv¸½¶Žò\CšyF»ôRé+±9qzªyéiãdtñHƉËÜçƒs—™»µµ·›éƒ¸9EOO(£¦{£0µ“Nüa7-nü£Ô9› |®«©`Ž­ñ¶'ìfqnV¸–ósžNRK“óoõÃÃS] ÓÑŠ·‰ ¨{ã¤-¶Ênál »Q{Ü‹¹wk½ETa\uW°æWBèæ…ŽÊYS³{C‰¸»\ ˆ¶ž€ƒF[];ðGËQ⨥.5„?(7ÖÚkºÁyU[_&>ãPÍ¥;A€µ†Ì—jIÿí—CØE0ŽÚ)šY¶Íµ·óä¸fmSd†76¨Z`fo”-n}4AAÁÊŠ×Õ×ÓÖq¦Û ㎬´È34Üݺe$jMïmË©«ú¾Ä~"¡Ðpq¸i•Ôì»åËòTíl,Üâl9½%M­nN.ÂZ\Ø€6p67<È"³Íi}‹Q派Ũ€©0ÿÒìkØRÿQ]ªL?ô»ö¿ÔAv°”‘È6!§UšÂoÌÉû'ýa=Lt”RUNì±E‘îµìÐ.NŠ2Ê©„RÑÕÒ9ÐíØjÐË€ui q¡±Õošî¡‘°ù D1³8–8å°çë——Ä$§c)hOLÐ×MA=H|rÙÌ9XA!º5ÂäXÞÖÖà;4D$aqÌ5X²¢7GœDnx#œ./É¡·¹QÐáRIв®« §¦…EHv[˜ìHf9\tÐiÊ©›ƒÔÉO.p覩m%,;gJÁíh»¾Ë_ɹ6·¥eu-DÍìtr_!&Ù¬mʽ¬«Ž†•ÕÜ´´ïsœCZôÔ5°×RäæàýYÃá†*¶F°³ÿ ñ‚â šuß{ Ï.à¯qÜ9Ø–;áÛÂ%k§§k²íZ/äÜ>–S©äA&жÕqE0 Ì™å‚ÝâÛØlVˆ±ú)]‡6Ó5õìÏ]ÐZþQ£ðb†» –ž±®c%©ãt­~Hì,ÝÔ}¾µWj顬,Š'ÉŒ4Ó›–¶WKk‘äÜ;'/ÑæAÑÐâqW¶G²)cdr:<Ò€Ðâ×›k{\oRLð†™XtÌ,W3¦†Žšµ²ÆÈ©[)/¾w6lòuå%cY‚LÌJi›„A[F] Š›hÖæŽ!pƒV¼_*ú èé+éë)içà âl¬kˆÊáq§©oÚ2öÎÛÛ6þNuÅÐpv¶©)æÃ!2µô¯5›ax™Îð¹¶ûÖ³Á|[Œ4^0Á!¢.¾†‹Gn½ó oÜyvâXËò ^5Ë}Vk›‡¨‹„1ÔGL $‘ÅïÈá•×ú.}õ:àj€.‘I®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DEáÜPbÙ¢{Ë#á¼B¢lÌŒÏõs û—…)_@Ú!GZû½TCxêYv;ó̱¾ IØÙnª~þ ›£v$h²ŸûÇ¿ó_7ÙoBÅóEò1¤îpY\^×Ùr’œµØ¿†Äf{ ¢§–‚Û;úsnÖëP}d’>J(dŽAJù¢©yÛ˜Ãæ»n/åZúú-Ëpk§‰–Í+›Qwu™ o r.6¼áuUͨ§Ÿ ž)iÎ-X21Ñy@ßc”ßB,y7+:§É?°×ÀÃM#¥¥ÊÙÚ^Xs·G ‚}âè/î/k‹ï²õr8­F#AŒS:£¥iÌÔGLZ"i{nHsÜ5Ð\è/ʽ~1YàÒöâ {<±¶¦6ÆÇJl¤gòÔƒkanTjÅç+Fð.¹Ü*ªZŒNYfÄ6˜}4®cc—È 7¶îsô½Vè¤üÓÿd ç0ÙøE‰áðÖ2®‚6J t$jGÖô)[ôì;áÝÞYpSôb‡öâ*å&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wy6%éØwû¼®Ñ&Ľ;øww“aÂ^‡|;»ÊíRl8KÓ°ï‡wyKÂé1¹qZXë+(LùZÙ. žBNŠÁIÃÿât¾ÙŸêFZÄñ6bVg½²æ÷-‹’§Â§¯ÌæRPFÖbRÈjˉšÍÄ€Fû[én÷ ëQqTøý{è318ª&’‚J‰"ÅeYºkmH³µòU½+gƒ„5±Tb’<ñHƒä nÐ]ûΈ/^r±Äoë›Ãgá'‡ÃXʺÙ($5Ð8‘©[к9?6ÿQUý¡ýƒøŠ v%éØwû¼›ôì;áÝÞWh‚“aÂ^‡|;»Ê÷bøiiv¯™Ð‡Hæ‹ë›Ør *M_Ð¥ö#ñ™æ´¾Å¨ŒóZ_bÔ@T˜év5ì)¨®Õ&ú]{ _ê »XKù—þÉܳXMù‰?dÿ¢ &ž:Z9*'vX¢Œ½î±6h'WÓbõRKMÆ0š˜!¨$1ÿL°òmÙq˸n6Rj°è«0Ùé^ÆÍ ¢.P rÝBŽŸžZ6UOK P?<ÒS=ÅÕÐ4´´{Nà íÅ0÷>f6º”¾L­6ñ¼»]-éQÝa’' Êc{@™¹”´Xºö¿–;7±y¡Š<ôyc.qd’¹Ñ¼“{å \‹®ó®šÝÓáÕòã1bì¢nͲ5Œ†î-¸h1h¹ÑÜ‚ÀÛ]PXM‰PÓìvÕ´Ñí¿5žV§ìÜë¼nçR—*î Õ #&:Z†:˜A#_<‘å!ïp#(òÁ7۷꺖·+tÐ[D¢"" """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆ0lQµÅÍcCŽò¥61gϳfmù²‹¬ÑlØL“Êé)X.I „†úã&Êe<.‚ ÇÏ$ïå’@ÜÇî€?r܈5˜" ®Ñ¢Ø@;ÅÑxæ5âÎh<š…‰Š2ÀÃKFæÛEš Ç#/|­½­»‘zñ™Žy^¢ 8.ƒRÒKYy#mœ[µï~JŸ±¥éN쿺§Äq1B衎 *j¦¾Îì ¶òIÐI[0ê¹ëiä’jé]²9²kúÞ=;ZlizS»/î›^”îËûªZÌ]´µ¢Ž*:šªƒ˜²Ï%—µîç ç\è¼ðÌod Z©åž=«ac\ÖÿæÌ@o¨ž{ »ØÒô§v_Ý64½)Ý—÷\ñá#i$•ðÔ²xåØBÀe2ÍA½­­Öc‰¼aµuTÒÂã­i.kˆÍ-qi6:Ü ¾ØÒô§v_Ý64½)Ý—÷Tµ˜Í53¹’É=šãA»É0k«®G _RÊ,@ÕÏ4QÔÒËi-˜6Îö ´w[ ¶ØÒô§v_Ý64½)Ý—÷P…D. -š2HiQÀçZ¨«éqß%$Í–6Hc.nìÃx¿* -/JweýÓcKÒÙuSVãü^¢Hi¨f«186W1Íhi:€.nçz¨:-/JweýÓcKÒÙu':H#•ÑIÑ¡Á²6ÎÒSqøßPæ2†±ð6§Šº¥­i`}ò3f¶m/–ßf¨: /JweýÓcKÒÙuE>6": ʨ $I$-mìà]ÿ´ãñêwKTpO[$Ñ ƒ` òXw8—õ[èP_lizS»/î›^”îËûªJln–¥°œ²Å´dp•¹Ly Cƒ¯¸ŒÃœ,fÆÙ”±GGU4Õ!îŽ6‚XÛ]Ç3€QË}w ½ØÒô§v_Ý64½)Ý—÷U”µñTÐ2±Í};pæÎ29„}7ÿE£Æ à ]4¯~]œo`-ЛœÎ 9÷‚ëcKÒÙtØÒô§v_ÝC‰æXY!Ñ—4ÇK}ÄqY “±¥éN쿺lizS»/î£" ;^”îËû­´ÜR ¨f5."7µÖÙo±¿:‚ˆ ÀÜ,½D£ÖcFmöÖ±LE[çtÒ9®hh‰Á¹[é_ÞVôAãÆf8 äYjÁpÈpìš’ZËÉlâØ®I<þ•¹IØÒô§v_Ý64½)Ý—÷Q‘/Jweýוoæ&Äâæ²0Û‘k›“ÿ5派ŨŒóZ_bÔ@T˜év5ì)¨®Õ&ú]{ _ê »XMù‰?dÿ¢Ía/æ_û%zú³A„UV5æ(i6Í•¤Úÿbƒá™hñSb¥…‚™Õ;H¦. k\ÖœÀ€GÒ>‚¥Wa±Vá54lqºx~O£™¹nµÍÑ šj*ZjGNÜ®tPµ·æ½­t7„XSªG¶ÅŽ_($‹m¥÷òoYøj‰â=”í.¶Ùšá¡G®šÚXò¨µX5\Õµ:¸™ISL32:bè›Y`7\ÛrÓãvÓÇfÿ’xÝtñÙ¿ä‚íQKÀš QÏãµD0VñÈÚæâÁ#x6ä±ë/°.ž;7ü“Æì §ŽÍÿ$T‘¸Ç..Ž6å"ÄësûÊäg«¤Ä%šXéj]P+ ™Ícãò‘‚3£)¿îRünÀºxìßòO°.ž;7üxÁ‹añTRÒÐÅ;Üêy]0hòü±¿BNîE®›Äpy };#¬ŒÒ² šÍÁÌ.!ÂæÖ9Ξ¥·Æì §ŽÍÿ$ñ»éã³ÉsÕâbŸÃR AdûFFì¢<å…¬[6P§”Ì•4X…TÑVáÐU\ö—¶rÉ4¶Ií'[÷RI)b/‘’T>HÚÇÆAk£ngsiªÐþí µ¯’iÝ+¤“ ¾1ƒîQ«x sêä}d­– Bs4~mì7/f¾IpÐÛ‘ƒ8AE!acj nk]µ0¸1¡Çɹ<ÿó ÉxE‡Ã ²ÈérºòË<8´´¼ù%B¬à”5HÉbŒa4í{ãÈ:ÛÉzNªt¸.zàŽ¥Ì–:§Õ2LÃ3žçZw‹<„Y‹AUƒMˆQ¸HÖ1ä_ë4 Õ;L爞%ÎÓ%pŒäcžÖ–‚}9”(žì:ZY§Îéæ¹á¶¸¶€(ã`§ž³­,ñLM·Ä`·f=è1—§fÔ2‡–2G5Â#‘åŸHn¾ÿq^CÓÈØsÃQ|q½î1‘—îÛ¿ÿ¡j<Ø›ëLÍkœÙxâ sƒÅ¬÷¦ #xl9x Ù\^ꨌ—͔Ҵ½¥hq7Ƚ‡9Õ¸1çg¨uLcee?’cœã–gÆ÷¸hûWµ\"Š“[ À½Ïd…ñ›Â[}ÜÞ]-¥Æ‹ø5ôòÆj?8ìÇâ©(xWÈê¶L×2W5å”î ‰¹Ë[˜Ü릧÷'ƒxcðúZ‰f‡e5LÅû3bcŒ ¬apßfö’µ;ƒ.b8±c‚¥Äϧ7–\@<—Ü¿b (18je™²gì^X÷ͳbåçõ)r~iÿ²Tzz3K ¬Ž]_3åÌ[{fvb?}”‰?4ÿÙ(*8)ú1Cûñrªx+Ç(|‡}Éÿ˜«ŒúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅYõîLúŽ÷ ÅI«ú¾Ä~"´dÔw¹o«2˜c±ˆ ŒÏ5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚÂ[˜žü¥fˆ+qJóKVÔS¼ ⦒HÉòƒ òU5xõT4˜]žÖ͵x–\dk„orç=ú—EYKmE$¥Â9ãtn-66p±·½A›¡šJ‡½²^¡ì|–vü®ÌªÿêƒL\#‰àhªéó1’F%k|¶¹á·&Ö.ÇU"³‚ò±ÑH÷Ææ6Àµ —w¸€4yÛÈZbàåg9„Ý¢ÃÉË’ÖäËn[_TçáE4Ô²º–¤¾¤9͊ͤn]kj7{¬ñ|Mð`b”Ò:8Ë.h‹œas€p¶ðloè²õœ‚é…-UM4°gË,E€¸<‚àZZ[b@:4ZÚYXKG ø{è¥ÎødˆÄüÏ9œÒ,|­÷·*^§„µ¬€Í³ aïäê$ºüú–žO¤­pìbWÚ*¸e$ÕMN*Zç5ïZ÷ú-ßkzVñÁú0ÿÏBIŒ™]w\‚sýo(5Þ°=K{p¸ÈØûGPú‘¨úN.'“uÞr ê^ÐUE4Â*†C&p÷4ö j,M· ¸¤\!Â./°»ŒÇ”4Ý®¾â ‡–þð¤C€A è]WY-!ˆÂÈŸ ´l<€€ ¶€E½ktxPk#ÖUTº9ö¾g6ã-ì,ÖÊuµÏ)ÐX,šï9Î?Àe&»ÎG³ð£ó8=rÿ5è‘ùœ¹šô@DDD@DDD@DDDANyä¥c«Þa³\!îknãMÄ+]T@Bë‘ {Èôm‹M‡?­I6%<¾Yk%dlœã!° >;UÒfí ùý>Rì²:ŠjÙ*ßHæJÙv9%’âÄ€\n. Ž—ç+ ŸĨÝ=#¸¤Tò°Ç&Í[´­êAÐqÚ®“7hSŽÕt™»B¸ÆSNé°¾=„O,”ôоJ–¹î”„’n"çŸÕ{õˆ7ñÚ®“7hSŽÕt™»B´" üv«¤ÍÚãµ]&nЭƒªé3v…8íWI›´+B ßÇjºLÝ¡N;UÒfí Ј7ñÚ®“7hSŽÕt™»B´" üv«¤ÍÚãµ]&nЭƒªé3v…8íWI›´+B ßÇjºLÝ¡Z¤‘ò»4sÝÎãr±Dy­/±j#<֗ص6Ö»†˜«_ôÚ0ím¡/º¹T”ã@‹…/õt“Ã;#«uNGI’´G «|¥ìÙÜèZ./+žâÚ\òr®%‰â Ä&d”ÒÊccˆÙÙ›ݧ:èC ÃZ©W¿¢|²9ûw6W—¾#;ön'Sv^ß¹Fð†Gâ"–<>i×G²1¯9\æµÚY¥¶â÷p;ôÝx±ð†®Ž‘’ÕÑ:Hd–xã˜JÛ—5Î ÛA•¦Ç]Úuppz3\êÀÙ#Ë\ö¶W<´Y¤´,=ÁGgp¶Hçì¤}ÌŽ |ÏsZ_ô‹A6뻵¸Ì°b­Ã©¨öõkÒéCÏ{›-“ÝLëN!D* .„—½†7KK^[­´ääU•œˆ‘5+ ês4™&©‘¯6Ík<GÒ<†ãE;¡~…CK#£t.s¶`†‚ç/­…ì/Ì‚z" """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5ê›2<áôÅÏe-EHŽw°à,r‹×u‡Ûɽ»^׋±ÁÃÐn²Q𜂅õSÓSº&l¼¬®vFžK ØtUœ$•Æž–‘Èþ1;v‚6›Ng[Q¾À}¥Ú.wĦØÐÐÎ,b‚fLéZëÄèÚÓ©6»]s¿UŸÅ*qzvESDÆVÓÂæ #qk/µ$€3“ÑÉͨv(¹CÂR\:Ià ¥’ig=¯sæy6#Év[ß[zTš¼W¢’ªšIf ÐäöG½¤˜—[&ŸGìAÑ"ã*1Êù¡šLЖÒÇTÉct.h”²6¸\g9l]k\î;¯¥ÆŠÔUO稡O4±ENÀí§‘}s^Äù:Œ¢×ßÎh¹ê¬j¶ú ÇЊzjÈiÌoÍ´x‘¬7ö›hocº×1"Ç1‰ib”Í…Âça⸵ì}¬GÑúCM÷w%À±ÞC¬EË¿ÄA†éÉŠ»ìÜàcÊÈYÚ˼óXƒe9¸ã¤Á±,R(Øè)„› › 2s~bàGÙ}n‚é0üc”8cq Õ/§uKäÙ¿+Z°ËŸ[Þù³nDn?ˆÍC-tM¤d0PGXö¹åäµÄ´€“£¬}EN‹Œv#W†×ÕšGK=D­d²µÍþR ùZ.çuì7+j,Z®\EÔsšWäª|| €CakïbMÜAÛw¥ÛÈ£lqµ¬c@kZÑ`ÜY.~“¬®žñ:S±’Jçås³5²½€6ÆÚµ ß_Q¾•’cø¥E3¡/†äµ x§sr7hÆÛWÝÀ‡oòw5Ð;4\ƒøA_XŒœ>8è ’IÙ¦i`sy$†o±»Žåf1:ñ;äwâ­­¡ŽÎà\›5ì-}Ö7¶ð‚ñkå á4ÍHòNòÞEBò+1œœXׯ%ªü˜”Ø‹êm¥ÈûJÁ7ƒ=þ‚2\Ö¶*¡³.¾KLÀé°Ñt@?;‰sK4ÊÔsÜßT- ¡¤m[ªÛK©p³¦Œäz]¿-耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]ªFS Rzî5UTæ6E C¢Ù6Ú;É ›ïò¯èWj V ‡ÖÌéª)ZùÐǸ €½±×yÞƒš«ªŠ—eˆmc’‰^Ã+EXŒ;È \´ }&ÛÕµ6/SNk·˜¹Y]cž¡ìû,ü¹ùÃéŒqxíZÖ,C€¢ûƒ£i¸§`7w(qxÿäIûPTTcuðÞ–:FOZ* FFSù6ÉpáÈà7ò)ïÄ&‹–º¦C4q=Î¥® ‹î±#’ûÖêŒ.†¨;oLÇæJNãœ46÷ç°om, ¥â͉»¹r[B9Ps\¨­ee]&*[ZÙžé#`Ý™¯$ý+Ÿ$h2,‡Ó²gãURÖÔÀúyNÎARö² !c¯“6[I±<ªÖ“  ¡ÓÓS1“8é5. ÛBN¿áåä˜>-KêL#Üó˜ÙÄ5±ÐPcUn¢36 ÓІ¾@ÜÑ“‘·;ô³G-Ï*‹ã$¼cŸ!“S½—‡;¡ûF´9úÝtÔ\ ·®Ž|:’ ÔøADԔ즛#ÍCIˆNatí’Æ¼j—ÓꑹWPâSA'ƒé„ÜaÕ%®‹›;©Áˆ<àIswÚæú‘ȯê0úJªVSO d……¥­uü’7wßÒ¢M€ÑÊiš#ka…î³R\KrÞ÷½ý>„ÎámC"t¯¦ŒxÀ’È35îiÁ¹ZSbã˪–ì~®*×Ë.ÉÅí†/åA oÐîÔrs©çƒØC˜#41dˆò †å…·r¯YÁü%Ž{…7{\Ãqqg}-ëØ]¸M]}K%ô|Yí#/”ß(@s­ïV*=% 5 )¢ƒ¿RIûJ€¤×yÈöqþ£)5Þr=œ€ ™Áë—ù¯Y1ïáìqk†â ˆXÇæpzåþkÑéj¦™™à{äcC[~{ úTWA §dîŠ33kd-šðð¶*¬k«¢}TQA$ÕSl†ÙÅ­I7¸òs —&A6m­ 3óÛËÜA8`ø`݇R -ù†îË—›êéêÑl¢†­õqQÓ²¥à‡ÌØ€{¯Îë\îå[Ÿ…íåî&~t|·—¸‚lxM#k¦¬’¥òíX÷Æ £9Ï$ïC÷¬æÂðúˆáŽziY´M|-pŒs4¦á»™WçáGGÁûy{‰Ÿ…íåî Q†SÉ ‚ ‚w<ÈÙ„-%’lúÿŠÚ]gCAO‡áÐÐÀÀ ‰€5ç'ÒwžrUv~t|·—¸™øQÑð~Þ^â žÂ6PìsgÙñveÍk^Ößm£KNæ=†‹dfÍà°YÍ×É<ãS§¥TçáGGÁûy{‰Ÿ…íåî ŸY†ÓÕA$b(Z÷‚ Œ-uîA ‚5(¿=‚E€RSQKMS5L–]«šø ƒ@k-`h N~t|·—¸™øQÑð~Þ^â fRÓÇ|DÛ‚VpI${É?jŠÜ k27 ¢ Ôeì¶¶¿'-‡¸(yøQÑð~Þ^âgáGGÁûy{ˆ,…aÒI ¥sâqtnt-%„œÄƒm õõê·ñxlFÆ;í-”}+ß7¯Òª3ð££àý¼½ÄÏÂŽƒöò÷YÕÐQ×µ­¬¤‚ 4Ý¢hÃì} 6SÁÏg lÙ´±™ZVé æpU9øQÑð~Þ^âgáGGÁûy{ˆ'Ôa8u^^3‡ÒÍ”¸¤-u‹ÉÔrêDTðÀ†(ã¡ 1 h4N@ª3ð££àý¼½ÄÏÂŽƒöò÷]¢¤ÏÂŽƒöò÷? :>ÛËÜAvŠ“? :>ÛËÜLü(èø?o/qÚ*Lü(èø?o/q3ð££àý¼½Äh©3ð££àý¼½ÄÏÂŽƒöò÷]¢¤ÏÂŽƒöò÷? :>ÛËÜAvŠ“? :>ÛËÜLü(èø?o/qÚ*Lü(èø?o/q[PG\pçMˆ v͵ÈNç9¹m{Ü€oö ÚŠUkYS!cY-çhÿBWœpþ¢Ÿ²#"Û>+3çq0›f‘­h¿Ú½‡Ž¢1$,¤‘‡s˜Æ~ЃJ)|gɲ¦ÍkÛf/eï?¨§ì‚Ȥ:¼0]ÑS4\ ˜ÀÔè¼pþ¢Ÿ²#"ί|TsÈÈ)Ùœ?$7€«p9¤©À0Ùæy|²RÄ÷¸ï$´POgšÒû¢3Íi}‹QRaÿ¥Ø×°¥þ¢»T˜év5ì)¨‚íI®ó‘ìãüFRk¼ä{8ÿA?3ƒ×/ó^‰™Áë—ù¯DIŽÅ0?ýaþ[•Ú[‡I_ˆá’6X¢e4æY%÷e"ÂÀ›Ü žŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêȤñhºu?Ý“ºœZ.O÷dî ŒŠO‹§SýÙ;©Å¢éÔÿvNêÊOÿÆl?Ñ8´]:ŸîÉÝYK²Ž‹dÙÙ+Œ™¼€í½ Æ›Íë=ˆülQ—¯«e[+Ù,Ÿ’¬‰…ïqÎÝ ÆFõF1ðexë%|øKadO“Ž6[åü̻쩪ªë(8ÃQ ¤¯ ša¤qþA„X¹¤tÔä«oÕÇÁ”ñ‘½QŒ|AMS_S E ²â-²ÆØæ®Ž0Z#Ú:ÎEìÑšÙ|«Iqʾ-Dщœ²I9mE£ˆÔ1…¡¶ÌÒ 9¿ÂÝm¢´ðëxÖßÁ¸ïÑ˳â§'®ÜëoŒêŒcàÊdc²bÓº§Êêª!cm¥Æ\nFcåçÄ’ÇUôIã#z£ø2ž27ª1ƒ(,ëÿáÕ^ÅÿèT^þŒa?ú8Pj±ýµ$Ñ7ÅÞÇ4^‘Ö¹ ÊH8=†Ã+É#¥‰¯k…‹H` óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_æ½?3ƒ×/ó^ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_æ½?3ƒ×/ó^ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ óZ_bÔFy­/±j *L?ô»ö¿ÔWj“ý.ƽ…/õ]¢"" """ """ """ )5Þr=œ€(ÊMwœgà#GæpzåþkÑ#ó8=rÿ5耈ˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€Ï5¥ö-DgšÒû¢¤ÃÿK±¯aKýEv©0ÿÒìkØRÿQÚ" """ """ """ ""“]ç#ÙÇøŒ¤×yÈöqþ‚4~g®_潌˜ÒÂ#‡=Œ—ü¬lµäq9Àî ý©³ªè¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@DÙÕt_â`ï¦Î«¢ÿ}gUщƒ¾›:®‹üLôMWEþ&úlêº/ñ0wÐ6u]ø˜;鳪è¿ÄÁß@gšÒû¢È±ÑCoË‘485ÁÖ6Ýq¢ÅaK--]MWŽYê2½î~æƒ` rŸ©fˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼œf.ƒO÷¤ï(È‚O‹ Óýé;ÉÆbè4ÿzNòŒˆ$ñ˜º ?Þ“¼µO1žc!k[pVÞÀa¿Ôµ¢" """ """ """ """ """ ƒK&%UGOR‡Æ'‰²µ®šK€à½£µìVܘ—>ÛKÿM0ßø6ÿ¢ƒùmRPFɉsá½´¿ôÓ&%φöÒÿÓRUlÓVTâÒRK …t’9™‰.½€µ¬Iɉsá½´¿ôÓ&%φöÒÿÓToÇêpâ#ÄLdÃRè¤|,$Ê݉‘¹[Èw j®ðùßUFÊ—¾76`$fÌÝ¡¤h/ËëAîLKŸ í¥ÿ¦™1.|7¶—þš’ˆ)j1Šš.a˜TñR¼×m<¸eyÈÒíC˜/{Y^ÅšfDî úWùƒ?³Qü·.Ò‹Ïéý«Ô ÈÓÓ‚A¬nŸùòM…?Lofï’ÐÿÎ;ÖT,J­Ô8lõ,ŒHøÛv´›w ”› ~˜ÞÍß$ØSôÆönù* fãTÓñªšY⑤JÐÍ™c­'~aè6X7„´†)d|Q5‘>V‡°f‘  Æñ£€: è¶ý1½›¾I°§éìÝò\ûñø£‘°:г<·%8cs¹§5ô²ä»yMÛ¯®§…4• ‚vK… È×åiŽæÚ‚à]¸ýëò_D&Ÿ¦7³wÉ6ý1½›¾J«©’©•K^:‰#u‚˜ƒDUTVUÓÂâþ*ñkKAÓÞ¦ÓÀ'sxcZÒââ Óì\ö ÿÇõMþ[WIIôj}‰ÿP°§éìÝòM…?Lofï’Œˆ$ì)úc{7|“aOÓٻ䨪±aG‹¶šVLèÐliß)ÍšÚäÃÖ¡xÕMOÒ¤<ºIådL DìŒ v…¶Þ4ß®íè:­…?Lofï’l)úc{7|—68A. ’h%ŽNØ£»œç‡ž_Ùôºj¬h+£Ä)̬ŽXË^c|r·+˜á¼O´\ ³ØSôÆönù/ 3Z\k`/ù·|”u„ß™“öOú ÓA[!C\!Â9EÛ›}®¤ª~ þŒP{?ù•p€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆ#a¿ðl7ÿEòÚ¤®f«TÕr5òâØ¸ÈÆÆÆ²¤5­k@ÈÿJÑâ[c_ýuªVéëUdô²†dqˆ4‡ŽK‡.9ý*‡Ä ¶Æ¾/û'ˆ=m|_öAuI‚AJè¤ÛM,̙ӾY ¤yinºs¶à¤QP¶„ÎØæ‘ÑI!{cyE}á¼¶¾¶ää\ïˆ=m|_öO(zÛø¿ìƒ­EÉxCÖØ×Åÿdñ‡­±¯‹þÈ×ÿ‘83û5Ërí(¼þŸÚ·ýBäðîPaØ­>"ÚÜFy©ólÅDáíšZt·1];èäkØlæAæ(üã½eGª¦Š²–JiÛš)•ÂöÑVIÁl*Y#ÙT縗8šÙµ'ÿzÇÅ<#õU_?}È06ª–zªÚšÃJÒ e³ Í 6ÒåB§àu%;XÖÕMfÓº›FFÜÌ9wÙ¢æíûÔŸðÕU|lýôñOýUWÆÏßA"·e^ ÚæUOORÖ±­|yt ÏÈAûC¿˜-Tø>Jµ¥Ì šîkŒ¶$Ü’.§u–)᪪øÙûéâžúª¯Ÿ¾‚Ò–•”•¬sŽÒWJoÎãr·ªOðÕU|lýôñOýUWÆÏß@Á?âøïþ©¿Ëjé)>O±?êN…QáL‘”q½‚Wgy|®y&ÖÞâNà¥MžžX^#•™‘夎k‚ûfŠ“Å<#õU_?}IÌçVžå_âžúª¯Ÿ¾ž)᪪øÙûè.Ö~fOÙ?è©üSÂ?UUñ³÷ÓÅ<õU_?}|ý öó*ái¤¤‚†’:Zfd†!•.&ÃÖu+r" """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""ÿÙprivoxy-3.0.21-stable/./gateway.c000640 001751 001751 00000110050 12060362340 015560 0ustar00fkfk000000 000000 const char gateway_rcs[] = "$Id: gateway.c,v 1.93 2012/12/07 12:45:20 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/gateway.c,v $ * * Purpose : Contains functions to connect to a server, possibly * using a "forwarder" (i.e. HTTP proxy and/or a SOCKS4 * or SOCKS5 proxy). * * Copyright : Written by and Copyright (C) 2001-2009 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #ifndef _WIN32 #include #endif #include #include #include "assert.h" #ifdef _WIN32 #include #endif /* def _WIN32 */ #ifdef __BEOS__ #include #endif /* def __BEOS__ */ #ifdef __OS2__ #include #endif /* def __OS2__ */ #include "project.h" #include "jcc.h" #include "errlog.h" #include "jbsockets.h" #include "gateway.h" #include "miscutil.h" #include "list.h" #ifdef FEATURE_CONNECTION_KEEP_ALIVE #ifdef HAVE_POLL #ifdef __GLIBC__ #include #else #include #endif /* def __GLIBC__ */ #endif /* HAVE_POLL */ #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ const char gateway_h_rcs[] = GATEWAY_H_VERSION; static jb_socket socks4_connect(const struct forward_spec * fwd, const char * target_host, int target_port, struct client_state *csp); static jb_socket socks5_connect(const struct forward_spec *fwd, const char *target_host, int target_port, struct client_state *csp); enum { SOCKS4_REQUEST_GRANTED = 90, SOCKS4_REQUEST_REJECT = 91, SOCKS4_REQUEST_IDENT_FAILED = 92, SOCKS4_REQUEST_IDENT_CONFLICT = 93 }; enum { SOCKS5_REQUEST_GRANTED = 0, SOCKS5_REQUEST_FAILED = 1, SOCKS5_REQUEST_DENIED = 2, SOCKS5_REQUEST_NETWORK_UNREACHABLE = 3, SOCKS5_REQUEST_HOST_UNREACHABLE = 4, SOCKS5_REQUEST_CONNECTION_REFUSED = 5, SOCKS5_REQUEST_TTL_EXPIRED = 6, SOCKS5_REQUEST_PROTOCOL_ERROR = 7, SOCKS5_REQUEST_BAD_ADDRESS_TYPE = 8 }; /* structure of a socks client operation */ struct socks_op { unsigned char vn; /* socks version number */ unsigned char cd; /* command code */ unsigned char dstport[2]; /* destination port */ unsigned char dstip[4]; /* destination address */ char userid; /* first byte of userid */ char padding[3]; /* make sure sizeof(struct socks_op) is endian-independent. */ /* more bytes of the userid follow, terminated by a NULL */ }; /* structure of a socks server reply */ struct socks_reply { unsigned char vn; /* socks version number */ unsigned char cd; /* command code */ unsigned char dstport[2]; /* destination port */ unsigned char dstip[4]; /* destination address */ }; static const char socks_userid[] = "anonymous"; #ifdef FEATURE_CONNECTION_SHARING #define MAX_REUSABLE_CONNECTIONS 100 static unsigned int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT; static struct reusable_connection reusable_connection[MAX_REUSABLE_CONNECTIONS]; static int mark_connection_unused(const struct reusable_connection *connection); /********************************************************************* * * Function : initialize_reusable_connections * * Description : Initializes the reusable_connection structures. * Must be called with connection_reuse_mutex locked. * * Parameters : N/A * * Returns : void * *********************************************************************/ extern void initialize_reusable_connections(void) { unsigned int slot = 0; #if !defined(HAVE_POLL) && !defined(_WIN32) log_error(LOG_LEVEL_INFO, "Detecting already dead connections might not work " "correctly on your platform. In case of problems, " "unset the keep-alive-timeout option."); #endif for (slot = 0; slot < SZ(reusable_connection); slot++) { mark_connection_closed(&reusable_connection[slot]); } log_error(LOG_LEVEL_CONNECT, "Initialized %d socket slots.", slot); } /********************************************************************* * * Function : remember_connection * * Description : Remembers a server connection for reuse later on. * * Parameters : * 1 : connection = The server connection to remember. * * Returns : void * *********************************************************************/ void remember_connection(const struct reusable_connection *connection) { unsigned int slot = 0; int free_slot_found = FALSE; assert(NULL != connection); assert(connection->sfd != JB_INVALID_SOCKET); if (mark_connection_unused(connection)) { return; } privoxy_mutex_lock(&connection_reuse_mutex); /* Find free socket slot. */ for (slot = 0; slot < SZ(reusable_connection); slot++) { if (reusable_connection[slot].sfd == JB_INVALID_SOCKET) { assert(reusable_connection[slot].in_use == 0); log_error(LOG_LEVEL_CONNECT, "Remembering socket %d for %s:%d in slot %d.", connection->sfd, connection->host, connection->port, slot); free_slot_found = TRUE; break; } } if (!free_slot_found) { log_error(LOG_LEVEL_CONNECT, "No free slots found to remember socket for %s:%d. Last slot %d.", connection->host, connection->port, slot); privoxy_mutex_unlock(&connection_reuse_mutex); close_socket(connection->sfd); return; } assert(NULL != connection->host); reusable_connection[slot].host = strdup_or_die(connection->host); reusable_connection[slot].sfd = connection->sfd; reusable_connection[slot].port = connection->port; reusable_connection[slot].in_use = 0; reusable_connection[slot].timestamp = connection->timestamp; reusable_connection[slot].request_sent = connection->request_sent; reusable_connection[slot].response_received = connection->response_received; reusable_connection[slot].keep_alive_timeout = connection->keep_alive_timeout; reusable_connection[slot].requests_sent_total = connection->requests_sent_total; assert(reusable_connection[slot].gateway_host == NULL); assert(reusable_connection[slot].gateway_port == 0); assert(reusable_connection[slot].forwarder_type == SOCKS_NONE); assert(reusable_connection[slot].forward_host == NULL); assert(reusable_connection[slot].forward_port == 0); reusable_connection[slot].forwarder_type = connection->forwarder_type; if (NULL != connection->gateway_host) { reusable_connection[slot].gateway_host = strdup_or_die(connection->gateway_host); } else { reusable_connection[slot].gateway_host = NULL; } reusable_connection[slot].gateway_port = connection->gateway_port; if (NULL != connection->forward_host) { reusable_connection[slot].forward_host = strdup_or_die(connection->forward_host); } else { reusable_connection[slot].forward_host = NULL; } reusable_connection[slot].forward_port = connection->forward_port; privoxy_mutex_unlock(&connection_reuse_mutex); } #endif /* def FEATURE_CONNECTION_SHARING */ /********************************************************************* * * Function : mark_connection_closed * * Description : Marks a reused connection closed. * * Parameters : * 1 : closed_connection = The connection to mark as closed. * * Returns : void * *********************************************************************/ void mark_connection_closed(struct reusable_connection *closed_connection) { closed_connection->in_use = FALSE; closed_connection->sfd = JB_INVALID_SOCKET; freez(closed_connection->host); closed_connection->port = 0; closed_connection->timestamp = 0; closed_connection->request_sent = 0; closed_connection->response_received = 0; closed_connection->keep_alive_timeout = 0; closed_connection->requests_sent_total = 0; closed_connection->forwarder_type = SOCKS_NONE; freez(closed_connection->gateway_host); closed_connection->gateway_port = 0; freez(closed_connection->forward_host); closed_connection->forward_port = 0; } #ifdef FEATURE_CONNECTION_SHARING /********************************************************************* * * Function : forget_connection * * Description : Removes a previously remembered connection from * the list of reusable connections. * * Parameters : * 1 : sfd = The socket belonging to the connection in question. * * Returns : void * *********************************************************************/ void forget_connection(jb_socket sfd) { unsigned int slot = 0; assert(sfd != JB_INVALID_SOCKET); privoxy_mutex_lock(&connection_reuse_mutex); for (slot = 0; slot < SZ(reusable_connection); slot++) { if (reusable_connection[slot].sfd == sfd) { assert(reusable_connection[slot].in_use); log_error(LOG_LEVEL_CONNECT, "Forgetting socket %d for %s:%d in slot %d.", sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot); mark_connection_closed(&reusable_connection[slot]); break; } } privoxy_mutex_unlock(&connection_reuse_mutex); } #endif /* def FEATURE_CONNECTION_SHARING */ #ifdef FEATURE_CONNECTION_KEEP_ALIVE /********************************************************************* * * Function : connection_destination_matches * * Description : Determines whether a remembered connection can * be reused. That is, whether the destination and * the forwarding settings match. * * Parameters : * 1 : connection = The connection to check. * 2 : http = The destination for the connection. * 3 : fwd = The forwarder settings. * * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ int connection_destination_matches(const struct reusable_connection *connection, const struct http_request *http, const struct forward_spec *fwd) { if ((connection->forwarder_type != fwd->type) || (connection->gateway_port != fwd->gateway_port) || (connection->forward_port != fwd->forward_port) || (connection->port != http->port)) { return FALSE; } if (( (NULL != connection->gateway_host) && (NULL != fwd->gateway_host) && strcmpic(connection->gateway_host, fwd->gateway_host)) && (connection->gateway_host != fwd->gateway_host)) { log_error(LOG_LEVEL_CONNECT, "Gateway mismatch. Previous gateway: %s. Current gateway: %s", connection->gateway_host, fwd->gateway_host); return FALSE; } if (( (NULL != connection->forward_host) && (NULL != fwd->forward_host) && strcmpic(connection->forward_host, fwd->forward_host)) && (connection->forward_host != fwd->forward_host)) { log_error(LOG_LEVEL_CONNECT, "Forwarding proxy mismatch. Previous proxy: %s. Current proxy: %s", connection->forward_host, fwd->forward_host); return FALSE; } return (!strcmpic(connection->host, http->host)); } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_CONNECTION_SHARING /********************************************************************* * * Function : close_unusable_connections * * Description : Closes remembered connections that have timed * out or have been closed on the other side. * * Parameters : none * * Returns : Number of connections that are still alive. * *********************************************************************/ int close_unusable_connections(void) { unsigned int slot = 0; int connections_alive = 0; privoxy_mutex_lock(&connection_reuse_mutex); for (slot = 0; slot < SZ(reusable_connection); slot++) { if (!reusable_connection[slot].in_use && (JB_INVALID_SOCKET != reusable_connection[slot].sfd)) { time_t time_open = time(NULL) - reusable_connection[slot].timestamp; time_t latency = (reusable_connection[slot].response_received - reusable_connection[slot].request_sent) / 2; if (reusable_connection[slot].keep_alive_timeout < time_open + latency) { log_error(LOG_LEVEL_CONNECT, "The connection to %s:%d in slot %d timed out. " "Closing socket %d. Timeout is: %d. Assumed latency: %d.", reusable_connection[slot].host, reusable_connection[slot].port, slot, reusable_connection[slot].sfd, reusable_connection[slot].keep_alive_timeout, latency); close_socket(reusable_connection[slot].sfd); mark_connection_closed(&reusable_connection[slot]); } else if (!socket_is_still_alive(reusable_connection[slot].sfd)) { log_error(LOG_LEVEL_CONNECT, "The connection to %s:%d in slot %d is no longer usable. " "Closing socket %d.", reusable_connection[slot].host, reusable_connection[slot].port, slot, reusable_connection[slot].sfd); close_socket(reusable_connection[slot].sfd); mark_connection_closed(&reusable_connection[slot]); } else { connections_alive++; } } } privoxy_mutex_unlock(&connection_reuse_mutex); return connections_alive; } /********************************************************************* * * Function : get_reusable_connection * * Description : Returns an open socket to a previously remembered * open connection (if there is one). * * Parameters : * 1 : http = The destination for the connection. * 2 : fwd = The forwarder settings. * * Returns : JB_INVALID_SOCKET => No reusable connection found, * otherwise a usable socket. * *********************************************************************/ static jb_socket get_reusable_connection(const struct http_request *http, const struct forward_spec *fwd) { jb_socket sfd = JB_INVALID_SOCKET; unsigned int slot = 0; close_unusable_connections(); privoxy_mutex_lock(&connection_reuse_mutex); for (slot = 0; slot < SZ(reusable_connection); slot++) { if (!reusable_connection[slot].in_use && (JB_INVALID_SOCKET != reusable_connection[slot].sfd)) { if (connection_destination_matches(&reusable_connection[slot], http, fwd)) { reusable_connection[slot].in_use = TRUE; sfd = reusable_connection[slot].sfd; log_error(LOG_LEVEL_CONNECT, "Found reusable socket %d for %s:%d in slot %d. Timestamp made %d " "seconds ago. Timeout: %d. Latency: %d. Requests served: %d", sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot, time(NULL) - reusable_connection[slot].timestamp, reusable_connection[slot].keep_alive_timeout, (int)(reusable_connection[slot].response_received - reusable_connection[slot].request_sent), reusable_connection[slot].requests_sent_total); break; } } } privoxy_mutex_unlock(&connection_reuse_mutex); return sfd; } /********************************************************************* * * Function : mark_connection_unused * * Description : Gives a remembered connection free for reuse. * * Parameters : * 1 : connection = The connection in question. * * Returns : TRUE => Socket found and marked as unused. * FALSE => Socket not found. * *********************************************************************/ static int mark_connection_unused(const struct reusable_connection *connection) { unsigned int slot = 0; int socket_found = FALSE; assert(connection->sfd != JB_INVALID_SOCKET); privoxy_mutex_lock(&connection_reuse_mutex); for (slot = 0; slot < SZ(reusable_connection); slot++) { if (reusable_connection[slot].sfd == connection->sfd) { assert(reusable_connection[slot].in_use); socket_found = TRUE; log_error(LOG_LEVEL_CONNECT, "Marking open socket %d for %s:%d in slot %d as unused.", connection->sfd, reusable_connection[slot].host, reusable_connection[slot].port, slot); reusable_connection[slot].in_use = 0; reusable_connection[slot].timestamp = connection->timestamp; break; } } privoxy_mutex_unlock(&connection_reuse_mutex); return socket_found; } /********************************************************************* * * Function : set_keep_alive_timeout * * Description : Sets the timeout after which open * connections will no longer be reused. * * Parameters : * 1 : timeout = The timeout in seconds. * * Returns : void * *********************************************************************/ void set_keep_alive_timeout(unsigned int timeout) { keep_alive_timeout = timeout; } #endif /* def FEATURE_CONNECTION_SHARING */ /********************************************************************* * * Function : forwarded_connect * * Description : Connect to a specified web server, possibly via * a HTTP proxy and/or a SOCKS proxy. * * Parameters : * 1 : fwd = the proxies to use when connecting. * 2 : http = the http request and apropos headers * 3 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_INVALID_SOCKET => failure, else it is the socket file descriptor. * *********************************************************************/ jb_socket forwarded_connect(const struct forward_spec * fwd, struct http_request *http, struct client_state *csp) { const char * dest_host; int dest_port; jb_socket sfd = JB_INVALID_SOCKET; #ifdef FEATURE_CONNECTION_SHARING if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING) && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { sfd = get_reusable_connection(http, fwd); if (JB_INVALID_SOCKET != sfd) { return sfd; } } #endif /* def FEATURE_CONNECTION_SHARING */ /* Figure out if we need to connect to the web server or a HTTP proxy. */ if (fwd->forward_host) { /* HTTP proxy */ dest_host = fwd->forward_host; dest_port = fwd->forward_port; } else { /* Web server */ dest_host = http->host; dest_port = http->port; } /* Connect, maybe using a SOCKS proxy */ switch (fwd->type) { case SOCKS_NONE: sfd = connect_to(dest_host, dest_port, csp); break; case SOCKS_4: case SOCKS_4A: sfd = socks4_connect(fwd, dest_host, dest_port, csp); break; case SOCKS_5: case SOCKS_5T: sfd = socks5_connect(fwd, dest_host, dest_port, csp); break; default: /* Should never get here */ log_error(LOG_LEVEL_FATAL, "Internal error in forwarded_connect(). Bad proxy type: %d", fwd->type); } if (JB_INVALID_SOCKET != sfd) { log_error(LOG_LEVEL_CONNECT, "Created new connection to %s:%d on socket %d.", http->host, http->port, sfd); } return sfd; } /********************************************************************* * * Function : socks4_connect * * Description : Connect to the SOCKS server, and connect through * it to the specified server. This handles * all the SOCKS negotiation, and returns a file * descriptor for a socket which can be treated as a * normal (non-SOCKS) socket. * * Logged error messages are saved to csp->error_message * and later reused by error_response() for the CGI * message. strdup allocation failures are handled there. * * Parameters : * 1 : fwd = Specifies the SOCKS proxy to use. * 2 : target_host = The final server to connect to. * 3 : target_port = The final port to connect to. * 4 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor. * *********************************************************************/ static jb_socket socks4_connect(const struct forward_spec * fwd, const char * target_host, int target_port, struct client_state *csp) { unsigned long web_server_addr; char buf[BUFFER_SIZE]; struct socks_op *c = (struct socks_op *)buf; struct socks_reply *s = (struct socks_reply *)buf; size_t n; size_t csiz; jb_socket sfd; int err = 0; char *errstr = NULL; if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0')) { /* XXX: Shouldn't the config file parser prevent this? */ errstr = "NULL gateway host specified."; err = 1; } if (fwd->gateway_port <= 0) { errstr = "invalid gateway port specified."; err = 1; } if (err) { log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); csp->error_message = strdup(errstr); errno = EINVAL; return(JB_INVALID_SOCKET); } /* build a socks request for connection to the web server */ strlcpy(&(c->userid), socks_userid, sizeof(buf) - sizeof(struct socks_op)); csiz = sizeof(*c) + sizeof(socks_userid) - sizeof(c->userid) - sizeof(c->padding); switch (fwd->type) { case SOCKS_4: web_server_addr = resolve_hostname_to_ip(target_host); if (web_server_addr == INADDR_NONE) { errstr = "could not resolve target host"; log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s %s", errstr, target_host); err = 1; } else { web_server_addr = htonl(web_server_addr); } break; case SOCKS_4A: web_server_addr = 0x00000001; n = csiz + strlen(target_host) + 1; if (n > sizeof(buf)) { errno = EINVAL; errstr = "buffer cbuf too small."; log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); err = 1; } else { strlcpy(buf + csiz, target_host, sizeof(buf) - sizeof(struct socks_op) - csiz); /* * What we forward to the socks4a server should have the * size of socks_op, plus the length of the userid plus * its \0 byte (which we don't have to add because the * first byte of the userid is counted twice as it's also * part of sock_op) minus the padding bytes (which are part * of the userid as well), plus the length of the target_host * (which is stored csiz bytes after the beginning of the buffer), * plus another \0 byte. */ assert(n == sizeof(struct socks_op) + strlen(&(c->userid)) - sizeof(c->padding) + strlen(buf + csiz) + 1); csiz = n; } break; default: /* Should never get here */ log_error(LOG_LEVEL_FATAL, "socks4_connect: SOCKS4 impossible internal error - bad SOCKS type."); /* Not reached */ return(JB_INVALID_SOCKET); } if (err) { csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } c->vn = 4; c->cd = 1; c->dstport[0] = (unsigned char)((target_port >> 8 ) & 0xff); c->dstport[1] = (unsigned char)((target_port ) & 0xff); c->dstip[0] = (unsigned char)((web_server_addr >> 24) & 0xff); c->dstip[1] = (unsigned char)((web_server_addr >> 16) & 0xff); c->dstip[2] = (unsigned char)((web_server_addr >> 8) & 0xff); c->dstip[3] = (unsigned char)((web_server_addr ) & 0xff); /* pass the request to the socks server */ sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); if (sfd == JB_INVALID_SOCKET) { /* The error an its reason have already been logged by connect_to() */ return(JB_INVALID_SOCKET); } else if (write_socket(sfd, (char *)c, csiz)) { errstr = "SOCKS4 negotiation write failed."; log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); err = 1; close_socket(sfd); } else if (!data_is_available(sfd, csp->config->socket_timeout)) { if (socket_is_still_alive(sfd)) { errstr = "SOCKS4 negotiation timed out"; } else { errstr = "SOCKS4 negotiation got aborted by the server"; } log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); err = 1; close_socket(sfd); } else if (read_socket(sfd, buf, sizeof(buf)) != sizeof(*s)) { errstr = "SOCKS4 negotiation read failed."; log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); err = 1; close_socket(sfd); } if (err) { csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } switch (s->cd) { case SOCKS4_REQUEST_GRANTED: return(sfd); case SOCKS4_REQUEST_REJECT: errstr = "SOCKS request rejected or failed."; errno = EINVAL; break; case SOCKS4_REQUEST_IDENT_FAILED: errstr = "SOCKS request rejected because " "SOCKS server cannot connect to identd on the client."; errno = EACCES; break; case SOCKS4_REQUEST_IDENT_CONFLICT: errstr = "SOCKS request rejected because " "the client program and identd report " "different user-ids."; errno = EACCES; break; default: errno = ENOENT; snprintf(buf, sizeof(buf), "SOCKS request rejected for reason code %d.", s->cd); errstr = buf; } log_error(LOG_LEVEL_CONNECT, "socks4_connect: %s", errstr); csp->error_message = strdup(errstr); close_socket(sfd); return(JB_INVALID_SOCKET); } /********************************************************************* * * Function : translate_socks5_error * * Description : Translates a SOCKS errors to a string. * * Parameters : * 1 : socks_error = The error code to translate. * * Returns : The string translation. * *********************************************************************/ static const char *translate_socks5_error(int socks_error) { switch (socks_error) { /* XXX: these should be more descriptive */ case SOCKS5_REQUEST_FAILED: return "SOCKS5 request failed"; case SOCKS5_REQUEST_DENIED: return "SOCKS5 request denied"; case SOCKS5_REQUEST_NETWORK_UNREACHABLE: return "SOCKS5 network unreachable"; case SOCKS5_REQUEST_HOST_UNREACHABLE: return "SOCKS5 host unreachable"; case SOCKS5_REQUEST_CONNECTION_REFUSED: return "SOCKS5 connection refused"; case SOCKS5_REQUEST_TTL_EXPIRED: return "SOCKS5 TTL expired"; case SOCKS5_REQUEST_PROTOCOL_ERROR: return "SOCKS5 client protocol error"; case SOCKS5_REQUEST_BAD_ADDRESS_TYPE: return "SOCKS5 domain names unsupported"; case SOCKS5_REQUEST_GRANTED: return "everything's peachy"; default: return "SOCKS5 negotiation protocol error"; } } /********************************************************************* * * Function : socks5_connect * * Description : Connect to the SOCKS server, and connect through * it to the specified server. This handles * all the SOCKS negotiation, and returns a file * descriptor for a socket which can be treated as a * normal (non-SOCKS) socket. * * Parameters : * 1 : fwd = Specifies the SOCKS proxy to use. * 2 : target_host = The final server to connect to. * 3 : target_port = The final port to connect to. * 4 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_INVALID_SOCKET => failure, else a socket file descriptor. * *********************************************************************/ static jb_socket socks5_connect(const struct forward_spec *fwd, const char *target_host, int target_port, struct client_state *csp) { int err = 0; char cbuf[300]; char sbuf[10]; size_t client_pos = 0; int server_size = 0; size_t hostlen = 0; jb_socket sfd; const char *errstr = NULL; assert(fwd->gateway_host); if ((fwd->gateway_host == NULL) || (*fwd->gateway_host == '\0')) { errstr = "NULL gateway host specified"; err = 1; } if (fwd->gateway_port <= 0) { /* * XXX: currently this can't happen because in * case of invalid gateway ports we use the defaults. * Of course we really shouldn't do that. */ errstr = "invalid gateway port specified"; err = 1; } hostlen = strlen(target_host); if (hostlen > (size_t)255) { errstr = "target host name is longer than 255 characters"; err = 1; } if ((fwd->type != SOCKS_5) && (fwd->type != SOCKS_5T)) { /* Should never get here */ log_error(LOG_LEVEL_FATAL, "SOCKS5 impossible internal error - bad SOCKS type"); err = 1; } if (err) { errno = EINVAL; assert(errstr != NULL); log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } /* pass the request to the socks server */ sfd = connect_to(fwd->gateway_host, fwd->gateway_port, csp); if (sfd == JB_INVALID_SOCKET) { errstr = "socks5 server unreachable"; log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); /* Free the generic error message provided by connect_to() */ freez(csp->error_message); csp->error_message = strdup(errstr); return(JB_INVALID_SOCKET); } client_pos = 0; cbuf[client_pos++] = '\x05'; /* Version */ cbuf[client_pos++] = '\x01'; /* One authentication method supported */ cbuf[client_pos++] = '\x00'; /* The no authentication authentication method */ if (write_socket(sfd, cbuf, client_pos)) { errstr = "SOCKS5 negotiation write failed"; csp->error_message = strdup(errstr); log_error(LOG_LEVEL_CONNECT, "%s", errstr); close_socket(sfd); return(JB_INVALID_SOCKET); } if (!data_is_available(sfd, csp->config->socket_timeout)) { if (socket_is_still_alive(sfd)) { errstr = "SOCKS5 negotiation timed out"; } else { errstr = "SOCKS5 negotiation got aborted by the server"; } err = 1; } if (!err && read_socket(sfd, sbuf, sizeof(sbuf)) != 2) { errstr = "SOCKS5 negotiation read failed"; err = 1; } if (!err && (sbuf[0] != '\x05')) { errstr = "SOCKS5 negotiation protocol version error"; err = 1; } if (!err && (sbuf[1] == '\xff')) { errstr = "SOCKS5 authentication required"; err = 1; } if (!err && (sbuf[1] != '\x00')) { errstr = "SOCKS5 negotiation protocol error"; err = 1; } if (err) { assert(errstr != NULL); log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); csp->error_message = strdup(errstr); close_socket(sfd); errno = EINVAL; return(JB_INVALID_SOCKET); } client_pos = 0; cbuf[client_pos++] = '\x05'; /* Version */ cbuf[client_pos++] = '\x01'; /* TCP connect */ cbuf[client_pos++] = '\x00'; /* Reserved, must be 0x00 */ cbuf[client_pos++] = '\x03'; /* Address is domain name */ cbuf[client_pos++] = (char)(hostlen & 0xffu); assert(sizeof(cbuf) - client_pos > (size_t)255); /* Using strncpy because we really want the nul byte padding. */ strncpy(cbuf + client_pos, target_host, sizeof(cbuf) - client_pos); client_pos += (hostlen & 0xffu); cbuf[client_pos++] = (char)((target_port >> 8) & 0xff); cbuf[client_pos++] = (char)((target_port ) & 0xff); if (write_socket(sfd, cbuf, client_pos)) { errstr = "SOCKS5 negotiation write failed"; csp->error_message = strdup(errstr); log_error(LOG_LEVEL_CONNECT, "%s", errstr); close_socket(sfd); errno = EINVAL; return(JB_INVALID_SOCKET); } /* * Optimistically send the request headers with the initial * request if the user requested use of Tor extensions, the * CONNECT method isn't being used (in which case the client * doesn't send data until it gets our 200 response) and the * client request has been already read completely. * * Not optimistically sending the request body (if there is one) * makes it easier to implement, but isn't an actual requirement. */ if ((fwd->type == SOCKS_5T) && (csp->http->ssl == 0) && (csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ)) { char *client_headers = list_to_text(csp->headers); size_t header_length; if (client_headers == NULL) { log_error(LOG_LEVEL_FATAL, "Out of memory rebuilding client headers"); } list_remove_all(csp->headers); header_length= strlen(client_headers); log_error(LOG_LEVEL_CONNECT, "Optimistically sending %d bytes of client headers intended for %s", header_length, csp->http->hostport); if (write_socket(sfd, client_headers, header_length)) { log_error(LOG_LEVEL_CONNECT, "optimistically writing header to: %s failed: %E", csp->http->hostport); freez(client_headers); return(JB_INVALID_SOCKET); } freez(client_headers); } server_size = read_socket(sfd, sbuf, sizeof(sbuf)); if (server_size != sizeof(sbuf)) { errstr = "SOCKS5 negotiation read failed"; } else { if (sbuf[0] != '\x05') { errstr = "SOCKS5 negotiation protocol version error"; } else if (sbuf[2] != '\x00') { errstr = "SOCKS5 negotiation protocol error"; } else if (sbuf[1] != SOCKS5_REQUEST_GRANTED) { errstr = translate_socks5_error(sbuf[1]); } else { return(sfd); } } assert(errstr != NULL); csp->error_message = strdup(errstr); log_error(LOG_LEVEL_CONNECT, "socks5_connect: %s", errstr); close_socket(sfd); errno = EINVAL; return(JB_INVALID_SOCKET); } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./urlmatch.c000640 001751 001751 00000110731 12060362753 015754 0ustar00fkfk000000 000000 const char urlmatch_rcs[] = "$Id: urlmatch.c,v 1.75 2012/12/07 12:49:47 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/urlmatch.c,v $ * * Purpose : Declares functions to match URLs against URL * patterns. * * Copyright : Written by and Copyright (C) 2001-2011 * the Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifndef _WIN32 #include #include #endif #include #include #include #include #if !defined(_WIN32) && !defined(__OS2__) #include #endif #include "project.h" #include "urlmatch.h" #include "ssplit.h" #include "miscutil.h" #include "errlog.h" const char urlmatch_h_rcs[] = URLMATCH_H_VERSION; enum regex_anchoring { NO_ANCHORING, LEFT_ANCHORED, RIGHT_ANCHORED, RIGHT_ANCHORED_HOST }; static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern); /********************************************************************* * * Function : free_http_request * * Description : Freez a http_request structure * * Parameters : * 1 : http = points to a http_request structure to free * * Returns : N/A * *********************************************************************/ void free_http_request(struct http_request *http) { assert(http); freez(http->cmd); freez(http->ocmd); freez(http->gpc); freez(http->host); freez(http->url); freez(http->hostport); freez(http->path); freez(http->ver); freez(http->host_ip_addr_str); #ifndef FEATURE_EXTENDED_HOST_PATTERNS freez(http->dbuffer); freez(http->dvec); http->dcount = 0; #endif } #ifndef FEATURE_EXTENDED_HOST_PATTERNS /********************************************************************* * * Function : init_domain_components * * Description : Splits the domain name so we can compare it * against wildcards. It used to be part of * parse_http_url, but was separated because the * same code is required in chat in case of * intercepted requests. * * Parameters : * 1 : http = pointer to the http structure to hold elements. * * Returns : JB_ERR_OK on success * JB_ERR_PARSE on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err init_domain_components(struct http_request *http) { char *vec[BUFFER_SIZE]; size_t size; char *p; http->dbuffer = strdup_or_die(http->host); /* map to lower case */ for (p = http->dbuffer; *p ; p++) { *p = (char)privoxy_tolower(*p); } /* split the domain name into components */ http->dcount = ssplit(http->dbuffer, ".", vec, SZ(vec)); if (http->dcount <= 0) { /* * Error: More than SZ(vec) components in domain * or: no components in domain */ log_error(LOG_LEVEL_ERROR, "More than SZ(vec) components in domain or none at all."); return JB_ERR_PARSE; } /* save a copy of the pointers in dvec */ size = (size_t)http->dcount * sizeof(*http->dvec); http->dvec = malloc_or_die(size); memcpy(http->dvec, vec, size); return JB_ERR_OK; } #endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */ /********************************************************************* * * Function : url_requires_percent_encoding * * Description : Checks if an URL contains invalid characters * according to RFC 3986 that should be percent-encoded. * Does not verify whether or not the passed string * actually is a valid URL. * * Parameters : * 1 : url = URL to check * * Returns : True in case of valid URLs, false otherwise * *********************************************************************/ int url_requires_percent_encoding(const char *url) { static const char allowed_characters[128] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '!', '\0', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '\0', '=', '\0', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\0', ']', '\0', '_', '\0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\0', '\0', '\0', '~', '\0' }; while (*url != '\0') { const unsigned int i = (unsigned char)*url++; if (i >= sizeof(allowed_characters) || '\0' == allowed_characters[i]) { return TRUE; } } return FALSE; } /********************************************************************* * * Function : parse_http_url * * Description : Parse out the host and port from the URL. Find the * hostname & path, port (if ':'), and/or password (if '@') * * Parameters : * 1 : url = URL (or is it URI?) to break down * 2 : http = pointer to the http structure to hold elements. * Must be initialized with valid values (like NULLs). * 3 : require_protocol = Whether or not URLs without * protocol are acceptable. * * Returns : JB_ERR_OK on success * JB_ERR_PARSE on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err parse_http_url(const char *url, struct http_request *http, int require_protocol) { int host_available = 1; /* A proxy can dream. */ /* * Save our initial URL */ http->url = strdup_or_die(url); /* * Check for * URI. If found, we're done. */ if (*http->url == '*') { http->path = strdup_or_die("*"); http->hostport = strdup_or_die(""); if (http->url[1] != '\0') { return JB_ERR_PARSE; } return JB_ERR_OK; } /* * Split URL into protocol,hostport,path. */ { char *buf; char *url_noproto; char *url_path; buf = strdup_or_die(url); /* Find the start of the URL in our scratch space */ url_noproto = buf; if (strncmpic(url_noproto, "http://", 7) == 0) { url_noproto += 7; } else if (strncmpic(url_noproto, "https://", 8) == 0) { /* * Should only happen when called from cgi_show_url_info(). */ url_noproto += 8; http->ssl = 1; } else if (*url_noproto == '/') { /* * Short request line without protocol and host. * Most likely because the client's request * was intercepted and redirected into Privoxy. */ http->host = NULL; host_available = 0; } else if (require_protocol) { freez(buf); return JB_ERR_PARSE; } url_path = strchr(url_noproto, '/'); if (url_path != NULL) { /* * Got a path. * * NOTE: The following line ignores the path for HTTPS URLS. * This means that you get consistent behaviour if you type a * https URL in and it's parsed by the function. (When the * URL is actually retrieved, SSL hides the path part). */ http->path = strdup_or_die(http->ssl ? "/" : url_path); *url_path = '\0'; http->hostport = strdup_or_die(url_noproto); } else { /* * Repair broken HTTP requests that don't contain a path, * or CONNECT requests */ http->path = strdup_or_die("/"); http->hostport = strdup_or_die(url_noproto); } freez(buf); } if (!host_available) { /* Without host, there is nothing left to do here */ return JB_ERR_OK; } /* * Split hostport into user/password (ignored), host, port. */ { char *buf; char *host; char *port; buf = strdup_or_die(http->hostport); /* check if url contains username and/or password */ host = strchr(buf, '@'); if (host != NULL) { /* Contains username/password, skip it and the @ sign. */ host++; } else { /* No username or password. */ host = buf; } /* Move after hostname before port number */ if (*host == '[') { /* Numeric IPv6 address delimited by brackets */ host++; port = strchr(host, ']'); if (port == NULL) { /* Missing closing bracket */ freez(buf); return JB_ERR_PARSE; } *port++ = '\0'; if (*port == '\0') { port = NULL; } else if (*port != ':') { /* Garbage after closing bracket */ freez(buf); return JB_ERR_PARSE; } } else { /* Plain non-escaped hostname */ port = strchr(host, ':'); } /* check if url contains port */ if (port != NULL) { /* Contains port */ char *endptr; long parsed_port; /* Terminate hostname and point to start of port string */ *port++ = '\0'; parsed_port = strtol(port, &endptr, 10); if ((parsed_port <= 0) || (parsed_port > 65535) || (*endptr != '\0')) { log_error(LOG_LEVEL_ERROR, "Invalid port in URL: %s.", url); freez(buf); return JB_ERR_PARSE; } http->port = (int)parsed_port; } else { /* No port specified. */ http->port = (http->ssl ? 443 : 80); } http->host = strdup_or_die(host); freez(buf); } #ifdef FEATURE_EXTENDED_HOST_PATTERNS return JB_ERR_OK; #else /* Split domain name so we can compare it against wildcards */ return init_domain_components(http); #endif /* def FEATURE_EXTENDED_HOST_PATTERNS */ } /********************************************************************* * * Function : unknown_method * * Description : Checks whether a method is unknown. * * Parameters : * 1 : method = points to a http method * * Returns : TRUE if it's unknown, FALSE otherwise. * *********************************************************************/ static int unknown_method(const char *method) { static const char * const known_http_methods[] = { /* Basic HTTP request type */ "GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "TRACE", "CONNECT", /* webDAV extensions (RFC2518) */ "PROPFIND", "PROPPATCH", "MOVE", "COPY", "MKCOL", "LOCK", "UNLOCK", /* * Microsoft webDAV extension for Exchange 2000. See: * http://lists.w3.org/Archives/Public/w3c-dist-auth/2002JanMar/0001.html * http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp */ "BCOPY", "BMOVE", "BDELETE", "BPROPFIND", "BPROPPATCH", /* * Another Microsoft webDAV extension for Exchange 2000. See: * http://systems.cs.colorado.edu/grunwald/MobileComputing/Papers/draft-cohen-gena-p-base-00.txt * http://lists.w3.org/Archives/Public/w3c-dist-auth/2002JanMar/0001.html * http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp */ "SUBSCRIBE", "UNSUBSCRIBE", "NOTIFY", "POLL", /* * Yet another WebDAV extension, this time for * Web Distributed Authoring and Versioning (RFC3253) */ "VERSION-CONTROL", "REPORT", "CHECKOUT", "CHECKIN", "UNCHECKOUT", "MKWORKSPACE", "UPDATE", "LABEL", "MERGE", "BASELINE-CONTROL", "MKACTIVITY", }; int i; for (i = 0; i < SZ(known_http_methods); i++) { if (0 == strcmpic(method, known_http_methods[i])) { return FALSE; } } return TRUE; } /********************************************************************* * * Function : parse_http_request * * Description : Parse out the host and port from the URL. Find the * hostname & path, port (if ':'), and/or password (if '@') * * Parameters : * 1 : req = HTTP request line to break down * 2 : http = pointer to the http structure to hold elements * * Returns : JB_ERR_OK on success * JB_ERR_CGI_PARAMS on malformed command/URL * or >100 domains deep. * *********************************************************************/ jb_err parse_http_request(const char *req, struct http_request *http) { char *buf; char *v[10]; /* XXX: Why 10? We should only need three. */ int n; jb_err err; memset(http, '\0', sizeof(*http)); buf = strdup_or_die(req); n = ssplit(buf, " \r\n", v, SZ(v)); if (n != 3) { freez(buf); return JB_ERR_PARSE; } /* * Fail in case of unknown methods * which we might not handle correctly. * * XXX: There should be a config option * to forward requests with unknown methods * anyway. Most of them don't need special * steps. */ if (unknown_method(v[0])) { log_error(LOG_LEVEL_ERROR, "Unknown HTTP method detected: %s", v[0]); freez(buf); return JB_ERR_PARSE; } if (strcmpic(v[2], "HTTP/1.1") && strcmpic(v[2], "HTTP/1.0")) { log_error(LOG_LEVEL_ERROR, "The only supported HTTP " "versions are 1.0 and 1.1. This rules out: %s", v[2]); freez(buf); return JB_ERR_PARSE; } http->ssl = !strcmpic(v[0], "CONNECT"); err = parse_http_url(v[1], http, !http->ssl); if (err) { freez(buf); return err; } /* * Copy the details into the structure */ http->cmd = strdup_or_die(req); http->gpc = strdup_or_die(v[0]); http->ver = strdup_or_die(v[2]); freez(buf); return JB_ERR_OK; } /********************************************************************* * * Function : compile_pattern * * Description : Compiles a host, domain or TAG pattern. * * Parameters : * 1 : pattern = The pattern to compile. * 2 : anchoring = How the regex should be modified * before compilation. Can be either * one of NO_ANCHORING, LEFT_ANCHORED, * RIGHT_ANCHORED or RIGHT_ANCHORED_HOST. * 3 : url = In case of failures, the spec member is * logged and the structure freed. * 4 : regex = Where the compiled regex should be stored. * * Returns : JB_ERR_OK - Success * JB_ERR_MEMORY - Out of memory * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_pattern(const char *pattern, enum regex_anchoring anchoring, struct url_spec *url, regex_t **regex) { int errcode; char rebuf[BUFFER_SIZE]; const char *fmt = NULL; assert(pattern); assert(strlen(pattern) < sizeof(rebuf) - 2); if (pattern[0] == '\0') { *regex = NULL; return JB_ERR_OK; } switch (anchoring) { case NO_ANCHORING: fmt = "%s"; break; case RIGHT_ANCHORED: fmt = "%s$"; break; case RIGHT_ANCHORED_HOST: fmt = "%s\\.?$"; break; case LEFT_ANCHORED: fmt = "^%s"; break; default: log_error(LOG_LEVEL_FATAL, "Invalid anchoring in compile_pattern %d", anchoring); } *regex = zalloc(sizeof(**regex)); if (NULL == *regex) { free_url_spec(url); return JB_ERR_MEMORY; } snprintf(rebuf, sizeof(rebuf), fmt, pattern); errcode = regcomp(*regex, rebuf, (REG_EXTENDED|REG_NOSUB|REG_ICASE)); if (errcode) { size_t errlen = regerror(errcode, *regex, rebuf, sizeof(rebuf)); if (errlen > (sizeof(rebuf) - (size_t)1)) { errlen = sizeof(rebuf) - (size_t)1; } rebuf[errlen] = '\0'; log_error(LOG_LEVEL_ERROR, "error compiling %s from %s: %s", pattern, url->spec, rebuf); free_url_spec(url); return JB_ERR_PARSE; } return JB_ERR_OK; } /********************************************************************* * * Function : compile_url_pattern * * Description : Compiles the three parts of an URL pattern. * * Parameters : * 1 : url = Target url_spec to be filled in. * 2 : buf = The url pattern to compile. Will be messed up. * * Returns : JB_ERR_OK - Success * JB_ERR_MEMORY - Out of memory * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_url_pattern(struct url_spec *url, char *buf) { char *p; p = strchr(buf, '/'); if (NULL != p) { /* * Only compile the regex if it consists of more than * a single slash, otherwise it wouldn't affect the result. */ if (p[1] != '\0') { /* * XXX: does it make sense to compile the slash at the beginning? */ jb_err err = compile_pattern(p, LEFT_ANCHORED, url, &url->preg); if (JB_ERR_OK != err) { return err; } } *p = '\0'; } /* * IPv6 numeric hostnames can contain colons, thus we need * to delimit the hostname before the real port separator. * As brackets are already used in the hostname pattern, * we use angle brackets ('<', '>') instead. */ if ((buf[0] == '<') && (NULL != (p = strchr(buf + 1, '>')))) { *p++ = '\0'; buf++; if (*p == '\0') { /* IPv6 address without port number */ p = NULL; } else if (*p != ':') { /* Garbage after address delimiter */ return JB_ERR_PARSE; } } else { p = strchr(buf, ':'); } if (NULL != p) { *p++ = '\0'; url->port_list = strdup_or_die(p); } else { url->port_list = NULL; } if (buf[0] != '\0') { return compile_host_pattern(url, buf); } return JB_ERR_OK; } #ifdef FEATURE_EXTENDED_HOST_PATTERNS /********************************************************************* * * Function : compile_host_pattern * * Description : Parses and compiles a host pattern. * * Parameters : * 1 : url = Target url_spec to be filled in. * 2 : host_pattern = Host pattern to compile. * * Returns : JB_ERR_OK - Success * JB_ERR_MEMORY - Out of memory * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern) { return compile_pattern(host_pattern, RIGHT_ANCHORED_HOST, url, &url->host_regex); } #else /********************************************************************* * * Function : compile_host_pattern * * Description : Parses and "compiles" an old-school host pattern. * * Parameters : * 1 : url = Target url_spec to be filled in. * 2 : host_pattern = Host pattern to parse. * * Returns : JB_ERR_OK - Success * JB_ERR_PARSE - Cannot parse regex * *********************************************************************/ static jb_err compile_host_pattern(struct url_spec *url, const char *host_pattern) { char *v[150]; size_t size; char *p; /* * Parse domain part */ if (host_pattern[strlen(host_pattern) - 1] == '.') { url->unanchored |= ANCHOR_RIGHT; } if (host_pattern[0] == '.') { url->unanchored |= ANCHOR_LEFT; } /* * Split domain into components */ url->dbuffer = strdup_or_die(host_pattern); /* * Map to lower case */ for (p = url->dbuffer; *p ; p++) { *p = (char)privoxy_tolower(*p); } /* * Split the domain name into components */ url->dcount = ssplit(url->dbuffer, ".", v, SZ(v)); if (url->dcount < 0) { free_url_spec(url); return JB_ERR_PARSE; } else if (url->dcount != 0) { /* * Save a copy of the pointers in dvec */ size = (size_t)url->dcount * sizeof(*url->dvec); url->dvec = malloc_or_die(size); memcpy(url->dvec, v, size); } /* * else dcount == 0 in which case we needn't do anything, * since dvec will never be accessed and the pattern will * match all domains. */ return JB_ERR_OK; } /********************************************************************* * * Function : simplematch * * Description : String matching, with a (greedy) '*' wildcard that * stands for zero or more arbitrary characters and * character classes in [], which take both enumerations * and ranges. * * Parameters : * 1 : pattern = pattern for matching * 2 : text = text to be matched * * Returns : 0 if match, else nonzero * *********************************************************************/ static int simplematch(const char *pattern, const char *text) { const unsigned char *pat = (const unsigned char *)pattern; const unsigned char *txt = (const unsigned char *)text; const unsigned char *fallback = pat; int wildcard = 0; unsigned char lastchar = 'a'; unsigned i; unsigned char charmap[32]; while (*txt) { /* EOF pattern but !EOF text? */ if (*pat == '\0') { if (wildcard) { pat = fallback; } else { return 1; } } /* '*' in the pattern? */ if (*pat == '*') { /* The pattern ends afterwards? Speed up the return. */ if (*++pat == '\0') { return 0; } /* Else, set wildcard mode and remember position after '*' */ wildcard = 1; fallback = pat; } /* Character range specification? */ if (*pat == '[') { memset(charmap, '\0', sizeof(charmap)); while (*++pat != ']') { if (!*pat) { return 1; } else if (*pat == '-') { if ((*++pat == ']') || *pat == '\0') { return(1); } for (i = lastchar; i <= *pat; i++) { charmap[i / 8] |= (unsigned char)(1 << (i % 8)); } } else { charmap[*pat / 8] |= (unsigned char)(1 << (*pat % 8)); lastchar = *pat; } } } /* -END- if Character range specification */ /* * Char match, or char range match? */ if ((*pat == *txt) || (*pat == '?') || ((*pat == ']') && (charmap[*txt / 8] & (1 << (*txt % 8))))) { /* * Success: Go ahead */ pat++; } else if (!wildcard) { /* * No match && no wildcard: No luck */ return 1; } else if (pat != fallback) { /* * Increment text pointer if in char range matching */ if (*pat == ']') { txt++; } /* * Wildcard mode && nonmatch beyond fallback: Rewind pattern */ pat = fallback; /* * Restart matching from current text pointer */ continue; } txt++; } /* Cut off extra '*'s */ if (*pat == '*') pat++; /* If this is the pattern's end, fine! */ return(*pat); } /********************************************************************* * * Function : simple_domaincmp * * Description : Domain-wise Compare fqdn's. The comparison is * both left- and right-anchored. The individual * domain names are compared with simplematch(). * This is only used by domain_match. * * Parameters : * 1 : pv = array of patterns to compare * 2 : fv = array of domain components to compare * 3 : len = length of the arrays (both arrays are the * same length - if they weren't, it couldn't * possibly be a match). * * Returns : 0 => domains are equivalent, else no match. * *********************************************************************/ static int simple_domaincmp(char **pv, char **fv, int len) { int n; for (n = 0; n < len; n++) { if (simplematch(pv[n], fv[n])) { return 1; } } return 0; } /********************************************************************* * * Function : domain_match * * Description : Domain-wise Compare fqdn's. Governed by the bimap in * pattern->unachored, the comparison is un-, left-, * right-anchored, or both. * The individual domain names are compared with * simplematch(). * * Parameters : * 1 : pattern = a domain that may contain a '*' as a wildcard. * 2 : fqdn = domain name against which the patterns are compared. * * Returns : 0 => domains are equivalent, else no match. * *********************************************************************/ static int domain_match(const struct url_spec *pattern, const struct http_request *fqdn) { char **pv, **fv; /* vectors */ int plen, flen; int unanchored = pattern->unanchored & (ANCHOR_RIGHT | ANCHOR_LEFT); plen = pattern->dcount; flen = fqdn->dcount; if (flen < plen) { /* fqdn is too short to match this pattern */ return 1; } pv = pattern->dvec; fv = fqdn->dvec; if (unanchored == ANCHOR_LEFT) { /* * Right anchored. * * Convert this into a fully anchored pattern with * the fqdn and pattern the same length */ fv += (flen - plen); /* flen - plen >= 0 due to check above */ return simple_domaincmp(pv, fv, plen); } else if (unanchored == 0) { /* Fully anchored, check length */ if (flen != plen) { return 1; } return simple_domaincmp(pv, fv, plen); } else if (unanchored == ANCHOR_RIGHT) { /* Left anchored, ignore all extra in fqdn */ return simple_domaincmp(pv, fv, plen); } else { /* Unanchored */ int n; int maxn = flen - plen; for (n = 0; n <= maxn; n++) { if (!simple_domaincmp(pv, fv, plen)) { return 0; } /* * Doesn't match from start of fqdn * Try skipping first part of fqdn */ fv++; } return 1; } } #endif /* def FEATURE_EXTENDED_HOST_PATTERNS */ /********************************************************************* * * Function : create_url_spec * * Description : Creates a "url_spec" structure from a string. * When finished, free with free_url_spec(). * * Parameters : * 1 : url = Target url_spec to be filled in. Will be * zeroed before use. * 2 : buf = Source pattern, null terminated. NOTE: The * contents of this buffer are destroyed by this * function. If this function succeeds, the * buffer is copied to url->spec. If this * function fails, the contents of the buffer * are lost forever. * * Returns : JB_ERR_OK - Success * JB_ERR_PARSE - Cannot parse regex (Detailed message * written to system log) * *********************************************************************/ jb_err create_url_spec(struct url_spec *url, char *buf) { assert(url); assert(buf); memset(url, '\0', sizeof(*url)); /* Remember the original specification for the CGI pages. */ url->spec = strdup_or_die(buf); /* Is it a tag pattern? */ if (0 == strncmpic(url->spec, "TAG:", 4)) { /* The pattern starts with the first character after "TAG:" */ const char *tag_pattern = buf + 4; return compile_pattern(tag_pattern, NO_ANCHORING, url, &url->tag_regex); } /* If it isn't a tag pattern it must be an URL pattern. */ return compile_url_pattern(url, buf); } /********************************************************************* * * Function : free_url_spec * * Description : Called from the "unloaders". Freez the url * structure elements. * * Parameters : * 1 : url = pointer to a url_spec structure. * * Returns : N/A * *********************************************************************/ void free_url_spec(struct url_spec *url) { if (url == NULL) return; freez(url->spec); #ifdef FEATURE_EXTENDED_HOST_PATTERNS if (url->host_regex) { regfree(url->host_regex); freez(url->host_regex); } #else freez(url->dbuffer); freez(url->dvec); url->dcount = 0; #endif /* ndef FEATURE_EXTENDED_HOST_PATTERNS */ freez(url->port_list); if (url->preg) { regfree(url->preg); freez(url->preg); } if (url->tag_regex) { regfree(url->tag_regex); freez(url->tag_regex); } } /********************************************************************* * * Function : port_matches * * Description : Compares a port against a port list. * * Parameters : * 1 : port = The port to check. * 2 : port_list = The list of port to compare with. * * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ static int port_matches(const int port, const char *port_list) { return ((NULL == port_list) || match_portlist(port_list, port)); } /********************************************************************* * * Function : host_matches * * Description : Compares a host against a host pattern. * * Parameters : * 1 : url = The URL to match * 2 : pattern = The URL pattern * * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ static int host_matches(const struct http_request *http, const struct url_spec *pattern) { #ifdef FEATURE_EXTENDED_HOST_PATTERNS return ((NULL == pattern->host_regex) || (0 == regexec(pattern->host_regex, http->host, 0, NULL, 0))); #else return ((NULL == pattern->dbuffer) || (0 == domain_match(pattern, http))); #endif } /********************************************************************* * * Function : path_matches * * Description : Compares a path against a path pattern. * * Parameters : * 1 : path = The path to match * 2 : pattern = The URL pattern * * Returns : TRUE for yes, FALSE otherwise. * *********************************************************************/ static int path_matches(const char *path, const struct url_spec *pattern) { return ((NULL == pattern->preg) || (0 == regexec(pattern->preg, path, 0, NULL, 0))); } /********************************************************************* * * Function : url_match * * Description : Compare a URL against a URL pattern. * * Parameters : * 1 : pattern = a URL pattern * 2 : url = URL to match * * Returns : Nonzero if the URL matches the pattern, else 0. * *********************************************************************/ int url_match(const struct url_spec *pattern, const struct http_request *http) { if (pattern->tag_regex != NULL) { /* It's a tag pattern and shouldn't be matched against URLs */ return 0; } return (port_matches(http->port, pattern->port_list) && host_matches(http, pattern) && path_matches(http->path, pattern)); } /********************************************************************* * * Function : match_portlist * * Description : Check if a given number is covered by a comma * separated list of numbers and ranges (a,b-c,d,..) * * Parameters : * 1 : portlist = String with list * 2 : port = port to check * * Returns : 0 => no match * 1 => match * *********************************************************************/ int match_portlist(const char *portlist, int port) { char *min, *max, *next, *portlist_copy; min = portlist_copy = strdup_or_die(portlist); /* * Zero-terminate first item and remember offset for next */ if (NULL != (next = strchr(portlist_copy, (int) ','))) { *next++ = '\0'; } /* * Loop through all items, checking for match */ while (NULL != min) { if (NULL == (max = strchr(min, (int) '-'))) { /* * No dash, check for equality */ if (port == atoi(min)) { freez(portlist_copy); return(1); } } else { /* * This is a range, so check if between min and max, * or, if max was omitted, between min and 65K */ *max++ = '\0'; if (port >= atoi(min) && port <= (atoi(max) ? atoi(max) : 65535)) { freez(portlist_copy); return(1); } } /* * Jump to next item */ min = next; /* * Zero-terminate next item and remember offset for n+1 */ if ((NULL != next) && (NULL != (next = strchr(next, (int) ',')))) { *next++ = '\0'; } } freez(portlist_copy); return 0; } /********************************************************************* * * Function : parse_forwarder_address * * Description : Parse out the host and port from a forwarder address. * * Parameters : * 1 : address = The forwarder address to parse. * 2 : hostname = Used to return the hostname. NULL on error. * 3 : port = Used to return the port. Untouched if no port * is specified. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out of memory * JB_ERR_PARSE on malformed address. * *********************************************************************/ jb_err parse_forwarder_address(char *address, char **hostname, int *port) { char *p = address; if ((*address == '[') && (NULL == strchr(address, ']'))) { /* XXX: Should do some more validity checks here. */ return JB_ERR_PARSE; } *hostname = strdup_or_die(address); if ((**hostname == '[') && (NULL != (p = strchr(*hostname, ']')))) { *p++ = '\0'; memmove(*hostname, (*hostname + 1), (size_t)(p - *hostname)); if (*p == ':') { *port = (int)strtol(++p, NULL, 0); } } else if (NULL != (p = strchr(*hostname, ':'))) { *p++ = '\0'; *port = (int)strtol(p, NULL, 0); } return JB_ERR_OK; } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./w32log.c000640 001751 001751 00000110117 11760446001 015243 0ustar00fkfk000000 000000 const char w32log_rcs[] = "$Id: w32log.c,v 1.48 2012/05/27 15:45:05 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/w32log.c,v $ * * Purpose : Functions for creating and destroying the log window, * ouputting strings, processing messages and so on. * * Copyright : Written by and Copyright (C) 2001-2009 members of * the Privoxy team. http://www.privoxy.org/ * * Written by and Copyright (C) 1999 Adam Lock * * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #ifndef STRICT #define STRICT #endif #include #include #include "project.h" #include "w32log.h" #include "w32taskbar.h" #include "win32.h" #include "w32res.h" #include "jcc.h" #include "miscutil.h" #include "errlog.h" #include "loadcfg.h" const char w32res_h_rcs[] = W32RES_H_VERSION; #ifdef __MINGW32__ #include "cygwin.h" const char cygwin_h_rcs[] = CYGWIN_H_VERSION; #endif const char w32log_h_rcs[] = W32LOG_H_VERSION; #ifndef _WIN_CONSOLE /* entire file */ /* * Timers and the various durations */ #define TIMER_ANIM_ID 1 #define TIMER_ANIM_TIME 100 #define TIMER_ANIMSTOP_ID 2 #define TIMER_ANIMSTOP_TIME 1000 #define TIMER_CLIPBUFFER_ID 3 #define TIMER_CLIPBUFFER_TIME 1000 #define TIMER_CLIPBUFFER_FORCE_ID 4 #define TIMER_CLIPBUFFER_FORCE_TIME 5000 /* * Styles of text that can be output */ #define STYLE_NONE 0 #define STYLE_HIGHLIGHT 1 #define STYLE_LINK 2 #define STYLE_HEADER 3 /* * Number of frames of animation in tray activity sequence */ #define ANIM_FRAMES 8 #define DEFAULT_MAX_BUFFER_LINES 200 #define DEFAULT_LOG_FONT_NAME "MS Sans Serif" #define DEFAULT_LOG_FONT_SIZE 8 /* * These values affect the way the log window behaves, they should be read * from a file but for the moment, they are hardcoded here. Some options are * configurable through the UI. */ /* Indicates whether task bar shows activity animation */ BOOL g_bShowActivityAnimation = 1; /* Indicates whether the log window is shown */ BOOL g_bShowLogWindow = 1; /* Indicates if the log window appears on the task bar */ BOOL g_bShowOnTaskBar = 0; /* Indicates whether closing the log window really just hides it */ BOOL g_bCloseHidesWindow = 1; /* Indicates if messages are logged at all */ BOOL g_bLogMessages = 1; /* Indicates whether log messages are highlighted */ BOOL g_bHighlightMessages = 1; /* Indicates if buffer is limited in size */ BOOL g_bLimitBufferSize = 1; /* Maximum number of lines allowed in buffer when limited */ int g_nMaxBufferLines = DEFAULT_MAX_BUFFER_LINES; /* Font to use */ char g_szFontFaceName[32] = DEFAULT_LOG_FONT_NAME; /* Size of font to use */ int g_nFontSize = DEFAULT_LOG_FONT_SIZE; /* FIXME: this is a kludge */ const char * g_default_actions_file = NULL; const char * g_user_actions_file = NULL; const char * g_default_filterfile = NULL; const char * g_user_filterfile = NULL; #ifdef FEATURE_TRUST const char * g_trustfile = NULL; #endif /* def FEATURE_TRUST */ /* FIXME: end kludge */ /* Regular expression for detected URLs */ #define RE_URL "http:[^ \n\r]*" /* * Regular expressions that are used to perform highlight in the log window */ static struct _Pattern { const char *str; int style; regex_t buffer; } patterns_to_highlight[] = { /* url headers */ { RE_URL, STYLE_LINK }, /* { "[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[^ \n\r]*", STYLE_LINK }, */ /* interesting text to highlight */ /* see jcc.c crunch_reason for the full list */ { "Crunch: Blocked:", STYLE_HIGHLIGHT }, { "Crunch: Untrusted", STYLE_HIGHLIGHT }, { "Crunch: Redirected:", STYLE_HIGHLIGHT }, { "Crunch: DNS failure", STYLE_HIGHLIGHT }, { "Crunch: Forwarding failed", STYLE_HIGHLIGHT }, { "Crunch: Connection failure", STYLE_HIGHLIGHT }, { "Crunch: Out of memory", STYLE_HIGHLIGHT }, { "Connect: Found reusable socket", STYLE_HIGHLIGHT }, { "Connect: Reusing server socket", STYLE_HIGHLIGHT }, { "Connect: Created new connection to", STYLE_HIGHLIGHT }, { "hung up on us", STYLE_HIGHLIGHT }, { "Crunching Referer:", STYLE_HIGHLIGHT }, /* what are all the possible error strings?? */ { "Error:", STYLE_HIGHLIGHT }, /* http headers */ { "referer:", STYLE_HEADER }, { "proxy-connection:", STYLE_HEADER }, { "proxy-agent:", STYLE_HEADER }, { "user-agent:", STYLE_HEADER }, { "host:", STYLE_HEADER }, { "accept:", STYLE_HEADER }, { "accept-encoding:", STYLE_HEADER }, { "accept-language:", STYLE_HEADER }, { "accept-charset:", STYLE_HEADER }, { "accept-ranges:", STYLE_HEADER }, { "date:", STYLE_HEADER }, { "cache-control:", STYLE_HEADER }, { "cache-last-checked:", STYLE_HEADER }, { "connection:", STYLE_HEADER }, { "content-type", STYLE_HEADER }, { "content-length", STYLE_HEADER }, { "cookie", STYLE_HEADER }, { "last-modified:", STYLE_HEADER }, { "pragma:", STYLE_HEADER }, { "server:", STYLE_HEADER }, { "etag:", STYLE_HEADER }, { "expires:", STYLE_HEADER }, { "warning:", STYLE_HEADER }, /* this is the terminator statement - do not delete! */ { NULL, STYLE_NONE } }; /* * Public variables */ HWND g_hwndLogFrame; HICON g_hiconApp; /* * Private variables */ static CRITICAL_SECTION g_criticalsection; static HWND g_hwndTray; static HWND g_hwndLogBox; static WNDPROC g_fnLogBox; static HICON g_hiconAnim[ANIM_FRAMES]; static HICON g_hiconIdle; static HICON g_hiconOff; static int g_nAnimFrame; static BOOL g_bClipPending = FALSE; static int g_nRichEditVersion = 0; /* * Private functions */ static HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow); static HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance); static LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static BOOL InitRichEdit(void); static void LogClipBuffer(void); static void LogCreatePatternMatchingBuffers(void); static void LogDestroyPatternMatchingBuffers(void); static int LogPutStringNoMatch(const char *pszText, int style); static void SetIdleIcon(void); /********************************************************************* * * Function : InitLogWindow * * Description : Initialise the log window. * * Parameters : None * * Returns : Always TRUE (there should be error checking on the resources). * *********************************************************************/ BOOL InitLogWindow(void) { int i; /* Load the icons */ g_hiconIdle = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IDLE)); g_hiconOff = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_OFF)); for (i = 0; i < ANIM_FRAMES; i++) { g_hiconAnim[i] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ANIMATED1 + i)); } g_hiconApp = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAINICON)); /* Create the user interface */ g_hwndLogFrame = CreateLogWindow(g_hInstance, g_nCmdShow); g_hwndTray = CreateTrayWindow(g_hInstance); TrayAddIcon(g_hwndTray, 1, g_hiconApp, "Privoxy"); /* Create pattern matching buffers (for highlighting */ LogCreatePatternMatchingBuffers(); /* Create a critical section to protect multi-threaded access to certain things */ InitializeCriticalSection(&g_criticalsection); return TRUE; } /********************************************************************* * * Function : TermLogWindow * * Description : Cleanup the logwindow. * * Parameters : None * * Returns : N/A * *********************************************************************/ void TermLogWindow(void) { int i; LogDestroyPatternMatchingBuffers(); TrayDeleteIcon(g_hwndTray, 1); DeleteObject(g_hiconApp); DeleteObject(g_hiconIdle); DeleteObject(g_hiconOff); for (i = 0; i < ANIM_FRAMES; i++) { DeleteObject(g_hiconAnim[i]); } } /********************************************************************* * * Function : LogCreatePatternMatchingBuffers * * Description : Compile the pattern matching buffers. * * Parameters : None * * Returns : N/A * *********************************************************************/ void LogCreatePatternMatchingBuffers(void) { int i; for (i = 0; patterns_to_highlight[i].str != NULL; i++) { regcomp(&patterns_to_highlight[i].buffer, patterns_to_highlight[i].str, REG_ICASE); } } /********************************************************************* * * Function : LogDestroyPatternMatchingBuffers * * Description : Free up the pattern matching buffers. * * Parameters : None * * Returns : N/A * *********************************************************************/ void LogDestroyPatternMatchingBuffers(void) { int i; for (i = 0; patterns_to_highlight[i].str != NULL; i++) { regfree(&patterns_to_highlight[i].buffer); } } /********************************************************************* * * Function : LogPutString * * Description : Inserts text into the logging window. This is really * a regexp aware wrapper function to `LogPutStringNoMatch'. * * Parameters : * 1 : pszText = pointer to string going to the log window * * Returns : 1 => success, else the return code from `LogPutStringNoMatch'. * FIXME: this is backwards to the rest of IJB and to common * programming practice. Please use 0 => success instead. * *********************************************************************/ int LogPutString(const char *pszText) { int i; int result = 0; if (!g_bLogMessages) { return 1; } if (pszText == NULL || strlen(pszText) == 0) { return 1; } /* Critical section stops multiple threads doing nasty interactions that * foul up the highlighting and output. */ EnterCriticalSection(&g_criticalsection); if (g_bHighlightMessages) { regmatch_t match; /* First things first, regexp scan for various things that we would like highlighted */ for (i = 0; patterns_to_highlight[i].str != NULL; i++) { if (regexec(&patterns_to_highlight[i].buffer, pszText, 1, &match, 0) == 0) { char *pszBefore = NULL; char *pszMatch = NULL; char *pszAfter = NULL; int nMatchSize; /* Split the string up into pieces representing the strings, before at and after the matching pattern */ if (match.rm_so > 0) { pszBefore = (char *)malloc((match.rm_so + 1) * sizeof(char)); memset(pszBefore, 0, (match.rm_so + 1) * sizeof(char)); strncpy(pszBefore, pszText, match.rm_so); } if (match.rm_eo < (regoff_t)strlen(pszText)) { pszAfter = strdup(&pszText[match.rm_eo]); } nMatchSize = match.rm_eo - match.rm_so; pszMatch = (char *)malloc(nMatchSize + 1); strncpy(pszMatch, &pszText[match.rm_so], nMatchSize); pszMatch[nMatchSize] = '\0'; /* Recursively call LogPutString */ if (pszBefore) { LogPutString(pszBefore); free(pszBefore); } if (pszMatch) { LogPutStringNoMatch(pszMatch, patterns_to_highlight[i].style); free(pszMatch); } if (pszAfter) { LogPutString(pszAfter); free(pszAfter); } result = 1; goto end; } } } result = LogPutStringNoMatch(pszText, STYLE_NONE); end: LeaveCriticalSection(&g_criticalsection); return result; } /********************************************************************* * * Function : LogPutStringNoMatch * * Description : Puts a string into the logging window. * * Parameters : * 1 : pszText = pointer to string going to the log window * 2 : style = STYLE_NONE, STYLE_HEADER, STYLE_HIGHLIGHT, or STYLE_LINK * * Returns : Always 1 => success. * FIXME: this is backwards to the rest of IJB and to common * programming practice. Please use 0 => success instead. * *********************************************************************/ int LogPutStringNoMatch(const char *pszText, int style) { CHARRANGE range; CHARFORMAT format; int nTextLength; assert(g_hwndLogBox); if (g_hwndLogBox == NULL) { return 1; } /* TODO preserve existing selection */ /* Go to the end of the text */ nTextLength = GetWindowTextLength(g_hwndLogBox); range.cpMin = nTextLength; range.cpMax = nTextLength; SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range); /* Apply a formatting style */ memset(&format, 0, sizeof(format)); format.cbSize = sizeof(format); format.dwMask = CFM_BOLD | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_ITALIC | CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_CHARSET; format.bCharSet = DEFAULT_CHARSET; format.yHeight = (g_nFontSize * 1440) / 72; strlcpy(format.szFaceName, g_szFontFaceName, sizeof(format.szFaceName)); if (style == STYLE_NONE) { /* DO NOTHING */ format.dwEffects |= CFE_AUTOCOLOR; } else if (style == STYLE_HEADER) { format.dwEffects |= CFE_AUTOCOLOR | CFE_ITALIC; } else if (style == STYLE_HIGHLIGHT) { format.dwEffects |= CFE_AUTOCOLOR | CFE_BOLD; } else if (style == STYLE_LINK) { format.dwEffects |= CFE_UNDERLINE; format.crTextColor = RGB(0, 0, 255); } SendMessage(g_hwndLogBox, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &format); /* Append text to the end */ SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) pszText); /* TODO Restore the old selection */ /* Purge buffer */ if (strchr(pszText, '\n') != NULL) { SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID, TIMER_CLIPBUFFER_TIME, NULL); if (!g_bClipPending) { /* Set the force clip timer going. This timer ensures clipping is done intermittently even when there is a sustained burst of logging */ SetTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID, TIMER_CLIPBUFFER_FORCE_TIME, NULL); } g_bClipPending = TRUE; } return 1; } /********************************************************************* * * Function : LogShowActivity * * Description : Start the spinner. * * Parameters : None * * Returns : N/A * *********************************************************************/ void LogShowActivity(void) { /* Start some activity timers */ if (g_bShowActivityAnimation) { SetTimer(g_hwndLogFrame, TIMER_ANIM_ID, TIMER_ANIM_TIME, NULL); SetTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID, TIMER_ANIMSTOP_TIME, NULL); } } /********************************************************************* * * Function : LogClipBuffer * * Description : Prunes old lines from the log. * * Parameters : None * * Returns : N/A * *********************************************************************/ void LogClipBuffer(void) { int nLines = SendMessage(g_hwndLogBox, EM_GETLINECOUNT, 0, 0); if (g_bLimitBufferSize && nLines > g_nMaxBufferLines) { /* Compute the range representing the lines to be deleted */ LONG nLastLineToDelete = nLines - g_nMaxBufferLines; LONG nLastChar = SendMessage(g_hwndLogBox, EM_LINEINDEX, nLastLineToDelete, 0); CHARRANGE range; range.cpMin = 0; range.cpMax = nLastChar; /* TODO get current selection */ /* TODO adjust and clip old selection against range to be deleted */ /* Select range and erase it (turning off autoscroll to prevent nasty scrolling) */ SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL); SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range); SendMessage(g_hwndLogBox, EM_REPLACESEL, FALSE, (LPARAM) ""); SendMessage(g_hwndLogBox, EM_SETOPTIONS, ECOOP_XOR, ECO_AUTOVSCROLL); /* reposition (back to) the end of the log content */ range.cpMin = SendMessage (g_hwndLogBox, WM_GETTEXTLENGTH, 0, 0); range.cpMax = -1; SendMessage(g_hwndLogBox, EM_EXSETSEL, 0, (LPARAM) &range); /* restore vertical ScrollBar stuff (messed up by AUTOVSCROLL) */ SendMessage (g_hwndLogBox, EM_SCROLL, SB_LINEDOWN, 0); } } /********************************************************************* * * Function : CreateHiddenLogOwnerWindow * * Description : Creates a hidden owner window that stops the log * window appearing in the task bar. * * Parameters : * 1 : hInstance = application's instance handle * * Returns : Handle to newly created window. * *********************************************************************/ HWND CreateHiddenLogOwnerWindow(HINSTANCE hInstance) { static const char *szWndName = "PrivoxyLogOwner"; WNDCLASS wc; HWND hwnd; wc.style = 0; wc.lpfnWndProc = LogOwnerWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = g_hiconApp; wc.hCursor = 0; wc.hbrBackground = 0; wc.lpszMenuName = 0; wc.lpszClassName = szWndName; RegisterClass(&wc); hwnd = CreateWindow(szWndName, szWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); return hwnd; } /********************************************************************* * * Function : LogOwnerWindowProc * * Description : Dummy procedure that does nothing special. * * Parameters : * 1 : hwnd = window handle * 2 : uMsg = message number * 3 : wParam = first param for this message * 4 : lParam = next param for this message * * Returns : Same as `DefWindowProc'. * *********************************************************************/ LRESULT CALLBACK LogOwnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } /********************************************************************* * * Function : CreateLogWindow * * Description : Create the logging window. * * Parameters : * 1 : hInstance = application's instance handle * 2 : nCmdShow = window show value (MIN, MAX, NORMAL, etc...) * * Returns : Handle to newly created window. * *********************************************************************/ HWND CreateLogWindow(HINSTANCE hInstance, int nCmdShow) { static const char *szWndName = "PrivoxyLogWindow"; static const char *szWndTitle = "Privoxy"; HWND hwnd = NULL; HWND hwndOwner = (g_bShowOnTaskBar) ? NULL : CreateHiddenLogOwnerWindow(hInstance); RECT rcClient; WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_DBLCLKS; wc.lpfnWndProc = LogWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = g_hiconApp; wc.hCursor = 0; wc.hbrBackground = 0; wc.lpszMenuName = MAKEINTRESOURCE(IDR_LOGVIEW); wc.lpszClassName = szWndName; wc.hbrBackground = GetStockObject(WHITE_BRUSH); RegisterClassEx(&wc); hwnd = CreateWindowEx(WS_EX_APPWINDOW, szWndName, szWndTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, NULL, hInstance, NULL); /* Now create a child list box */ GetClientRect(hwnd, &rcClient); /* Create a rich edit control */ InitRichEdit(); g_hwndLogBox = CreateWindowEx(0, (g_nRichEditVersion == 0x0100) ? "RichEdit" : RICHEDIT_CLASS, "", ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY | ES_NOHIDESEL | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom, hwnd, NULL, hInstance, NULL); /* SendMessage(g_hwndLogBox, EM_SETWORDWRAPMODE, 0, 0); */ /* Subclass the control to catch certain messages */ g_fnLogBox = (WNDPROC) GetWindowLong(g_hwndLogBox, GWL_WNDPROC); SetWindowLong(g_hwndLogBox, GWL_WNDPROC, (LONG) LogRichEditProc); /* Minimizing looks stupid when the log window is not on the task bar, so hide instead */ if (!g_bShowOnTaskBar && (nCmdShow == SW_SHOWMINIMIZED || nCmdShow == SW_MINIMIZE || nCmdShow == SW_SHOWMINNOACTIVE)) { g_bShowLogWindow = FALSE; nCmdShow = SW_HIDE; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); GetClientRect(g_hwndLogFrame, &rcClient); SetWindowPos(g_hwndLogBox, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_NOZORDER); return hwnd; } /********************************************************************* * * Function : InitRichEdit * * Description : Initialise the rich edit control library. * * Parameters : None * * Returns : TRUE => success, FALSE => failure. * FIXME: this is backwards to the rest of IJB and to common * programming practice. Please use 0 => success instead. * *********************************************************************/ BOOL InitRichEdit(void) { static HINSTANCE hInstRichEdit; if (hInstRichEdit == NULL) { g_nRichEditVersion = 0; hInstRichEdit = LoadLibraryA("RICHED20.DLL"); if (hInstRichEdit) { g_nRichEditVersion = _RICHEDIT_VER; } else { hInstRichEdit = LoadLibraryA("RICHED32.DLL"); if (hInstRichEdit) { g_nRichEditVersion = 0x0100; } } } return (hInstRichEdit != NULL) ? TRUE : FALSE; } /********************************************************************* * * Function : ShowLogWindow * * Description : Shows or hides the log window. We will also raise the * window on a show command in case it is buried. * * Parameters : * 1 : bShow = TRUE to show, FALSE to mimize/hide * * Returns : N/A * *********************************************************************/ void ShowLogWindow(BOOL bShow) { if (bShow) { SetForegroundWindow(g_hwndLogFrame); SetWindowPos(g_hwndLogFrame, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); } else if (g_bShowOnTaskBar) { ShowWindow(g_hwndLogFrame, SW_MINIMIZE); } else { ShowWindow(g_hwndLogFrame, SW_HIDE); } } /********************************************************************* * * Function : EditFile * * Description : Opens the specified setting file for editing. * FIXME: What if the file has no associated application. Check for return values * from ShellExecute?? * * Parameters : * 1 : filename = filename from the config (aka config.txt) file. * * Returns : N/A * *********************************************************************/ void EditFile(const char *filename) { if (filename) { ShellExecute(g_hwndLogFrame, "open", filename, NULL, NULL, SW_SHOWNORMAL); } } /*--------------------------------------------------------------------------*/ /* Windows message handlers */ /*--------------------------------------------------------------------------*/ /********************************************************************* * * Function : OnLogRButtonUp * * Description : Handler for WM_RBUTTONUP messages. * * Parameters : * 1 : nModifier = wParam from mouse message (unused) * 2 : x = x coordinate of the mouse event * 3 : y = y coordinate of the mouse event * * Returns : N/A * *********************************************************************/ void OnLogRButtonUp(int nModifier, int x, int y) { HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_POPUP_SELECTION)); if (hMenu != NULL) { HMENU hMenuPopup = GetSubMenu(hMenu, 0); /* Check if there is a selection */ CHARRANGE range; SendMessage(g_hwndLogBox, EM_EXGETSEL, 0, (LPARAM) &range); if (range.cpMin == range.cpMax) { EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_GRAYED); } else { EnableMenuItem(hMenuPopup, ID_EDIT_COPY, MF_BYCOMMAND | MF_ENABLED); } /* Display the popup */ TrackPopupMenu(hMenuPopup, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, x, y, 0, g_hwndLogFrame, NULL); DestroyMenu(hMenu); } } /********************************************************************* * * Function : OnLogCommand * * Description : Handler for WM_COMMAND messages. * * Parameters : * 1 : nCommand = the command portion of the menu selection event * * Returns : N/A * *********************************************************************/ void OnLogCommand(int nCommand) { switch (nCommand) { case ID_TOGGLE_SHOWWINDOW: g_bShowLogWindow = !g_bShowLogWindow; ShowLogWindow(g_bShowLogWindow); break; case ID_FILE_EXIT: PostMessage(g_hwndLogFrame, WM_CLOSE, 0, 0); break; case ID_EDIT_COPY: SendMessage(g_hwndLogBox, WM_COPY, 0, 0); break; case ID_VIEW_CLEARLOG: SendMessage(g_hwndLogBox, WM_SETTEXT, 0, (LPARAM) ""); break; case ID_VIEW_LOGMESSAGES: g_bLogMessages = !g_bLogMessages; /* SaveLogSettings(); */ break; case ID_VIEW_MESSAGEHIGHLIGHTING: g_bHighlightMessages = !g_bHighlightMessages; /* SaveLogSettings(); */ break; case ID_VIEW_LIMITBUFFERSIZE: g_bLimitBufferSize = !g_bLimitBufferSize; /* SaveLogSettings(); */ break; case ID_VIEW_ACTIVITYANIMATION: g_bShowActivityAnimation = !g_bShowActivityAnimation; /* SaveLogSettings(); */ break; #ifdef FEATURE_TOGGLE case ID_TOGGLE_ENABLED: global_toggle_state = !global_toggle_state; log_error(LOG_LEVEL_INFO, "Now toggled %s", global_toggle_state ? "ON" : "OFF"); /* * Leverage TIMER_ANIMSTOP_ID to set the idle icon through the * "application queue". According to MSDN, 10 milliseconds are * the lowest value possible and seem to be close enough to * "instantly". */ SetTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID, 10, NULL); break; #endif /* def FEATURE_TOGGLE */ case ID_TOOLS_EDITCONFIG: EditFile(configfile); break; case ID_TOOLS_EDITDEFAULTACTIONS: EditFile(g_default_actions_file); break; case ID_TOOLS_EDITUSERACTIONS: EditFile(g_user_actions_file); break; case ID_TOOLS_EDITDEFAULTFILTERS: EditFile(g_default_filterfile); break; case ID_TOOLS_EDITUSERFILTERS: EditFile(g_user_filterfile); break; #ifdef FEATURE_TRUST case ID_TOOLS_EDITTRUST: EditFile(g_trustfile); break; #endif /* def FEATURE_TRUST */ case ID_HELP_GPL: ShellExecute(g_hwndLogFrame, "open", "LICENSE.txt", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_FAQ: ShellExecute(g_hwndLogFrame, "open", "doc\\faq\\index.html", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_MANUAL: ShellExecute(g_hwndLogFrame, "open", "doc\\user-manual\\index.html", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_STATUS: ShellExecute(g_hwndLogFrame, "open", CGI_PREFIX "show-status", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_ABOUT: MessageBox(g_hwndLogFrame, win32_blurb, "About Privoxy", MB_OK); break; default: /* DO NOTHING */ break; } } /********************************************************************* * * Function : OnLogInitMenu * * Description : Handler for WM_INITMENU messages. Enable, disable, * check, and/or uncheck menu options as apropos. * * Parameters : * 1 : hmenu = handle to menu to "make current" * * Returns : N/A * *********************************************************************/ void OnLogInitMenu(HMENU hmenu) { /* Only enable editors if there is a file to edit */ EnableMenuItem(hmenu, ID_TOOLS_EDITDEFAULTACTIONS, MF_BYCOMMAND | (g_default_actions_file ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hmenu, ID_TOOLS_EDITUSERACTIONS, MF_BYCOMMAND | (g_user_actions_file ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hmenu, ID_TOOLS_EDITDEFAULTFILTERS, MF_BYCOMMAND | (g_default_filterfile ? MF_ENABLED : MF_GRAYED)); EnableMenuItem(hmenu, ID_TOOLS_EDITUSERFILTERS, MF_BYCOMMAND | (g_user_filterfile ? MF_ENABLED : MF_GRAYED)); #ifdef FEATURE_TRUST EnableMenuItem(hmenu, ID_TOOLS_EDITTRUST, MF_BYCOMMAND | (g_trustfile ? MF_ENABLED : MF_GRAYED)); #endif /* def FEATURE_TRUST */ /* Check/uncheck options */ CheckMenuItem(hmenu, ID_VIEW_LOGMESSAGES, MF_BYCOMMAND | (g_bLogMessages ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hmenu, ID_VIEW_MESSAGEHIGHLIGHTING, MF_BYCOMMAND | (g_bHighlightMessages ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hmenu, ID_VIEW_LIMITBUFFERSIZE, MF_BYCOMMAND | (g_bLimitBufferSize ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hmenu, ID_VIEW_ACTIVITYANIMATION, MF_BYCOMMAND | (g_bShowActivityAnimation ? MF_CHECKED : MF_UNCHECKED)); #ifdef FEATURE_TOGGLE /* by haroon - menu item for Enable toggle on/off */ CheckMenuItem(hmenu, ID_TOGGLE_ENABLED, MF_BYCOMMAND | (global_toggle_state ? MF_CHECKED : MF_UNCHECKED)); #endif /* def FEATURE_TOGGLE */ CheckMenuItem(hmenu, ID_TOGGLE_SHOWWINDOW, MF_BYCOMMAND | (g_bShowLogWindow ? MF_CHECKED : MF_UNCHECKED)); } /********************************************************************* * * Function : OnLogTimer * * Description : Handler for WM_TIMER messages. * * Parameters : * 1 : nTimer = timer id (animation start/stop or clip buffer) * * Returns : N/A * *********************************************************************/ void OnLogTimer(int nTimer) { switch (nTimer) { case TIMER_ANIM_ID: TraySetIcon(g_hwndTray, 1, g_hiconAnim[g_nAnimFrame++ % ANIM_FRAMES]); break; case TIMER_ANIMSTOP_ID: g_nAnimFrame = 0; SetIdleIcon(); KillTimer(g_hwndLogFrame, TIMER_ANIM_ID); KillTimer(g_hwndLogFrame, TIMER_ANIMSTOP_ID); break; case TIMER_CLIPBUFFER_ID: case TIMER_CLIPBUFFER_FORCE_ID: LogClipBuffer(); g_bClipPending = FALSE; KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_ID); KillTimer(g_hwndLogFrame, TIMER_CLIPBUFFER_FORCE_ID); break; default: /* DO NOTHING */ break; } } /********************************************************************* * * Function : SetIdleIcon * * Description : Sets the tray icon to either idle or off * * Parameters : none * * Returns : N/A * *********************************************************************/ void SetIdleIcon() { #ifdef FEATURE_TOGGLE if (!global_toggle_state) { TraySetIcon(g_hwndTray, 1, g_hiconOff); } else #endif /* def FEATURE_TOGGLE */ TraySetIcon(g_hwndTray, 1, g_hiconIdle); } /********************************************************************* * * Function : LogRichEditProc * * Description : Window subclass routine handles some events for the rich edit control. * * Parameters : * 1 : hwnd = window handle of the rich edit control * 2 : uMsg = message number * 3 : wParam = first param for this message * 4 : lParam = next param for this message * * Returns : Appropriate M$ window message handler codes. * *********************************************************************/ LRESULT CALLBACK LogRichEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_RBUTTONUP: { POINT pt; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); ClientToScreen(hwnd, &pt); OnLogRButtonUp(wParam, pt.x, pt.y); return 0; } case WM_CHAR: { if ((GetKeyState(VK_CONTROL) != 0) && (wParam == 4)) /* ctrl+d */ { OnLogCommand(ID_VIEW_CLEARLOG); return 0; } } } return CallWindowProc(g_fnLogBox, hwnd, uMsg, wParam, lParam); } /********************************************************************* * * Function : LogWindowProc * * Description : Windows call back routine handles events on the log window. * * Parameters : * 1 : hwnd = handle of the logging window * 2 : uMsg = message number * 3 : wParam = first param for this message * 4 : lParam = next param for this message * * Returns : Appropriate M$ window message handler codes. * *********************************************************************/ LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: return 0; case WM_CLOSE: /* This is the end - my only friend - the end */ DestroyWindow(g_hwndLogBox); DestroyWindow(g_hwndLogFrame); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_SHOWWINDOW: g_bShowLogWindow = wParam; case WM_SIZE: /* Resize the logging window to fit the new frame */ if (g_hwndLogBox) { RECT rc; GetClientRect(g_hwndLogFrame, &rc); SetWindowPos(g_hwndLogBox, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER); } return 0; case WM_INITMENU: OnLogInitMenu((HMENU) wParam); return 0; case WM_TIMER: OnLogTimer(wParam); return 0; case WM_COMMAND: OnLogCommand(LOWORD(wParam)); return 0; case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: if (g_bCloseHidesWindow) { ShowLogWindow(FALSE); return 0; } break; case SC_MINIMIZE: ShowLogWindow(FALSE); return 0; } break; case WM_CHAR: if ((GetKeyState(VK_CONTROL) != 0) && (wParam == 4)) /* ctrl+d */ { OnLogCommand(ID_VIEW_CLEARLOG); return 0; } break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } #endif /* ndef _WIN_CONSOLE - entire file */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./privoxy.1000640 001751 001751 00000020761 12114407541 015571 0ustar00fkfk000000 000000 .\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "PRIVOXY" "1" "02 March 2013" "Privoxy 3.0.21" "" .SH NAME privoxy \- Privacy Enhancing Proxy .SH SYNOPSIS \fBprivoxy\fR [\fB\-\-chroot\fR ] [\fB\-\-config-test\fR ] [\fB\-\-help\fR ] [\fB\-\-no-daemon\fR ] [\fB\-\-pidfile \fIpidfile\fB\fR ] [\fB\-\-pre-chroot-nslookup \fIhostname\fB\fR ] [\fB\-\-user \fIuser[.group]\fB\fR ] [\fB\-\-version\fR ] [\fB\fIconfigfile\fB\fR ] .SH "OPTIONS" .PP \fBPrivoxy\fR may be invoked with the following command line options: .TP \fB\-\-chroot\fR Before changing to the user ID given in the \-\-user option, chroot to that user's home directory, i.e. make the kernel pretend to the \fBPrivoxy\fR process that the directory tree starts there. If set up carefully, this can limit the impact of possible vulnerabilities in \fBPrivoxy\fR to the files contained in that hierarchy. .TP \fB\-\-config-test\fR Exit after loading the configuration files before binding to the listen address. The exit code signals whether or not the configuration files have been successfully loaded. If the exit code is 1, at least one of the configuration files is invalid, if it is 0, all the configuration files have been successfully loaded (but may still contain errors that can currently only be detected at run time). This option doesn't affect the log setting, combination with "--no-daemon" is recommended if a configured log file shouldn't be used. .TP \fB\-\-help\fR Print brief usage info and exit. .TP \fB\-\-no-daemon\fR Don't become a daemon, i.e. don't fork and become process group leader, don't detach from controlling tty, and do all logging there. .TP \fB\-\-pidfile \fIpidfile\fB\fR On startup, write the process ID to \fIpidfile\fR. Delete the \fIpidfile\fR on exit. Failure to create or delete the \fIpidfile\fR is non-fatal. If no \fB\-\-pidfile\fR option is given, no PID file will be used. .TP \fB\-\-pre-chroot-nslookup \fIhostname\fB\fR Initialize the resolver library using \fIhostname\fR before chroot'ing. On some systems this reduces the number of files that must be copied into the chroot tree. .TP \fB\-\-user \fIuser[.group]\fB\fR After (optionally) writing the PID file, assume the user ID of \fIuser\fR and the GID of \fIgroup\fR, or, if the optional \fIgroup\fR was not given, the default group of \fIuser\fR. Exit if the privileges are not sufficient to do so. .TP \fB\-\-version\fR Print version info and exit. .PP If the \fIconfigfile\fR is not specified on the command line, \fBPrivoxy\fR will look for a file named \fIconfig\fR in the current directory. If no \fIconfigfile\fR is found, \fBPrivoxy\fR will fail to start. .SH "DESCRIPTION" .PP Privoxy is a non-caching web proxy with advanced filtering capabilities for enhancing privacy, modifying web page data and HTTP headers, controlling access, and removing ads and other obnoxious Internet junk. Privoxy has a flexible configuration and can be customized to suit individual needs and tastes. It has application for both stand-alone systems and multi-user networks. .PP Privoxy is Free Software and licensed under the GNU GPLv2. .PP Privoxy is an associated project of Software in the Public Interest (SPI). .PP Helping hands and donations are welcome: .TP 0.2i \(bu http://www.privoxy.org/faq/general.html#PARTICIPATE .TP 0.2i \(bu http://www.privoxy.org/faq/general.html#DONATE .SH "INSTALLATION AND USAGE" .PP Browsers can either be individually configured to use \fBPrivoxy\fR as a HTTP proxy (recommended), or \fBPrivoxy\fR can be combined with a packet filter to build an intercepting proxy (see \fIconfig\fR). The default setting is for localhost, on port 8118 (configurable in the main config file). To set the HTTP proxy in Firefox, go through: \fBTools\fR; \fBOptions\fR; \fBGeneral\fR; \fBConnection Settings\fR; \fBManual Proxy Configuration\fR. .PP For Internet Explorer, go through: \fBTools\fR; \fBInternet Properties\fR; \fBConnections\fR; \fBLAN Settings\fR. .PP The Secure (SSL) Proxy should also be set to the same values, otherwise https: URLs will not be proxied. Note: \fBPrivoxy\fR can only proxy HTTP and HTTPS traffic. Do not try it with FTP or other protocols. HTTPS presents some limitations, and not all features will work with HTTPS connections. .PP For other browsers, check the documentation. .SH "CONFIGURATION" .PP \fBPrivoxy\fR can be configured with the various configuration files. The default configuration files are: \fIconfig\fR, \fIdefault.filter\fR, \fIdefault.action\fR and \fIdefault.action\fR. \fIuser.action\fR should be used for locally defined exceptions to the default rules in \fImatch-all.action\fR and \fIdefault.action\fR, and \fIuser.filter\fR for locally defined filters. These are well commented. On Unix and Unix-like systems, these are located in \fI/etc/privoxy/\fR by default. .PP \fBPrivoxy\fR uses the concept of \fBactions\fR in order to manipulate the data stream between the browser and remote sites. There are various actions available with specific functions for such things as blocking web sites, managing cookies, etc. These actions can be invoked individually or combined, and used against individual URLs, or groups of URLs that can be defined using wildcards and regular expressions. The result is that the user has greatly enhanced control and freedom. .PP The actions list (ad blocks, etc) can also be configured with your web browser at http://config.privoxy.org/ (assuming the configuration allows it). \fBPrivoxy's\fR configuration parameters can also be viewed at the same page. In addition, \fBPrivoxy\fR can be toggled on/off. This is an internal page, and does not require Internet access. .PP See the \fIUser Manual\fR for a detailed explanation of installation, general usage, all configuration options, new features and notes on upgrading. .SH "FILES" .nf \fI/usr/sbin/privoxy\fR \fI/etc/privoxy/config\fR \fI/etc/privoxy/match-all.action\fR \fI/etc/privoxy/default.action\fR \fI/etc/privoxy/user.action\fR \fI/etc/privoxy/default.filter\fR \fI/etc/privoxy/user.filter\fR \fI/etc/privoxy/trust\fR \fI/etc/privoxy/templates/*\fR \fI/var/log/privoxy/logfile\fR .fi .PP Various other files should be included, but may vary depending on platform and build configuration. Additional documentation should be included in the local documentation directory. .SH "SIGNALS" .PP \fBPrivoxy\fR terminates on the \fBSIGINT\fR and \fBSIGTERM\fR signals. Log rotation scripts may cause a re-opening of the logfile by sending a \fBSIGHUP\fR to \fBPrivoxy\fR. Note that unlike other daemons, \fBPrivoxy\fR does not need to be made aware of config file changes by \fBSIGHUP\fR -- it will detect them automatically. Signals other than the ones listed above aren't explicitly handled and result in the default action defined by the operating system. .SH "NOTES" .PP Please see the \fIUser Manual\fR on how to contact the developers, for feature requests, reporting problems, and other questions. .SH "SEE ALSO" .PP Other references and sites of interest to \fBPrivoxy\fR users: .PP http://www.privoxy.org/, the \fBPrivoxy\fR Home page. http://www.privoxy.org/faq/, the \fBPrivoxy\fR FAQ. http://www.privoxy.org/developer-manual/, the \fBPrivoxy\fR developer manual. https://sourceforge.net/projects/ijbswa/, the Project Page for \fBPrivoxy\fR on SourceForge. http://config.privoxy.org/, the web-based user interface. \fBPrivoxy\fR must be running for this to work. Shortcut: http://p.p/ https://sourceforge.net/tracker/?group_id=11118&atid=460288, to submit ``misses'' and other configuration related suggestions to the developers. .SH "DEVELOPMENT TEAM" .nf Fabian Keil, lead developer David Schmidt Hal Burgiss Lee Rian Roland Rosenfeld Ian Silvester .fi .SH "COPYRIGHT AND LICENSE" .SS "COPYRIGHT" .PP Copyright (C) 2001-2013 by Privoxy Developers .PP Some source code is based on code Copyright (C) 1997 by Anonymous Coders and Junkbusters, Inc. and licensed under the \fIGNU General Public License\fR. .SS "LICENSE" .PP \fBPrivoxy\fR is free software; you can redistribute it and/or modify it under the terms of the \fIGNU General Public License\fR, version 2, as published by the Free Software Foundation. .PP \fBPrivoxy\fR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \fIlicense\fR for details. privoxy-3.0.21-stable/./jbsockets.c000640 001751 001751 00000123145 12116117330 016116 0ustar00fkfk000000 000000 const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.123 2013/03/06 21:06:18 diem Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $ * * Purpose : Contains wrappers for system-specific sockets code, * so that the rest of Junkbuster can be more * OS-independent. Contains #ifdefs to make this work * on many platforms. * * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written * by and Copyright (C) 1997 Anonymous Coders and * Junkbusters Corporation. http://www.junkbusters.com * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #include #include #include #include #include #include #ifdef _WIN32 #ifndef STRICT #define STRICT #endif #include #include #include #else #ifndef __OS2__ #include #endif #include #include #include #include #include #ifndef __BEOS__ #include #ifndef __OS2__ #include #endif #else #include #endif #if defined(__EMX__) || defined (__OS2__) #include /* OS/2/EMX needs a little help with select */ #ifdef __OS2__ #include #endif #endif #endif #ifdef HAVE_POLL #ifdef __GLIBC__ #include #else #include #endif /* def __GLIBC__ */ #endif /* HAVE_POLL */ #include "project.h" /* For mutex semaphores only */ #include "jcc.h" #include "jbsockets.h" #include "filters.h" #include "errlog.h" /* Mac OSX doesn't define AI_NUMERICSESRV */ #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0 #endif const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION; /* * Maximum number of gethostbyname(_r) retries in case of * soft errors (TRY_AGAIN). * XXX: Does it make sense to make this a config option? */ #define MAX_DNS_RETRIES 10 #define MAX_LISTEN_BACKLOG 128 #ifdef HAVE_RFC2553 static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp); #else static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp); #endif /********************************************************************* * * Function : connect_to * * Description : Open a socket and connect to it. Will check * that this is allowed according to ACL. * * Parameters : * 1 : host = hostname to connect to * 2 : portnum = port to connect to (XXX: should be unsigned) * 3 : csp = Current client state (buffers, headers, etc...) * * Returns : JB_INVALID_SOCKET => failure, else it is the socket * file descriptor. * *********************************************************************/ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) { jb_socket fd; int forwarded_connect_retries = 0; do { /* * XXX: The whole errno overloading is ridiculous and should * be replaced with something sane and thread safe */ /* errno = 0;*/ #ifdef HAVE_RFC2553 fd = rfc2553_connect_to(host, portnum, csp); #else fd = no_rfc2553_connect_to(host, portnum, csp); #endif if ((fd != JB_INVALID_SOCKET) || (errno == EINVAL) || (csp->fwd == NULL) || ((csp->fwd->forward_host == NULL) && (csp->fwd->type == SOCKS_NONE))) { break; } forwarded_connect_retries++; if (csp->config->forwarded_connect_retries != 0) { log_error(LOG_LEVEL_ERROR, "Attempt %d of %d to connect to %s failed. Trying again.", forwarded_connect_retries, csp->config->forwarded_connect_retries + 1, host); } } while (forwarded_connect_retries < csp->config->forwarded_connect_retries); return fd; } #ifdef HAVE_RFC2553 /* Getaddrinfo implementation */ static jb_socket rfc2553_connect_to(const char *host, int portnum, struct client_state *csp) { struct addrinfo hints, *result, *rp; char service[6]; int retval; jb_socket fd; fd_set wfds; struct timeval timeout; #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) int flags; #endif int connect_failed; /* * XXX: Initializeing it here is only necessary * because not all situations are properly * covered yet. */ int socket_error = 0; #ifdef FEATURE_ACL struct access_control_addr dst[1]; #endif /* def FEATURE_ACL */ /* Don't leak memory when retrying. */ freez(csp->error_message); freez(csp->http->host_ip_addr_str); retval = snprintf(service, sizeof(service), "%d", portnum); if ((-1 == retval) || (sizeof(service) <= retval)) { log_error(LOG_LEVEL_ERROR, "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes", portnum); csp->error_message = strdup("Invalid port number"); csp->http->host_ip_addr_str = strdup("unknown"); return(JB_INVALID_SOCKET); } memset((char *)&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICSERV; /* avoid service look-up */ #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif if ((retval = getaddrinfo(host, service, &hints, &result))) { log_error(LOG_LEVEL_INFO, "Can not resolve %s: %s", host, gai_strerror(retval)); /* XXX: Should find a better way to propagate this error. */ errno = EINVAL; csp->error_message = strdup(gai_strerror(retval)); csp->http->host_ip_addr_str = strdup("unknown"); return(JB_INVALID_SOCKET); } csp->http->host_ip_addr_str = malloc(NI_MAXHOST); if (NULL == csp->http->host_ip_addr_str) { freeaddrinfo(result); log_error(LOG_LEVEL_ERROR, "Out of memory while getting the server IP address."); return JB_INVALID_SOCKET; } for (rp = result; rp != NULL; rp = rp->ai_next) { #ifdef FEATURE_ACL memcpy(&dst->addr, rp->ai_addr, rp->ai_addrlen); if (block_acl(dst, csp)) { #ifdef __OS2__ socket_error = errno = SOCEPERM; #else socket_error = errno = EPERM; #endif continue; } #endif /* def FEATURE_ACL */ retval = getnameinfo(rp->ai_addr, rp->ai_addrlen, csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (retval) { log_error(LOG_LEVEL_ERROR, "Failed to get the host name from the socket structure: %s", gai_strerror(retval)); continue; } fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); #ifdef _WIN32 if (fd == JB_INVALID_SOCKET) #else if (fd < 0) #endif { continue; } #ifndef _WIN32 if (fd >= FD_SETSIZE) { log_error(LOG_LEVEL_ERROR, "Server socket number too high to use select(): %d >= %d", fd, FD_SETSIZE); close_socket(fd); return JB_INVALID_SOCKET; } #endif #ifdef TCP_NODELAY { /* turn off TCP coalescence */ int mi = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int)); } #endif /* def TCP_NODELAY */ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { flags |= O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ connect_failed = 0; while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET) { #ifdef __OS2__ errno = sock_errno(); #endif /* __OS2__ */ #ifdef _WIN32 if (errno == WSAEINPROGRESS) #else /* ifndef _WIN32 */ if (errno == EINPROGRESS) #endif /* ndef _WIN32 || __OS2__ */ { break; } if (errno != EINTR) { socket_error = errno; close_socket(fd); connect_failed = 1; break; } } if (connect_failed) { continue; } #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) if (flags != -1) { flags &= ~O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ /* wait for connection to complete */ FD_ZERO(&wfds); FD_SET(fd, &wfds); memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = 30; /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */ if ((select((int)fd + 1, NULL, &wfds, NULL, &timeout) > 0) && FD_ISSET(fd, &wfds)) { socklen_t optlen = sizeof(socket_error); if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error, &optlen)) { if (!socket_error) { /* Connection established, no need to try other addresses. */ break; } if (rp->ai_next != NULL) { /* * There's another address we can try, so log that this * one didn't work out. If the last one fails, too, * it will get logged outside the loop body so we don't * have to mention it here. */ log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.", csp->http->host_ip_addr_str, service, strerror(socket_error)); } } else { socket_error = errno; log_error(LOG_LEVEL_ERROR, "Could not get the state of " "the connection to [%s]:%s: %s; dropping connection.", csp->http->host_ip_addr_str, service, strerror(errno)); } } /* Connection failed, try next address */ close_socket(fd); } freeaddrinfo(result); if (!rp) { log_error(LOG_LEVEL_CONNECT, "Could not connect to [%s]:%s: %s.", host, service, strerror(socket_error)); csp->error_message = strdup(strerror(socket_error)); return(JB_INVALID_SOCKET); } log_error(LOG_LEVEL_CONNECT, "Connected to %s[%s]:%s.", host, csp->http->host_ip_addr_str, service); return(fd); } #else /* ndef HAVE_RFC2553 */ /* Pre-getaddrinfo implementation */ static jb_socket no_rfc2553_connect_to(const char *host, int portnum, struct client_state *csp) { struct sockaddr_in inaddr; jb_socket fd; unsigned int addr; fd_set wfds; struct timeval tv[1]; #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) int flags; #endif #ifdef FEATURE_ACL struct access_control_addr dst[1]; #endif /* def FEATURE_ACL */ /* Don't leak memory when retrying. */ freez(csp->http->host_ip_addr_str); memset((char *)&inaddr, 0, sizeof inaddr); if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE) { csp->http->host_ip_addr_str = strdup("unknown"); return(JB_INVALID_SOCKET); } #ifdef FEATURE_ACL dst->addr = ntohl(addr); dst->port = portnum; if (block_acl(dst, csp)) { #ifdef __OS2__ errno = SOCEPERM; #else errno = EPERM; #endif return(JB_INVALID_SOCKET); } #endif /* def FEATURE_ACL */ inaddr.sin_addr.s_addr = addr; inaddr.sin_family = AF_INET; csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr)); #ifndef _WIN32 if (sizeof(inaddr.sin_port) == sizeof(short)) #endif /* ndef _WIN32 */ { inaddr.sin_port = htons((unsigned short) portnum); } #ifndef _WIN32 else { inaddr.sin_port = htonl((unsigned long)portnum); } #endif /* ndef _WIN32 */ fd = socket(inaddr.sin_family, SOCK_STREAM, 0); #ifdef _WIN32 if (fd == JB_INVALID_SOCKET) #else if (fd < 0) #endif { return(JB_INVALID_SOCKET); } #ifndef _WIN32 if (fd >= FD_SETSIZE) { log_error(LOG_LEVEL_ERROR, "Server socket number too high to use select(): %d >= %d", fd, FD_SETSIZE); close_socket(fd); return JB_INVALID_SOCKET; } #endif #ifdef TCP_NODELAY { /* turn off TCP coalescence */ int mi = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &mi, sizeof (int)); } #endif /* def TCP_NODELAY */ #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { flags |= O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET) { #ifdef _WIN32 if (errno == WSAEINPROGRESS) #elif __OS2__ if (sock_errno() == EINPROGRESS) #else /* ifndef _WIN32 */ if (errno == EINPROGRESS) #endif /* ndef _WIN32 || __OS2__ */ { break; } #ifdef __OS2__ if (sock_errno() != EINTR) #else if (errno != EINTR) #endif /* __OS2__ */ { close_socket(fd); return(JB_INVALID_SOCKET); } } #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) if (flags != -1) { flags &= ~O_NDELAY; fcntl(fd, F_SETFL, flags); } #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ /* wait for connection to complete */ FD_ZERO(&wfds); FD_SET(fd, &wfds); tv->tv_sec = 30; tv->tv_usec = 0; /* MS Windows uses int, not SOCKET, for the 1st arg of select(). Weird! */ if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0) { close_socket(fd); return(JB_INVALID_SOCKET); } return(fd); } #endif /* ndef HAVE_RFC2553 */ /********************************************************************* * * Function : write_socket * * Description : Write the contents of buf (for n bytes) to socket fd. * * Parameters : * 1 : fd = file descriptor (aka. handle) of socket to write to. * 2 : buf = pointer to data to be written. * 3 : len = length of data to be written to the socket "fd". * * Returns : 0 on success (entire buffer sent). * nonzero on error. * *********************************************************************/ #ifdef AMIGA int write_socket(jb_socket fd, const char *buf, ssize_t len) #else int write_socket(jb_socket fd, const char *buf, size_t len) #endif { if (len == 0) { return 0; } log_error(LOG_LEVEL_WRITING, "to socket %d: %N", fd, len, buf); #if defined(_WIN32) return (send(fd, buf, (int)len, 0) != (int)len); #elif defined(__BEOS__) || defined(AMIGA) return (send(fd, buf, len, 0) != len); #elif defined(__OS2__) /* * Break the data up into SOCKET_SEND_MAX chunks for sending... * OS/2 seemed to complain when the chunks were too large. */ #define SOCKET_SEND_MAX 65000 { int send_len, send_rc = 0, i = 0; while ((i < len) && (send_rc != -1)) { if ((i + SOCKET_SEND_MAX) > len) send_len = len - i; else send_len = SOCKET_SEND_MAX; send_rc = send(fd,(char*)buf + i, send_len, 0); if (send_rc == -1) return 1; i = i + send_len; } return 0; } #else return (write(fd, buf, len) != len); #endif } /********************************************************************* * * Function : read_socket * * Description : Read from a TCP/IP socket in a platform independent way. * * Parameters : * 1 : fd = file descriptor of the socket to read * 2 : buf = pointer to buffer where data will be written * Must be >= len bytes long. * 3 : len = maximum number of bytes to read * * Returns : On success, the number of bytes read is returned (zero * indicates end of file), and the file position is advanced * by this number. It is not an error if this number is * smaller than the number of bytes requested; this may hap- * pen for example because fewer bytes are actually available * right now (maybe because we were close to end-of-file, or * because we are reading from a pipe, or from a terminal, * or because read() was interrupted by a signal). On error, * -1 is returned, and errno is set appropriately. In this * case it is left unspecified whether the file position (if * any) changes. * *********************************************************************/ int read_socket(jb_socket fd, char *buf, int len) { int ret; if (len <= 0) { return(0); } #if defined(_WIN32) ret = recv(fd, buf, len, 0); #elif defined(__BEOS__) || defined(AMIGA) || defined(__OS2__) ret = recv(fd, buf, (size_t)len, 0); #else ret = (int)read(fd, buf, (size_t)len); #endif if (ret > 0) { log_error(LOG_LEVEL_RECEIVED, "from socket %d: %N", fd, ret, buf); } return ret; } /********************************************************************* * * Function : data_is_available * * Description : Waits for data to arrive on a socket. * * Parameters : * 1 : fd = file descriptor of the socket to read * 2 : seconds_to_wait = number of seconds after which we give up. * * Returns : TRUE if data arrived in time, * FALSE otherwise. * *********************************************************************/ int data_is_available(jb_socket fd, int seconds_to_wait) { char buf[10]; fd_set rfds; struct timeval timeout; int n; memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = seconds_to_wait; #ifdef __OS2__ /* Copy and pasted from jcc.c ... */ memset(&rfds, 0, sizeof(fd_set)); #else FD_ZERO(&rfds); #endif FD_SET(fd, &rfds); n = select(fd+1, &rfds, NULL, NULL, &timeout); /* * XXX: Do we care about the different error conditions? */ return ((n == 1) && (1 == recv(fd, buf, 1, MSG_PEEK))); } /********************************************************************* * * Function : close_socket * * Description : Closes a TCP/IP socket * * Parameters : * 1 : fd = file descriptor of socket to be closed * * Returns : void * *********************************************************************/ void close_socket(jb_socket fd) { #if defined(_WIN32) || defined(__BEOS__) closesocket(fd); #elif defined(AMIGA) CloseSocket(fd); #elif defined(__OS2__) soclose(fd); #else close(fd); #endif } /********************************************************************* * * Function : drain_and_close_socket * * Description : Closes a TCP/IP socket after draining unread data * * Parameters : * 1 : fd = file descriptor of the socket to be closed * * Returns : void * *********************************************************************/ void drain_and_close_socket(jb_socket fd) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE if (socket_is_still_alive(fd)) #endif { int bytes_drained_total = 0; int bytes_drained; #ifdef HAVE_SHUTDOWN /* Apparently Windows has shutdown() but not SHUT_WR. */ #ifndef SHUT_WR #define SHUT_WR 1 #endif if (0 != shutdown(fd, SHUT_WR)) { log_error(LOG_LEVEL_CONNECT, "Failed to shutdown socket %d: %E", fd); } #endif #define ARBITRARY_DRAIN_LIMIT 10000 do { char drainage[500]; if (!data_is_available(fd, 0)) { /* * If there is no data available right now, don't try * to drain the socket as read_socket() could block. */ break; } bytes_drained = read_socket(fd, drainage, sizeof(drainage)); if (bytes_drained < 0) { log_error(LOG_LEVEL_CONNECT, "Failed to drain socket %d: %E", fd); } else if (bytes_drained > 0) { bytes_drained_total += bytes_drained; if (bytes_drained_total > ARBITRARY_DRAIN_LIMIT) { log_error(LOG_LEVEL_CONNECT, "Giving up draining socket %d", fd); break; } } } while (bytes_drained > 0); if (bytes_drained_total != 0) { log_error(LOG_LEVEL_CONNECT, "Drained %d bytes before closing socket %d", bytes_drained_total, fd); } } close_socket(fd); } /********************************************************************* * * Function : bind_port * * Description : Call socket, set socket options, and listen. * Called by listen_loop to "boot up" our proxy address. * * Parameters : * 1 : hostnam = TCP/IP address to bind/listen to * 2 : portnum = port to listen on * 3 : pfd = pointer used to return file descriptor. * * Returns : if success, returns 0 and sets *pfd. * if failure, returns -3 if address is in use, * -2 if address unresolvable, * -1 otherwise *********************************************************************/ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) { #ifdef HAVE_RFC2553 struct addrinfo hints; struct addrinfo *result, *rp; /* * XXX: portnum should be a string to allow symbolic service * names in the configuration file and to avoid the following * int2string. */ char servnam[6]; int retval; #else struct sockaddr_in inaddr; #endif /* def HAVE_RFC2553 */ jb_socket fd; #ifndef _WIN32 int one = 1; #endif /* ndef _WIN32 */ *pfd = JB_INVALID_SOCKET; #ifdef HAVE_RFC2553 retval = snprintf(servnam, sizeof(servnam), "%d", portnum); if ((-1 == retval) || (sizeof(servnam) <= retval)) { log_error(LOG_LEVEL_ERROR, "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes", portnum); return -1; } memset(&hints, 0, sizeof(struct addrinfo)); if (hostnam == NULL) { /* * XXX: This is a hack. The right thing to do * would be to bind to both AF_INET and AF_INET6. * This will also fail if there is no AF_INET * version available. */ hints.ai_family = AF_INET; } else { hints.ai_family = AF_UNSPEC; } hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; /* Really any stream protocol or TCP only */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if ((retval = getaddrinfo(hostnam, servnam, &hints, &result))) { log_error(LOG_LEVEL_ERROR, "Can not resolve %s: %s", hostnam, gai_strerror(retval)); return -2; } #else memset((char *)&inaddr, '\0', sizeof inaddr); inaddr.sin_family = AF_INET; inaddr.sin_addr.s_addr = resolve_hostname_to_ip(hostnam); if (inaddr.sin_addr.s_addr == INADDR_NONE) { return(-2); } #ifndef _WIN32 if (sizeof(inaddr.sin_port) == sizeof(short)) #endif /* ndef _WIN32 */ { inaddr.sin_port = htons((unsigned short) portnum); } #ifndef _WIN32 else { inaddr.sin_port = htonl((unsigned long) portnum); } #endif /* ndef _WIN32 */ #endif /* def HAVE_RFC2553 */ #ifdef HAVE_RFC2553 for (rp = result; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); #else fd = socket(AF_INET, SOCK_STREAM, 0); #endif /* def HAVE_RFC2553 */ #ifdef _WIN32 if (fd == JB_INVALID_SOCKET) #else if (fd < 0) #endif { #ifdef HAVE_RFC2553 continue; #else return(-1); #endif } #ifndef _WIN32 /* * This is not needed for Win32 - in fact, it stops * duplicate instances of Privoxy from being caught. * * On UNIX, we assume the user is sensible enough not * to start Privoxy multiple times on the same IP. * Without this, stopping and restarting Privoxy * from a script fails. * Note: SO_REUSEADDR is meant to only take over * sockets which are *not* in listen state in Linux, * e.g. sockets in TIME_WAIT. YMMV. */ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); #endif /* ndef _WIN32 */ #ifdef HAVE_RFC2553 if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0) #else if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0) #endif { #ifdef _WIN32 errno = WSAGetLastError(); if (errno == WSAEADDRINUSE) #else if (errno == EADDRINUSE) #endif { #ifdef HAVE_RFC2553 freeaddrinfo(result); #endif close_socket(fd); return(-3); } else { close_socket(fd); #ifndef HAVE_RFC2553 return(-1); } } #else } } else { /* bind() succeeded, escape from for-loop */ /* * XXX: Support multiple listening sockets (e.g. localhost * resolves to AF_INET and AF_INET6, but only the first address * is used */ break; } } freeaddrinfo(result); if (rp == NULL) { /* All bind()s failed */ return(-1); } #endif /* ndef HAVE_RFC2553 */ while (listen(fd, MAX_LISTEN_BACKLOG) == -1) { if (errno != EINTR) { return(-1); } } *pfd = fd; return 0; } /********************************************************************* * * Function : get_host_information * * Description : Determines the IP address the client used to * reach us and the hostname associated with it. * * XXX: Most of the code has been copy and pasted * from accept_connection() and not all of the * ifdefs paths have been tested afterwards. * * Parameters : * 1 : afd = File descriptor returned from accept(). * 2 : ip_address = Pointer to return the pointer to * the ip address string. * 3 : port = Pointer to return the pointer to * the TCP port string. * 4 : hostname = Pointer to return the pointer to * the hostname or NULL if the caller * isn't interested in it. * * Returns : void. * *********************************************************************/ void get_host_information(jb_socket afd, char **ip_address, char **port, char **hostname) { #ifdef HAVE_RFC2553 struct sockaddr_storage server; int retval; #else struct sockaddr_in server; struct hostent *host = NULL; #endif /* HAVE_RFC2553 */ #if defined(_WIN32) || defined(__OS2__) || defined(AMIGA) /* according to accept_connection() this fixes a warning. */ int s_length, s_length_provided; #else socklen_t s_length, s_length_provided; #endif #ifndef HAVE_RFC2553 #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS) struct hostent result; #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS) struct hostent_data hdata; #else char hbuf[HOSTENT_BUFFER_SIZE]; int thd_err; #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */ #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */ #endif /* ifndef HAVE_RFC2553 */ s_length = s_length_provided = sizeof(server); if (NULL != hostname) { *hostname = NULL; } *ip_address = NULL; *port = NULL; if (!getsockname(afd, (struct sockaddr *) &server, &s_length)) { if (s_length > s_length_provided) { log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address"); return; } /* * XXX: Workaround for missing header on Windows when * configured with --disable-ipv6-support. * The proper fix is to not use NI_MAXSERV in * that case. It works by accident on other platforms * as in included unconditionally there. */ #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif *port = malloc(NI_MAXSERV); if (NULL == *port) { log_error(LOG_LEVEL_ERROR, "Out of memory while getting the client's port."); return; } #ifdef HAVE_RFC2553 *ip_address = malloc(NI_MAXHOST); if (NULL == *ip_address) { log_error(LOG_LEVEL_ERROR, "Out of memory while getting the client's IP address."); freez(*port); return; } retval = getnameinfo((struct sockaddr *) &server, s_length, *ip_address, NI_MAXHOST, *port, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV); if (retval) { log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s", gai_strerror(retval)); freez(*ip_address); freez(*port); return; } #else *ip_address = strdup(inet_ntoa(server.sin_addr)); snprintf(*port, NI_MAXSERV, "%hu", ntohs(server.sin_port)); #endif /* HAVE_RFC2553 */ if (NULL == hostname) { /* * We're done here, the caller isn't * interested in knowing the hostname. */ return; } #ifdef HAVE_RFC2553 *hostname = malloc(NI_MAXHOST); if (NULL == *hostname) { log_error(LOG_LEVEL_ERROR, "Out of memory while getting the client's hostname."); return; } retval = getnameinfo((struct sockaddr *) &server, s_length, *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD); if (retval) { log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s", gai_strerror(retval)); freez(*hostname); } #else #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) gethostbyaddr_r((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET, &result, hbuf, HOSTENT_BUFFER_SIZE, &host, &thd_err); #elif defined(HAVE_GETHOSTBYADDR_R_7_ARGS) host = gethostbyaddr_r((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET, &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err); #elif defined(HAVE_GETHOSTBYADDR_R_5_ARGS) if (0 == gethostbyaddr_r((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET, &result, &hdata)) { host = &result; } else { host = NULL; } #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&resolver_mutex); host = gethostbyaddr((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET); privoxy_mutex_unlock(&resolver_mutex); #else host = gethostbyaddr((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET); #endif if (host == NULL) { log_error(LOG_LEVEL_ERROR, "Unable to get my own hostname: %E\n"); } else { *hostname = strdup(host->h_name); } #endif /* else def HAVE_RFC2553 */ } return; } /********************************************************************* * * Function : accept_connection * * Description : Accepts a connection on one of possibly multiple * sockets. The socket(s) to check must have been * created using bind_port(). * * Parameters : * 1 : csp = Client state, cfd, ip_addr_str, and * ip_addr_long will be set by this routine. * 2 : fds = File descriptors returned from bind_port * * Returns : when a connection is accepted, it returns 1 (TRUE). * On an error it returns 0 (FALSE). * *********************************************************************/ int accept_connection(struct client_state * csp, jb_socket fds[]) { #ifdef HAVE_RFC2553 /* XXX: client is stored directly into csp->tcp_addr */ #define client (csp->tcp_addr) #else struct sockaddr_in client; #endif jb_socket afd; #if defined(_WIN32) || defined(__OS2__) || defined(AMIGA) /* Wierdness - fix a warning. */ int c_length; #else socklen_t c_length; #endif int retval; int i; int max_selected_socket; fd_set selected_fds; jb_socket fd; c_length = sizeof(client); /* * Wait for a connection on any socket. * Return immediately if no socket is listening. * XXX: Why not treat this as fatal error? */ FD_ZERO(&selected_fds); max_selected_socket = 0; for (i = 0; i < MAX_LISTENING_SOCKETS; i++) { if (JB_INVALID_SOCKET != fds[i]) { FD_SET(fds[i], &selected_fds); if (max_selected_socket < fds[i] + 1) { max_selected_socket = fds[i] + 1; } } } if (0 == max_selected_socket) { return 0; } do { retval = select(max_selected_socket, &selected_fds, NULL, NULL, NULL); } while (retval < 0 && errno == EINTR); if (retval <= 0) { if (0 == retval) { log_error(LOG_LEVEL_ERROR, "Waiting on new client failed because select(2) returned 0." " This should not happen."); } else { log_error(LOG_LEVEL_ERROR, "Waiting on new client failed because of problems in select(2): " "%s.", strerror(errno)); } return 0; } for (i = 0; i < MAX_LISTENING_SOCKETS && !FD_ISSET(fds[i], &selected_fds); i++); if (i >= MAX_LISTENING_SOCKETS) { log_error(LOG_LEVEL_ERROR, "select(2) reported connected clients (number = %u, " "descriptor boundary = %u), but none found.", retval, max_selected_socket); return 0; } fd = fds[i]; /* Accept selected connection */ #ifdef _WIN32 afd = accept (fd, (struct sockaddr *) &client, &c_length); if (afd == JB_INVALID_SOCKET) { return 0; } #else do { #if defined(FEATURE_ACCEPT_FILTER) && defined(SO_ACCEPTFILTER) struct accept_filter_arg af_options; bzero(&af_options, sizeof(af_options)); strlcpy(af_options.af_name, "httpready", sizeof(af_options.af_name)); setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &af_options, sizeof(af_options)); #endif afd = accept (fd, (struct sockaddr *) &client, &c_length); } while (afd < 1 && errno == EINTR); if (afd < 0) { return 0; } #endif #ifdef SO_LINGER { struct linger linger_options; linger_options.l_onoff = 1; linger_options.l_linger = 5; if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_options, sizeof(linger_options))) { log_error(LOG_LEVEL_ERROR, "Setting SO_LINGER on socket %d failed.", afd); } } #endif #ifndef _WIN32 if (afd >= FD_SETSIZE) { log_error(LOG_LEVEL_ERROR, "Client socket number too high to use select(): %d >= %d", afd, FD_SETSIZE); close_socket(afd); return 0; } #endif csp->cfd = afd; #ifdef HAVE_RFC2553 csp->ip_addr_str = malloc(NI_MAXHOST); if (NULL == csp->ip_addr_str) { log_error(LOG_LEVEL_ERROR, "Out of memory while getting the client's IP address."); return 0; } retval = getnameinfo((struct sockaddr *) &client, c_length, csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (!csp->ip_addr_str || retval) { log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s", (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory"); freez(csp->ip_addr_str); } #undef client #else csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr)); csp->ip_addr_long = ntohl(client.sin_addr.s_addr); #endif /* def HAVE_RFC2553 */ return 1; } /********************************************************************* * * Function : resolve_hostname_to_ip * * Description : Resolve a hostname to an internet tcp/ip address. * NULL or an empty string resolve to INADDR_ANY. * * Parameters : * 1 : host = hostname to resolve * * Returns : INADDR_NONE => failure, INADDR_ANY or tcp/ip address if successful. * *********************************************************************/ unsigned long resolve_hostname_to_ip(const char *host) { struct sockaddr_in inaddr; struct hostent *hostp; #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) || defined(HAVE_GETHOSTBYNAME_R_3_ARGS) struct hostent result; #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) || defined(HAVE_GETHOSTBYNAME_R_5_ARGS) char hbuf[HOSTENT_BUFFER_SIZE]; int thd_err; #else /* defined(HAVE_GETHOSTBYNAME_R_3_ARGS) */ struct hostent_data hdata; #endif /* def HAVE_GETHOSTBYNAME_R_(6|5)_ARGS */ #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */ if ((host == NULL) || (*host == '\0')) { return(INADDR_ANY); } memset((char *) &inaddr, 0, sizeof inaddr); if ((inaddr.sin_addr.s_addr = inet_addr(host)) == -1) { unsigned int dns_retries = 0; #if defined(HAVE_GETHOSTBYNAME_R_6_ARGS) while (gethostbyname_r(host, &result, hbuf, HOSTENT_BUFFER_SIZE, &hostp, &thd_err) && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES)) { log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", dns_retries, host); } #elif defined(HAVE_GETHOSTBYNAME_R_5_ARGS) while (NULL == (hostp = gethostbyname_r(host, &result, hbuf, HOSTENT_BUFFER_SIZE, &thd_err)) && (thd_err == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES)) { log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", dns_retries, host); } #elif defined(HAVE_GETHOSTBYNAME_R_3_ARGS) /* * XXX: Doesn't retry in case of soft errors. * Does this gethostbyname_r version set h_errno? */ if (0 == gethostbyname_r(host, &result, &hdata)) { hostp = &result; } else { hostp = NULL; } #elif defined(MUTEX_LOCKS_AVAILABLE) privoxy_mutex_lock(&resolver_mutex); while (NULL == (hostp = gethostbyname(host)) && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES)) { log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", dns_retries, host); } privoxy_mutex_unlock(&resolver_mutex); #else while (NULL == (hostp = gethostbyname(host)) && (h_errno == TRY_AGAIN) && (dns_retries++ < MAX_DNS_RETRIES)) { log_error(LOG_LEVEL_ERROR, "Timeout #%u while trying to resolve %s. Trying again.", dns_retries, host); } #endif /* def HAVE_GETHOSTBYNAME_R_(6|5|3)_ARGS */ /* * On Mac OSX, if a domain exists but doesn't have a type A * record associated with it, the h_addr member of the struct * hostent returned by gethostbyname is NULL, even if h_length * is 4. Therefore the second test below. */ if (hostp == NULL || hostp->h_addr == NULL) { errno = EINVAL; log_error(LOG_LEVEL_ERROR, "could not resolve hostname %s", host); return(INADDR_NONE); } if (hostp->h_addrtype != AF_INET) { #ifdef _WIN32 errno = WSAEPROTOTYPE; #else errno = EPROTOTYPE; #endif log_error(LOG_LEVEL_ERROR, "hostname %s resolves to unknown address type.", host); return(INADDR_NONE); } memcpy((char *)&inaddr.sin_addr, (char *)hostp->h_addr, sizeof(inaddr.sin_addr)); } return(inaddr.sin_addr.s_addr); } /********************************************************************* * * Function : socket_is_still_alive * * Description : Figures out whether or not a socket is still alive. * * Parameters : * 1 : sfd = The socket to check. * * Returns : TRUE for yes, otherwise FALSE. * *********************************************************************/ int socket_is_still_alive(jb_socket sfd) { char buf[10]; int no_data_waiting; #ifdef HAVE_POLL int poll_result; struct pollfd poll_fd[1]; memset(poll_fd, 0, sizeof(poll_fd)); poll_fd[0].fd = sfd; poll_fd[0].events = POLLIN; poll_result = poll(poll_fd, 1, 0); if (-1 == poll_result) { log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd); return FALSE; } no_data_waiting = !(poll_fd[0].revents & POLLIN); #else fd_set readable_fds; struct timeval timeout; int ret; memset(&timeout, '\0', sizeof(timeout)); FD_ZERO(&readable_fds); FD_SET(sfd, &readable_fds); ret = select((int)sfd+1, &readable_fds, NULL, NULL, &timeout); if (ret < 0) { log_error(LOG_LEVEL_CONNECT, "select() on socket %d failed: %E", sfd); return FALSE; } no_data_waiting = !FD_ISSET(sfd, &readable_fds); #endif /* def HAVE_POLL */ return (no_data_waiting || (1 == recv(sfd, buf, 1, MSG_PEEK))); } /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./pcrs.h000640 001751 001751 00000012457 11217504052 015110 0ustar00fkfk000000 000000 #ifndef PCRS_H_INCLUDED #define PCRS_H_INCLUDED /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/pcrs.h,v $ * * Purpose : Header file for pcrs.c * * Copyright : see pcrs.c * *********************************************************************/ #define PCRS_H_VERSION "$Id: pcrs.h,v 1.17 2009/05/16 13:27:20 fabiankeil Exp $" #ifndef _PCRE_H #include #endif #ifdef __cplusplus extern "C" { #endif /* * Constants: */ #define FALSE 0 #define TRUE 1 /* Capacity */ #define PCRS_MAX_SUBMATCHES 33 /* Maximum number of capturing subpatterns allowed. MUST be <= 99! FIXME: Should be dynamic */ #define PCRS_MAX_MATCH_INIT 40 /* Initial amount of matches that can be stored in global searches */ #define PCRS_MAX_MATCH_GROW 1.6 /* Factor by which storage for matches is extended if exhausted */ /* * PCRS error codes * * They are supposed to be handled together with PCRE error * codes and have to start with an offset to prevent overlaps. * * PCRE 6.7 uses error codes from -1 to -21, PCRS error codes * below -100 should be safe for a while. */ #define PCRS_ERR_NOMEM -100 /* Failed to acquire memory. */ #define PCRS_ERR_CMDSYNTAX -101 /* Syntax of s///-command */ #define PCRS_ERR_STUDY -102 /* pcre error while studying the pattern */ #define PCRS_ERR_BADJOB -103 /* NULL job pointer, pattern or substitute */ #define PCRS_WARN_BADREF -104 /* Backreference out of range */ #define PCRS_WARN_TRUNCATION -105 /* At least one pcrs variable was too big, * only the first part was used. */ /* Flags */ #define PCRS_GLOBAL 1 /* Job should be applied globally, as with perl's g option */ #define PCRS_TRIVIAL 2 /* Backreferences in the substitute are ignored */ #define PCRS_SUCCESS 4 /* Job did previously match */ /* * Data types: */ /* A compiled substitute */ typedef struct { char *text; /* The plaintext part of the substitute, with all backreferences stripped */ size_t length; /* The substitute may not be a valid C string so we can't rely on strlen(). */ int backrefs; /* The number of backreferences */ int block_offset[PCRS_MAX_SUBMATCHES]; /* Array with the offsets of all plaintext blocks in text */ size_t block_length[PCRS_MAX_SUBMATCHES]; /* Array with the lengths of all plaintext blocks in text */ int backref[PCRS_MAX_SUBMATCHES]; /* Array with the backref number for all plaintext block borders */ int backref_count[PCRS_MAX_SUBMATCHES + 2]; /* Array with the number of references to each backref index */ } pcrs_substitute; /* * A match, including all captured subpatterns (submatches) * Note: The zeroth is the whole match, the PCRS_MAX_SUBMATCHES + 0th * is the range before the match, the PCRS_MAX_SUBMATCHES + 1th is the * range after the match. */ typedef struct { int submatches; /* Number of captured subpatterns */ int submatch_offset[PCRS_MAX_SUBMATCHES + 2]; /* Offset for each submatch in the subject */ size_t submatch_length[PCRS_MAX_SUBMATCHES + 2]; /* Length of each submatch in the subject */ } pcrs_match; /* A PCRS job */ typedef struct PCRS_JOB { pcre *pattern; /* The compiled pcre pattern */ pcre_extra *hints; /* The pcre hints for the pattern */ int options; /* The pcre options (numeric) */ int flags; /* The pcrs and user flags (see "Flags" above) */ pcrs_substitute *substitute; /* The compiled pcrs substitute */ struct PCRS_JOB *next; /* Pointer for chaining jobs to joblists */ } pcrs_job; /* * Prototypes: */ /* Main usage */ extern pcrs_job *pcrs_compile_command(const char *command, int *errptr); extern pcrs_job *pcrs_compile(const char *pattern, const char *substitute, const char *options, int *errptr); extern int pcrs_execute(pcrs_job *job, const char *subject, size_t subject_length, char **result, size_t *result_length); extern int pcrs_execute_list(pcrs_job *joblist, char *subject, size_t subject_length, char **result, size_t *result_length); /* Freeing jobs */ extern pcrs_job *pcrs_free_job(pcrs_job *job); extern void pcrs_free_joblist(pcrs_job *joblist); /* Info on errors: */ extern const char *pcrs_strerror(const int error); extern int pcrs_job_is_dynamic(char *job); extern char pcrs_get_delimiter(const char *string); extern char *pcrs_execute_single_command(const char *subject, const char *pcrs_command, int *hits); /* * Variable/value pair for dynamic pcrs commands. */ struct pcrs_variable { const char *name; char *value; int static_value; }; extern pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_variable v[], int *error); /* Only relevant for maximum pcrs variable size */ #ifndef PCRS_BUFFER_SIZE #define PCRS_BUFFER_SIZE 4000 #endif /* ndef PCRS_BUFFER_SIZE */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ndef PCRS_H_INCLUDED */ /* Local Variables: tab-width: 3 end: */ privoxy-3.0.21-stable/./amiga.c000640 001751 001751 00000014412 11726427304 015214 0ustar00fkfk000000 000000 const char amiga_rcs[] = "$Id: amiga.c,v 1.16 2012/03/09 16:24:36 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/amiga.c,v $ * * Purpose : Amiga-specific declarations. * * Copyright : Written by and Copyright (C) 2001 the SourceForge * Privoxy team. http://www.privoxy.org/ * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software * Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * The GNU General Public License should be included with * this file. If not, you can view it at * http://www.gnu.org/copyleft/gpl.html * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *********************************************************************/ #include "config.h" #ifdef AMIGA #include #include #include "project.h" const char amiga_h_rcs[] = AMIGA_H_VERSION; static char *ver USED = "$VER: Privoxy " __AMIGAVERSION__ " (" __AMIGADATE__ ")"; #ifdef __amigaos4__ static char *stack USED = "$STACK: 524288"; #else unsigned long __stack = 100*1024; #endif struct Task *main_task = NULL; int childs = 0; void serve(struct client_state *csp); SAVEDS ULONG server_thread(void) { struct client_state *local_csp; struct UserData UserData; struct Task *me=FindTask(NULL); #ifdef __amigaos4__ struct Library *SocketBase; #endif Wait(SIGF_SINGLE); local_csp=(struct client_state *)(me->tc_UserData); me->tc_UserData=&UserData; SocketBase=(APTR)OpenLibrary("bsdsocket.library",3); if (SocketBase) #ifdef __amigaos4__ { ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, NULL); } if (ISocket) #endif { SetErrnoPtr(&(UserData.eno),sizeof(int)); local_csp->cfd=ObtainSocket(local_csp->cfd, AF_INET, SOCK_STREAM, 0); if (JB_INVALID_SOCKET!=local_csp->cfd) { Signal(main_task,SIGF_SINGLE); serve((struct client_state *) local_csp); } else { local_csp->flags &= ~CSP_FLAG_ACTIVE; Signal(main_task,SIGF_SINGLE); } #ifdef __amigaos4__ DropInterface((struct Interface *)ISocket); #endif CloseLibrary(SocketBase); } else { #ifdef __amigaos4__ CloseLibrary(SocketBase); #endif local_csp->flags &= ~CSP_FLAG_ACTIVE; Signal(main_task,SIGF_SINGLE); } childs--; return 0; } static BPTR olddir; void amiga_exit(void) { #ifdef __amigaos4__ if (ISocket) #else if (SocketBase) #endif { #ifdef __amigaos4__ struct Library *SocketBase = ISocket->Data.LibBase; DropInterface((struct Interface *)ISocket); #endif CloseLibrary(SocketBase); } CurrentDir(olddir); } #ifndef __amigaos4__ static struct SignalSemaphore memsem; static struct SignalSemaphore *memsemptr = NULL; #endif static struct UserData GlobalUserData; void InitAmiga(void) { #ifdef __amigaos4__ struct Library *SocketBase; #endif main_task = FindTask(NULL); main_task->tc_UserData = &GlobalUserData; if (((struct Library *)SysBase)->lib_Version < 39) { exit(RETURN_FAIL); } signal(SIGINT,SIG_IGN); SocketBase = (APTR)OpenLibrary("bsdsocket.library",3); #ifdef __amigaos4__ if (SocketBase) { ISocket = (struct SocketIFace *)GetInterface(SocketBase, "main", 1, NULL); } if (!ISocket) #else if (!SocketBase) #endif { #ifdef __amigaos4__ CloseLibrary(SocketBase); #endif fprintf(stderr, "Can't open bsdsocket.library V3+\n"); exit(RETURN_ERROR); } SetErrnoPtr(&(GlobalUserData.eno),sizeof(int)); #ifndef __amigaos4__ InitSemaphore(&memsem); memsemptr = &memsem; #endif olddir=CurrentDir(GetProgramDir()); atexit(amiga_exit); } #ifndef __amigaos4__ #ifdef __GNUC__ #ifdef libnix /* multithreadingsafe libnix replacements */ static void *memPool=NULL; void *malloc (size_t s) { ULONG *mem; LONG size = s; if (size<=0) { return NULL; } if (!memPool) { if (!(memPool=CreatePool(MEMF_ANY,32*1024,8*1024))) { return NULL; } } size += sizeof(ULONG) + MEM_BLOCKMASK; size &= ~MEM_BLOCKMASK; if (memsemptr) { ObtainSemaphore(memsemptr); } if ((mem=AllocPooled(memPool,size))) { *mem++=size; } if (memsemptr) { ReleaseSemaphore(memsemptr); } return mem; } void free (void *m) { ULONG *mem = m; if (mem && memPool) { ULONG size=*--mem; if (memsemptr) { ObtainSemaphore(memsemptr); } FreePooled(memPool,mem,size); if (memsemptr) { ReleaseSemaphore(memsemptr); } } } void *realloc (void *old, size_t ns) { void *new; LONG osize, *o = old; LONG nsize = ns; if (!old) { return malloc(nsize); } osize = (*(o-1)) - sizeof(ULONG); if (nsize <= osize) { return old; } if ((new = malloc(nsize))) { ULONG *n = new; osize >>= 2; while(osize--) { *n++ = *o++; } free(old); } return new; } void __memCleanUp (void) { if (memsemptr) { ObtainSemaphore(memsemptr); } if (memPool) { DeletePool(memPool); } if (memsemptr) { ReleaseSemaphore(memsemptr); } } #define ADD2LIST(a,b,c) asm(".stabs \"_" #b "\"," #c ",0,0,_" #a) #define ADD2EXIT(a,pri) ADD2LIST(a,__EXIT_LIST__,22); \ asm(".stabs \"___EXIT_LIST__\",20,0,0," #pri "+128") ADD2EXIT(__memCleanUp,-50); #elif !defined(ixemul) #error No libnix and no ixemul!? #endif /* libnix */ #else #error Only GCC is supported, multithreading safe malloc/free required. #endif /* __GNUC__ */ #endif /* !__amigaos4__ */ #endif /* def AMIGA */