FileDocCategorySizeDatePackage
ImpsAddress.javaAPI DocAndroid 1.5 API8225Wed May 06 22:42:46 BST 2009com.android.im.imps

ImpsAddress.java

/*
 * Copyright (C) 2007-2008 Esmertec AG.
 * Copyright (C) 2007-2008 The Android Open Source Project
 *
 * 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 com.android.im.imps;

import android.os.Parcel;

import com.android.im.engine.Address;
import com.android.im.engine.ImEntity;

/**
 * The abstract representation of an IMPS address.
 */
public abstract class ImpsAddress extends Address {
    private static final char[] SPECIALS = {'/', '@', '+'};

    protected String mUser;
    protected String mResource;
    protected String mDomain;

    private String mFullAddress;

    protected ImpsAddress() {
    }

    protected ImpsAddress(String user, String resource, String domain) {
        // build the full address and unify the fields to lower case since imps
        // address is case insensitive.
        StringBuilder buf = new StringBuilder(ImpsConstants.ADDRESS_PREFIX);
        if(user != null) {
            buf.append(user.toLowerCase());
        }
        if(resource != null) {
            buf.append('/').append(resource.toLowerCase());
        }
        if(domain != null) {
            buf.append('@').append(domain.toLowerCase());
        }
        mFullAddress = buf.toString();
        mUser = user;
        mResource = resource;
        mDomain = domain;
        verifyAddress();
    }

    protected ImpsAddress(String full){
        this(full, true);
    }

    protected ImpsAddress(String full, boolean verify) {
        if (full == null || full.length() == 0) {
            throw new IllegalArgumentException();
        }

        //TODO: escape reserved characters.
        if(!full.startsWith(ImpsConstants.ADDRESS_PREFIX)) {
            full = ImpsConstants.ADDRESS_PREFIX + full;
        }

        parse(full);
        mFullAddress = full;

        if (verify) {
            verifyAddress();
        }
    }

    private void parse(String full) {
        mUser = parseUser(full);
        mResource = parseResource(full);
        mDomain = parseDomain(full);
    }

    private void verifyAddress() throws IllegalArgumentException {
        ImpsLog.log("verifyAddress:" + mUser + ", " + mResource + ",  " + mDomain);
        if(mUser == null && mResource == null) {
            throw new IllegalArgumentException();
        }

        if(mUser != null) {
            if(mUser.length() == 0) {
                throw new IllegalArgumentException("Invalid user");
            }
            if(mUser.charAt(0) == '+') {//mobile number
                for(int i = 1; i < mUser.length(); i++) {
                    if(!Character.isDigit(mUser.charAt(i))) {
                        throw new IllegalArgumentException("Invalid user");
                    }
                }
            } else if(!isAlphaSequence(mUser)) {
                throw new IllegalArgumentException("Invalid user");
            }
        }

        if(mResource != null && !isAlphaSequence(mResource)) {
            throw new IllegalArgumentException("Invalid resource");
        }
        if(mDomain != null && !isAlphaSequence(mDomain)) {
            throw new IllegalArgumentException("Invalid domain");
        }
    }

    /**
     * Gets the User-part of the address which refers to the identification of
     * the IMPS user.
     *
     * @return the User-part of the address.
     */
    public String getUser() {
        return mUser;
    }

    /**
     * Gets the Resource-part of the address which identifies the referred
     * public or private resource.
     *
     * @return the Resource-part of the address.
     */
    public String getResource() {
        return mResource;
    }

    /**
     * Gets the Domain-part of the address which identifies the IMPS server
     * domain.
     *
     * @return the Domain-part of the address.
     */
    public String getDomain() {
        return mDomain;
    }

    /**
     * Gets the full string representation of the address.
     */
    @Override
    public String getFullName() {
        return mFullAddress;
    }

    @Override
    public void writeToParcel(Parcel dest) {
        dest.writeString(mFullAddress);
    }

    @Override
    public void readFromParcel(Parcel source) {
        mFullAddress = source.readString();
        parse(mFullAddress);
    }

    @Override
    public boolean equals(Object other) {
        return other instanceof ImpsAddress
                && mFullAddress.equalsIgnoreCase(((ImpsAddress)other).mFullAddress);
    }

    @Override
    public int hashCode() {
        return mFullAddress.toLowerCase().hashCode();
    }

    /**
     * Formats the address to a PrimitiveElement which can be used as the
     * content of Sender or Recipient.
     *
     * @return a PrimitiveElement.
     */
    public abstract PrimitiveElement toPrimitiveElement();

    /**
     * Gets the entity this address object refers to.
     *
     * @param connection
     * @return the entity this address refers to or <code>null</code> if the
     *         entity not found.
     */
    abstract ImEntity getEntity(ImpsConnection connection);

    /**
     * Constructs an ImpsAddress from the Sender or Recipient element in a
     * primitive.
     *
     * @param elem the Sender of Recipient element.
     * @return the ImpsAddress object or <code>null</code> if it's not a valid
     *         element.
     */
    public static ImpsAddress fromPrimitiveElement(PrimitiveElement elem) {
        String type = elem.getTagName();
        if(ImpsTags.User.equals(type)) {
            return new ImpsUserAddress(elem.getChildContents(ImpsTags.UserID), false);
        } else if(ImpsTags.Group.equals(type)) {
            PrimitiveElement child = elem.getFirstChild();
            if(child == null) {
                throw new IllegalArgumentException();
            }
            if(ImpsTags.GroupID.equals(child.getTagName())){
                return new ImpsGroupAddress(child.getContents());
            } else {
                String screeName = child.getChildContents(ImpsTags.SName);
                String groupId = child.getChildContents(ImpsTags.GroupID);
                return new ImpsGroupAddress(groupId, screeName);
            }
        } else if(ImpsTags.ContactList.equals(type)) {
            return new ImpsContactListAddress(elem.getContents(), false);
        } else {
            throw new IllegalArgumentException();
        }
    }

    private String parseUser(String full) {
        int index = full.indexOf('/');
        if(index == 3) {
            return null;
        }
        if (index == -1) {
            index = full.lastIndexOf('@');
        }
        if (index == -1) {
            index = full.length();
        }
        return full.substring(3, index);
    }

    private String parseResource(String full) {
        int beginIndex = full.indexOf('/');
        if (beginIndex == -1) {
            return null;
        }
        int endIndex = full.lastIndexOf('@');
        if (endIndex == -1 || endIndex < beginIndex) {
            endIndex = full.length();
        }
        return full.substring(beginIndex + 1, endIndex);
    }

    private String parseDomain(String full) {
        int beginIndex = full.lastIndexOf('@');
        return beginIndex == -1 ? null : full.substring(beginIndex + 1);
    }

    private boolean isAlphaSequence(String str) {
        for(int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if(ch < 32 || ch > 126 || isSpecial(ch)) {
                return false;
            }
        }
        return true;
    }

    private boolean isSpecial(char ch) {
        for (char element : SPECIALS) {
            if(ch == element) {
                return true;
            }
        }
        return false;
    }
}