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;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值