| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2017-04-22 22:24:06 +0200 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2017-04-22 22:24:06 +0200 |
| commit | 7c321d614e8d91b23434b13bfcf89274797815ec (patch) | |
| tree | 58b8e4fcba63b38a052423401df413606a7e8076 /src | |
Initial Commit.
Diffstat (limited to 'src')
27 files changed, 1869 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..5d1adf6 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,11 @@ +add_subdirectory(error) +add_subdirectory(parameters) +add_subdirectory(meta_net) +add_subdirectory(irc) + +set( + SRC_FILES ${SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/main.c +) + +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) diff --git a/src/error/CMakeLists.txt b/src/error/CMakeLists.txt new file mode 100644 index 0000000..fa07534 --- /dev/null +++ b/src/error/CMakeLists.txt @@ -0,0 +1,6 @@ +set( + SRC_FILES ${SRC_FILES} +) + +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) + diff --git a/src/error/error.h b/src/error/error.h new file mode 100644 index 0000000..145c838 --- /dev/null +++ b/src/error/error.h @@ -0,0 +1,143 @@ +#ifndef _JH_ERROR_ERROR_H_ +#define _JH_ERROR_ERROR_H_ + +#include <stdio.h> + +#include "../pervasive.h" + +#ifndef JH_DEBUG_PROGRAM_FLOW + #define JH_DEBUG_PROGRAM_FLOW (0 || JH_DEBUG_ALL) +#endif + +#ifndef JH_DEBUG_CONFIG + #define JH_DEBUG_CONFIG (0 || JH_DEBUG_ALL) +#endif + +#ifndef JH_DEBUG_LEARNING + #define JH_DEBUG_LEARNING (0 || JH_DEBUG_ALL) +#endif + +#ifndef JH_DEBUG_NETWORK + #define JH_DEBUG_NETWORK 1 +#endif + +#ifndef JH_DEBUG_NETWORK + #define JH_DEBUG_NETWORK (0 || JH_DEBUG_ALL) +#endif + +#define JH_ENABLE_WARNINGS_OUTPUT 1 +#define JH_ENABLE_RUNTIME_ERRORS_OUTPUT 1 +#define JH_ENABLE_PROGRAMMING_ERRORS_OUTPUT 1 +#define JH_ENABLE_FATAL_ERROR_OUTPUT 1 + +#ifdef JH_ENABLE_ERROR_LOCATION + #define JH_LOCATION " [" __FILE__ "][" JH_TO_STRING(__LINE__) "]" +#else + #define JH_LOCATION "" +#endif + +#define JH_PRINT_STDERR(io, symbol, str, ...)\ + fprintf(io, "[" symbol "]" JH_LOCATION " " str "\n", __VA_ARGS__); + +/* + * Given that we use preprocessor contants as flags, we can expect the compilers + * to remove the test condition for disabled flags. No need to be shy about + * allowing many debug options. + */ + +#define JH_DEBUG(io, flag, str, ...)\ + JH_ISOLATE\ + (\ + if (flag)\ + {\ + JH_PRINT_STDERR(io, "D", str, __VA_ARGS__);\ + }\ + ) + + +#define JH_WARNING(io, str, ...)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_WARNINGS_OUTPUT)\ + {\ + JH_PRINT_STDERR(io, "W", str, __VA_ARGS__);\ + }\ + ) + +#define JH_ERROR(io, str, ...)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_RUNTIME_ERRORS_OUTPUT)\ + {\ + JH_PRINT_STDERR(io, "E", str, __VA_ARGS__);\ + }\ + ) + +#define JH_PROG_ERROR(io, str, ...)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\ + {\ + JH_PRINT_STDERR(io, "P", str, __VA_ARGS__);\ + }\ + ) + +#define JH_FATAL(io, str, ...)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_FATAL_ERROR_OUTPUT)\ + {\ + JH_PRINT_STDERR(io, "F", str, __VA_ARGS__);\ + }\ + ) + +/* For outputs without dynamic content (static). ******************************/ + +#define JH_PRINT_S_STDERR(io, symbol, str)\ + fprintf(io, "[" symbol "]" JH_LOCATION " " str "\n"); + +#define JH_S_DEBUG(io, flag, str)\ + JH_ISOLATE\ + (\ + if (flag)\ + {\ + JH_PRINT_S_STDERR(io, "D", str);\ + }\ + ) + +#define JH_S_WARNING(io, str)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_WARNINGS_OUTPUT)\ + {\ + JH_PRINT_S_STDERR(io, "W", str);\ + }\ + ) + +#define JH_S_ERROR(io, str)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_RUNTIME_ERRORS_OUTPUT)\ + {\ + JH_PRINT_S_STDERR(io, "E", str);\ + }\ + ) + +#define JH_S_PROG_ERROR(io, str)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_PROGRAMMING_ERRORS_OUTPUT)\ + {\ + JH_PRINT_S_STDERR(io, "P", str);\ + }\ + ) + +#define JH_S_FATAL(io, str)\ + JH_ISOLATE\ + (\ + if (JH_ENABLE_FATAL_ERROR_OUTPUT)\ + {\ + JH_PRINT_S_STDERR(io, "F", str);\ + }\ + ) +#endif diff --git a/src/irc/CMakeLists.txt b/src/irc/CMakeLists.txt new file mode 100644 index 0000000..b037d15 --- /dev/null +++ b/src/irc/CMakeLists.txt @@ -0,0 +1,11 @@ +set( + SRC_FILES ${SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/irc.c + ${CMAKE_CURRENT_SOURCE_DIR}/irc_handle_connected.c + ${CMAKE_CURRENT_SOURCE_DIR}/irc_handle_dcc_events.c + ${CMAKE_CURRENT_SOURCE_DIR}/irc_receive.c + ${CMAKE_CURRENT_SOURCE_DIR}/irc_select.c + ${CMAKE_CURRENT_SOURCE_DIR}/irc_send.c +) + +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) diff --git a/src/irc/irc.c b/src/irc/irc.c new file mode 100644 index 0000000..3e0bca7 --- /dev/null +++ b/src/irc/irc.c @@ -0,0 +1,110 @@ +#include <libircclient/libircclient.h> + +#include <string.h> + +#include "../error/error.h" + +#include "../parameters/parameters.h" + +#include "irc.h" +#include "irc_event_handlers.h" + +int JH_irc_initialize +( + struct JH_irc irc [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + struct JH_meta_net jh_net [const restrict static 1] +) +{ + memset((void *) &(irc->callbacks), 0, sizeof(irc_callbacks_t)); + + irc->callbacks.event_connect = JH_irc_handle_connected_event; + irc->callbacks.event_join = JH_irc_do_nothing; + irc->callbacks.event_nick = JH_irc_do_nothing; + irc->callbacks.event_quit = JH_irc_do_nothing; + irc->callbacks.event_part = JH_irc_do_nothing; + irc->callbacks.event_mode = JH_irc_do_nothing; + irc->callbacks.event_topic = JH_irc_do_nothing; + irc->callbacks.event_kick = JH_irc_do_nothing; + irc->callbacks.event_channel = JH_irc_handle_channel_message_event; + irc->callbacks.event_privmsg = JH_irc_do_nothing; + irc->callbacks.event_notice = JH_irc_do_nothing; + irc->callbacks.event_invite = JH_irc_do_nothing; + irc->callbacks.event_umode = JH_irc_do_nothing; + + irc->callbacks.event_ctcp_rep = JH_irc_do_nothing; + irc->callbacks.event_ctcp_action = JH_irc_handle_ctcp_action_event; + irc->callbacks.event_unknown = JH_irc_do_nothing; + irc->callbacks.event_numeric = JH_irc_handle_numeric_event; + + irc->callbacks.event_dcc_chat_req = JH_irc_handle_dcc_chat_req_event; + irc->callbacks.event_dcc_send_req = JH_irc_handle_dcc_send_req_event; + + irc->session = irc_create_session(&(irc->callbacks)); + + irc->params = params; + irc->jh_net = jh_net; + + if (!(irc->session)) + { + JH_S_FATAL(stderr, "Unable to create IRC session."); + + return -1; + } + + return 0; +} + +int JH_irc_connect (struct JH_irc irc [const restrict static 1]) +{ + if (JH_parameters_get_irc_is_ipv6(irc->params)) + { + return + irc_connect6 + ( + irc->session, + JH_parameters_get_irc_server(irc->params), + JH_parameters_get_irc_port(irc->params), + JH_parameters_get_irc_password(irc->params), + JH_parameters_get_irc_nick(irc->params), + JH_parameters_get_irc_username(irc->params), + JH_parameters_get_irc_realname(irc->params) + ); + } + else + { + return + irc_connect + ( + irc->session, + JH_parameters_get_irc_server(irc->params), + JH_parameters_get_irc_port(irc->params), + JH_parameters_get_irc_password(irc->params), + JH_parameters_get_irc_nick(irc->params), + JH_parameters_get_irc_username(irc->params), + JH_parameters_get_irc_realname(irc->params) + ); + } +} + +void JH_irc_do_nothing +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +) +{ +} + +void JH_irc_handle_numeric_event +( + irc_session_t * session, + unsigned int event, + const char * origin, + const char ** params, + unsigned int count +) +{ +} diff --git a/src/irc/irc.h b/src/irc/irc.h new file mode 100644 index 0000000..9bdfcef --- /dev/null +++ b/src/irc/irc.h @@ -0,0 +1,43 @@ +#ifndef _JH_IRC_IRC_H_ +#define _JH_IRC_IRC_H_ + +#include "../parameters/parameters_types.h" + +#include "../meta_net/meta_net.h" + +#include "irc_types.h" + +int JH_irc_initialize +( + struct JH_irc irc [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + struct JH_meta_net meta_net [const restrict static 1] +); + +int JH_irc_connect (struct JH_irc irc [const restrict static 1]); + +int JH_irc_send_message +( + struct JH_irc irc [const restrict static 1], + const char msg [const restrict static 1] +); + +/* TODO */ +void JH_irc_finalize (struct JH_irc irc [const restrict static 1]); + +int JH_irc_pre_select +( + struct JH_irc irc [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1], + int max_fd [const restrict static 1] +); + +int JH_irc_post_select +( + struct JH_irc irc [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1] +); + +#endif diff --git a/src/irc/irc_event_handlers.h b/src/irc/irc_event_handlers.h new file mode 100644 index 0000000..447fbb6 --- /dev/null +++ b/src/irc/irc_event_handlers.h @@ -0,0 +1,69 @@ +#ifndef _JH_IRC_IRC_EVENT_HANDLERS_H_ +#define _JH_IRC_IRC_EVENT_HANDLERS_H_ + +#include <libircclient/libircclient.h> + +void JH_irc_do_nothing +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +); + +void JH_irc_handle_connected_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +); + +void JH_irc_handle_channel_message_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +); + +void JH_irc_handle_ctcp_action_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +); + +void JH_irc_handle_numeric_event +( + irc_session_t * session, + unsigned int event, + const char * origin, + const char ** params, + unsigned int count +); + +void JH_irc_handle_dcc_chat_req_event +( + irc_session_t * session, + const char * nick, + const char * addr, + irc_dcc_t dccid +); + +void JH_irc_handle_dcc_send_req_event +( + irc_session_t * session, + const char * nick, + const char * addr, + const char * filename, + unsigned long size, + irc_dcc_t dccid +); + +#endif diff --git a/src/irc/irc_handle_connected.c b/src/irc/irc_handle_connected.c new file mode 100644 index 0000000..3d24af9 --- /dev/null +++ b/src/irc/irc_handle_connected.c @@ -0,0 +1,27 @@ +#include <libircclient/libircclient.h> + +#include "../parameters/parameters.h" + +#include "irc.h" +#include "irc_event_handlers.h" + +void JH_irc_handle_connected_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +) +{ + struct JH_irc * irc; + + irc = (struct JH_irc *) irc_get_ctx(session); + + irc_cmd_join + ( + session, + JH_parameters_get_irc_channel(irc->params), + 0 + ); +} diff --git a/src/irc/irc_handle_dcc_events.c b/src/irc/irc_handle_dcc_events.c new file mode 100644 index 0000000..2fe6904 --- /dev/null +++ b/src/irc/irc_handle_dcc_events.c @@ -0,0 +1,27 @@ +#include <libircclient/libircclient.h> + +#include "irc_event_handlers.h" + +void JH_irc_handle_dcc_chat_req_event +( + irc_session_t * session, + const char * nick, + const char * addr, + irc_dcc_t dccid +) +{ + irc_dcc_decline(session, dccid); +} + +void JH_irc_handle_dcc_send_req_event +( + irc_session_t * session, + const char * nick, + const char * addr, + const char * filename, + unsigned long size, + irc_dcc_t dccid +) +{ + irc_dcc_decline(session, dccid); +} diff --git a/src/irc/irc_receive.c b/src/irc/irc_receive.c new file mode 100644 index 0000000..0edb324 --- /dev/null +++ b/src/irc/irc_receive.c @@ -0,0 +1,50 @@ +#include <string.h> + +#include <libircclient/libircclient.h> + +#include "../meta_net/meta_net.h" + +#include "irc.h" +#include "irc_event_handlers.h" + +void JH_irc_handle_channel_message_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +) +{ + struct JH_irc * irc; + + irc = (struct JH_irc *) irc_get_ctx(session); + + JH_meta_net_handle_user_message + ( + irc->jh_net, + params[1], + strlen(params[1]) + ); +} + +void JH_irc_handle_ctcp_action_event +( + irc_session_t * session, + const char * event, + const char * origin, + const char ** params, + unsigned int count +) +{ + struct JH_irc * irc; + + irc = (struct JH_irc *) irc_get_ctx(session); + + JH_meta_net_handle_user_action + ( + irc->jh_net, + params[0], + strlen(params[0]) + ); +} diff --git a/src/irc/irc_select.c b/src/irc/irc_select.c new file mode 100644 index 0000000..fe15662 --- /dev/null +++ b/src/irc/irc_select.c @@ -0,0 +1,38 @@ +#include <libircclient/libircclient.h> + +#include "irc.h" + +int JH_irc_pre_select +( + struct JH_irc irc [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1], + int max_fd [const restrict static 1] +) +{ + while (!irc_is_connected(irc->session)) + { + /* TODO: reconnect or fail. */ + JH_irc_connect(irc); + /* TODO: wait a bit... */ + } + + irc_add_select_descriptors(irc->session, in, out, max_fd); + + return 0; +} + +int JH_irc_post_select +( + struct JH_irc irc [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1] +) +{ + if (!irc_process_select_descriptors(irc->session, in, out)) + { + /* TODO: reconnect or fail. */ + } + + return 0; +} diff --git a/src/irc/irc_send.c b/src/irc/irc_send.c new file mode 100644 index 0000000..7e474be --- /dev/null +++ b/src/irc/irc_send.c @@ -0,0 +1,38 @@ +#include <libircclient/libircclient.h> + +#include "../pervasive.h" + +#include "../parameters/parameters.h" + +#include "irc.h" + +int JH_irc_send_message +( + struct JH_irc irc [const restrict static 1], + const char msg [const restrict static 1] +) +{ + if (JH_IS_PREFIX("/me ", msg)) + { + /* TODO: what to do in case of failure? */ + (void) irc_cmd_me + ( + irc->session, + JH_parameters_get_irc_channel(irc->params), + (msg + 4) + ); + } + else + { + /* TODO: what to do in case of failure? */ + (void) irc_cmd_msg + ( + irc->session, + JH_parameters_get_irc_channel(irc->params), + msg + ); + } + + return 0; +} + diff --git a/src/irc/irc_types.h b/src/irc/irc_types.h new file mode 100644 index 0000000..f846076 --- /dev/null +++ b/src/irc/irc_types.h @@ -0,0 +1,14 @@ +#ifndef _JH_IRC_IRC_TYPES_H_ +#define _JH_IRC_IRC_TYPES_H_ + +#include <libircclient/libircclient.h> + +struct JH_irc +{ + irc_callbacks_t callbacks; + irc_session_t * session; + const struct JH_parameters * params; + struct JH_meta_net * jh_net; +}; + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..509255c --- /dev/null +++ b/src/main.c @@ -0,0 +1,206 @@ +/* According to POSIX.1-2001, POSIX.1-2008 */ +#include <sys/select.h> + +#include <stdio.h> + +#include "error/error.h" + +#include "parameters/parameters.h" + +#include "irc/irc.h" + +#include "meta_net/meta_net.h" + +#include "pervasive.h" + +static void print_help (const char runnable [const restrict static 1]) +{ + printf + ( + "JabberHive - IRC Gateway\n" + "Software Version %d\n" + "Protocol Version %d\n" + "\nUsages:\n" + " GATEWAY:\t%s SOCKET_NAME IRC_SERVER IRC_NICK IRC_CHANNEL IRC_PORT" + " [OPTIONS]\n" + " SHOW HELP:\tAnything else.\n" + "\nParameters:\n" + " SOCKET_NAME:\tValid UNIX socket.\n" + " IRC_SERVER:\tAddress of the IRC server. Prefixing with '#' will" + " enable SSL.\n" + " IRC_NICK:\tIRC nick to be used.\n" + " IRC_CHANNEL:\tIRC channel to connect to.\n" + " IRC_PORT:\tPort to use for the IRC connection.\n" + "\nOptions:\n" + " -6, --ipv6:\tEnables IPv6.\n" + " -u USERNAME, --username USERNAME:\tSets the IRC username.\n" + " -r REALNAME, --realname REALNAME:\tSets the IRC realname.\n" + " -p PASSWORD, --password PASSWORD:\tSets the IRC password.\n", + JH_PROGRAM_VERSION, + JH_PROTOCOL_VERSION, + runnable + ); +} + +static int initialize +( + struct JH_irc irc [const restrict static 1], + struct JH_meta_net socket [const restrict static 1], + struct JH_parameters params [const restrict static 1], + const int argc, + const char * argv [const static argc] +) +{ + if (JH_parameters_initialize(params, argc, argv) < 0) + { + print_help(argv[0]); + + return -1; + } + + JH_meta_net_initialize(socket); + + if (JH_irc_initialize(irc, params, socket) < 0) + { + JH_meta_net_finalize(socket); + + return -1; + } + + return 0; +} + +static int connect_all +( + struct JH_irc irc [const restrict static 1], + struct JH_meta_net socket [const restrict static 1], + struct JH_parameters params [const restrict static 1] +) +{ + if (JH_meta_net_connect(socket, params) < 0) + { + return -1; + } + + if (JH_irc_connect(irc) < 0) + { + return -1; + } + + return 0; +} + +static int event_handling_loop +( + struct JH_irc irc [const restrict static 1], + struct JH_meta_net socket [const restrict static 1], + struct JH_parameters params [const restrict static 1] +) +{ + struct timeval tv; + fd_set in_set, out_set; + int fd_max, error; + + for (;;) + { + + tv.tv_usec = 250000; + tv.tv_sec = 0; + + FD_ZERO(&in_set); + FD_ZERO(&out_set); + + fd_max = 0; + + if (JH_irc_pre_select(irc, &in_set, &out_set, &fd_max) < 0) + { + JH_meta_net_finalize(socket); + + return -1; + } + + if + ( + JH_meta_net_pre_select + ( + socket, + params, + &in_set, + &out_set, + &fd_max + ) < 0 + ) + { + JH_irc_finalize(irc); + + return -1; + } + + error = + select + ( + (fd_max + 1), + &in_set, + &out_set, + (fd_set *) NULL, + &tv + ); + + if (error < 0) + { + JH_ERROR + ( + stderr, + "Unable to select the sockets: %s.", + strerror(error) + ); + } + + if (JH_irc_post_select(irc, &in_set, &out_set) < 0) + { + JH_meta_net_finalize(socket); + + return -1; + } + + if + ( + JH_meta_net_post_select + ( + socket, + params, + &in_set, + &out_set + ) < 0 + ) + { + JH_irc_finalize(irc); + + return -1; + } + } + + return 0; +} + +int main (const int argc, const char * argv [const static argc]) +{ + struct JH_parameters params; + struct JH_meta_net socket; + struct JH_irc irc; + + if (initialize(&irc, &socket, ¶ms, argc, argv) < 0) + { + return -1; + } + + if (connect_all(&irc, &socket, ¶ms) < 0) + { + JH_irc_finalize(&irc); + JH_meta_net_finalize(&socket); + + return -1; + } + + return event_handling_loop(&irc, &socket, ¶ms); +} diff --git a/src/meta_net/CMakeLists.txt b/src/meta_net/CMakeLists.txt new file mode 100644 index 0000000..ca047c3 --- /dev/null +++ b/src/meta_net/CMakeLists.txt @@ -0,0 +1,9 @@ +set( + SRC_FILES ${SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/meta_net.c + ${CMAKE_CURRENT_SOURCE_DIR}/meta_net_handle_reply.c + ${CMAKE_CURRENT_SOURCE_DIR}/meta_net_select.c + ${CMAKE_CURRENT_SOURCE_DIR}/meta_net_try_request.c +) + +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) diff --git a/src/meta_net/meta_net.c b/src/meta_net/meta_net.c new file mode 100644 index 0000000..fdd0fec --- /dev/null +++ b/src/meta_net/meta_net.c @@ -0,0 +1,158 @@ +#include <sys/socket.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include "../error/error.h" + +#include "../parameters/parameters.h" + +#include "meta_net.h" + +static int open_socket +( + struct JH_meta_net s [const restrict static 1], + const char socket_name [const restrict static 1] +) +{ + struct sockaddr_un addr; + int flags; + const int old_errno = errno; + + errno = 0; + + s->fd = socket(AF_UNIX, SOCK_STREAM, 0); + + if (s->fd == -1) + { + JH_FATAL + ( + stderr, + "Unable to create socket: %s.", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + errno = old_errno; + + memset((void *) &addr, 0, sizeof(addr)); + + addr.sun_family = AF_UNIX; + + strncpy + ( + (void *) addr.sun_path, + (const void *) socket_name, + (sizeof(addr.sun_path) - 1) + ); + + errno = 0; + + if (connect(s->fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) + { + JH_FATAL + ( + stderr, + "Unable to connect to address: %s.", + strerror(errno) + ); + + errno = old_errno; + + close(s->fd); + + return -1; + } + + errno = 0; + + flags = fcntl(s->fd, F_GETFD, 0); + + if (flags < 0) + { + JH_FATAL + ( + stderr, + "Unable to get fd flag information for JabberHive socket: %s.", + strerror(errno) + ); + + errno = old_errno; + + close(s->fd); + + return -1; + } + + errno = 0; + + if (fcntl(s->fd, F_SETFL, (flags | O_NONBLOCK)) == -1) + { + JH_FATAL + ( + stderr, + "Unable to get fd flag information for JabberHive socket: %s.", + strerror(errno) + ); + + errno = old_errno; + + close(s->fd); + + return -1; + } + + errno = old_errno; + + return 0; +} + +int JH_meta_net_connect +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1] +) +{ + return + open_socket + ( + socket, + JH_parameters_get_socket_name(params) + ); +} + +void JH_meta_net_initialize +( + struct JH_meta_net socket [const restrict static 1] +) +{ + socket->in.data = (char *) NULL; + socket->in.capacity = 0; + socket->in.length = 0; + socket->in.index = 0; + + socket->out.data = (char *) NULL; + socket->out.capacity = 0; + socket->out.length = 0; + socket->out.index = 0; + + socket->fd = -1; + socket->has_request_in_progress = 0; +} + +void JH_meta_net_finalize +( + struct JH_meta_net socket [const restrict static 1] +) +{ + /* TODO */ +} diff --git a/src/meta_net/meta_net.h b/src/meta_net/meta_net.h new file mode 100644 index 0000000..ce5c61e --- /dev/null +++ b/src/meta_net/meta_net.h @@ -0,0 +1,82 @@ +#ifndef _JH_META_NET_META_NET_H_ +#define _JH_META_NET_META_NET_H_ + +#include "../parameters/parameters_types.h" + +#include "../irc/irc_types.h" + +#include "meta_net_types.h" + +void JH_meta_net_initialize +( + struct JH_meta_net socket [const restrict static 1] +); + +int JH_meta_net_connect +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1] +); + +void JH_meta_net_finalize +( + struct JH_meta_net socket [const restrict static 1] +); + +int JH_meta_net_try_request +( + struct JH_meta_net socket [const restrict static 1], + const char string [const restrict static 1], + const size_t string_size +); + +int JH_meta_net_handle_user_message +( + struct JH_meta_net socket [const restrict static 1], + const char string [const restrict static 1], + const size_t string_size +); + +int JH_meta_net_handle_user_action +( + struct JH_meta_net socket [const restrict static 1], + const char string [const restrict static 1], + const size_t string_size +); + +int JH_meta_net_read +( + struct JH_meta_net socket [const restrict static 1] +); + +/* TODO */ +int JH_meta_net_write +( + struct JH_meta_net socket [const restrict static 1] +); + +void JH_meta_net_handle_reply +( + struct JH_meta_net socket [const restrict static 1], + struct JH_irc irc [const restrict static 1], + const struct JH_parameters params [const restrict static 1] +); + +int JH_meta_net_pre_select +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1], + int max_fd [const restrict static 1] +); + +int JH_meta_net_post_select +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1] +); + +#endif diff --git a/src/meta_net/meta_net_handle_reply.c b/src/meta_net/meta_net_handle_reply.c new file mode 100644 index 0000000..b823078 --- /dev/null +++ b/src/meta_net/meta_net_handle_reply.c @@ -0,0 +1,74 @@ +#include "../error/error.h" + +#include "../irc/irc.h" +#include "../parameters/parameters.h" + +#include "meta_net.h" + +void JH_meta_net_handle_reply +( + struct JH_meta_net socket [const restrict static 1], + struct JH_irc irc [const restrict static 1], + const struct JH_parameters params [const restrict static 1] +) +{ + if (socket->in.index == 0) + { + /* No reply to handle. */ + return; + } + + socket->in.data[socket->in.index] = '\0'; + + if (JH_IS_PREFIX("!CPV ", socket->in.data)) + { + } + else if (JH_IS_PREFIX("!CPS ", socket->in.data)) + { + } + else if (JH_IS_PREFIX("!GR ", socket->in.data)) + { + /* TODO: /me vs message should be handled prior to this. */ + JH_irc_send_message(irc, (socket->in.data + 4)); + + JH_DEBUG + ( + stderr, + /* TODO: Parameter dependent behavior. */ + JH_DEBUG_DISPLAY_IRC_MSG_EXCHANGES, + "<%s> %s", + JH_parameters_get_irc_nick(params), + (socket->in.data + 4) + ); + } + else if (JH_IS_PREFIX("!AI ", socket->in.data)) + { + /* TODO: Parameter dependent behavior. */ + JH_DEBUG + ( + stderr, + 1, + "Received: %s.", + socket->in.data + ); + } + else if (JH_IS_PREFIX("!P ", socket->in.data)) + { + socket->has_request_in_progress = 0; + } + else if (JH_IS_PREFIX("!N ", socket->in.data)) + { + JH_S_WARNING(stderr, "Received Negative reply."); + + socket->has_request_in_progress = 0; + } + else + { + JH_WARNING + ( + stderr, + "Unsupported reply received: %s.", + socket->in.data + ); + } +} diff --git a/src/meta_net/meta_net_select.c b/src/meta_net/meta_net_select.c new file mode 100644 index 0000000..069a671 --- /dev/null +++ b/src/meta_net/meta_net_select.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <sys/select.h> + +#include "meta_net.h" + +int JH_meta_net_pre_select +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1], + int max_fd [const restrict static 1] +) +{ + FD_SET(socket->fd, in); + FD_SET(socket->fd, out); + + if ((*max_fd) < socket->fd) + { + *max_fd = socket->fd; + } + + return 0; +} + +int JH_meta_net_post_select +( + struct JH_meta_net socket [const restrict static 1], + const struct JH_parameters params [const restrict static 1], + fd_set in [const restrict static 1], + fd_set out [const restrict static 1] +) +{ + if (FD_ISSET(socket->fd, in)) + { + if (JH_meta_net_read(socket) < 0) + { + /* TODO: Try to reconnect. */ + return -1; + } + } + + if (FD_ISSET(socket->fd, out)) + { + if (JH_meta_net_write(socket) < 0) + { + /* TODO: Try to reconnect. */ + return -1; + } + } + + return 0; +} diff --git a/src/meta_net/meta_net_try_request.c b/src/meta_net/meta_net_try_request.c new file mode 100644 index 0000000..121ef8d --- /dev/null +++ b/src/meta_net/meta_net_try_request.c @@ -0,0 +1,232 @@ +#include <sys/socket.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> + +#include "../error/error.h" + +#include "../parameters/parameters.h" + +#include "meta_net.h" + +/******************************************************************************/ +/** MEMORY ALLOCATION *********************************************************/ +/******************************************************************************/ +static int ensure_string_capacity +( + char * string [const restrict static 1], + size_t string_capacity [const restrict static 1], + const size_t string_required_capacity +) +{ + char * new_string; + + if (string_required_capacity <= *string_capacity) + { + return 0; + } + + new_string = + (char *) realloc + ( + (void *) *string, + ((size_t) string_required_capacity) * sizeof(char) + ); + + if (new_string == (char *) NULL) + { + JH_S_ERROR + ( + stderr, + "Unable to reallocate memory to match string's required size." + ); + + return -1; + } + + *string_capacity = string_required_capacity; + *string = new_string; + + return 1; +} + +/******************************************************************************/ +/** EXPORTED ******************************************************************/ +/******************************************************************************/ +int JH_meta_net_handle_user_message +( + struct JH_meta_net socket [const restrict static 1], + const char string [const restrict static 1], + const size_t string_size +) +{ + if (socket->out.length != 0) + { + return 1; + } + + if + ( + ensure_string_capacity + ( + &(socket->out.data), + &(socket->out.capacity), + string_size + ) + < 0 + ) + { + return -1; + } + + memcpy + ( + (void *) socket->out.data, + (const void *) string, + (string_size * sizeof(char)) + ); + + socket->out.length = string_size; + socket->out.index = 0; + + socket->has_request_in_progress = 1; + + return 0; +} + +int JH_meta_net_handle_user_action +( + struct JH_meta_net socket [const restrict static 1], + const char string [const restrict static 1], + const size_t string_size +) +{ + if (socket->out.length != 0) + { + return 1; + } + + if + ( + ensure_string_capacity + ( + &(socket->out.data), + &(socket->out.capacity), + (string_size + (JH_META_NET_ACTION_STRING_LENGTH + 1)) + ) + < 0 + ) + { + return -1; + } + + memcpy + ( + (void *) socket->out.data, + (const void *) JH_META_NET_ACTION_STRING, + (JH_META_NET_ACTION_STRING_LENGTH * sizeof(char)) + ); + + socket->out.data[JH_META_NET_ACTION_STRING_LENGTH] = ' '; + + memcpy + ( + (void *) (socket->out.data + (JH_META_NET_ACTION_STRING_LENGTH + 1)), + (const void *) string, + (string_size * sizeof(char)) + ); + + socket->out.length = string_size; + socket->out.index = 0; + + socket->has_request_in_progress = 1; + + return 0; +} + +int JH_meta_net_read +( + struct JH_meta_net socket [const restrict static 1] +) +{ + const int old_errno = errno; + ssize_t in_bytes_count; + + if ((SIZE_MAX - JH_META_NET_READ_SIZE) < socket->in.length) + { + JH_S_ERROR + ( + stderr, + "Unable to read from JabberHive socket: max buffer size reached." + ); + + return -1; + } + + if + ( + ensure_string_capacity + ( + &(socket->in.data), + &(socket->in.capacity), + (socket->in.length + JH_META_NET_READ_SIZE) + ) + < 0 + ) + { + return -1; + } + + errno = 0; + + in_bytes_count = + read + ( + socket->fd, + (&(socket->in.data) + socket->in.length), + (size_t) JH_META_NET_READ_SIZE + ); + + if (in_bytes_count < 0) + { + if (errno == EAGAIN) + { + errno = old_errno; + + return 0; + } + + JH_ERROR + ( + stderr, + "Unable to read from JabberHive socket: %s.", + strerror(errno) + ); + + errno = old_errno; + + return -1; + } + + errno = old_errno; + + /* Safe. */ + socket->in.length += (size_t) in_bytes_count; + + while (socket->in.index < socket->in.length) + { + if (socket->in.data[socket->in.index] == '\n') + { + break; + } + + socket->in.index += 1; + } + + return 0; +} diff --git a/src/meta_net/meta_net_types.h b/src/meta_net/meta_net_types.h new file mode 100644 index 0000000..251f85b --- /dev/null +++ b/src/meta_net/meta_net_types.h @@ -0,0 +1,26 @@ +#ifndef _JH_META_NET_META_NET_TYPES_H_ +#define _JH_META_NET_META_NET_TYPES_H_ + +#include <stdio.h> + +#define JH_META_NET_READ_SIZE 64 +#define JH_META_NET_ACTION_STRING "/me" +#define JH_META_NET_ACTION_STRING_LENGTH 3 + +struct JH_meta_net_buffer +{ + char * data; + size_t capacity; + size_t length; + size_t index; +}; + +struct JH_meta_net +{ + int fd; + int has_request_in_progress; + struct JH_meta_net_buffer in; + struct JH_meta_net_buffer out; +}; + +#endif diff --git a/src/parameters/CMakeLists.txt b/src/parameters/CMakeLists.txt new file mode 100644 index 0000000..2aa7ece --- /dev/null +++ b/src/parameters/CMakeLists.txt @@ -0,0 +1,7 @@ +set( + SRC_FILES ${SRC_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/parameters.c + ${CMAKE_CURRENT_SOURCE_DIR}/parameters_getters.c +) +set(SRC_FILES ${SRC_FILES} PARENT_SCOPE) + diff --git a/src/parameters/parameters.c b/src/parameters/parameters.c new file mode 100644 index 0000000..63556f0 --- /dev/null +++ b/src/parameters/parameters.c @@ -0,0 +1,250 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> + +#include "../error/error.h" + +#include "parameters.h" + +static int parse_port +( + struct JH_parameters param [const restrict static 1], + const char argv [const restrict] +) +{ + long long int input; + const int old_errno = errno; + + errno = 0; + + input = strtoll(argv, (char **) NULL, 10); + + if + ( + (errno != 0) + || (input > (long long int) USHRT_MAX) + || (input < 1) + ) + { + JH_FATAL + ( + stderr, + "Invalid or value for parameter 'port', accepted " + "range is " + "[1, %hu] (integer).", + USHRT_MAX + ); + + errno = old_errno; + + return -1; + } + + param->port = (unsigned short) input; + + errno = old_errno; + + return 0; +} + +static void set_default_to_all_fields +( + struct JH_parameters param [const restrict static 1] +) +{ + param->socket_name = (const char *) NULL; + param->server = (const char *) NULL; + param->password = (const char *) NULL; + param->nick = (const char *) NULL; + param->username = (const char *) NULL; + param->realname = (const char *) NULL; + param->channel = (const char *) NULL; + param->port = 0; + param->use_ipv6 = 0; +} + +static int is_valid +( + struct JH_parameters param [const restrict static 1] +) +{ + int valid; + + valid = 1; + + if (param->socket_name == (const char *) NULL) + { + JH_S_FATAL(stderr, "Missing parameter: Zero of One socket name."); + + valid = 0; + } + + if (param->server == (const char *) NULL) + { + JH_S_FATAL(stderr, "Missing parameter: IRC server address."); + + valid = 0; + } + + if (param->nick == (const char *) NULL) + { + JH_S_FATAL(stderr, "Missing parameter: IRC nick."); + + valid = 0; + } + + if (param->channel == (const char *) NULL) + { + JH_S_FATAL(stderr, "Missing parameter: IRC channel."); + + valid = 0; + } + + if (param->port == 0) + { + JH_S_FATAL(stderr, "Missing parameter: IRC port."); + + valid = 0; + } + + return valid; +} + +static void set_parameters +( + struct JH_parameters param [const restrict static 1], + int const argc, + const char * argv [const static argc] +) +{ + if (argc < 2) + { + return; + } + + param->socket_name = argv[1]; + + if (argc < 3) + { + return; + } + + param->server = argv[2]; + + if (argc < 4) + { + return; + } + + param->nick = argv[3]; + + if (argc < 5) + { + return; + } + + param->channel = argv[4]; + + if (argc < 6) + { + return; + } + + parse_port(param, argv[5]); +} + +static int set_options +( + struct JH_parameters param [const restrict static 1], + int const argc, + const char * argv [const static argc] +) +{ + int i; + + for (i = (JH_PARAMETERS_COUNT + 1); i < argc; ++i) + { + + if + ( + JH_STRING_EQUALS("-6", argv[i]) + || JH_STRING_EQUALS("--ipv6", argv[i]) + ) + { + param->use_ipv6 = 1; + } + else if + ( + JH_STRING_EQUALS("-u", argv[i]) + || JH_STRING_EQUALS("--username", argv[i]) + ) + { + if (i == (argc - 1)) + { + JH_FATAL(stderr, "Missing value for option \"%s\".", argv[i]); + + return -1; + } + + param->username = argv[++i]; + } + else if + ( + JH_STRING_EQUALS("-r", argv[i]) + || JH_STRING_EQUALS("--realname", argv[i]) + ) + { + if (i == (argc - 1)) + { + JH_FATAL(stderr, "Missing value for option \"%s\".", argv[i]); + + return -1; + } + + param->realname = argv[++i]; + } + else if + ( + JH_STRING_EQUALS("-p", argv[i]) + || JH_STRING_EQUALS("--password", argv[i]) + ) + { + if (i == (argc - 1)) + { + JH_FATAL(stderr, "Missing value for option \"%s\".", argv[i]); + + return -1; + } + + param->password = argv[++i]; + } + else + { + JH_FATAL(stderr, "Unrecognized option \"%s\".", argv[i]); + + return -1; + } + } + + return 0; +} + +int JH_parameters_initialize +( + struct JH_parameters param [const restrict static 1], + int const argc, + const char * argv [const static argc] +) +{ + set_default_to_all_fields(param); + + set_parameters(param, argc, argv); + + if (!is_valid(param)) + { + return -1; + } + + return set_options(param, argc, argv); +} diff --git a/src/parameters/parameters.h b/src/parameters/parameters.h new file mode 100644 index 0000000..58fc957 --- /dev/null +++ b/src/parameters/parameters.h @@ -0,0 +1,60 @@ +#ifndef _JH_CLI_PARAMETERS_H_ +#define _JH_CLI_PARAMETERS_H_ + +#include "parameters_types.h" + +int JH_parameters_initialize +( + struct JH_parameters param [const restrict static 1], + int const argc, + const char * argv [const static argc] +); + +const char * JH_parameters_get_socket_name +( + const struct JH_parameters param [const restrict static 1] +); + +const char * JH_parameters_get_irc_server +( + const struct JH_parameters param [const restrict static 1] +); + +unsigned short JH_parameters_get_irc_port +( + const struct JH_parameters param [const restrict static 1] +); + +/* Having it as an invocation parameter makes it readable by other users on the + * machine. + */ +const char * JH_parameters_get_irc_password +( + const struct JH_parameters param [const restrict static 1] +); + +const char * JH_parameters_get_irc_nick +( + const struct JH_parameters param [const restrict static 1] +); + +const char * JH_parameters_get_irc_username +( + const struct JH_parameters param [const restrict static 1] +); + +const char * JH_parameters_get_irc_realname +( + const struct JH_parameters param [const restrict static 1] +); + +const char * JH_parameters_get_irc_channel +( + const struct JH_parameters param [const restrict static 1] +); + +int JH_parameters_get_irc_is_ipv6 +( + const struct JH_parameters param [const restrict static 1] +); +#endif diff --git a/src/parameters/parameters_getters.c b/src/parameters/parameters_getters.c new file mode 100644 index 0000000..ee2bdee --- /dev/null +++ b/src/parameters/parameters_getters.c @@ -0,0 +1,73 @@ +#include "parameters.h" + +const char * JH_parameters_get_socket_name +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->socket_name; +} + +const char * JH_parameters_get_irc_server +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->server; +} + +unsigned short JH_parameters_get_irc_port +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->port; +} + +const char * JH_parameters_get_irc_password +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->password; +} + +const char * JH_parameters_get_irc_nick +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->nick; +} + +const char * JH_parameters_get_irc_username +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->username; +} + +const char * JH_parameters_get_irc_realname +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->realname; +} + +const char * JH_parameters_get_irc_channel +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->channel; +} + +int JH_parameters_get_irc_is_ipv6 +( + const struct JH_parameters param [const restrict static 1] +) +{ + return param->use_ipv6; +} diff --git a/src/parameters/parameters_types.h b/src/parameters/parameters_types.h new file mode 100644 index 0000000..7d8dd1c --- /dev/null +++ b/src/parameters/parameters_types.h @@ -0,0 +1,21 @@ +#ifndef _JH_CLI_PARAMETERS_TYPES_H_ +#define _JH_CLI_PARAMETERS_TYPES_H_ + +#define JH_PARAMETERS_COUNT 5 + +struct JH_parameters +{ + const char * restrict socket_name; + + const char * server; + const char * password; + const char * nick; + const char * username; + const char * realname; + const char * channel; + unsigned short port; + + int use_ipv6; +}; + +#endif diff --git a/src/pervasive.h b/src/pervasive.h new file mode 100644 index 0000000..e69d077 --- /dev/null +++ b/src/pervasive.h @@ -0,0 +1,31 @@ +#ifndef _JH_PERVASIVE_H_ +#define _JH_PERVASIVE_H_ + +#include <string.h> + +#define JH_PROGRAM_VERSION 1 +#define JH_PROTOCOL_VERSION 1 + +#ifdef __FRAMA_C__ + #define JH_RUNNING_FRAMA_C 1 +#endif + +#define JH_DEBUG_ALL 1 + +#ifndef JH_DEBUG_ALL + #define JH_DEBUG_ALL 0 +#endif +#ifndef JH_DEBUG_DISPLAY_IRC_MSG_EXCHANGES + #define JH_DEBUG_DISPLAY_IRC_MSG_EXCHANGES JH_DEBUG_ALL +#endif + +#define JH__TO_STRING(x) #x +#define JH_TO_STRING(x) JH__TO_STRING(x) +#define JH_ISOLATE(a) do {a} while (0) + +/* strncmp stops at '\0' and strlen does not count '\0'. */ +#define JH_IS_PREFIX(a, b) (strncmp(a, b, strlen(a)) == 0) + +#define JH_STRING_EQUALS(a, b) (strcmp(a, b) == 0) + +#endif |


