Add vCard support

Only nicknames, photos, birthdays, addresses, telephone numbers, emails,
JIDs, titles, roles, notes, and URLs are supported

Due to the synopsis array not having enough space, `/vcard photo
open-self` and `/vcard photo save-self` are not documented properly in
the synopsis section of the `/vcard` command, but they are documented in
the arguments section

Fixed memory leak in vcard autocomplete (thanks to debXwoody)
This commit is contained in:
Marouane L
2022-09-06 17:29:07 +01:00
parent fc8455ba34
commit f934c5b59f
25 changed files with 3688 additions and 7 deletions

View File

@@ -41,6 +41,7 @@
#include <assert.h>
#include <libgen.h>
#include <dirent.h>
#include <ctype.h>
#include "common.h"
#include "config/preferences.h"
@@ -131,6 +132,7 @@ static char* _lastactivity_autocomplete(ProfWin* window, const char* const input
static char* _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _mood_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);
@@ -276,6 +278,15 @@ static Autocomplete mood_ac;
static Autocomplete mood_type_ac;
static Autocomplete adhoc_cmd_ac;
static Autocomplete lastactivity_ac;
static Autocomplete vcard_ac;
static Autocomplete vcard_photo_ac;
static Autocomplete vcard_element_ac;
static Autocomplete vcard_set_ac;
static Autocomplete vcard_name_ac;
static Autocomplete vcard_set_param_ac;
static Autocomplete vcard_togglable_param_ac;
static Autocomplete vcard_toggle_ac;
static Autocomplete vcard_address_type_ac;
/*!
* \brief Initialization of auto completion for commands.
@@ -1181,6 +1192,89 @@ cmd_ac_init(void)
lastactivity_ac = autocomplete_new();
autocomplete_add(lastactivity_ac, "set");
autocomplete_add(lastactivity_ac, "get");
vcard_ac = autocomplete_new();
autocomplete_add(vcard_ac, "get");
autocomplete_add(vcard_ac, "photo");
autocomplete_add(vcard_ac, "set");
autocomplete_add(vcard_ac, "add");
autocomplete_add(vcard_ac, "remove");
autocomplete_add(vcard_ac, "save");
vcard_photo_ac = autocomplete_new();
autocomplete_add(vcard_photo_ac, "open");
autocomplete_add(vcard_photo_ac, "save");
vcard_element_ac = autocomplete_new();
autocomplete_add(vcard_element_ac, "nickname");
autocomplete_add(vcard_element_ac, "birthday");
autocomplete_add(vcard_element_ac, "address");
autocomplete_add(vcard_element_ac, "tel");
autocomplete_add(vcard_element_ac, "email");
autocomplete_add(vcard_element_ac, "jid");
autocomplete_add(vcard_element_ac, "title");
autocomplete_add(vcard_element_ac, "role");
autocomplete_add(vcard_element_ac, "note");
autocomplete_add(vcard_element_ac, "url");
vcard_set_ac = autocomplete_new();
autocomplete_add(vcard_set_ac, "fullname");
autocomplete_add(vcard_set_ac, "name");
vcard_name_ac = autocomplete_new();
autocomplete_add(vcard_name_ac, "family");
autocomplete_add(vcard_name_ac, "given");
autocomplete_add(vcard_name_ac, "middle");
autocomplete_add(vcard_name_ac, "prefix");
autocomplete_add(vcard_name_ac, "suffix");
vcard_set_param_ac = autocomplete_new();
autocomplete_add(vcard_set_param_ac, "pobox");
autocomplete_add(vcard_set_param_ac, "extaddr");
autocomplete_add(vcard_set_param_ac, "street");
autocomplete_add(vcard_set_param_ac, "locality");
autocomplete_add(vcard_set_param_ac, "region");
autocomplete_add(vcard_set_param_ac, "pocode");
autocomplete_add(vcard_set_param_ac, "country");
autocomplete_add(vcard_set_param_ac, "type");
autocomplete_add(vcard_set_param_ac, "home");
autocomplete_add(vcard_set_param_ac, "work");
autocomplete_add(vcard_set_param_ac, "voice");
autocomplete_add(vcard_set_param_ac, "fax");
autocomplete_add(vcard_set_param_ac, "pager");
autocomplete_add(vcard_set_param_ac, "msg");
autocomplete_add(vcard_set_param_ac, "cell");
autocomplete_add(vcard_set_param_ac, "video");
autocomplete_add(vcard_set_param_ac, "bbs");
autocomplete_add(vcard_set_param_ac, "modem");
autocomplete_add(vcard_set_param_ac, "isdn");
autocomplete_add(vcard_set_param_ac, "pcs");
autocomplete_add(vcard_set_param_ac, "preferred");
autocomplete_add(vcard_set_param_ac, "x400");
vcard_togglable_param_ac = autocomplete_new();
autocomplete_add(vcard_togglable_param_ac, "home");
autocomplete_add(vcard_togglable_param_ac, "work");
autocomplete_add(vcard_togglable_param_ac, "voice");
autocomplete_add(vcard_togglable_param_ac, "fax");
autocomplete_add(vcard_togglable_param_ac, "pager");
autocomplete_add(vcard_togglable_param_ac, "msg");
autocomplete_add(vcard_togglable_param_ac, "cell");
autocomplete_add(vcard_togglable_param_ac, "video");
autocomplete_add(vcard_togglable_param_ac, "bbs");
autocomplete_add(vcard_togglable_param_ac, "modem");
autocomplete_add(vcard_togglable_param_ac, "isdn");
autocomplete_add(vcard_togglable_param_ac, "pcs");
autocomplete_add(vcard_togglable_param_ac, "preferred");
autocomplete_add(vcard_togglable_param_ac, "x400");
vcard_toggle_ac = autocomplete_new();
autocomplete_add(vcard_toggle_ac, "on");
autocomplete_add(vcard_toggle_ac, "off");
vcard_address_type_ac = autocomplete_new();
autocomplete_add(vcard_address_type_ac, "domestic");
autocomplete_add(vcard_address_type_ac, "international");
}
void
@@ -1502,6 +1596,17 @@ cmd_ac_reset(ProfWin* window)
autocomplete_reset(mood_ac);
autocomplete_reset(mood_type_ac);
autocomplete_reset(adhoc_cmd_ac);
autocomplete_reset(vcard_ac);
autocomplete_reset(vcard_photo_ac);
autocomplete_reset(vcard_element_ac);
autocomplete_reset(vcard_set_ac);
autocomplete_reset(vcard_name_ac);
autocomplete_reset(vcard_set_param_ac);
autocomplete_reset(vcard_togglable_param_ac);
autocomplete_reset(vcard_toggle_ac);
autocomplete_reset(vcard_address_type_ac);
autocomplete_reset(script_ac);
autocomplete_reset(lastactivity_ac);
@@ -1672,6 +1777,15 @@ cmd_ac_uninit(void)
autocomplete_free(intype_ac);
autocomplete_free(adhoc_cmd_ac);
autocomplete_free(lastactivity_ac);
autocomplete_free(vcard_ac);
autocomplete_free(vcard_photo_ac);
autocomplete_free(vcard_element_ac);
autocomplete_free(vcard_set_ac);
autocomplete_free(vcard_name_ac);
autocomplete_free(vcard_set_param_ac);
autocomplete_free(vcard_togglable_param_ac);
autocomplete_free(vcard_toggle_ac);
autocomplete_free(vcard_address_type_ac);
}
static void
@@ -1944,6 +2058,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete);
g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete);
g_hash_table_insert(ac_funcs, "/cmd", _adhoc_cmd_autocomplete);
g_hash_table_insert(ac_funcs, "/vcard", _vcard_autocomplete);
int len = strlen(input);
char parsed[len + 1];
@@ -4322,3 +4437,138 @@ _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previ
return result;
}
static char*
_vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
gboolean parse_result = FALSE;
gchar** args = parse_args(input, 0, 7, &parse_result);
if (parse_result && (g_strcmp0(args[0], "set") == 0)) {
gboolean space_at_end = g_str_has_suffix(input, " ");
int num_args = g_strv_length(args);
gboolean is_num = TRUE;
if (num_args >= 2) {
for (int i = 0; i < strlen(args[1]); i++) {
if (!isdigit((int)args[1][i])) {
is_num = FALSE;
break;
}
}
}
if ((num_args == 2 && space_at_end && is_num) || (num_args == 3 && !space_at_end && is_num)) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s", args[0], args[1]);
result = autocomplete_param_with_ac(input, beginning->str, vcard_set_param_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
g_strfreev(args);
return result;
}
} else if ((num_args == 3 && space_at_end && is_num && (g_strcmp0(args[2], "type") == 0)) || (num_args == 4 && !space_at_end && is_num && (g_strcmp0(args[2], "type") == 0))) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
result = autocomplete_param_with_ac(input, beginning->str, vcard_address_type_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
g_strfreev(args);
return result;
}
} else if ((num_args == 3 && space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2])) || (num_args == 4 && !space_at_end && is_num && autocomplete_contains(vcard_togglable_param_ac, args[2]))) {
GString* beginning = g_string_new("/vcard");
g_string_append_printf(beginning, " %s %s %s", args[0], args[1], args[2]);
result = autocomplete_param_with_ac(input, beginning->str, vcard_toggle_ac, TRUE, previous);
g_string_free(beginning, TRUE);
if (result) {
g_strfreev(args);
return result;
}
} else {
result = autocomplete_param_with_ac(input, "/vcard set name", vcard_name_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/vcard set", vcard_set_ac, TRUE, previous);
if (result) {
return result;
}
}
}
result = autocomplete_param_with_ac(input, "/vcard add", vcard_element_ac, TRUE, previous);
if (result) {
return result;
}
if (window->type == WIN_MUC) {
char* unquoted = strip_arg_quotes(input);
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid);
if (nick_ac) {
result = autocomplete_param_with_ac(unquoted, "/vcard get", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_ac(unquoted, "/vcard photo open", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_ac(unquoted, "/vcard photo save", nick_ac, TRUE, previous);
if (result) {
free(unquoted);
return result;
}
}
free(unquoted);
} else {
char* unquoted = strip_arg_quotes(input);
result = autocomplete_param_with_func(unquoted, "/vcard get", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_func(unquoted, "/vcard photo open", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
result = autocomplete_param_with_func(unquoted, "/vcard photo save", roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
return result;
}
free(unquoted);
}
result = autocomplete_param_with_ac(input, "/vcard photo", vcard_photo_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/vcard", vcard_ac, TRUE, previous);
if (result) {
return result;
}
return result;
}