1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.packet;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.BufferedInputStream;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.File;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.FileInputStream;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.reflect.Field;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.reflect.Modifier;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.URL;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.MessageDigest;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.NoSuchAlgorithmException;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.HashMap;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Iterator;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Map;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Map.Entry;
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Connection;
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.PacketCollector;
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.SmackConfiguration;
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.XMPPException;
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketIDFilter;
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ;
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.XMPPError;
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringUtils;
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A VCard class for use with the
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <a href="http://www.jivesoftware.org/smack/" target="_blank">SMACK jabber library</a>.<p>
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You should refer to the
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <a href="http://www.jabber.org/jeps/jep-0054.html" target="_blank">JEP-54 documentation</a>.<p>
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Please note that this class is incomplete but it does provide the most commonly found
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * information in vCards. Also remember that VCard transfer is not a standard, and the protocol
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * may change or be replaced.<p>
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <b>Usage:</b>
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <pre>
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * // To save VCard:
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * VCard vCard = new VCard();
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setFirstName("kir");
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setLastName("max");
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setEmailHome("foo@fee.bar");
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setJabberId("jabber@id.org");
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setOrganization("Jetbrains, s.r.o");
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setNickName("KIR");
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setField("TITLE", "Mr");
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setAddressFieldHome("STREET", "Some street");
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setAddressFieldWork("CTRY", "US");
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.setPhoneWork("FAX", "3443233");
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.save(connection);
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * // To load VCard:
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p/>
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * VCard vCard = new VCard();
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.load(conn); // load own VCard
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * vCard.load(conn, "joe@foo.bar"); // load someone's VCard
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * </pre>
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Kirill Maximov (kir@maxkir.com)
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class VCard extends IQ {
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Phone types:
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * VOICE?, FAX?, PAGER?, MSG?, CELL?, VIDEO?, BBS?, MODEM?, ISDN?, PCS?, PREF?
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> homePhones = new HashMap<String, String>();
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> workPhones = new HashMap<String, String>();
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Address types:
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * POSTAL?, PARCEL?, (DOM | INTL)?, PREF?, POBOX?, EXTADR?, STREET?, LOCALITY?,
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * REGION?, PCODE?, CTRY?
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> homeAddr = new HashMap<String, String>();
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> workAddr = new HashMap<String, String>();
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String firstName;
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String lastName;
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String middleName;
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String emailHome;
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String emailWork;
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String organization;
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String organizationUnit;
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String photoMimeType;
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String photoBinval;
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Such as DESC ROLE GEO etc.. see JEP-0054
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> otherSimpleFields = new HashMap<String, String>();
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    // fields that, as they are should not be escaped before forwarding to the server
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Map<String, String> otherUnescapableFields = new HashMap<String, String>();
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public VCard() {
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set generic VCard field.
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param field value of field. Possible values: NICKNAME, PHOTO, BDAY, JABBERID, MAILER, TZ,
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *              GEO, TITLE, ROLE, LOGO, NOTE, PRODID, REV, SORT-STRING, SOUND, UID, URL, DESC.
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getField(String field) {
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return otherSimpleFields.get(field);
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set generic VCard field.
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param value value of field
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param field field to set. See {@link #getField(String)}
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @see #getField(String)
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setField(String field, String value) {
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setField(field, value, false);
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set generic, unescapable VCard field. If unescabale is set to true, XML maybe a part of the
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * value.
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param value         value of field
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param field         field to set. See {@link #getField(String)}
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param isUnescapable True if the value should not be escaped, and false if it should.
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setField(String field, String value, boolean isUnescapable) {
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!isUnescapable) {
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            otherSimpleFields.put(field, value);
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        else {
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            otherUnescapableFields.put(field, value);
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getFirstName() {
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return firstName;
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setFirstName(String firstName) {
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.firstName = firstName;
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Update FN field
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        updateFN();
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getLastName() {
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return lastName;
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setLastName(String lastName) {
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.lastName = lastName;
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Update FN field
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        updateFN();
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getMiddleName() {
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return middleName;
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setMiddleName(String middleName) {
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.middleName = middleName;
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Update FN field
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        updateFN();
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getNickName() {
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return otherSimpleFields.get("NICKNAME");
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setNickName(String nickName) {
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        otherSimpleFields.put("NICKNAME", nickName);
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getEmailHome() {
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return emailHome;
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setEmailHome(String email) {
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.emailHome = email;
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getEmailWork() {
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return emailWork;
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setEmailWork(String emailWork) {
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.emailWork = emailWork;
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getJabberId() {
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return otherSimpleFields.get("JABBERID");
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setJabberId(String jabberId) {
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        otherSimpleFields.put("JABBERID", jabberId);
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getOrganization() {
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return organization;
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setOrganization(String organization) {
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.organization = organization;
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getOrganizationUnit() {
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return organizationUnit;
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setOrganizationUnit(String organizationUnit) {
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.organizationUnit = organizationUnit;
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Get home address field
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *                  LOCALITY, REGION, PCODE, CTRY
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getAddressFieldHome(String addrField) {
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return homeAddr.get(addrField);
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set home address field
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *                  LOCALITY, REGION, PCODE, CTRY
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAddressFieldHome(String addrField, String value) {
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        homeAddr.put(addrField, value);
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Get work address field
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *                  LOCALITY, REGION, PCODE, CTRY
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getAddressFieldWork(String addrField) {
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return workAddr.get(addrField);
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set work address field
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *                  LOCALITY, REGION, PCODE, CTRY
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAddressFieldWork(String addrField, String value) {
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        workAddr.put(addrField, value);
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set home phone number
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneNum  phone number
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setPhoneHome(String phoneType, String phoneNum) {
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        homePhones.put(phoneType, phoneNum);
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Get home phone number
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getPhoneHome(String phoneType) {
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return homePhones.get(phoneType);
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set work phone number
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneNum  phone number
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setPhoneWork(String phoneType, String phoneNum) {
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        workPhones.put(phoneType, phoneNum);
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Get work phone number
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getPhoneWork(String phoneType) {
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return workPhones.get(phoneType);
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Set the avatar for the VCard by specifying the url to the image.
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param avatarURL the url to the image(png,jpeg,gif,bmp)
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAvatar(URL avatarURL) {
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        byte[] bytes = new byte[0];
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            bytes = getBytes(avatarURL);
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (IOException e) {
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            e.printStackTrace();
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setAvatar(bytes);
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Removes the avatar from the vCard
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *  This is done by setting the PHOTO value to the empty string as defined in XEP-0153
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void removeAvatar() {
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Remove avatar (if any)
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        photoBinval = null;
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        photoMimeType = null;
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Specify the bytes of the JPEG for the avatar to use.
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * If bytes is null, then the avatar will be removed.
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * 'image/jpeg' will be used as MIME type.
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param bytes the bytes of the avatar, or null to remove the avatar data
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAvatar(byte[] bytes) {
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setAvatar(bytes, "image/jpeg");
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Specify the bytes for the avatar to use as well as the mime type.
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param bytes the bytes of the avatar.
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param mimeType the mime type of the avatar.
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAvatar(byte[] bytes, String mimeType) {
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If bytes is null, remove the avatar
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (bytes == null) {
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            removeAvatar();
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Otherwise, add to mappings.
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        String encodedImage = StringUtils.encodeBase64(bytes);
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setAvatar(encodedImage, mimeType);
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Specify the Avatar used for this vCard.
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param encodedImage the Base64 encoded image as String
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param mimeType the MIME type of the image
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void setAvatar(String encodedImage, String mimeType) {
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        photoBinval = encodedImage;
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        photoMimeType = mimeType;
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Return the byte representation of the avatar(if one exists), otherwise returns null if
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * no avatar could be found.
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <b>Example 1</b>
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <pre>
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * // Load Avatar from VCard
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * byte[] avatarBytes = vCard.getAvatar();
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p/>
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * // To create an ImageIcon for Swing applications
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * ImageIcon icon = new ImageIcon(avatar);
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p/>
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * // To create just an image object from the bytes
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * ByteArrayInputStream bais = new ByteArrayInputStream(avatar);
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * try {
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *   Image image = ImageIO.read(bais);
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *  }
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *  catch (IOException e) {
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *    e.printStackTrace();
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * }
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * </pre>
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return byte representation of avatar.
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public byte[] getAvatar() {
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (photoBinval == null) {
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return StringUtils.decodeBase64(photoBinval);
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the MIME Type of the avatar or null if none is set
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the MIME Type of the avatar or null
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getAvatarMimeType() {
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return photoMimeType;
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Common code for getting the bytes of a url.
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param url the url to read.
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static byte[] getBytes(URL url) throws IOException {
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        final String path = url.getPath();
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        final File file = new File(path);
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (file.exists()) {
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return getFileBytes(file);
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return null;
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static byte[] getFileBytes(File file) throws IOException {
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        BufferedInputStream bis = null;
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            bis = new BufferedInputStream(new FileInputStream(file));
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int bytes = (int) file.length();
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            byte[] buffer = new byte[bytes];
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int readBytes = bis.read(buffer);
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (readBytes != buffer.length) {
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new IOException("Entire file not read");
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return buffer;
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        finally {
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (bis != null) {
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                bis.close();
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the SHA-1 Hash of the Avatar image.
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the SHA-1 Hash of the Avatar image.
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getAvatarHash() {
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        byte[] bytes = getAvatar();
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (bytes == null) {
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        MessageDigest digest;
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            digest = MessageDigest.getInstance("SHA-1");
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (NoSuchAlgorithmException e) {
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            e.printStackTrace();
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        digest.update(bytes);
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return StringUtils.encodeHex(digest.digest());
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void updateFN() {
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        StringBuilder sb = new StringBuilder();
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (firstName != null) {
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sb.append(StringUtils.escapeForXML(firstName)).append(' ');
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (middleName != null) {
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sb.append(StringUtils.escapeForXML(middleName)).append(' ');
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (lastName != null) {
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sb.append(StringUtils.escapeForXML(lastName));
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setField("FN", sb.toString());
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Save this vCard for the user connected by 'connection'. Connection should be authenticated
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * and not anonymous.<p>
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * <p/>
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * NOTE: the method is asynchronous and does not wait for the returned value.
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param connection the Connection to use.
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @throws XMPPException thrown if there was an issue setting the VCard in the server.
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void save(Connection connection) throws XMPPException {
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        checkAuthenticated(connection, true);
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setType(IQ.Type.SET);
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setFrom(connection.getUser());
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(getPacketID()));
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.sendPacket(this);
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Packet response = collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Cancel the collector.
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        collector.cancel();
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (response == null) {
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException("No response from server on status set.");
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (response.getError() != null) {
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException(response.getError());
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Load VCard information for a connected user. Connection should be authenticated
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * and not anonymous.
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void load(Connection connection) throws XMPPException {
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        checkAuthenticated(connection, true);
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setFrom(connection.getUser());
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        doLoad(connection, connection.getUser());
542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Load VCard information for a given user. Connection should be authenticated and not anonymous.
546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void load(Connection connection, String user) throws XMPPException {
548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        checkAuthenticated(connection, false);
549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
550d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setTo(user);
551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        doLoad(connection, user);
552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void doLoad(Connection connection, String user) throws XMPPException {
555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setType(Type.GET);
556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        PacketCollector collector = connection.createPacketCollector(
557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                new PacketIDFilter(getPacketID()));
558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connection.sendPacket(this);
559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        VCard result = null;
561d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = (VCard) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (result == null) {
565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                String errorMessage = "Timeout getting VCard information";
566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new XMPPException(errorMessage, new XMPPError(
567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        XMPPError.Condition.request_timeout, errorMessage));
568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (result.getError() != null) {
570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new XMPPException(result.getError());
571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (ClassCastException e) {
574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            System.out.println("No VCard for " + user);
575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        copyFieldsFrom(result);
578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getChildElementXML() {
581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        StringBuilder sb = new StringBuilder();
582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        new VCardWriter(sb).write();
583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return sb.toString();
584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void copyFieldsFrom(VCard from) {
587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        Field[] fields = VCard.class.getDeclaredFields();
588d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (Field field : fields) {
589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (field.getDeclaringClass() == VCard.class &&
590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    !Modifier.isFinal(field.getModifiers())) {
591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                try {
592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    field.setAccessible(true);
593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    field.set(this, field.get(from));
594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                catch (IllegalAccessException e) {
596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    throw new RuntimeException("This cannot happen:" + field, e);
597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void checkAuthenticated(Connection connection, boolean checkForAnonymous) {
603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (connection == null) {
604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalArgumentException("No connection was provided");
605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!connection.isAuthenticated()) {
607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalArgumentException("Connection is not authenticated");
608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (checkForAnonymous && connection.isAnonymous()) {
610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalArgumentException("Connection cannot be anonymous");
611d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean hasContent() {
615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        //noinspection OverlyComplexBooleanExpression
616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return hasNameField()
617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || hasOrganizationFields()
618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || emailHome != null
619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || emailWork != null
620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || otherSimpleFields.size() > 0
621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || otherUnescapableFields.size() > 0
622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || homeAddr.size() > 0
623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || homePhones.size() > 0
624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || workAddr.size() > 0
625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || workPhones.size() > 0
626d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                || photoBinval != null
627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                ;
628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean hasNameField() {
631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return firstName != null || lastName != null || middleName != null;
632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean hasOrganizationFields() {
635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return organization != null || organizationUnit != null;
636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    // Used in tests:
639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean equals(Object o) {
641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (this == o) return true;
642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (o == null || getClass() != o.getClass()) return false;
643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        final VCard vCard = (VCard) o;
645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (emailHome != null ? !emailHome.equals(vCard.emailHome) : vCard.emailHome != null) {
647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
649d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (emailWork != null ? !emailWork.equals(vCard.emailWork) : vCard.emailWork != null) {
650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (firstName != null ? !firstName.equals(vCard.firstName) : vCard.firstName != null) {
653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!homeAddr.equals(vCard.homeAddr)) {
656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!homePhones.equals(vCard.homePhones)) {
659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
660d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (lastName != null ? !lastName.equals(vCard.lastName) : vCard.lastName != null) {
662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (middleName != null ? !middleName.equals(vCard.middleName) : vCard.middleName != null) {
665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (organization != null ?
668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                !organization.equals(vCard.organization) : vCard.organization != null) {
669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (organizationUnit != null ?
672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                !organizationUnit.equals(vCard.organizationUnit) : vCard.organizationUnit != null) {
673d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
674d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
675d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!otherSimpleFields.equals(vCard.otherSimpleFields)) {
676d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
677d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
678d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!workAddr.equals(vCard.workAddr)) {
679d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
680d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
681d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (photoBinval != null ? !photoBinval.equals(vCard.photoBinval) : vCard.photoBinval != null) {
682d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return false;
683d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
684d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
685d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return workPhones.equals(vCard.workPhones);
686d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
687d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
688d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public int hashCode() {
689d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        int result;
690d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = homePhones.hashCode();
691d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + workPhones.hashCode();
692d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + homeAddr.hashCode();
693d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + workAddr.hashCode();
694d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (firstName != null ? firstName.hashCode() : 0);
695d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (lastName != null ? lastName.hashCode() : 0);
696d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (middleName != null ? middleName.hashCode() : 0);
697d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (emailHome != null ? emailHome.hashCode() : 0);
698d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (emailWork != null ? emailWork.hashCode() : 0);
699d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (organization != null ? organization.hashCode() : 0);
700d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (organizationUnit != null ? organizationUnit.hashCode() : 0);
701d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + otherSimpleFields.hashCode();
702d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        result = 29 * result + (photoBinval != null ? photoBinval.hashCode() : 0);
703d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return result;
704d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
705d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
706d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String toString() {
707d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return getChildElementXML();
708d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
709d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
710d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    //==============================================================
711d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
712d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private class VCardWriter {
713d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
714d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private final StringBuilder sb;
715d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
716d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        VCardWriter(StringBuilder sb) {
717d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.sb = sb;
718d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
719d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
720d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public void write() {
721d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendTag("vCard", "xmlns", "vcard-temp", hasContent(), new ContentBuilder() {
722d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void addTagContent() {
723d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    buildActualContent();
724d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
725d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            });
726d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
727d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
728d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void buildActualContent() {
729d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (hasNameField()) {
730d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendN();
731d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
732d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
733d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendOrganization();
734d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendGenericFields();
735d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendPhoto();
736d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
737d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendEmail(emailWork, "WORK");
738d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendEmail(emailHome, "HOME");
739d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
740d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendPhones(workPhones, "WORK");
741d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendPhones(homePhones, "HOME");
742d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
743d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendAddress(workAddr, "WORK");
744d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendAddress(homeAddr, "HOME");
745d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
746d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
747d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendPhoto() {
748d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (photoBinval == null)
749d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return;
750d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
751d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendTag("PHOTO", true, new ContentBuilder() {
752d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void addTagContent() {
753d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    appendTag("BINVAL", photoBinval); // No need to escape photoBinval, as it's already Base64 encoded
754d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    appendTag("TYPE", StringUtils.escapeForXML(photoMimeType));
755d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
756d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            });
757d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
758d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendEmail(final String email, final String type) {
759d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (email != null) {
760d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag("EMAIL", true, new ContentBuilder() {
761d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    public void addTagContent() {
762d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag(type);
763d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag("INTERNET");
764d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag("PREF");
765d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendTag("USERID", StringUtils.escapeForXML(email));
766d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
767d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                });
768d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
769d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
770d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
771d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendPhones(Map<String, String> phones, final String code) {
772d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Iterator<Map.Entry<String, String>> it = phones.entrySet().iterator();
773d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            while (it.hasNext()) {
774d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                final Map.Entry<String,String> entry = it.next();
775d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag("TEL", true, new ContentBuilder() {
776d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    public void addTagContent() {
777d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag(entry.getKey());
778d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag(code);
779d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendTag("NUMBER", StringUtils.escapeForXML(entry.getValue()));
780d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
781d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                });
782d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
783d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
784d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
785d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendAddress(final Map<String, String> addr, final String code) {
786d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (addr.size() > 0) {
787d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag("ADR", true, new ContentBuilder() {
788d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    public void addTagContent() {
789d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendEmptyTag(code);
790d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
791d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        Iterator<Map.Entry<String, String>> it = addr.entrySet().iterator();
792d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        while (it.hasNext()) {
793d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            final Entry<String, String> entry = it.next();
794d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            appendTag(entry.getKey(), StringUtils.escapeForXML(entry.getValue()));
795d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
796d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
797d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                });
798d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
799d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
800d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
801d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendEmptyTag(Object tag) {
802d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sb.append('<').append(tag).append("/>");
803d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
804d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
805d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendGenericFields() {
806d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Iterator<Map.Entry<String, String>> it = otherSimpleFields.entrySet().iterator();
807d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            while (it.hasNext()) {
808d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Map.Entry<String, String> entry = it.next();
809d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag(entry.getKey().toString(),
810d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        StringUtils.escapeForXML(entry.getValue()));
811d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
812d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
813d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            it = otherUnescapableFields.entrySet().iterator();
814d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            while (it.hasNext()) {
815d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Map.Entry<String, String> entry = it.next();
816d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag(entry.getKey().toString(),entry.getValue());
817d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
818d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
819d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
820d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendOrganization() {
821d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (hasOrganizationFields()) {
822d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                appendTag("ORG", true, new ContentBuilder() {
823d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    public void addTagContent() {
824d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendTag("ORGNAME", StringUtils.escapeForXML(organization));
825d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        appendTag("ORGUNIT", StringUtils.escapeForXML(organizationUnit));
826d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
827d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                });
828d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
829d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
830d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
831d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendN() {
832d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendTag("N", true, new ContentBuilder() {
833d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void addTagContent() {
834d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    appendTag("FAMILY", StringUtils.escapeForXML(lastName));
835d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    appendTag("GIVEN", StringUtils.escapeForXML(firstName));
836d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    appendTag("MIDDLE", StringUtils.escapeForXML(middleName));
837d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
838d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            });
839d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
840d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
841d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendTag(String tag, String attr, String attrValue, boolean hasContent,
842d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                ContentBuilder builder) {
843d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sb.append('<').append(tag);
844d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (attr != null) {
845d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                sb.append(' ').append(attr).append('=').append('\'').append(attrValue).append('\'');
846d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
847d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
848d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (hasContent) {
849d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                sb.append('>');
850d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                builder.addTagContent();
851d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                sb.append("</").append(tag).append(">\n");
852d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
853d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            else {
854d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                sb.append("/>\n");
855d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
856d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
857d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
858d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendTag(String tag, boolean hasContent, ContentBuilder builder) {
859d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendTag(tag, null, null, hasContent, builder);
860d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
861d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
862d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private void appendTag(String tag, final String tagText) {
863d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (tagText == null) return;
864d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            final ContentBuilder contentBuilder = new ContentBuilder() {
865d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void addTagContent() {
866d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    sb.append(tagText.trim());
867d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
868d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            };
869d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            appendTag(tag, true, contentBuilder);
870d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
871d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
872d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
873d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
874d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    //==============================================================
875d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
876d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private interface ContentBuilder {
877d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
878d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        void addTagContent();
879d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
880d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
881d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    //==============================================================
882d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
883d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
884