grim/purple-spasm

Basic chat support is working
draft
14 months ago, Gary Kramlich
a1e6bcaf27c3
Parents 78292b8a66a6
Children 7388a4c9a1b3
Basic chat support is working
--- a/src/spasm-account.c Sun Apr 19 06:50:19 2020 -0500
+++ b/src/spasm-account.c Sun Apr 19 13:55:45 2020 -0500
@@ -219,7 +219,6 @@
account = spasm_account_get_account(sa);
connection = purple_account_get_connection(account);
-
username = purple_account_get_username(account);
state = g_strdup_printf("%s,%s", SPASM_PLUGIN_ID, username);
@@ -389,3 +388,10 @@
}
}
+SpasmChatService *
+spasm_account_get_chat_service(SpasmAccount *sa) {
+ g_return_val_if_fail(sa != NULL, NULL);
+
+ return sa->chat;
+}
+
--- a/src/spasm-account.h Sun Apr 19 06:50:19 2020 -0500
+++ b/src/spasm-account.h Sun Apr 19 13:55:45 2020 -0500
@@ -61,6 +61,8 @@
gboolean spasm_account_get_partnered(const SpasmAccount *sa);
gboolean spasm_account_get_twitter_connected(const SpasmAccount *sa);
+SpasmChatService *spasm_account_get_chat_service(SpasmAccount *sa);
+
G_END_DECLS
#endif /* SPASM_ACCOUNT_H */
--- a/src/spasm-chat.c Sun Apr 19 06:50:19 2020 -0500
+++ b/src/spasm-chat.c Sun Apr 19 13:55:45 2020 -0500
@@ -36,8 +36,95 @@
GSocketConnection *socket_connection;
GOutputStream *output_stream;
GDataInputStream *input_stream;
+
+ GHashTable *handlers;
+ gint id; /* used to track ids for this service */
};
+typedef struct {
+ gchar *name;
+ gint n_args;
+ void (*callback)(SpasmChatService *sa, const gchar *from, gchar **args);
+} SpasmChatMessageHandler;
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static gchar *
+spasm_chat_service_nick_from_mask(const gchar *mask) {
+ gchar *nick = NULL, *bang = NULL;
+
+ bang = strchr(mask, '!');
+ if(bang == NULL) {
+ nick = g_strdup(mask);
+ } else {
+ nick = g_strndup(mask, bang - mask); /* eww pointer math... */
+ }
+
+ return nick;
+}
+
+/******************************************************************************
+ * Handlers
+ *****************************************************************************/
+static void
+spasm_chat_service_handle_join(SpasmChatService *chat, const gchar *from,
+ gchar **args)
+{
+ PurpleConnection *connection = NULL;
+ const gchar *name = args[0] + 1; /* we want to ignore the leading # */
+
+ connection = spasm_account_get_connection(chat->sa);
+ serv_got_joined_chat(connection, chat->id++, name);
+}
+
+static void
+spasm_chat_service_handle_privmsg(SpasmChatService *chat, const gchar *from,
+ gchar **args)
+{
+ PurpleAccount *account = NULL;
+ PurpleConversation *conversation = NULL;
+ gchar *nick = spasm_chat_service_nick_from_mask(from);
+ gint id = 0;
+
+ account = spasm_account_get_account(chat->sa);
+ conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
+ args[0] + 1, account);
+ if(conversation != NULL) {
+ id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conversation));
+ serv_got_chat_in(spasm_account_get_connection(chat->sa), id, nick, 0,
+ args[1] + 1, time(NULL));
+ }
+
+ g_free(nick);
+}
+
+static GHashTable *
+spasm_chat_service_init_handlers(void) {
+ static SpasmChatMessageHandler handlers[] = {
+ { "001", 0, NULL }, /* ignore RPL_WELCOME */
+ { "002", 0, NULL }, /* ignore RPL_YOURHOST */
+ { "003", 0, NULL }, /* ignore RPL_CREATED */
+ { "004", 0, NULL }, /* ignore RPL_MYINFO */
+ { "353", 0, NULL }, /* ignore RPL_NAMREPLY */
+ { "366", 0, NULL }, /* ignore RPL_ENDOFNAMES */
+ { "372", 0, NULL }, /* ignore RPL_MOTD */
+ { "375", 0, NULL }, /* ignore RPL_MOTDSTART */
+ { "376", 0, NULL }, /* ignore RPL_ENDOFMOTD */
+ { "JOIN", 1, spasm_chat_service_handle_join },
+ { "PRIVMSG", 2, spasm_chat_service_handle_privmsg },
+ };
+ GHashTable *ret = NULL;
+ gint i;
+
+ ret = g_hash_table_new(g_str_hash, g_str_equal);
+ for(i = 0; i < G_N_ELEMENTS(handlers); i++) {
+ g_hash_table_insert(ret, handlers[i].name, &handlers[i]);
+ }
+
+ return ret;
+}
+
/******************************************************************************
* sending
*****************************************************************************/
@@ -57,6 +144,8 @@
buffer = g_strdup_vprintf(format, vargs);
va_end(vargs);
+ purple_debug_info("spasm-chat", "send buffer: %s\n", buffer);
+
success = g_output_stream_printf(
chat->output_stream,
NULL,
@@ -90,11 +179,56 @@
spasm_chat_service_parse(SpasmChatService *chat,
const gchar *buffer)
{
+ SpasmChatMessageHandler *handler = NULL;
+ gchar **parts = NULL;
+
+ g_return_if_fail(buffer != NULL);
+
+ /* special case message parsing */
if(purple_str_has_prefix(buffer, "PING ")) {
- purple_debug_misc("spasm", "PING? PONG!\n");
+ purple_debug_misc("spasm-chat", "PING? PONG!\n");
spasm_chat_service_real_send(chat, "PONG %s\r\n", buffer + 5);
+
+ return;
}
+
+ /* handle basic message parsing */
+ if(buffer[0] != ':') {
+ purple_debug_warning("spasm", "failed to parse message \"%s\"\n",
+ buffer);
+
+ return;
+ }
+
+ parts = g_strsplit(buffer, " ", 3);
+
+ /* look up the command handler */
+ handler = g_hash_table_lookup(chat->handlers, parts[1]);
+ if(handler == NULL) {
+ purple_debug_misc("spasm-chat", "unknown message type %s\n", parts[1]);
+
+ purple_debug_misc("spasm-chat", "from: %s\n", parts[0]);
+ purple_debug_misc("spasm-chat", "command: %s\n", parts[1]);
+ purple_debug_misc("spasm-chat", "args: %s\n", parts[2]);
+ purple_debug_misc("spasm-chat", "-----\n");
+ } else {
+ if(handler->callback != NULL) {
+ gchar **args = g_strsplit(g_strstrip(parts[2]), " ",
+ handler->n_args);
+ gchar *from = parts[0];
+
+ if(from && *from == ':') {
+ from++; /* increment past the : */
+ }
+
+ handler->callback(chat, from, args);
+
+ g_strfreev(args);
+ }
+ }
+
+ g_strfreev(parts);
}
static void spasm_chat_read(SpasmChatService *chat);
@@ -137,8 +271,6 @@
return;
}
- purple_debug_info("spasm", "chat buffer: %s\n", buffer);
-
spasm_chat_service_parse(chat, buffer);
g_free(buffer);
@@ -219,7 +351,9 @@
g_return_val_if_fail(sa, NULL);
chat = g_slice_new0(SpasmChatService);
+
chat->sa = sa;
+ chat->handlers = spasm_chat_service_init_handlers();
return chat;
}
@@ -252,8 +386,17 @@
);
}
-GList *_spasm_chat_service_info(PurpleConnection *connection) {
- return NULL;
+GList *
+spasm_chat_service_info(PurpleConnection *connection) {
+ GList *entries = NULL;
+ struct proto_chat_entry *pce = NULL;
+
+ pce = g_new0(struct proto_chat_entry, 1);
+ pce->label = _("Channel");
+ pce->identifier = "channel";
+ entries = g_list_append(entries, pce);
+
+ return entries;
}
GHashTable *
@@ -278,7 +421,16 @@
spasm_chat_service_join(PurpleConnection *connection,
GHashTable *components)
{
+ SpasmAccount *sa = NULL;
+ SpasmChatService *chat = NULL;
+ const gchar *channel = NULL;
+ channel = g_hash_table_lookup(components, "channel");
+
+ sa = purple_connection_get_protocol_data(connection);
+ chat = spasm_account_get_chat_service(sa);
+
+ spasm_chat_service_real_send(chat, "JOIN #%s\r\n", channel);
}
gchar *
@@ -297,7 +449,24 @@
const gchar *message,
PurpleMessageFlags flags)
{
- return -1;
+ SpasmAccount *sa = NULL;
+ SpasmChatService *chat = NULL;
+ PurpleConversation *conversation = purple_find_chat(connection, id);
+
+ if(conversation == NULL) {
+ return -1;
+ }
+
+ sa = purple_connection_get_protocol_data(connection);
+ chat = spasm_account_get_chat_service(sa);
+ spasm_chat_service_real_send(chat, "PRIVMSG #%s :%s\r\n",
+ purple_conversation_get_name(conversation),
+ message);
+
+ serv_got_chat_in(connection, id, spasm_account_get_display_name(sa), flags,
+ message, time(NULL));
+
+ return 0;
}
void
--- a/src/spasm-plugin.c Sun Apr 19 06:50:19 2020 -0500
+++ b/src/spasm-plugin.c Sun Apr 19 13:55:45 2020 -0500
@@ -78,7 +78,6 @@
.status_types = spasm_status_types,
// chat stuff
-#if 0
.chat_info = spasm_chat_service_info,
.chat_info_defaults = spasm_chat_service_info_default,
.join_chat = spasm_chat_service_join,
@@ -86,7 +85,6 @@
.chat_leave = spasm_chat_service_leave,
.chat_send = spasm_chat_service_send,
.set_chat_topic = spasm_chat_service_set_topic,
-#endif
};
static PurplePluginInfo info = {