/* * Copyright (C) 2010 Collabora Ltd. * Copyright (C) 2011 Philip Withnall * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * 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, see . * * Authors: * Philip Withnall */ using GLib; using Gee; /** * Errors related to IM addresses and IM address handling. */ public errordomain Folks.ImDetailsError { /** * The specified IM address could not be parsed. */ INVALID_IM_ADDRESS } /** * Object representing an IM address value that can have some parameters * associated with it. * * See {@link Folks.AbstractFieldDetails}. * * @since 0.6.0 */ public class Folks.ImFieldDetails : AbstractFieldDetails { /** * Create a new ImFieldDetails. * * @param value the value of the field, which should be a valid, non-empty * IM address * @param parameters initial parameters. See * {@link AbstractFieldDetails.parameters}. A `null` value is equivalent to an * empty map of parameters. * * @return a new ImFieldDetails * * @since 0.6.0 */ public ImFieldDetails (string value, MultiMap? parameters = null) { if (value == "") { warning ("Empty IM address passed to ImFieldDetails."); } this.value = value; if (parameters != null) this.parameters = (!) parameters; } /** * {@inheritDoc} * * @since 0.6.0 */ public override bool equal (AbstractFieldDetails that) { return base.equal (that); } /** * {@inheritDoc} * * @since 0.6.0 */ public override uint hash () { return base.hash (); } } /** * IM addresses exposed by an object implementing {@link PresenceDetails}. * * @since 0.1.13 */ public interface Folks.ImDetails : Object { /** * A mapping of IM protocol to an (unordered) set of IM addresses. * * Each mapping is from an arbitrary protocol identifier to a set of IM * addresses on that protocol for the contact, listed in no particular order. * * There must be no duplicate IM addresses in each set, though a given * IM address may be present in the sets for different protocols. * * All the IM addresses must be normalised using * {@link ImDetails.normalise_im_address} before being added to this property. * * @since 0.5.1 */ public abstract MultiMap im_addresses { get; set; } /** * Change the contact's set of IM addresses. * * It's preferred to call this rather than setting * {@link ImDetails.im_addresses} directly, as this method gives error * notification and will only return once the IM addresses have been written * to the relevant backing store (or the operation's failed). * * @param im_addresses the new map of protocols to IM addresses * @throws PropertyError if setting the IM addresses failed * @since 0.6.2 */ public virtual async void change_im_addresses ( MultiMap im_addresses) throws PropertyError { /* Default implementation. */ throw new PropertyError.NOT_WRITEABLE ( _("IM addresses are not writeable on this contact.")); } /** * Normalise an IM address so that it's suitable for string comparison. * * IM addresses for various protocols can be represented in different ways, * only one of which is canonical. In order to allow simple string comparisons * of IM addresses to work, the IM addresses must be normalised beforehand. * * If the provided IM address is invalid, * {@link Folks.ImDetailsError.INVALID_IM_ADDRESS} will be thrown. Note that * this isn't guaranteed to be thrown for all invalid addresses, but if it is * thrown, the address is guaranteed to be invalid. * * @param im_address the address to normalise * @param protocol the protocol of this im_address * * @since 0.2.0 * @throws Folks.ImDetailsError if the provided IM address was invalid */ public static string normalise_im_address (string im_address, string protocol) throws Folks.ImDetailsError { if (protocol == "aim" || protocol == "myspace") { return im_address.replace (" ", "").down ().normalize (); } else if (protocol == "irc" || protocol == "yahoo" || protocol == "yahoojp" || protocol == "groupwise") { return im_address.down ().normalize (); } else if (protocol == "jabber") { /* Parse the JID */ string[] parts = im_address.split ("/", 2); if (parts.length < 1) { throw new ImDetailsError.INVALID_IM_ADDRESS ( /* Translators: the parameter is an IM address. */ _("The IM address '%s' could not be understood."), im_address); } string? resource = null; if (parts.length == 2) resource = parts[1]; parts = parts[0].split ("@", 2); if (parts.length < 1) { throw new ImDetailsError.INVALID_IM_ADDRESS ( /* Translators: the parameter is an IM address. */ _("The IM address '%s' could not be understood."), im_address); } string? node, _domain; if (parts.length == 2) { node = parts[0]; _domain = parts[1]; } else { node = null; _domain = parts[0]; } if ((node != null && node == "") || (_domain == null || _domain == "") || (resource != null && resource == "")) { throw new ImDetailsError.INVALID_IM_ADDRESS ( /* Translators: the parameter is an IM address. */ _("The IM address '%s' could not be understood."), im_address); } string domain = ((!) _domain).down (); if (node != null) node = ((!) node).down (); /* Build a new JID */ string? normalised = null; if (node != null && resource != null) { normalised = "%s@%s/%s".printf ((!) node, domain, (!) resource); } else if (node != null) { normalised = "%s@%s".printf ((!) node, domain); } else if (resource != null) { normalised = "%s/%s".printf (domain, (!) resource); } else { throw new ImDetailsError.INVALID_IM_ADDRESS ( /* Translators: the parameter is an IM address. */ _("The IM address '%s' could not be understood."), im_address); } return ((!) normalised).normalize (-1, NormalizeMode.NFKC); } else { /* Fallback */ return im_address.normalize (); } } }