summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2020-08-23 21:28:14 +0300
committerdefanor <defanor@uberspace.net>2020-08-23 21:28:14 +0300
commitd10756f1974af1d502a3cb01d92c5fdb62576f0e (patch)
tree51cb58611470f1df2687ea0ddfff14216353c021
parent895ee3c88d5a8564ddb0794bb8d263dbbb285697 (diff)
Comment examples/basic.c and include it into the manual
-rw-r--r--examples/basic.c68
-rw-r--r--rexmpp.texi5
2 files changed, 55 insertions, 18 deletions
diff --git a/examples/basic.c b/examples/basic.c
index cbc9f4f..88a1ca4 100644
--- a/examples/basic.c
+++ b/examples/basic.c
@@ -4,9 +4,10 @@
#include <syslog.h>
#include <gnutls/gnutls.h>
#include <gsasl.h>
-
#include <rexmpp.h>
+/* A logger callback. This one just prints all the logs into
+ stderr. */
void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) {
char *priority_str = "unknown";
switch (priority) {
@@ -24,6 +25,9 @@ void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) {
fprintf(stderr, "\n");
}
+/* A SASL property callback, used to retrieve credentials. This one
+ just asks user for a password and provides AUTHID based on the
+ initial JID. */
int my_sasl_property_cb (rexmpp_t *s, Gsasl_property prop) {
if (prop == GSASL_PASSWORD) {
char buf[4096];
@@ -48,6 +52,7 @@ int my_sasl_property_cb (rexmpp_t *s, Gsasl_property prop) {
return GSASL_NO_CALLBACK;
}
+/* An XML in callback, printing what was received. */
int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) {
char *xml_buf = rexmpp_xml_serialize(node);
printf("recv: %s\n", xml_buf);
@@ -55,6 +60,7 @@ int my_xml_in_cb (rexmpp_t *s, xmlNodePtr node) {
return 0;
}
+/* An XML out callback, printing what is about to be sent. */
int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) {
char *xml_buf = rexmpp_xml_serialize(node);
printf("send: %s\n", xml_buf);
@@ -63,43 +69,57 @@ int my_xml_out_cb (rexmpp_t *s, xmlNodePtr node) {
}
main (int argc, char **argv) {
- rexmpp_t s;
- rexmpp_err_t err;
if (argc != 2) {
printf("Usage: %s <jid>", argv[0]);
return -1;
}
+ /* The minimal initialisation: provide an allocated rexmpp_t
+ structure and an initial jid. */
+ rexmpp_t s;
+ rexmpp_err_t err;
err = rexmpp_init(&s, argv[1]);
+ if (err != REXMPP_SUCCESS) {
+ puts("Failed to initialise rexmpp.");
+ return -1;
+ }
+
+ /* Set the primary callback functions: for logging, SASL, XML in and
+ out. */
s.log_function = my_logger;
s.sasl_property_cb = my_sasl_property_cb;
s.xml_in_cb = my_xml_in_cb;
s.xml_out_cb = my_xml_out_cb;
- if (err != REXMPP_SUCCESS) {
- puts("error");
- return -1;
- }
+
+ /* Could set a client certificate for SASL EXTERNAL authentication
+ here. */
/* gnutls_certificate_set_x509_key_file(s.gnutls_cred, */
/* "cert.pem", */
/* "key.pem", */
/* GNUTLS_X509_FMT_PEM); */
- fd_set read_fds, write_fds;
- int nfds;
- struct timeval tv;
- struct timeval *mtv;
- int n = 0;
+ /* Could also set various other things manually. */
/* s.socks_host = "127.0.0.1"; */
/* s.socks_port = 4321; */
/* s.manual_host = "foo.custom"; */
/* gnutls_certificate_set_x509_trust_file(s.gnutls_cred, */
/* "foo.custom.crt", */
/* GNUTLS_X509_FMT_PEM); */
-
s.roster_cache_file = "roster.xml";
+ /* Once the main structure is initialised and everything is
+ sufficiently configured, we are ready to run the main loop and
+ call rexmpp from it. */
+
+ fd_set read_fds, write_fds;
+ int nfds;
+ struct timeval tv;
+ struct timeval *mtv;
+ int n = 0;
+
do {
+ /* Check if we have some user input. */
if (n > 0 && FD_ISSET(STDIN_FILENO, &read_fds)) {
char input[4097];
ssize_t input_len;
@@ -110,6 +130,7 @@ main (int argc, char **argv) {
input[input_len - 1] = '\0';
if (strlen(input) != 0) {
if (input[0] == '<') {
+ /* Raw XML input. */
xmlDocPtr doc = xmlReadMemory(input, input_len, "", "utf-8", 0);
if (doc != NULL) {
xmlNodePtr node = xmlDocGetRootElement(doc);
@@ -124,12 +145,10 @@ main (int argc, char **argv) {
puts("Failed to read a document");
}
} else if (strcmp(input, ".") == 0) {
+ /* Exit. */
rexmpp_stop(&s);
- } else if (strcmp(input, "connerr") == 0) {
- close(s.server_socket);
- s.server_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
- gnutls_transport_set_int(s.gnutls_session, s.server_socket);
} else {
+ /* A test message for a fixed JID. */
xmlNodePtr msg = rexmpp_xml_add_id(&s, xmlNewNode(NULL, "message"));
xmlNewProp(msg, "to", "test2@foo.custom");
xmlNewProp(msg, "type", "chat");
@@ -139,6 +158,8 @@ main (int argc, char **argv) {
}
}
}
+
+ /* Run a single rexmpp iteration. */
err = rexmpp_run(&s, &read_fds, &write_fds);
if (err == REXMPP_SUCCESS) {
puts("done");
@@ -148,6 +169,7 @@ main (int argc, char **argv) {
puts("error");
break;
}
+ /* Could inspect the state here. */
/* printf("res %d / conn %d / tls %d / sasl %d / stream %d / carbons %d\n", */
/* s.resolver_state, */
/* s.tcp_state, */
@@ -155,18 +177,28 @@ main (int argc, char **argv) {
/* s.sasl_state, */
/* s.stream_state, */
/* s.carbons_state); */
+
+ /* Ask rexmpp which file descriptors it is interested in, and what
+ the timeouts should be. */
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
-
nfds = rexmpp_fds(&s, &read_fds, &write_fds);
mtv = rexmpp_timeout(&s, NULL, (struct timeval*)&tv);
+ /* Add other file descriptors we are interested in, particularly
+ stdin for user input. */
FD_SET(STDIN_FILENO, &read_fds);
+
+ /* Run select(2) with all those file descriptors and timeouts,
+ waiting for either user input or some rexmpp event to occur. */
n = select(nfds, &read_fds, &write_fds, NULL, mtv);
if (n == -1) {
printf("select error: %s\n", strerror(errno));
break;
}
} while (1);
+
+ /* Deinitialise the rexmpp structure in the end, freeing whatever it
+ allocated. */
rexmpp_done(&s);
}
diff --git a/rexmpp.texi b/rexmpp.texi
index 5a23721..e92b969 100644
--- a/rexmpp.texi
+++ b/rexmpp.texi
@@ -21,6 +21,7 @@
@menu
* Copying Conditions:: License information.
* Introduction:: The basics.
+* Examples:: usage examples.
@end menu
@node Copying Conditions
@@ -51,5 +52,9 @@ in relevant standards: the intent is to keep the library flexible and
simple, only handling (or assisting with) more complex and routine parts
of the protocol.
+@node Examples
+@chapter Examples
+@section A basic example
+@verbatiminclude examples/basic.c
@bye