java版飞信协议实现

原始的代码不记得是哪个作者了,如果原作者看见了,我要说声谢谢
但这个真的做了大改动,我怕原作者也看不出来了~最近比较忙,如果谁愿意,去改改吧,不知道为什么,这个很不稳定,老是405错误,或者最近移动的问题?


给出代码:

 

 package myFetion;  
   
 import java.io.BufferedReader;  
 import java.io.InputStream;  
 import java.io.InputStreamReader;  
 import java.io.OutputStreamWriter;  
 import java.io.UnsupportedEncodingException;  
 import java.net.HttpURLConnection;  
 import java.net.URL;  
 import java.nio.ByteBuffer;  
 import java.security.MessageDigest;  
 import java.util.HashMap;  
 import java.util.Iterator;  
 import java.util.List;  
 import java.util.Map;  
 import java.util.UUID;  
 import java.util.Map.Entry;  
 import java.util.regex.Matcher;  
 import java.util.regex.Pattern;  
   
 import org.apache.commons.codec.binary.Hex;  
 import org.dom4j.Attribute;  
 import org.dom4j.Document;  
 import org.dom4j.DocumentHelper;  
 import org.dom4j.Element;  
   
 public class libFx {  
   
     // [start] 变量定义  
     private static final String SIP_M = "M fetion.com.cn SIP-C/2.0";  
     private static final String SIP_S = "S fetion.com.cn SIP-C/2.0";  
     private static String URL_SD = "http://221.176.31.42/ht/sd.aspx";  
     private static String URL_LOGIN = "https://uid.fetion.com.cn/ssiportal/SSIAppSignIn.aspx";  
     private static String URL_CONFIG = "http://nav.fetion.com.cn/nav/getsystemconfig.aspx";  
   
     private int call, seq;  
     private String username, password;  
     private String ssic, sid, guid, domain, uri;  
   
     private HashMap<String, buddyInfo> allBuddys = new HashMap<String, buddyInfo>();  
   
     // [end]  
   
     private class resResult {  
         int status;  
         Map<String, List<String>> header;  
         String response;  
     }  
   
     public class buddyInfo {  
         String uri;  
         String mobile;  
         String localname;  
         String nickname;  
         String buddytype;  
         String displayname;  
     }  
   
     public libFx(String username, String password) {  
         this.username = username;  
         this.password = password;  
     }  
   
     public void getSystemConfig() {  
         String data = "<config><user mobile-no=\"" + username;  
         data += "\" /><client type=\"PC\" version=\"3.2.0540\" platform=\"W5.1\" />";  
         data += "<servers version=\"0\" /><service-no version=\"0\" /><parameters version=\"0\" />";  
         data += "<hints version=\"0\" /><http-applications version=\"0\" /></config>";  
   
         resResult res = httpRequest(URL_CONFIG, data, null);  
   
         try {  
             String[] resSplit = res.response.split("\r\n");  
             String xmlData = resSplit[0];  
   
             Document xml = DocumentHelper.parseText(xmlData);  
   
             Element httptunnel = (Element) xml.selectObject("/config/servers/http-tunnel");  
             URL_SD = httptunnel.getStringValue();  
   
             Element ssiappsignin = (Element) xml.selectObject("/config/servers/ssi-app-sign-in");  
             URL_LOGIN = ssiappsignin.getStringValue();  
   
         } catch (Exception ex) {  
             System.out.println(ex.getMessage());  
         }  
     }  
   
     // [start] 登录,注册到服务器,退出  
     public String Login() {  
         String debugMsg = "";  
         try {  
             String data = "mobileno=" + username + "&pwd=" + password + "";  
             resResult res = httpRequest(URL_LOGIN, data, null);  
   
             if (res == null) {  
                 debugMsg = "login error";  
                 return debugMsg;  
             }  
             String header = res.header.values().toString();  
             Pattern ssicPattern = Pattern.compile("ssic=(.*?);");  
             Matcher matcher = ssicPattern.matcher(header);  
   
             if (matcher.find()) {  
                 ssic = matcher.group(1);  
             }  
   
             Document document = DocumentHelper.parseText(res.response);  
             Element root = document.getRootElement();  
             Element user = root.element("user");  
             // 示例:<user uri="sip:857179488@fetion.com.cn;p=6006" mobile-no="15910510159" user-status="101" user-id="607221518">  
             uri = user.attribute("uri").getValue();  
             int a = uri.indexOf("@");  
             int b = uri.indexOf(";");  
   
             sid = uri.substring(4, a);  
             domain = uri.substring(a + 1, b);  
   
         } catch (Exception ex) {  
             debugMsg += ex.getMessage();  
             return debugMsg;  
         }  
   
         return "OK" + debugMsg;  
     }  
   
     public String Register() {  
         String debugMsg = "";  
   
         String arg = "<args><device type=\"PC\" version=\"2009112603\" client-version=\"3.5.2540\" />";  
         arg += "<caps value=\"simple-im;im-session;temp-group;personal-group;im-relay;xeno-im;direct-sms;sms2fetion\" />";  
         arg += "<events value=\"contact;permission;system-message;personal-group;compact\" /><user-info attributes=\"all\" />";  
         arg += "<presence><basic value=\"400\" desc=\"\" /></presence></args>";  
   
         String response = null, nonce = null;  
   
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "1 R");  
         String msg = createSipData("R fetion.com.cn SIP-C/2.0", fields, arg) + "SIPP";  
         // 发送请求  
         response = sendRequest(nextUrl("i"), msg).response;  
         response = sendRequest(nextUrl("s"), "SIPP").response;  
   
         Pattern noncePattern = Pattern.compile("nonce=\"(\\w+)\"");  
         Matcher m = noncePattern.matcher(response);  
         if (m.find()) {  
             nonce = m.group(1);  
         } else {  
             return "not find noce!" + response;  
         }  
   
         String salt = "777A6D03";  
         String cnonce = calc_cnonce();  
         String calcResponse = calc_response(nonce, cnonce);  
         String strA = "Digest algorithm=\"SHA1-sess\",response=\"" + calcResponse + "\",";  
         strA += "cnonce=\"" + cnonce + "\",salt=\"" + salt + "\",ssic=\"" + ssic + "\"";  
   
         fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "2 R");  
         fields.put("A", strA);  
         msg = createSipData("R fetion.com.cn SIP-C/2.0", fields, arg) + "SIPP";  
         // 发送请求  
         response = sendRequest(nextUrl("s"), msg).response;  
         response = sendRequest(nextUrl("s"), "SIPP").response;  
         if (response == null) {  
             return "not 2R";  
         }  
   
         return "OK" + debugMsg;  
     }  
   
     public boolean logout() {  
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", "1");  
         fields.put("Q", "2 R");  
         fields.put("X", "0");  
         String msg = createSipData("R fetion.com.cn SIP-C/2.0", fields, null) + "SIPP";  
   
         String response = sendRequest(nextUrl("s"), msg).response;  
         System.out.println("退出:" + response);  
         if (response == null || response.equals("")) {  
             return false;  
         }  
         return true;  
     }  
   
     // [end]  
   
     // [start] 相关算法  
     private String nextCall() {  
         call += 1;  
         return String.valueOf(call);  
     }  
   
     private String nextUrl(String t) {  
         seq++;  
         System.out.println(URL_SD + "?t=" + t + "&i=" + seq);  
   
         return new StringBuffer(URL_SD).append("?t=").append(t).append("&i=").append(seq).toString();  
     }  
   
     private String calc_cnonce() {  
         MessageDigest md5 = null;  
         String md5Str = null;  
         try {  
             md5 = MessageDigest.getInstance("MD5");  
             md5.update(UUID.randomUUID().toString().getBytes("UTF-8"));  
             md5Str = new String(Hex.encodeHex(md5.digest())).toUpperCase();  
         } catch (Exception e) {  
             return null;  
         }  
         return md5Str;  
     }  
   
     private String calc_response(String nonce, String cnonce) {  
   
         String temp = ":";  
         String strTemp = "REGISTER";  
         char[] saltChars = { 0x77, 0x7A, 0x6D, 0x03 };  
         String salt = String.valueOf(saltChars);  
   
         String h3 = null;  
         try {  
             int sidLength = sid.getBytes("UTF-8").length;  
             int domainLength = domain.getBytes("UTF-8").length;  
             int nonceLength = nonce.getBytes("UTF-8").length;  
             int tempLength = temp.getBytes("UTF-8").length;  
             int strTempLength = strTemp.getBytes("UTF-8").length;  
             int cnonceLength = cnonce.getBytes("UTF-8").length;  
   
             ByteBuffer buf = null;  
   
             // 晕,这部有点多余可以省略,就是把原来加密过的字符串转成字节  
             // byte[] decode = Hex.decodeHex(binstr.toUpperCase().toCharArray());  
   
             MessageDigest sha1 = MessageDigest.getInstance("SHA-1");  
   
             // 密码使用SHA-1加密  
             sha1 = MessageDigest.getInstance("SHA-1");  
   
             sha1.update(password.getBytes("UTF-8"));  
             byte[] src = sha1.digest();  
             // 加密后把{ 0x77, 0x7A, 0x6D, 0x03 }这四个字符加上用SHA-1加密过的密码  
             buf = ByteBuffer.allocate(src.length + salt.getBytes("UTF-8").length);  
             buf.put(salt.getBytes("UTF-8"));  
             buf.put(src);  
             buf.flip();  
             sha1.update(buf);  
             buf.clear();  
             // 然后再把相加过的`字节数组`用SHA-1加密  
             byte[] decode = sha1.digest();  
   
             // 用SHA-1加密```形式如 sid:domain:decode  
             buf = ByteBuffer.allocate(sidLength + domainLength + decode.length + (tempLength * 2));  
             buf.put(sid.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(domain.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(decode);  
             buf.flip();  
             sha1.update(buf);  
   
             byte[] keyBytes = sha1.digest();  
             // 用MD5加密```形式如 key:nonce:cnonce 上面生成的就是key 生成h1  
             MessageDigest md5 = MessageDigest.getInstance("MD5");  
             buf = ByteBuffer.allocate(keyBytes.length + nonceLength + cnonceLength + (tempLength * 2));  
             buf.put(keyBytes);  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(nonce.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(cnonce.getBytes("UTF-8"));  
             buf.flip();  
             md5.update(buf);  
             buf.clear();  
   
             String h1 = new String(Hex.encodeHex(md5.digest())).toUpperCase();  
   
             // 用MD5加密```形式如 REGISTER:sid 生成h2  
             buf = ByteBuffer.allocate(sidLength + strTempLength + tempLength);  
             buf.put(strTemp.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(sid.getBytes("UTF-8"));  
             buf.flip();  
             md5.update(buf);  
             buf.clear();  
   
             String h2 = new String(Hex.encodeHex(md5.digest())).toUpperCase();  
   
             // 用MD5加密```形式如 h1:nonce:h2 生成h2  
             buf = ByteBuffer.allocate(h1.getBytes("UTF-8").length + nonceLength + h2.getBytes("UTF-8").length + (tempLength * 2));  
             buf.put(h1.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(nonce.getBytes("UTF-8"));  
             buf.put(temp.getBytes("UTF-8"));  
             buf.put(h2.getBytes("UTF-8"));  
             buf.flip();  
             md5.update(buf);  
             buf.clear();  
   
             h3 = new String(Hex.encodeHex(md5.digest())).toUpperCase();  
   
         } catch (Exception e) {  
             e.printStackTrace();  
         }  
   
         return h3;  
   
     }  
   
     private String createSipData(String invite, HashMap<String, String> fields, String arg) {  
         StringBuffer sip = new StringBuffer(invite).append("\r\n");  
         for (Map.Entry<String, String> entry : fields.entrySet()) {  
             sip.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");  
         }  
         if (arg != null) {  
             try {  
                 sip.append("L: ").append(arg.getBytes("UTF-8").length).append("\r\n\r\n").append(arg);  
             } catch (UnsupportedEncodingException e) {  
                 return null;  
             }  
         }  
   
         return sip.toString();  
     }  
   
     // [end]  
   
     // [start] http请求  
     private resResult httpRequest(String strUrl, String data, Map<String, String> heads) {  
         resResult res = new resResult();  
   
         URL url = null;  
         HttpURLConnection conn = null;  
         for (int i = 0; i < 10; i++) {// 如果请求失败,则重试5次  
             try {  
                 url = new URL(strUrl);  
                 conn = (HttpURLConnection) url.openConnection();  
   
                 conn.setDoOutput(true);// 设置输出  
                 conn.setUseCaches(false);// 不使用缓存  
                 conn.setRequestMethod("POST");  
   
                 // 循环设置请求头部,比如cookie  
                 if (heads != null) {  
                     for (Entry<String, String> entry : heads.entrySet())  
                         conn.setRequestProperty(entry.getKey(), entry.getValue());  
                 }  
   
                 OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());  
                 out.write(data);// 写入请求(POST)数据  
                 out.flush();  
                 out.close();  
   
                 InputStream in = conn.getInputStream();  
                 BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8"));  
                 String line = "", response = "";  
                 while ((line = br.readLine()) != null) {  
                     response += line + "\r\n";  
                 }  
   
                 Map<String, List<String>> resHeads = conn.getHeaderFields();  
   
                 res.status = conn.getResponseCode();  
                 System.out.println("conn_code:" + res.status);  
   
                 res.response = response;  
                 res.header = resHeads;  
   
             } catch (Exception e) {  
                 System.out.println(e.getMessage());  
             } finally {  
                 if (conn != null)  
                     conn.disconnect();  
             }  
   
             if (res.status == 200) {  
                 break;// 重试若干次,当返回200则跳出  
             }  
             try {  
                 Thread.sleep(1000);  
             } catch (InterruptedException e) {  
             }  
         }  
         return res;  
     }  
   
     private resResult sendRequest(String strUrl, String data) {  
         if (guid == null) {  
             guid = UUID.randomUUID().toString();  
         }  
         resResult res = new resResult();  
         try {  
   
             Map<String, String> cookies = new HashMap<String, String>();  
   
             cookies.put("User-Agent", "IIC2.0/PC 3.5.2540");  
             cookies.put("Cookie", "ssic=" + ssic);  
             cookies.put("Content-Type", "application/oct-stream");  
             cookies.put("Pragma", "xz4BBcV" + guid);  
   
             // StringRequestEntity m_data = new StringRequestEntity(data, "text/xml", "utf-8");  
             res = httpRequest(strUrl, data, cookies);  
   
         } catch (Exception e) {  
             return null;  
         }  
         return res;  
     }  
   
     // [end]  
   
     // /以下是飞信应用API  
     public HashMap<String, buddyInfo> getContactsInfo() {  
   
         allBuddys = getContactsList();  
   
         StringBuffer arg = new StringBuffer("<args><contacts attributes=\"all\">");  
         for (Entry<String, buddyInfo> buddy : allBuddys.entrySet()) {  
             arg.append("<contact uri=\"").append(buddy.getKey()).append("\" />");  
         }  
         arg.append("</contacts></args>");  
   
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "1 S");  
         fields.put("N", "GetContactsInfo");  
         String msg = createSipData(SIP_S, fields, arg.toString()) + "SIPP";  
   
         try {  
             sendRequest(nextUrl("s"), msg);  
             Thread.sleep(2000);  
             String response = sendRequest(nextUrl("s"), "SIPP").response;  
   
             String[] resSplit = response.split("\r\n\r\n");  
             String xmlData = resSplit[1].replace("</results>SIPP", "</results>");  
   
             Document xml = DocumentHelper.parseText(xmlData);  
   
             List contacts = xml.selectNodes("/results/contacts/contact");  
             Iterator itc = contacts.iterator();  
             while (itc.hasNext()) {  
                 Element elt = (Element) itc.next();  
                 Attribute uri = elt.attribute("uri");  
                 buddyInfo buddy = allBuddys.get(uri.getStringValue());  
   
                 Element personal = elt.element("personal");  
                 Attribute mobile = personal.attribute("mobile-no");  
                 Attribute nickname = personal.attribute("nickname");  
   
                 buddy.mobile = mobile.getStringValue();  
                 buddy.nickname = nickname.getStringValue();  
                 buddy.buddytype = "mobile";  
   
                 String display = buddy.localname;  
                 if (display.equals(""))  
                     display = buddy.nickname;  
                 if (display.equals(""))  
                     display = buddy.mobile;  
                 if (display.equals(""))  
                     display = "猪头啦";  
                 buddy.displayname = display;  
             }  
   
         } catch (Exception ex) {  
   
         }  
   
         return allBuddys;  
   
     }  
   
     private HashMap<String, buddyInfo> getContactsList() {  
         String arg = "<args><contacts><buddy-lists /><buddies attributes=\"all\" />";  
         arg += "<mobile-buddies attributes=\"all\" /><chat-friends /><blacklist /></contacts></args>";  
   
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "1 S");  
         fields.put("N", "GetContactList");  
         String msg = createSipData(SIP_S, fields, arg) + "SIPP";  
   
         sendRequest(nextUrl("s"), msg);  
         String response = sendRequest(nextUrl("s"), "SIPP").response;  
   
         HashMap<String, buddyInfo> lstbuddys = new HashMap<String, buddyInfo>();  
   
         try {  
             String[] resSplit = response.split("\r\n\r\n");  
             String xmlData = resSplit[1].replace("</results>SIPP", "</results>");  
   
             Document xml = DocumentHelper.parseText(xmlData);  
   
             // 获取飞信好友  
             List buddys = xml.selectNodes("/results/contacts/buddies/buddy");  
             Iterator itb = buddys.iterator();  
             while (itb.hasNext()) {  
                 Element elt = (Element) itb.next();  
                 Attribute uri = elt.attribute("uri");  
                 Attribute localname = elt.attribute("local-name");  
   
                 buddyInfo buddy = new buddyInfo();  
                 buddy.uri = uri.getStringValue();  
                 buddy.localname = localname.getStringValue();  
                 buddy.buddytype = "buddy";  
                 lstbuddys.put(buddy.uri, buddy);  
             }  
   
             // 获取手机好友  
             List mobiles = xml.selectNodes("/results/contacts/mobile-buddies/mobile-buddy");  
             Iterator itm = mobiles.iterator();  
             while (itm.hasNext()) {  
                 Element elt = (Element) itm.next();  
                 Attribute uri = elt.attribute("uri");  
                 Attribute localname = elt.attribute("local-name");  
   
                 buddyInfo buddy = new buddyInfo();  
                 buddy.uri = uri.getStringValue();  
                 buddy.localname = localname.getStringValue();  
                 buddy.buddytype = "mobile";  
                 lstbuddys.put(buddy.uri, buddy);  
             }  
   
         } catch (Exception ex) {  
   
         }  
   
         return lstbuddys;  
     }  
   
     private String getUri(String mobile) {  
         if (allBuddys.entrySet().size() == 0)  
             getContactsInfo();  
         for (Entry<String, buddyInfo> entry : allBuddys.entrySet()) {  
             if (entry.getValue().mobile.equals(mobile))  
                 return entry.getKey();  
         }  
   
         return null;  
     }  
   
     public boolean sendCatSms(String content) {  
         return sendCatSms(null, content);  
     }  
   
     public boolean sendCatSms(String to, String content) {  
   
         // T试了好像只能是标准的sip地址,不知道有没有什么办法能换成手机号,sip:57358215@fetion.com.cn;p=4009中4009的计算公式:  
         // 13开头的手机号  
         // p=手机号码前6位 - 134099  
         // 15开头的手机号  
         // p=手机号码前6位 - 153099  
   
         // String toMobile = buddys.get(to);  
   
         // if (toMobile == null || "".equals(toMobile))  
         // return false;  
   
         String sendto = to;  
         if (!to.startsWith("sip"))  
             sendto = getUri(to);  
         if (sendto == null)  
             return false;  
   
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "1 M");  
         fields.put("T", to == null ? uri : sendto);  
         fields.put("N", "SendCatSMS");  
         String msg = createSipData(SIP_M, fields, content) + "SIPP";  
   
         sendRequest(nextUrl("s"), msg);  
         String response = sendRequest(nextUrl("s"), "SIPP").response;  
   
         if (response.indexOf("Send SMS OK") > 0)  
             return true;  
         else  
             return false;  
     }  
   
     public boolean sendSms(String to, String content) {  
         int len = content.length();  
         HashMap<String, String> fields = new HashMap<String, String>();  
         fields.put("F", sid);  
         fields.put("I", nextCall());  
         fields.put("Q", "0 M");  
         fields.put("T", uri);  
         fields.put("C", "text/html-fragment");  
         fields.put("K", "SaveHistory");  
         fields.put("L", String.valueOf(len));  
         String msg = createSipData(SIP_M, fields, content) + "SIPP";  
   
         String response = sendRequest(nextUrl("s"), msg).response;  
         response = sendRequest(nextUrl("s"), "SIPP").response;  
   
         if (response.indexOf("Send SMS OK") > 0)  
             return true;  
         else  
             return false;  
     }  
 }  
posted @ 2009-12-13 14:42  龙城叫花鸡  阅读(905)  评论(0编辑  收藏  举报