about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command.c81
-rw-r--r--src/jabber.c40
-rw-r--r--src/jabber.h8
-rw-r--r--src/preferences.c2
-rw-r--r--src/profanity.c26
-rw-r--r--src/profanity.h3
-rw-r--r--src/stanza.h2
-rw-r--r--src/ui.h1
-rw-r--r--src/windows.c33
9 files changed, 173 insertions, 23 deletions
diff --git a/src/command.c b/src/command.c
index 7621cd9a..3f2f2e10 100644
--- a/src/command.c
+++ b/src/command.c
@@ -65,11 +65,13 @@ static gboolean _cmd_set_boolean_preference(const char * const inp,
 static char *_cmd_complete(char *inp);
 static void _cmd_reset_command_completer(void);
 static char *_cmd_who_complete(char *inp);
-static void _cmd_reset_who_completer(void);
+static void _cmd_who_reset_completer(void);
 static char *_cmd_help_complete(char *inp);
 static void _cmd_help_reset_completer(void);
 static char *_cmd_notify_complete(char *inp);
 static void _cmd_notify_reset_completer(void);
+static char *_cmd_sub_complete(char *inp);
+static void _cmd_sub_reset_completer(void);
 static void _cmd_complete_parameters(char *input, int *size);
 static void _notify_autocomplete(char *input, int *size);
 static void _parameter_autocomplete(char *input, int *size, char *command,
@@ -199,12 +201,18 @@ static struct cmd_t main_commands[] =
 
     { "/sub",
         _cmd_sub,
-        { "/sub user@host", "Subscribe to presence notifications of user.",
-        { "/sub user@host",
+        { "/sub <add|del|request|show> [jid]", "Manage subscriptions.",
+        { "/sub <add|del|request|show> [jid]",
           "------------------",
-          "Send a subscription request to the user to be informed of their presence.",
+          "add     : Approve subscription to a contact.",
+          "del     : Remove subscription for a contact.",
+          "request : Send a subscription request to the user to be informed of their",
+          "        : presence.",
+          "show    : Show subscriprion status for a contact.",
           "",
-          "Example: /sub myfriend@jabber.org",
+          "If optional parameter 'jid' isn't set command belongs to the current window.",
+          "",
+          "Example: /sub add myfriend@jabber.org",
           NULL  } } },
 
     { "/tiny",
@@ -462,6 +470,7 @@ static PAutocomplete commands_ac;
 static PAutocomplete who_ac;
 static PAutocomplete help_ac;
 static PAutocomplete notify_ac;
+static PAutocomplete sub_ac;
 
 /*
  * Initialise command autocompleter and history
@@ -485,6 +494,12 @@ cmd_init(void)
     p_autocomplete_add(notify_ac, strdup("typing"));
     p_autocomplete_add(notify_ac, strdup("remind"));
 
+    sub_ac = p_autocomplete_new();
+    p_autocomplete_add(sub_ac, strdup("add"));
+    p_autocomplete_add(sub_ac, strdup("del"));
+    p_autocomplete_add(sub_ac, strdup("request"));
+    p_autocomplete_add(sub_ac, strdup("show"));
+
     unsigned int i;
     for (i = 0; i < ARRAY_SIZE(main_commands); i++) {
         struct cmd_t *pcmd = main_commands+i;
@@ -554,8 +569,9 @@ cmd_reset_autocomplete()
     prefs_reset_boolean_choice();
     _cmd_help_reset_completer();
     _cmd_notify_reset_completer();
+    _cmd_sub_reset_completer();
+    _cmd_who_reset_completer();
     _cmd_reset_command_completer();
-    _cmd_reset_who_completer();
 }
 
 GSList *
@@ -655,7 +671,7 @@ _cmd_who_complete(char *inp)
 }
 
 static void
-_cmd_reset_who_completer(void)
+_cmd_who_reset_completer(void)
 {
     p_autocomplete_reset(who_ac);
 }
@@ -684,6 +700,18 @@ _cmd_notify_reset_completer(void)
     p_autocomplete_reset(notify_ac);
 }
 
+static char *
+_cmd_sub_complete(char *inp)
+{
+    return p_autocomplete_complete(sub_ac, inp);
+}
+
+static void
+_cmd_sub_reset_completer(void)
+{
+    p_autocomplete_reset(sub_ac);
+}
+
 static void
 _cmd_complete_parameters(char *input, int *size)
 {
@@ -710,6 +738,8 @@ _cmd_complete_parameters(char *input, int *size)
         contact_list_find_contact);
     _parameter_autocomplete(input, size, "/connect",
         prefs_find_login);
+    _parameter_autocomplete(input, size, "/sub",
+        _cmd_sub_complete);
     _parameter_autocomplete(input, size, "/help",
         _cmd_help_complete);
     _parameter_autocomplete(input, size, "/who",
@@ -775,13 +805,40 @@ _cmd_sub(const char * const inp, struct cmd_help_t help)
         cons_show("Usage: %s", help.usage);
         result = TRUE;
     } else {
-        char *user, *lower;
-        user = strndup(inp+5, strlen(inp)-5);
-        lower = g_utf8_strdown(user, -1);
+        char *inp_cpy, *subcmd;
+        char *jid, *bare_jid;
 
-        jabber_subscribe(lower);
-        cons_show("Sent subscription request to %s.", user);
+        inp_cpy = strndup(inp+5, strlen(inp)-5);
+        /* using strtok is bad idea */
+        subcmd = strtok(inp_cpy, " ");
+        jid = strtok(NULL, " ");
 
+        if (jid != NULL) {
+            jid = strdup(jid);
+        } else {
+            jid = win_get_recipient();
+        }
+
+        bare_jid = strtok(jid, "/");
+
+        if (strcmp(subcmd, "add") == 0) {
+            jabber_subscription(bare_jid, PRESENCE_SUBSCRIBED);
+            cons_show("Accepted subscription for %s", bare_jid);
+            log_info("Accepted subscription for %s", bare_jid);
+        } else if (strcmp(subcmd, "del") == 0) {
+            jabber_subscription(bare_jid, PRESENCE_UNSUBSCRIBED);
+            cons_show("Deleted subscription for %s", bare_jid);
+            log_info("Deleted subscription for %s", bare_jid);
+        } else if (strcmp(subcmd, "request") == 0) {
+            jabber_subscription(bare_jid, PRESENCE_SUBSCRIBE);
+            cons_show("Sent subscription request to %s.", bare_jid);
+            log_info("Sent subscription request to %s.", bare_jid);
+        } else if (strcmp(subcmd, "show") == 0) {
+            /* TODO: not implemented yet */
+        }
+
+        free(jid);
+        free(inp_cpy);
         result = TRUE;
     }
 
diff --git a/src/jabber.c b/src/jabber.c
index f16a4737..bb691a42 100644
--- a/src/jabber.c
+++ b/src/jabber.c
@@ -219,16 +219,31 @@ jabber_send_gone(const char * const recipient)
 }
 
 void
-jabber_subscribe(const char * const recipient)
+jabber_subscription(const char * const jid, jabber_subscr_t action)
 {
     xmpp_stanza_t *presence;
+    char *type, *jid_cpy, *bare_jid;
+
+    // jid must be a bare JID
+    jid_cpy = strdup(jid);
+    bare_jid = strtok(jid_cpy, "/");
+
+    if (action == PRESENCE_SUBSCRIBE)
+        type = STANZA_TYPE_SUBSCRIBE;
+    else if (action == PRESENCE_SUBSCRIBED)
+        type = STANZA_TYPE_SUBSCRIBED;
+    else if (action == PRESENCE_UNSUBSCRIBED)
+        type = STANZA_TYPE_UNSUBSCRIBED;
+    else // unknown action
+        return;
 
     presence = xmpp_stanza_new(jabber_conn.ctx);
     xmpp_stanza_set_name(presence, STANZA_NAME_PRESENCE);
-    xmpp_stanza_set_type(presence, STANZA_TYPE_SUBSCRIBE);
-    xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, recipient);
+    xmpp_stanza_set_type(presence, type);
+    xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, bare_jid);
     xmpp_send(jabber_conn.conn, presence);
     xmpp_stanza_release(presence);
+    free(jid_cpy);
 }
 
 void
@@ -698,12 +713,7 @@ _presence_handler(xmpp_conn_t * const conn,
         else
             status_str = NULL;
 
-        if ((type != NULL) && (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0)) {
-            if (strcmp(short_jid, short_from) !=0) {
-                prof_handle_contact_offline(short_from, "offline", status_str);
-            }
-        } else {
-
+        if (type == NULL) { // available
             xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW);
             if (show != NULL)
                 show_str = xmpp_stanza_get_text(show);
@@ -713,6 +723,18 @@ _presence_handler(xmpp_conn_t * const conn,
             if (strcmp(short_jid, short_from) !=0) {
                 prof_handle_contact_online(short_from, show_str, status_str);
             }
+        } else if (strcmp(type, STANZA_TYPE_UNAVAILABLE) == 0) {
+            if (strcmp(short_jid, short_from) !=0) {
+                prof_handle_contact_offline(short_from, "offline", status_str);
+            }
+        } else if (strcmp(type, STANZA_TYPE_SUBSCRIBE) == 0) {
+            prof_handle_subscription(short_from, PRESENCE_SUBSCRIBE);
+        } else if (strcmp(type, STANZA_TYPE_SUBSCRIBED) == 0) {
+            prof_handle_subscription(short_from, PRESENCE_SUBSCRIBED);
+        } else if (strcmp(type, STANZA_TYPE_UNSUBSCRIBED) == 0) {
+            prof_handle_subscription(short_from, PRESENCE_UNSUBSCRIBED);
+        } else { /* unknown type */
+            log_debug("Received presence with unknown type '%s'", type);
         }
     }
 
diff --git a/src/jabber.h b/src/jabber.h
index e15c6fff..5dea2a06 100644
--- a/src/jabber.h
+++ b/src/jabber.h
@@ -40,14 +40,20 @@ typedef enum {
     PRESENCE_XA
 } jabber_presence_t;
 
+typedef enum {
+    PRESENCE_SUBSCRIBE,
+    PRESENCE_SUBSCRIBED,
+    PRESENCE_UNSUBSCRIBED
+} jabber_subscr_t;
+
 void jabber_init(const int disable_tls);
 jabber_conn_status_t jabber_connect(const char * const user,
     const char * const passwd);
 void jabber_disconnect(void);
 void jabber_process_events(void);
-void jabber_subscribe(const char * const recipient);
 void jabber_join(const char * const room, const char * const nick);
 void jabber_leave_chat_room(const char * const room_jid);
+void jabber_subscription(const char * const jid, jabber_subscr_t action);
 void jabber_send(const char * const msg, const char * const recipient);
 void jabber_send_groupchat(const char * const msg, const char * const recipient);
 void jabber_send_inactive(const char * const recipient);
diff --git a/src/preferences.c b/src/preferences.c
index 1cde801a..e6275bbc 100644
--- a/src/preferences.c
+++ b/src/preferences.c
@@ -21,6 +21,7 @@
  */
 
 #include "config.h"
+#include "preferences.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -115,7 +116,6 @@ prefs_load(void)
     boolean_choice_ac = p_autocomplete_new();
     p_autocomplete_add(boolean_choice_ac, strdup("on"));
     p_autocomplete_add(boolean_choice_ac, strdup("off"));
-
 }
 
 void
diff --git a/src/profanity.c b/src/profanity.c
index 2d1561e2..fb25a9f4 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -145,6 +145,32 @@ prof_handle_error_message(const char *from, const char *err_msg)
 }
 
 void
+prof_handle_subscription(const char *from, jabber_subscr_t type)
+{
+    switch (type) {
+    case PRESENCE_SUBSCRIBE:
+        /* TODO: auto-subscribe if needed */
+        cons_show("Received authorization request from %s", from);
+        log_info("Received authorization request from %s", from);
+        win_show_system_msg(from, "Authorization request, type '/sub add' to accept or '/sub del' to reject");
+        break;
+    case PRESENCE_SUBSCRIBED:
+        cons_show("Subscription received from %s", from);
+        log_info("Subscription received from %s", from);
+        win_show_system_msg(from, "Subscribed");
+        break;
+    case PRESENCE_UNSUBSCRIBED:
+        cons_show("%s deleted subscription", from);
+        log_info("%s deleted subscription", from);
+        win_show_system_msg(from, "Unsubscribed");
+        break;
+    default:
+        /* unknown type */
+	break;
+    }
+}
+
+void
 prof_handle_login_success(const char *jid)
 {
     const char *msg = "logged in successfully.";
diff --git a/src/profanity.h b/src/profanity.h
index baf2a6b9..a547ce23 100644
--- a/src/profanity.h
+++ b/src/profanity.h
@@ -23,6 +23,8 @@
 #ifndef PROFANITY_H
 #define PROFANITY_H
 
+#include "jabber.h"
+
 void prof_run(const int disable_tls, char *log_level);
 
 void prof_handle_login_success(const char *jid);
@@ -34,6 +36,7 @@ void prof_handle_contact_offline(char *contact, char *show, char *status);
 void prof_handle_incoming_message(char *from, char *message);
 void prof_handle_delayed_message(char *from, char *message, GTimeVal tv_stamp);
 void prof_handle_error_message(const char *from, const char *err_msg);
+void prof_handle_subscription(const char *from, jabber_subscr_t type);
 void prof_handle_roster(GSList *roster);
 void prof_handle_gone(const char * const from);
 void prof_handle_room_history(const char * const room_jid,
diff --git a/src/stanza.h b/src/stanza.h
index 6f244327..706307fa 100644
--- a/src/stanza.h
+++ b/src/stanza.h
@@ -49,6 +49,8 @@
 #define STANZA_TYPE_GROUPCHAT "groupchat"
 #define STANZA_TYPE_UNAVAILABLE "unavailable"
 #define STANZA_TYPE_SUBSCRIBE "subscribe"
+#define STANZA_TYPE_SUBSCRIBED "subscribed"
+#define STANZA_TYPE_UNSUBSCRIBED "unsubscribed"
 #define STANZA_TYPE_GET "get"
 #define STANZA_TYPE_ERROR "error"
 
diff --git a/src/ui.h b/src/ui.h
index d22afc75..9d958946 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -91,6 +91,7 @@ void win_show_gone(const char * const from);
 void win_show_incomming_msg(const char * const from, const char * const message,
     GTimeVal *tv_stamp);
 void win_show_error_msg(const char * const from, const char *err_msg);
+void win_show_system_msg(const char * const from, const char *message);
 void win_show_outgoing_msg(const char * const from, const char * const to,
     const char * const message);
 void win_handle_special_keys(const int * const ch);
diff --git a/src/windows.c b/src/windows.c
index abf8f2fa..c608e0ca 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -433,6 +433,39 @@ win_show_gone(const char * const from)
     }
 }
 
+void
+win_show_system_msg(const char * const from, const char *message)
+{
+    int win_index;
+    WINDOW *win;
+    char from_cpy[strlen(from) + 1];
+    char *bare_jid;
+
+    if (from == NULL || message == NULL)
+        return;
+
+    strcpy(from_cpy, from);
+    bare_jid = strtok(from_cpy, "/");
+
+    win_index = _find_prof_win_index(bare_jid);
+    if (win_index == NUM_WINS) {
+        win_index = _new_prof_win(bare_jid);
+        status_bar_active(win_index);
+        dirty = TRUE;
+    }
+    win = _wins[win_index].win;
+
+    _win_show_time(win);
+    wattron(win, COLOUR_ONLINE);
+    wprintw(win, "*%s %s\n", bare_jid, message);
+    wattroff(win, COLOUR_ONLINE);
+
+    // this is the current window
+    if (win_index == _curr_prof_win) {
+        dirty = TRUE;
+    }
+}
+
 #ifdef HAVE_LIBNOTIFY
 static void
 _win_notify(const char * const message, int timeout,