001package ezvcard.property;
002
003import java.net.URI;
004import java.net.URISyntaxException;
005import java.util.LinkedHashMap;
006import java.util.List;
007import java.util.Map;
008import java.util.Objects;
009
010import ezvcard.SupportedVersions;
011import ezvcard.VCard;
012import ezvcard.VCardVersion;
013import ezvcard.ValidationWarning;
014import ezvcard.parameter.ImppType;
015import ezvcard.parameter.Pid;
016
017/*
018 Copyright (c) 2012-2026, Michael Angstadt
019 All rights reserved.
020
021 Redistribution and use in source and binary forms, with or without
022 modification, are permitted provided that the following conditions are met: 
023
024 1. Redistributions of source code must retain the above copyright notice, this
025 list of conditions and the following disclaimer. 
026 2. Redistributions in binary form must reproduce the above copyright notice,
027 this list of conditions and the following disclaimer in the documentation
028 and/or other materials provided with the distribution. 
029
030 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
031 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
032 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
033 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
034 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
035 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
036 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
037 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
038 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
039 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
040
041 The views and conclusions contained in the software and documentation are those
042 of the authors and should not be interpreted as representing official policies, 
043 either expressed or implied, of the FreeBSD Project.
044 */
045
046/**
047 * <p>
048 * Defines an instant messenger handle. The handle is represented as a URI in
049 * the format "{@code <PROTOCOL>:<HANDLE>}". For example, a Yahoo! Messenger
050 * handle of "johndoe@yahoo.com" would look like this:
051 * "ymsgr:johndoe@yahoo.com".
052 * </p>
053 * 
054 * <p>
055 * <b>Code sample</b>
056 * </p>
057 * 
058 * <pre class="brush:java">
059 * VCard vcard = new VCard();
060 * 
061 * //URI
062 * Impp impp = new Impp("aim:johndoe@aol.com");
063 * vcard.addImpp(impp);
064 * 
065 * //static factory methods
066 * impp = Impp.msn("janedoe@msn.com");
067 * vcard.addImpp(impp);
068 * </pre>
069 * 
070 * <p>
071 * <b>Property name:</b> {@code IMPP}
072 * </p>
073 * <p>
074 * <b>Supported versions:</b> {@code 3.0, 4.0}
075 * </p>
076 * @author Michael Angstadt
077 * @see <a href="http://tools.ietf.org/html/rfc6350#page-36">RFC 6350 p.36</a>
078 * @see <a href="http://tools.ietf.org/html/rfc4770">RFC 4770</a>
079 */
080@SupportedVersions({ VCardVersion.V3_0, VCardVersion.V4_0 })
081public class Impp extends VCardProperty implements HasAltId {
082        private static final String AIM = "aim";
083        private static final String ICQ = "icq";
084        private static final String IRC = "irc";
085        private static final String MSN = "msnim";
086        private static final String SIP = "sip";
087        private static final String SKYPE = "skype";
088        private static final String XMPP = "xmpp";
089        private static final String YAHOO = "ymsgr";
090
091        private URI uri;
092
093        /**
094         * Creates an IMPP property. Note that this class has static factory methods
095         * for creating IMPP properties of common IM protocols.
096         * @param uri the IM URI (e.g. "aim:johndoe@aol.com")
097         * @throws IllegalArgumentException if the URI is not a valid URI
098         */
099        public Impp(String uri) {
100                setUri(uri);
101        }
102
103        /**
104         * Creates an IMPP property. Note that this class has static factory methods
105         * for creating IMPP properties of common IM protocols.
106         * @param uri the IM URI (e.g. "aim:johndoe@aol.com")
107         */
108        public Impp(URI uri) {
109                setUri(uri);
110        }
111
112        /**
113         * Creates an IMPP property. Note that this class has static factory methods
114         * for creating IMPP properties of common IM protocols.
115         * @param protocol the IM protocol (e.g. "aim")
116         * @param handle the IM handle (e.g. "johndoe@aol.com")
117         */
118        public Impp(String protocol, String handle) {
119                setUri(protocol, handle);
120        }
121
122        /**
123         * Copy constructor.
124         * @param original the property to make a copy of
125         */
126        public Impp(Impp original) {
127                super(original);
128                uri = original.uri;
129        }
130
131        /**
132         * Creates an IMPP property that contains a AOL Instant Messenger handle.
133         * @param handle the IM handle
134         * @return the IMPP property instance
135         */
136        public static Impp aim(String handle) {
137                return new Impp(AIM, handle);
138        }
139
140        /**
141         * Determines if this IMPP property contains an AOL Instant Messenger
142         * handle.
143         * @return true if it contains an AOL Instant Messenger handle, false if not
144         */
145        public boolean isAim() {
146                return isProtocol(AIM);
147        }
148
149        /**
150         * Creates an IMPP property that contains a Yahoo! Messenger handle.
151         * @param handle the IM handle
152         * @return the IMPP property instance
153         */
154        public static Impp yahoo(String handle) {
155                return new Impp(YAHOO, handle);
156        }
157
158        /**
159         * Determines if this IMPP property contains a Yahoo! Messenger handle.
160         * @return true if it contains a Yahoo! Messenger handle, false if not
161         */
162        public boolean isYahoo() {
163                return isProtocol(YAHOO);
164        }
165
166        /**
167         * Creates an IMPP property that contains an MSN IMPP property.
168         * @param handle the IM handle
169         * @return the IMPP property instance
170         */
171        public static Impp msn(String handle) {
172                return new Impp(MSN, handle);
173        }
174
175        /**
176         * Determines if this IMPP property contains an MSN handle.
177         * @return true if it contains an MSN handle, false if not
178         */
179        public boolean isMsn() {
180                return isProtocol(MSN);
181        }
182
183        /**
184         * Creates an IMPP property that contains an ICQ handle.
185         * @param handle the IM handle
186         * @return the IMPP property instance
187         */
188        public static Impp icq(String handle) {
189                return new Impp(ICQ, handle);
190        }
191
192        /**
193         * Determines if this IMPP property contains an ICQ handle.
194         * @return true if it contains an ICQ handle, false if not
195         */
196        public boolean isIcq() {
197                return isProtocol(ICQ);
198        }
199
200        /**
201         * Creates an IMPP property that contains an IRC handle.
202         * @param handle the IM handle
203         * @return the IMPP property instance
204         */
205        public static Impp irc(String handle) {
206                return new Impp(IRC, handle);
207        }
208
209        /**
210         * Determines if this IMPP property contains an IRC handle.
211         * @return true if it contains an IRC handle, false if not
212         */
213        public boolean isIrc() {
214                return isProtocol(IRC);
215        }
216
217        /**
218         * Creates an IMPP property that contains a Session Initiation Protocol
219         * handle.
220         * @param handle the IM handle
221         * @return the IMPP property instance
222         */
223        public static Impp sip(String handle) {
224                return new Impp(SIP, handle);
225        }
226
227        /**
228         * Determines if this IMPP property contains a Session Initiation Protocol
229         * handle.
230         * @return true if it contains a SIP handle, false if not
231         */
232        public boolean isSip() {
233                return isProtocol(SIP);
234        }
235
236        /**
237         * Creates an IMPP property that contains a Skype handle.
238         * @param handle the IM handle
239         * @return the IMPP property instance
240         */
241        public static Impp skype(String handle) {
242                return new Impp(SKYPE, handle);
243        }
244
245        /**
246         * Determines if this IMPP property contains a Skype handle.
247         * @return true if it contains a Skype handle, false if not
248         */
249        public boolean isSkype() {
250                return isProtocol(SKYPE);
251        }
252
253        /**
254         * Creates an IMPP property that contains an Extensible Messaging and
255         * Presence Protocol handle.
256         * @param handle the IM handle
257         * @return the IMPP property instance
258         */
259        public static Impp xmpp(String handle) {
260                return new Impp(XMPP, handle);
261        }
262
263        /**
264         * Determines if this IMPP property contains an Extensible Messaging and
265         * Presence Protocol handle.
266         * @return true if it contains an XMPP handle, false if not
267         */
268        public boolean isXmpp() {
269                return isProtocol(XMPP);
270        }
271
272        private boolean isProtocol(String protocol) {
273                return uri != null && protocol.equalsIgnoreCase(uri.getScheme());
274        }
275
276        /**
277         * Gets the IM URI.
278         * @return the IM URI
279         */
280        public URI getUri() {
281                return uri;
282        }
283
284        /**
285         * Sets the IM URI.
286         * @param uri the IM URI (e.g. "aim:theuser@aol.com")
287         * @throws IllegalArgumentException if the URI is not a valid URI
288         */
289        public void setUri(String uri) {
290                setUri((uri == null) ? null : URI.create(uri));
291        }
292
293        /**
294         * Sets the IM URI.
295         * @param uri the IM URI (e.g. "aim:theuser@aol.com")
296         */
297        public void setUri(URI uri) {
298                this.uri = uri;
299        }
300
301        /**
302         * Sets the IM URI.
303         * @param protocol the IM protocol (e.g. "aim")
304         * @param handle the IM handle (e.g. "theuser@aol.com")
305         */
306        public void setUri(String protocol, String handle) {
307                try {
308                        this.uri = new URI(protocol, handle, null);
309                } catch (URISyntaxException e) {
310                        throw new IllegalArgumentException(e);
311                }
312        }
313
314        /**
315         * Gets the IM protocol. Use {@link #setUri(String, String)} to set the
316         * protocol.
317         * @return the IM protocol (e.g. "aim") or null if not set
318         */
319        public String getProtocol() {
320                if (uri == null) {
321                        return null;
322                }
323                return uri.getScheme();
324        }
325
326        /**
327         * Gets the IM handle. Use {@link #setUri(String, String)} to set the
328         * handle.
329         * @return the IM handle (e.g. "johndoe@aol.com") or null if not set
330         */
331        public String getHandle() {
332                if (uri == null) {
333                        return null;
334                }
335                return uri.getSchemeSpecificPart();
336        }
337
338        /**
339         * Gets the list that stores this property's IMPP types (TYPE parameters).
340         * @return the IMPP types (e.g. "HOME", "WORK") (this list is mutable)
341         */
342        public List<ImppType> getTypes() {
343                return parameters.new TypeParameterList<ImppType>() {
344                        @Override
345                        protected ImppType _asObject(String value) {
346                                return ImppType.get(value);
347                        }
348                };
349        }
350
351        /**
352         * Gets the MEDIATYPE parameter.
353         * <p>
354         * <b>Supported versions:</b> {@code 4.0}
355         * </p>
356         * @return the media type or null if not set
357         */
358        public String getMediaType() {
359                return parameters.getMediaType();
360        }
361
362        /**
363         * Sets the MEDIATYPE parameter.
364         * <p>
365         * <b>Supported versions:</b> {@code 4.0}
366         * </p>
367         * @param mediaType the media type or null to remove
368         */
369        public void setMediaType(String mediaType) {
370                parameters.setMediaType(mediaType);
371        }
372
373        @Override
374        public List<Pid> getPids() {
375                return super.getPids();
376        }
377
378        @Override
379        public Integer getPref() {
380                return super.getPref();
381        }
382
383        @Override
384        public void setPref(Integer pref) {
385                super.setPref(pref);
386        }
387
388        //@Override
389        public String getAltId() {
390                return parameters.getAltId();
391        }
392
393        //@Override
394        public void setAltId(String altId) {
395                parameters.setAltId(altId);
396        }
397
398        @Override
399        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
400                if (uri == null) {
401                        warnings.add(new ValidationWarning(8));
402                }
403        }
404
405        @Override
406        protected Map<String, Object> toStringValues() {
407                Map<String, Object> values = new LinkedHashMap<>();
408                values.put("uri", uri);
409                return values;
410        }
411
412        @Override
413        public Impp copy() {
414                return new Impp(this);
415        }
416
417        @Override
418        public int hashCode() {
419                final int prime = 31;
420                int result = super.hashCode();
421                result = prime * result + Objects.hash(uri);
422                return result;
423        }
424
425        @Override
426        public boolean equals(Object obj) {
427                if (this == obj) return true;
428                if (!super.equals(obj)) return false;
429                if (getClass() != obj.getClass()) return false;
430                Impp other = (Impp) obj;
431                return Objects.equals(uri, other.uri);
432        }
433}