// This Source Code Form is subject to the terms of the Mozilla Public // License, version 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include "plugin.hh" #include "account.hh" #include "channel.hh" #include "user.hh" #include "message.h" static const char format_regex[] = "<([^>]*?)>"; static const size_t max_groups = 2; char *message__translate_code(struct t_account *account, const char *code) { struct t_channel *channel; struct t_user *user; size_t resultlen; char *identifier, *alttext, *result, *symbol, *prefix; identifier = strdup(code); alttext = strchr(identifier, '|'); if (alttext) *alttext++ = '\0'; switch (identifier[0]) { case '#': /* channel */ if (alttext) { prefix = "#"; symbol = strdup(alttext); } else { channel = channel__search(account, identifier+1); if (channel) { prefix = "#"; symbol = strdup(channel->name); } else { prefix = "Channel:"; symbol = strdup(identifier+1); } } break; case '@': /* user */ if (alttext) { prefix = "@"; symbol = strdup(alttext); } else { user = user__search(account, identifier+1); if (user) { prefix = "@"; symbol = strdup(user->profile.display_name); } else { prefix = "User:"; symbol = strdup(identifier+1); } } break; case '!': /* special */ if (alttext) { prefix = "@"; symbol = strdup(alttext); } else { prefix = "@"; symbol = strdup(identifier+1); } break; default: /* url */ prefix = ""; symbol = strdup(code); break; } free(identifier); resultlen = snprintf(NULL, 0, "%s%s%s%s", weechat_color("chat_nick"), prefix, symbol, weechat_color("reset")) + 1; result = malloc(resultlen); snprintf(result, resultlen, "%s%s%s%s", weechat_color("chat_nick"), prefix, symbol, weechat_color("reset")); free(symbol); return result; } void message__htmldecode(char *dest, const char *src, size_t n) { size_t i, j; for (i = 0, j = 0; i < n; i++, j++) switch (src[i]) { case '\0': dest[j] = '\0'; return; case '&': if (src[i+1] == 'g' && src[i+2] == 't' && src[i+3] == ';') { dest[j] = '>'; i += 3; break; } else if (src[i+1] == 'l' && src[i+2] == 't' && src[i+3] == ';') { dest[j] = '<'; i += 3; break; } else if (src[i+1] == 'a' && src[i+2] == 'm' && src[i+3] == 'p' && src[i+4] == ';') { dest[j] = '&'; i += 4; break; } /* fallthrough */ default: dest[j] = src[i]; break; } dest[j-1] = '\0'; return; } char *message__decode(struct t_account *account, const char *text) { int rc; regex_t reg; regmatch_t groups[max_groups]; char msgbuf[100]; char *decoded_text; const char *cursor; size_t offset; if ((rc = regcomp(®, format_regex, REG_EXTENDED))) { regerror(rc, ®, msgbuf, sizeof(msgbuf)); weechat_printf( account->buffer, _("%s%s: error compiling message formatting regex: %s"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, msgbuf); return strdup(text); } decoded_text = malloc(MESSAGE_MAX_LENGTH); if (!decoded_text) { regfree(®); weechat_printf( account->buffer, _("%s%s: error allocating space for message"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME); return strdup(text); } decoded_text[0] = '\0'; for (cursor = text; regexec(®, cursor, max_groups, groups, 0) == 0; cursor += offset) { offset = groups[0].rm_eo; char *copy = strdup(cursor); if (!copy) { regfree(®); free(decoded_text); weechat_printf( account->buffer, _("%s%s: error allocating space for message"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME); return strdup(text); } copy[groups[1].rm_eo] = '\0'; char *match = strdup(copy + groups[1].rm_so); if (!match) { free(copy); regfree(®); free(decoded_text); weechat_printf( account->buffer, _("%s%s: error allocating space for message"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME); return strdup(text); } copy[groups[0].rm_so] = '\0'; char *prematch = strdup(copy); if (!prematch) { free(match); free(copy); regfree(®); free(decoded_text); weechat_printf( account->buffer, _("%s%s: error allocating space for message"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME); return strdup(text); } free(copy); strncat(decoded_text, prematch, MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); free(prematch); char *replacement = message__translate_code(account, match); free(match); strncat(decoded_text, replacement, MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); free(replacement); } strncat(decoded_text, cursor, MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); message__htmldecode(decoded_text, decoded_text, MESSAGE_MAX_LENGTH); regfree(®); return decoded_text; }