net.solosky.litefetion.LiteFetion.java Source code

Java tutorial

Introduction

Here is the source code for net.solosky.litefetion.LiteFetion.java

Source

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/

/**
* Project  : LiteFetion
* Package  : net.solosky.litefetion
* File     : LiteFetion.java
* Author   : solosky < solosky772@qq.com >
* Created  : 2010-10-2
* License  : Apache License 2.0 
*/
package net.solosky.litefetion;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;

import javax.imageio.ImageIO;

import net.solosky.litefetion.bean.ActionResult;
import net.solosky.litefetion.bean.Buddy;
import net.solosky.litefetion.bean.BuddyState;
import net.solosky.litefetion.bean.ClientState;
import net.solosky.litefetion.bean.Cord;
import net.solosky.litefetion.bean.Presence;
import net.solosky.litefetion.bean.Relation;
import net.solosky.litefetion.bean.Settings;
import net.solosky.litefetion.bean.User;
import net.solosky.litefetion.bean.VerifyImage;
import net.solosky.litefetion.http.Cookie;
import net.solosky.litefetion.http.HttpClient;
import net.solosky.litefetion.http.HttpRequest;
import net.solosky.litefetion.http.HttpResponse;
import net.solosky.litefetion.notify.ApplicationConfirmedNotify;
import net.solosky.litefetion.notify.BuddyApplicationNotify;
import net.solosky.litefetion.notify.BuddyMessageNotify;
import net.solosky.litefetion.notify.BuddyStateNotify;
import net.solosky.litefetion.notify.ClientStateNotify;
import net.solosky.litefetion.notify.Notify;
import net.solosky.litefetion.util.StringHelper;

import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 *
 * LiteFetion
 * WebFetion????
 *
 * @author solosky <solosky772@qq.com>
 */
public class LiteFetion {

    /**
     * HttpClient,?http
     */
    private HttpClient client;

    /**
     * 
     */
    private User user;

    /**
     * ?
     */
    private ArrayList<Buddy> buddyList;

    /**
     * 
     */
    private ArrayList<Cord> cordList;

    /**
     * ?
     */
    private volatile ClientState clientState;

    /**
     * ,?
     */
    private int requestVersion;

    /**
     * SessionId
     */
    private String sessionId;

    /**
     * ?Notify
     */
    private int pollNotifyFailed;

    /**
     * Logger
     */
    private static Logger logger = Logger.getLogger(LiteFetion.class);

    /**
     * 
     */
    public LiteFetion() {
        this.client = new HttpClient();
        this.user = new User();
        this.buddyList = new ArrayList<Buddy>();
        this.cordList = new ArrayList<Cord>();
        this.clientState = ClientState.NEW;
        this.requestVersion = 0;
        this.pollNotifyFailed = 0;
    }

    /**
     * ?????????
     * ??
     * 
     * @param account      ?????
     * @param password      ?
     * @param presence      ?
     * @param verifyImage   ?????
     * @return            ?
     */
    public ActionResult login(String account, String password, Presence presence, VerifyImage verifyImage) {

        this.updateClientState(ClientState.LOGGING);

        //
        ActionResult result = this.signIn(account, password, presence, verifyImage);
        logger.debug("[Login] #1 SignIn:" + result.toString());
        if (result != ActionResult.SUCCESS)
            return this.processLoginFailed(result, 1);

        //??
        result = this.retirePersonalInfo();
        logger.debug("[Login] #2 retirePersonalInfo:" + result.toString());
        if (result != ActionResult.SUCCESS)
            return this.processLoginFailed(result, 2);

        //??
        result = this.retireBuddyList();
        logger.debug("[Login] #3 retireBuddyList:" + result.toString());
        if (result != ActionResult.SUCCESS)
            return this.processLoginFailed(result, 3);

        //???
        this.pollNotify();
        logger.debug("[Login] #4 Poll Buddy State Notify: Success.");

        logger.debug("[Login] Login Success.");
        this.updateClientState(ClientState.ONLINE);
        return ActionResult.SUCCESS;
    }

    /**
     * 
     * @return      ?
     */
    public ActionResult logout() {
        this.signOut();
        this.updateClientState(ClientState.LOGOUT);
        return ActionResult.SUCCESS;
    }

    /**
     * ???
     * @param type         ???sessionId VerifyImage.TYPE_*
     * @return            ??null
     */
    public VerifyImage retireVerifyImage(String type) {
        try {
            String picurl = StringHelper.format(Settings.WEBIM_URL_GET_PIC, type);
            HttpRequest request = this.createHttpRequest(picurl, "GET");
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            VerifyImage image = new VerifyImage();
            image.setVerifyType(type);
            image.setImageData(response.getResponseData());
            image.setSessionId(this.client.getCookie(type).getValue());
            return image;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 
     * @param url      ?
     * @param method   
     * @return
     */
    private HttpRequest createHttpRequest(String url, String method) {
        HttpRequest request = new HttpRequest(url, method);
        request.addHeader("User-Agent",
                "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729)");
        request.addHeader("Accept",
                "text/html,application/xhtml+xml,application/xml,image/png,image/*;q=0.9,*/*;q=0.8");
        request.addHeader("Accept-Language", "en-us,en;q=0.5");
        request.addHeader("Accept-Encoding", "gzip,deflate");
        request.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
        return request;
    }

    /**
     * ?versionssid
     * @param url
     * @return
     */
    private HttpRequest createActionHttpRequest(String url) {
        url = StringHelper.format(url, this.nextRequestVersion());
        HttpRequest request = this.createHttpRequest(url, "POST");
        request.addPostValue("ssid", this.sessionId);
        return request;
    }

    /**
     * ?
     * @return
     */
    private synchronized int nextRequestVersion() {
        return this.requestVersion++;
    }

    /**
     * ?,??
     * @return
     */
    private ActionResult signIn(String account, String password, Presence presence, VerifyImage verifyImage) {
        try {
            HttpRequest request = this.createHttpRequest(Settings.WEBIM_URL_LOGIN, "POST");
            request.addPostValue("UserName", account);
            request.addPostValue("Pwd", password);
            if (verifyImage != null) {
                request.addPostValue("Ccp", verifyImage.getVerifyCode());
            }
            request.addPostValue("OnlineStatus", Integer.toString(presence.getValue()));
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                Cookie cookie = this.client.getCookie("webim_sessionid");
                if (cookie != null) {
                    this.sessionId = cookie.getValue();
                    this.client.getCookieList().remove(cookie);
                }

                return ActionResult.SUCCESS;
            } else if (status == 312) {
                return ActionResult.VERIFY_FAILED;
            } else if (status == 404) {
                return ActionResult.USER_NOT_FOUND;
            } else if (status == 321) {
                return ActionResult.PASSWORD_NOT_MATCH;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ??
     * @return
     */
    private ActionResult signOut() {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_LOGOUT);
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            return status == 200 ? ActionResult.SUCCESS : ActionResult.REQUEST_FAILED;
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ?
     */
    private ActionResult processLoginFailed(ActionResult result, int step) {
        this.updateClientState(ClientState.LOGIN_FAIL);
        logger.warn("Login failed: [result=" + result + ", step=" + step + "]");
        return result;
    }

    /**
     * ?
     */
    private synchronized void updateClientState(ClientState state) {
        this.clientState = state;
    }

    /**
     * ??
     * @return
     */
    public ClientState getClientState() {
        return this.clientState;
    }

    //////////////////////////////////?///////////////////////////////////////

    /**
     * ??
     */
    private ActionResult retirePersonalInfo() {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_GET_PERSONAL_INFO);
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            if (json.getInt("rc") == 200) {

                json = json.getJSONObject("rv");
                user.setMobile(json.getLong("mn"));
                user.setNickName(json.getString("nn"));
                user.setUri(json.getString("uri"));
                user.setSid(json.getInt("sid"));
                user.setUserId(json.getInt("uid"));
                user.setImpresa(json.getString("i"));

                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ??
     * @return      ?
     */
    private ActionResult retireBuddyList() {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_GET_CONTACT_LIST);
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            if (json.getInt("rc") == 200) {
                json = json.getJSONObject("rv");
                //?
                this.buddyList.clear();
                JSONArray buddies = json.getJSONArray("bds");
                for (int i = 0; i < buddies.length(); i++) {
                    JSONObject jo = buddies.getJSONObject(i);
                    Buddy buddy = new Buddy();
                    buddy.setUri(jo.getString("uri"));
                    buddy.setUserId(jo.getInt("uid"));
                    buddy.setBlack(jo.getInt("isBk") == 1);
                    buddy.setLocalName(jo.getString("ln"));
                    buddy.setCordIds(jo.getString("bl"));
                    buddy.setRelation(Relation.valueOf(jo.getInt("rs")));

                    this.buddyList.add(buddy);
                }

                //
                this.cordList.clear();
                JSONArray cords = json.getJSONArray("bl");
                for (int i = 0; i < cords.length(); i++) {
                    JSONObject jo = cords.getJSONObject(i);
                    Cord cord = new Cord();
                    cord.setId(jo.getInt("id"));
                    cord.setTitle(jo.getString("n"));

                    this.cordList.add(cord);
                }

                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ???
     * @param buddy      ?
     * @param message   ?
     * @param isSendSMS   ???      
     * @return          ?
     */
    public ActionResult sendMessage(Buddy buddy, String message, boolean isSendSMS) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_SEND_MESSAGE);
            request.addPostValue("To", Integer.toString(buddy.getUserId()));
            request.addPostValue("msg", message);
            request.addPostValue("IsSendSms", isSendSMS ? "1" : "0");
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ??
     * @param message      ?
     * @return            ?
     */
    public ActionResult sendSelfSMS(String message) {
        return this.sendMessage(this.getUser(), message, true);
    }

    /**
     * 
     * @param impresa   
     * @return         ?
     */
    public ActionResult setImpresa(String impresa) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_SET_PERSONAL_INFO);
            request.addPostValue("Impresa", impresa);
            //request.addPostValue("NickName", "haha");
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                this.user.setImpresa(impresa);
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ?
     * @param presence      ?:ONLINE, AWAY, BUSY, OFFLINE(HIDDEN)
     * @param custom      ??AWAY?? "?~"
     * @return            ?
     */
    public ActionResult setPresence(Presence presence, String custom) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_SET_PERSONAL_INFO);
            request.addPostValue("Presence", Integer.toString(presence.getValue()));
            request.addPostValue("Custom", custom);
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                this.user.setPresence(presence.getValue());
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ?????,??VerifyImage.TYPE_ADD_BUDDY
     * @param account         ??
     * @param desc            ({$desc})
     * @param localName         ??
     * @param cord            null
     * @param verifyImage      ????VerifyImage.TYPE_ADD_BUDDY??
     * @return               ?
     */
    public ActionResult addBuddy(String account, String desc, String localName, Cord cord,
            VerifyImage verifyImage) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_ADD_BUDDY);
            request.addPostValue("AddType", account.length() == 11 ? "1" : "0"); //?1,?0
            request.addPostValue("UserName", account);
            request.addPostValue("Desc", desc == null ? "" : desc);
            request.addPostValue("LocalName", localName == null ? "" : localName);
            request.addPostValue("Ccp", verifyImage.getVerifyCode());
            request.addPostValue("CcpId", verifyImage.getSessionId());

            request.addPostValue("BuddyLists", cord == null ? "0" : Integer.toString(cord.getId()));
            request.addPostValue("PhraseId", "0");
            request.addPostValue("SubscribeFlag", "0");

            this.client.removeCookie(VerifyImage.TYPE_ADD_BUDDY);

            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {

                JSONObject jo = json.getJSONObject("rv");
                Buddy buddy = new Buddy();
                buddy.setUri(jo.getString("uri"));
                buddy.setUserId(jo.getInt("uid"));
                buddy.setBlack(false);
                buddy.setLocalName(jo.getString("ln"));
                buddy.setRelation(Relation.UNCONFIRMED);

                this.buddyList.add(buddy);

                return ActionResult.SUCCESS;
            } else if (status == 312) {
                return ActionResult.VERIFY_FAILED; //?
            } else if (status == 404) {
                return ActionResult.USER_NOT_FOUND; //?
            } else if (status == 521) {
                return ActionResult.BUDDY_EXISTS; //??
            } else {
                logger.debug("addBuddy failed, unkown status:" + status);
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ??
     * @param buddy         ??
     * @param isAgree      ?????
     * @param localName      ????? ???null??
     * @param cord         ??? ???null??
     * @return            ?
     */
    public ActionResult handleBuddyApplication(Buddy buddy, boolean isAgree, String localName, Cord cord) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_HANDLE_ADD_BUDDY);
            request.addPostValue("BuddyId", Integer.toString(buddy.getUserId()));
            request.addPostValue("Result", isAgree ? "1" : "0");
            request.addPostValue("BuddyList", cord == null ? "0" : Integer.toString(cord.getId()));
            request.addPostValue("LocalName", localName == null ? "" : localName);
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                if (isAgree) {
                    buddy.setRelation(Relation.BUDDY); //?
                } else {
                    this.buddyList.remove(buddy); //?????
                }
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }

        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ????
     * @param buddy      ?
     * @return
     */
    public ActionResult blackBuddy(Buddy buddy) {
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_OP_BUDDY);
            request.addPostValue("Op", "1");
            request.addPostValue("To", Integer.toString(buddy.getUserId()));
            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                buddy.setBlack(true);
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }

        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ???
     * @param toBuddies      ????(litefetion.getUser())
     * @param message      ?????
     * @return            ??
     */
    public ActionResult batchSendSMS(List<Buddy> toBuddies, String message) {
        try {
            if (toBuddies == null || toBuddies.size() == 0)
                return ActionResult.WRONG_PARAM;

            //?? 346339663,346379375?
            Iterator<Buddy> it = toBuddies.iterator();
            StringBuffer recievers = new StringBuffer();
            while (it.hasNext()) {
                Buddy b = it.next();
                recievers.append(Integer.toString(b.getUserId()));
                if (it.hasNext()) { //??,
                    recievers.append(",");
                }
            }

            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_SEND_SMS);
            request.addPostValue("UserName", Integer.toString(this.user.getUserId()));
            request.addPostValue("Message", message);
            request.addPostValue("Receivers", recievers.toString());

            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ??
     * 
     * @param toBuddies      ????(litefetion.getUser())
     * @param message      ?????
     * @param sendDate      ?? ?+11-??,?
     * @return            ??
     */

    public ActionResult sendScheduleSMS(List<Buddy> toBuddies, String message, Date sendDate) {
        try {
            if (toBuddies == null || toBuddies.size() == 0)
                return ActionResult.WRONG_PARAM;

            // ?+11-??
            //? 2007.7.1 22:56  2010.7.1 23:07 - 2011.7.1 22:56?
            Calendar calMin = Calendar.getInstance();
            calMin.add(Calendar.MINUTE, 11);
            Calendar calMax = Calendar.getInstance();
            calMax.add(Calendar.YEAR, 1);
            //????
            if (sendDate.before(calMin.getTime()) || sendDate.after(calMax.getTime())) {
                return ActionResult.WRONG_PARAM;
            }

            //?? 346339663,346379375?
            Iterator<Buddy> it = toBuddies.iterator();
            StringBuffer recievers = new StringBuffer();
            while (it.hasNext()) {
                Buddy b = it.next();
                recievers.append(Integer.toString(b.getUserId()));
                if (it.hasNext()) { //??,
                    recievers.append(",");
                }
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d H:m:s");
            sdf.setTimeZone(TimeZone.getTimeZone("GMT 0"));
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_SET_SCHEDULESMS);
            request.addPostValue("UserName", Integer.toString(this.user.getUserId()));
            request.addPostValue("Message", message);
            request.addPostValue("Receivers", recievers.toString());
            request.addPostValue("SendTime", sdf.format(sendDate));

            HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
            JSONObject json = new JSONObject(response.getResponseString());
            int status = json.getInt("rc");
            if (status == 200) {
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.REQUEST_FAILED;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        } catch (JSONException e) {
            return ActionResult.JSON_FAILED;
        }
    }

    /**
     * ???
     * @param buddy      ?
     * @param size      ????1,2,3,4,5,6??????:
     *                 1=24x24, 2=32x32, 3=64x64, 4=96x96, 5=16x16, 6=48x48
     * @return         ??buddy.portrait
     */
    public ActionResult retirePortrait(Buddy buddy, int size) {
        try {
            if (size < 1 || size > 6)
                throw new IllegalArgumentException("size should be those values:{1,2,3,4,5,6}");
            if (buddy.getCrc() != null) {
                String url = Settings.WEBIM_URL_GET_PORTRAIT;
                url = StringHelper.format(url, buddy.getUserId(), size, buddy.getCrc(), buddy.getUserId());
                HttpRequest request = this.createHttpRequest(url, "GET");
                HttpResponse response = this.client.tryExecute(request, Settings.FEITON_MAX_REQUEST_EXECUTE_TIMES);
                BufferedImage portrait = ImageIO.read(new ByteArrayInputStream(response.getResponseData()));
                buddy.setPortrait(portrait);
                return ActionResult.SUCCESS;
            } else {
                return ActionResult.PORTRAIT_NOT_FOUND;
            }
        } catch (IOException e) {
            return ActionResult.HTTP_FAILED;
        }
    }

    /**
     * ?????
     * ????
     */
    public List<Notify> pollNotify() {
        List<Notify> notifyList = new ArrayList<Notify>();
        try {
            HttpRequest request = this.createActionHttpRequest(Settings.WEBIM_URL_CONNECT);
            HttpResponse response = this.client.execute(request);
            JSONObject json = new JSONObject(response.getResponseString());

            int status = json.getInt("rc");
            if (status == 200) {
                JSONArray dataArr = json.getJSONArray("rv");
                for (int i = 0; i < dataArr.length(); i++) {
                    JSONObject jo = dataArr.getJSONObject(i);
                    Notify notify = this.processNotify(jo);
                    if (notify != null) {
                        notifyList.add(notify);
                    }
                }
            } else if (status == 302) {
                //No Data..
            } else {
            }
        } catch (IOException e) {
            //?IO??
            this.pollNotifyFailed++;
            if (this.pollNotifyFailed > Settings.FETION_MAX_POLL_NOTIFY_FAILED) {
                this.updateClientState(ClientState.NET_ERROR);
                notifyList.add(new ClientStateNotify(ClientState.NET_ERROR));
                this.pollNotifyFailed = 0; //?
            }
            logger.warn("Poll Notify failed.", e);
        } catch (JSONException e) {
            logger.warn("Poll Notify failed.", e);
        }
        logger.debug("Poll Notify: notify size:" + notifyList.size());
        return notifyList;
    }

    /**
     * ????
     * @param jo
     * @throws JSONException 
     */
    private Notify processNotify(JSONObject jo) throws JSONException {
        int dataType = jo.getInt("DataType");
        JSONObject data = jo.getJSONObject("Data");
        Buddy buddy = null;
        switch (dataType) {

        case 2: //???
            int userId = data.getInt("uid");
            buddy = this.getBuddyByUserId(userId);
            if (buddy != null) {
                BuddyState beforeState = buddy.getState();
                if (data.optLong("mn") != 0) {
                    buddy.setMobile(data.optLong("mn"));
                }
                if (data.optString("nn") != null && data.optString("nn").length() > 0) {
                    buddy.setNickName(data.optString("nn"));
                }
                buddy.setImpresa(data.optString("i"));
                if (data.optString("sms") != null && data.optString("sms").length() > 0) {
                    buddy.setSMSPolicy(data.optString("sms"));
                }
                buddy.setSid(data.optInt("sid"));
                buddy.setPresence(data.optInt("pb"));
                buddy.setCrc(data.optString("crc"));
                BuddyState currentState = buddy.getState();
                logger.debug("BuddyState changed: buddy=" + buddy.getDisplayName() + ", before=" + beforeState
                        + ", current=" + currentState);
                return new BuddyStateNotify(beforeState, currentState, buddy);
            }
            break;

        case 3: //??
            int fromUserId = data.getInt("fromUid");
            String message = data.getString("msg");
            int msgType = data.getInt("msgType");
            buddy = this.getBuddyByUserId(fromUserId);
            if (msgType == 2 && buddy != null) { //?
                logger.debug("Buddy Message received: buddy=" + buddy.getDisplayName() + ", text=" + message);
                return new BuddyMessageNotify(buddy, message, new Date());
            } else if (msgType == 3 || msgType == 4) { //TODO ..?????..
            }
            break;

        case 4: //?
            int exitCode = data.getInt("ec");
            ClientState state = ClientState.LOGOUT;
            if (exitCode == 900) {
                state = ClientState.OTHER_LOGIN;
            } else if (exitCode >= 902 && exitCode <= 905) {
                state = ClientState.LOGOUT;
            } else {
                state = ClientState.LOGOUT;
            }
            logger.debug("ClientState changed: clientState=" + state);
            return new ClientStateNotify(state);

        case 5: //?
            buddy = new Buddy();
            buddy.setUserId(data.getInt("uid"));
            buddy.setUri(data.getString("uri"));
            buddy.setRelation(Relation.STRANGER);
            this.buddyList.add(buddy); //?
            String desc = data.getString("desc");
            logger.debug("Buddy Application received: buddy=" + buddy + ", desc=" + desc);
            return new BuddyApplicationNotify(buddy, desc);

        case 6: //??,???ba=1
            if (data.getInt("ba") == 1) {
                buddy = this.getBuddyByUserId(data.getInt("uid"));
                if (buddy != null) {
                    Relation relation = Relation.valueOf(data.getInt("rs"));
                    buddy.setRelation(relation);
                    logger.debug("Buddy confirmed application: buddy=" + buddy + ", isAgreed="
                            + (relation == Relation.DECLINED));
                    return new ApplicationConfirmedNotify(buddy, relation == Relation.BUDDY);
                }
            }
        }

        return null;
    }
    //////////////////////////////////??///////////////////////////////////////

    //////////////////////////////////?///////////////////////////////

    /**
     * 
     */
    public User getUser() {
        return this.user;
    }

    /**
     * ?,????
     */
    public List<Buddy> getBuddyList() {
        return this.buddyList;
    }

    /**
     * 
     * @return
     */
    public List<Cord> getCordList() {
        return this.cordList;
    }

    /**
     * ??
     * @return ?
     */
    public Buddy getBuddyByUserId(int userId) {
        Iterator<Buddy> it = this.buddyList.iterator();
        while (it.hasNext()) {
            Buddy buddy = it.next();
            if (buddy.getUserId() == userId) {
                return buddy;
            }
        }
        return null;
    }

    /**
     * ?uri?
     * @param uri
     * @return
     */
    public Buddy getBuddyByUri(String uri) {
        Iterator<Buddy> it = this.buddyList.iterator();
        while (it.hasNext()) {
            Buddy buddy = it.next();
            if (uri.equals(buddy.getUri())) {
                return buddy;
            }
        }
        return null;
    }

    /**
     * ????
     */
    public List<Buddy> getBlackList() {
        ArrayList<Buddy> list = new ArrayList<Buddy>();
        Iterator<Buddy> it = this.buddyList.iterator();
        while (it.hasNext()) {
            Buddy buddy = it.next();
            if (buddy.isBlack()) {
                list.add(buddy);
            }
        }
        return list;
    }

    /**
     * 
     */
    public List<Buddy> getStrangerList() {
        ArrayList<Buddy> list = new ArrayList<Buddy>();
        Iterator<Buddy> it = this.buddyList.iterator();
        while (it.hasNext()) {
            Buddy buddy = it.next();
            if (buddy.getRelation() == Relation.STRANGER) {
                list.add(buddy);
            }
        }
        return list;
    }

    /**
     * ?
     * @param cord      
     * @return
     */
    public List<Buddy> getBuddyListByCord(Cord cord) {
        ArrayList<Buddy> list = new ArrayList<Buddy>();
        Iterator<Buddy> it = this.buddyList.iterator();
        Buddy buddy = null;
        String[] buddyCordIds = null;
        while (it.hasNext()) {
            buddy = it.next();
            if (buddy.getCordIds() != null) {
                buddyCordIds = buddy.getCordIds().split(";");
                for (String cid : buddyCordIds) {
                    if (cid.equals(Integer.toString(cord.getId()))) {
                        list.add(buddy);
                    }
                }
            }
        }
        return list;
    }

    /**
     * ??
     * @return
     */
    public synchronized List<Buddy> getBuddyListWithoutCord() {
        ArrayList<Buddy> list = new ArrayList<Buddy>();
        Iterator<Buddy> it = this.buddyList.iterator();
        Buddy buddy = null;
        String buddyCordId = null;
        while (it.hasNext()) {
            buddy = it.next();
            buddyCordId = buddy.getCordIds();
            if (buddyCordId == null || buddyCordId.length() == 0) {
                list.add(buddy);
            }
        }
        return list;
    }

    //////////////////////////////////??///////////////////////////////
}