diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2012-01-16 19:52:08 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2012-01-16 19:52:08 +0100 |
commit | b91c231096c726d0d8ecdc4c88e19a229feb615b (patch) | |
tree | df21ac2dccdbedcba04e14345339f2f702249193 /src/core | |
parent | ca07f584063aa68f0c5d3263128f4149bb61b5e0 (diff) | |
download | weechat-b91c231096c726d0d8ecdc4c88e19a229feb615b.zip |
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)
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/core/Makefile.am | 4 | ||||
-rw-r--r-- | src/core/wee-hook.c | 70 | ||||
-rw-r--r-- | src/core/wee-hook.h | 7 | ||||
-rw-r--r-- | src/core/wee-url.c | 628 | ||||
-rw-r--r-- | src/core/wee-url.h | 59 |
6 files changed, 759 insertions, 12 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6dd15ea1e..f5afb1803 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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}) diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 78ebf7e36..ae69f3ec0 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -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 \ diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c index a7824339a..9ad507526 100644 --- a/src/core/wee-hook.c +++ b/src/core/wee-hook.c @@ -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; @@ -1363,6 +1366,19 @@ hook_process (struct t_weechat_plugin *plugin, } /* + * 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])); diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h index 38faf5c7e..2c8d1200e 100644 --- a/src/core/wee-hook.h +++ b/src/core/wee-hook.h @@ -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, diff --git a/src/core/wee-url.c b/src/core/wee-url.c new file mode 100644 index 000000000..c64253e37 --- /dev/null +++ b/src/core/wee-url.c @@ -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; +} diff --git a/src/core/wee-url.h b/src/core/wee-url.h new file mode 100644 index 000000000..bb83fbdd9 --- /dev/null +++ b/src/core/wee-url.h @@ -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 */ |