mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-12-12 14:01:08 +01:00
Prefix subprojects with 'smack-'
instead of using the old baseName=smack appendix=project.name approach, we are now going convention over configuration and renaming the subprojects directories to the proper name. Having a prefix is actually very helpful, because the resulting libraries will be named like the subproject. And a core-4.0.0-rc1.jar is not as explicit about what it actually *is* as a smack-core-4.0.0-rc1.jar. SMACK-265
This commit is contained in:
parent
b6fb1f3743
commit
91fd15ad86
758 changed files with 42 additions and 42 deletions
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2014 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.vcardtemp;
|
||||
|
||||
import org.jivesoftware.smack.ConnectionCreationListener;
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
|
||||
public class VCardManager {
|
||||
public static final String NAMESPACE = "vcard-temp";
|
||||
public static final String ELEMENT = "vCard";
|
||||
|
||||
static {
|
||||
XMPPConnection.addConnectionCreationListener(new ConnectionCreationListener() {
|
||||
@Override
|
||||
public void connectionCreated(XMPPConnection connection) {
|
||||
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(NAMESPACE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given entity understands the vCard-XML format and allows the exchange of such.
|
||||
*
|
||||
* @param jid
|
||||
* @param connection
|
||||
* @return true if the given entity understands the vCard-XML format and exchange.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public static boolean isSupported(String jid, XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
return ServiceDiscoveryManager.getInstanceFor(connection).supportsFeature(jid, NAMESPACE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,859 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jivesoftware.smackx.vcardtemp.packet;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.vcardtemp.VCardManager;
|
||||
|
||||
/**
|
||||
* A VCard class for use with the
|
||||
* <a href="http://www.jivesoftware.org/smack/" target="_blank">SMACK jabber library</a>.<p>
|
||||
* <p/>
|
||||
* You should refer to the
|
||||
* <a href="http://www.jabber.org/jeps/jep-0054.html" target="_blank">JEP-54 documentation</a>.<p>
|
||||
* <p/>
|
||||
* Please note that this class is incomplete but it does provide the most commonly found
|
||||
* information in vCards. Also remember that VCard transfer is not a standard, and the protocol
|
||||
* may change or be replaced.<p>
|
||||
* <p/>
|
||||
* <b>Usage:</b>
|
||||
* <pre>
|
||||
* <p/>
|
||||
* // To save VCard:
|
||||
* <p/>
|
||||
* VCard vCard = new VCard();
|
||||
* vCard.setFirstName("kir");
|
||||
* vCard.setLastName("max");
|
||||
* vCard.setEmailHome("foo@fee.bar");
|
||||
* vCard.setJabberId("jabber@id.org");
|
||||
* vCard.setOrganization("Jetbrains, s.r.o");
|
||||
* vCard.setNickName("KIR");
|
||||
* <p/>
|
||||
* vCard.setField("TITLE", "Mr");
|
||||
* vCard.setAddressFieldHome("STREET", "Some street");
|
||||
* vCard.setAddressFieldWork("CTRY", "US");
|
||||
* vCard.setPhoneWork("FAX", "3443233");
|
||||
* <p/>
|
||||
* vCard.save(connection);
|
||||
* <p/>
|
||||
* // To load VCard:
|
||||
* <p/>
|
||||
* VCard vCard = new VCard();
|
||||
* vCard.load(conn); // load own VCard
|
||||
* vCard.load(conn, "joe@foo.bar"); // load someone's VCard
|
||||
* </pre>
|
||||
*
|
||||
* @author Kirill Maximov (kir@maxkir.com)
|
||||
*/
|
||||
public class VCard extends IQ {
|
||||
private static final Logger LOGGER = Logger.getLogger(VCard.class.getName());
|
||||
|
||||
private static final String DEFAULT_MIME_TYPE = "image/jpeg";
|
||||
|
||||
/**
|
||||
* Phone types:
|
||||
* VOICE?, FAX?, PAGER?, MSG?, CELL?, VIDEO?, BBS?, MODEM?, ISDN?, PCS?, PREF?
|
||||
*/
|
||||
private Map<String, String> homePhones = new HashMap<String, String>();
|
||||
private Map<String, String> workPhones = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Address types:
|
||||
* POSTAL?, PARCEL?, (DOM | INTL)?, PREF?, POBOX?, EXTADR?, STREET?, LOCALITY?,
|
||||
* REGION?, PCODE?, CTRY?
|
||||
*/
|
||||
private Map<String, String> homeAddr = new HashMap<String, String>();
|
||||
private Map<String, String> workAddr = new HashMap<String, String>();
|
||||
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String middleName;
|
||||
|
||||
private String emailHome;
|
||||
private String emailWork;
|
||||
|
||||
private String organization;
|
||||
private String organizationUnit;
|
||||
|
||||
private String photoMimeType;
|
||||
private String photoBinval;
|
||||
|
||||
/**
|
||||
* Such as DESC ROLE GEO etc.. see JEP-0054
|
||||
*/
|
||||
private Map<String, String> otherSimpleFields = new HashMap<String, String>();
|
||||
|
||||
// fields that, as they are should not be escaped before forwarding to the server
|
||||
private Map<String, String> otherUnescapableFields = new HashMap<String, String>();
|
||||
|
||||
public VCard() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set generic VCard field.
|
||||
*
|
||||
* @param field value of field. Possible values: NICKNAME, PHOTO, BDAY, JABBERID, MAILER, TZ,
|
||||
* GEO, TITLE, ROLE, LOGO, NOTE, PRODID, REV, SORT-STRING, SOUND, UID, URL, DESC.
|
||||
*/
|
||||
public String getField(String field) {
|
||||
return otherSimpleFields.get(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set generic VCard field.
|
||||
*
|
||||
* @param value value of field
|
||||
* @param field field to set. See {@link #getField(String)}
|
||||
* @see #getField(String)
|
||||
*/
|
||||
public void setField(String field, String value) {
|
||||
setField(field, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set generic, unescapable VCard field. If unescabale is set to true, XML maybe a part of the
|
||||
* value.
|
||||
*
|
||||
* @param value value of field
|
||||
* @param field field to set. See {@link #getField(String)}
|
||||
* @param isUnescapable True if the value should not be escaped, and false if it should.
|
||||
*/
|
||||
public void setField(String field, String value, boolean isUnescapable) {
|
||||
if (!isUnescapable) {
|
||||
otherSimpleFields.put(field, value);
|
||||
}
|
||||
else {
|
||||
otherUnescapableFields.put(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
// Update FN field
|
||||
updateFN();
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
// Update FN field
|
||||
updateFN();
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
// Update FN field
|
||||
updateFN();
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return otherSimpleFields.get("NICKNAME");
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
otherSimpleFields.put("NICKNAME", nickName);
|
||||
}
|
||||
|
||||
public String getEmailHome() {
|
||||
return emailHome;
|
||||
}
|
||||
|
||||
public void setEmailHome(String email) {
|
||||
this.emailHome = email;
|
||||
}
|
||||
|
||||
public String getEmailWork() {
|
||||
return emailWork;
|
||||
}
|
||||
|
||||
public void setEmailWork(String emailWork) {
|
||||
this.emailWork = emailWork;
|
||||
}
|
||||
|
||||
public String getJabberId() {
|
||||
return otherSimpleFields.get("JABBERID");
|
||||
}
|
||||
|
||||
public void setJabberId(String jabberId) {
|
||||
otherSimpleFields.put("JABBERID", jabberId);
|
||||
}
|
||||
|
||||
public String getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(String organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public String getOrganizationUnit() {
|
||||
return organizationUnit;
|
||||
}
|
||||
|
||||
public void setOrganizationUnit(String organizationUnit) {
|
||||
this.organizationUnit = organizationUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get home address field
|
||||
*
|
||||
* @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
|
||||
* LOCALITY, REGION, PCODE, CTRY
|
||||
*/
|
||||
public String getAddressFieldHome(String addrField) {
|
||||
return homeAddr.get(addrField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set home address field
|
||||
*
|
||||
* @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
|
||||
* LOCALITY, REGION, PCODE, CTRY
|
||||
*/
|
||||
public void setAddressFieldHome(String addrField, String value) {
|
||||
homeAddr.put(addrField, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get work address field
|
||||
*
|
||||
* @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
|
||||
* LOCALITY, REGION, PCODE, CTRY
|
||||
*/
|
||||
public String getAddressFieldWork(String addrField) {
|
||||
return workAddr.get(addrField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set work address field
|
||||
*
|
||||
* @param addrField one of POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
|
||||
* LOCALITY, REGION, PCODE, CTRY
|
||||
*/
|
||||
public void setAddressFieldWork(String addrField, String value) {
|
||||
workAddr.put(addrField, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set home phone number
|
||||
*
|
||||
* @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
|
||||
* @param phoneNum phone number
|
||||
*/
|
||||
public void setPhoneHome(String phoneType, String phoneNum) {
|
||||
homePhones.put(phoneType, phoneNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get home phone number
|
||||
*
|
||||
* @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
|
||||
*/
|
||||
public String getPhoneHome(String phoneType) {
|
||||
return homePhones.get(phoneType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set work phone number
|
||||
*
|
||||
* @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
|
||||
* @param phoneNum phone number
|
||||
*/
|
||||
public void setPhoneWork(String phoneType, String phoneNum) {
|
||||
workPhones.put(phoneType, phoneNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get work phone number
|
||||
*
|
||||
* @param phoneType one of VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
|
||||
*/
|
||||
public String getPhoneWork(String phoneType) {
|
||||
return workPhones.get(phoneType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the avatar for the VCard by specifying the url to the image.
|
||||
*
|
||||
* @param avatarURL the url to the image(png,jpeg,gif,bmp)
|
||||
*/
|
||||
public void setAvatar(URL avatarURL) {
|
||||
byte[] bytes = new byte[0];
|
||||
try {
|
||||
bytes = getBytes(avatarURL);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting bytes from URL: " + avatarURL, e);
|
||||
}
|
||||
|
||||
setAvatar(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the avatar from the vCard
|
||||
*
|
||||
* This is done by setting the PHOTO value to the empty string as defined in XEP-0153
|
||||
*/
|
||||
public void removeAvatar() {
|
||||
// Remove avatar (if any)
|
||||
photoBinval = null;
|
||||
photoMimeType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the bytes of the JPEG for the avatar to use.
|
||||
* If bytes is null, then the avatar will be removed.
|
||||
* 'image/jpeg' will be used as MIME type.
|
||||
*
|
||||
* @param bytes the bytes of the avatar, or null to remove the avatar data
|
||||
*/
|
||||
public void setAvatar(byte[] bytes) {
|
||||
setAvatar(bytes, DEFAULT_MIME_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the bytes for the avatar to use as well as the mime type.
|
||||
*
|
||||
* @param bytes the bytes of the avatar.
|
||||
* @param mimeType the mime type of the avatar.
|
||||
*/
|
||||
public void setAvatar(byte[] bytes, String mimeType) {
|
||||
// If bytes is null, remove the avatar
|
||||
if (bytes == null) {
|
||||
removeAvatar();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, add to mappings.
|
||||
String encodedImage = StringUtils.encodeBase64(bytes);
|
||||
|
||||
setAvatar(encodedImage, mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the Avatar used for this vCard.
|
||||
*
|
||||
* @param encodedImage the Base64 encoded image as String
|
||||
* @param mimeType the MIME type of the image
|
||||
*/
|
||||
public void setAvatar(String encodedImage, String mimeType) {
|
||||
photoBinval = encodedImage;
|
||||
photoMimeType = mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoded avatar string. This is used by the provider.
|
||||
*
|
||||
* @param encodedAvatar the encoded avatar string.
|
||||
* @deprecated Use {@link #setAvatar(String, String)} instead.
|
||||
*/
|
||||
public void setEncodedImage(String encodedAvatar) {
|
||||
setAvatar(encodedAvatar, DEFAULT_MIME_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the byte representation of the avatar(if one exists), otherwise returns null if
|
||||
* no avatar could be found.
|
||||
* <b>Example 1</b>
|
||||
* <pre>
|
||||
* // Load Avatar from VCard
|
||||
* byte[] avatarBytes = vCard.getAvatar();
|
||||
* <p/>
|
||||
* // To create an ImageIcon for Swing applications
|
||||
* ImageIcon icon = new ImageIcon(avatar);
|
||||
* <p/>
|
||||
* // To create just an image object from the bytes
|
||||
* ByteArrayInputStream bais = new ByteArrayInputStream(avatar);
|
||||
* try {
|
||||
* Image image = ImageIO.read(bais);
|
||||
* }
|
||||
* catch (IOException e) {
|
||||
* e.printStackTrace();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @return byte representation of avatar.
|
||||
*/
|
||||
public byte[] getAvatar() {
|
||||
if (photoBinval == null) {
|
||||
return null;
|
||||
}
|
||||
return StringUtils.decodeBase64(photoBinval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MIME Type of the avatar or null if none is set
|
||||
*
|
||||
* @return the MIME Type of the avatar or null
|
||||
*/
|
||||
public String getAvatarMimeType() {
|
||||
return photoMimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common code for getting the bytes of a url.
|
||||
*
|
||||
* @param url the url to read.
|
||||
*/
|
||||
public static byte[] getBytes(URL url) throws IOException {
|
||||
final String path = url.getPath();
|
||||
final File file = new File(path);
|
||||
if (file.exists()) {
|
||||
return getFileBytes(file);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] getFileBytes(File file) throws IOException {
|
||||
BufferedInputStream bis = null;
|
||||
try {
|
||||
bis = new BufferedInputStream(new FileInputStream(file));
|
||||
int bytes = (int) file.length();
|
||||
byte[] buffer = new byte[bytes];
|
||||
int readBytes = bis.read(buffer);
|
||||
if (readBytes != buffer.length) {
|
||||
throw new IOException("Entire file not read");
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
finally {
|
||||
if (bis != null) {
|
||||
bis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA-1 Hash of the Avatar image.
|
||||
*
|
||||
* @return the SHA-1 Hash of the Avatar image.
|
||||
*/
|
||||
public String getAvatarHash() {
|
||||
byte[] bytes = getAvatar();
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MessageDigest digest;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-1");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to get message digest", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
digest.update(bytes);
|
||||
return StringUtils.encodeHex(digest.digest());
|
||||
}
|
||||
|
||||
private void updateFN() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (firstName != null) {
|
||||
sb.append(StringUtils.escapeForXML(firstName)).append(' ');
|
||||
}
|
||||
if (middleName != null) {
|
||||
sb.append(StringUtils.escapeForXML(middleName)).append(' ');
|
||||
}
|
||||
if (lastName != null) {
|
||||
sb.append(StringUtils.escapeForXML(lastName));
|
||||
}
|
||||
setField("FN", sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save this vCard for the user connected by 'connection'. XMPPConnection should be authenticated
|
||||
* and not anonymous.<p>
|
||||
* <p/>
|
||||
* NOTE: the method is asynchronous and does not wait for the returned value.
|
||||
*
|
||||
* @param connection the XMPPConnection to use.
|
||||
* @throws XMPPErrorException thrown if there was an issue setting the VCard in the server.
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public void save(XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
checkAuthenticated(connection, true);
|
||||
|
||||
setType(IQ.Type.SET);
|
||||
setFrom(connection.getUser());
|
||||
connection.createPacketCollectorAndSend(this).nextResultOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load VCard information for a connected user. XMPPConnection should be authenticated
|
||||
* and not anonymous.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public void load(XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
checkAuthenticated(connection, true);
|
||||
|
||||
setFrom(connection.getUser());
|
||||
doLoad(connection, connection.getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load VCard information for a given user. XMPPConnection should be authenticated and not anonymous.
|
||||
* @throws XMPPErrorException
|
||||
* @throws NoResponseException if there was no response from the server.
|
||||
* @throws NotConnectedException
|
||||
*/
|
||||
public void load(XMPPConnection connection, String user) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
checkAuthenticated(connection, false);
|
||||
|
||||
setTo(user);
|
||||
doLoad(connection, user);
|
||||
}
|
||||
|
||||
private void doLoad(XMPPConnection connection, String user) throws NoResponseException, XMPPErrorException, NotConnectedException {
|
||||
setType(Type.GET);
|
||||
VCard result = (VCard) connection.createPacketCollectorAndSend(this).nextResultOrThrow();
|
||||
copyFieldsFrom(result);
|
||||
}
|
||||
|
||||
public String getChildElementXML() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
new VCardWriter(sb).write();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void copyFieldsFrom(VCard from) {
|
||||
Field[] fields = VCard.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (field.getDeclaringClass() == VCard.class &&
|
||||
!Modifier.isFinal(field.getModifiers())) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(this, field.get(from));
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("This cannot happen:" + field, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAuthenticated(XMPPConnection connection, boolean checkForAnonymous) {
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("No connection was provided");
|
||||
}
|
||||
if (!connection.isAuthenticated()) {
|
||||
throw new IllegalArgumentException("XMPPConnection is not authenticated");
|
||||
}
|
||||
if (checkForAnonymous && connection.isAnonymous()) {
|
||||
throw new IllegalArgumentException("XMPPConnection cannot be anonymous");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasContent() {
|
||||
//noinspection OverlyComplexBooleanExpression
|
||||
return hasNameField()
|
||||
|| hasOrganizationFields()
|
||||
|| emailHome != null
|
||||
|| emailWork != null
|
||||
|| otherSimpleFields.size() > 0
|
||||
|| otherUnescapableFields.size() > 0
|
||||
|| homeAddr.size() > 0
|
||||
|| homePhones.size() > 0
|
||||
|| workAddr.size() > 0
|
||||
|| workPhones.size() > 0
|
||||
|| photoBinval != null
|
||||
;
|
||||
}
|
||||
|
||||
private boolean hasNameField() {
|
||||
return firstName != null || lastName != null || middleName != null;
|
||||
}
|
||||
|
||||
private boolean hasOrganizationFields() {
|
||||
return organization != null || organizationUnit != null;
|
||||
}
|
||||
|
||||
// Used in tests:
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final VCard vCard = (VCard) o;
|
||||
|
||||
if (emailHome != null ? !emailHome.equals(vCard.emailHome) : vCard.emailHome != null) {
|
||||
return false;
|
||||
}
|
||||
if (emailWork != null ? !emailWork.equals(vCard.emailWork) : vCard.emailWork != null) {
|
||||
return false;
|
||||
}
|
||||
if (firstName != null ? !firstName.equals(vCard.firstName) : vCard.firstName != null) {
|
||||
return false;
|
||||
}
|
||||
if (!homeAddr.equals(vCard.homeAddr)) {
|
||||
return false;
|
||||
}
|
||||
if (!homePhones.equals(vCard.homePhones)) {
|
||||
return false;
|
||||
}
|
||||
if (lastName != null ? !lastName.equals(vCard.lastName) : vCard.lastName != null) {
|
||||
return false;
|
||||
}
|
||||
if (middleName != null ? !middleName.equals(vCard.middleName) : vCard.middleName != null) {
|
||||
return false;
|
||||
}
|
||||
if (organization != null ?
|
||||
!organization.equals(vCard.organization) : vCard.organization != null) {
|
||||
return false;
|
||||
}
|
||||
if (organizationUnit != null ?
|
||||
!organizationUnit.equals(vCard.organizationUnit) : vCard.organizationUnit != null) {
|
||||
return false;
|
||||
}
|
||||
if (!otherSimpleFields.equals(vCard.otherSimpleFields)) {
|
||||
return false;
|
||||
}
|
||||
if (!workAddr.equals(vCard.workAddr)) {
|
||||
return false;
|
||||
}
|
||||
if (photoBinval != null ? !photoBinval.equals(vCard.photoBinval) : vCard.photoBinval != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return workPhones.equals(vCard.workPhones);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = homePhones.hashCode();
|
||||
result = 29 * result + workPhones.hashCode();
|
||||
result = 29 * result + homeAddr.hashCode();
|
||||
result = 29 * result + workAddr.hashCode();
|
||||
result = 29 * result + (firstName != null ? firstName.hashCode() : 0);
|
||||
result = 29 * result + (lastName != null ? lastName.hashCode() : 0);
|
||||
result = 29 * result + (middleName != null ? middleName.hashCode() : 0);
|
||||
result = 29 * result + (emailHome != null ? emailHome.hashCode() : 0);
|
||||
result = 29 * result + (emailWork != null ? emailWork.hashCode() : 0);
|
||||
result = 29 * result + (organization != null ? organization.hashCode() : 0);
|
||||
result = 29 * result + (organizationUnit != null ? organizationUnit.hashCode() : 0);
|
||||
result = 29 * result + otherSimpleFields.hashCode();
|
||||
result = 29 * result + (photoBinval != null ? photoBinval.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getChildElementXML();
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
|
||||
private class VCardWriter {
|
||||
|
||||
private final StringBuilder sb;
|
||||
|
||||
VCardWriter(StringBuilder sb) {
|
||||
this.sb = sb;
|
||||
}
|
||||
|
||||
public void write() {
|
||||
appendTag(VCardManager.ELEMENT, "xmlns", VCardManager.NAMESPACE, hasContent(), new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
buildActualContent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void buildActualContent() {
|
||||
if (hasNameField()) {
|
||||
appendN();
|
||||
}
|
||||
|
||||
appendOrganization();
|
||||
appendGenericFields();
|
||||
appendPhoto();
|
||||
|
||||
appendEmail(emailWork, "WORK");
|
||||
appendEmail(emailHome, "HOME");
|
||||
|
||||
appendPhones(workPhones, "WORK");
|
||||
appendPhones(homePhones, "HOME");
|
||||
|
||||
appendAddress(workAddr, "WORK");
|
||||
appendAddress(homeAddr, "HOME");
|
||||
}
|
||||
|
||||
private void appendPhoto() {
|
||||
if (photoBinval == null)
|
||||
return;
|
||||
|
||||
appendTag("PHOTO", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendTag("BINVAL", photoBinval); // No need to escape photoBinval, as it's already Base64 encoded
|
||||
appendTag("TYPE", StringUtils.escapeForXML(photoMimeType));
|
||||
}
|
||||
});
|
||||
}
|
||||
private void appendEmail(final String email, final String type) {
|
||||
if (email != null) {
|
||||
appendTag("EMAIL", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendEmptyTag(type);
|
||||
appendEmptyTag("INTERNET");
|
||||
appendEmptyTag("PREF");
|
||||
appendTag("USERID", StringUtils.escapeForXML(email));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void appendPhones(Map<String, String> phones, final String code) {
|
||||
for (final Map.Entry<String,String> entry : phones.entrySet()) {
|
||||
appendTag("TEL", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendEmptyTag(entry.getKey());
|
||||
appendEmptyTag(code);
|
||||
appendTag("NUMBER", StringUtils.escapeForXML(entry.getValue()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void appendAddress(final Map<String, String> addr, final String code) {
|
||||
if (addr.size() > 0) {
|
||||
appendTag("ADR", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendEmptyTag(code);
|
||||
|
||||
for (final Entry<String, String> entry : addr.entrySet()) {
|
||||
appendTag(entry.getKey(), StringUtils.escapeForXML(entry.getValue()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void appendEmptyTag(Object tag) {
|
||||
sb.append('<').append(tag).append("/>");
|
||||
}
|
||||
|
||||
private void appendGenericFields() {
|
||||
for (Map.Entry<String, String> entry : otherSimpleFields.entrySet()) {
|
||||
appendTag(entry.getKey().toString(),
|
||||
StringUtils.escapeForXML(entry.getValue()));
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : otherUnescapableFields.entrySet()) {
|
||||
appendTag(entry.getKey().toString(),entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void appendOrganization() {
|
||||
if (hasOrganizationFields()) {
|
||||
appendTag("ORG", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendTag("ORGNAME", StringUtils.escapeForXML(organization));
|
||||
appendTag("ORGUNIT", StringUtils.escapeForXML(organizationUnit));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void appendN() {
|
||||
appendTag("N", true, new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
appendTag("FAMILY", StringUtils.escapeForXML(lastName));
|
||||
appendTag("GIVEN", StringUtils.escapeForXML(firstName));
|
||||
appendTag("MIDDLE", StringUtils.escapeForXML(middleName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void appendTag(String tag, String attr, String attrValue, boolean hasContent,
|
||||
ContentBuilder builder) {
|
||||
sb.append('<').append(tag);
|
||||
if (attr != null) {
|
||||
sb.append(' ').append(attr).append('=').append('\'').append(attrValue).append('\'');
|
||||
}
|
||||
|
||||
if (hasContent) {
|
||||
sb.append('>');
|
||||
builder.addTagContent();
|
||||
sb.append("</").append(tag).append(">\n");
|
||||
}
|
||||
else {
|
||||
sb.append("/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendTag(String tag, boolean hasContent, ContentBuilder builder) {
|
||||
appendTag(tag, null, null, hasContent, builder);
|
||||
}
|
||||
|
||||
private void appendTag(String tag, final CharSequence tagText) {
|
||||
if (tagText == null) return;
|
||||
final ContentBuilder contentBuilder = new ContentBuilder() {
|
||||
public void addTagContent() {
|
||||
sb.append(tagText.toString().trim());
|
||||
}
|
||||
};
|
||||
appendTag(tag, true, contentBuilder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
|
||||
private interface ContentBuilder {
|
||||
|
||||
void addTagContent();
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.vcardtemp.provider;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.provider.IQProvider;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* vCard provider.
|
||||
*
|
||||
* @author Gaston Dombiak
|
||||
* @author Derek DeMoro
|
||||
*/
|
||||
public class VCardProvider implements IQProvider {
|
||||
private static final Logger LOGGER = Logger.getLogger(VCardProvider.class.getName());
|
||||
|
||||
private static final String PREFERRED_ENCODING = "UTF-8";
|
||||
|
||||
public IQ parseIQ(XmlPullParser parser) throws Exception {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
int event = parser.getEventType();
|
||||
// get the content
|
||||
while (true) {
|
||||
switch (event) {
|
||||
case XmlPullParser.TEXT:
|
||||
// We must re-escape the xml so that the DOM won't throw an exception
|
||||
sb.append(StringUtils.escapeForXML(parser.getText()));
|
||||
break;
|
||||
case XmlPullParser.START_TAG:
|
||||
sb.append('<').append(parser.getName()).append('>');
|
||||
break;
|
||||
case XmlPullParser.END_TAG:
|
||||
sb.append("</").append(parser.getName()).append('>');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (event == XmlPullParser.END_TAG && "vCard".equals(parser.getName())) break;
|
||||
|
||||
event = parser.next();
|
||||
}
|
||||
}
|
||||
catch (XmlPullParserException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception parsing VCard", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOGGER.log(Level.SEVERE, "Exception parsing VCard", e);
|
||||
}
|
||||
|
||||
String xmlText = sb.toString();
|
||||
return createVCardFromXML(xmlText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a users vCard from xml file.
|
||||
*
|
||||
* @param xml the xml representing a users vCard.
|
||||
* @return the VCard.
|
||||
* @throws Exception if an exception occurs.
|
||||
*/
|
||||
public static VCard createVCardFromXML(String xml) throws Exception {
|
||||
VCard vCard = new VCard();
|
||||
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document document = documentBuilder.parse(
|
||||
new ByteArrayInputStream(xml.getBytes(PREFERRED_ENCODING)));
|
||||
|
||||
new VCardReader(vCard, document).initializeFields();
|
||||
return vCard;
|
||||
}
|
||||
|
||||
private static class VCardReader {
|
||||
|
||||
private final VCard vCard;
|
||||
private final Document document;
|
||||
|
||||
VCardReader(VCard vCard, Document document) {
|
||||
this.vCard = vCard;
|
||||
this.document = document;
|
||||
}
|
||||
|
||||
public void initializeFields() {
|
||||
vCard.setFirstName(getTagContents("GIVEN"));
|
||||
vCard.setLastName(getTagContents("FAMILY"));
|
||||
vCard.setMiddleName(getTagContents("MIDDLE"));
|
||||
setupPhoto();
|
||||
|
||||
setupEmails();
|
||||
|
||||
vCard.setOrganization(getTagContents("ORGNAME"));
|
||||
vCard.setOrganizationUnit(getTagContents("ORGUNIT"));
|
||||
|
||||
setupSimpleFields();
|
||||
|
||||
setupPhones();
|
||||
setupAddresses();
|
||||
}
|
||||
|
||||
private void setupPhoto() {
|
||||
String binval = null;
|
||||
String mimetype = null;
|
||||
|
||||
NodeList photo = document.getElementsByTagName("PHOTO");
|
||||
if (photo.getLength() != 1)
|
||||
return;
|
||||
|
||||
Node photoNode = photo.item(0);
|
||||
NodeList childNodes = photoNode.getChildNodes();
|
||||
|
||||
int childNodeCount = childNodes.getLength();
|
||||
List<Node> nodes = new ArrayList<Node>(childNodeCount);
|
||||
for (int i = 0; i < childNodeCount; i++)
|
||||
nodes.add(childNodes.item(i));
|
||||
|
||||
String name = null;
|
||||
String value = null;
|
||||
for (Node n : nodes) {
|
||||
name = n.getNodeName();
|
||||
value = n.getTextContent();
|
||||
if (name.equals("BINVAL")) {
|
||||
binval = value;
|
||||
}
|
||||
else if (name.equals("TYPE")) {
|
||||
mimetype = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (binval == null || mimetype == null)
|
||||
return;
|
||||
|
||||
vCard.setAvatar(binval, mimetype);
|
||||
}
|
||||
|
||||
private void setupEmails() {
|
||||
NodeList nodes = document.getElementsByTagName("USERID");
|
||||
if (nodes == null) return;
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Element element = (Element) nodes.item(i);
|
||||
if ("WORK".equals(element.getParentNode().getFirstChild().getNodeName())) {
|
||||
vCard.setEmailWork(getTextContent(element));
|
||||
}
|
||||
else {
|
||||
vCard.setEmailHome(getTextContent(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPhones() {
|
||||
NodeList allPhones = document.getElementsByTagName("TEL");
|
||||
if (allPhones == null) return;
|
||||
for (int i = 0; i < allPhones.getLength(); i++) {
|
||||
NodeList nodes = allPhones.item(i).getChildNodes();
|
||||
String type = null;
|
||||
String code = null;
|
||||
String value = null;
|
||||
for (int j = 0; j < nodes.getLength(); j++) {
|
||||
Node node = nodes.item(j);
|
||||
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
|
||||
String nodeName = node.getNodeName();
|
||||
if ("NUMBER".equals(nodeName)) {
|
||||
value = getTextContent(node);
|
||||
}
|
||||
else if (isWorkHome(nodeName)) {
|
||||
type = nodeName;
|
||||
}
|
||||
else {
|
||||
code = nodeName;
|
||||
}
|
||||
}
|
||||
if (value == null) continue;
|
||||
if (code == null)
|
||||
code = "VOICE";
|
||||
if ("HOME".equals(type)) {
|
||||
vCard.setPhoneHome(code, value);
|
||||
}
|
||||
else { // By default, setup work phone
|
||||
vCard.setPhoneWork(code, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWorkHome(String nodeName) {
|
||||
return "HOME".equals(nodeName) || "WORK".equals(nodeName);
|
||||
}
|
||||
|
||||
private void setupAddresses() {
|
||||
NodeList allAddresses = document.getElementsByTagName("ADR");
|
||||
if (allAddresses == null) return;
|
||||
for (int i = 0; i < allAddresses.getLength(); i++) {
|
||||
Element addressNode = (Element) allAddresses.item(i);
|
||||
|
||||
String type = null;
|
||||
List<String> code = new ArrayList<String>();
|
||||
List<String> value = new ArrayList<String>();
|
||||
NodeList childNodes = addressNode.getChildNodes();
|
||||
for (int j = 0; j < childNodes.getLength(); j++) {
|
||||
Node node = childNodes.item(j);
|
||||
if (node.getNodeType() != Node.ELEMENT_NODE) continue;
|
||||
String nodeName = node.getNodeName();
|
||||
if (isWorkHome(nodeName)) {
|
||||
type = nodeName;
|
||||
}
|
||||
else {
|
||||
code.add(nodeName);
|
||||
value.add(getTextContent(node));
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < value.size(); j++) {
|
||||
if ("HOME".equals(type)) {
|
||||
vCard.setAddressFieldHome((String) code.get(j), (String) value.get(j));
|
||||
}
|
||||
else { // By default, setup work address
|
||||
vCard.setAddressFieldWork((String) code.get(j), (String) value.get(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTagContents(String tag) {
|
||||
NodeList nodes = document.getElementsByTagName(tag);
|
||||
if (nodes != null && nodes.getLength() == 1) {
|
||||
return getTextContent(nodes.item(0));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setupSimpleFields() {
|
||||
NodeList childNodes = document.getDocumentElement().getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node node = childNodes.item(i);
|
||||
if (node instanceof Element) {
|
||||
Element element = (Element) node;
|
||||
|
||||
String field = element.getNodeName();
|
||||
if (element.getChildNodes().getLength() == 0) {
|
||||
vCard.setField(field, "");
|
||||
}
|
||||
else if (element.getChildNodes().getLength() == 1 &&
|
||||
element.getChildNodes().item(0) instanceof Text) {
|
||||
vCard.setField(field, getTextContent(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTextContent(Node node) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
appendText(result, node);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private void appendText(StringBuilder result, Node node) {
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node nd = childNodes.item(i);
|
||||
String nodeValue = nd.getNodeValue();
|
||||
if (nodeValue != null) {
|
||||
result.append(nodeValue);
|
||||
}
|
||||
appendText(result, nd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue