1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-03 00:03:12 +02:00

core: add URL transfer (using libcurl), add function hook_process_hashtable in plugin API, add support of URL in hook_process/hook_process_hashtable (task #10247)

This commit is contained in:
Sebastien Helleu
2012-01-16 19:52:08 +01:00
parent ca07f58406
commit b91c231096
52 changed files with 2049 additions and 56 deletions
+3
View File
@@ -124,6 +124,9 @@ IF(ICONV_FOUND)
ADD_DEFINITIONS( -DHAVE_ICONV )
ENDIF(ICONV_FOUND)
# Check for CURL
FIND_PACKAGE(CURL REQUIRED)
FIND_LIBRARY(DL_LIBRARY
NAMES dl
PATHS /lib /usr/lib /usr/libexec /usr/local/lib /usr/local/libexec
+3
View File
@@ -39,6 +39,7 @@ wee-proxy.c wee-proxy.h
wee-string.c wee-string.h
wee-upgrade.c wee-upgrade.h
wee-upgrade-file.c wee-upgrade-file.h
wee-url.c wee-url.h
wee-utf8.c wee-utf8.h
wee-util.c wee-util.h)
@@ -59,5 +60,7 @@ IF(GNUTLS_FOUND)
INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_PATH})
ENDIF(GNUTLS_FOUND)
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
ADD_LIBRARY(weechat_core STATIC ${LIB_CORE_SRC})
+3 -1
View File
@@ -17,7 +17,7 @@
# along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
#
INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(GCRYPT_CFLAGS) $(GNUTLS_CFLAGS)
INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(GCRYPT_CFLAGS) $(GNUTLS_CFLAGS) $(CURL_CFLAGS)
noinst_LIBRARIES = lib_weechat_core.a
@@ -59,6 +59,8 @@ lib_weechat_core_a_SOURCES = weechat.c \
wee-upgrade.h \
wee-upgrade-file.c \
wee-upgrade-file.h \
wee-url.c \
wee-url.h \
wee-utf8.c \
wee-utf8.h \
wee-util.c \
+59 -11
View File
@@ -46,6 +46,7 @@
#include "wee-log.h"
#include "wee-network.h"
#include "wee-string.h"
#include "wee-url.h"
#include "wee-utf8.h"
#include "wee-util.h"
#include "../gui/gui-chat.h"
@@ -1293,13 +1294,14 @@ hook_fd_exec (fd_set *read_fds, fd_set *write_fds, fd_set *exception_fds)
}
/*
* hook_process: hook a process (using fork)
* hook_process_hashtable: hook a process (using fork) with options in hashtable
*/
struct t_hook *
hook_process (struct t_weechat_plugin *plugin,
const char *command, int timeout,
t_hook_callback_process *callback, void *callback_data)
hook_process_hashtable (struct t_weechat_plugin *plugin,
const char *command, struct t_hashtable *options,
int timeout,
t_hook_callback_process *callback, void *callback_data)
{
struct t_hook *new_hook;
struct t_hook_process *new_hook_process;
@@ -1341,6 +1343,7 @@ hook_process (struct t_weechat_plugin *plugin,
new_hook->hook_data = new_hook_process;
new_hook_process->callback = callback;
new_hook_process->command = strdup (command);
new_hook_process->options = (options) ? hashtable_dup (options) : NULL;
new_hook_process->timeout = timeout;
new_hook_process->child_read[HOOK_PROCESS_STDOUT] = -1;
new_hook_process->child_read[HOOK_PROCESS_STDERR] = -1;
@@ -1362,6 +1365,19 @@ hook_process (struct t_weechat_plugin *plugin,
return new_hook;
}
/*
* hook_process: hook a process (using fork)
*/
struct t_hook *
hook_process (struct t_weechat_plugin *plugin,
const char *command, int timeout,
t_hook_callback_process *callback, void *callback_data)
{
return hook_process_hashtable (plugin, command, NULL, timeout,
callback, callback_data);
}
/*
* hook_process_child: child process for hook process: execute function and
* return string result into pipe for WeeChat process
@@ -1371,6 +1387,8 @@ void
hook_process_child (struct t_hook *hook_process)
{
char *exec_args[4] = { "sh", "-c", NULL, NULL };
const char *ptr_url;
int rc;
/*
* close stdin, so that process will fail to read stdin (process reading
@@ -1392,14 +1410,36 @@ hook_process_child (struct t_hook *hook_process)
_exit (EXIT_FAILURE);
}
/* launch command */
exec_args[2] = HOOK_PROCESS(hook_process, command);
execvp (exec_args[0], exec_args);
rc = EXIT_SUCCESS;
/* should not be executed if execvp was ok */
fprintf (stderr, "Error with command '%s'\n",
HOOK_PROCESS(hook_process, command));
_exit (EXIT_FAILURE);
if (strncmp (HOOK_PROCESS(hook_process, command), "url:", 4) == 0)
{
/* get URL output (on stdout or file, depending on options) */
ptr_url = HOOK_PROCESS(hook_process, command) + 4;
while (ptr_url[0] == ' ')
{
ptr_url++;
}
rc = weeurl_download (ptr_url, HOOK_PROCESS(hook_process, options));
if (rc != 0)
fprintf (stderr, "Error with URL '%s'\n", ptr_url);
}
else
{
/* launch command */
exec_args[2] = HOOK_PROCESS(hook_process, command);
execvp (exec_args[0], exec_args);
/* should not be executed if execvp was ok */
fprintf (stderr, "Error with command '%s'\n",
HOOK_PROCESS(hook_process, command));
rc = EXIT_FAILURE;
}
fflush (stdout);
fflush (stderr);
_exit (rc);
}
/*
@@ -3051,6 +3091,8 @@ unhook (struct t_hook *hook)
case HOOK_TYPE_PROCESS:
if (HOOK_PROCESS(hook, command))
free (HOOK_PROCESS(hook, command));
if (HOOK_PROCESS(hook, options))
hashtable_free (HOOK_PROCESS(hook, options));
if (HOOK_PROCESS(hook, hook_fd[HOOK_PROCESS_STDOUT]))
unhook (HOOK_PROCESS(hook, hook_fd[HOOK_PROCESS_STDOUT]));
if (HOOK_PROCESS(hook, hook_fd[HOOK_PROCESS_STDERR]))
@@ -3378,6 +3420,8 @@ hook_add_to_infolist_type (struct t_infolist *infolist, int type,
return 0;
if (!infolist_new_var_string (ptr_item, "command", HOOK_PROCESS(ptr_hook, command)))
return 0;
if (!infolist_new_var_string (ptr_item, "options", hashtable_get_string (HOOK_PROCESS(ptr_hook, options), "keys_values")))
return 0;
if (!infolist_new_var_integer (ptr_item, "timeout", HOOK_PROCESS(ptr_hook, timeout)))
return 0;
if (!infolist_new_var_integer (ptr_item, "child_read_stdout", HOOK_PROCESS(ptr_hook, child_read[HOOK_PROCESS_STDOUT])))
@@ -3792,6 +3836,10 @@ hook_print_log ()
log_printf (" process data:");
log_printf (" callback. . . . . . . : 0x%lx", HOOK_PROCESS(ptr_hook, callback));
log_printf (" command . . . . . . . : '%s'", HOOK_PROCESS(ptr_hook, command));
log_printf (" options . . . . . . . : 0x%lx (hashtable: '%s')",
HOOK_PROCESS(ptr_hook, options),
hashtable_get_string (HOOK_PROCESS(ptr_hook, options),
"keys_values"));
log_printf (" timeout . . . . . . . : %d", HOOK_PROCESS(ptr_hook, timeout));
log_printf (" child_read[stdout]. . : %d", HOOK_PROCESS(ptr_hook, child_read[HOOK_PROCESS_STDOUT]));
log_printf (" child_write[stdout] . : %d", HOOK_PROCESS(ptr_hook, child_write[HOOK_PROCESS_STDOUT]));
+7
View File
@@ -194,6 +194,7 @@ struct t_hook_process
{
t_hook_callback_process *callback; /* process callback (after child end)*/
char *command; /* command executed by child */
struct t_hashtable *options; /* options for process (see doc) */
long timeout; /* timeout (ms) (0 = no timeout) */
int child_read[2]; /* to read data in pipe from child */
int child_write[2]; /* to write data in pipe for child */
@@ -443,6 +444,12 @@ extern struct t_hook *hook_process (struct t_weechat_plugin *plugin,
int timeout,
t_hook_callback_process *callback,
void *callback_data);
extern struct t_hook *hook_process_hashtable (struct t_weechat_plugin *plugin,
const char *command,
struct t_hashtable *options,
int timeout,
t_hook_callback_process *callback,
void *callback_data);
extern struct t_hook *hook_connect (struct t_weechat_plugin *plugin,
const char *proxy, const char *address,
int port, int sock, int ipv6,
+628
View File
@@ -0,0 +1,628 @@
/*
* Copyright (C) 2012 Sebastien 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/>.
*/
/*
* wee-url.c: URL transfer
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "weechat.h"
#include "wee-url.h"
#include "wee-hashtable.h"
#include "wee-infolist.h"
#include "wee-string.h"
#define URL_DEF_CONST(__prefix, __name) \
{ #__name, CURL##__prefix##_##__name }
#define URL_DEF_OPTION(__name, __type, __constants) \
{ #__name, CURLOPT_##__name, URL_TYPE_##__type, __constants }
char *url_type_string[] = { "string", "long", "mask" };
struct t_url_constant url_proxy_types[] =
{
#if LIBCURL_VERSION_NUM >= 0x070A00
/* libcurl >= 7.10 */
URL_DEF_CONST(PROXY, HTTP),
#endif
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_CONST(PROXY, HTTP_1_0),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A00
/* libcurl >= 7.10 */
URL_DEF_CONST(PROXY, SOCKS4),
URL_DEF_CONST(PROXY, SOCKS5),
#endif
#if LIBCURL_VERSION_NUM >= 0x071200
/* libcurl >= 7.18.0 */
URL_DEF_CONST(PROXY, SOCKS4A),
URL_DEF_CONST(PROXY, SOCKS5_HOSTNAME),
#endif
{ NULL, 0 },
};
struct t_url_constant url_protocols[] =
{
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_CONST(PROTO, HTTP),
URL_DEF_CONST(PROTO, HTTPS),
URL_DEF_CONST(PROTO, FTP),
URL_DEF_CONST(PROTO, FTPS),
URL_DEF_CONST(PROTO, SCP),
URL_DEF_CONST(PROTO, SFTP),
URL_DEF_CONST(PROTO, TELNET),
URL_DEF_CONST(PROTO, LDAP),
URL_DEF_CONST(PROTO, LDAPS),
URL_DEF_CONST(PROTO, DICT),
URL_DEF_CONST(PROTO, FILE),
URL_DEF_CONST(PROTO, TFTP),
#endif
#if LIBCURL_VERSION_NUM >= 0x071400
/* libcurl >= 7.20.0 */
URL_DEF_CONST(PROTO, IMAP),
URL_DEF_CONST(PROTO, IMAPS),
URL_DEF_CONST(PROTO, POP3),
URL_DEF_CONST(PROTO, POP3S),
URL_DEF_CONST(PROTO, SMTP),
URL_DEF_CONST(PROTO, SMTPS),
URL_DEF_CONST(PROTO, RTSP),
#endif
#if LIBCURL_VERSION_NUM >= 0x071500
/* libcurl >= 7.21.0 */
URL_DEF_CONST(PROTO, RTMP),
URL_DEF_CONST(PROTO, RTMPT),
URL_DEF_CONST(PROTO, RTMPE),
URL_DEF_CONST(PROTO, RTMPTE),
URL_DEF_CONST(PROTO, RTMPS),
URL_DEF_CONST(PROTO, RTMPTS),
#endif
#if LIBCURL_VERSION_NUM >= 0x071502
/* libcurl >= 7.21.2 */
URL_DEF_CONST(PROTO, GOPHER),
#endif
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_CONST(PROTO, ALL),
#endif
{ NULL, 0 },
};
struct t_url_constant url_netrc[] =
{
#if LIBCURL_VERSION_NUM >= 0x070908
/* libcurl >= 7.9.8 */
URL_DEF_CONST(_NETRC, IGNORED),
URL_DEF_CONST(_NETRC, OPTIONAL),
URL_DEF_CONST(_NETRC, REQUIRED),
#endif
{ NULL, 0 },
};
struct t_url_constant url_auth[] =
{
#if LIBCURL_VERSION_NUM >= 0x070A06
/* libcurl >= 7.10.6 */
URL_DEF_CONST(AUTH, NONE),
URL_DEF_CONST(AUTH, BASIC),
URL_DEF_CONST(AUTH, DIGEST),
URL_DEF_CONST(AUTH, GSSNEGOTIATE),
URL_DEF_CONST(AUTH, NTLM),
#endif
#if LIBCURL_VERSION_NUM >= 0x071303
/* libcurl >= 7.19.3 */
URL_DEF_CONST(AUTH, DIGEST_IE),
#endif
#if LIBCURL_VERSION_NUM >= 0x071600
/* libcurl >= 7.22.0 */
URL_DEF_CONST(AUTH, NTLM_WB),
#endif
#if LIBCURL_VERSION_NUM >= 0x071503
/* libcurl >= 7.21.3 */
URL_DEF_CONST(AUTH, ONLY),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A06
/* libcurl >= 7.10.6 */
URL_DEF_CONST(AUTH, ANY),
URL_DEF_CONST(AUTH, ANYSAFE),
#endif
{ NULL, 0 },
};
struct t_url_constant url_authtype[] =
{
#if LIBCURL_VERSION_NUM >= 0x071504
/* libcurl >= 7.21.4 */
URL_DEF_CONST(_TLSAUTH, NONE),
URL_DEF_CONST(_TLSAUTH, SRP),
#endif
{ NULL, 0 },
};
struct t_url_constant url_postredir[] =
{
#if LIBCURL_VERSION_NUM >= 0x071301
/* libcurl >= 7.19.1 */
URL_DEF_CONST(_REDIR, POST_301),
URL_DEF_CONST(_REDIR, POST_302),
#endif
{ NULL, 0 },
};
struct t_url_option url_options[] =
{
/* behavior options */
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(HEADER, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071501
/* libcurl >= 7.21 */
URL_DEF_OPTION(WILDCARDMATCH, LONG, NULL),
#endif
/* error options */
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(FAILONERROR, LONG, NULL),
#endif
/* network options */
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_OPTION(PROTOCOLS, MASK, url_protocols),
URL_DEF_OPTION(REDIR_PROTOCOLS, MASK, url_protocols),
#endif
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(PROXY, STRING, NULL),
URL_DEF_OPTION(PROXYPORT, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A00
/* libcurl >= 7.10 */
URL_DEF_OPTION(PROXYTYPE, LONG, url_proxy_types),
#endif
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_OPTION(NOPROXY, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070300
/* libcurl >= 7.3 */
URL_DEF_OPTION(HTTPPROXYTUNNEL, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071304
/* libcurl >= 7.19.4 */
URL_DEF_OPTION(SOCKS5_GSSAPI_SERVICE, STRING, NULL),
URL_DEF_OPTION(SOCKS5_GSSAPI_NEC, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070300
/* libcurl >= 7.3 */
URL_DEF_OPTION(INTERFACE, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070F02
/* libcurl >= 7.15.2 */
URL_DEF_OPTION(LOCALPORT, LONG, NULL),
URL_DEF_OPTION(LOCALPORTRANGE, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070903
/* libcurl >= 7.9.3 */
URL_DEF_OPTION(DNS_CACHE_TIMEOUT, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A00
/* libcurl >= 7.10 */
URL_DEF_OPTION(BUFFERSIZE, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(PORT, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070B02
/* libcurl >= 7.11.2 */
URL_DEF_OPTION(TCP_NODELAY, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071300
/* libcurl >= 7.19.0 */
URL_DEF_OPTION(ADDRESS_SCOPE, LONG, NULL),
#endif
/* name and password options (authentication) */
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(NETRC, LONG, url_netrc),
#endif
#if LIBCURL_VERSION_NUM >= 0x070B00
/* libcurl >= 7.11.0 */
URL_DEF_OPTION(NETRC_FILE, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(USERPWD, STRING, NULL),
URL_DEF_OPTION(PROXYUSERPWD, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071301
/* libcurl >= 7.19.1 */
URL_DEF_OPTION(USERNAME, STRING, NULL),
URL_DEF_OPTION(PASSWORD, STRING, NULL),
URL_DEF_OPTION(PROXYUSERNAME, STRING, NULL),
URL_DEF_OPTION(PROXYPASSWORD, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A06
/* libcurl >= 7.10.6 */
URL_DEF_OPTION(HTTPAUTH, MASK, url_auth),
#endif
#if LIBCURL_VERSION_NUM >= 0x071504
/* libcurl >= 7.21.4 */
URL_DEF_OPTION(TLSAUTH_TYPE, MASK, url_authtype),
URL_DEF_OPTION(TLSAUTH_USERNAME, STRING, NULL),
URL_DEF_OPTION(TLSAUTH_PASSWORD, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A07
/* libcurl >= 7.10.7 */
URL_DEF_OPTION(PROXYAUTH, MASK, url_auth),
#endif
/* HTTP options */
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(AUTOREFERER, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071506
/* libcurl >= 7.15.6 */
URL_DEF_OPTION(ACCEPT_ENCODING, STRING, NULL),
URL_DEF_OPTION(TRANSFER_ENCODING, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(FOLLOWLOCATION, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070A04
/* libcurl >= 7.10.4 */
URL_DEF_OPTION(UNRESTRICTED_AUTH, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070500
/* libcurl >= 7.5 */
URL_DEF_OPTION(MAXREDIRS, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x071301
/* libcurl >= 7.19.1 */
URL_DEF_OPTION(POSTREDIR, MASK, url_postredir),
#endif
#if LIBCURL_VERSION_NUM >= 0x070100
/* libcurl >= 7.1 */
URL_DEF_OPTION(POST, LONG, NULL),
URL_DEF_OPTION(POSTFIELDS, STRING, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x070200
/* libcurl >= 7.2 */
URL_DEF_OPTION(POSTFIELDSIZE, LONG, NULL),
#endif
{ NULL, 0, 0, NULL },
};
/*
* weeurl_search_constant: search a constant in array of constants
*/
int
weeurl_search_constant (struct t_url_constant *constants, const char *name)
{
int i;
for (i = 0; constants[i].name; i++)
{
if (string_strcasecmp (constants[i].name, name) == 0)
{
return i;
}
}
/* constant not found */
return -1;
}
/*
* weeurl_get_mask_value: get value of mask using constants
* string_mask has format: "const1+const2+const3"
*/
long
weeurl_get_mask_value (struct t_url_constant *constants,
const char *string_mask)
{
char **items, *item;
int num_items, i, index;
long mask;
mask = 0;
items = string_split (string_mask, "+", 0, 0, &num_items);
if (items)
{
for (i = 0; i < num_items; i++)
{
item = string_remove_quotes(items[i], "'\"");
if (item)
{
index = weeurl_search_constant (constants, item);
if (index >= 0)
mask |= constants[index].value;
free (item);
}
}
string_free_split (items);
}
return mask;
}
/*
* weeurl_search_option: search an url option in table of options
*/
int
weeurl_search_option (const char *name)
{
int i;
for (i = 0; url_options[i].name; i++)
{
if (string_strcasecmp (url_options[i].name, name) == 0)
{
return i;
}
}
/* option not found */
return -1;
}
/*
* weeurl_read: read callback for curl, used to read data from a file
*/
size_t
weeurl_read (void *buffer, size_t size, size_t nmemb, void *stream)
{
return (stream) ? fread (buffer, size, nmemb, stream) : 0;
}
/*
* weeurl_write: write callback for curl, used to write data in a file
*/
size_t
weeurl_write (void *buffer, size_t size, size_t nmemb, void *stream)
{
return (stream) ? fwrite (buffer, size, nmemb, stream) : 0;
}
/*
* weeurl_set_options: callback called for each option in hashtable "options",
* it sets option in CURL easy handle
*/
void
weeurl_option_map_cb (void *data,
struct t_hashtable *hashtable,
const void *key, const void *value)
{
CURL *curl;
int index, index_constant, rc;
long long_value;
/* make C compiler happy */
(void) hashtable;
curl = (CURL *)data;
if (!curl)
return;
index = weeurl_search_option ((const char *)key);
if (index >= 0)
{
switch (url_options[index].type)
{
case URL_TYPE_STRING:
curl_easy_setopt (curl, url_options[index].option,
(const char *)value);
break;
case URL_TYPE_LONG:
if (url_options[index].constants)
{
index_constant = weeurl_search_constant (url_options[index].constants,
(const char *)value);
if (index_constant >= 0)
{
curl_easy_setopt (curl, url_options[index].option,
url_options[index].constants[index_constant].value);
}
}
else
{
rc = sscanf ((const char *)value, "%ld", &long_value);
if (rc != EOF)
{
curl_easy_setopt (curl, url_options[index].option,
long_value);
}
}
break;
case URL_TYPE_MASK:
if (url_options[index].constants)
{
long_value = weeurl_get_mask_value (url_options[index].constants,
(const char *)value);
curl_easy_setopt (curl, url_options[index].option,
long_value);
}
break;
}
}
return;
}
/*
* weeurl_download: download URL, using options
* return code:
* 0: ok
* 1: invalid url
* 2: error downloading url
* 3: memory error
* 4: file error
*/
int
weeurl_download (const char *url, struct t_hashtable *options)
{
CURL *curl;
struct t_url_file url_file[2];
char *url_file_option[2] = { "file_in", "file_out" };
char *url_file_mode[2] = { "rb", "wb" };
CURLoption url_file_opt_func[2] = { CURLOPT_READFUNCTION, CURLOPT_WRITEFUNCTION };
CURLoption url_file_opt_data[2] = { CURLOPT_READDATA, CURLOPT_WRITEDATA };
void *url_file_opt_cb[2] = { &weeurl_read, &weeurl_write };
int rc, i;
rc = 0;
for (i = 0; i < 2; i++)
{
url_file[i].filename = NULL;
url_file[i].stream = NULL;
}
if (!url || !url[0])
{
rc = 1;
goto end;
}
curl = curl_easy_init();
if (!curl)
{
rc = 3;
goto end;
}
/* set default options */
curl_easy_setopt (curl, CURLOPT_URL, url);
curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, "1");
/* set file in/out from options in hashtable */
if (options)
{
for (i = 0; i < 2; i++)
{
url_file[i].filename = hashtable_get (options, url_file_option[i]);
if (url_file[i].filename)
{
url_file[i].stream = fopen (url_file[i].filename, url_file_mode[i]);
if (!url_file[i].stream)
{
rc = 4;
goto end;
}
curl_easy_setopt (curl, url_file_opt_func[i], url_file_opt_cb[i]);
curl_easy_setopt (curl, url_file_opt_data[i], url_file[i].stream);
}
}
}
/* set other options in hashtable */
hashtable_map (options, &weeurl_option_map_cb, curl);
/* perform action! */
if (curl_easy_perform (curl) != CURLE_OK)
rc = 2;
/* cleanup */
curl_easy_cleanup (curl);
end:
for (i = 0; i < 2; i++)
{
if (url_file[i].stream)
fclose (url_file[i].stream);
}
return rc;
}
/*
* weeurl_option_add_to_infolist: add an url option in an infolist
* return 1 if ok, 0 if error
*/
int
weeurl_option_add_to_infolist (struct t_infolist *infolist,
struct t_url_option *option)
{
struct t_infolist_item *ptr_item;
char *constants;
int i, length;
if (!infolist || !option)
return 0;
ptr_item = infolist_new_item (infolist);
if (!ptr_item)
return 0;
if (!infolist_new_var_string (ptr_item, "name", option->name))
return 0;
if (!infolist_new_var_integer (ptr_item, "option", option->option))
return 0;
if (!infolist_new_var_string (ptr_item, "type", url_type_string[option->type]))
return 0;
if (option->constants)
{
length = 1;
for (i = 0; option->constants[i].name; i++)
{
length += strlen (option->constants[i].name) + 1;
}
constants = malloc (length);
if (constants)
{
constants[0] = '\0';
for (i = 0; option->constants[i].name; i++)
{
if (i > 0)
strcat (constants, ",");
strcat (constants, option->constants[i].name);
}
if (!infolist_new_var_string (ptr_item, "constants", constants))
{
free (constants);
return 0;
}
free (constants);
}
}
return 1;
}
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2012 Sebastien 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/>.
*/
#ifndef __WEECHAT_URL_H
#define __WEECHAT_URL_H 1
struct t_hashtable;
struct t_infolist;
enum t_url_type
{
URL_TYPE_STRING = 0,
URL_TYPE_LONG,
URL_TYPE_MASK,
};
struct t_url_constant
{
char *name; /* string with name of constant */
long value; /* value of constant */
};
struct t_url_option
{
char *name; /* name of option */
int option; /* option (for curl_easy_setopt()) */
enum t_url_type type; /* type of argument expected */
struct t_url_constant *constants; /* constants allowed for this option */
};
struct t_url_file
{
char *filename; /* filename */
FILE *stream; /* file stream */
};
extern struct t_url_option url_options[];
extern int weeurl_download (const char *url, struct t_hashtable *options);
extern int weeurl_option_add_to_infolist (struct t_infolist *infolist,
struct t_url_option *option);
#endif /* __WEECHAT_URL_H */
+2
View File
@@ -71,6 +71,8 @@ ENDIF(LIBINTL_LIBRARY)
LIST(APPEND EXTRA_LIBS "m")
LIST(APPEND EXTRA_LIBS ${CURL_LIBRARIES})
ADD_EXECUTABLE(${EXECUTABLE} ${WEECHAT_CURSES_SRC})
INCLUDE_DIRECTORIES(.. ../../core ../../plugins)
+1
View File
@@ -31,6 +31,7 @@ weechat_curses_LDADD = ./../../core/lib_weechat_core.a \
$(NCURSES_LFLAGS) \
$(GCRYPT_LFLAGS) \
$(GNUTLS_LFLAGS) \
$(CURL_LFLAGS) \
-lm
weechat_curses_SOURCES = gui-curses-bar-window.c \
+2
View File
@@ -64,6 +64,8 @@ IF(LIBINTL_LIBRARY)
LIST(APPEND EXTRA_LIBS ${LIBINTL_LIBRARY})
ENDIF(LIBINTL_LIBRARY)
LIST(APPEND EXTRA_LIBS ${CURL_LIBRARIES})
ADD_EXECUTABLE(${EXECUTABLE} ${WEECHAT_GTK_SRC})
INCLUDE_DIRECTORIES(.. ../../core ../../plugins)
+2 -1
View File
@@ -30,7 +30,8 @@ weechat_gtk_LDADD = ./../../core/lib_weechat_core.a \
$(PLUGINS_LFLAGS) \
$(GTK_LFLAGS) \
$(GCRYPT_LFLAGS) \
$(GNUTLS_LFLAGS)
$(GNUTLS_LFLAGS) \
$(CURL_LFLAGS)
weechat_gtk_SOURCES = gui-gtk-bar-window.c \
gui-gtk-chat.c \
+22 -1
View File
@@ -42,6 +42,7 @@
#include "../core/wee-infolist.h"
#include "../core/wee-input.h"
#include "../core/wee-string.h"
#include "../core/wee-url.h"
#include "../core/wee-util.h"
#include "../gui/gui-bar.h"
#include "../gui/gui-bar-item.h"
@@ -400,7 +401,7 @@ plugin_api_infolist_get_internal (void *data, const char *infolist_name,
struct t_gui_hotlist *ptr_hotlist;
struct t_gui_key *ptr_key;
struct t_weechat_plugin *ptr_plugin;
int context, number;
int context, number, i;
char *error;
/* make C compiler happy */
@@ -770,6 +771,22 @@ plugin_api_infolist_get_internal (void *data, const char *infolist_name,
}
}
}
else if (string_strcasecmp (infolist_name, "url_options") == 0)
{
ptr_infolist = infolist_new ();
if (ptr_infolist)
{
for (i = 0; url_options[i].name; i++)
{
if (!weeurl_option_add_to_infolist (ptr_infolist, &url_options[i]))
{
infolist_free (ptr_infolist);
return NULL;
}
}
return ptr_infolist;
}
}
else if (string_strcasecmp (infolist_name, "window") == 0)
{
/* invalid window pointer ? */
@@ -1080,6 +1097,10 @@ plugin_api_init ()
N_("plugin pointer (optional)"),
N_("plugin name (can start or end with \"*\" as wildcard) (optional)"),
&plugin_api_infolist_get_internal, NULL);
hook_infolist (NULL, "url_options", N_("options for URL"),
NULL,
NULL,
&plugin_api_infolist_get_internal, NULL);
hook_infolist (NULL, "window", N_("list of windows"),
N_("window pointer (optional)"),
N_("\"current\" for current window or a window number (optional)"),
+1
View File
@@ -634,6 +634,7 @@ plugin_load (const char *filename, int argc, char **argv)
new_plugin->hook_timer = &hook_timer;
new_plugin->hook_fd = &hook_fd;
new_plugin->hook_process = &hook_process;
new_plugin->hook_process_hashtable = &hook_process_hashtable;
new_plugin->hook_connect = &hook_connect;
new_plugin->hook_print = &hook_print;
new_plugin->hook_signal = &hook_signal;
+40
View File
@@ -2667,6 +2667,45 @@ weechat_lua_api_hook_process (lua_State *L)
API_RETURN_STRING_FREE(result);
}
/*
* weechat_lua_api_hook_process_hashtable: hook a process with options in
* a hashtable
*/
static int
weechat_lua_api_hook_process_hashtable (lua_State *L)
{
const char *command, *function, *data;
struct t_hashtable *options;
int timeout;
char *result;
API_FUNC(1, "hook_process_hashtable", API_RETURN_EMPTY);
if (lua_gettop (lua_current_interpreter) < 5)
API_WRONG_ARGS(API_RETURN_EMPTY);
command = lua_tostring (lua_current_interpreter, -5);
options = weechat_lua_tohashtable (lua_current_interpreter, -4,
WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE);
timeout = lua_tonumber (lua_current_interpreter, -3);
function = lua_tostring (lua_current_interpreter, -2);
data = lua_tostring (lua_current_interpreter, -1);
result = script_ptr2str (script_api_hook_process_hashtable (weechat_lua_plugin,
lua_current_script,
command,
options,
timeout,
&weechat_lua_api_hook_process_cb,
function,
data));
if (options)
weechat_hashtable_free (options);
API_RETURN_STRING_FREE(result);
}
/*
* weechat_lua_api_hook_connect_cb: callback for connect hooked
*/
@@ -6207,6 +6246,7 @@ const struct luaL_reg weechat_lua_api_funcs[] = {
API_DEF_FUNC(hook_timer),
API_DEF_FUNC(hook_fd),
API_DEF_FUNC(hook_process),
API_DEF_FUNC(hook_process_hashtable),
API_DEF_FUNC(hook_connect),
API_DEF_FUNC(hook_print),
API_DEF_FUNC(hook_signal),
@@ -2505,6 +2505,41 @@ XS (XS_weechat_api_hook_process)
API_RETURN_STRING_FREE(result);
}
/*
* weechat::hook_process_hashtable: hook a process with options in a hashtable
*/
XS (XS_weechat_api_hook_process_hashtable)
{
char *command, *function, *data, *result;
struct t_hashtable *options;
dXSARGS;
API_FUNC(1, "hook_process_hashtable", API_RETURN_EMPTY);
if (items < 5)
API_WRONG_ARGS(API_RETURN_EMPTY);
command = SvPV_nolen (ST (0));
options = weechat_perl_hash_to_hashtable (ST (1),
WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE);
function = SvPV_nolen (ST (3));
data = SvPV_nolen (ST (4));
result = script_ptr2str (script_api_hook_process_hashtable (weechat_perl_plugin,
perl_current_script,
command,
options,
SvIV (ST (2)), /* timeout */
&weechat_perl_api_hook_process_cb,
function,
data));
if (options)
weechat_hashtable_free (options);
API_RETURN_STRING_FREE(result);
}
/*
* weechat_perl_api_hook_connect_cb: callback for connect hooked
*/
@@ -5565,6 +5600,7 @@ weechat_perl_api_init (pTHX)
API_DEF_FUNC(hook_timer);
API_DEF_FUNC(hook_fd);
API_DEF_FUNC(hook_process);
API_DEF_FUNC(hook_process_hashtable);
API_DEF_FUNC(hook_connect);
API_DEF_FUNC(hook_print);
API_DEF_FUNC(hook_signal);
@@ -2608,6 +2608,46 @@ weechat_python_api_hook_process (PyObject *self, PyObject *args)
API_RETURN_STRING_FREE(result);
}
/*
* weechat_python_api_hook_process_hashtable: hook a process with options in
* a hashtable
*/
static PyObject *
weechat_python_api_hook_process_hashtable (PyObject *self, PyObject *args)
{
char *command, *function, *data, *result;
int timeout;
struct t_hashtable *options;
PyObject *dict, *return_value;
API_FUNC(1, "hook_process_hashtable", API_RETURN_EMPTY);
command = NULL;
options = NULL;
timeout = 0;
function = NULL;
data = NULL;
if (!PyArg_ParseTuple (args, "sOiss", &command, &dict, &timeout, &function,
&data))
API_WRONG_ARGS(API_RETURN_EMPTY);
options = weechat_python_dict_to_hashtable (dict,
WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE);
result = script_ptr2str (script_api_hook_process_hashtable (weechat_python_plugin,
python_current_script,
command,
options,
timeout,
&weechat_python_api_hook_process_cb,
function,
data));
if (options)
weechat_hashtable_free (options);
API_RETURN_STRING_FREE(result);
}
/*
* weechat_python_api_hook_connect_cb: callback for connect hooked
*/
@@ -5733,6 +5773,7 @@ PyMethodDef weechat_python_funcs[] =
API_DEF_FUNC(hook_timer),
API_DEF_FUNC(hook_fd),
API_DEF_FUNC(hook_process),
API_DEF_FUNC(hook_process_hashtable),
API_DEF_FUNC(hook_connect),
API_DEF_FUNC(hook_print),
API_DEF_FUNC(hook_signal),
@@ -2988,6 +2988,54 @@ weechat_ruby_api_hook_process (VALUE class, VALUE command, VALUE timeout,
API_RETURN_STRING_FREE(result);
}
/*
* weechat_ruby_api_hook_process_hashtable: hook a process with options in
* a hashtable
*/
static VALUE
weechat_ruby_api_hook_process_hashtable (VALUE class, VALUE command,
VALUE options, VALUE timeout,
VALUE function, VALUE data)
{
char *c_command, *c_function, *c_data, *result;
struct t_hashtable *c_options;
int c_timeout;
VALUE return_value;
API_FUNC(1, "hook_process_hashtable", API_RETURN_EMPTY);
if (NIL_P (command) || NIL_P (options) || NIL_P (timeout)
|| NIL_P (function) || NIL_P (data))
API_WRONG_ARGS(API_RETURN_EMPTY);
Check_Type (command, T_STRING);
Check_Type (options, T_HASH);
Check_Type (timeout, T_FIXNUM);
Check_Type (function, T_STRING);
Check_Type (data, T_STRING);
c_command = StringValuePtr (command);
c_options = weechat_ruby_hash_to_hashtable (options,
WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE);
c_timeout = FIX2INT (timeout);
c_function = StringValuePtr (function);
c_data = StringValuePtr (data);
result = script_ptr2str (script_api_hook_process_hashtable (weechat_ruby_plugin,
ruby_current_script,
c_command,
c_options,
c_timeout,
&weechat_ruby_api_hook_process_cb,
c_function,
c_data));
if (c_options)
weechat_hashtable_free (c_options);
API_RETURN_STRING_FREE(result);
}
/*
* weechat_ruby_api_hook_connect_cb: callback for connect hooked
*/
@@ -6638,6 +6686,7 @@ weechat_ruby_api_init (VALUE ruby_mWeechat)
API_DEF_FUNC(hook_timer, 5);
API_DEF_FUNC(hook_fd, 6);
API_DEF_FUNC(hook_process, 4);
API_DEF_FUNC(hook_process_hashtable, 5);
API_DEF_FUNC(hook_connect, 8);
API_DEF_FUNC(hook_print, 6);
API_DEF_FUNC(hook_signal, 3);
+47 -23
View File
@@ -859,7 +859,50 @@ script_api_hook_fd (struct t_weechat_plugin *weechat_plugin,
}
/*
* script_api_hook_connect: hook a connection
* script_api_hook_process_hashtable: hook a process
* return new hook, NULL if error
*/
struct t_hook *
script_api_hook_process_hashtable (struct t_weechat_plugin *weechat_plugin,
struct t_plugin_script *script,
const char *command,
struct t_hashtable *options,
int timeout,
int (*callback)(void *data,
const char *command,
int return_code,
const char *out,
const char *err),
const char *function,
const char *data)
{
struct t_script_callback *new_script_callback;
struct t_hook *new_hook;
new_script_callback = script_callback_alloc ();
if (!new_script_callback)
return NULL;
script_callback_init (new_script_callback, script, function, data);
script_callback_add (script, new_script_callback);
new_hook = weechat_hook_process_hashtable (command, options, timeout,
callback, new_script_callback);
if (!new_hook)
{
script_callback_remove (script, new_script_callback);
return NULL;
}
new_script_callback->hook = new_hook;
return new_hook;
}
/*
* script_api_hook_process: hook a process
* return new hook, NULL if error
*/
@@ -876,28 +919,9 @@ script_api_hook_process (struct t_weechat_plugin *weechat_plugin,
const char *function,
const char *data)
{
struct t_script_callback *new_script_callback;
struct t_hook *new_hook;
new_script_callback = script_callback_alloc ();
if (!new_script_callback)
return NULL;
script_callback_init (new_script_callback, script, function, data);
script_callback_add (script, new_script_callback);
new_hook = weechat_hook_process (command, timeout, callback,
new_script_callback);
if (!new_hook)
{
script_callback_remove (script, new_script_callback);
return NULL;
}
new_script_callback->hook = new_hook;
return new_hook;
return script_api_hook_process_hashtable (weechat_plugin, script, command,
NULL, timeout,
callback, function, data);
}
/*
+12
View File
@@ -152,6 +152,18 @@ extern struct t_hook *script_api_hook_fd (struct t_weechat_plugin *weechat_plugi
int (*callback)(void *data, int fd),
const char *function,
const char *data);
extern struct t_hook *script_api_hook_process_hashtable (struct t_weechat_plugin *weechat_plugin,
struct t_plugin_script *script,
const char *command,
struct t_hashtable *options,
int timeout,
int (*callback)(void *data,
const char *command,
int return_code,
const char *out,
const char *err),
const char *function,
const char *data);
extern struct t_hook *script_api_hook_process (struct t_weechat_plugin *weechat_plugin,
struct t_plugin_script *script,
const char *command,
+44
View File
@@ -2933,6 +2933,49 @@ weechat_tcl_api_hook_process (ClientData clientData, Tcl_Interp *interp,
API_RETURN_STRING_FREE(result);
}
/*
* weechat_tcl_api_hook_process_hashtable: hook a process with options in
* a hashtable
*/
static int
weechat_tcl_api_hook_process_hashtable (ClientData clientData,
Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
Tcl_Obj *objp;
char *command, *function, *data, *result;
struct t_hashtable *options;
int i, timeout;
API_FUNC(1, "hook_process_hashtable", API_RETURN_EMPTY);
if (objc < 6)
API_WRONG_ARGS(API_RETURN_EMPTY);
if ((Tcl_GetIntFromObj (interp, objv[3], &timeout) != TCL_OK))
API_WRONG_ARGS(API_RETURN_EMPTY);
command = Tcl_GetStringFromObj (objv[1], &i);
options = weechat_tcl_dict_to_hashtable (interp, objv[2],
WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE);
function = Tcl_GetStringFromObj (objv[4], &i);
data = Tcl_GetStringFromObj (objv[5], &i);
result = script_ptr2str (script_api_hook_process_hashtable (weechat_tcl_plugin,
tcl_current_script,
command,
options,
timeout,
&weechat_tcl_api_hook_process_cb,
function,
data));
if (options)
weechat_hashtable_free (options);
API_RETURN_STRING_FREE(result);
}
/*
* weechat_tcl_api_hook_connect_cb: callback for connect hooked
*/
@@ -6380,6 +6423,7 @@ void weechat_tcl_api_init (Tcl_Interp *interp)
API_DEF_FUNC(hook_timer);
API_DEF_FUNC(hook_fd);
API_DEF_FUNC(hook_process);
API_DEF_FUNC(hook_process_hashtable);
API_DEF_FUNC(hook_connect);
API_DEF_FUNC(hook_print);
API_DEF_FUNC(hook_signal);
+16 -1
View File
@@ -46,7 +46,7 @@ struct timeval;
*/
/* API version (used to check that plugin has same API and can be loaded) */
#define WEECHAT_PLUGIN_API_VERSION "20111219-01"
#define WEECHAT_PLUGIN_API_VERSION "20120112-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@@ -516,6 +516,16 @@ struct t_weechat_plugin
const char *out,
const char *err),
void *callback_data);
struct t_hook *(*hook_process_hashtable) (struct t_weechat_plugin *plugin,
const char *command,
struct t_hashtable *options,
int timeout,
int (*callback)(void *data,
const char *command,
int return_code,
const char *out,
const char *err),
void *callback_data);
struct t_hook *(*hook_connect) (struct t_weechat_plugin *plugin,
const char *proxy,
const char *address,
@@ -1281,6 +1291,11 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
__callback_data) \
weechat_plugin->hook_process(weechat_plugin, __command, __timeout, \
__callback, __callback_data)
#define weechat_hook_process_hashtable(__command, __options, __timeout, \
__callback, __callback_data) \
weechat_plugin->hook_process_hashtable(weechat_plugin, __command, \
__options, __timeout, \
__callback, __callback_data)
#define weechat_hook_connect(__proxy, __address, __port, __sock, \
__ipv6, __gnutls_sess, __gnutls_cb, \
__gnutls_dhkey_size, __gnutls_priorities, \