This is Google's cache of http://loginprogram.googlecode.com/svn-history/r26/qqlogin/src/com/xnet/qqlogin/webqq/WebQQClient.java. It is a snapshot of the page as it appeared on 7 Jan 2013 01:46:18 GMT. The current page could have changed in the meantime. Learn more Tip: To quickly find your search term on this page, press Ctrl+F or ⌘-F (Mac) and use the find bar. Text-only version package com.xnet.qqlogin.webqq; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import javax.swing.JLabel; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpResponse; import com.xnet.browser.http.HttpService; import com.xnet.common.StringUtil; import com.xnet.qqlogin.common.GlobalURL; import com.xnet.qqlogin.common.QQUtils; import com.xnet.qqlogin.common.VerifyCode; /** * <p>Description: </p> * @author Huoyan * @version 1.0 * <p>Copyright 2011</p> */ public class WebQQClient extends HttpService { private final Log log = LogFactory.getLog(this.getClass()); private String qq = null; private String pwd = null; private boolean loginState = false; //登录状态 private long clientid = 18662986; private String psessionid = ""; private String ptwebqq; private String vfwebqq = null; private String skey = null; public WebQQClient(String qq, String pwd){ this.qq = qq; this.pwd = pwd; this.clientid = QQUtils.createClientID(); //设置请求头中参数refer setRefer(GlobalURL.REFER); } /** * webQQ接口登录 */ public void login(String verifyCode){ try { if(qq == null || pwd == null){ log.error("使用qq: " + qq + "登录时,用户名或密码为空,登录失败"); }else{/* //登录步骤1,获取登陆表单信息,检查当前QQ是否需要验证码登录 String checkIdUrl = GlobalURL.CHECK_ID_URL + qq; //发送请求 String res = getReturnStr(checkIdUrl); //使用正则匹配获取验证码编号 // ptui_checkVC('0','!ZLE');返回这个就不需要获取验证码了。验证码就是!ZLE // ptui_checkVC('1','95ab7db15e5ab17f50f25d33598259e83ccc098c4af2f8a4');这个长字符串就需要使用了 String checkType = StringUtil.findPattern("\\,\\'([!\\w]+)\\'", res); log.info(checkType); String check = ""; //客户端输入的验证码 //判断是否需要验证码登录 if (!checkType.startsWith("!")) { //需要输入验证码登录 byte[] ibs = readCheckImage(GlobalURL.CHECK_IMAGE_URL + "&uin=" + qq + "&vc_type=" + checkType); //将图片设置在组件JLable上 ImageIcon ii = new ImageIcon(ibs); //lbl.setIcon(ii); }else{ //无需验证码登录 check = checkType; }*/ StringBuffer loginUrl = new StringBuffer(GlobalURL.LOGIN_URL); //登录步骤2,发送登录信息 loginUrl.append("u=").append(qq) .append("&p=").append(QQUtils.makeMD5Str(pwd, verifyCode)) .append("&verifycode=").append(verifyCode) .append("&webqq_type=10").append("&remember_uin=1") .append("&login2qq=1").append("&aid=1003903") .append("&u1=http%3A%2F%2Fweb.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10") .append("&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=4-11-25648"); //发送请求-登录 log.info(loginUrl.toString()); String res = getReturnStr(loginUrl.toString()); log.info(res); //返回结果 // ptuiCB('0','0','http://web2.qq.com/loginproxy.html?strong=true','0','登录成功!'); // ptuiCB('3','0','','0','您输入的帐号或者密码不正确,请重新输入。'); // ptuiCB('4','0','','0','您输入的验证码有误,请重试。'); // ptuiCB('7','0','','0','很遗憾,网络连接出现异常,请您稍后再试。(688916544)'); if (StringUtil.exist("登录成功!", res)) { log.info(">>正在登录.."); } else { log.info("一登录失败"); //System.out.println(res.indexOf("3",8)); //待完善 return; } // 从cookie中提取ptwebqq,skey ptwebqq = getCookie("ptwebqq"); skey = getCookie("skey"); //登录步骤3, 再次登陆,只有这次登陆,才算真正登陆qq,这个时候,如果你qq已经登陆,会把你的qq踢下线,而且此次登陆才算上线。 String channelLoginUrl = "http://d.web2.qq.com/channel/login2"; String content = "{\"status\":\"online\",\"ptwebqq\":\"" + ptwebqq + "\",\"passwd_sig\":\"\",\"clientid\":\"" + clientid + "\",\"psessionid\":null}&clientid=" + clientid + "&psessionid="; content = "r=" + URLEncoder.encode(content);// urlencode转码,拼装post数据 //发送请求 res = postReturnStr(channelLoginUrl, content); // 这次登陆基本上不会发生什么问题 // 下面提取很重要的2个数据psessionid ,vwebqq,通用采用正则表达式,虽然结果是个json vfwebqq = StringUtil.findPattern("\"vfwebqq\":\"(\\w+)\"", res); psessionid = StringUtil.findPattern("\"psessionid\":\"(\\w+)\"", res); log.info(">>登录成功\n vfwebqq="+vfwebqq + ", psessionid="+psessionid); loginState = true; //当前登录状态 // 到此,登陆就算完成了,后面可以调用发送qq信息等接口了 } } catch (Exception e) { e.printStackTrace(); } finally { shutdown(); } } /** * 获取验证码图片字节 * @param uri */ private byte[] readCheckImage(String uri){ HttpResponse res = get(uri); byte[] b = null; try { InputStream in = res.getEntity().getContent(); b = IOUtils.toByteArray(in); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return b; } public static void main(String[] args) { //需要验证码QQ2508786110,2351221103, 2536565342 //不需要2232924183 WebQQClient c = new WebQQClient("2232924183", "asdf1234"); String vc = new VerifyCode(c.getClient()).getVerifyCode("2232924183", new JLabel()); c.login(vc); } }
poll的返回值,也是一个JSON结构,如:{"retcode":103,"errmsg":""} {"retcode":121,"t":"0"} {"retcode":100006,"errmsg":""}
返回103、121,代表连接不成功,需要重新登录;
返回102,代表连接正常,此时服务器暂无信息;
返回0,代表服务器有信息传递过来:包括群信、群成员给你的发信,QQ好友给你的发信。
另外,此程序必须考虑另一种情况:如果网络断线,curl_easy_perform()将返回CURLE_COULDNT_RESOLVE_HOST,返回值buffer为了避免无效赋值:必须赋值为空字符串。
发生错误或有信息到来之时,poll马上返回相应的JSON,占用的时间很短;
但没有信息过来的时候,poll占用的时间一般比较长,不确定,时快时慢。
2)如果等poll获得返回值之后,再去响应用户其他的动作,会感觉有点卡。于是我们另开一个线程,循环不断的poll,而不影响主程序的正常响应,这就是所谓的异步通信;如获得有效信息,即可通过SendMessage消息机制传回主窗口。
线程程序:
http://svn.code.sf.net/p/pythonguiqq/code-0/trunk/api/Api_socket.py
http://svn.code.sf.net/p/pythonguiqq/code-0/trunk/api/md5.py
https://code.google.com/p/loginprogram/source/checkout