MyQQ.cpp: 非完全版本

// MyQQ.cpp: 非完全版本
//////////////////////////////////////////////////////////////////////
#include "QQdef.h"
#include "QQcrypt.h"
#include "winsock2.h"
#include "md5.h"
#include "MyQQ.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
MyQQ::MyQQ()
{
  s = NULL;
  LoginToken = NULL;
  LoginTokenLength = 0;
  Status = 0; //下线
  IsLogin = false;
  LastID = 0;
  MessageText = NULL;
  FriendListHead = NULL;
  FriendListTail = NULL;
  send_seq = random() & 0x0000ffff;
  LastOnline = time(NULL);
  UDPServerNum = 0;
  //服务器地址
  LoginServer = (char *)malloc(16*sizeof(char));
  //QQ号
  UserID = 0;
  //密码
  Password = NULL;
 
  //得到初始化密钥,按2004版
  InitKey = (unsigned char*)malloc(QQ_KEY_LENGTH);
  int i;
  for(i = 0; i < 16; i++)
    InitKey = rand();
  SessionKey = (unsigned char*)malloc(QQ_KEY_LENGTH);
}

MyQQ::~MyQQ()
{
  if(LoginServer != NULL)
    free(LoginServer);
  if(MyIP != NULL)
    free(MyIP);
  if(MessageText != NULL)
    free(MessageText);
  if(Password != NULL)
    free(Password);
  if(InitKey != NULL)
    free(InitKey);
  if(PwdKey != NULL)
    free(PwdKey);
  if(SessionKey != NULL)
    free(SessionKey);
  if(FriendListHead != NULL)
  {
    QQFriend *p = FriendListHead->next;
    while(p != NULL)
    {
        free(FriendListHead);
        FriendListHead = p;
        p = p->next;
    }
    if(FriendListTail != NULL)
        free(FriendListTail);
  }
}

void MyQQ::Login(int pMode)
{
  unsigned char *buf, *cursor, *raw_data, *encrypted_data;
  int seq_ret;
  int encrypted_len, bytes;
 
  //登录模式:1 为正常登录,2为隐身登录 ,3登录即离开
  LoginMode = pMode;
 
  if(LoginToken == NULL)
  {
    //发送获取登录令牌的包
    qq_get_logintoken();
  }
  else
  {
    //2004登录包
    buf = (unsigned char*)malloc(MAX_PACKAGE_LENGTH); //包长65535
    raw_data = (unsigned char*)malloc(QQ_LOGIN_DATA_LENGTH); //数据长
    encrypted_data = (unsigned char*)malloc(QQ_LOGIN_DATA_LENGTH + 16); //加密数据长度多16

    // 产生密文
    // 000-015 用PwdKey加密空串
    MCrypter.qq_crypt(ENCRYPT, (unsigned char*)"", 0, PwdKey, raw_data, &encrypted_len);

    //016-051 36字节的固定内容
    memmove(raw_data + 16, login_16_51, 36);

    //052-052 登录方式
    raw_data[52] = (unsigned char)LoginMode;

    //053-068 16字节固定内容
    memmove(raw_data + 53, login_53_68, 16);

    //069 登录令牌长度
    int pos = 69;
    raw_data[pos++] = (unsigned char)LoginTokenLength;

    //070-? 登录令牌
    memmove(raw_data + pos, LoginToken, LoginTokenLength);

    pos += LoginTokenLength;

    //未知字节0x40
    raw_data[pos++] = 0x40;

    //固定字节
    memmove(raw_data + pos, LOGIN_SEGMENTS, 100);

    pos += 100;

    //剩下的字节填零
    for(; pos < QQ_LOGIN_DATA_LENGTH; pos++)
        raw_data[pos] = 0x00;

    //加密
    MCrypter.qq_crypt(ENCRYPT, raw_data, QQ_LOGIN_DATA_LENGTH, InitKey, encrypted_data, &encrypted_len);

    cursor = buf;
    bytes = 0;
    bytes += create_packet_head_seq(buf, &cursor, QQ_CMD_LOGIN, true, &seq_ret);
    bytes += create_packet_dw(buf, &cursor, UserID);
    bytes += create_packet_data(buf, &cursor, InitKey, QQ_KEY_LENGTH);
    bytes += create_packet_data(buf, &cursor, encrypted_data, encrypted_len);
    bytes += create_packet_b(buf, &cursor, QQ_PACKET_TAIL);

    if (bytes == (cursor - buf)) //包被无误创建
    {
        qq_send_packet(buf, bytes, QQ_CMD_LOGIN);
    }

    free(buf);
    free(raw_data);
    free(encrypted_data);
  }
}

//从包中读取一个字节
int MyQQ::read_packet_b(unsigned char * buf, unsigned char ** cursor, int buflen, unsigned char * b)
{
  if(*cursor <= buf + buflen - sizeof(*b))
  {
    *b = **(unsigned char **) cursor;
    *cursor += sizeof(*b);
    return sizeof(*b);
  }
  else
    return -1;
}

//从包中读取一个字
int MyQQ::read_packet_w(unsigned char * buf, unsigned char ** cursor, int buflen, short * w)
{
  if(*cursor <= buf + buflen - sizeof(*w))
  {
    *w = ntohs(**(short **) cursor);
    *cursor += sizeof(*w);
    return sizeof(*w);
  } else
    return -1;
}

//处理收到的消息
void MyQQ::qq_process_recv_im(unsigned char* buf, int buf_len, short seq)
{
  int len, bytes;
  unsigned char *data, *cursor;
  qq_recv_im_header *im_header;

  len = buf_len;
  data = (unsigned char *)malloc(len);

  if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len))
  {
    if(len < 16)
        return;
    else
        qq_send_packet_recv_im_ack(seq, data);

    cursor = data;
    bytes = 0;
    im_header = (qq_recv_im_header *)malloc(sizeof(qq_recv_im_header));
    bytes += read_packet_dw(data, &cursor, len, &(im_header->sender_uid));
    bytes += read_packet_dw(data, &cursor, len, &(im_header->receiver_uid));
    bytes += read_packet_dw(data, &cursor, len, &(im_header->server_im_seq));

    bytes += read_packet_data(data, &cursor, len, (unsigned char *) & (im_header->sender_ip), 4);
    bytes += read_packet_w(data, &cursor, len, &(im_header->sender_port));
    bytes += read_packet_w(data, &cursor, len, &(im_header->im_type));

    if (bytes != 20) { // im_header的长度
    return;
  }

  if (im_header->receiver_uid != UserID)
  {
    return;
  }

  LastID = im_header->sender_uid;

  switch (im_header->im_type)
  {
  case QQ_RECV_IM_TO_BUDDY:
    qq_process_recv_normal_im(data, &cursor, len);
    break;
  case QQ_RECV_IM_TO_UNKNOWN:
    qq_process_recv_normal_im(data, &cursor, len);
    break;
  case QQ_RECV_IM_GROUP_IM:
    //qq_process_recv_group_im(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_ADD_TO_GROUP:
    //qq_process_recv_group_im_been_added(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_DEL_FROM_GROUP:
    //qq_process_recv_group_im_been_removed(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_APPLY_ADD_TO_GROUP:
    //qq_process_recv_group_im_apply_join(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_APPROVE_APPLY_ADD_TO_GROUP:
    //qq_process_recv_group_im_been_approved(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP:
    //qq_process_recv_group_im_been_rejected(data, &cursor, len, im_header->sender_uid, gc);
    break;
  case QQ_RECV_IM_SYS_NOTIFICATION:
    //_qq_process_recv_sys_im(data, &cursor, len, gc);
    break;
  default:
    break;
  }// switch
  }
}
//处理登录Reply的消息
void MyQQ::qq_process_login_reply(unsigned char* buf, int buf_len)
{
if(IsLogin == true)
return;

int len, ret, bytes;
unsigned char *data;

len = buf_len;
data = (unsigned char*)malloc(len);
if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, PwdKey, data, &len)) {

if (data[0] == QQ_LOGIN_REPLY_OK) {
ret = qq_process_login_ok(data, len);
} else {
ret = QQ_LOGIN_REPLY_MISC_ERROR;
}
} else {
len = buf_len;
if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, InitKey, data, &len)) {
bytes = 0;
switch (data[0]) {
case QQ_LOGIN_REPLY_REDIRECT:
ret = qq_process_login_redirect(data, len);
break;
case QQ_LOGIN_REPLY_PWD_ERROR:
ret = qq_process_login_wrong_pwd(data, len);
break;
default:
ret = QQ_LOGIN_REPLY_MISC_ERROR;
}
} else {
ret = QQ_LOGIN_REPLY_MISC_ERROR;
}
}

switch (ret) {
case QQ_LOGIN_REPLY_PWD_ERROR:
MessageBox(NULL,"QQ密码错误!","错误",MB_OK);
break;
case QQ_LOGIN_REPLY_MISC_ERROR:
MessageBox(NULL,"QQ登录出错,请重试!","错误",MB_OK);
break;
case QQ_LOGIN_REPLY_OK:
break;
case QQ_LOGIN_REPLY_REDIRECT:
break;
default:
break;
} // switch ret
}

void MyQQ::qq_process_group_cmd_reply(unsigned char* cursor, int len, short seq){}

void MyQQ::qq_process_msg_sys(unsigned char* cursor, int len, short seq){}

void MyQQ::qq_process_friend_change_status(unsigned char* buf, int buf_len)
{
int len, bytes;
unsigned char *data, *cursor;

len = buf_len;
data = (unsigned char*)malloc(len);
cursor = data;

qq_buddy_status * ss;

if(MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len))
{
ss = (qq_buddy_status *)malloc(sizeof(qq_buddy_status));
bytes = 0;
// 000-003: uid
bytes += read_packet_dw(data, &cursor, len, &ss->uid);
// 004-004: 0x01
bytes += read_packet_b(data, &cursor, len, &ss->unknown1);
// 005-008: ip
ss->ip = (unsigned char*)malloc(4);
bytes += read_packet_data(data, &cursor, len, ss->ip, 4);
// 009-010: port
bytes += read_packet_w(data, &cursor, len, &ss->port);
// 011-011: 0x00
bytes += read_packet_b(data, &cursor, len, &ss->unknown2);
// 012-012: status
bytes += read_packet_b(data, &cursor, len, &ss->status);
// 013-014:
bytes += read_packet_w(data, &cursor, len, &ss->unknown3);
// 015-030: unknown key
ss->unknown_key = (unsigned char*)malloc(QQ_KEY_LENGTH);
bytes += read_packet_data(data, &cursor, len, ss->unknown_key, QQ_KEY_LENGTH);
}
//这里是更新好友的状态,可自己实现接口
//I_QQChangeBuddyStatus(ss->uid, ss->status);
}

int MyQQ::qq_process_login_ok(unsigned char * data, int len)
{
qq_login_reply_ok lrop;
int bytes;
unsigned char* cursor;

cursor = data;
bytes = 0;

// 000-000: reply code
bytes += read_packet_b(data, &cursor, len, &lrop.result);
// 001-016: session key
lrop.session_key = (unsigned char*)malloc(QQ_KEY_LENGTH);
memcpy(lrop.session_key,cursor,QQ_KEY_LENGTH);

cursor += QQ_KEY_LENGTH;
bytes += QQ_KEY_LENGTH;

// 017-020: login uid
bytes += read_packet_dw(data, &cursor, len, &lrop.uid);
// 021-024: server detected user public IP
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.client_ip, 4);
// 025-026: server detected user port
bytes += read_packet_w(data, &cursor, len, &lrop.client_port);
// 027-030: server detected itself ip 127.0.0.1 ?
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.server_ip, 4);
// 031-032: server listening port
bytes += read_packet_w(data, &cursor, len, &lrop.server_port);
// 033-036: login time for current session
bytes += read_packet_dw(data, &cursor, len, (DWORD *) & lrop.login_time);
// 037-062: 26 bytes, unknown
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown1, 26);
// 063-066: unknown server1 ip address
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown_server1_ip, 4);
// 067-068: unknown server1 port
bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server1_port);
// 069-072: unknown server2 ip address
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown_server2_ip, 4);
// 073-074: unknown server2 port
bytes += read_packet_w(data, &cursor, len, &lrop.unknown_server2_port);
// 075-076: 2 bytes unknown
bytes += read_packet_w(data, &cursor, len, &lrop.unknown2);
// 077-078: 2 bytes unknown
bytes += read_packet_w(data, &cursor, len, &lrop.unknown3);
// 079-110: 32 bytes unknown
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown4, 32);
// 111-122: 12 bytes unknown
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown5, 12);
// 123-126: login IP of last session
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.last_client_ip, 4);
// 127-130: login time of last session
bytes += read_packet_dw(data, &cursor, len, (DWORD *) & lrop.last_login_time);
// 131-138: 8 bytes unknown
bytes += read_packet_data(data, &cursor, len, (unsigned char *) & lrop.unknown6, 8);

memcpy(SessionKey,lrop.session_key, QQ_KEY_LENGTH);

sprintf(MyIP,"%d.%d.%d.%d",lrop.client_ip[0],lrop.client_ip[1],lrop.client_ip[2],lrop.client_ip[3]);
MyPort = lrop.client_port;
IsLogin = true;

qq_send_packet_get_info(UserID);

switch(LoginMode)
{
case 1:
Status = 1;
break;
case 2:
Status = 3;
break;
default:
break;
}

qq_send_packet_change_status();

GetFriendList();

return QQ_LOGIN_REPLY_OK;
}

int MyQQ::qq_process_login_redirect(unsigned char * data, int len)
{
int bytes, ret;
unsigned char *cursor;

qq_login_reply_redirect_packet lrrp;

cursor = data;
bytes = 0;

// 000-000: reply code
bytes += read_packet_b(data, &cursor, len, &lrrp.result);

// 001-004: login uid
bytes += read_packet_dw(data, &cursor, len, &lrrp.uid);

// 005-008: redirected new server IP
bytes += read_packet_data(data, &cursor, len, lrrp.new_server_ip, 4);

// 009-010: redirected new server port
bytes += read_packet_w(data, &cursor, len, &lrrp.new_server_port);

if (bytes != QQ_LOGIN_REPLY_REDIRECT_PACKET_LEN) {
ret = QQ_LOGIN_REPLY_MISC_ERROR;
} else {
sprintf(LoginServer,"%d.%d.%d.%d",lrrp.new_server_ip[0],lrrp.new_server_ip[1],lrrp.new_server_ip[2],lrrp.new_server_ip[3]);

//服务器端口
LoginPort = lrrp.new_server_port;

ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(LoginServer);
ServerAddr.sin_port = htons(LoginPort);

//向新的服务器地址发送登录请求
Login(LoginMode);

ret = QQ_LOGIN_REPLY_REDIRECT;
}

return ret;
}
int MyQQ::qq_process_login_wrong_pwd(unsigned char * data, int len)
{
return QQ_LOGIN_REPLY_PWD_ERROR;
}

void MyQQ::qq_send_packet_change_status()
{
unsigned char *raw_data, *cursor, away_cmd;
DWORD misc_status;

if (IsLogin == false)
return;

switch (Status) {
case 1:
away_cmd = QQ_BUDDY_ONLINE_NORMAL;
break;
case 2:
away_cmd = QQ_BUDDY_ONLINE_INVISIBLE;
break;
case 3:
away_cmd = QQ_BUDDY_ONLINE_AWAY;
break;
default:
away_cmd = QQ_BUDDY_ONLINE_NORMAL;
} // switch

raw_data = (unsigned char*)malloc(5);
cursor = raw_data;
misc_status = 0x00000000;


create_packet_b(raw_data, &cursor, away_cmd);
create_packet_dw(raw_data, &cursor, misc_status);

qq_send_cmd(QQ_CMD_CHANGE_ONLINE_STATUS, TRUE, 0, TRUE, raw_data, 5);

}

void MyQQ::TurnInvisible()
{
Status = 2;
qq_send_packet_change_status();
}

void MyQQ::TurnVisible()
{
Status = 1;
qq_send_packet_change_status();
}

void MyQQ::TurnAway()
{
Status = 3;
qq_send_packet_change_status();
}

void MyQQ::Logout()
{
int i;

for (i = 0; i < 4; i++)
qq_send_cmd(QQ_CMD_LOGOUT, FALSE, 0xffff, FALSE, PwdKey, QQ_KEY_LENGTH);

IsLogin = false;
Status = 0;
}

void MyQQ::QQSendTextMessage(DWORD to_uid, char * msg, int type)
{

unsigned char *cursor, *raw_data;
short client_tag, normal_im_type;
int msg_len, raw_len, bytes;
time_t now;
unsigned char *md5;
char *msg_filtered;
char *font_size = NULL, *font_color = NULL, *font_name = NULL, *tmp;
bool is_bold = FALSE, is_italic = FALSE, is_underline = FALSE;
const char *start, *end, *last;


client_tag = QQ_CLIENT;
normal_im_type = QQ_NORMAL_IM_TEXT;

last = msg;

msg_filtered = msg;

msg_len = strlen(msg_filtered);
now = time(NULL);
md5 = gen_session_md5(UserID, SessionKey);

int font_name_len, tail_len;
font_name_len = DEFAULT_FONT_NAME_LEN;
tail_len = font_name_len + QQ_SEND_IM_AFTER_MSG_HEADER_LEN + 1;

raw_len = QQ_SEND_IM_BEFORE_MSG_LEN + msg_len + tail_len;
raw_data = (unsigned char*)malloc(raw_len);
cursor = raw_data;
bytes = 0;

//000-003: receiver uid
bytes += create_packet_dw(raw_data, &cursor, UserID);
//004-007: sender uid
bytes += create_packet_dw(raw_data, &cursor, to_uid);
//008-009: sender client version
bytes += create_packet_w(raw_data, &cursor, client_tag);
//010-013: receiver uid
bytes += create_packet_dw(raw_data, &cursor, UserID);
//014-017: sender uid
bytes += create_packet_dw(raw_data, &cursor, to_uid);
//018-033: md5 of (uid+session_key)
bytes += create_packet_data(raw_data, &cursor, md5, 16);
//034-035: message type
bytes += create_packet_w(raw_data, &cursor, normal_im_type);

//036-037: sequence number
//bytes += create_packet_w(raw_data, &cursor, qd->send_seq);
bytes += create_packet_w(raw_data, &cursor, send_seq);

//038-041: send time
bytes += create_packet_dw(raw_data, &cursor, (DWORD)now);
//042-042: always 0x00
bytes += create_packet_b(raw_data, &cursor, 0x00);
//043-043: sender icon
//bytes += create_packet_b(raw_data, &cursor, qd->my_icon);
bytes += create_packet_b(raw_data, &cursor, MyIcon);
//044-046: always 0x00
bytes += create_packet_w(raw_data, &cursor, 0x0000);
bytes += create_packet_b(raw_data, &cursor, 0x00);
//047-047: we use font attr
bytes += create_packet_b(raw_data, &cursor, 0x01);
//048-051: always 0x00
bytes += create_packet_dw(raw_data, &cursor, 0x00000000);
//052-052: text message type (normal/auto-reply)
bytes += create_packet_b(raw_data, &cursor, type);
//053- : msg ends with 0x00
bytes += create_packet_data(raw_data, &cursor, (unsigned char *)msg_filtered, msg_len);

unsigned char *send_im_tail = qq_get_send_im_tail(font_color, font_size, font_name, false,false, false, tail_len);

bytes += create_packet_data(raw_data, &cursor, send_im_tail, tail_len);

if (bytes == raw_len) // create packet OK
{
qq_send_cmd(QQ_CMD_SEND_IM, TRUE, 0, TRUE, raw_data, cursor - raw_data);
}
}
unsigned char * MyQQ::gen_session_md5(int uid, unsigned char * session_key)
{
unsigned char *src, md5_str[QQ_KEY_LENGTH];
unsigned char *cursor;
md5_state_t ctx;

src = (unsigned char *)malloc(20);
cursor = src;
create_packet_dw(src, &cursor, uid);
create_packet_data(src, &cursor, session_key, QQ_KEY_LENGTH);

md5_init(&ctx);
md5_append(&ctx, src, 20);
md5_finish(&ctx, (md5_byte_t *) md5_str);

unsigned char * t = (unsigned char *)malloc(QQ_KEY_LENGTH);
memcpy(t,md5_str, QQ_KEY_LENGTH);
return t;
}

unsigned char * MyQQ::qq_get_send_im_tail(const char * font_color,
const char * font_size,
const char * font_name,
bool is_bold, bool is_italic, bool is_underline, int tail_len)
{
char *s1, *s2;
unsigned char *rgb;
int font_name_len;
unsigned char *send_im_tail;
const unsigned char simsun[] = { 0xcb, 0xce, 0xcc, 0xe5 };


font_name_len = DEFAULT_FONT_NAME_LEN;
font_name = (const char*)&(simsun[0]);

send_im_tail = (unsigned char*)malloc(tail_len);

memcpy(send_im_tail + QQ_SEND_IM_AFTER_MSG_HEADER_LEN,
font_name, tail_len - QQ_SEND_IM_AFTER_MSG_HEADER_LEN);

send_im_tail[tail_len - 1] = tail_len;

send_im_tail[0] = 0x00;
send_im_tail[1] = 10;

if (is_bold)
send_im_tail[1] |= 0x20;
if (is_italic)
send_im_tail[1] |= 0x40;
if (is_underline)
send_im_tail[1] |= 0x80;


send_im_tail[2] = send_im_tail[3] = send_im_tail[4] = 0;

send_im_tail[5] = 0x00;
send_im_tail[6] = 0x86;
send_im_tail[7] = 0x22;
return (unsigned char *) send_im_tail;
}

//处理普通的QQ消息
void MyQQ::qq_process_recv_normal_im(unsigned char * data, unsigned char ** cursor, int len)
{
int bytes;
qq_recv_normal_im_common *common;
qq_recv_normal_im_unprocessed *im_unprocessed;

if (*cursor >= (data + len - 1)) {
return;
}
else
common = (qq_recv_normal_im_common *)malloc(sizeof(qq_recv_normal_im_common));

bytes = qq_normal_im_common_read(data, cursor, len, common);
if (bytes < 0) {
return;
}

switch (common->normal_im_type) {
case QQ_NORMAL_IM_TEXT:
qq_process_recv_normal_im_text (data, cursor, len, common);
break;
case QQ_NORMAL_IM_FILE_REJECT_UDP:
//qq_process_recv_file_reject (data, cursor, len,
// common->sender_uid, gc);
break;
case QQ_NORMAL_IM_FILE_APPROVE_UDP:
//qq_process_recv_file_accept (data, cursor, len,
// common->sender_uid, gc);
break;
case QQ_NORMAL_IM_FILE_REQUEST:
//qq_process_recv_file_request (data, cursor, len,
// common->sender_uid, gc);
break;
case QQ_NORMAL_IM_FILE_CANCEL:
//qq_process_recv_file_cancel (data, cursor, len,
// common->sender_uid, gc);
break;
case QQ_NORMAL_IM_FILE_NOTIFY:
//qq_process_recv_file_notify (data, cursor, len,
// common->sender_uid, gc);
break;
default:
return;
} // normal_im_type

g_free (common->session_md5);
}

void MyQQ::qq_process_recv_normal_im_text(unsigned char * data, unsigned char ** cursor, int len, qq_recv_normal_im_common * common)
{
short gaim_msg_type;
char *name;
char *msg_with_gaim_smiley;
char *msg_utf8_encoded;
qq_recv_normal_im_text *im_text;

if (*cursor >= (data + len - 1)) {
return;
} else
im_text = (qq_recv_normal_im_text *)malloc(sizeof(qq_recv_normal_im_text));

im_text->common = common;

read_packet_w(data, cursor, len, &(im_text->msg_seq));
read_packet_dw(data, cursor, len, &(im_text->send_time));
read_packet_b(data, cursor, len, &(im_text->unknown1));
read_packet_b(data, cursor, len, &(im_text->sender_icon));
read_packet_data(data, cursor, len, (unsigned char *) & (im_text->unknown2), 3);
read_packet_b(data, cursor, len, &(im_text->is_there_font_attr));
read_packet_data(data, cursor, len, (unsigned char *) & (im_text->unknown3), 4);
read_packet_b(data, cursor, len, &(im_text->msg_type));

if (im_text->msg_type == QQ_IM_AUTO_REPLY) {
im_text->is_there_font_attr = 0x00;
im_text->msg = (unsigned char *)malloc(1024);
memcpy(im_text->msg,*cursor, data + len - *cursor);
} else {
if (im_text->is_there_font_attr) {
im_text->msg = (unsigned char *)malloc(1500);
memcpy(im_text->msg,*cursor, strlen((const char *)*cursor));
im_text->msg[strlen((const char *)*cursor)] = 0;

}
else
{ im_text->msg = (unsigned char *)malloc(1024);
memcpy(im_text->msg,*cursor, data + len - *cursor);
im_text->msg[data + len - *cursor] = 0;
}
}

MessageText = im_text->msg;
//如果需要自动回复
if(Status == 3)
{
//I_QQAutoReply()函数获取预先设置的自动回复消息内容,需自己实现
char* MText = I_QQAutoReply();
QQSendTextMessage(common->sender_uid,MText,0x01);
}

//在主界面中显示消息
//I_QQReceiveMessage((char *)MessageText,common->sender_uid);
}

int MyQQ::qq_normal_im_common_read(unsigned char * data, unsigned char ** cursor, int len, qq_recv_normal_im_common * common)
{
int bytes;

bytes = 0;

bytes += read_packet_w(data, cursor, len, &(common->sender_ver));
bytes += read_packet_dw(data, cursor, len, &(common->sender_uid));
bytes += read_packet_dw(data, cursor, len, &(common->receiver_uid));

common->session_md5 = (unsigned char *)malloc(QQ_KEY_LENGTH);
memcpy(common->session_md5,*cursor, QQ_KEY_LENGTH);
bytes += QQ_KEY_LENGTH;
*cursor += QQ_KEY_LENGTH;

bytes += read_packet_w(data, cursor, len, &(common->normal_im_type));

if (bytes != 28) {
return -1;
}

return bytes;
}

//请求获得在线好友列表
void MyQQ::qq_send_packet_get_buddies_online(unsigned char position)
{

unsigned char *raw_data, *cursor;

raw_data = (unsigned char*)malloc(5);
cursor = raw_data;

create_packet_b(raw_data, &cursor, QQ_GET_ONLINE_BUDDY_02);
// 001-001 seems it supports 255 online buddies at most
create_packet_b(raw_data, &cursor, position);
// 002-002
create_packet_b(raw_data, &cursor, 0x00);
// 003-004
create_packet_w(raw_data, &cursor, 0x0000);

qq_send_cmd(QQ_CMD_GET_FRIENDS_ONLINE, TRUE, 0, TRUE, raw_data, 5);

}

//处理在线好友列表消息
void MyQQ::qq_process_get_buddies_online_reply(unsigned char * buf, int buf_len)
{
int len, bytes;
unsigned char *data, *cursor, position;
qq_buddy *q_bud;
qq_friends_online_entry *fe;
QQFriend *p;

len = buf_len;
data = (unsigned char *)malloc(len);
cursor = data;

if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len))
{
read_packet_b(data, &cursor, len, &position);

fe = (qq_friends_online_entry *)malloc(sizeof(qq_friends_online_entry));
qq_buddy_status * s = (qq_buddy_status *)malloc(sizeof(qq_buddy_status));

while (cursor < (data + len))
{

bytes = 0;

// 000-003: uid
bytes += read_packet_dw(data, &cursor, len, &s->uid);
// 004-004: 0x01
bytes += read_packet_b(data, &cursor, len, &s->unknown1);
// 005-008: ip
s->ip = (unsigned char*)malloc(4);
bytes += read_packet_data(data, &cursor, len, s->ip, 4);
// 009-010: port
bytes += read_packet_w(data, &cursor, len, &s->port);
// 011-011: 0x00
bytes += read_packet_b(data, &cursor, len, &s->unknown2);
// 012-012: status
bytes += read_packet_b(data, &cursor, len, &s->status);
// 013-014:
bytes += read_packet_w(data, &cursor, len, &s->unknown3);
// 015-030: unknown key
s->unknown_key = (unsigned char*)malloc(QQ_KEY_LENGTH);
bytes += read_packet_data(data, &cursor, len, s->unknown_key, QQ_KEY_LENGTH);

// 031-032: unknown4
bytes += read_packet_w(data, &cursor, len, &fe->unknown1);
// 033-033: flag1
bytes += read_packet_b(data, &cursor, len, &fe->flag1);
// 034-034: comm_flag
bytes += read_packet_b(data, &cursor, len, &fe->comm_flag);
// 035-036:
bytes += read_packet_w(data, &cursor, len, &fe->unknown2);
// 037-037:
bytes += read_packet_b(data, &cursor, len, &fe->ending); // 0x00

p = FriendListHead;
while(p != NULL)
{
if(p->Buddy->uid == s->uid)
{
p->Buddy->status = s->status;
break;
}
p = p->next;
}
} // while cursor

if(position != 0xFF)
{
//如果类表为接收完,继续发消息请求
qq_send_packet_get_buddies_online(position);
}
else
{
//更新好友的状态
p = FriendListHead;
while(p != NULL)
{
if(p->Buddy->status != QQ_BUDDY_ONLINE_OFFLINE)
{
//I_QQChangeBuddyStatus(p->Buddy->uid, p->Buddy->status);
}
p = p->next;
}
}
}
}

//请求获得好友列表
void MyQQ::qq_send_packet_get_buddies_list(short position)
{
unsigned char *raw_data, *cursor;
int data_len;

data_len = 3;
raw_data = (unsigned char*)malloc(data_len);
cursor = raw_data;
// 000-001 starting position, can manually specify
create_packet_w(raw_data, &cursor, position);

create_packet_b(raw_data, &cursor, 0x00);

qq_send_cmd(QQ_CMD_GET_FRIENDS_LIST, TRUE, 0, TRUE, raw_data, data_len);
}

//处理好友列表消息
void MyQQ::qq_process_get_buddies_list_reply(unsigned char * buf, int buf_len)
{
qq_buddy *q_bud;
int len, bytes, bytes_expected, i;
short position = 0, unknown;
unsigned char *data, *cursor, bar;//, pascal_len;
unsigned short pascal_len;
char *name;


len = buf_len;
data = (unsigned char *)malloc(len);
cursor = data;

if (MCrypter.qq_crypt(DECRYPT, buf, buf_len, SessionKey, data, &len)) {
read_packet_w(data, &cursor, len, &position);
i = 0;
while (cursor < (data + len)) {
q_bud = (qq_buddy *)malloc(sizeof(qq_buddy));
bytes = 0;
// 000-003: uid
bytes += read_packet_dw(data, &cursor, len, &q_bud->uid);
// 004-004: 0xff if buddy is self, 0x00 otherwise
bytes += read_packet_b(data, &cursor, len, &bar);
// 005-005: icon index (1-255)
bytes += read_packet_b(data, &cursor, len, &q_bud->icon);
// 006-006: age
bytes += read_packet_b(data, &cursor, len, &q_bud->age);
// 007-007: gender
bytes += read_packet_b(data, &cursor, len, &q_bud->gender);

//这里如果字符集不同还要进行转换
pascal_len = cursor[0];
q_bud->nickname = (unsigned char*)malloc(pascal_len+1);
memcpy(q_bud->nickname,cursor+1,pascal_len);
q_bud->nickname[pascal_len] = 0;
pascal_len++;


cursor += pascal_len;
bytes += pascal_len;
bytes += read_packet_w(data, &cursor, len, &unknown);

bytes += read_packet_b(data, &cursor, len, &q_bud->flag1);
bytes += read_packet_b(data, &cursor, len, &q_bud->comm_flag);

bytes_expected = 12 + pascal_len;

if (q_bud->uid == 0 || bytes != bytes_expected) {

continue;
} else
i++;

//这里应是将好友信息写入本地好友列表
AddBuddyToList(q_bud);
} // while cursor

if (position == 0xFFFFFFFF) {
//在主界面上显示好友列表
//I_QQUpdateBuddyList();

//若接收完毕,则请求在线好友列表
qq_send_packet_get_buddies_online(QQ_FRIENDS_ONLINE_POSITION_START);
} else //继续请求好友列表
qq_send_packet_get_buddies_list(position);
}
}
//读取好友状态
int MyQQ::qq_buddy_status_read(unsigned char * data, unsigned char ** cursor, int len, qq_buddy_status * s)
{
int bytes;

bytes = 0;

// 000-003: uid
bytes += read_packet_dw(data, cursor, len, &s->uid);
// 004-004: 0x01
bytes += read_packet_b(data, cursor, len, &s->unknown1);
// 005-008: ip
s->ip = (unsigned char *)malloc(4);
bytes += read_packet_data(data, cursor, len, s->ip, 4);
// 009-010: port
bytes += read_packet_w(data, cursor, len, &s->port);
// 011-011: 0x00
bytes += read_packet_b(data, cursor, len, &s->unknown2);
// 012-012: status
bytes += read_packet_b(data, cursor, len, &s->status);
// 013-014:
bytes += read_packet_w(data, cursor, len, &s->unknown3);
// 015-030: unknown key
s->unknown_key = (unsigned char *)malloc(QQ_KEY_LENGTH);
bytes += read_packet_data(data, cursor, len, s->unknown_key, QQ_KEY_LENGTH);

if (s->uid == 0 || bytes != 31)
return -1;

return bytes;
}


void MyQQ::AddBuddyToList(qq_buddy * pBuddy)
{
qq_buddy * temp = (qq_buddy*)malloc(sizeof(qq_buddy));
memcpy(temp,pBuddy,sizeof(qq_buddy));

QQFriend * p = (QQFriend*)malloc(sizeof(QQFriend));
p->Buddy = temp;
p->next = NULL;

if(FriendListHead == NULL)
{
FriendListHead = p;
FriendListTail = p;
}
else
{
FriendListTail->next = p;
FriendListTail = p;
}
}


void MyQQ::GetFriendList()
{
  qq_send_packet_get_buddies_list(QQ_FRIENDS_LIST_POSITION_START);
}

void MyQQ::GetOnlineFriendList()
{
  qq_send_packet_get_buddies_online(QQ_FRIENDS_ONLINE_POSITION_START);
}


void MyQQ::ListFriend()
{
  char Num[15];
  char Name[256];
  QQFriend * p = FriendListHead;
  while(p != NULL)
  {
    sprintf(Num,"%d",(p->Buddy)->uid);
    sprintf(Name,"%s%c",(char*)((p->Buddy)->nickname),'/0');
    MessageBox(NULL,Name,Num,MB_OK);
    p = p->next;
  }
}


//发送收到消息的ACK
void MyQQ::qq_send_packet_recv_im_ack(short seq, unsigned char * data)
{
  qq_send_cmd(QQ_CMD_RECV_IM, FALSE, seq, FALSE, data, 16);
}

int MyQQ::random()
{
  return 0xdead;
}

//私有函数,发送在线包
void MyQQ::qq_send_packet_keep_alive()
{
  unsigned char *raw_data, *cursor;
 
  raw_data = (unsigned char*)malloc(4);
  cursor = raw_data;
 
  //其实发送什么内容都可以
  create_packet_dw(raw_data, &cursor, UserID);
 
  qq_send_cmd(QQ_CMD_KEEP_ALIVE, FALSE, 0, TRUE, raw_data, 4);
}

void MyQQ::KeepAlive()
{
  qq_send_packet_keep_alive();
}

void MyQQ::qq_send_packet_get_info(DWORD uid)
{
  char uid_str[15];
  qq_info_query *query;
  sprintf(uid_str, "%d", uid);
  qq_send_cmd(QQ_CMD_GET_USER_INFO, TRUE, 0, TRUE, (unsigned char*)&uid_str[0], strlen(uid_str));
}


void MyQQ::qq_get_logintoken()
{
  unsigned char *buf, *cursor;
 
  buf = (unsigned char*)malloc(MAX_PACKAGE_LENGTH); //包长65535
  cursor = buf;
 
  time_t now = time(NULL);
 
  short bytes_written = 0;

  bytes_written += create_packet_b(buf, &cursor, QQ_PACKET_TAG);
  bytes_written += create_packet_w(buf, &cursor, QQ_CLIENT);
  bytes_written += create_packet_w(buf, &cursor, QQ_CMD_REQUEST_LOGIN_TOKEN);
  bytes_written += create_packet_w(buf, &cursor, (WORD)now);
  bytes_written += create_packet_dw(buf, &cursor, (DWORD)UserID);
  bytes_written += create_packet_b(buf, &cursor, 0);
  bytes_written += create_packet_b(buf, &cursor, QQ_PACKET_TAIL);


  int aa = sendto(s,(const char *)buf,bytes_written,0,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr));
  if(aa == SOCKET_ERROR)
  {
    aa = WSAGetLastError();
    char num[6];
    sprintf(num,"%d",aa);
    MessageBox(NULL,num,"SendError!",MB_OK);
  }

  free(buf);
}

//处理请求登录令牌返回包
void MyQQ::qq_process_logintoken_reply(unsigned char * data,int len)
{
  if(LoginToken!= NULL)
    return;
 
  int bytes;
  unsigned char* cursor;
  unsigned char RCode,TokenLen;
 
  cursor = data;
  bytes = 0;
 
  // 000-000: reply code
  bytes+=read_packet_b(data,&cursor,len,&RCode);
 
  if(RCode == 0x00)
  {
    //令牌长度
    bytes += read_packet_b(data, &cursor, len, &TokenLen); 
    LoginTokenLength = TokenLen;   
    LoginToken = (unsigned char *)malloc(TokenLen);
    //令牌内容
    bytes += read_packet_data(data, &cursor, len, LoginToken, (int)TokenLen);
  }
  Login(LoginMode);
}

//初始化参数
int MyQQ::InitParam(int QQnum,char *QQpass)
{
  UserID=QQnum; 
  if(UserID == 0)
    return 1;
 
  strcpy(Password,QQpass);
  if(Password == NULL)
    return 2;
 
  //得到密码密钥
  md5_state_t ctx;
  md5_byte_t pwkey_tmp[QQ_KEY_LENGTH];
 
  md5_init(&ctx);
  md5_append(&ctx, (unsigned char*)Password, strlen(Password));
  md5_finish(&ctx, pwkey_tmp);
 
  md5_init(&ctx);
  md5_append(&ctx, pwkey_tmp, QQ_KEY_LENGTH);
  md5_finish(&ctx, pwkey_tmp);
 
  PwdKey = (unsigned char*)malloc(QQ_KEY_LENGTH);
  memcpy(PwdKey,pwkey_tmp,QQ_KEY_LENGTH);
 
  //本地地址
  char szName[255];
  memset(szName,0,255);
  gethostname(szName,255);
  hostent * host;
  host= gethostbyname(szName);
  if(host->h_addr_list[0])
  {
    struct in_addr addr;
    memmove(&addr, host->h_addr_list[0], 4);
    //获得标准IP地址
    MyIP=inet_ntoa(addr);
  }
 
  //创建UDP Socket
  s = socket(AF_INET,SOCK_DGRAM,0);
  int ErrCode;
  //本地端口
  MyPort = 4000;
  while(1)
  {
    LocalAddr.sin_family = AF_INET;
    LocalAddr.sin_addr.s_addr = inet_addr(MyIP);
    LocalAddr.sin_port = htons(MyPort);
  
    ErrCode = bind(s,(LPSOCKADDR)&LocalAddr,sizeof(LocalAddr));
    if(ErrCode == SOCKET_ERROR)
    {
        if((ErrCode = WSAGetLastError()) == 10048)
        {
          //如果该端口已被使用,则端口数加1,再重试
          MyPort++;
          continue;
        }
        char num[15];
        sprintf(num,"错误代码%d",ErrCode);
        MessageBox(NULL,num,"本地创建Socket失败!",MB_OK);
        break;
    }
    else
        break;
}

return 0;
}

//初始化QQ服务端信息
int MyQQ::InitUDPServer()
{
  strcpy(LoginServer,udp_server_list[UDPServerNum]);
 
  //服务器端口
  LoginPort = 8000;
 
  ServerAddr.sin_family = AF_INET;
  ServerAddr.sin_addr.s_addr = inet_addr(LoginServer);
  ServerAddr.sin_port = htons(LoginPort);
  return 0;
}

/*
int UserID;//QQnum
char PassWord[32];//
Unsigned char PwdKey[QQ_KEY_LENGTH];
SOCKET s;
char MyIP[16];
int MyPort;
SOCKADDR_IN LocalAddr,ServerAddr;
*/

你可能感兴趣的:(MyQQ.cpp: 非完全版本)