网友分享的用aardio开发的SmartQQ源码

源码如下(直接可运行):

import win.ui; import process; import console;
/*DSG{{*/
mainForm = win.form(text="SmartQQ--by Danboy";right=543;bottom=490;max=false)
mainForm.add(
button={cls="button";text="扫码登录";left=48;top=435;right=174;bottom=462;ah=1;aw=1;z=10};
edit={cls="edit";left=242;top=26;right=523;bottom=113;ah=1;aw=1;bgcolor=16053492;edge=1;multiline=1;style=1539;z=1};
groupbox={cls="groupbox";left=7;top=0;right=218;bottom=467;ah=1;aw=1;bgcolor=15793151;edge=1;z=2};
groupbox2={cls="groupbox";text="消息群发:";left=226;top=10;right=537;bottom=167;ah=1;aw=1;edge=1;z=7};
groupbox3={cls="groupbox";text="消息接收";left=224;top=187;right=537;bottom=467;ah=1;aw=1;edge=1;z=9};
phtoplus={cls="plus";left=12;top=6;right=50;bottom=44;ah=1;aw=1;z=3};
qrplus={cls="plus";left=20;top=260;right=210;bottom=429;ah=1;aw=1;foreRepeat="center";z=5};
richedit={cls="richedit";left=227;top=201;right=534;bottom=463;ah=1;aw=1;bgcolor=16053492;multiline=1;vscroll=1;wrap=1;z=11};
send={cls="button";text="发送";left=345;top=124;right=422;bottom=162;ah=1;aw=1;z=8};
static={cls="static";left=65;top=28;right=207;bottom=42;ah=1;aw=1;transparent=1;z=6};
treeview={cls="treeview";left=7;top=49;right=216;bottom=463;ah=1;asel=false;aw=1;bgcolor=15856113;edge=1;hide=1;style=256;vscroll=1;z=4}
)
/*}}*/

mainForm.button.oncommand = function(id,event){
thread.set("runStart",true);
}

mainForm.wndproc = function(hwnd,message,wParam,lParam){
if wParam == 0xF060/*_SC_CLOSE*/ process().terminate();
}
mainForm.enableDpiScaling();
mainForm.show();

mainForm.qrplus.foreground = "\res\alloylogo.png";
import win.ui.statusbar;
win.ui.statusbar(mainForm).addItem('源码请访问:http://bbs.aardio.com/', 520/*宽度*/);

while ! thread.get("runStart") { win.delay(1000); }

import fsys;
fsys.delete( {"C:\二维码.png";"C:\phto.png";"C:\phtos.png"});
var http = com.CreateObject("WinHttp.WinHttpRequest.5.1");
http.setOption(4,13056); //忽略错误标志
http.SetTimeouts(10000,100000,10000,10000 ); //设置超时
var t = tostring(math.random()) ++ tostring(math.random(10, 99));
http.Open("GET","https://ssl.ptlogin2.qq.com/ptqrshow?appid=501004106&e=0&l=M&s=5&d=72&v=4&t=0" ++ t , false);
http.Send();
var stream = com.CreateObject("Adodb.Stream");
stream.Type = 1;
stream.Mode = 3;
stream.Open();
stream.Write( { _safearray = http.ResponseBody } ); //aardio13.52后版本可以直接写成:stream.Write(http.ResponseBody)
stream.SaveToFile("C:\二维码.png",2);
stream.Close();
mainForm.qrplus.foreground = "C:\二维码.png";

var qrsig = string.match(http.GetResponseHeader("Set-Cookie"),"qrsig=(.+?);");
import web.script;
var js = web.script("JavaScript");
var hash33 = /*
function hash33(o) {
for (var t = 0,
e = 0,
n = o.length; e < n; ++e) t += (t << 5) + o.charCodeAt(e);
return 2147483647 & t
}
hash33("
*/
var ptqrtoken = js.Eval(hash33 ++ qrsig ++ '")');
var nickname;
while true {
http.Open("GET",'https://ssl.ptlogin2.qq.com/ptqrlogin?u1=http%3A%2F%2Fw.qq.com%2Fproxy.html&ptqrtoken=' ++ ptqrtoken ++ '&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1504153382266&js_ver=10228&js_type=1&login_sig=&pt_uistyle=40&aid=501004106&daid=164&mibao_css=m_webqq&',false);
http.Send(); //响应信息,判断是二维码状态(是否失效、认证)和首次登录
win.delay(1000);
if string.indexOf(http.ResponseText,"登录成功") {
var checkUrl = string.match(http.ResponseText,"(http.+?)',");
nickname = string.left(string.split(http.ResponseText,"<'登录成功!', '>")[2],string.len(string.split(http.ResponseText,"<'登录成功!', '>")[2]) - 5,true); //登录的QQ昵称
http.setOption(6,0); //禁止自动重定向
http.Open("GET",checkUrl,false);
http.Send(); //检测登录
break ;
} elseif string.indexOf(http.ResponseText,"二维码已失效") {
mainForm.msgbox("二维码已失效,请重试"); process().terminate();
}

}
var uin,skey,p_uin,p_skey,pt4_token = string.match(http.GetAllResponseHeaders(),"uin=(.+?);.+?skey=(.+?);.+?p_uin=(.+?);.+?p_skey=(.+?);.+?pt4_token=(.+?);");
var cookie = "uin=" ++ uin ++ "; skey=" ++ skey ++ "; p_uin=" ++ p_uin ++ "; p_skey=" ++ p_skey ++ "; pt4_token=" ++ pt4_token ++ "; ptwebqq=" ++ qrsig; //须加qrsig
thread.set("cookie",cookie);

http.Open("GET",'http://s.web2.qq.com/api/getvfwebqq?ptwebqq=&clientid=53999199&psessionid=&t=1504250606785',false);
http.SetRequestHeader("Referer", 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1');
http.SetRequestHeader("Cookie","uin=" ++ uin ++ "; skey=" ++ skey ++ "; p_uin=" ++ p_uin ++ "; p_skey=" ++ p_skey ++ "; pt4_token=" ++ pt4_token ++ ";");
http.Send();
import web.json;
var vfwebqq = web.json.parse(http.ResponseText)["result"]["vfwebqq"]; //取得vfwebqq

//二次登录
http.Open("POST",'http://d1.web2.qq.com/channel/login2',false);
http.SetRequestHeader("Referer", 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2');
http.SetRequestHeader("Cookie",cookie);
http.Send('r={"ptwebqq":"","clientid":53999199,"psessionid":"","status":"online"}');
var psessionid,QQ = web.json.parse(http.ResponseText)["result"]["psessionid"],web.json.parse(http.ResponseText)["result"]["uin"];
thread.set("psessionid",psessionid); thread.set("QQ",QQ);

var gethash = /*
var hash2 = function(uin,ptvfwebqq){
uin += "";
var ptb = [];
for (var i=0;i<ptvfwebqq.length;i++){
var ptbIndex = i%4;
ptb[ptbIndex] ^= ptvfwebqq.charCodeAt(i);
}
var salt = ["EC", "OK"];
var uinByte = [];
uinByte[0] = (((uin >> 24) & 0xFF) ^ salt[0].charCodeAt(0));
uinByte[1] = (((uin >> 16) & 0xFF) ^ salt[0].charCodeAt(1));
uinByte[2] = (((uin >> 8) & 0xFF) ^ salt[1].charCodeAt(0));
uinByte[3] = ((uin & 0xFF) ^ salt[1].charCodeAt(1));
var result = [];
for (var i=0;i<8;i++){
if (i%2 == 0)
result = ptb[i>>1];
else
result = uinByte[i>>1];
}
return byte2hex(result);

};
var byte2hex = function(bytes){//bytes array
var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
var buf = "";

for (var i=0;i<bytes.length;i++){
buf += (hex[(bytes>>4) & 0xF]);
buf += (hex[bytes & 0xF]);
}
return buf;
}
hash2("
*/
var hash = js.Eval(gethash ++ QQ ++ '","' + qrsig + '")'); //获取hash

http.Open("GET", 'http://d1.web2.qq.com/channel/get_online_buddies2?vfwebqq=' + vfwebqq + '&clientid=53999199&psessionid=' + psessionid + '&t=1505017526904',false)
http.SetRequestHeader("Referer", 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2');
http.SetRequestHeader("Cookie",cookie);
http.Send(); //获取登录状态
if string.indexOf(http.ResponseText,"online") {
mainForm.static.text = nickname; mainForm.button.hide = 1;
} else {
mainForm.msgbox("登录失败,请重新尝试"); process().terminate();
}

http.Open("POST",'http://s.web2.qq.com/api/get_user_friends2',false); //取好友列表
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.SetRequestHeader("Referer", 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1');
http.SetRequestHeader("Cookie",cookie);
http.Send('r={"vfwebqq":"' + vfwebqq + '","hash":"' + hash + '"}');
var friendtab = web.json.parse(http.ResponseText);
for i=1;#friendtab["result"]["categories"] - 1 { //分组名排序
for j=i+1;#friendtab["result"]["categories"] {
if tonumber(friendtab["result"]["categories"]["sort"]) > tonumber(friendtab["result"]["categories"][j]["sort"]) {
table.insert(friendtab["result"]["categories"],friendtab["result"]["categories"][j],i);
table.remove(friendtab["result"]["categories"],j+1);
}
}
}
var hitem = mainForm.treeview.insertItem(text = "QQ好友");
var qqfs0 = mainForm.treeview.insertItem({text = "我的好友"},hitem);
var qqfstab,uintab,gidtab = {},{},{}; table.push(qqfstab,qqfs0);
for i=1;#friendtab["result"]["categories"] { //挑出各分组成员名
var qqfs1 = mainForm.treeview.insertItem({text = friendtab["result"]["categories"]["name"]},hitem); //分组名加到QQ好友根组下
table.push(qqfstab,qqfs1);
for j=1;#friendtab["result"]["friends"] {
if ! friendtab["result"]["friends"][j] continue ;
if friendtab["result"]["friends"][j]["categories"] == friendtab["result"]["categories"]["index"] { //分组
for k=1;#friendtab["result"]["marknames"] {
if friendtab["result"]["marknames"][k]["uin"] == friendtab["result"]["friends"][j]["uin"] {
table.push(uintab,friendtab["result"]["marknames"][k]["markname"],friendtab["result"]["friends"][j]["uin"]);
mainForm.treeview.insertItem({friendtab["result"]["marknames"][k]["markname"]},qqfs1);
friendtab["result"]["friends"][j] = null; break ;
}
}
for k=1;#friendtab["result"]["info"] {
if ! friendtab["result"]["friends"][j] continue ;
if friendtab["result"]["info"][k]["uin"] == friendtab["result"]["friends"][j]["uin"] {
table.push(uintab,friendtab["result"]["info"][k]["nick"],friendtab["result"]["friends"][j]["uin"])
mainForm.treeview.insertItem({friendtab["result"]["info"][k]["nick"]},qqfs1);
}
}
} elseif i == 1 ? friendtab["result"]["friends"][j]["categories"] == "0" { //我的好友
for k=1;#friendtab["result"]["marknames"] {
if friendtab["result"]["marknames"][k]["uin"] == friendtab["result"]["friends"][j]["uin"] {
table.push(uintab,friendtab["result"]["marknames"][k]["markname"],friendtab["result"]["friends"][j]["uin"]);
mainForm.treeview.insertItem({friendtab["result"]["marknames"][k]["markname"]},qqfs0);
friendtab["result"]["friends"][j] = null; break ;
}
}
for k=1;#friendtab["result"]["info"] {
if ! friendtab["result"]["friends"][j] continue ;
if friendtab["result"]["info"][k]["uin"] == friendtab["result"]["friends"][j]["uin"] {
table.push(uintab,friendtab["result"]["info"][k]["nick"],friendtab["result"]["friends"][j]["uin"]);
mainForm.treeview.insertItem({friendtab["result"]["info"][k]["nick"]},qqfs0);
}
}
}

}
}

http.Open("POST",'http://s.web2.qq.com/api/get_group_name_list_mask2',false); //取群列表
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.SetRequestHeader("Referer", 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1');
http.SetRequestHeader("Cookie",cookie);
http.Send('r={"vfwebqq":"' + vfwebqq + '","hash":"' + hash + '"}');
var grouptab = web.json.parse(http.ResponseText);
var hitemq = mainForm.treeview.insertItem(text = "QQ群组");
for i=1;#grouptab["result"]["gnamelist"] {
table.push(gidtab,grouptab["result"]["gnamelist"]["name"],grouptab["result"]["gnamelist"]["gid"]);
mainForm.treeview.insertItem({grouptab["result"]["gnamelist"]["name"]},hitemq);
}
table.push(qqfstab,hitemq);
thread.set("uintab",uintab); thread.set("gidtab",gidtab);

import win.ui.ctrl.treeviewex; //调用树形控件扩展库实现节点自选择--carl论坛坛主的
var treeviewEx = win.ui.ctrl.treeviewex(mainForm.treeview)
treeviewEx.onnotify = function(id,code,ptr) { /*响应通知*/
return treeviewEx.exOnnotify(id,code,ptr);
};
treeviewEx.exIsToggle = true;//开启点击节点时折叠的就展开,展开的就折叠,默认已开启
treeviewEx.exIsChecked = true;//开启1.打勾节点则全选所有子节点,不打勾则全不选子节点,2.子节点其中一个打勾,则父节点打勾,默认已开启

mainForm.threadCallable(); //多线程操作界面线程
thread.invoke(
function(mainForm){
import win.ui; import com; import web.json; import console; import thread.table;
var cookie = thread.get("cookie");
var uintab,gidtab = thread.get("uintab"),thread.get("gidtab");
var psessionid,QQ = thread.get("psessionid"),thread.get("QQ");
var http = com.CreateObject("WinHttp.WinHttpRequest.5.1");
http.setOption(4,13056); //忽略错误标志--不知道有什么用,该报错还是会报错而中断程序,只能加try了
http.SetTimeouts(10000,100000,10000,10000 ); //设置超时
mainForm.qrplus.hide = 1; mainForm.treeview.hide = 0;

function GetLogo(){
try { http.Open("GET", 'https://q.qlogo.cn/g?b=qq&nk=' + QQ + '&s=100&t=1505017526894',false); //取QQ头像
http.Send(); } catch (e) {
GetLogo();
}
}

GetLogo();
var stream = com.CreateObject("Adodb.Stream");
stream.Type = 1;
stream.Mode = 3;
stream.Open();
stream.Write( { _safearray = http.ResponseBody } );
stream.SaveToFile("C:\phto.png",2);
stream.Close();
import gdip.image;
var image = gdip.image("C:\phto.png");
image = image.getThumbnail(0.4,0.4,true);
image.save("C:\phtos.png");
mainForm.phtoplus.foreground = "C:\phtos.png";

while true { try { //发送心跳包接收消息
http.Open("POST",'http://d1.web2.qq.com/channel/poll2',false);
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.SetRequestHeader("Referer", 'http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2');
http.SetRequestHeader("Cookie",cookie);
http.Send('r={"ptwebqq":"","clientid":53999199,"psessionid":"' + psessionid + '","key":""}');
if http.ResponseText {
var nametab = thread.table("nametab");
var msg = web.json.parse(http.ResponseText)["result"][1]["value"]["content"][2]
var uin = web.json.parse(http.ResponseText)["result"][1]["value"]["from_uin"]
var name;
if string.indexOf(http.ResponseText,'"message"') { //QQ好友消息
for k,v in uintab {
if v = uin name = uintab[k-1]
}
for k,v in nametab.each() {
if v = name { mainForm.richedit.log("QQ好友-" + name + ': ' + msg,'\r\n');
break ; }
}
} elseif string.indexOf(http.ResponseText,"group_message") { //QQ群组消息
for k,v in gidtab {
if v = uin name = gidtab[k-1]
}
for k,v in nametab.each() {
if v = name { mainForm.richedit.log("QQ群组-" + name + ': ' + msg,'\r\n');
break ; }
}
}
if mainForm.richedit.getLength() > 2000 mainForm.richedit.clear();
}
sleep(500);
} }
},mainForm
)

mainForm.send.oncommand = function(id,event){
for i=1;#qqfstab {
if mainForm.treeview.getChecked(qqfstab) {
for hItem in mainForm.treeview.each(qqfstab){
if mainForm.treeview.getChecked(hItem) {
var name = mainForm.treeview.getItemText(hItem);
for k,v in uintab {
if v = name { //发送QQ好友消息
var buf = 'r={"to":' + uintab[k+1] +',"content":"[\\"' + mainForm.edit.text +'\\",[\\"font\\",{\\"name\\":\\"
宋体\\",\\"size\\":10,\\"style\\":[0,0,0],\\"color\\":\\"000000\\"}]]","face":0,"clientid":53999199,"msg_id":20610002,"psessionid":"' + psessionid + '"}'
http.Open("POST",'http://d1.web2.qq.com/channel/send_buddy_msg2',false);
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.SetRequestHeader("Referer", 'http://d1.web2.qq.com/cfproxy.html?v=20151105001&callback=1');
http.SetRequestHeader("Cookie",cookie);
http.Send(buf);
}
}
for k,v in gidtab {
if v = name { //发送QQ群组消息
var buf = 'r={"group_uin":' + gidtab[k+1] +',"content":"[\\"' + mainForm.edit.text +'\\",[\\"font\\",{\\"name\\":\\"
宋体\\",\\"size\\":10,\\"style\\":[0,0,0],\\"color\\":\\"000000\\"}]]","face":0,"clientid":53999199,"msg_id":20610001,"psessionid":"' + psessionid + '"}'
http.Open("POST",'http://d1.web2.qq.com/channel/send_qun_msg2',false);
http.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
http.SetRequestHeader("Referer", 'http://d1.web2.qq.com/cfproxy.html?v=20151105001&callback=1');
http.SetRequestHeader("Cookie",cookie);
http.Send(buf);
}
}
}
}
}
}
}

import thread.table;
tmid = mainForm.addtimer( //多线程用不了treeview控件的each函数,只能用定时器处理了....
500/*毫秒*/,
function(hwnd,msg,id,tick){//定时执行代码
var nametab = thread.table("nametab",true);
for i=1;#qqfstab {
if mainForm.treeview.getChecked(qqfstab) {
for hItem in mainForm.treeview.each(qqfstab){
if mainForm.treeview.getChecked(hItem) {
var name = mainForm.treeview.getItemText(hItem);
nametab.push(name);
}
}
}
}
}
);

return win.loopMessage();