summaryrefslogtreecommitdiff
path: root/src/rexmpp.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp.h')
-rw-r--r--src/rexmpp.h510
1 files changed, 380 insertions, 130 deletions
diff --git a/src/rexmpp.h b/src/rexmpp.h
index 6157f86..0aa6252 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -9,45 +9,67 @@
#ifndef REXMPP_H
#define REXMPP_H
-#include <ares.h>
-#include <gnutls/gnutls.h>
-#include <gsasl.h>
-#include <libxml/tree.h>
-#include "rexmpp_tcp.h"
-#include "rexmpp_socks.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include "config.h"
-typedef struct rexmpp rexmpp_t;
-
-/**
- @brief An info/query callback function type.
- @param[in,out] s A ::rexmpp structure.
- @param[in] request A request that was made.
- @param[in] response A response we have received. @c NULL if we are
- giving up on this IQ.
-
- A callback must not free the request or the response, but merely
- inspect those and react.
-*/
-typedef void (*rexmpp_iq_callback_t) (rexmpp_t *s,
- xmlNodePtr request,
- xmlNodePtr response,
- int success);
+#ifdef HAVE_GPGME
+#include <gpgme.h>
+#endif
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
-typedef struct rexmpp_iq rexmpp_iq_t;
+typedef struct rexmpp rexmpp_t;
-/** @brief A pending info/query request. */
-struct rexmpp_iq
-{
- /** @brief The sent request. */
- xmlNodePtr request;
- /** @brief A callback to call on reply. */
- rexmpp_iq_callback_t cb;
- /** @brief Next pending IQ. */
- rexmpp_iq_t *next;
+/** Error codes. */
+enum rexmpp_err {
+ /** An operation is finished. */
+ REXMPP_SUCCESS,
+ /** An operation is in progress. */
+ REXMPP_E_AGAIN,
+ /** A message can't be queued for sending, because the queue is
+ full. */
+ REXMPP_E_SEND_QUEUE_FULL,
+ /** The library can't take responsibility for message delivery (and
+ doesn't try to send it), because XEP-0198 stanza queue is
+ full. */
+ REXMPP_E_STANZA_QUEUE_FULL,
+ /** An operation (reading or sending) was cancelled by a user. */
+ REXMPP_E_CANCELLED,
+ /** An attempt to send while send buffer is empty. */
+ REXMPP_E_SEND_BUFFER_EMPTY,
+ /** An attempt to start sending while send buffer is not empty. */
+ REXMPP_E_SEND_BUFFER_NOT_EMPTY,
+ /** SASL-related error. */
+ REXMPP_E_SASL,
+ /** OpenPGP-related error. */
+ REXMPP_E_PGP,
+ /** TLS-related error. */
+ REXMPP_E_TLS,
+ /** TCP-related error. */
+ REXMPP_E_TCP,
+ /** DNS-related error. */
+ REXMPP_E_DNS,
+ /** XML-related error. */
+ REXMPP_E_XML,
+ /** JID-related error. */
+ REXMPP_E_JID,
+ /** Failure to allocate memory. */
+ REXMPP_E_MALLOC,
+ /** Roster-related error. */
+ REXMPP_E_ROSTER,
+ /** A roster item is not found. */
+ REXMPP_E_ROSTER_ITEM_NOT_FOUND,
+ /** An erroneous parameter is supplied. */
+ REXMPP_E_PARAM,
+ /** A stream error. */
+ REXMPP_E_STREAM,
+ /** An unspecified error. */
+ REXMPP_E_OTHER
};
-
/** @brief DNS resolver state */
enum resolver_st {
REXMPP_RESOLVER_NONE,
@@ -96,8 +118,6 @@ enum stream_st {
REXMPP_STREAM_SM_ACKS,
/** Resuming a stream. */
REXMPP_STREAM_SM_RESUME,
- /** Restarting a stream. */
- REXMPP_STREAM_RESTART,
/** The streams are ready for use: messaging and other higher-level
things not covered here. */
REXMPP_STREAM_READY,
@@ -111,7 +131,9 @@ enum stream_st {
/** The server-to-client stream is closed. */
REXMPP_STREAM_CLOSED,
/** A stream error was detected in the server-to-client stream. */
- REXMPP_STREAM_ERROR
+ REXMPP_STREAM_ERROR,
+ /** A stream error that should be fixed by a reconnect. */
+ REXMPP_STREAM_ERROR_RECONNECT
};
/** @brief TLS state */
@@ -156,53 +178,81 @@ enum carbons_st {
REXMPP_CARBONS_ACTIVE
};
-/** Error codes. */
-enum rexmpp_err {
- /** An operation is finished. */
- REXMPP_SUCCESS,
- /** An operation is in progress. */
- REXMPP_E_AGAIN,
- /** A message can't be queued for sending, because the queue is
- full. */
- REXMPP_E_SEND_QUEUE_FULL,
- /** The library can't take responsibility for message delivery (and
- doesn't try to send it), because XEP-0198 stanza queue is
- full. */
- REXMPP_E_STANZA_QUEUE_FULL,
- /** An operation (reading or sending) was cancelled by a user. */
- REXMPP_E_CANCELLED,
- /** An attempt to send while send buffer is empty. */
- REXMPP_E_SEND_BUFFER_EMPTY,
- /** An attempt to start sending while send buffer is not empty. */
- REXMPP_E_SEND_BUFFER_NOT_EMPTY,
- /** SASL-related error. */
- REXMPP_E_SASL,
- /** TLS-related error. */
- REXMPP_E_TLS,
- /** TCP-related error. */
- REXMPP_E_TCP,
- /** DNS-related error. */
- REXMPP_E_DNS,
- /** XML-related error. */
- REXMPP_E_XML,
- /** JID-related error. */
- REXMPP_E_JID,
- /** Failure to allocate memory. */
- REXMPP_E_MALLOC,
- /** Roster-related error. */
- REXMPP_E_ROSTER,
- /** A roster item is not found. */
- REXMPP_E_ROSTER_ITEM_NOT_FOUND,
- /** An erroneous parameter is supplied. */
- REXMPP_E_PARAM
+/** @brief TLS policy */
+enum tls_pol {
+ REXMPP_TLS_REQUIRE,
+ REXMPP_TLS_PREFER,
+ REXMPP_TLS_AVOID
};
+
typedef enum rexmpp_err rexmpp_err_t;
+#include "rexmpp_xml.h"
+#include "rexmpp_xml_parser.h"
+#include "rexmpp_tcp.h"
+#include "rexmpp_socks.h"
+#include "rexmpp_dns.h"
+#include "rexmpp_tls.h"
+#include "rexmpp_jid.h"
+#include "rexmpp_jingle.h"
+#include "rexmpp_sasl.h"
+
+/**
+ @brief An info/query callback function type.
+ @param[in,out] s A ::rexmpp structure.
+ @param[in] request A request that was made.
+ @param[in] response A response we have received. @c NULL if we are
+ giving up on this IQ.
+
+ A callback must not free the request or the response, but merely
+ inspect those and react.
+*/
+typedef void (*rexmpp_iq_callback_t) (rexmpp_t *s,
+ void *cb_data,
+ rexmpp_xml_t *request,
+ rexmpp_xml_t *response,
+ int success);
+
+typedef struct rexmpp_iq rexmpp_iq_t;
+
+/** @brief A pending info/query request. */
+struct rexmpp_iq
+{
+ /** @brief The sent request. */
+ rexmpp_xml_t *request;
+ /** @brief A callback to call on reply. */
+ rexmpp_iq_callback_t cb;
+ /** @brief User-supplied data, to pass to a callback function. */
+ void *cb_data;
+ /** @brief Next pending IQ. */
+ rexmpp_iq_t *next;
+};
+
+typedef struct rexmpp_muc_ping rexmpp_muc_ping_t;
+
+/** @brief MUC self-ping data. */
+struct rexmpp_muc_ping
+{
+ /** @brief Own occupant JID to ping. */
+ char *jid;
+ /** @brief Optional password to rejoin with. */
+ char *password;
+ /** @brief Ping delay, in seconds. */
+ unsigned int delay;
+ /** @brief Whether a ping is requested (pending) already. */
+ int requested;
+ /** @brief When the MUC was active. */
+ struct timespec last_activity;
+ rexmpp_muc_ping_t *next;
+};
+
typedef void (*log_function_t) (rexmpp_t *s, int priority, const char *format, va_list args);
-typedef int (*sasl_property_cb_t) (rexmpp_t *s, Gsasl_property prop);
-typedef int (*xml_in_cb_t) (rexmpp_t *s, xmlNodePtr node);
-typedef int (*xml_out_cb_t) (rexmpp_t *s, xmlNodePtr node);
-typedef void (*roster_modify_cb_t) (rexmpp_t *s, xmlNodePtr item);
+typedef int (*sasl_property_cb_t) (rexmpp_t *s, rexmpp_sasl_property prop);
+typedef int (*xml_in_cb_t) (rexmpp_t *s, rexmpp_xml_t *node);
+typedef int (*xml_out_cb_t) (rexmpp_t *s, rexmpp_xml_t *node);
+typedef void (*roster_modify_cb_t) (rexmpp_t *s, rexmpp_xml_t *item);
+typedef int (*console_print_cb_t) (rexmpp_t *s, const char *format, va_list args);
+typedef void (*socket_cb_t) (rexmpp_t *s, int socket);
/** @brief Complete connection state */
struct rexmpp
@@ -219,12 +269,12 @@ struct rexmpp
enum carbons_st carbons_state;
/* Basic configuration. */
- char *initial_jid;
+ struct rexmpp_jid initial_jid;
/* Manual host/port configuration. */
const char *manual_host;
uint16_t manual_port;
- int manual_direct_tls;
+ bool manual_direct_tls;
/* Miscellaneous settings */
const char *disco_node;
@@ -234,15 +284,36 @@ struct rexmpp
uint16_t socks_port;
/* Various knobs (these are used instead of loadable modules). */
- int enable_carbons;
- int enable_service_discovery;
- int manage_roster;
+ bool enable_carbons; /* XEP-0280 */
+ bool manage_roster;
const char *roster_cache_file;
+ bool track_roster_presence;
+ bool track_roster_events; /* XEP-0163 */
+ bool nick_notifications; /* XEP-0172 */
+ bool retrieve_openpgp_keys; /* XEP-0373 */
+ bool autojoin_bookmarked_mucs; /* XEP-0402 */
+ enum tls_pol tls_policy;
+ bool enable_jingle;
+ const char *client_name; /* XEP-0030, XEP-0092 */
+ const char *client_type; /* XEP-0030 */
+ const char *client_version; /* XEP-0092 */
+ const char *local_address; /* For ICE, XEP-0176 */
+ bool jingle_prefer_rtcp_mux;
+ /* A delay in seconds, to use for MUC self-ping by default */
+ unsigned int muc_ping_default_delay;
/* Resource limits. */
uint32_t stanza_queue_size;
uint32_t send_queue_size;
uint32_t iq_queue_size;
+ uint32_t iq_cache_size;
+ uint32_t max_jingle_sessions;
+
+ /* X.509 settings: for TLS and DTLS, to use for SASL EXTERNAL
+ authentication and DTLS-SRTP on Jingle calls. */
+ const char *x509_key_file;
+ const char *x509_cert_file;
+ const char *x509_trust_file;
/* Callbacks. */
log_function_t log_function;
@@ -250,41 +321,57 @@ struct rexmpp
xml_in_cb_t xml_in_cb;
xml_out_cb_t xml_out_cb;
roster_modify_cb_t roster_modify_cb;
+ console_print_cb_t console_print_cb;
+ socket_cb_t socket_cb;
/* Stream-related state. */
- char *assigned_jid;
- xmlNodePtr stream_features;
- xmlNodePtr roster_items;
+ struct rexmpp_jid assigned_jid;
+ rexmpp_xml_t *stream_features;
+ rexmpp_xml_t *roster_items;
char *roster_ver;
+ rexmpp_xml_t *roster_presence;
+ rexmpp_xml_t *roster_events;
/* Other dynamic data. */
- xmlNodePtr disco_info;
+ rexmpp_xml_t *disco_info;
+ /* Includes Jingle RTP session candidates; rexmpp prioritizes the
+ ones listed earlier on incoming calls. */
+ rexmpp_xml_t *jingle_rtp_description;
/* IQs we're waiting for responses to. */
rexmpp_iq_t *active_iq;
+ /* Cached IQ requests and responses. */
+ rexmpp_xml_t *iq_cache;
+
+ /* Jingle context. */
+ rexmpp_jingle_ctx_t *jingle;
+
/* Connection and stream management. */
- unsigned int id_counter;
unsigned int reconnect_number;
time_t reconnect_seconds;
- struct timeval next_reconnect_time;
- xmlNodePtr stanza_queue;
+ struct timespec next_reconnect_time;
+ rexmpp_xml_t *stanza_queue;
uint32_t stanzas_out_count;
uint32_t stanzas_out_acknowledged;
uint32_t stanzas_in_count;
char *stream_id;
/* Server ping configuration and state. */
- int ping_delay;
- int ping_requested;
- time_t last_network_activity;
+ unsigned int ping_delay;
+ bool ping_requested;
+ struct timespec last_network_activity;
+
+ /* MUC self-ping */
+ rexmpp_muc_ping_t *muc_ping;
/* DNS-related structures. */
- ares_channel resolver_channel;
- struct ares_srv_reply *server_srv;
- struct ares_srv_reply *server_srv_cur;
- struct ares_srv_reply *server_srv_tls;
- struct ares_srv_reply *server_srv_tls_cur;
+ rexmpp_dns_ctx_t resolver;
+ rexmpp_dns_result_t *server_srv;
+ int server_srv_cur;
+ rexmpp_dns_result_t *server_srv_tls;
+ int server_srv_tls_cur;
+ struct rexmpp_dns_srv *server_active_srv;
/* The XMPP server we are connecting to. */
const char *server_host;
@@ -292,6 +379,9 @@ struct rexmpp
/* The primary socket used for communication with the server. */
int server_socket;
+ /* Whether the address it's connected to was verified with
+ DNSSEC. */
+ bool server_socket_dns_secure;
/* A structure used to establish a TCP connection. */
rexmpp_tcp_conn_t server_connection;
@@ -302,27 +392,43 @@ struct rexmpp
NULL if there is anything in the send queue). Not appending data
to it, see send_queue for queuing. */
char *send_buffer;
- ssize_t send_buffer_len;
- ssize_t send_buffer_sent;
+ size_t send_buffer_len;
+ size_t send_buffer_sent;
/* A queue of XML elements to send. */
- xmlNodePtr send_queue;
+ rexmpp_xml_t *send_queue;
+
+ /* An input queue of parsed XML structures. */
+ rexmpp_xml_t *input_queue;
+ rexmpp_xml_t *input_queue_last;
/* XML parser context, and current element pointer for building
XML nodes with a SAX2 parser interface. */
- xmlParserCtxtPtr xml_parser;
- xmlNodePtr current_element_root;
- xmlNodePtr current_element;
+ rexmpp_xml_parser_ctx_t xml_parser;
+
+ /* The children are stored in reverse order during building. */
+ rexmpp_xml_t *current_element_root;
+ rexmpp_xml_t *current_element;
/* TLS structures. */
- void *tls_session_data;
- size_t tls_session_data_size;
- gnutls_session_t gnutls_session;
- gnutls_certificate_credentials_t gnutls_cred;
+ rexmpp_tls_t *tls;
/* SASL structures. */
- Gsasl *sasl_ctx;
- Gsasl_session *sasl_session;
+ rexmpp_sasl_ctx_t *sasl;
+
+ /* OpenPGP structures */
+#ifdef HAVE_GPGME
+ gpgme_ctx_t pgp_ctx;
+#else
+ void *pgp_ctx;
+#endif
+
+ /* curl structures */
+#ifdef HAVE_CURL
+ CURLM *curl_multi;
+#else
+ void *curl_multi;
+#endif
};
/**
@@ -331,7 +437,9 @@ struct rexmpp
@param[in] jid Initial bare JID.
@returns ::REXMPP_SUCCESS or some ::rexmpp_err error.
*/
-rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid);
+rexmpp_err_t rexmpp_init (rexmpp_t *s,
+ const char *jid,
+ log_function_t log_function);
/**
@brief ::rexmpp structure deinitialisation. This will free all the
@@ -342,8 +450,8 @@ void rexmpp_done (rexmpp_t *s);
/**
@brief Runs a single iteration.
- @param[in,out] s An initialised :rexmpp structure.
- @param[in] File descriptors available for reading from.
+ @param[in,out] s An initialised ::rexmpp structure.
+ @param[in] read_fds File descriptors available for reading from.
@param[in] write_fds File descriptors available for writing to.
\callergraph
@@ -362,7 +470,7 @@ rexmpp_err_t rexmpp_stop (rexmpp_t *s);
@param[in] node An XML element to send. The library assumes
ownership of the element, so it must not be freed by the caller.
*/
-rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node);
+rexmpp_err_t rexmpp_send (rexmpp_t *s, rexmpp_xml_t *node);
/**
@brief Prepare and send a new info/query request.
@@ -372,29 +480,171 @@ rexmpp_err_t rexmpp_send (rexmpp_t *s, xmlNodePtr node);
@param[in] payload IQ payload, the library assumes ownership of it.
@param[in] cb A ::rexmpp_iq_callback_t function to call on reply
(or if we will give up on it), can be NULL.
+ @param[in] cb_data A data pointer to pass to cb.
This function is specifically for IQs that should be tracked by the
library. If an application wants to track replies on its own, it
should use ::rexmpp_send.
*/
-void rexmpp_iq_new (rexmpp_t *s,
- const char *type,
- const char *to,
- xmlNodePtr payload,
- rexmpp_iq_callback_t cb);
+rexmpp_err_t rexmpp_iq_new (rexmpp_t *s,
+ const char *type,
+ const char *to,
+ rexmpp_xml_t *payload,
+ rexmpp_iq_callback_t cb,
+ void *cb_data);
-struct timeval *rexmpp_timeout (rexmpp_t *s, struct timeval *max_tv, struct timeval *tv);
-int rexmpp_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
+/**
+ @brief Same as ::rexmpp_iq_new, but caches responses, and can use
+ cached ones.
+ @param[in] fresh Do not read cache, make a new request.
+*/
+rexmpp_err_t rexmpp_cached_iq_new (rexmpp_t *s,
+ const char *type,
+ const char *to,
+ rexmpp_xml_t *payload,
+ rexmpp_iq_callback_t cb,
+ void *cb_data,
+ int fresh);
+
+/**
+ @brief Reply to an IQ.
+*/
+void rexmpp_iq_reply (rexmpp_t *s,
+ rexmpp_xml_t *req,
+ const char *type,
+ rexmpp_xml_t *payload);
+
+/**
+ @brief Determines the maximum time to wait before the next
+ ::rexmpp_run call.
+ @param[in] s ::rexmpp
+ @param[in] max_tv An existing timeout (can be NULL), to return if
+ there's no more urgent timeouts.
+ @param[in,out] tv An allocated timespec structure, to store the
+ time in.
+ @returns A pointer to either max_tv or tv.
+*/
+struct timespec *rexmpp_timeout (rexmpp_t *s,
+ struct timespec *max_tv,
+ struct timespec *tv);
+/**
+ @brief Sets file descriptors to watch.
+ @param[in] s ::rexmpp
+ @param[out] read_fds File descriptor set to monitor for read
+ events.
+ @param[out] write_fds File descriptor set to monitor for write
+ events.
+ @returns The highest-numbered file descriptor, plus 1. Suitable for
+ select(2) calls.
+*/
+int rexmpp_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
-char *rexmpp_xml_serialize (xmlNodePtr node);
-xmlNodePtr rexmpp_xml_add_id (rexmpp_t *s, xmlNodePtr node);
+/**
+ @brief The logging function.
+ @param[in] s ::rexmpp
+ @param[in] priority A syslog priority.
+ @param[in] format
+*/
void rexmpp_log (rexmpp_t *s, int priority, const char *format, ...);
-int rexmpp_xml_match (xmlNodePtr node,
- const char *namespace,
- const char *name);
-xmlNodePtr rexmpp_xml_find_child (xmlNodePtr node,
- const char *namespace,
- const char *name);
+
+/**
+ @brief Gets an appropriate display name for a JID.
+ @param[in] s ::rexmpp
+ @param[in] jid_str A JID string.
+ @returns A newly allocated null-terminated string, or NULL on
+ error.
+*/
+char *rexmpp_get_name (rexmpp_t *s, const char *jid_str);
+
+/**
+ @brief Finds a PEP event.
+ @param[in] s ::rexmpp
+ @param[in] from JID.
+ @param[in] node PEP node.
+ @param[out] prev_event The event preceding the returned one.
+ @returns A pointer to the message announcing an event, or NULL on
+ failure.
+*/
+rexmpp_xml_t *rexmpp_find_event (rexmpp_t *s,
+ const char *from,
+ const char *node,
+ rexmpp_xml_t **prev_event);
+
+void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len);
+
+/**
+ @brief A strerror function for ::rexmpp_err
+ @param[in] error Error code, as returned by rexmpp functions.
+ @returns A string explaining the error.
+*/
+const char *rexmpp_strerror (rexmpp_err_t error);
+
+
+/**
+ @brief Recurisevly searches for a given feature, using service
+ discovery, starting from a given JID. If it finds such a feature,
+ it call the provided callback, providing it both IQ request and
+ response for the entity that provided the feature; if the feature
+ isn't found, it calls the callback with NULL values.
+
+ @param[in,out] s ::rexmpp
+ @param[in] jid An XMPP address to start searching from.
+ @param[in] feature_var A feature to search for.
+ @param[in] cb A ::rexmpp_iq_callback_t function to call on reply.
+ @param[in] cb_data A data pointer to pass to cb.
+ @param[in] fresh Force a new request, instead of looking up the
+ cache.
+ @param[in] max_requests Maximum number of IQ requests to perform
+ before giving up.
+*/
+rexmpp_err_t
+rexmpp_disco_find_feature (rexmpp_t *s,
+ const char *jid,
+ const char *feature_var,
+ rexmpp_iq_callback_t cb,
+ void *cb_data,
+ int fresh,
+ int max_requests);
+
+/**
+ @brief Add a MUC JID to self-ping
+ @param[in,out] s ::rexmpp
+ @param[in] jid Own occupant JID to ping
+ @param[in] password Optional password to rejoin with
+ @param[in] delay How often to ping, in seconds
+*/
+rexmpp_err_t rexmpp_muc_ping_set (rexmpp_t *s,
+ const char *occupant_jid,
+ const char *password,
+ unsigned int delay);
+
+/**
+ @brief Remove a MUC JID to self-ping
+ @param[in,out] s ::rexmpp
+ @param[in] jid Own occupant JID
+*/
+rexmpp_err_t rexmpp_muc_ping_remove (rexmpp_t *s,
+ const char *occupant_jid);
+
+/**
+ @brief Join a MUC, optionally setting self-ping
+ @param[in,out] s ::rexmpp
+ @param[in] occupant_jid Occupant JID
+ @param[in] password Optional password
+ @param[in] ping_delay MUC self-ping delay, 0 to not set it
+*/
+rexmpp_err_t rexmpp_muc_join (rexmpp_t *s,
+ const char *occupant_jid,
+ const char *password,
+ unsigned int ping_delay);
+
+/**
+ @brief Leave a MUC, stop self-pinging it
+ @param[in,out] s ::rexmpp
+ @param[in] occupant_jid Occupant JID
+*/
+rexmpp_err_t rexmpp_muc_leave (rexmpp_t *s, const char *occupant_jid);
+
#endif