1
0
Fork 0

Merge branch 'master' into chatstates

Conflicts:
	Makefile.am
This commit is contained in:
James Booth 2012-10-30 01:38:08 +00:00
commit d339004f55
16 changed files with 507 additions and 740 deletions

View File

@ -14,7 +14,7 @@ check_PROGRAMS = tests/testsuite
tests_testsuite_SOURCES = tests/test_contact_list.c src/contact_list.c src/contact.c \
tests/test_common.c tests/test_prof_history.c src/prof_history.c src/common.c \
tests/test_prof_autocomplete.c src/prof_autocomplete.c tests/testsuite.c \
tests/test_chat_session.c src/chat_session.c
tests/test_chat_session.c src/chat_session.c src/log.c
tests_testsuite_LDADD = -lheadunit -lstdc++
man_MANS = docs/profanity.1

View File

@ -1,8 +1,8 @@
/*
/*
* chat_session.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
@ -26,30 +26,37 @@
#include <glib.h>
#include "chat_session.h"
#include "log.h"
static ChatSession _chat_session_new(const char * const recipient);
static ChatSession _chat_session_new(const char * const recipient,
gboolean recipient_supports);
static void _chat_session_free(ChatSession session);
struct chat_session_t {
char *recipient;
chat_state_t state;
gboolean sent;
gboolean recipient_supports;
};
static GHashTable *sessions;
void
chat_session_init(void)
chat_sessions_init(void)
{
sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify)_chat_session_free);
}
void
chat_session_start(const char * const recipient)
chat_sessions_clear(void)
{
g_hash_table_remove_all(sessions);
}
void
chat_session_start(const char * const recipient, gboolean recipient_supports)
{
char *key = strdup(recipient);
ChatSession session = _chat_session_new(key);
ChatSession session = _chat_session_new(key, recipient_supports);
g_hash_table_insert(sessions, key, session);
}
@ -59,46 +66,26 @@ chat_session_end(const char * const recipient)
g_hash_table_remove(sessions, recipient);
}
chat_state_t
chat_session_get_state(const char * const recipient)
gboolean
chat_session_recipient_supports(const char * const recipient)
{
ChatSession session = g_hash_table_lookup(sessions, recipient);
if (session == NULL) {
return SESSION_ERR;
log_error("No chat session found for %s.", recipient);
return FALSE;
} else {
return session->state;
return session->recipient_supports;
}
}
void
chat_session_set_state(const char * const recipient, chat_state_t state)
{
ChatSession session = g_hash_table_lookup(sessions, recipient);
session->state = state;
}
gboolean
chat_session_get_sent(const char * const recipient)
{
ChatSession session = g_hash_table_lookup(sessions, recipient);
return session->sent;
}
void
chat_session_sent(const char * const recipient)
{
ChatSession session = g_hash_table_lookup(sessions, recipient);
session->sent = TRUE;
}
static ChatSession
_chat_session_new(const char * const recipient)
_chat_session_new(const char * const recipient, gboolean recipient_supports)
{
ChatSession new_session = malloc(sizeof(struct chat_session_t));
new_session->recipient = strdup(recipient);
new_session->state = ACTIVE;
new_session->sent = FALSE;
new_session->recipient_supports = recipient_supports;
return new_session;
}

View File

@ -1,8 +1,8 @@
/*
/*
* chat_session.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
@ -27,21 +27,11 @@
typedef struct chat_session_t *ChatSession;
typedef enum {
ACTIVE,
INACTIVE,
GONE,
COMPOSING,
PAUSED,
SESSION_ERR
} chat_state_t;
void chat_session_init(void);
void chat_session_start(const char * const recipient);
void chat_sessions_init(void);
void chat_sessions_clear(void);
void chat_session_start(const char * const recipient,
gboolean recipient_supports);
void chat_session_end(const char * const recipient);
chat_state_t chat_session_get_state(const char * const recipient);
void chat_session_set_state(const char * const recipient, chat_state_t state);
gboolean chat_session_get_sent(const char * const recipient);
void chat_session_sent(const char * const recipient);
gboolean chat_session_recipient_supports(const char * const recipient);
#endif

View File

@ -82,6 +82,7 @@ static gboolean _cmd_prefs(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_who(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_connect(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_disconnect(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_sub(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_msg(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_tiny(const char * const inp, struct cmd_help_t help);
static gboolean _cmd_close(const char * const inp, struct cmd_help_t help);
@ -178,6 +179,16 @@ static struct cmd_t main_commands[] =
"Example : /msg boothj5@gmail.com Hey, here's a message!",
NULL } } },
{ "/sub",
_cmd_sub,
{ "/sub user@host", "Subscribe to presence notifications of user.",
{ "/sub user@host",
"------------------",
"Send a subscription request to the user to be informed of their presence.",
"",
"Example: /sub myfriend@jabber.org",
NULL } } },
{ "/tiny",
_cmd_tiny,
{ "/tiny url", "Send url as tinyurl in current chat.",
@ -442,7 +453,7 @@ cmd_init(void)
p_autocomplete_add(who_ac, (gchar *)strdup(pcmd->cmd+1));
}
p_autocomplete_add(who_ac, "offline");
p_autocomplete_add(who_ac, strdup("offline"));
history_init();
}
@ -691,6 +702,32 @@ _cmd_connect(const char * const inp, struct cmd_help_t help)
return result;
}
static gboolean
_cmd_sub(const char * const inp, struct cmd_help_t help)
{
gboolean result = FALSE;
jabber_conn_status_t conn_status = jabber_get_connection_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are currently not connected.");
result = TRUE;
} else if (strlen(inp) < 6) {
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);
jabber_subscribe(lower);
cons_show("Sent subscription request to %s.", user);
result = TRUE;
}
return result;
}
static gboolean
_cmd_disconnect(const char * const inp, struct cmd_help_t help)
{
@ -788,16 +825,16 @@ _cmd_who(const char * const inp, struct cmd_help_t help)
// get show
strtok(inp_cpy, " ");
char *show = strtok(NULL, " ");
char *presence = strtok(NULL, " ");
// bad arg
if ((show != NULL)
&& (strcmp(show, "online") != 0)
&& (strcmp(show, "offline") != 0)
&& (strcmp(show, "away") != 0)
&& (strcmp(show, "chat") != 0)
&& (strcmp(show, "xa") != 0)
&& (strcmp(show, "dnd") != 0)) {
if ((presence != NULL)
&& (strcmp(presence, "online") != 0)
&& (strcmp(presence, "offline") != 0)
&& (strcmp(presence, "away") != 0)
&& (strcmp(presence, "chat") != 0)
&& (strcmp(presence, "xa") != 0)
&& (strcmp(presence, "dnd") != 0)) {
cons_show("Usage: %s", help.usage);
// valid arg
@ -805,23 +842,23 @@ _cmd_who(const char * const inp, struct cmd_help_t help)
GSList *list = get_contact_list();
// no arg, show all contacts
if (show == NULL) {
if (presence == NULL) {
cons_show("All contacts:");
cons_show_contacts(list);
// online, show all status that indicate online
} else if (strcmp("online", show) == 0) {
cons_show("Contacts (%s):", show);
} else if (strcmp("online", presence) == 0) {
cons_show("Contacts (%s):", presence);
GSList *filtered = NULL;
while (list != NULL) {
PContact contact = list->data;
const char * const contact_show = (p_contact_show(contact));
if ((strcmp(contact_show, "online") == 0)
|| (strcmp(contact_show, "away") == 0)
|| (strcmp(contact_show, "dnd") == 0)
|| (strcmp(contact_show, "xa") == 0)
|| (strcmp(contact_show, "chat") == 0)) {
const char * const contact_presence = (p_contact_presence(contact));
if ((strcmp(contact_presence, "online") == 0)
|| (strcmp(contact_presence, "away") == 0)
|| (strcmp(contact_presence, "dnd") == 0)
|| (strcmp(contact_presence, "xa") == 0)
|| (strcmp(contact_presence, "chat") == 0)) {
filtered = g_slist_append(filtered, contact);
}
list = g_slist_next(list);
@ -831,12 +868,12 @@ _cmd_who(const char * const inp, struct cmd_help_t help)
// show specific status
} else {
cons_show("Contacts (%s):", show);
cons_show("Contacts (%s):", presence);
GSList *filtered = NULL;
while (list != NULL) {
PContact contact = list->data;
if (strcmp(p_contact_show(contact), show) == 0) {
if (strcmp(p_contact_presence(contact), presence) == 0) {
filtered = g_slist_append(filtered, contact);
}
list = g_slist_next(list);

View File

@ -28,28 +28,42 @@
#include "contact.h"
struct p_contact_t {
char *jid;
char *name;
char *show;
char *presence;
char *status;
char *subscription;
};
PContact
p_contact_new(const char * const name, const char * const show,
const char * const status)
p_contact_new(const char * const jid, const char * const name,
const char * const presence, const char * const status,
const char * const subscription)
{
PContact contact = malloc(sizeof(struct p_contact_t));
contact->name = strdup(name);
contact->jid = strdup(jid);
if (show == NULL || (strcmp(show, "") == 0))
contact->show = strdup("online");
if (name != NULL) {
contact->name = strdup(name);
} else {
contact->name = NULL;
}
if (presence == NULL || (strcmp(presence, "") == 0))
contact->presence = strdup("online");
else
contact->show = strdup(show);
contact->presence = strdup(presence);
if (status != NULL)
contact->status = strdup(status);
else
contact->status = NULL;
if (subscription != NULL)
contact->subscription = strdup(subscription);
else
contact->subscription = NULL;
return contact;
}
@ -57,35 +71,67 @@ PContact
p_contact_copy(PContact contact)
{
PContact copy = malloc(sizeof(struct p_contact_t));
copy->name = strdup(contact->name);
copy->show = strdup(contact->show);
copy->jid = strdup(contact->jid);
if (contact->name != NULL) {
copy->name = strdup(contact->name);
} else {
copy->name = NULL;
}
copy->presence = strdup(contact->presence);
if (contact->status != NULL)
copy->status = strdup(contact->status);
else
copy->status = NULL;
if (contact->subscription != NULL)
copy->subscription = strdup(contact->subscription);
else
copy->subscription = NULL;
return copy;
}
void
p_contact_free(PContact contact)
{
free(contact->name);
if (contact->show != NULL) {
free(contact->show);
contact->show = NULL;
if (contact->jid != NULL) {
free(contact->jid);
contact->jid = NULL;
}
if (contact->name != NULL) {
free(contact->name);
contact->name = NULL;
}
if (contact->presence != NULL) {
free(contact->presence);
contact->presence = NULL;
}
if (contact->status != NULL) {
free(contact->status);
contact->status = NULL;
}
if (contact->subscription != NULL) {
free(contact->subscription);
contact->subscription = NULL;
}
free(contact);
contact = NULL;
}
const char *
p_contact_jid(const PContact contact)
{
return contact->jid;
}
const char *
p_contact_name(const PContact contact)
{
@ -93,9 +139,9 @@ p_contact_name(const PContact contact)
}
const char *
p_contact_show(const PContact contact)
p_contact_presence(const PContact contact)
{
return contact->show;
return contact->presence;
}
const char *
@ -104,12 +150,50 @@ p_contact_status(const PContact contact)
return contact->status;
}
const char *
p_contact_subscription(const PContact contact)
{
return contact->subscription;
}
void
p_contact_set_presence(const PContact contact, const char * const presence)
{
if (contact->presence != NULL) {
free(contact->presence);
contact->presence = NULL;
}
if (presence == NULL) {
contact->presence = NULL;
} else {
contact->presence = strdup(presence);
}
}
void
p_contact_set_status(const PContact contact, const char * const status)
{
if (contact->status != NULL) {
free(contact->status);
contact->status = NULL;
}
if (status == NULL) {
contact->status = NULL;
} else {
contact->status = strdup(status);
}
}
int
p_contacts_equal_deep(const PContact c1, const PContact c2)
{
int jid_eq = (g_strcmp0(c1->jid, c2->jid) == 0);
int name_eq = (g_strcmp0(c1->name, c2->name) == 0);
int show_eq = (g_strcmp0(c1->show, c2->show) == 0);
int presence_eq = (g_strcmp0(c1->presence, c2->presence) == 0);
int status_eq = (g_strcmp0(c1->status, c2->status) == 0);
int subscription_eq = (g_strcmp0(c1->subscription, c2->subscription) == 0);
return (name_eq && show_eq && status_eq);
return (jid_eq && name_eq && presence_eq && status_eq && subscription_eq);
}

View File

@ -25,13 +25,18 @@
typedef struct p_contact_t *PContact;
PContact p_contact_new(const char * const name, const char * const show,
const char * const status);
PContact p_contact_new(const char * const jid, const char * const name,
const char * const presence, const char * const status,
const char * const subscription);
PContact p_contact_copy(PContact contact);
void p_contact_free(PContact contact);
const char * p_contact_jid(PContact contact);
const char * p_contact_name(PContact contact);
const char * p_contact_show(PContact contact);
const char * p_contact_presence(PContact contact);
const char * p_contact_status(PContact contact);
const char * p_contact_subscription(const PContact contact);
void p_contact_set_presence(const PContact contact, const char * const presence);
void p_contact_set_status(const PContact contact, const char * const status);
int p_contacts_equal_deep(const PContact c1, const PContact c2);
#endif

View File

@ -22,24 +22,30 @@
#include <string.h>
#include <glib.h>
#include "contact.h"
#include "log.h"
#include "prof_autocomplete.h"
static PAutocomplete ac;
static GHashTable *contacts;
static gboolean _key_equals(void *key1, void *key2);
void
contact_list_init(void)
{
ac = p_obj_autocomplete_new((PStrFunc)p_contact_name,
(PCopyFunc)p_contact_copy,
(PEqualDeepFunc)p_contacts_equal_deep,
(GDestroyNotify)p_contact_free);
ac = p_autocomplete_new();
contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free,
(GDestroyNotify)p_contact_free);
}
void
contact_list_clear(void)
{
p_autocomplete_clear(ac);
g_hash_table_remove_all(contacts);
}
void
@ -49,22 +55,63 @@ contact_list_reset_search_attempts(void)
}
gboolean
contact_list_remove(const char * const name)
contact_list_add(const char * const jid, const char * const name,
const char * const presence, const char * const status,
const char * const subscription)
{
return p_autocomplete_remove(ac, name);
gboolean added = FALSE;
PContact contact = g_hash_table_lookup(contacts, jid);
if (contact == NULL) {
contact = p_contact_new(jid, name, presence, status, subscription);
g_hash_table_insert(contacts, strdup(jid), contact);
p_autocomplete_add(ac, strdup(jid));
added = TRUE;
}
return added;
}
gboolean
contact_list_add(const char * const name, const char * const show,
contact_list_update_contact(const char * const jid, const char * const presence,
const char * const status)
{
return p_autocomplete_add(ac, p_contact_new(name, show, status));
gboolean changed = FALSE;
PContact contact = g_hash_table_lookup(contacts, jid);
if (contact == NULL) {
log_warning("Contact not in list: %s", jid);
return FALSE;
}
if (g_strcmp0(p_contact_presence(contact), presence) != 0) {
p_contact_set_presence(contact, presence);
changed = TRUE;
}
if (g_strcmp0(p_contact_status(contact), status) != 0) {
p_contact_set_status(contact, status);
changed = TRUE;
}
return changed;
}
GSList *
get_contact_list(void)
{
return p_autocomplete_get_list(ac);
GSList *result = NULL;
GHashTableIter iter;
gpointer key;
gpointer value;
g_hash_table_iter_init(&iter, contacts);
while (g_hash_table_iter_next(&iter, &key, &value)) {
result = g_slist_append(result, value);
}
// resturn all contact structs
return result;
}
char *
@ -76,15 +123,14 @@ contact_list_find_contact(char *search_str)
PContact
contact_list_get_contact(const char const *jid)
{
GSList *contacts = get_contact_list();
while (contacts != NULL) {
PContact contact = contacts->data;
if (strcmp(p_contact_name(contact), jid) == 0) {
return contact;
}
contacts = g_slist_next(contacts);
}
return NULL;
return g_hash_table_lookup(contacts, jid);
}
static
gboolean _key_equals(void *key1, void *key2)
{
gchar *str1 = (gchar *) key1;
gchar *str2 = (gchar *) key2;
return (g_strcmp0(str1, str2) == 0);
}

View File

@ -30,9 +30,11 @@
void contact_list_init(void);
void contact_list_clear(void);
void contact_list_reset_search_attempts(void);
gboolean contact_list_add(const char * const name, const char * const show,
gboolean contact_list_add(const char * const jid, const char * const name,
const char * const presence, const char * const status,
const char * const subscription);
gboolean contact_list_update_contact(const char * const jid, const char * const presence,
const char * const status);
gboolean contact_list_remove(const char * const name);
GSList * get_contact_list(void);
char * contact_list_find_contact(char *search_str);
PContact contact_list_get_contact(const char const *jid);

View File

@ -25,7 +25,9 @@
#include <strophe.h>
#include "chat_session.h"
#include "common.h"
#include "contact_list.h"
#include "jabber.h"
#include "log.h"
#include "preferences.h"
@ -49,6 +51,8 @@ static void _xmpp_file_logger(void * const userdata,
const char * const msg);
static xmpp_log_t * _xmpp_get_file_logger();
static void _jabber_roster_request(void);
// XMPP event handlers
static void _connection_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status, const int error,
@ -165,23 +169,16 @@ jabber_send(const char * const msg, const char * const recipient)
}
void
jabber_roster_request(void)
jabber_subscribe(const char * const recipient)
{
xmpp_stanza_t *iq, *query;
xmpp_stanza_t *presence;
iq = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster");
query = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_ROSTER);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_send(jabber_conn.conn, iq);
xmpp_stanza_release(iq);
presence = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(presence, "presence");
xmpp_stanza_set_type(presence, "subscribe");
xmpp_stanza_set_attribute(presence, "to", recipient);
xmpp_send(jabber_conn.conn, presence);
xmpp_stanza_release(presence);
}
void
@ -248,11 +245,32 @@ jabber_get_jid(void)
void
jabber_free_resources(void)
{
chat_sessions_clear();
xmpp_conn_release(jabber_conn.conn);
xmpp_ctx_free(jabber_conn.ctx);
xmpp_shutdown();
}
static void
_jabber_roster_request(void)
{
xmpp_stanza_t *iq, *query;
iq = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster");
query = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_ROSTER);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_send(jabber_conn.conn, iq);
xmpp_stanza_release(iq);
}
static int
_message_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata)
@ -319,21 +337,16 @@ _connection_handler(xmpp_conn_t * const conn,
if (status == XMPP_CONN_CONNECT) {
const char *jid = xmpp_conn_get_jid(conn);
prof_handle_login_success(jid);
chat_sessions_init();
xmpp_stanza_t* pres;
xmpp_handler_add(conn, _message_handler, NULL, "message", NULL, ctx);
xmpp_handler_add(conn, _presence_handler, NULL, "presence", NULL, ctx);
xmpp_id_handler_add(conn, _roster_handler, "roster", ctx);
xmpp_timed_handler_add(conn, _ping_timed_handler, PING_INTERVAL, ctx);
pres = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pres, "presence");
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
_jabber_roster_request();
jabber_conn.conn_status = JABBER_CONNECTED;
jabber_conn.presence = PRESENCE_ONLINE;
jabber_roster_request();
} else {
// received close stream response from server after disconnect
@ -362,6 +375,7 @@ static int
_roster_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *query, *item;
char *type = xmpp_stanza_get_type(stanza);
@ -369,27 +383,25 @@ _roster_handler(xmpp_conn_t * const conn,
log_error("Roster query failed");
else {
query = xmpp_stanza_get_child_by_name(stanza, "query");
GSList *roster = NULL;
item = xmpp_stanza_get_children(query);
while (item != NULL) {
const char *name = xmpp_stanza_get_attribute(item, "name");
const char *jid = xmpp_stanza_get_attribute(item, "jid");
const char *name = xmpp_stanza_get_attribute(item, "name");
const char *sub = xmpp_stanza_get_attribute(item, "subscription");
gboolean added = contact_list_add(jid, name, "offline", NULL, sub);
jabber_roster_entry *entry = malloc(sizeof(jabber_roster_entry));
if (name != NULL) {
entry->name = strdup(name);
} else {
entry->name = NULL;
if (!added) {
log_warning("Attempt to add contact twice: %s", jid);
}
entry->jid = strdup(jid);
roster = g_slist_append(roster, entry);
item = xmpp_stanza_get_next(item);
}
prof_handle_roster(roster);
xmpp_stanza_t* pres;
pres = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pres, "presence");
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
}
return 1;
@ -434,26 +446,28 @@ _presence_handler(xmpp_conn_t * const conn,
char *from = xmpp_stanza_get_attribute(stanza, "from");
char *short_from = strtok(from, "/");
char *type = xmpp_stanza_get_attribute(stanza, "type");
char *show_str, *status_str;
xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, "show");
if (show != NULL)
show_str = xmpp_stanza_get_text(show);
else
show_str = NULL;
xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, "status");
if (status != NULL)
status_str = xmpp_stanza_get_text(status);
else
status_str = NULL;
if (strcmp(short_jid, short_from) !=0) {
if (type == NULL) {
if ((type != NULL) && (strcmp(type, "unavailable") == 0)) {
if (strcmp(short_jid, short_from) !=0) {
prof_handle_contact_offline(short_from, "offline", status_str);
}
} else {
xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, "show");
if (show != NULL)
show_str = xmpp_stanza_get_text(show);
else
show_str = "online";
if (strcmp(short_jid, short_from) !=0) {
prof_handle_contact_online(short_from, show_str, status_str);
} else {
prof_handle_contact_offline(short_from, show_str, status_str);
}
}

View File

@ -44,8 +44,8 @@ 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_roster_request(void);
void jabber_process_events(void);
void jabber_subscribe(const char * const recipient);
void jabber_send(const char * const msg, const char * const recipient);
void jabber_update_presence(jabber_presence_t status, const char * const msg);
const char * jabber_get_jid(void);

View File

@ -29,59 +29,25 @@ struct p_autocomplete_t {
GSList *items;
GSList *last_found;
gchar *search_str;
PStrFunc str_func;
PCopyFunc copy_func;
PEqualDeepFunc equal_deep_func;
GDestroyNotify free_func;
};
static gchar * _search_from(PAutocomplete ac, GSList *curr);
static const char *_str_func_default(const char *orig);
static const char *_copy_func_default(const char *orig);
static int _deep_equals_func_default(const char *o1, const char *o2);
PAutocomplete
p_autocomplete_new(void)
{
return p_obj_autocomplete_new(NULL, NULL, NULL, NULL);
}
PAutocomplete
p_obj_autocomplete_new(PStrFunc str_func, PCopyFunc copy_func,
PEqualDeepFunc equal_deep_func, GDestroyNotify free_func)
{
PAutocomplete new = malloc(sizeof(struct p_autocomplete_t));
new->items = NULL;
new->last_found = NULL;
new->search_str = NULL;
if (str_func)
new->str_func = str_func;
else
new->str_func = (PStrFunc)_str_func_default;
if (copy_func)
new->copy_func = copy_func;
else
new->copy_func = (PCopyFunc)_copy_func_default;
if (free_func)
new->free_func = free_func;
else
new->free_func = (GDestroyNotify)free;
if (equal_deep_func)
new->equal_deep_func = equal_deep_func;
else
new->equal_deep_func = (PEqualDeepFunc)_deep_equals_func_default;
return new;
}
void
p_autocomplete_clear(PAutocomplete ac)
{
g_slist_free_full(ac->items, ac->free_func);
g_slist_free_full(ac->items, free);
ac->items = NULL;
p_autocomplete_reset(ac);
@ -109,16 +75,16 @@ p_autocomplete_add(PAutocomplete ac, void *item)
while(curr) {
// insert
if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) > 0) {
if (g_strcmp0(curr->data, item) > 0) {
ac->items = g_slist_insert_before(ac->items,
curr, item);
return TRUE;
// update
} else if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) == 0) {
} else if (g_strcmp0(curr->data, item) == 0) {
// only update if data different
if (!ac->equal_deep_func(curr->data, item)) {
ac->free_func(curr->data);
if (strcmp(curr->data, item) != 0) {
free(curr->data);
curr->data = item;
return TRUE;
} else {
@ -141,7 +107,7 @@ p_autocomplete_remove(PAutocomplete ac, const char * const item)
{
// reset last found if it points to the item to be removed
if (ac->last_found != NULL)
if (g_strcmp0(ac->str_func(ac->last_found->data), item) == 0)
if (g_strcmp0(ac->last_found->data, item) == 0)
ac->last_found = NULL;
if (!ac->items) {
@ -150,10 +116,10 @@ p_autocomplete_remove(PAutocomplete ac, const char * const item)
GSList *curr = ac->items;
while(curr) {
if (g_strcmp0(ac->str_func(curr->data), item) == 0) {
if (g_strcmp0(curr->data, item) == 0) {
void *current_item = curr->data;
ac->items = g_slist_remove(ac->items, curr->data);
ac->free_func(current_item);
free(current_item);
return TRUE;
}
@ -172,7 +138,7 @@ p_autocomplete_get_list(PAutocomplete ac)
GSList *curr = ac->items;
while(curr) {
copy = g_slist_append(copy, ac->copy_func(curr->data));
copy = g_slist_append(copy, strdup(curr->data));
curr = g_slist_next(curr);
}
@ -221,17 +187,17 @@ _search_from(PAutocomplete ac, GSList *curr)
while(curr) {
// match found
if (strncmp(ac->str_func(curr->data),
if (strncmp(curr->data,
ac->search_str,
strlen(ac->search_str)) == 0) {
gchar *result =
(gchar *) malloc((strlen(ac->str_func(curr->data)) + 1) * sizeof(gchar));
(gchar *) malloc((strlen(curr->data) + 1) * sizeof(gchar));
// set pointer to last found
ac->last_found = curr;
// return the string, must be free'd by caller
strcpy(result, ac->str_func(curr->data));
strcpy(result, curr->data);
return result;
}
@ -240,21 +206,3 @@ _search_from(PAutocomplete ac, GSList *curr)
return NULL;
}
static const char *
_str_func_default(const char *orig)
{
return orig;
}
static const char *
_copy_func_default(const char *orig)
{
return strdup(orig);
}
static int
_deep_equals_func_default(const char *o1, const char *o2)
{
return (strcmp(o1, o2) == 0);
}

View File

@ -41,7 +41,6 @@
static log_level_t _get_log_level(char *log_level);
static gboolean _process_input(char *inp);
static void _create_config_directory();
static void _free_roster_entry(jabber_roster_entry *entry);
static void _init(const int disable_tls, char *log_level);
static void _shutdown(void);
@ -168,38 +167,33 @@ prof_handle_failed_login(void)
void
prof_handle_contact_online(char *contact, char *show, char *status)
{
gboolean result = contact_list_add(contact, show, status);
if (result) {
win_contact_online(contact, show, status);
gboolean updated = contact_list_update_contact(contact, show, status);
if (updated) {
PContact result = contact_list_get_contact(contact);
if (p_contact_subscription(result) != NULL) {
if (strcmp(p_contact_subscription(result), "none") != 0) {
win_contact_online(contact, show, status);
win_page_off();
}
}
}
win_page_off();
}
void
prof_handle_contact_offline(char *contact, char *show, char *status)
{
gboolean result = contact_list_add(contact, "offline", status);
if (result) {
win_contact_offline(contact, show, status);
}
win_page_off();
}
gboolean updated = contact_list_update_contact(contact, "offline", status);
void
prof_handle_roster(GSList *roster)
{
while (roster != NULL) {
jabber_roster_entry *entry = roster->data;
// if contact not in contact list add them as offline
if (contact_list_find_contact(entry->jid) == NULL) {
contact_list_add(entry->jid, "offline", NULL);
if (updated) {
PContact result = contact_list_get_contact(contact);
if (p_contact_subscription(result) != NULL) {
if (strcmp(p_contact_subscription(result), "none") != 0) {
win_contact_offline(contact, show, status);
win_page_off();
}
}
roster = g_slist_next(roster);
}
g_slist_free_full(roster, (GDestroyNotify)_free_roster_entry);
}
static void
@ -211,16 +205,6 @@ _create_config_directory(void)
g_string_free(dir, TRUE);
}
static void
_free_roster_entry(jabber_roster_entry *entry)
{
if (entry->name != NULL) {
free(entry->name);
entry->name = NULL;
}
free(entry->jid);
}
static log_level_t
_get_log_level(char *log_level)
{

View File

@ -23,11 +23,6 @@
#ifndef PROFANITY_H
#define PROFANITY_H
typedef struct roster_entry_t {
char *name;
char *jid;
} jabber_roster_entry;
void prof_run(const int disable_tls, char *log_level);
void prof_handle_login_success(const char *jid);

View File

@ -427,8 +427,8 @@ win_show_outgoing_msg(const char * const from, const char * const to,
}
if (contact != NULL) {
if (strcmp(p_contact_show(contact), "offline") == 0) {
const char const *show = p_contact_show(contact);
if (strcmp(p_contact_presence(contact), "offline") == 0) {
const char const *show = p_contact_presence(contact);
const char const *status = p_contact_status(contact);
_show_status_string(win, to, show, status, "--", "offline");
}
@ -703,44 +703,56 @@ cons_show_contacts(GSList *list)
while(curr) {
PContact contact = curr->data;
const char *show = p_contact_show(contact);
const char *jid = p_contact_jid(contact);
const char *name = p_contact_name(contact);
const char *presence = p_contact_presence(contact);
const char *status = p_contact_status(contact);
const char *sub = p_contact_subscription(contact);
_win_show_time(_cons_win);
if (strcmp(sub, "none") != 0) {
_win_show_time(_cons_win);
if (strcmp(show, "online") == 0) {
wattron(_cons_win, COLOUR_ONLINE);
} else if (strcmp(show, "away") == 0) {
wattron(_cons_win, COLOUR_AWAY);
} else if (strcmp(show, "chat") == 0) {
wattron(_cons_win, COLOUR_CHAT);
} else if (strcmp(show, "dnd") == 0) {
wattron(_cons_win, COLOUR_DND);
} else if (strcmp(show, "xa") == 0) {
wattron(_cons_win, COLOUR_XA);
} else {
wattron(_cons_win, COLOUR_OFFLINE);
}
if (strcmp(presence, "online") == 0) {
wattron(_cons_win, COLOUR_ONLINE);
} else if (strcmp(presence, "away") == 0) {
wattron(_cons_win, COLOUR_AWAY);
} else if (strcmp(presence, "chat") == 0) {
wattron(_cons_win, COLOUR_CHAT);
} else if (strcmp(presence, "dnd") == 0) {
wattron(_cons_win, COLOUR_DND);
} else if (strcmp(presence, "xa") == 0) {
wattron(_cons_win, COLOUR_XA);
} else {
wattron(_cons_win, COLOUR_OFFLINE);
}
wprintw(_cons_win, "%s", p_contact_name(contact));
wprintw(_cons_win, " is %s", show);
wprintw(_cons_win, "%s", jid);
if (p_contact_status(contact))
wprintw(_cons_win, ", \"%s\"", p_contact_status(contact));
if (name != NULL) {
wprintw(_cons_win, " (%s)", name);
}
wprintw(_cons_win, "\n");
wprintw(_cons_win, " is %s", presence);
if (strcmp(show, "online") == 0) {
wattroff(_cons_win, COLOUR_ONLINE);
} else if (strcmp(show, "away") == 0) {
wattroff(_cons_win, COLOUR_AWAY);
} else if (strcmp(show, "chat") == 0) {
wattroff(_cons_win, COLOUR_CHAT);
} else if (strcmp(show, "dnd") == 0) {
wattroff(_cons_win, COLOUR_DND);
} else if (strcmp(show, "xa") == 0) {
wattroff(_cons_win, COLOUR_XA);
} else {
wattroff(_cons_win, COLOUR_OFFLINE);
if (status != NULL) {
wprintw(_cons_win, ", \"%s\"", p_contact_status(contact));
}
wprintw(_cons_win, "\n");
if (strcmp(presence, "online") == 0) {
wattroff(_cons_win, COLOUR_ONLINE);
} else if (strcmp(presence, "away") == 0) {
wattroff(_cons_win, COLOUR_AWAY);
} else if (strcmp(presence, "chat") == 0) {
wattroff(_cons_win, COLOUR_CHAT);
} else if (strcmp(presence, "dnd") == 0) {
wattroff(_cons_win, COLOUR_DND);
} else if (strcmp(presence, "xa") == 0) {
wattroff(_cons_win, COLOUR_XA);
} else {
wattroff(_cons_win, COLOUR_OFFLINE);
}
}
curr = g_slist_next(curr);

View File

@ -31,24 +31,24 @@ static void empty_list_when_none_added(void)
static void contains_one_element(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
assert_int_equals(1, g_slist_length(list));
}
static void first_element_correct(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
PContact james = list->data;
assert_string_equals("James", p_contact_name(james));
assert_string_equals("James", p_contact_jid(james));
}
static void contains_two_elements(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("Dave", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
contact_list_add("Dave", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
assert_int_equals(2, g_slist_length(list));
@ -56,22 +56,22 @@ static void contains_two_elements(void)
static void first_and_second_elements_correct(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("Dave", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
contact_list_add("Dave", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
PContact dave = list->data;
PContact james = (g_slist_next(list))->data;
PContact first = list->data;
PContact second = (g_slist_next(list))->data;
assert_string_equals("James", p_contact_name(james));
assert_string_equals("Dave", p_contact_name(dave));
assert_string_equals("James", p_contact_jid(first));
assert_string_equals("Dave", p_contact_jid(second));
}
static void contains_three_elements(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("Bob", NULL, NULL);
contact_list_add("Dave", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
contact_list_add("Bob", NULL, NULL, NULL, NULL);
contact_list_add("Dave", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
assert_int_equals(3, g_slist_length(list));
@ -79,194 +79,100 @@ static void contains_three_elements(void)
static void first_three_elements_correct(void)
{
contact_list_add("Bob", NULL, NULL);
contact_list_add("Dave", NULL, NULL);
contact_list_add("James", NULL, NULL);
contact_list_add("Bob", NULL, NULL, NULL, NULL);
contact_list_add("Dave", NULL, NULL, NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);
GSList *list = get_contact_list();
PContact bob = list->data;
PContact dave = (g_slist_next(list))->data;
PContact james = (g_slist_next(g_slist_next(list)))->data;
assert_string_equals("James", p_contact_name(james));
assert_string_equals("Dave", p_contact_name(dave));
assert_string_equals("Bob", p_contact_name(bob));
assert_string_equals("James", p_contact_jid(james));
assert_string_equals("Dave", p_contact_jid(dave));
assert_string_equals("Bob", p_contact_jid(bob));
}
static void add_twice_at_beginning_adds_once(void)
{
contact_list_add("James", NULL, NULL);
contact_list_add("James", NULL, NULL);
contact_list_add("Dave", NULL, NULL);
contact_list_add("Bob", NULL, NULL);
contact_list_add("James", NULL, NULL, NULL, NULL);