diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index ee0f717e..d817b2ef 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -129,6 +129,7 @@ static char* _url_autocomplete(ProfWin* window, const char* const input, gboolea static char* _executable_autocomplete(ProfWin* window, const char* const input, gboolean previous); static char* _lastactivity_autocomplete(ProfWin* window, const char* const input, gboolean previous); 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* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context); @@ -269,6 +270,8 @@ static Autocomplete avatar_ac; static Autocomplete url_ac; static Autocomplete executable_ac; static Autocomplete intype_ac; +static Autocomplete mood_ac; +static Autocomplete mood_type_ac; /*! * \brief Initialization of auto completion for commands. @@ -1057,6 +1060,90 @@ cmd_ac_init(void) intype_ac = autocomplete_new(); autocomplete_add(intype_ac, "console"); autocomplete_add(intype_ac, "titlebar"); + + mood_ac = autocomplete_new(); + autocomplete_add(mood_ac, "set"); + mood_type_ac = autocomplete_new(); + autocomplete_add(mood_type_ac, "afraid"); + autocomplete_add(mood_type_ac, "amazed"); + autocomplete_add(mood_type_ac, "angry"); + autocomplete_add(mood_type_ac, "amorous"); + autocomplete_add(mood_type_ac, "annoyed"); + autocomplete_add(mood_type_ac, "anxious"); + autocomplete_add(mood_type_ac, "aroused"); + autocomplete_add(mood_type_ac, "ashamed"); + autocomplete_add(mood_type_ac, "bored"); + autocomplete_add(mood_type_ac, "brave"); + autocomplete_add(mood_type_ac, "calm"); + autocomplete_add(mood_type_ac, "cautious"); + autocomplete_add(mood_type_ac, "cold"); + autocomplete_add(mood_type_ac, "confident"); + autocomplete_add(mood_type_ac, "confused"); + autocomplete_add(mood_type_ac, "contemplative"); + autocomplete_add(mood_type_ac, "contented"); + autocomplete_add(mood_type_ac, "cranky"); + autocomplete_add(mood_type_ac, "crazy"); + autocomplete_add(mood_type_ac, "creative"); + autocomplete_add(mood_type_ac, "curious"); + autocomplete_add(mood_type_ac, "dejected"); + autocomplete_add(mood_type_ac, "depressed"); + autocomplete_add(mood_type_ac, "disappointed"); + autocomplete_add(mood_type_ac, "disgusted"); + autocomplete_add(mood_type_ac, "dismayed"); + autocomplete_add(mood_type_ac, "distracted"); + autocomplete_add(mood_type_ac, "embarrassed"); + autocomplete_add(mood_type_ac, "envious"); + autocomplete_add(mood_type_ac, "excited"); + autocomplete_add(mood_type_ac, "flirtatious"); + autocomplete_add(mood_type_ac, "frustrated"); + autocomplete_add(mood_type_ac, "grumpy"); + autocomplete_add(mood_type_ac, "guilty"); + autocomplete_add(mood_type_ac, "happy"); + autocomplete_add(mood_type_ac, "hopeful"); + autocomplete_add(mood_type_ac, "hot"); + autocomplete_add(mood_type_ac, "humbled"); + autocomplete_add(mood_type_ac, "humiliated"); + autocomplete_add(mood_type_ac, "hungry"); + autocomplete_add(mood_type_ac, "hurt"); + autocomplete_add(mood_type_ac, "impressed"); + autocomplete_add(mood_type_ac, "in_awe"); + autocomplete_add(mood_type_ac, "in_love"); + autocomplete_add(mood_type_ac, "indignant"); + autocomplete_add(mood_type_ac, "interested"); + autocomplete_add(mood_type_ac, "intoxicated"); + autocomplete_add(mood_type_ac, "invincible"); + autocomplete_add(mood_type_ac, "jealous"); + autocomplete_add(mood_type_ac, "lonely"); + autocomplete_add(mood_type_ac, "lucky"); + autocomplete_add(mood_type_ac, "mean"); + autocomplete_add(mood_type_ac, "moody"); + autocomplete_add(mood_type_ac, "nervous"); + autocomplete_add(mood_type_ac, "neutral"); + autocomplete_add(mood_type_ac, "offended"); + autocomplete_add(mood_type_ac, "outraged"); + autocomplete_add(mood_type_ac, "playful"); + autocomplete_add(mood_type_ac, "proud"); + autocomplete_add(mood_type_ac, "relaxed"); + autocomplete_add(mood_type_ac, "relieved"); + autocomplete_add(mood_type_ac, "remorseful"); + autocomplete_add(mood_type_ac, "restless"); + autocomplete_add(mood_type_ac, "sad"); + autocomplete_add(mood_type_ac, "sarcastic"); + autocomplete_add(mood_type_ac, "serious"); + autocomplete_add(mood_type_ac, "shocked"); + autocomplete_add(mood_type_ac, "shy"); + autocomplete_add(mood_type_ac, "sick"); + autocomplete_add(mood_type_ac, "sleepy"); + autocomplete_add(mood_type_ac, "spontaneous"); + autocomplete_add(mood_type_ac, "stressed"); + autocomplete_add(mood_type_ac, "strong"); + autocomplete_add(mood_type_ac, "surprised"); + autocomplete_add(mood_type_ac, "thankful"); + autocomplete_add(mood_type_ac, "thirsty"); + autocomplete_add(mood_type_ac, "tired"); + autocomplete_add(mood_type_ac, "undefined"); + autocomplete_add(mood_type_ac, "weak"); + autocomplete_add(mood_type_ac, "worried"); } void @@ -1372,6 +1459,8 @@ cmd_ac_reset(ProfWin* window) autocomplete_reset(url_ac); autocomplete_reset(executable_ac); autocomplete_reset(intype_ac); + autocomplete_reset(mood_ac); + autocomplete_reset(mood_type_ac); autocomplete_reset(script_ac); if (script_show_ac) { @@ -1801,6 +1890,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete); g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete); g_hash_table_insert(ac_funcs, "/intype", _intype_autocomplete); + g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete); int len = strlen(input); char parsed[len + 1]; @@ -4147,3 +4237,21 @@ _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous result = autocomplete_param_with_ac(input, "/intype", intype_ac, FALSE, previous); return result; } + +static char* +_mood_autocomplete(ProfWin* window, const char* const input, gboolean previous) +{ + char* result = NULL; + + result = autocomplete_param_with_ac(input, "/mood", status_ac, TRUE, previous); + if (result) { + return result; + } + + result = autocomplete_param_with_ac(input, "/mood set", mood_type_ac, FALSE, previous); + if (result) { + return result; + } + + return result; +} diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 7bc4a1ff..ab491f0c 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2679,6 +2679,22 @@ static struct cmd_t command_defs[] = { "/register someuser my.xmppserv.er port 5443 tls force") }, + { "/mood", + parse_args, 2, 3, NULL, + CMD_NOSUBFUNCS + CMD_MAINFUNC(cmd_mood) + CMD_TAGS( + CMD_TAG_CHAT) + CMD_SYN( + "/mood set [text]") + CMD_DESC( + "Set your mood (XEP-0107). Use tab to switch through predefined moods.") + CMD_ARGS( + { "set ", "Setting your mood." }, + { "", "Additional Text." }) + CMD_EXAMPLES( + "/mood set happy \"So happy to use Profanity!\"") + }, // NEXT-COMMAND (search helper) }; diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 74bbc5e0..fe5d5e45 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -9645,3 +9645,19 @@ cmd_register(ProfWin* window, const char* const command, gchar** args) log_info("we are leaving the registration process"); return TRUE; } + +gboolean +cmd_mood(ProfWin* window, const char* const command, gchar** args) +{ + if (g_strcmp0(args[0], "set") == 0) { + if(args[1]) { + cons_show("Your mood: %s", args[1]); + if (args[2]) { + publish_user_mood(args[1], args[2]); + } else { + publish_user_mood(args[1], args[1]); + } + } + } + return TRUE; +} diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 5e2a7876..f4cbe0bf 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -249,5 +249,6 @@ gboolean cmd_editor(ProfWin* window, const char* const command, gchar** args); gboolean cmd_correct_editor(ProfWin* window, const char* const command, gchar** args); gboolean cmd_silence(ProfWin* window, const char* const command, gchar** args); gboolean cmd_register(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_mood(ProfWin* window, const char* const command, gchar** args); #endif diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index ebc052fc..81eec81e 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2798,3 +2798,55 @@ iq_muc_register_nick(const char* const roomjid) xmpp_stanza_release(iq); xmpp_stanza_release(query); } + +void +publish_user_mood(const char* const mood, const char* const text) +{ + xmpp_ctx_t* const ctx = connection_get_ctx(); + char* id = connection_create_stanza_id(); + + xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); + + xmpp_stanza_t* pubsub = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(pubsub, STANZA_NAME_PUBSUB); + xmpp_stanza_set_ns(pubsub, STANZA_NS_PUBSUB); + xmpp_stanza_add_child(iq, pubsub); + + xmpp_stanza_t* publish = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(publish, STANZA_NAME_PUBLISH); + xmpp_stanza_set_attribute(publish, STANZA_ATTR_NODE, STANZA_NS_MOOD); + xmpp_stanza_add_child(pubsub, publish); + + xmpp_stanza_t* item = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(item, STANZA_NAME_ITEM); + xmpp_stanza_set_attribute(item, "id", "current"); + xmpp_stanza_add_child(publish, item); + + xmpp_stanza_t* mood_t = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(mood_t, STANZA_NAME_MOOD); + xmpp_stanza_set_ns(mood_t, STANZA_NS_MOOD); + xmpp_stanza_add_child(item, mood_t); + + xmpp_stanza_t* x = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(x, mood); + xmpp_stanza_add_child(mood_t, x); + + xmpp_stanza_t* text_t = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(text_t, STANZA_NAME_TEXT); + xmpp_stanza_add_child(mood_t, text_t); + + xmpp_stanza_t* t = xmpp_stanza_new(ctx); + xmpp_stanza_set_text(t, text); + xmpp_stanza_add_child(text_t, t); + + iq_send_stanza(iq); + + xmpp_stanza_release(iq); + xmpp_stanza_release(pubsub); + xmpp_stanza_release(publish); + xmpp_stanza_release(item); + xmpp_stanza_release(mood_t); + xmpp_stanza_release(x); + xmpp_stanza_release(text_t); + xmpp_stanza_release(t); +} diff --git a/src/xmpp/message.c b/src/xmpp/message.c index 4aa22437..70371576 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -161,8 +161,16 @@ _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* con } else if (type && g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0) { // XEP-0045: Multi-User Chat _handle_groupchat(stanza); + } else if (type && g_strcmp0(type, STANZA_TYPE_HEADLINE) == 0) { - _handle_headline(stanza); + xmpp_stanza_t* event = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_PUBSUB_EVENT); + // TODO: do we want to handle all pubsub here or should additionaly check for STANZA_NS_MOOD? + if (event) { + _handle_pubsub(stanza, event); + return 1; + } else { + _handle_headline(stanza); + } } else if (type == NULL || g_strcmp0(type, STANZA_TYPE_CHAT) == 0 || g_strcmp0(type, STANZA_TYPE_NORMAL) == 0) { // type: chat, normal (==NULL) diff --git a/src/xmpp/session.c b/src/xmpp/session.c index 046d4fd2..4a19e211 100644 --- a/src/xmpp/session.c +++ b/src/xmpp/session.c @@ -286,6 +286,36 @@ session_get_account_name(void) return saved_account.name; } +static int +_receive_mood(xmpp_stanza_t* const stanza, void* const userdata) +{ + const char* from = xmpp_stanza_get_from(stanza); + xmpp_stanza_t* event = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_EVENT, STANZA_NS_PUBSUB_EVENT); + if (event) { + xmpp_stanza_t* items = xmpp_stanza_get_child_by_name(event, STANZA_NAME_ITEMS); + if (items) { + xmpp_stanza_t* item = xmpp_stanza_get_child_by_name(items, STANZA_NAME_ITEM); + if (item) { + xmpp_stanza_t* mood = xmpp_stanza_get_child_by_name_and_ns(item, STANZA_NAME_MOOD, STANZA_NS_MOOD); + if (mood) { + xmpp_stanza_t* c = xmpp_stanza_get_children(mood); + if (c) { + const char* m = xmpp_stanza_get_name(c); + xmpp_stanza_t* t = xmpp_stanza_get_child_by_name(mood, STANZA_NAME_TEXT); + if (t) { + const char* text = xmpp_stanza_get_text(t); + cons_show("Mood from %s %s (%s)", from, m, text); + } else { + cons_show("Mood from %s %s", from, m); + } + } + } + } + } + } + return TRUE; +} + void session_login_success(gboolean secured) { @@ -330,6 +360,9 @@ session_login_success(gboolean secured) g_timer_destroy(reconnect_timer); reconnect_timer = NULL; } + + message_pubsub_event_handler_add(STANZA_NS_MOOD, _receive_mood, NULL, NULL); + caps_add_feature(STANZA_NS_MOOD_NOTIFY); } void diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 7aac5d08..9e957749 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -117,6 +117,8 @@ #define STANZA_NAME_USERNAME "username" #define STANZA_NAME_PROPOSE "propose" #define STANZA_NAME_REPORT "report" +#define STANZA_NAME_EVENT "event" +#define STANZA_NAME_MOOD "mood" #define STANZA_NAME_RECEIVED "received" #define STANZA_NAME_SENT "sent" @@ -241,6 +243,8 @@ #define STANZA_NS_JINGLE_MESSAGE "urn:xmpp:jingle-message:0" #define STANZA_NS_JINGLE_RTP "urn:xmpp:jingle:apps:rtp:1" #define STANZA_NS_REPORTING "urn:xmpp:reporting:1" +#define STANZA_NS_MOOD "http://jabber.org/protocol/mood" +#define STANZA_NS_MOOD_NOTIFY "http://jabber.org/protocol/mood+notify" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 16293d73..8a2d2eb2 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -307,4 +307,6 @@ FormField* form_get_field_by_tag(DataForm* form, const char* const tag); Autocomplete form_get_value_ac(DataForm* form, const char* const tag); void form_reset_autocompleters(DataForm* form); +void publish_user_mood(const char* const mood, const char* const text); + #endif diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index 847ce82a..a01c9930 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -426,6 +426,11 @@ iq_muc_register_nick(const char* const roomjid) { } +void +publish_user_mood(const char* const mood, const char* const text) +{ +} + // caps functions void caps_add_feature(char* feature)