Files
libstrophe-gh-mirror/examples/vcard.c
2025-10-31 16:22:54 +01:00

288 lines
7.3 KiB
C

/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* 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 or GPLv3 licenses.
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <strophe.h>
#ifndef _WIN32
#include <libgen.h> /* basename */
#else
#define strtok_r strtok_s
#define basename(x) "vcard"
#endif
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 *conn, void *userdata)
{
(void)userdata;
fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn);
return 0;
}
static int recv_vcard(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *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 *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *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;
}