Updated Norwegian bokmål translation
[platform/upstream/folks.git] / folks / im-details.vala
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  * Copyright (C) 2011 Philip Withnall
4  *
5  * This library is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 2.1 of the License, or
8  * (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Authors:
19  *       Philip Withnall <philip.withnall@collabora.co.uk>
20  */
21
22 using GLib;
23 using Gee;
24
25 /**
26  * Errors related to IM addresses and IM address handling.
27  */
28 public errordomain Folks.ImDetailsError
29 {
30   /**
31    * The specified IM address could not be parsed.
32    */
33   INVALID_IM_ADDRESS
34 }
35
36 /**
37  * Object representing an IM address value that can have some parameters
38  * associated with it.
39  *
40  * See {@link Folks.AbstractFieldDetails}.
41  *
42  * @since 0.6.0
43  */
44 public class Folks.ImFieldDetails : AbstractFieldDetails<string>
45 {
46   /**
47    * Create a new ImFieldDetails.
48    *
49    * @param value the value of the field, which should be a valid, non-empty
50    * IM address
51    * @param parameters initial parameters. See
52    * {@link AbstractFieldDetails.parameters}. A `null` value is equivalent to an
53    * empty map of parameters.
54    *
55    * @return a new ImFieldDetails
56    *
57    * @since 0.6.0
58    */
59   public ImFieldDetails (string value,
60       MultiMap<string, string>? parameters = null)
61     {
62       if (value == "")
63         {
64           warning ("Empty IM address passed to ImFieldDetails.");
65         }
66
67       this.value = value;
68       if (parameters != null)
69         this.parameters = (!) parameters;
70     }
71
72   /**
73    * {@inheritDoc}
74    *
75    * @since 0.6.0
76    */
77   public override bool equal (AbstractFieldDetails<string> that)
78     {
79       return base.equal (that);
80     }
81
82   /**
83    * {@inheritDoc}
84    *
85    * @since 0.6.0
86    */
87   public override uint hash ()
88     {
89       return base.hash ();
90     }
91 }
92
93 /**
94  * IM addresses exposed by an object implementing {@link PresenceDetails}.
95  *
96  * @since 0.1.13
97  */
98 public interface Folks.ImDetails : Object
99 {
100   /**
101    * A mapping of IM protocol to an (unordered) set of IM addresses.
102    *
103    * Each mapping is from an arbitrary protocol identifier to a set of IM
104    * addresses on that protocol for the contact, listed in no particular order.
105    *
106    * There must be no duplicate IM addresses in each set, though a given
107    * IM address may be present in the sets for different protocols.
108    *
109    * All the IM addresses must be normalised using
110    * {@link ImDetails.normalise_im_address} before being added to this property.
111    *
112    * @since 0.5.1
113    */
114   public abstract MultiMap<string, ImFieldDetails> im_addresses
115     {
116       get; set;
117     }
118
119   /**
120    * Change the contact's set of IM addresses.
121    *
122    * It's preferred to call this rather than setting
123    * {@link ImDetails.im_addresses} directly, as this method gives error
124    * notification and will only return once the IM addresses have been written
125    * to the relevant backing store (or the operation's failed).
126    *
127    * @param im_addresses the new map of protocols to IM addresses
128    * @throws PropertyError if setting the IM addresses failed
129    * @since 0.6.2
130    */
131   public virtual async void change_im_addresses (
132       MultiMap<string, ImFieldDetails> im_addresses) throws PropertyError
133     {
134       /* Default implementation. */
135       throw new PropertyError.NOT_WRITEABLE (
136           _("IM addresses are not writeable on this contact."));
137     }
138
139   /**
140    * Normalise an IM address so that it's suitable for string comparison.
141    *
142    * IM addresses for various protocols can be represented in different ways,
143    * only one of which is canonical. In order to allow simple string comparisons
144    * of IM addresses to work, the IM addresses must be normalised beforehand.
145    *
146    * If the provided IM address is invalid,
147    * {@link Folks.ImDetailsError.INVALID_IM_ADDRESS} will be thrown. Note that
148    * this isn't guaranteed to be thrown for all invalid addresses, but if it is
149    * thrown, the address is guaranteed to be invalid.
150    *
151    * @param im_address the address to normalise
152    * @param protocol the protocol of this im_address
153    *
154    * @since 0.2.0
155    * @throws Folks.ImDetailsError if the provided IM address was invalid
156    */
157   public static string normalise_im_address (string im_address, string protocol)
158       throws Folks.ImDetailsError
159     {
160       if (protocol == "aim" || protocol == "myspace")
161         {
162           return im_address.replace (" ", "").down ().normalize ();
163         }
164       else if (protocol == "irc" || protocol == "yahoo" ||
165           protocol == "yahoojp" || protocol == "groupwise")
166         {
167           return im_address.down ().normalize ();
168         }
169       else if (protocol == "jabber")
170         {
171           /* Parse the JID */
172           string[] parts = im_address.split ("/", 2);
173
174           if (parts.length < 1)
175             {
176               throw new ImDetailsError.INVALID_IM_ADDRESS (
177                   /* Translators: the parameter is an IM address. */
178                   _("The IM address '%s' could not be understood."),
179                   im_address);
180             }
181
182           string? resource = null;
183           if (parts.length == 2)
184             resource = parts[1];
185
186           parts = parts[0].split ("@", 2);
187
188           if (parts.length < 1)
189             {
190               throw new ImDetailsError.INVALID_IM_ADDRESS (
191                   /* Translators: the parameter is an IM address. */
192                   _("The IM address '%s' could not be understood."),
193                   im_address);
194             }
195
196           string? node, _domain;
197           if (parts.length == 2)
198             {
199               node = parts[0];
200               _domain = parts[1];
201             }
202           else
203             {
204               node = null;
205               _domain = parts[0];
206             }
207
208           if ((node != null && node == "") ||
209               (_domain == null || _domain == "") ||
210               (resource != null && resource == ""))
211             {
212               throw new ImDetailsError.INVALID_IM_ADDRESS (
213                   /* Translators: the parameter is an IM address. */
214                   _("The IM address '%s' could not be understood."),
215                   im_address);
216             }
217
218           string domain = ((!) _domain).down ();
219           if (node != null)
220             node = ((!) node).down ();
221
222           /* Build a new JID */
223           string? normalised = null;
224
225           if (node != null && resource != null)
226             {
227               normalised = "%s@%s/%s".printf ((!) node, domain, (!) resource);
228             }
229           else if (node != null)
230             {
231               normalised = "%s@%s".printf ((!) node, domain);
232             }
233           else if (resource != null)
234             {
235               normalised = "%s/%s".printf (domain, (!) resource);
236             }
237           else
238             {
239               throw new ImDetailsError.INVALID_IM_ADDRESS (
240                   /* Translators: the parameter is an IM address. */
241                   _("The IM address '%s' could not be understood."),
242                   im_address);
243             }
244
245           return ((!) normalised).normalize (-1, NormalizeMode.NFKC);
246         }
247       else
248         {
249           /* Fallback */
250           return im_address.normalize ();
251         }
252     }
253 }