--- a/src/spasm-chat.c Sun Apr 19 13:55:45 2020 -0500
+++ b/src/spasm-chat.c Sun Apr 19 17:22:00 2020 -0500
@@ -39,17 +39,32 @@
gint id; /* used to track ids for this service */
- void (*callback)(SpasmChatService *sa, const gchar *from, gchar **args);
-} SpasmChatMessageHandler;
+typedef void (*SpasmChatMessageHandler)(SpasmChatService *sa, + const gchar *trailing); /******************************************************************************
*****************************************************************************/
+spasm_chat_service_regex_init(SpasmChatService *chat) { + chat->regex_message = g_regex_new("(?::(?<prefix>[^ ]+) +)?" + "(?:(?: +(?<middle>[^ :]+)))*" + "(?<coda> +:(?<trailing>.*)?)?", + g_assert(chat->regex_message != NULL); + chat->regex_target = g_regex_new("(?:#(?<target>[^\\s]+))", 0, 0, NULL); + g_assert(chat->regex_target != NULL); spasm_chat_service_nick_from_mask(const gchar *mask) {
gchar *nick = NULL, *bang = NULL;
@@ -65,68 +80,7 @@
/******************************************************************************
- *****************************************************************************/
-spasm_chat_service_handle_join(SpasmChatService *chat, const gchar *from,
- 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);
-spasm_chat_service_handle_privmsg(SpasmChatService *chat, const gchar *from,
- PurpleAccount *account = NULL;
- PurpleConversation *conversation = NULL;
- gchar *nick = spasm_chat_service_nick_from_mask(from);
- account = spasm_account_get_account(chat->sa);
- conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
- 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));
-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;
- 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]);
-/******************************************************************************
*****************************************************************************/
spasm_chat_service_real_send(SpasmChatService *chat,
@@ -151,6 +105,7 @@
@@ -173,62 +128,148 @@
/******************************************************************************
+ *****************************************************************************/ +spasm_chat_service_handle_ping(SpasmChatService *chat, const gchar *prefix, + const gchar *middle, const gchar *trailing) + spasm_chat_service_real_send(chat, "PONG :%s", trailing); +spasm_chat_service_handle_join(SpasmChatService *chat, const gchar *prefix, + const gchar *middle, const gchar *trailing) + GMatchInfo *info = NULL; + if(g_regex_match(chat->regex_target, middle, 0, &info)) { + gchar *target = g_match_info_fetch_named(info, "target"); + PurpleConnection *connection = NULL; + connection = spasm_account_get_connection(chat->sa); + serv_got_joined_chat(connection, chat->id++, target); + g_match_info_unref(info); +spasm_chat_service_handle_privmsg(SpasmChatService *chat, const gchar *prefix, + const gchar *middle, const gchar *trailing) + GMatchInfo *info = NULL; + if(g_regex_match(chat->regex_target, middle, 0, &info)) { + PurpleAccount *account = NULL; + PurpleConversation *conversation = NULL; + gchar *target = NULL, *nick = NULL; + target = g_match_info_fetch_named(info, "target"); + nick = spasm_chat_service_nick_from_mask(prefix); + account = spasm_account_get_account(chat->sa); + purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, + if(conversation != NULL) { + gint id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conversation)); + serv_got_chat_in(spasm_account_get_connection(chat->sa), id, + nick, 0, trailing, time(NULL)); + purple_debug_misc("spasm-chat", + "failed to to find a target in \"%s\"\n", middle); + g_match_info_unref(info); +spasm_chat_service_init_handlers(void) { + GHashTable *handlers = NULL; + handlers = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(handlers, "001", NULL); /* Ignore RPL_WELCOME */ + g_hash_table_insert(handlers, "002", NULL); /* Ignore RPL_YOURHOST */ + g_hash_table_insert(handlers, "003", NULL); /* Ignore RPL_CREATED */ + g_hash_table_insert(handlers, "004", NULL); /* Ignore RPL_MYINFO */ + g_hash_table_insert(handlers, "353", NULL); /* Ignore RPL_NAMREPLY */ + g_hash_table_insert(handlers, "366", NULL); /* Ignore RPL_ENDOFNAMES */ + g_hash_table_insert(handlers, "372", NULL); /* Ignore RPL_MOTD */ + g_hash_table_insert(handlers, "375", NULL); /* Ignore RPL_MOTDSTART */ + g_hash_table_insert(handlers, "376", NULL); /* Ignore RPL_ENDOFMOTD */ + g_hash_table_insert(handlers, "JOIN", spasm_chat_service_handle_join); + g_hash_table_insert(handlers, "PING", spasm_chat_service_handle_ping); + g_hash_table_insert(handlers, "PRIVMSG", + spasm_chat_service_handle_privmsg); +/****************************************************************************** *****************************************************************************/
spasm_chat_service_parse(SpasmChatService *chat,
- SpasmChatMessageHandler *handler = NULL;
+ GMatchInfo *info = NULL; + gchar *prefix = NULL, *command = NULL, *middle = NULL, *trailing = NULL; + gboolean matches = FALSE; g_return_if_fail(buffer != NULL);
- /* special case message parsing */
- if(purple_str_has_prefix(buffer, "PING ")) {
- purple_debug_misc("spasm-chat", "PING? PONG!\n");
- spasm_chat_service_real_send(chat, "PONG %s\r\n", buffer + 5);
+ matches = g_regex_match(chat->regex_message, buffer, 0, &info); + purple_debug_misc("spasm-chat", "failed to parse \"%s\"\n", buffer);
- /* handle basic message parsing */
- purple_debug_warning("spasm", "failed to parse message \"%s\"\n",
+ g_match_info_unref(info); - parts = g_strsplit(buffer, " ", 3);
+ prefix = g_match_info_fetch_named(info, "prefix"); + command = g_match_info_fetch_named(info, "command"); + middle = g_match_info_fetch_named(info, "middle"); + trailing = g_match_info_fetch_named(info, "trailing"); + g_match_info_unref(info); - /* look up the command handler */
- handler = g_hash_table_lookup(chat->handlers, parts[1]);
- purple_debug_misc("spasm-chat", "unknown message type %s\n", parts[1]);
+ /* Look up the command handler. */ + if(g_hash_table_lookup_extended(chat->handlers, command, NULL, &value)) { + /* Ignored replies have a NULL handler. */ + SpasmChatMessageHandler handler = (SpasmChatMessageHandler)value; - 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");
+ handler(chat, prefix, middle, trailing); - if(handler->callback != NULL) {
- gchar **args = g_strsplit(g_strstrip(parts[2]), " ",
- gchar *from = parts[0];
- if(from && *from == ':') {
- from++; /* increment past the : */
- handler->callback(chat, from, args);
+ purple_debug_misc("spasm-chat", "no handler found for \"%s\"\n", + purple_debug_misc("spasm-chat", "prefix: \"%s\"\n", prefix); + purple_debug_misc("spasm-chat", "command: \"%s\"\n", command); + purple_debug_misc("spasm-chat", "middle: \"%s\"\n", middle); + purple_debug_misc("spasm-chat", "trailing: \"%s\"\n", trailing); + purple_debug_misc("spasm-chat", "----\n");
static void spasm_chat_read(SpasmChatService *chat);
@@ -324,14 +365,14 @@
spasm_chat_service_real_send(
spasm_account_get_access_token(chat->sa)
/* now try to use our nick */
spasm_chat_service_real_send(
spasm_account_get_name(chat->sa)
@@ -355,6 +396,8 @@
chat->handlers = spasm_chat_service_init_handlers();
+ spasm_chat_service_regex_init(chat); @@ -365,6 +408,9 @@
g_object_unref(chat->socket_client);
g_object_unref(chat->socket_connection);
+ g_regex_unref(chat->regex_message); + g_regex_unref(chat->regex_target); g_slice_free(SpasmChatService, chat);
@@ -430,7 +476,7 @@
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);
+ spasm_chat_service_real_send(chat, "JOIN #%s", channel); @@ -459,7 +505,7 @@
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",
+ spasm_chat_service_real_send(chat, "PRIVMSG #%s :%s", purple_conversation_get_name(conversation),