Skip to content

Commit

Permalink
Add support for message-tags
Browse files Browse the repository at this point in the history
Not doing anything with it yet, though.
  • Loading branch information
progval committed Sep 18, 2021
1 parent badf813 commit fa27329
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 6 deletions.
8 changes: 8 additions & 0 deletions src/core/app_irc_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ static void irc_event_privmsg(SircSession *sirc, const char *event,
const char *origin, const char *params[], int count);
static void irc_event_notice(SircSession *sirc, const char *event,
const char *origin, const char *params[], int count);
static void irc_event_tagmsg(SircSession *sirc, const char *event,
const char *origin, const char *params[], int count);
static void irc_event_channel_notice(SircSession *sirc, const char *event,
const char *origin, const char *params[], int count);
static void irc_event_invite(SircSession *sirc, const char *event,
Expand Down Expand Up @@ -113,6 +115,7 @@ void srn_application_init_irc_event(SrnApplication *app) {
app->irc_events.channel = irc_event_channel;
app->irc_events.privmsg = irc_event_privmsg;
app->irc_events.notice = irc_event_notice;
app->irc_events.tagmsg = irc_event_tagmsg;
app->irc_events.channel_notice = irc_event_channel_notice;
app->irc_events.invite = irc_event_invite;
app->irc_events.ctcp_req = irc_event_ctcp_req;
Expand Down Expand Up @@ -824,6 +827,11 @@ static void irc_event_notice(SircSession *sirc, const char *event,
srn_chat_add_notice_message(chat, chat_user, msg);
}

static void irc_event_tagmsg(SircSession *sirc, const char *event,
const char *origin, const char **params, int count){
/* Not used yet */
}

static void irc_event_channel_notice(SircSession *sirc, const char *event,
const char *origin, const char **params, int count){
const char *chan;
Expand Down
4 changes: 4 additions & 0 deletions src/core/server_cap.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ static ServerCapSupport supported_caps[] = {
},

// /* IRCv3.2 */
{
.name = "message-tags",
.offset = offsetof(EnabledCap, message_tags),
},
// {
// .name = "server-time",
// .offset = offsetof(EnabledCap, server_time),
Expand Down
1 change: 1 addition & 0 deletions src/inc/core/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ struct _EnabledCap {
bool sasl;

// Version 3.2
bool message_tags;
bool server_time;
bool userhost_in_names;
bool cap_notify;
Expand Down
1 change: 1 addition & 0 deletions src/inc/sirc/sirc_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef struct {
SircEventCallback channel;
SircEventCallback privmsg;
SircEventCallback notice;
SircEventCallback tagmsg;
SircEventCallback channel_notice;
SircEventCallback invite;
SircEventCallback ctcp_req;
Expand Down
4 changes: 4 additions & 0 deletions src/sirc/sirc_event_hdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ void sirc_event_hdr(SircSession *sirc, SircMessage *imsg){
g_return_if_fail(events->error);
events->error(sirc, event, origin, params, imsg->nparam);
}
else if (strcasecmp(event, "TAGMSG") == 0){
g_return_if_fail(events->error);
events->tagmsg(sirc, event, origin, params, imsg->nparam);
}
else {
g_return_if_fail(events->unknown);
events->unknown(sirc, event, origin, params, imsg->nparam);
Expand Down
111 changes: 105 additions & 6 deletions src/sirc/sirc_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
#include "log.h"
#include "utils.h"

/* https://ircv3.net/specs/extensions/message-tags#size-limit */
#define TAGS_SIZE_LIMIT 8191

SircMessage *sirc_message_new(){
return g_malloc0(sizeof(SircMessage));
}
Expand All @@ -50,6 +53,15 @@ void sirc_message_free(SircMessage *imsg){
str_assign(&imsg->params[i], NULL);
}

for (int i = 0; i < imsg->ntags; i++){
str_assign(&imsg->tags[i].key, NULL);
str_assign(&imsg->tags[i].value, NULL);
}

if (imsg->ntags > 0) {
g_free(imsg->tags);
}

g_free(imsg);
}

Expand All @@ -63,6 +75,8 @@ void sirc_message_transcoding(SircMessage *imsg, const char *from_codeset) {
for (int i = 0; i < imsg->nparam; i++){
str_transcoding(&imsg->params[i], from_codeset);
}

/* No need to transcode tags, they are guaranteed to be UTF-8 */
}

/**
Expand All @@ -80,20 +94,105 @@ SircMessage* sirc_parse(char *line){
imsg = sirc_message_new();

/* This is a IRC message
* IRS protocol message format?
* See: https://tools.ietf.org/html/rfc1459#section-2.3
* IRC protocol message format?
* See: https://ircv3.net/specs/extensions/message-tags
*/
char *rfc1459_line;
char *tags_ptr;
char *prefix_ptr, *command_ptr;
char *trailing_ptr, *params_ptr;
char *nick_ptr, *user_ptr, *host_ptr;

// <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
if (line[0] == ':'){
prefix_ptr = strtok(line + 1, " "); // Skip ':'
// <message> ::= ['@' <tags> <SPACE> ] [':' <prefix> <SPACE> ] <command> <params> <crlf>
if (line[0] == '@'){
size_t ntags;
tags_ptr = line + 1;
rfc1459_line = strchr(line, ' ') + 1;

/* Count the number of tags to allocate a tag array */
ntags = 1;
for (char *p=tags_ptr; *p != ' '; p++){
if (*p == ';'){
ntags++;
}
}

imsg->ntags = ntags;
imsg->tags = g_malloc_n(ntags, sizeof(SircMessageTag));
size_t i=0;
char current_tag_key[TAGS_SIZE_LIMIT];
char current_tag_value[TAGS_SIZE_LIMIT];
char *current_tag_key_ptr = current_tag_key;
char *current_tag_value_ptr = current_tag_value;
gboolean in_key = TRUE;
for (char *p=tags_ptr; ; p++){
if (*p == ';' || *p == ' '){
/* next tag or end of tags*/
in_key = TRUE;
*current_tag_key_ptr = '\0';
imsg->tags[i].key = strdup(current_tag_key);
if (current_tag_value == current_tag_value_ptr){
/* Key is absent or empty */
imsg->tags[i].value = NULL;
}
else {
*current_tag_value_ptr = '\0';
imsg->tags[i].value = strdup(current_tag_value);
}
if (*p == ' '){
/* end of tags */
break;
}
i++;

current_tag_key_ptr = current_tag_key;
current_tag_value_ptr = current_tag_value;
}
else if (*p == '=' && in_key){
/* tag's value */
in_key = FALSE;
}
else if (in_key){
*(current_tag_key_ptr++) = *p;
}
else if (!in_key && *p == '\\'){
/* Possibly an escaped character in the value */
p++;
if (*p == ':')
*(current_tag_value_ptr++) = ';';
else if (*p == 's')
*(current_tag_value_ptr++) = ' ';
else if (*p == '\\')
*(current_tag_value_ptr++) = '\\';
else if (*p == 'r')
*(current_tag_value_ptr++) = '\r';
else if (*p == 'n')
*(current_tag_value_ptr++) = '\n';
else{
/* Not an escaped character, it was a literal \ */
*(current_tag_value_ptr++) = '\\';
*(current_tag_value_ptr++) = *p;
}
}
else{
*(current_tag_value_ptr++) = *p;
}
}
}
else{
imsg->tags = NULL;
imsg->ntags = 0;
rfc1459_line = line;
}

/* Now parse like in RFC1459 */

if (rfc1459_line[0] == ':'){
prefix_ptr = strtok(rfc1459_line + 1, " "); // Skip ':'
command_ptr = strtok(NULL, " ");
} else {
prefix_ptr = NULL;
command_ptr = strtok(line, " ");
command_ptr = strtok(rfc1459_line, " ");
}

params_ptr = strtok(NULL, "");
Expand Down
8 changes: 8 additions & 0 deletions src/sirc/sirc_parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
#define SIRC_PARAM_COUNT 64 // RFC 2812 limits it to 14

typedef struct {
char *key;
char *value; // possibly NULL
} SircMessageTag;

typedef struct {
size_t ntags;
SircMessageTag *tags;

char *prefix; // servername or nick!user@host
char *nick, *user, *host;

Expand Down

0 comments on commit fa27329

Please sign in to comment.