From 17757c86e658c157e1df00152028f5e7f38a0a5a Mon Sep 17 00:00:00 2001 From: James Booth Date: Wed, 24 Apr 2013 23:50:47 +0100 Subject: [PATCH] Support for XEP-0249 Direct MUC Invitations Commands /invite, /invites, /decline and /join --- src/command/command.c | 47 +++++++++++++++++++++++++++ src/muc.c | 68 ++++++++++++++++++++++++++++++++++++++++ src/muc.h | 10 ++++++ src/profanity.c | 12 +++++-- src/tools/autocomplete.c | 6 ++++ src/tools/autocomplete.h | 1 + src/ui/console.c | 37 ++++++++++++---------- src/ui/notifier.c | 14 ++++++--- src/ui/notifier.h | 3 +- src/ui/ui.h | 1 + 10 files changed, 174 insertions(+), 25 deletions(-) diff --git a/src/command/command.c b/src/command/command.c index 6cbfdac9..d9207763 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -102,6 +102,8 @@ static gboolean _cmd_close(gchar **args, struct cmd_help_t help); static gboolean _cmd_clear(gchar **args, struct cmd_help_t help); static gboolean _cmd_join(gchar **args, struct cmd_help_t help); static gboolean _cmd_invite(gchar **args, struct cmd_help_t help); +static gboolean _cmd_invites(gchar **args, struct cmd_help_t help); +static gboolean _cmd_decline(gchar **args, struct cmd_help_t help); static gboolean _cmd_rooms(gchar **args, struct cmd_help_t help); static gboolean _cmd_disco(gchar **args, struct cmd_help_t help); static gboolean _cmd_set_beep(gchar **args, struct cmd_help_t help); @@ -349,6 +351,24 @@ static struct cmd_t main_commands[] = "If a message is supplied it will be send as the reason for the invite.", NULL } } }, + { "/invites", + _cmd_invites, parse_args_with_freetext, 0, 0, + { "/invites", "Show outstanding chat room invites.", + { "/invites", + "--------", + "Show all rooms that you have been invited to, and have not yet been accepted or declind.", + "Use \"/join \" to accept a room invitation.", + "Use \"/decline \" to decline a room invitation.", + NULL } } }, + + { "/decline", + _cmd_decline, parse_args_with_freetext, 1, 1, + { "/decline room", "Decline a chat room invite.", + { "/decline room", + "-------------", + "Decline invitation to a chat room, the room will no longer be in the list of outstanding invites.", + NULL } } }, + { "/rooms", _cmd_rooms, parse_args, 0, 1, { "/rooms [conference-service]", "List chat rooms.", @@ -914,6 +934,7 @@ void cmd_reset_autocomplete() { contact_list_reset_search_attempts(); + muc_reset_invites_ac(); accounts_reset_all_search(); accounts_reset_enabled_search(); prefs_reset_boolean_choice(); @@ -1114,6 +1135,9 @@ _cmd_complete_parameters(char *input, int *size) } _parameter_autocomplete(input, size, "/invite", contact_list_find_contact); + _parameter_autocomplete(input, size, "/decline", muc_find_invite); + _parameter_autocomplete(input, size, "/join", muc_find_invite); + _parameter_autocomplete(input, size, "/connect", accounts_find_enabled); @@ -2201,6 +2225,7 @@ _cmd_join(gchar **args, struct cmd_help_t help) presence_join_room(room_jid); } ui_room_join(room_jid); + muc_remove_invite(room); jid_destroy(room_jid); jid_destroy(my_jid); @@ -2240,6 +2265,28 @@ _cmd_invite(gchar **args, struct cmd_help_t help) return TRUE; } +static gboolean +_cmd_invites(gchar **args, struct cmd_help_t help) +{ + GSList *invites = muc_get_invites(); + cons_show_room_invites(invites); + g_slist_free_full(invites, g_free); + return TRUE; +} + +static gboolean +_cmd_decline(gchar **args, struct cmd_help_t help) +{ + if (!muc_invites_include(args[0])) { + cons_show("No such invite exists."); + } else { + muc_remove_invite(args[0]); + cons_show("Declined invite to %s.", args[0]); + } + + return TRUE; +} + static gboolean _cmd_rooms(gchar **args, struct cmd_help_t help) { diff --git a/src/muc.c b/src/muc.c index dfa3f194..4f308f1d 100644 --- a/src/muc.c +++ b/src/muc.c @@ -29,6 +29,8 @@ #include "jid.h" #include "tools/autocomplete.h" +#include "ui/ui.h" + typedef struct _muc_room_t { char *room; // e.g. test@conference.server char *nick; // e.g. Some User @@ -41,9 +43,75 @@ typedef struct _muc_room_t { } ChatRoom; GHashTable *rooms = NULL; +Autocomplete invite_ac; static void _free_room(ChatRoom *room); +void +muc_init(void) +{ + invite_ac = autocomplete_new(); +} + +void +muc_add_invite(char *room) +{ + autocomplete_add(invite_ac, strdup(room)); +} + +void +muc_remove_invite(char *room) +{ + autocomplete_remove(invite_ac, room); +} + +gint +muc_invite_count(void) +{ + return autocomplete_length(invite_ac); +} + +GSList * +muc_get_invites(void) +{ + return autocomplete_get_list(invite_ac); +} + +gboolean +muc_invites_include(const char * const room) +{ + GSList *invites = autocomplete_get_list(invite_ac); + GSList *curr = invites; + while (curr != NULL) { + if (strcmp(curr->data, room) == 0) { + g_slist_free_full(invites, g_free); + return TRUE; + } else { + curr = g_slist_next(curr); + } + } + g_slist_free_full(invites, g_free); + return FALSE; +} + +void +muc_reset_invites_ac(void) +{ + autocomplete_reset(invite_ac); +} + +char * +muc_find_invite(char *search_str) +{ + return autocomplete_complete(invite_ac, search_str); +} + +void +muc_clear_invites(void) +{ + autocomplete_clear(invite_ac); +} + /* * Join the chat room with the specified nickname */ diff --git a/src/muc.h b/src/muc.h index 86ebabcb..b0458378 100644 --- a/src/muc.h +++ b/src/muc.h @@ -29,6 +29,7 @@ #include "jid.h" #include "tools/autocomplete.h" +void muc_init(void); void muc_join_room(const char * const room, const char * const nick); void muc_leave_room(const char * const room); gboolean muc_room_is_active(Jid *jid); @@ -56,4 +57,13 @@ void muc_set_roster_pending_nick_change(const char * const room, char* muc_complete_roster_nick_change(const char * const room, const char * const nick); +void muc_add_invite(const char *room); +void muc_remove_invite(const char * const room); +gint muc_invite_count(void); +GSList* muc_get_invites(void); +gboolean muc_invites_include(const char * const room); +void muc_reset_invites_ac(void); +char* muc_find_invite(char *search_str); +void muc_clear_invites(void); + #endif diff --git a/src/profanity.c b/src/profanity.c index 052575a9..61e540c0 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -224,6 +224,7 @@ prof_handle_lost_connection(void) { cons_show_error("Lost connection."); contact_list_clear(); + muc_clear_invites(); chat_sessions_clear(); ui_disconnected(); ui_current_page_off(); @@ -235,6 +236,7 @@ prof_handle_disconnect(const char * const jid) cons_show("%s logged out successfully.", jid); jabber_disconnect(); contact_list_clear(); + muc_clear_invites(); chat_sessions_clear(); ui_disconnected(); ui_current_page_off(); @@ -322,8 +324,13 @@ void prof_handle_room_invite(jabber_invite_t invite_type, const char * const invitor, const char * const room, const char * const reason) { - cons_show_room_invite(invitor, room, reason); - ui_current_page_off(); + Jid *room_jid = jid_create(room); + if (!muc_room_is_active(room_jid) && !muc_invites_include(room)) { + cons_show_room_invite(invitor, room, reason); + muc_add_invite(room); + ui_current_page_off(); + } + jid_destroy(room_jid); } void @@ -557,6 +564,7 @@ _init(const int disable_tls, char *log_level) cmd_init(); log_info("Initialising contact list"); contact_list_init(); + muc_init(); atexit(_shutdown); } diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index baeeecb2..72abcba4 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -71,6 +71,12 @@ autocomplete_free(Autocomplete ac) ac = NULL; } +gint +autocomplete_length(Autocomplete ac) +{ + return g_slist_length(ac->items); +} + gboolean autocomplete_add(Autocomplete ac, void *item) { diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h index 03f4a013..79f1a094 100644 --- a/src/tools/autocomplete.h +++ b/src/tools/autocomplete.h @@ -41,5 +41,6 @@ gboolean autocomplete_add(Autocomplete ac, void *item); gboolean autocomplete_remove(Autocomplete ac, const char * const item); GSList * autocomplete_get_list(Autocomplete ac); gchar * autocomplete_complete(Autocomplete ac, gchar *search_str); +gint autocomplete_length(Autocomplete ac); #endif diff --git a/src/ui/console.c b/src/ui/console.c index 36358635..ef94f58c 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -313,6 +313,24 @@ cons_show_wins(void) _cons_alert(); } +void +cons_show_room_invites(GSList *invites) +{ + cons_show(""); + if (invites == NULL) { + cons_show("No outstanding chat room invites."); + } else { + cons_show("Chat room invites, use /join or /decline commands:"); + while (invites != NULL) { + cons_show(" %s", invites->data); + invites = g_slist_next(invites); + } + } + + ui_console_dirty(); + _cons_alert(); +} + void cons_show_info(PContact pcontact) { @@ -653,12 +671,6 @@ void cons_show_room_invite(const char * const invitor, const char * const room, const char * const reason) { - char *display_room = NULL; - char *domain = strdup(jabber_get_domain()); - Jid *room_jid = jid_create(room); - GString *default_service = g_string_new("conference."); - g_string_append(default_service, domain); - cons_show(""); cons_show("Chat room invite received:"); cons_show(" From : %s", invitor); @@ -668,21 +680,12 @@ cons_show_room_invite(const char * const invitor, const char * const room, cons_show(" Message: %s", reason); } - if (strcmp(room_jid->domainpart, default_service->str) == 0) { - display_room = room_jid->localpart; - } else { - display_room = room_jid->barejid; - } - - cons_show("Type \"/join %s\" to accept the invitation", display_room); + cons_show("Use /join or /decline"); if (prefs_get_boolean(PREF_NOTIFY_INVITE)) { - notify_invite(invitor, room); + notify_invite(invitor, room, reason); } - jid_destroy(room_jid); - g_string_free(default_service, TRUE); - ui_console_dirty(); _cons_alert(); } diff --git a/src/ui/notifier.c b/src/ui/notifier.c index 941feba9..54951fde 100644 --- a/src/ui/notifier.c +++ b/src/ui/notifier.c @@ -33,6 +33,7 @@ #endif #include "log.h" +#include "muc.h" #include "ui/ui.h" static void _notify(const char * const message, int timeout, @@ -66,12 +67,16 @@ notify_typing(const char * const from) } void -notify_invite(const char * const from, const char * const room) +notify_invite(const char * const from, const char * const room, + const char * const reason) { GString *message = g_string_new("Room invite\nfrom: "); g_string_append(message, from); g_string_append(message, "\nto: "); g_string_append(message, room); + if (reason != NULL) { + g_string_append_printf(message, "\n\"%s\"", reason); + } _notify(message->str, 10000, "Incoming message"); @@ -91,8 +96,7 @@ void notify_remind(void) { gint unread = ui_unread(); - //gint open = jabber_open_invites(); - gint open = 0; + gint open = muc_invite_count(); GString *text = g_string_new(""); @@ -109,9 +113,9 @@ notify_remind(void) g_string_append(text, "\n"); } if (open == 1) { - g_string_append(text, "1 open invite"); + g_string_append(text, "1 room invite"); } else { - g_string_append_printf(text, "%d open invites", open); + g_string_append_printf(text, "%d room invites", open); } } diff --git a/src/ui/notifier.h b/src/ui/notifier.h index 60b2e337..8565f771 100644 --- a/src/ui/notifier.h +++ b/src/ui/notifier.h @@ -26,4 +26,5 @@ void notifier_uninit(void); void notify_typing(const char * const from); void notify_message(const char * const short_from); void notify_remind(void); -void notify_invite(const char * const from, const char * const room); +void notify_invite(const char * const from, const char * const room, + const char * const reason); diff --git a/src/ui/ui.h b/src/ui/ui.h index 4dbde5ee..36e0fd56 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -166,6 +166,7 @@ void cons_show_room_invite(const char * const invitor, const char * const room, void cons_check_version(gboolean not_available_msg); void cons_show_typing(const char * const short_from); void cons_show_incoming_message(const char * const short_from, const int win_index); +void cons_show_room_invites(GSList *invites); // status bar actions void status_bar_refresh(void);