1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-25 04:16:38 +02:00
Files
weechat/src/core/wee-proxy.c
T
Sébastien Helleu cf6aca1619 core: add pointer in some callbacks (closes #406)
This pointer is the first argument received by callbacks, and the
existing argument "data" is now automatically freed by WeeChat when the
object containing the callback is removed.

With this new pointer, the linked list of callbacks in scripts has been
removed. This will improve speed of scripts (using a lot of hooks),
reduce memory used by scripts and reduce time to unload scripts.

Following functions are affected in the C API:

* exec_on_files
* config_new
* config_new_section
* config_new_option
* hook_command
* hook_command_run
* hook_timer
* hook_fd
* hook_process
* hook_process_hashtable
* hook_connect
* hook_print
* hook_signal
* hook_hsignal
* hook_config
* hook_completion
* hook_modifier
* hook_info
* hook_info_hashtable
* hook_infolist
* hook_hdata
* hook_focus
* unhook_all_plugin
* buffer_new
* bar_item_new
* upgrade_new
* upgrade_read
2016-03-21 18:11:21 +01:00

714 lines
20 KiB
C

/*
* wee-proxy.c - proxy functions
*
* Copyright (C) 2003-2016 Sébastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat 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 3 of the License, or
* (at your option) any later version.
*
* WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "weechat.h"
#include "wee-proxy.h"
#include "wee-config.h"
#include "wee-hdata.h"
#include "wee-infolist.h"
#include "wee-log.h"
#include "wee-string.h"
#include "../plugins/plugin.h"
char *proxy_option_string[PROXY_NUM_OPTIONS] =
{ "type", "ipv6", "address", "port", "username", "password" };
char *proxy_option_default[PROXY_NUM_OPTIONS] =
{ "http", "off", "127.0.0.1", "3128", "", "" };
char *proxy_type_string[PROXY_NUM_TYPES] =
{ "http", "socks4", "socks5" };
struct t_proxy *weechat_proxies = NULL; /* first proxy */
struct t_proxy *last_weechat_proxy = NULL; /* last proxy */
struct t_proxy *weechat_temp_proxies = NULL; /* proxies used when */
struct t_proxy *last_weechat_temp_proxy = NULL; /* reading configuration */
/*
* Searches for a proxy option.
*
* Returns index of option in enum t_proxy_option, -1 if option is not found.
*/
int
proxy_search_option (const char *option_name)
{
int i;
if (!option_name)
return -1;
for (i = 0; i < PROXY_NUM_OPTIONS; i++)
{
if (string_strcasecmp (proxy_option_string[i], option_name) == 0)
return i;
}
/* proxy option not found */
return -1;
}
/*
* Searches for a proxy type.
*
* Returns index of option in enum t_proxy_type, -1 if type is not found.
*/
int
proxy_search_type (const char *type)
{
int i;
if (!type)
return -1;
for (i = 0; i < PROXY_NUM_TYPES; i++)
{
if (string_strcasecmp (proxy_type_string[i], type) == 0)
return i;
}
/* type not found */
return -1;
}
/*
* Checks if a proxy pointer is valid.
*
* Returns:
* 1: proxy exists
* 0: proxy does not exist
*/
int
proxy_valid (struct t_proxy *proxy)
{
struct t_proxy *ptr_proxy;
if (!proxy)
return 0;
for (ptr_proxy = weechat_proxies; ptr_proxy;
ptr_proxy = ptr_proxy->next_proxy)
{
if (ptr_proxy == proxy)
return 1;
}
/* proxy not found */
return 0;
}
/*
* Searches for a proxy by name.
*
* Returns pointer to proxy found, NULL if not found.
*/
struct t_proxy *
proxy_search (const char *name)
{
struct t_proxy *ptr_proxy;
if (!name || !name[0])
return NULL;
for (ptr_proxy = weechat_proxies; ptr_proxy;
ptr_proxy = ptr_proxy->next_proxy)
{
if (strcmp (ptr_proxy->name, name) == 0)
return ptr_proxy;
}
/* proxy not found */
return NULL;
}
/*
* Searches for a proxy by option name.
*
* Returns pointer to proxy found, NULL if not found.
*/
struct t_proxy *
proxy_search_with_option_name (const char *option_name)
{
char *proxy_name, *pos_option;
struct t_proxy *ptr_proxy;
ptr_proxy = NULL;
pos_option = strchr (option_name, '.');
if (pos_option)
{
proxy_name = string_strndup (option_name, pos_option - option_name);
if (proxy_name)
{
for (ptr_proxy = weechat_proxies; ptr_proxy;
ptr_proxy = ptr_proxy->next_proxy)
{
if (strcmp (ptr_proxy->name, proxy_name) == 0)
break;
}
free (proxy_name);
}
}
return ptr_proxy;
}
/*
* Sets name for a proxy.
*/
void
proxy_set_name (struct t_proxy *proxy, const char *name)
{
int length;
char *option_name;
if (!name || !name[0])
return;
length = strlen (name) + 64;
option_name = malloc (length);
if (option_name)
{
snprintf (option_name, length, "%s.type", name);
config_file_option_rename (proxy->options[PROXY_OPTION_TYPE], option_name);
snprintf (option_name, length, "%s.ipv6", name);
config_file_option_rename (proxy->options[PROXY_OPTION_IPV6], option_name);
snprintf (option_name, length, "%s.address", name);
config_file_option_rename (proxy->options[PROXY_OPTION_ADDRESS], option_name);
snprintf (option_name, length, "%s.port", name);
config_file_option_rename (proxy->options[PROXY_OPTION_PORT], option_name);
snprintf (option_name, length, "%s.username", name);
config_file_option_rename (proxy->options[PROXY_OPTION_USERNAME], option_name);
snprintf (option_name, length, "%s.password", name);
config_file_option_rename (proxy->options[PROXY_OPTION_PASSWORD], option_name);
if (proxy->name)
free (proxy->name);
proxy->name = strdup (name);
free (option_name);
}
}
/*
* Sets a property for a proxy.
*
* Returns:
* 1: OK
* 0: error
*/
int
proxy_set (struct t_proxy *proxy, const char *property, const char *value)
{
if (!proxy || !property || !value)
return 0;
if (string_strcasecmp (property, "name") == 0)
{
proxy_set_name (proxy, value);
return 1;
}
else if (string_strcasecmp (property, "type") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_TYPE], value, 1);
return 1;
}
else if (string_strcasecmp (property, "ipv6") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_IPV6], value, 1);
return 1;
}
else if (string_strcasecmp (property, "address") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_ADDRESS], value, 1);
return 1;
}
else if (string_strcasecmp (property, "port") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_PORT], value, 1);
return 1;
}
else if (string_strcasecmp (property, "username") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_USERNAME], value, 1);
return 1;
}
else if (string_strcasecmp (property, "password") == 0)
{
config_file_option_set (proxy->options[PROXY_OPTION_PASSWORD], value, 1);
return 1;
}
return 0;
}
/*
* Creates an option for a proxy.
*
* Returns pointer to new option, NULL if error.
*/
struct t_config_option *
proxy_create_option (const char *proxy_name, int index_option,
const char *value)
{
struct t_config_option *ptr_option;
int length;
char *option_name;
ptr_option = NULL;
length = strlen (proxy_name) + 1 +
strlen (proxy_option_string[index_option]) + 1;
option_name = malloc (length);
if (!option_name)
return NULL;
snprintf (option_name, length, "%s.%s",
proxy_name, proxy_option_string[index_option]);
switch (index_option)
{
case PROXY_OPTION_TYPE:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "integer",
N_("proxy type (http (default), socks4, socks5)"),
"http|socks4|socks5", 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_OPTION_IPV6:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "boolean",
N_("connect to proxy using ipv6"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_OPTION_ADDRESS:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "string",
N_("proxy server address (IP or hostname)"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_OPTION_PORT:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "integer",
N_("port for connecting to proxy server"),
NULL, 0, 65535, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_OPTION_USERNAME:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "string",
N_("username for proxy server "
"(note: content is evaluated, see /help eval)"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_OPTION_PASSWORD:
ptr_option = config_file_new_option (
weechat_config_file, weechat_config_section_proxy,
option_name, "string",
N_("password for proxy server "
"(note: content is evaluated, see /help eval)"),
NULL, 0, 0, value, NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
break;
case PROXY_NUM_OPTIONS:
break;
}
free (option_name);
return ptr_option;
}
/*
* Creates an option for a temporary proxy (when reading configuration file).
*/
void
proxy_create_option_temp (struct t_proxy *temp_proxy, int index_option,
const char *value)
{
struct t_config_option *new_option;
new_option = proxy_create_option (temp_proxy->name,
index_option,
value);
if (new_option && (index_option >= 0))
temp_proxy->options[index_option] = new_option;
}
/*
* Allocates and initializes a new proxy structure.
*
* Returns pointer to new proxy, NULL if error.
*/
struct t_proxy *
proxy_alloc (const char *name)
{
struct t_proxy *new_proxy;
int i;
new_proxy = malloc (sizeof (*new_proxy));
if (new_proxy)
{
new_proxy->name = strdup (name);
for (i = 0; i < PROXY_NUM_OPTIONS; i++)
{
new_proxy->options[i] = NULL;
}
new_proxy->prev_proxy = NULL;
new_proxy->next_proxy = NULL;
}
return new_proxy;
}
/*
* Adds a new proxy with options.
*
* Returns pointer to new proxy, NULL if error.
*/
struct t_proxy *
proxy_new_with_options (const char *name,
struct t_config_option *type,
struct t_config_option *ipv6,
struct t_config_option *address,
struct t_config_option *port,
struct t_config_option *username,
struct t_config_option *password)
{
struct t_proxy *new_proxy;
/* add proxy */
new_proxy = proxy_alloc (name);
if (!new_proxy)
return NULL;
new_proxy->options[PROXY_OPTION_TYPE] = type;
new_proxy->options[PROXY_OPTION_IPV6] = ipv6;
new_proxy->options[PROXY_OPTION_ADDRESS] = address;
new_proxy->options[PROXY_OPTION_PORT] = port;
new_proxy->options[PROXY_OPTION_USERNAME] = username;
new_proxy->options[PROXY_OPTION_PASSWORD] = password;
/* add proxy to proxies list */
new_proxy->prev_proxy = last_weechat_proxy;
if (weechat_proxies)
last_weechat_proxy->next_proxy = new_proxy;
else
weechat_proxies = new_proxy;
last_weechat_proxy = new_proxy;
new_proxy->next_proxy = NULL;
return new_proxy;
}
/*
* Adds a new proxy.
*
* Returns pointer to new proxy, NULL if error.
*/
struct t_proxy *
proxy_new (const char *name, const char *type, const char *ipv6,
const char *address, const char *port, const char *username,
const char *password)
{
struct t_config_option *option_type, *option_ipv6, *option_address;
struct t_config_option *option_port, *option_username, *option_password;
struct t_proxy *new_proxy;
if (!name || !name[0])
return NULL;
/* it's not possible to add 2 proxies with same name */
if (proxy_search (name))
return NULL;
/* look for type */
if (proxy_search_type (type) < 0)
return NULL;
option_type = proxy_create_option (name, PROXY_OPTION_TYPE,
type);
option_ipv6 = proxy_create_option (name, PROXY_OPTION_IPV6,
ipv6);
option_address = proxy_create_option (name, PROXY_OPTION_ADDRESS,
(address) ? address : "");
option_port = proxy_create_option (name, PROXY_OPTION_PORT,
port);
option_username = proxy_create_option (name, PROXY_OPTION_USERNAME,
(username) ? username : "");
option_password = proxy_create_option (name, PROXY_OPTION_PASSWORD,
(password) ? password : "");
new_proxy = proxy_new_with_options (name, option_type, option_ipv6,
option_address, option_port,
option_username, option_password);
if (!new_proxy)
{
if (option_type)
config_file_option_free (option_type);
if (option_ipv6)
config_file_option_free (option_ipv6);
if (option_address)
config_file_option_free (option_address);
if (option_port)
config_file_option_free (option_port);
if (option_username)
config_file_option_free (option_username);
if (option_password)
config_file_option_free (option_password);
}
return new_proxy;
}
/*
* Uses temporary proxies (added by reading configuration file).
*/
void
proxy_use_temp_proxies ()
{
struct t_proxy *ptr_temp_proxy, *next_temp_proxy;
int i, num_options_ok;
for (ptr_temp_proxy = weechat_temp_proxies; ptr_temp_proxy;
ptr_temp_proxy = ptr_temp_proxy->next_proxy)
{
num_options_ok = 0;
for (i = 0; i < PROXY_NUM_OPTIONS; i++)
{
if (!ptr_temp_proxy->options[i])
{
ptr_temp_proxy->options[i] = proxy_create_option (ptr_temp_proxy->name,
i,
proxy_option_default[i]);
}
if (ptr_temp_proxy->options[i])
num_options_ok++;
}
if (num_options_ok == PROXY_NUM_OPTIONS)
{
proxy_new_with_options (ptr_temp_proxy->name,
ptr_temp_proxy->options[PROXY_OPTION_TYPE],
ptr_temp_proxy->options[PROXY_OPTION_IPV6],
ptr_temp_proxy->options[PROXY_OPTION_ADDRESS],
ptr_temp_proxy->options[PROXY_OPTION_PORT],
ptr_temp_proxy->options[PROXY_OPTION_USERNAME],
ptr_temp_proxy->options[PROXY_OPTION_PASSWORD]);
}
else
{
for (i = 0; i < PROXY_NUM_OPTIONS; i++)
{
if (ptr_temp_proxy->options[i])
{
config_file_option_free (ptr_temp_proxy->options[i]);
ptr_temp_proxy->options[i] = NULL;
}
}
}
}
/* free all temp proxies */
while (weechat_temp_proxies)
{
next_temp_proxy = weechat_temp_proxies->next_proxy;
if (weechat_temp_proxies->name)
free (weechat_temp_proxies->name);
free (weechat_temp_proxies);
weechat_temp_proxies = next_temp_proxy;
}
last_weechat_temp_proxy = NULL;
}
/*
* Frees a proxy.
*/
void
proxy_free (struct t_proxy *proxy)
{
int i;
if (!proxy)
return;
/* remove proxy from proxies list */
if (proxy->prev_proxy)
(proxy->prev_proxy)->next_proxy = proxy->next_proxy;
if (proxy->next_proxy)
(proxy->next_proxy)->prev_proxy = proxy->prev_proxy;
if (weechat_proxies == proxy)
weechat_proxies = proxy->next_proxy;
if (last_weechat_proxy == proxy)
last_weechat_proxy = proxy->prev_proxy;
/* free data */
if (proxy->name)
free (proxy->name);
for (i = 0; i < PROXY_NUM_OPTIONS; i++)
{
config_file_option_free (proxy->options[i]);
}
free (proxy);
}
/*
* Frees all proxies.
*/
void
proxy_free_all ()
{
while (weechat_proxies)
{
proxy_free (weechat_proxies);
}
}
/*
* Returns hdata for proxy.
*/
struct t_hdata *
proxy_hdata_proxy_cb (const void *pointer, void *data,
const char *hdata_name)
{
struct t_hdata *hdata;
/* make C compiler happy */
(void) pointer;
(void) data;
hdata = hdata_new (NULL, hdata_name, "prev_proxy", "next_proxy",
0, 0, NULL, NULL);
if (hdata)
{
HDATA_VAR(struct t_proxy, name, STRING, 0, NULL, NULL);
HDATA_VAR(struct t_proxy, options, POINTER, 0, NULL, NULL);
HDATA_VAR(struct t_proxy, prev_proxy, POINTER, 0, NULL, hdata_name);
HDATA_VAR(struct t_proxy, next_proxy, POINTER, 0, NULL, hdata_name);
HDATA_LIST(weechat_proxies, WEECHAT_HDATA_LIST_CHECK_POINTERS);
HDATA_LIST(last_weechat_proxy, 0);
}
return hdata;
}
/*
* Adds a proxy in an infolist.
*
* Returns:
* 1: OK
* 0: error
*/
int
proxy_add_to_infolist (struct t_infolist *infolist, struct t_proxy *proxy)
{
struct t_infolist_item *ptr_item;
if (!infolist || !proxy)
return 0;
ptr_item = infolist_new_item (infolist);
if (!ptr_item)
return 0;
if (!infolist_new_var_string (ptr_item, "name", proxy->name))
return 0;
if (!infolist_new_var_integer (ptr_item, "type", CONFIG_INTEGER(proxy->options[PROXY_OPTION_TYPE])))
return 0;
if (!infolist_new_var_string (ptr_item, "type_string", proxy_type_string[CONFIG_INTEGER(proxy->options[PROXY_OPTION_TYPE])]))
return 0;
if (!infolist_new_var_integer (ptr_item, "ipv6", CONFIG_INTEGER(proxy->options[PROXY_OPTION_IPV6])))
return 0;
if (!infolist_new_var_string (ptr_item, "address", CONFIG_STRING(proxy->options[PROXY_OPTION_ADDRESS])))
return 0;
if (!infolist_new_var_integer (ptr_item, "port", CONFIG_INTEGER(proxy->options[PROXY_OPTION_PORT])))
return 0;
if (!infolist_new_var_string (ptr_item, "username", CONFIG_STRING(proxy->options[PROXY_OPTION_USERNAME])))
return 0;
if (!infolist_new_var_string (ptr_item, "password", CONFIG_STRING(proxy->options[PROXY_OPTION_PASSWORD])))
return 0;
return 1;
}
/*
* Prints proxies in WeeChat log file (usually for crash dump).
*/
void
proxy_print_log ()
{
struct t_proxy *ptr_proxy;
for (ptr_proxy = weechat_proxies; ptr_proxy;
ptr_proxy = ptr_proxy->next_proxy)
{
log_printf ("");
log_printf ("[proxy (addr:0x%lx)]", ptr_proxy);
log_printf (" name . . . . . . . . . : '%s'", ptr_proxy->name);
log_printf (" type . . . . . . . . . : %d (%s)",
CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_TYPE]),
proxy_type_string[CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_TYPE])]);
log_printf (" ipv6 . . . . . . . . . : %d", CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_IPV6]));
log_printf (" address. . . . . . . . : '%s'", CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_ADDRESS]));
log_printf (" port . . . . . . . . . : %d", CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));
log_printf (" username . . . . . . . : '%s'", CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_USERNAME]));
log_printf (" password . . . . . . . : '%s'", CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_PASSWORD]));
log_printf (" prev_proxy . . . . . . : 0x%lx", ptr_proxy->prev_proxy);
log_printf (" next_proxy . . . . . . : 0x%lx", ptr_proxy->next_proxy);
}
}