Files
libstrophe-gh/examples/vcard.c
Oleg Synelnykov 198bdd77d0 Remove -Wno-unused-parameter
Introduced UNUSED macro with cast to void in commoh.h for internal
use. Used cast to void directly in those files which do not
include common.h. Although this change doesn't fix semantic issues
with unused function parameters, it does explicitly mark all those
places, which might require attention in future.
2020-03-31 17:37:12 +03:00

284 lines
7.2 KiB
C

/* vcard.c
* strophe XMPP client library -- vCard example
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <libgen.h> /* basename */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *recipient;
const char *img_path;
} vcard_t;
typedef void (*vcard_cb_t)(vcard_t *, xmpp_stanza_t *);
#define REQ_TIMEOUT 5000
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *tmp;
char *s;
char *tok;
char *saveptr = NULL;
char *copy;
unsigned char *img;
size_t img_size;
size_t written;
FILE *fd;
tmp = xmpp_stanza_get_child_by_name(stanza, "TYPE");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
printf("PHOTO: %s, saving to file %s\n", s, vc->img_path);
xmpp_free(vc->ctx, s);
tmp = xmpp_stanza_get_child_by_name(stanza, "BINVAL");
assert(tmp != NULL);
s = xmpp_stanza_get_text(tmp);
assert(s != NULL);
/* remove \n and \r */
copy = (char *)malloc(strlen(s) + 1);
assert(copy != NULL);
copy[0] = '\0';
tok = strtok_r(s, "\n\r", &saveptr);
while (tok != NULL) {
strcat(copy, tok);
tok = strtok_r(NULL, "\n\r", &saveptr);
}
xmpp_base64_decode_bin(vc->ctx, copy, strlen(copy), &img, &img_size);
assert(img != NULL);
fd = fopen(vc->img_path, "w");
assert(fd != NULL);
written = fwrite(img, 1, img_size, fd);
if (written < img_size)
printf("Saving photo failed\n");
fclose(fd);
free(copy);
xmpp_free(vc->ctx, s);
xmpp_free(vc->ctx, img);
}
static void
vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza, const char *info)
{
char *s = xmpp_stanza_get_text(stanza);
assert(s != NULL);
printf("%s: %s\n", info, s);
xmpp_free(vc->ctx, s);
}
static void vcard_bday(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Birthday");
}
static void vcard_desc(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Description");
}
static void vcard_email(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *userid = xmpp_stanza_get_child_by_name(stanza, "USERID");
if (userid != NULL)
vcard_print_string(vc, userid, "E-mail");
}
static void vcard_fn(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Full name");
}
static void vcard_name(vcard_t *vc, xmpp_stanza_t *stanza)
{
xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(stanza, "GIVEN");
xmpp_stanza_t *family = xmpp_stanza_get_child_by_name(stanza, "FAMILY");
if (name != NULL)
vcard_print_string(vc, name, "Given name");
if (family != NULL)
vcard_print_string(vc, family, "Family name");
}
static void vcard_nick(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "Nickname");
}
static void vcard_url(vcard_t *vc, xmpp_stanza_t *stanza)
{
vcard_print_string(vc, stanza, "URL");
}
static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
{
vcard_cb_t cb = NULL;
const char *tag;
size_t i;
static struct {
const char *tag;
vcard_cb_t cb;
} vcard_tbl[] = {
{"PHOTO", vcard_photo}, {"BDAY", vcard_bday}, {"DESC", vcard_desc},
{"EMAIL", vcard_email}, {"FN", vcard_fn}, {"N", vcard_name},
{"NICKNAME", vcard_nick}, {"URL", vcard_url},
};
tag = xmpp_stanza_get_name(stanza);
if (tag == NULL)
goto exit;
for (i = 0; i < ARRAY_SIZE(vcard_tbl); ++i) {
if (strcmp(tag, vcard_tbl[i].tag) == 0) {
cb = vcard_tbl[i].cb;
break;
}
}
exit:
return cb;
}
static int timedout(xmpp_conn_t *const conn, void *const userdata)
{
(void)userdata;
fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn);
return 0;
}
static int recv_vcard(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata)
{
vcard_t *vc = userdata;
vcard_cb_t cb;
xmpp_stanza_t *child;
char *s;
size_t s_size;
int rc;
printf("Received vCard.\n\n");
child = xmpp_stanza_get_child_by_name(stanza, "error");
if (child != NULL) {
rc = xmpp_stanza_to_text(child, &s, &s_size);
assert(rc == XMPP_EOK);
printf("Error returned: %s.\n", s);
xmpp_free(vc->ctx, s);
goto exit;
}
child = xmpp_stanza_get_child_by_name(stanza, "vCard");
assert(child != NULL);
child = xmpp_stanza_get_children(child);
while (child != NULL) {
cb = vcard_cb_get(child);
if (cb != NULL)
cb(vc, child);
child = xmpp_stanza_get_next(child);
}
exit:
xmpp_disconnect(conn);
return 0;
}
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
{
printf("Requesting vCard from %s.\n", to);
xmpp_send_raw_string(conn,
"<iq from='%s' to='%s' type='get' id='%s'>"
"<vCard xmlns='vcard-temp'/></iq>",
xmpp_conn_get_bound_jid(conn), to, id);
}
static void conn_handler(xmpp_conn_t *const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t *const stream_error,
void *const userdata)
{
vcard_t *vc = userdata;
if (status == XMPP_CONN_CONNECT) {
send_vcard_req(conn, vc->recipient, "vc1");
xmpp_id_handler_add(conn, recv_vcard, "vc1", vc);
xmpp_timed_handler_add(conn, timedout, REQ_TIMEOUT, NULL);
} else {
if (error != 0)
fprintf(stderr, "Disconnected with error=%d.\n", error);
if (stream_error != NULL)
fprintf(stderr, "Stream error type=%d text=%s.\n",
stream_error->type, stream_error->text);
xmpp_stop(vc->ctx);
}
}
int main(int argc, char **argv)
{
xmpp_log_t *log;
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
const char *jid;
const char *pass;
char *prog;
vcard_t vcard;
if (argc < 4 || argc > 5) {
prog = argc > 0 ? strdup(argv[0]) : NULL;
printf("Usage: %s <login-jid> <password> <recipient-jid> "
"[image-file]\n\n",
prog == NULL ? "vcard" : basename(prog));
printf("If vCard contains a photo it will be stored to "
"image-file. If you don't provide the image-file "
"default filename will be generated.\n");
free(prog);
return 1;
}
jid = argv[1];
pass = argv[2];
vcard.recipient = argv[3];
vcard.img_path = argc > 4 ? argv[4] : "vcard.jpg";
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);
vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}