diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/LYCookie.c | 4 | ||||
-rw-r--r-- | src/LYExtern.c | 17 | ||||
-rw-r--r-- | src/LYReadCFG.c | 283 | ||||
-rw-r--r-- | src/LYStrings.c | 10 | ||||
-rw-r--r-- | src/LYStructs.h | 21 | ||||
-rw-r--r-- | src/LYUtils.c | 18 | ||||
-rw-r--r-- | src/LYrcFile.h | 3 |
7 files changed, 221 insertions, 135 deletions
diff --git a/src/LYCookie.c b/src/LYCookie.c index ca6f4cf0..54b12060 100644 --- a/src/LYCookie.c +++ b/src/LYCookie.c @@ -1,5 +1,5 @@ /* - * $LynxId: LYCookie.c,v 1.106 2010/11/07 21:21:02 tom Exp $ + * $LynxId: LYCookie.c,v 1.107 2010/12/08 09:42:15 tom Exp $ * * Lynx Cookie Support LYCookie.c * =================== @@ -134,7 +134,7 @@ static void MemAllocCopy(char **dest, temp = typecallocn(char, (unsigned)(end - start) + 1); if (temp == NULL) outofmem(__FILE__, "MemAllocCopy"); - LYStrNCpy(temp, start, (int) (end - start)); + LYStrNCpy(temp, start, (end - start)); HTSACopy(dest, temp); FREE(temp); } diff --git a/src/LYExtern.c b/src/LYExtern.c index 3c693b0e..94d2cb58 100644 --- a/src/LYExtern.c +++ b/src/LYExtern.c @@ -1,5 +1,5 @@ /* - * $LynxId: LYExtern.c,v 1.46 2010/10/04 08:56:57 tom Exp $ + * $LynxId: LYExtern.c,v 1.47 2010/12/09 00:34:51 tom Exp $ * External application support. This feature allows lynx to pass a given URL to an external program. @@ -241,6 +241,7 @@ static char *lookup_external(char *param, int pass, num_disabled, num_matched, num_choices, cur_choice; int length = 0; char *cmdbuf = NULL; + char **actions = 0; char **choices = 0; lynx_list_item_type *ptr = 0; @@ -260,8 +261,10 @@ static char *lookup_external(char *param, length++; } else if (pass != 0) { cmdbuf = format_command(ptr->command, param); - if (length > 1) - choices[num_choices] = cmdbuf; + if (length > 1) { + actions[num_choices] = cmdbuf; + choices[num_choices] = ptr->menu_name; + } } num_choices++; } @@ -269,8 +272,10 @@ static char *lookup_external(char *param, } if (length > 1) { if (pass == 0) { + actions = typecallocn(char *, (unsigned) length + 1); choices = typecallocn(char *, (unsigned) length + 1); } else { + actions[num_choices] = 0; choices[num_choices] = 0; } } @@ -299,11 +304,13 @@ static char *lookup_external(char *param, } for (pass = 0; choices[pass] != 0; pass++) { if (pass == cur_choice) { - cmdbuf = choices[pass]; + cmdbuf = actions[pass]; } else { - FREE(choices[pass]); + FREE(actions[pass]); } + FREE(choices[pass]); } + FREE(actions); FREE(choices); } return cmdbuf; diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c index 6ce38c0a..066c1690 100644 --- a/src/LYReadCFG.c +++ b/src/LYReadCFG.c @@ -1,5 +1,5 @@ /* - * $LynxId: LYReadCFG.c,v 1.158 2010/11/26 18:10:19 Frank.Heckenbach Exp $ + * $LynxId: LYReadCFG.c,v 1.159 2010/12/09 00:53:07 tom Exp $ */ #ifndef NO_RULES #include <HTRules.h> @@ -48,7 +48,7 @@ BOOLEAN LYUseNoviceLineTwo = TRUE; /* * Translate a TRUE/FALSE field in a string buffer. */ -static BOOL is_true(char *string) +static BOOL is_true(const char *string) { if (!strcasecomp(string, "TRUE") || !strcasecomp(string, "ON")) return (TRUE); @@ -59,9 +59,10 @@ static BOOL is_true(char *string) /* * Find an unescaped colon in a string buffer. */ -static char *find_colon(char *buffer) +static const char *find_colon(const char *buffer) { - char ch, *buf = buffer; + char ch; + const char *buf = buffer; if (buf == NULL) return NULL; @@ -79,19 +80,34 @@ static char *find_colon(char *buffer) return NULL; } -static void free_item_list(lynx_list_item_type **ptr) +static void free_item_list_item(lynx_list_item_type **list, + lynx_list_item_type *ptr) { - lynx_list_item_type *cur = *ptr; - lynx_list_item_type *next; + lynx_list_item_type *prev; + lynx_list_item_type *cur; + + for (cur = *list, prev = 0; cur != 0; prev = cur, cur = cur->next) { + if (cur == ptr) { + + if (prev != 0) + prev->next = cur->next; + else + *list = cur->next; + + FREE(cur->name); + FREE(cur->menu_name); + FREE(cur->command); + FREE(cur); + break; + } + } +} - while (cur) { - next = cur->next; - FREE(cur->name); - FREE(cur->command); - FREE(cur); - cur = next; +static void free_item_list(lynx_list_item_type **ptr) +{ + while (*ptr != 0) { + free_item_list_item(ptr, *ptr); } - *ptr = NULL; } /* @@ -112,15 +128,76 @@ static void free_all_item_lists(void) return; } +static const char *parse_list_bool(BOOL *target, const char *source) +{ + const char *result; + + source = LYSkipCBlanks(source); + result = find_colon(source); + + if (*source != '\0') { + char temp[20]; + size_t len = ((result != 0) + ? (size_t) (result - source) + : strlen(source)); + + if (len > sizeof(temp)) + len = (sizeof(temp) - 1); + LYStrNCpy(temp, source, len); + *target = is_true(temp); + CTRACE2(TRACE_CFG, (tfp, "parse_list_bool(%s) '%d'\n", source, *target)); + } + return result; +} + +static const char *parse_list_int(int *target, const char *source) +{ + const char *result; + + source = LYSkipCBlanks(source); + result = find_colon(source); + + if (*source != '\0') { + *target = atoi(source); + CTRACE2(TRACE_CFG, (tfp, "parse_list_int(%s) '%d'\n", source, *target)); + } + return result; +} + +static const char *parse_list_string(char **target, const char *source) +{ + const char *result; + + source = LYSkipCBlanks(source); + result = find_colon(source); + + if (*source != '\0') { + const char *next = ((result == 0) + ? (source + strlen(source)) + : result); + + *target = typecallocn(char, (size_t) (next - source + 1)); + + if (*target == NULL) + outofmem(__FILE__, "read_cfg"); + LYStrNCpy(*target, source, (next - source)); + remove_backslashes(*target); + + CTRACE2(TRACE_CFG, (tfp, "parse_list_string(%s) '%s'\n", source, *target)); + } + return result; +} + /* * Process string buffer fields for DOWNLOADER or UPLOADER * or PRINTERS or EXTERNALS menus */ static void add_item_to_list(char *buffer, lynx_list_item_type **list_ptr, - int special) + int special, + int menu_name) { - char *colon, *next_colon, *last_colon; + const char *colon, *last_colon; lynx_list_item_type *cur_item, *prev_item; /* @@ -128,24 +205,30 @@ static void add_item_to_list(char *buffer, * field, and act properly when found depending if external environment * $DISPLAY variable is set. */ - if ((last_colon = strrchr(buffer, ':')) != NULL && *(last_colon - 1) != '\\') { - *last_colon++ = '\0'; - /* - * If last_colon equals XWINDOWS then only continue - * if there is a $DISPLAY variable - */ - if (!strcasecomp(last_colon, "XWINDOWS")) { - if (LYgetXDisplay() == NULL) - return; - } - /* - * If last_colon equals NON_XWINDOWS then only continue - * if there is no $DISPLAY variable - */ - else if (!strcasecomp(last_colon, "NON_XWINDOWS")) { - if (LYgetXDisplay() != NULL) - return; - } + if ((colon = find_colon(buffer)) == 0) { + return; + } + for (last_colon = colon; + (colon = find_colon(last_colon + 1)) != 0; + last_colon = colon) { + ; + } + + /* + * If colon equals XWINDOWS then only continue + * if there is a $DISPLAY variable + */ + if (!strcasecomp(last_colon + 1, "XWINDOWS")) { + if (LYgetXDisplay() == NULL) + return; + } + /* + * If colon equals NON_XWINDOWS then only continue + * if there is no $DISPLAY variable + */ + else if (!strcasecomp(last_colon + 1, "NON_XWINDOWS")) { + if (LYgetXDisplay() != NULL) + return; } /* @@ -182,60 +265,41 @@ static void add_item_to_list(char *buffer, assert(cur_item != NULL); } - cur_item->next = NULL; - cur_item->name = NULL; - cur_item->command = NULL; - cur_item->always_enabled = FALSE; - cur_item->override_primary_action = FALSE; + /* fill-in nonzero default values */ cur_item->pagelen = 66; /* * Find first unescaped colon and process fields */ if ((colon = find_colon(buffer)) != NULL) { - /* - * Process name field - */ - cur_item->name = typecallocn(char, (unsigned) (colon - buffer + 1)); - - if (cur_item->name == NULL) - outofmem(__FILE__, "read_cfg"); - LYStrNCpy(cur_item->name, buffer, (int) (colon - buffer)); - remove_backslashes(cur_item->name); + colon = parse_list_string(&(cur_item->name), buffer); - /* - * Find end of command string and beginning of TRUE/FALSE option field. - * If we do not find a colon that ends the command string, leave the - * always_enabled option flag as FALSE. In any case, we want the - * command string. - */ - if ((next_colon = find_colon(colon + 1)) == NULL) { - next_colon = colon + strlen(colon); + if (colon && menu_name) { + colon = parse_list_string(&(cur_item->menu_name), colon + 1); } - if (next_colon - (colon + 1) > 0) { - cur_item->command = typecallocn(char, (unsigned) (next_colon - colon)); - - if (cur_item->command == NULL) - outofmem(__FILE__, "read_cfg"); - LYStrNCpy(cur_item->command, - colon + 1, - (int) (next_colon - (colon + 1))); - remove_backslashes(cur_item->command); + if (colon) { + colon = parse_list_string(&(cur_item->command), colon + 1); } - if (*next_colon++) { - colon = next_colon; - if ((next_colon = strchr(colon, ':')) != 0) - *next_colon++ = '\0'; - cur_item->always_enabled = is_true(colon); - if (next_colon) { - if (special) { - cur_item->pagelen = atoi(next_colon); - } else { - cur_item->override_primary_action = is_true(next_colon); - } + if (colon) { + colon = parse_list_bool(&(cur_item->always_enabled), colon + 1); + } + if (colon) { + if (special) { + (void) parse_list_int(&(cur_item->pagelen), colon + 1); + } else { + (void) parse_list_bool(&(cur_item->override_action), colon + 1); } } } + + /* ignore empty data */ + if (cur_item->name == NULL + || cur_item->command == NULL) { + CTRACE2(TRACE_CFG, (tfp, "ignoring incomplete list_item '%s'\n", buffer)); + free_item_list_item(list_ptr, cur_item); + } else if (cur_item->menu_name == NULL) { + StrAllocCopy(cur_item->menu_name, cur_item->command); + } } lynx_list_item_type *find_item_by_number(lynx_list_item_type *list_ptr, @@ -256,7 +320,7 @@ int match_item_by_name(lynx_list_item_type *ptr, return (ptr->command != 0 && !strncasecomp(ptr->name, name, (int) strlen(ptr->name)) - && (only_overriders ? ptr->override_primary_action : 1)); + && (only_overriders ? ptr->override_action : 1)); } #if defined(USE_COLOR_STYLE) || defined(USE_COLOR_TABLE) @@ -399,10 +463,8 @@ The special strings 'nocolor' or 'default', or\n") static void parse_color(char *buffer) { int color; - char *fg, *bg; - char *temp = 0; - - StrAllocCopy(temp, buffer); /* save a copy, for error messages */ + const char *fg, *bg; + char *temp_fg = 0; /* * We are expecting a line of the form: @@ -410,32 +472,31 @@ static void parse_color(char *buffer) */ color = atoi(buffer); if (NULL == (fg = find_colon(buffer))) - exit_with_color_syntax(temp); + exit_with_color_syntax(buffer); assert(fg != NULL); - *fg++ = '\0'; - - if (NULL == (bg = find_colon(fg))) - exit_with_color_syntax(temp); + if (NULL == (bg = find_colon(++fg))) + exit_with_color_syntax(buffer); assert(bg != NULL); - *bg++ = '\0'; + StrAllocCopy(temp_fg, fg); + temp_fg[bg++ - fg] = '\0'; #if defined(USE_SLANG) - if ((check_color(fg, default_fg) == ERR_COLOR) || + if ((check_color(temp_fg, default_fg) == ERR_COLOR) || (check_color(bg, default_bg) == ERR_COLOR)) - exit_with_color_syntax(temp); + exit_with_color_syntax(buffer); - SLtt_set_color(color, NULL, fg, bg); + SLtt_set_color(color, NULL, temp_fg, bg); #else if (lynx_chg_color(color, - check_color(fg, default_fg), + check_color(temp_fg, default_fg), check_color(bg, default_bg)) < 0) - exit_with_color_syntax(temp); + exit_with_color_syntax(buffer); #endif - FREE(temp); + FREE(temp_fg); } #endif /* USE_COLOR_TABLE */ /* *INDENT-OFF* */ @@ -550,29 +611,29 @@ static int outgoing_mail_charset_fun(char *value) */ static int assumed_color_fun(char *buffer) { - char *fg = buffer, *bg; - char *temp = 0; + const char *fg = buffer, *bg; + char *temp_fg = 0; if (LYuse_default_colors) { - StrAllocCopy(temp, buffer); /* save a copy, for error messages */ /* * We are expecting a line of the form: * FOREGROUND:BACKGROUND */ if (NULL == (bg = find_colon(fg))) - exit_with_color_syntax(temp); + exit_with_color_syntax(buffer); assert(bg != NULL); - *bg++ = '\0'; + StrAllocCopy(temp_fg, fg); + temp_fg[bg++ - fg] = '\0'; - default_fg = check_color(fg, default_fg); + default_fg = check_color(temp_fg, default_fg); default_bg = check_color(bg, default_bg); if (default_fg == ERR_COLOR || default_bg == ERR_COLOR) - exit_with_color_syntax(temp); + exit_with_color_syntax(buffer); #ifdef USE_SLANG /* * Sorry - the order of initialization of slang precludes setting the @@ -583,7 +644,7 @@ static int assumed_color_fun(char *buffer) * interface) -TD */ #endif - FREE(temp); + FREE(temp_fg); } else { CTRACE((tfp, "...ignored since DEFAULT_COLORS:off\n")); } @@ -1137,6 +1198,18 @@ static int parse_assumed_doc_charset_choice(char *p) #endif /* USE_CHARSET_CHOICE */ +#ifdef USE_EXTERNALS +/* + * EXTERNAL and EXTERNAL_MENU share the same list. EXTERNAL_MENU allows + * setting a different name than the command string. + */ +static int external_fun(char *str) +{ + add_item_to_list(str, &externals, FALSE, FALSE); + return 0; +} +#endif + #ifdef USE_PRETTYSRC static void html_src_bad_syntax(char *value, char *option_name) @@ -1396,7 +1469,8 @@ static Config_Type Config_Table [] = PARSE_FUN(RC_ENABLE_LYNXRC, enable_lynxrc), PARSE_SET(RC_ENABLE_SCROLLBACK, enable_scrollback), #ifdef USE_EXTERNALS - PARSE_ADD(RC_EXTERNAL, externals), + PARSE_FUN(RC_EXTERNAL, external_fun), + PARSE_ADD(RC_EXTERNAL_MENU, externals), #endif PARSE_Env(RC_FINGER_PROXY, 0), #if defined(_WINDOWS) /* 1998/10/05 (Mon) 17:34:15 */ @@ -1862,7 +1936,10 @@ void LYSetConfigValue(const char *name, break; case CONF_ADD_ITEM: if (q->add_value != 0) - add_item_to_list(value, q->add_value, (q->add_value == &printers)); + add_item_to_list(value, + q->add_value, + (q->add_value == &printers), + TRUE); break; case CONF_ADD_STRING: diff --git a/src/LYStrings.c b/src/LYStrings.c index 79424f63..bd13d9cf 100644 --- a/src/LYStrings.c +++ b/src/LYStrings.c @@ -1,4 +1,4 @@ -/* $LynxId: LYStrings.c,v 1.181 2010/09/25 15:20:49 tom Exp $ */ +/* $LynxId: LYStrings.c,v 1.182 2010/12/08 09:42:15 tom Exp $ */ #include <HTUtils.h> #include <HTCJK.h> #include <UCAux.h> @@ -994,7 +994,7 @@ static const char *expand_tiname(const char *first, size_t len, char **result, c if ((code = lookup_tiname(name, strnames)) >= 0 || (code = lookup_tiname(name, strfnames)) >= 0) { if (cur_term->type.Strings[code] != 0) { - LYStrNCpy(*result, cur_term->type.Strings[code], (int) (final - *result)); + LYStrNCpy(*result, cur_term->type.Strings[code], (final - *result)); (*result) += strlen(*result); } } @@ -2780,7 +2780,7 @@ char *LYElideString(char *str, static char s_str[MAX_LINE]; int len; - LYStrNCpy(buff, str, (int) sizeof(buff) - 1); + LYStrNCpy(buff, str, sizeof(buff) - 1); len = (int) strlen(buff); if (len > (LYcolLimit - 9)) { buff[cut_pos] = '.'; @@ -5070,7 +5070,7 @@ int LYgetstr(char *inputline, } if (recall != NORECALL && (ch == UPARROW || ch == DNARROW)) { - LYStrNCpy(inputline, MyEdit.buffer, (int) bufsize); + LYStrNCpy(inputline, MyEdit.buffer, bufsize); LYAddToCloset(recall, MyEdit.buffer); CTRACE((tfp, "LYgetstr(%s) recall\n", inputline)); return (ch); @@ -5163,7 +5163,7 @@ int LYgetstr(char *inputline, /* * Terminate the string and return. */ - LYStrNCpy(inputline, MyEdit.buffer, (int) bufsize); + LYStrNCpy(inputline, MyEdit.buffer, bufsize); if (!hidden) LYAddToCloset(recall, MyEdit.buffer); CTRACE((tfp, "LYgetstr(%s) LYE_ENTER\n", inputline)); diff --git a/src/LYStructs.h b/src/LYStructs.h index b4c1422b..b37e5198 100644 --- a/src/LYStructs.h +++ b/src/LYStructs.h @@ -1,5 +1,5 @@ /* - * $LynxId: LYStructs.h,v 1.29 2009/02/02 19:56:38 tom Exp $ + * $LynxId: LYStructs.h,v 1.30 2010/12/08 23:30:08 tom Exp $ */ #ifndef LYSTRUCTS_H #define LYSTRUCTS_H @@ -95,20 +95,21 @@ extern "C" { typedef struct _lynx_list_item_type { struct _lynx_list_item_type *next; /* the next item in the linked list */ char *name; /* a description of the item */ + char *menu_name; /* menu-name for EXTERNAL / EXTERNAL_MENU */ char *command; /* the command to execute */ - int always_enabled; /* a constant to tell whether or + BOOL always_enabled; /* a constant to tell whether or * not to disable the printer * when the no_print option is on */ /* HTML lists: */ - BOOL override_primary_action; /* whether primary action will be - * overridden by this - e.g. this - * allows invoking user's MUA when - * mailto: link is activated using - * normal "activate" command. This - * field is only examined by code that - * handles EXTERNAL command. - */ + BOOL override_action; /* whether primary action will be + * overridden by this - e.g. this + * allows invoking user's MUA when + * mailto: link is activated using + * normal "activate" command. This + * field is only examined by code that + * handles EXTERNAL command. + */ /* PRINTER lists: */ int pagelen; /* an integer to store the printer's * page length diff --git a/src/LYUtils.c b/src/LYUtils.c index 20d085ad..0ef6f93e 100644 --- a/src/LYUtils.c +++ b/src/LYUtils.c @@ -1,5 +1,5 @@ /* - * $LynxId: LYUtils.c,v 1.206 2010/11/07 21:21:08 tom Exp $ + * $LynxId: LYUtils.c,v 1.207 2010/12/08 09:42:15 tom Exp $ */ #include <HTUtils.h> #include <HTTCP.h> @@ -547,7 +547,7 @@ static BOOL show_whereis_targets(int flag, tmp[0] = data[itmp]; utf_extra = utf8_length(utf_flag, data + itmp); if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], (int) utf_extra); + LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); itmp += (int) utf_extra; /* * Start emphasis immediately if we are making the link @@ -618,7 +618,7 @@ static BOOL show_whereis_targets(int flag, */ utf_extra = utf8_length(utf_flag, data + itmp); if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], (int) utf_extra); + LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); itmp += (int) utf_extra; /* * Make sure we don't restore emphasis to the last @@ -744,7 +744,7 @@ static BOOL show_whereis_targets(int flag, tmp[0] = data[itmp]; utf_extra = utf8_length(utf_flag, data + itmp); if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], (int) utf_extra); + LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); itmp += (int) utf_extra; /* * Start emphasis immediately if we are making the link @@ -818,7 +818,7 @@ static BOOL show_whereis_targets(int flag, */ utf_extra = utf8_length(utf_flag, data + itmp); if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], (int) utf_extra); + LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); itmp += (int) utf_extra; /* * Make sure we don't restore emphasis to the last @@ -938,7 +938,7 @@ static BOOL show_whereis_targets(int flag, */ utf_extra = utf8_length(utf_flag, data + itmp); if (utf_extra) { - LYStrNCpy(&tmp[1], &data[itmp + 1], (int) utf_extra); + LYStrNCpy(&tmp[1], &data[itmp + 1], utf_extra); itmp += (int) utf_extra; /* * Make sure we don't restore emphasis to the @@ -4772,7 +4772,7 @@ BOOLEAN LYExpandHostForURL(char **AllocatedString, while (*EndS && !WHITE(*EndS) && *EndS != ',') { EndS++; /* Find separator */ } - LYStrNCpy(DomainSuffix, StartS, (int) (EndS - StartS)); + LYStrNCpy(DomainSuffix, StartS, (EndS - StartS)); } } while ((GotHost == FALSE) && (*DomainSuffix != '\0')); @@ -4788,7 +4788,7 @@ BOOLEAN LYExpandHostForURL(char **AllocatedString, while (*EndP && !WHITE(*EndP) && *EndP != ',') { EndP++; /* Find separator */ } - LYStrNCpy(DomainPrefix, StartP, (int) (EndP - StartP)); + LYStrNCpy(DomainPrefix, StartP, (EndP - StartP)); } } while ((GotHost == FALSE) && (*DomainPrefix != '\0')); @@ -5544,7 +5544,7 @@ void LYAddPathToHome(char *fbuffer, * what fits of the home path and return. This will fail, but we need * something in the buffer. - FM */ - LYStrNCpy(fbuffer, home, (int) (fbuffer_size - 1)); + LYStrNCpy(fbuffer, home, (fbuffer_size - 1)); FREE(home); return; } diff --git a/src/LYrcFile.h b/src/LYrcFile.h index b8e45a99..952c6074 100644 --- a/src/LYrcFile.h +++ b/src/LYrcFile.h @@ -1,5 +1,5 @@ /* - * $LynxId: LYrcFile.h,v 1.37 2010/11/26 18:10:19 Frank.Heckenbach Exp $ + * $LynxId: LYrcFile.h,v 1.38 2010/12/07 21:31:51 tom Exp $ */ #ifndef LYRCFILE_H #define LYRCFILE_H @@ -75,6 +75,7 @@ #define RC_ENABLE_LYNXRC "enable_lynxrc" #define RC_ENABLE_SCROLLBACK "enable_scrollback" #define RC_EXTERNAL "external" +#define RC_EXTERNAL_MENU "external_menu" #define RC_FILE_EDITOR "file_editor" #define RC_FILE_SORTING_METHOD "file_sorting_method" #define RC_FINGER_PROXY "finger_proxy" |