基于C语言Dll调用的pythonqq的一个应用拜年消息群发器的开发 - 开发 - 人日子...

来源:百度文库 编辑:神马文学网 时间:2024/04/27 14:50:03
基于C语言Dll调用的pythonqq的一个应用拜年消息群发器的开发文件: CQQlib&pythonqq.rar
大小: 262KB
下载:下载
源码共享之一:python dll调用,QQ消息群发,QQ自动化处理
QQ上的好友一大堆,很长时间以来想要群发消息给所有用户,但是搜索过无数次,尚没有发现一款好用免费的软件来群发消息,而且还要提心木马在程序中安插又不敢随便安装使用各种群发器。其实好用的群发器肯定是存在的,并且有些甚至不用加为好友就能发送广告消息,这是我还没有掌握的技术。不过多谢一些朋友的督促和帮助,我找一种给自己QQ好友群发消息的开源技术,在此公布出来与大家分享。
这项技术的来源是由于一次偶然的开发任务,那时一个好友提出需要QQ自动接收处理消息,我利用一个多月的时间找寻所有可能的实现方案,其中包括,
1、JAVA QQ,我下载QQ的JAVA开源版本,其中最容易找到的是LUMAQQ,但是已不能使用,停止了开发,但是我相信JAVA的QQ肯定有一些还是能用的,因为手机版的JAVA支持不会停止,
2、NET平台的QQ。我随后找一份开源的项目,LUMAQQ.NET是针对java lumaQQ转换到C#代码的。后来也是故障连连。
3、针对标准QQ程序的窗口监控,可能是就是传说中的钩子,由于以我的水平发现QQ这种隐藏较深的窗口消息事件,并处理这些事件难度太大,在我SPY++定位一个消息窗口失败后放弃了,后来我见到过其它人用这种方式截取QQ消息,当其我只是用模拟鼠标键盘的形式,群发了一堆消息就停止研究了。
4、WEBQQ,后来当我无计可施,打开了WEBQQ正在测试的页面,打算从WEB页面的跳动中的消息图标中找到突破口,当然这要用,.net来内嵌一个IE控件.并对DOCUMENT对象进行检索并做出处理.后来我才知道,WXPYTHON也能做这方面的工作.我不知道这个方式发展下去会怎么样,但这个时候光明出现了.当我和QQ机器人研究群中的一个程序员讨论WEBQQ机器人的问题时,他提到WEBQQ已经有人实现了啊.名叫myqq并给了我一下地址,我十分感谢他的提供,这是这篇文章所以后续内空的必要前提 ,所以我们必须记住并感谢的还有MYQQ的作者,09年的一个高三学生. 可是那我对他所说的WEB实现尚有疑问,那是需要QQ的WEB服务器的啊, 可是当我下载回他所说的源码及可运行程序的时候.我按说明运行了他的WEB服务,并打了网页,原来这是一个处理WEB请求的本地DLL控件.并在本地打开了一个服务端口.界面HTML+JAVASCRITP实现的. 我登录成功后心里充满了欢喜,并且带着很多的哀愁.那是因为C语言真难.
以上是几种偿试带着未了的愿望迎来了最终本文的重点.这里有两种核心方案分别是
1、C语言包装QQ协议,这是本文的重点,当我研究myqq 的代码及说明时我发现了这样的提示,WEB界面的QQ只是控制台QQ的一个包装,WEBQQ经常自己退出,而且不能登录,我当时还在想通过对JAVASCRIPT代码的更改达到QQ消息群发及消息到达回调函数的实现. 这样我无路可走了. 必须研究C语言的控制台代码,因为当时控制台的QQ相当稳定了.这样我操起十分不熟练的C,安装了一个蹩脚的C开发工具,DEV C++4.9. 他的蹩脚部分是因为他不能显不中文字符,即使是UNICODE编码的.这个问题只到现在困扰着我. 但在当时还有另一个问题,根本不能通过编译. 事情往往来得十分凑巧.第一次使用这个工具的我,居然很快又发现了需要进行一些必要的编译参数设置,其中关键的是,PGTHREAD这个参数,还有对,LIB库文件路径的引用.当我把所有这些做好后. 生成了第一个可以运行的C程序这是在我十年来生成的第一个C的EXE. 剩下的找编所有网站,把一段用C来请求WEB的代码写进来, 因为原来的代码中有一段取得QQ验证图片的代码,可是不能直接使用,但是为我节省了很多的时间.因为同样的SOCKET的调用.这一组代码为我带来了几K的收入,也是我从没预料的结果.因为我十分想找到myqq的作者分享这一点点收入.但是他还在专心考试,后来才有他考试结束的结果.当然这点收入太微不足道,始终没有跟他联系并提示一方面的信息,这成为我自己的小猫腻.
2、最后本文的所要分享的PYTHON的QQ,由于python的易用性和跨平台性,多年前我接触了一个PYTHON的QQ在这次开发过程中我又找到了它,但是这个项目和多年前基本状态没变,而QQ的协议已经千变万化了,我想myqq的成功运行就在于作者协议分析与实现的超强能力.我一直以来想把myqq与python的调用相结合.方式一通过python调用C的函数,比如登录和消息发送,方式二,通过C语言调用python的httplib然而这两种方式,相当难处理.在数年前我偶然的兴趣,曾实现过,python调用一个自已生成的C语言弄DLL.以提高图片分析对比的效率.这让我有机会凭直觉发现了一个myqq 作者安排的小窍门.作者在源码中安置了一个libqq.c其中生成文件中也有一个,libqq.dll,仿佛这就是那种公布出来的DLL接口,而python调用它应该不成问题.在我所有的QQ相当工作勉强提交完成后,我操起稍显熟悉的DEV C++.用默认的模版生成了一个,DLL hellworld 并且用,python的ctype去访问它.很顺利,我随后战战兢兢的打开myqq的源本,引入一个空白的DEV C++ DLL项目,通过LIB添加,生成参数的设置.我勇敢的把它进行再生成,当然出现了一些小错误还有异常,我顺着这棵向上延伸的青藤,处理了它上面生成的小虫们.这样我的项目,完全地成功的,在目的地址上产生了一个,显示更新日期为当前时间的, mydlldym.dll这是我自己起的名字.这样我的第一步完成了.
虽然如此我怀着对它能正常入驻python空间的怀疑,这种怀疑是因为myqq运行空间的不确定性,因为它的内部的处理可能并不合乎,python ctype的要求,有一些接口或参数类型可能会被挡在C语言的门外,让python望而兴叹,这是我所准备的,我只是在玩一个不知道结果的游戏.因为我对它们两个的交谈基本是门处汉.事情没有想像的糟糕,myqq的作者功夫了得,C的接口安排的有如天衣.登录和访问都没有问题.我的胆子放大了.回调函数是我要处理的关键. 我想要把python的回调函数指针传递给C的接口,这样我的工作就完成了.而在这以前我只知道,C的函数只是指针,而python的函数也只是一个空间的启始位置. 这次我要依靠Ctype了,我勇敢的碰一次运气吧. 我在DEV C++中笨捉地定义了接收接口,它的参数是*func类型,我的说法不够规范,但还能用并且不远处的时间点又一次给了我次一级的惊喜.因为高一级的惊喜是刚才的步骤所完成的python可以调用这个毛头小子的,libqq.原来python和C加在一起可能完成这项了不以的任务,其中有劳了ctype来搭起通信的桥梁. 我想其它的语言也是这可以使用libqq的,毕竟它的作者并没有预期python 会来访问它.所以这个跨语言的接入,在C的发展过程中已经按排好,并且肯定有相应的文档来规范这种行为,只是我当时并没有接触过官方说明.我感觉这些说明肯定会让人头大,而且如果我看过了也就只能剩下按部就班的验证了.而不会带给我什么喜悦之类的感触了.
至此我的python 和c 语言的dll正式会面并且贡献出来一个消息群发的免费的程序实现.相信对python爱好者是个好事.也会较有兴趣继续偿试的.谢谢大家观看,更谢谢那些编程资源的提供者们.
下面是libqq.c的源码,也就是调用之接口.开发工具,dev C++4.9 ,win XP
/*
* libqq.c
*
* LibQQ Program
*
* Copyright (C) 2009 Huang Guan
*
* 2009-5-6 23:23:51 Created.
*
* Description: This file mainly includes the functions about
*
*/
#define LIBQQLIB
#include
#include
#include
#include
#include
#include
#ifdef __WIN32__
#include
#include
#else
#include
#include
#endif
#include "debug.h"
#include "memory.h"
#include "qqclient.h"
#include "libqq.h"
#include "loop.h"
#include "buddy.h"
#include "qun.h"
#include "group.h"
#include "config.h"
#include "qqsocket.h"
#include "utf8.h"
#define MAX_USERS 1000
static int if_init = 0;
int (*FunP)(char * msg);
static char* util_escape( char* str )
{
unsigned char* ch;
ch = (unsigned char*)str;
while( *ch )
{
if( *ch < 0x80 ) //ASCII??
{
if( !isprint(*ch) ) //if not printable??
*ch = ' ';    //use space instead..
ch ++;    //skip one
}else{
ch +=2; //skip two
}
}
return str;
}
static char* mode_string( int mode )
{
switch( mode ){
case QQ_ONLINE:
return "Online";
case QQ_AWAY:
return "Away";
case QQ_BUSY:
return "Busy";
case QQ_OFFLINE:
return "Offline";
case QQ_HIDDEN:
return "Hidden";
case QQ_KILLME:
return "Kill Me";
case QQ_QUIET:
return "Quiet";
}
return "Unknown";
}
static void* login_ex( void* data )
{
qqclient* qq = (qqclient*) data;
pthread_detach(pthread_self());
DBG("login: %u", qq->number );
qqclient_login( qq );
return NULL;
}
EXPORT void libqq_setcallbackfunc(int (*pyFunP)(char * msg))
{
FunP=pyFunP;
FunP("set qq callback ok \n");
}
EXPORT int libqq_getstatus( qqclient* qq,qqstatus * pystatus)
{ pystatus->proxy_server_ip=qq->proxy_server_ip;
pystatus->number=qq->number;
pystatus->proxy_server_port=qq->proxy_server_port;
pystatus->last_login_time=qq->last_login_time;
pystatus->process=qq->process;
return 0;
}
EXPORT int libqq_getfriends(qqclient* qq, char* buf, int size, char online)
{
int i, len = 0;
//avoid editing the array
buf[0] = 0;
pthread_mutex_lock( &qq->buddy_list.mutex );
int ln = 1;
for( i=0; ibuddy_list.count; i++ )
{
qqbuddy * b = (qqbuddy*)qq->buddy_list.items[i];
if( online && b->status == QQ_OFFLINE ) continue;
if( *b->alias ){
len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln ++, b->number,
mode_string( (int) b->status ), util_escape( b->alias ) );
}else{
len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln ++, b->number,
mode_string( (int) b->status ), util_escape( b->nickname ) );
}
if( len + 80 > size ) break;
}
pthread_mutex_unlock( &qq->buddy_list.mutex );
return len;
}
EXPORT void libqq_init()
{
config_init();
if_init = 1;
qqsocket_init();
FunP=NULL;
}
EXPORT void libqq_cleanup()
{
config_end();
qqsocket_end();
}
EXPORT qqclient* libqq_create( uint number, char* pass )
{
if (FunP!=NULL)
{
(*FunP)("create qq --test call back ok\n");
}
qqclient* qq;
if( !if_init )
libqq_init();
NEW( qq, sizeof(qqclient) );
if( !qq ){
DEL( qq );
return NULL;
}
qqclient_create( qq, number, pass );
qq->auto_accept = 1;    //temporarily do this
return qq;
}
EXPORT int libqq_login( qqclient* qq )
{
int ret;
pthread_t ptr;
ret = pthread_create( &ptr, NULL, login_ex, (void*)qq );
if(    ret != 0 ){
DBG("thread creation failed. ret=%d", ret );
}
return ret;
}
EXPORT int libqq_logout( qqclient* qq )
{
DBG("logout %u", qq->number );
qqclient_logout( qq );
return 0;
}
EXPORT int libqq_detach( qqclient* qq )
{
DBG("detach %u", qq->number );
qqclient_detach( qq );
return 0;
}
EXPORT int libqq_getmessage( qqclient* qq, char* buf, int size, int wait )
{
int ret;
ret = qqclient_get_event( qq, buf, size, wait );
utf8_to_gb( buf, buf, size );
return ret;
}
EXPORT int libqq_sendmessage( qqclient* qq, uint to, char* buf, char qun_msg )
{
char* tmp;
int len = strlen(buf);
if( len<1 ) return -2;
NEW( tmp, len*2 );
gb_to_utf8( buf, tmp, len*2-1 );
if( qun_msg ){
qqqun* q = qun_get_by_ext( qq, to );
if( q )
qun_send_message( qq, q->number, tmp );
}else{
buddy_send_message( qq, to, tmp );
}
DEL( tmp );
return 0;
}
EXPORT void libqq_updatelist( qqclient* qq )
{
buddy_update_list( qq );
group_update_list( qq );
}
// 090622 by Huang Guan. change the type of code from uint to const char*
EXPORT void libqq_verify( qqclient* qq, const char* code )
{
if( code ){
qqclient_verify( qq, *(uint*)code );
}else{
qqclient_verify( qq, 0x00000000 );    //this will make the server change another png
}
}
EXPORT void libqq_remove( qqclient* qq )
{
qqclient_cleanup( qq );    //will call qqclient_logout if necessary
DEL( qq );
}
EXPORT void libqq_status( qqclient* qq, int st, uchar has_camera )
{
qq->has_camera = has_camera;
qqclient_change_status( qq, st );
}
EXPORT void libqq_addbuddy( qqclient* qq, uint uid, char* msg )
{
qqclient_add( qq, uid, msg );
}
EXPORT void libqq_delbuddy( qqclient* qq, uint uid )
{
qqclient_del( qq, uid );
}
void buddy_msg_callback ( qqclient* qq, uint uid, time_t t, char* msg )
{
char timestr[24];
struct tm * timeinfo;
char* str;
int len;
timeinfo = localtime ( &t );
strftime( timestr, 24, "%Y-%m-%d %H:%M:%S", timeinfo );
len = strlen( msg );
NEW( str, len+64 );
if( uid == 10000 ){
sprintf( str, "broadcast^$System^$%s", msg );
}else{
sprintf( str, "buddymsg^$%u^$%s^$%s", uid, timestr, msg );
}
if (FunP!=NULL)
{
(*FunP)(str);
}
//    printf("%s",str);
qqclient_put_message( qq, str );
}
void qun_msg_callback ( qqclient* qq, uint uid, uint int_uid,
time_t t, char* msg )
{
qqqun* q;
char timestr[24];
struct tm * timeinfo;
char* str;
int len;
timeinfo = localtime ( &t );
strftime( timestr, 24, "%Y-%m-%d %H:%M:%S", timeinfo );
q = qun_get( qq, int_uid, 1 );
if( !q ){
DBG("error: q=NULL");
return;
}
len = strlen( msg );
NEW( str, len+64 );
sprintf( str, "clustermsg^$%u^$%u^$%s^$%s", q->ext_number, uid, timestr, msg );
qqclient_put_message( qq, str );
}
EXPORT uint libqq_refresh( qqclient* qq )
{
char event[16];
qqclient_set_process( qq, qq->process );
sprintf( event, "status^$%d", qq->mode );
qqclient_put_event( qq, event );
buddy_put_event( qq );
group_put_event( qq );
qun_put_event( qq );
qqclient_set_process( qq, qq->process );
return qq->number;
}
EXPORT void libqq_getqunname( qqclient* qq, uint ext_id, char* buf )
{
qqqun* q = qun_get_by_ext( qq, ext_id );
if( q ){
strncpy( buf, q->name, 15 );
}else{
if( ext_id != 0 ){
sprintf( buf, "%u" , ext_id );
}
}
}
EXPORT void libqq_getqunmembername( qqclient* qq, uint ext_id, uint uid, char* buf )
{
qqqun* q = qun_get_by_ext( qq, ext_id );
if( q ){
qunmember* m = qun_member_get( qq, q, uid, 0 );
if( m ){
strncpy( buf, m->nickname, 15 );
return;
}
}
if( uid != 0 ){
sprintf( buf, "%u" , uid );
}
}
EXPORT void libqq_getbuddyname( qqclient* qq, uint uid, char* buf )
{
qqbuddy* b = buddy_get( qq, uid, 0 );
if( b ){
strncpy( buf, b->nickname, 15 );
}else{
if( uid != 0 ){
sprintf( buf, "%u" , uid );
}
}
}
// 090706 by HG
EXPORT void libqq_sethttpproxy( struct qqclient* qq, char* ip, ushort port )
{
struct sockaddr_in addr;
qq->network = PROXY_HTTP;
netaddr_set( ip, &addr );
qq->proxy_server_ip = ntohl( addr.sin_addr.s_addr );
qq->proxy_server_port = port;
}
EXPORT void libqq_getextrainfo( struct qqclient* qq, uint uid )
{
prot_buddy_get_extra_info( qq, uid );
}
下面是pythonqq.py也就是主程序 开发环境pytho2.6 ctype1.1 win XP ,
# -*- coding: cp936 -*-
from ctypes import *
import sys,os,getpass
import time
import autoreload
import cPickle
qq=None
m=None
sysct = sys.getfilesystemencoding()
def callback(abc):
global m
s="%s"%abc
ct = sys.getfilesystemencoding()
msg=s.decode('UTF-8').encode(sysct)
if (msg.find("$verf")==0 and qq):
m=msg
if msg.endswith("back "):
m=msg
print msg
return 0
CMPFUNC = CFUNCTYPE(c_int,c_char_p)
_callback = CMPFUNC(callback)
process=('P_INIT','P_LOGGING','P_VERIFYING','P_LOGIN','P_ERROR','P_DENIED','P_WRONGPASS','P_BUSY',)
class pyStatus(Structure):
_fields_ = [
('number',c_uint),
('proxy_server_ip',c_uint),
('proxy_server_port',c_ushort),
('last_login_time',c_uint),
('process',c_int),
]
class myqq():
def __init__(self,uid,pw):
self.xpuser=getpass.getuser()
self.conffile=self.xpuser+"/data.ini"
self.load()
self.dll = WinDLL("mydlldym.dll")
self.dll.libqq_init()
self.qq= self.dll.libqq_create(uid,pw)
self.dll.libqq_getstatus.argtypes = [c_int,POINTER(pyStatus)]
self.setcallback(_callback)
self.dll.libqq_login(self.qq)
self.status=pyStatus()
self.getstatus()
#buf='\0'*1024
#self.dll.libqq_getmessage(self.qq,buf,len(buf),-0)
def getstatus(self):
self.dll.libqq_getstatus(self.qq,byref(self.status))
return self.status
def setcallback(self,cbk):
self.dll.libqq_setcallbackfunc(cbk)
def sendmsg(self,uid,msg):
self.dll.libqq_sendmessage(self.qq,uid,msg,False )
def verify(self ,vstr):
self.dll.libqq_verify(self.qq,vstr)
def getfriends(self,online=0):
global sysct
buf='\0\0'*1024*10
self.dll.libqq_getfriends(self.qq,buf,len(buf),online)
self.buf=buf[:buf.find('\0')-1]
self.buf=self.buf.strip().decode('UTF-8').encode(sysct)
del buf
self.friends=[one.split() for one in self.buf.split('\n') ]
return len(self.friends)
def sendtoall(self,msg="天气不错。",wait=2,refresh=1):
if refresh:
self.getfriends()
self.havasend=[]
else :
self.load()
for i in qq.friends:
print i
if len(i)==4 and (i not in self.havasend):
print "begin send!"
self.sendmsg(int(i[1]),"@%s~:%s"%(i[3],msg))
self.havasend.append(i)
self.save()
print "have send!"
time.sleep(wait)
def close(self):
self.dll.libqq_logout(self.qq)
self.dll.libqq_cleanup()
self.save()
def load(self):
if os.path.exists(self.conffile):
self.friends,self.havasend=cPickle.load(open(self.conffile,'r'))
else:
self.friends,self.havasend=None,None
def save(self):
if not os.path.exists(self.xpuser):
os.mkdir(self.xpuser)
cPickle.dump((self.friends,self.havasend),open(self.conffile,'w'))
#qq=myqq(739825735,"w123456")
if __name__=='__main__':
qq=myqq(33322222,"pwassword")
#qq.setcallback(_callback)
import time
while True :
if m:
print m ,m.endswith("back "),m[-4:]
if m.find('$verf:')==0:
a=str(raw_input(m+':'))
qq.verify(a)
m=None
elif m.endswith("back "):
import callback
callback.set(qq)
print "change success"
m=None
time.sleep(1)
p= qq.getstatus().process
print '>>',
if p>=0 and pprint process[p]
if p==3:
qq.sendtoall(" 电影《本杰明。巴顿》 每天一个晚安,-来自我的机器。")
break ;
# into=str(raw_input('>>'))
"""
for i in range(2):
print 'dfd'
dll.libqq_sendmessage(qq,1154628187,"我错了,"*((i+1)%6),False )
"""
发表于: 2010-02-13 ,修改于: 2010-02-13 12:13,已浏览208次,有评论5条推荐投诉


网友评论
内容: 不会没人顶吧,我对这个非常有兴趣.
我也想实现提取QQ消息再处理,不过我看不懂你的文章啊.我看到发送消息的函数是在那个libqq.c里了.不过我看程序里并没有调用的地方啊.
still_linux 评论于:2010-02-27 14:57:56 (221.207.251.★)

内容: 环境设置. DEV C++ 4.9
tools-->compiler options  -- Comiler 页标签下,
打勾v   Add following command s when compiler   ..
-c -Wall -s -Werror
打勾 v Add these commands to the linker command line
-lpthreadGC2 -lws2_32
剩下的在工程属性中,工程文件中包括了.
在 project opthins -->parameters 页标签下.
Compiler 项
-DBUILDING_DLL=1
Linker 项.
--no-export-all-symbols --add-stdcall-alias
lib/pthread/libpthreadGC2.a
在driectories页下.:
library Directries 添加, pthread目录.
include Directories添加,pthread目录.
这是DEV C++设置参数的几个地方,最终都会在,
生成命令中体现出来.
窗口下方的,
Complie log 中有所显示.
其它的就是,GCC的设置.我用的是默认的,
本站网友评论于:2010-02-28 10:40:31 (60.28.180.★)

内容: 非常好的东西,整个项目文件都有了,很好的进行二次开发,我最近沉醉于这个.
still_linux 评论于:2010-03-01 20:17:47 (221.208.81.★)

内容: 看了好像又更新了呵.这个机器人其实改改还是很稳定的,如果有机器挂VPS上就更好了.我最近研究了很多版本的机器人了.
起点就是这里.
还有其他种类的.比如WEB QQ机器人,可以去im.qq.com/webqq 提取消息,也可以用3gqq做机器人.后者比较强大.
这种基于协议的QQ反应是最快的.相对也比较稳定.
still_linux 评论于:2010-05-07 07:57:10 (122.159.18.★)

内容: 对,这个QQ确识强大,我把它的源码放在,Eclipse CDT下编译了一下。想做成个多开的,带界面的,防掉线的。但一直没时间做这个大改动。但我想,3GQQ是比较持久和稳定可靠的。因为这个怕协议更改。
本站网友评论于:2010-06-01 22:27:13 (118.249.238.★)