/* * This file is part of telepathy-idle * * Copyright (C) 2006-2007 Collabora Limited * Copyright (C) 2006-2007 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "idle-handles.h" #include #include #include #include #include #define IDLE_DEBUG_FLAG IDLE_DEBUG_PARSER #include "idle-debug.h" #include "idle-muc-channel.h" /* When strict_mode is true, we validate the nick strictly against the IRC * RFCs (e.g. only ascii characters, no leading '-'. When strict_mode is * false, we releax the requirements slightly. This is because we don't want * to allow contribute to invalid nicks on IRC, but we want to be able to * handle them if another client allows people to use invalid nicks */ gboolean idle_nickname_is_valid(const gchar *nickname, gboolean strict_mode) { const gchar *char_pos; IDLE_DEBUG("Validating nickname '%s' with strict mode %d", nickname, strict_mode); /* FIXME: also check for max length? */ if (!nickname || *nickname == '\0') return FALSE; for (char_pos = nickname; *char_pos; char_pos = g_utf8_find_next_char(char_pos, NULL)) { /* only used for non-strict checks */ gunichar ucs4char = g_utf8_get_char_validated(char_pos, -1); switch (*char_pos) { case '[': case ']': case '\\': case '`': case '_': case '^': case '{': case '|': case '}': break; /* '-' is technically not allowed as first char in a nickname */ case '-': if (strict_mode) { if (char_pos == nickname) return FALSE; } break; default: if (strict_mode) { /* only accept ascii characters in strict mode */ if (!(g_ascii_isalpha(*char_pos) || ((char_pos != nickname) && g_ascii_isdigit(*char_pos)))) { IDLE_DEBUG("invalid character '%c'", *char_pos); return FALSE; } } else { /* allow unicode and digits as first char in non-strict mode */ if (!(g_unichar_isalpha(ucs4char) || g_unichar_isdigit(ucs4char))) { IDLE_DEBUG("invalid character %d", ucs4char); return FALSE; } } break; } } return TRUE; } static gboolean _channelname_is_valid(const gchar *channel) { static const gchar not_allowed_chars[] = {' ', '\007', ',', '\r', '\n', ':', '\0'}; gsize len; const gchar *tmp; if (!idle_muc_channel_is_typechar(channel[0])) return FALSE; len = strlen(channel); if ((len < 2) || (len > 50)) return FALSE; if (channel[0] == '!') { for (gsize i = 0; i < 5 && i + 1 < len; i++) { if (!g_ascii_isupper(channel[i + 1]) && !isdigit(channel[i + 1])) return FALSE; } } tmp = strchr(channel + 1, ':'); if (tmp != NULL) { for (const gchar *tmp2 = channel + 1; tmp2 != tmp; tmp2++) { if (strchr(not_allowed_chars, *tmp2)) return FALSE; } for (const gchar *tmp2 = tmp + 1; tmp2 != channel + len; tmp2++) { if (strchr(not_allowed_chars, *tmp2)) return FALSE; } } else { for (const gchar *tmp2 = channel + 1; tmp2 != channel + len; tmp2++) { if (strchr(not_allowed_chars, *tmp2)) return FALSE; } } return TRUE; } gchar *idle_normalize_nickname (const gchar *id, GError **error) { gchar *normalized; if (!idle_nickname_is_valid(id, FALSE)) { g_set_error(error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "invalid nickname"); return NULL; } normalized = g_utf8_strdown(id, -1); return normalized; } static gchar *_nick_normalize_func(TpHandleRepoIface *repo, const gchar *id, gpointer ctx, GError **error) { return idle_normalize_nickname (id, error); } static gchar *_channel_normalize_func(TpHandleRepoIface *repo, const gchar *id, gpointer ctx, GError **error) { gchar *normalized; if (!_channelname_is_valid(id)) { g_set_error(error, TP_ERROR, TP_ERROR_INVALID_HANDLE, "invalid channel ID"); return NULL; } normalized = g_utf8_strdown(id, -1); return normalized; } void idle_handle_repos_init(TpHandleRepoIface **handles) { g_assert(handles != NULL); handles[TP_HANDLE_TYPE_CONTACT] = (TpHandleRepoIface *) g_object_new(TP_TYPE_DYNAMIC_HANDLE_REPO, "handle-type", TP_HANDLE_TYPE_CONTACT, "normalize-function", _nick_normalize_func, "default-normalize-context", NULL, NULL); handles[TP_HANDLE_TYPE_ROOM] = (TpHandleRepoIface *) g_object_new(TP_TYPE_DYNAMIC_HANDLE_REPO, "handle-type", TP_HANDLE_TYPE_ROOM, "normalize-function", _channel_normalize_func, "default-normalize-context", NULL, NULL); }