⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serverevent.pm

📁 Net-OICQ-1.6
💻 PM
字号:
package Net::OICQ::ServerEvent;# $Id: ServerEvent.pm,v 1.4 2007/06/15 18:09:53 tans Exp $# Copyright (c) 2003 - 2006 Shufeng Tan.  All rights reserved.# # This package is free software and is provided "as is" without express# or implied warranty.  It may be used, redistributed and/or modified# under the terms of the Perl Artistic License (see# http://www.perl.com/perl/misc/Artistic.html)use strict;use warnings;eval "no encoding; use bytes;" if $] >= 5.008;use Crypt::OICQ qw(encrypt decrypt);use Net::OICQ::ClientEvent;our @ISA = qw(Net::OICQ::Event);my $InfoHeader = \@Net::OICQ::InfoHeader;sub new {	my ($class, $data, $oicq) = @_;	unless (defined $data and length($data) > 8) {		$oicq->log_t("Discard data from server:\n", unpack("H*", $data)) if $oicq->{Debug};		return;	}	my $time = time;	$oicq->{LastSvrAck} = $time;	my $self = {		Time  => $time,		OICQ  => $oicq,		Header => substr($data, 0, 7),	};	bless $self, $class;	my $cmdcode = $self->cmdcode;	my $cmd     = $self->cmd;	if ($cmd eq 'login' || $cmd =~ /^reg_new_id_/) {		$oicq->log_t("Cmd $cmd ($cmdcode):\n", $oicq->hexdump($data));		return undef;	}	if ($self->process) {		my $crypt = substr($data, 7, -1);		my $plain;		eval { $plain = decrypt(undef, $crypt, $oicq->{Key}) };		$oicq->log_t("Error in new ServerEvent:", unpack("H*", $self->{Header}), "$cmd\n", $@) if $@;		return undef unless defined $plain;		$self->{Data} = $plain;		$oicq->log_t("Server mesg header: ", unpack("H*", $self->{Header}),			" $cmd: ", unpack("H*", $self->{Data})) if $oicq->{Debug};	}	return $self;}# Server replies with user infosub get_user_info {	my ($self) = @_;	my $oicq = $self->{OICQ};	my $plain = $self->{Data};	my @field = split(/$Net::OICQ::FS/, $plain);	return unless defined $field[0];	$self->{Info} = \@field;	return if $field[0] =~ /^-/;	# If the info is about myself, update MyInfo field.	$oicq->{MyInfo} = [@field] if $field[0] == $oicq->{Id};	# Initialize Info for the QQ id	$oicq->{Info}->{$field[0]} = {} unless defined $oicq->{Info}->{$field[0]};	# Update nickname, age, sex, and face(or avatar)	my $hashref = $oicq->{Info}->{$field[0]};	$hashref->{Nickname} = $field[1];	$hashref->{Age}      = $field[7];	$hashref->{Sex}      = $field[8];	$hashref->{Face}     = $oicq->get_face($field[21]);	# Update user info file	my $datfile = "$oicq->{Dir}/$oicq->{Id}/$field[0].dat";	my $dat = new FileHandle(">$datfile");	if (defined $dat) {		print $dat "\$_ = {\n";		for(my $j = 0; $j<=$#field; $j++) {			printf $dat "%-15s => '%s',\n", $InfoHeader->[$j], $field[$j];		}		print $dat "};\n";		$dat->close;	} else {		$oicq->log_t("Failed to open user info file >$datfile");	}	return 1;}# Server return code is stored in $event->{ReturnCode}sub send_msg {	my ($self) = @_;	my $oicq = $self->{OICQ};	my $hex = unpack("H*", $self->{Data});	$self->{ReturnCode} = $hex;	return 1;}# recv_msg handles messages from QQ servers, other users, or groups# These event attributes will be set: SrcId, DstId, MsgType, MsgTime, Mesg,# SrcId2, DstId2, $oicq->{Info}->{$srcid}->{Client}, MsgSubtype, MsgSeq for user messages# GrpId, GrpType, SrcId2 for group messages# BotError if a chat bot is definedsub recv_msg {	my ($self) = @_;	my $oicq  = $self->{OICQ};	my $plain = $self->{Data};	my ($srcid, $dstid, $x) = unpack('NNN', substr($plain, 0, 12));	$self->{SrcId} = $srcid;	$self->{DstId} = $dstid;	$self->{N8_12} = $x;	my $srcaddr = $oicq->show_address(substr($plain, 12, 6));	my $msg_type = unpack('n', substr($plain, 18, 2));	$self->{SrcAddr} = $srcaddr;	$self->{MsgType} = $msg_type;	if ($srcid != 10000 and !defined($oicq->{Info}->{$srcid})) {		$oicq->{Info}->{$srcid} = {};	}	my $mesg;	if (grep {$msg_type == $_} 0x09, 0x0a, 0x84, 0x85) {		my ($client, $srcid2, $dstid2, $x, $subtype, $seq, $time) =			unpack('H4NNH32nnN', substr($plain, 20, 34));		$oicq->{Info}->{$srcid}->{Client} = $client;		$self->{SrcId2} = $srcid2;		$self->{DstId2} = $dstid2;		$self->{H30_46} = $x;		$self->{Subtype} = $subtype;		$self->{MsgSeq} = $seq;		$self->{MsgTime} = $time;		if ($subtype == 0x81) { # Request for file transfer, voice or video			#$mesg = unpack('H*', substr($plain, 54));			$self->{RequestId} = unpack('H*', substr($plain, 94, 2));			$self->{RequestIP} = $oicq->show_address(substr($plain, 96, 4));			if ($plain =~ /([^\x1f]+?)\x1f(\d+) \xd7\xd6\xbd\xda$/s) {				$self->{FileName} = $1;				$self->{FileSize} = $2;			} elsif ($plain =~ /(\xd3\xef\xd2\xf4\xc1\xc4\xcc\xec)/s) {				$self->{VoiceChat} = $1;			} elsif ($plain =~ /(\xd3\xef\xd2\xf4\xca\xd3\xc6\xb5\xc1\xc4\xcc\xec)/s) {				$self->{VideoChat} = $1;			} else {				$self->{Ignore} = 1;			}		} elsif ($subtype == 0x85) { # Cancel			#$mesg = unpack('H*', substr($plain, 54));			$self->{RequestCancelled} = unpack('H*', substr($plain, 84, 2));		} elsif ($subtype == 0x35) {			$self->{Ignore} = 1;			#$mesg = unpack('H*', substr($plain, 54));		} elsif ($subtype == 0x0b) {			$mesg = substr($plain, 73);		} else {			$mesg = substr($plain, 54);		}	} elsif ($msg_type == 0x20 or $msg_type == 0x2b) {  # Group message		my ($gid, $gtype, $srcid2, $x1, $seq, $time, $x2, $len, $x3) =			unpack('NH2NH4nNH8nH20', substr($plain, 20, 33));		$self->{GrpId} = $gid;		$self->{GrpType} = $gtype;		$self->{SrcId2} = $srcid2;		$self->{H9_10} = $x1;		$self->{MsgSeq} = $seq;		$self->{MsgTime} = $time;		$self->{H17_20} = $x2;		$self->{MsgLen} = $len;		$self->{MsgHead} = $x3;		$mesg = substr($plain, 53);	}	# Let's process the message tail	if ($mesg) {		my $tail_len = ord(substr($mesg, -1, 1));		my $tail = substr($mesg, -1-$tail_len);		if ($tail =~ /^ \0/) {			# get rid of tail from $mesg			substr($mesg, -1-$tail_len) = "";			# don't care about bold, italic, or underscore			$self->{FontSize} = ord(substr($tail, 2, 1)) & 0x1f;			$self->{FontColor} = unpack('H*', substr($tail, 3, 3));			$tail =~ s/.$//;			$self->{FontName} = substr($tail, 9);		}		if ($oicq->{LogChat}) {			my $grpid = exists($self->{GrpId}) ? "(Group $self->{GrpId})" : "";			my $time = substr(localtime($self->{MsgTime}), 4, 16);			$oicq->log_t("$time received message from $srcid$grpid:\n$mesg");		}	} elsif ($msg_type == 0x18) {		$self->{MsgHeader} = unpack("H*", substr($plain, 20, 5));		$mesg = substr($plain, 25);	} elsif ($msg_type == 0x30) {		$self->{MsgHeader} = unpack("H*", substr($plain, 20, 1));		$mesg = substr($plain, 21);	} elsif ($msg_type == 0x34) {  # Backdrop		$self->{MsgTime} = unpack('N', substr($plain, -4));		if (length($plain) <= 30) {			$self->{BackdropCancelled} = 1;			$mesg = "";		} else {			my $len = ord(substr($plain, 27, 1));			$self->{Backdrop} = substr($plain, 28, $len);			$mesg = substr($plain, 20);		}	} elsif ($msg_type == 0x41) {		$self->{MsgHeader} = unpack("H*", substr($plain, 20, 9));		$mesg = substr($plain, 29);	} elsif ($msg_type == 0x4c) {		$self->{MsgHeader} = unpack("H*", substr($plain, 20, 7));		$mesg = substr($plain, 27);	} elsif ($oicq->{Debug}) {		$mesg = unpack('H*', substr($plain, 20));		$oicq->log_t("Unknown message type $msg_type from $srcid, $srcaddr:\n$mesg");	}	$self->{Mesg} = $mesg;	if (defined $oicq->{Socket} and defined $mesg and ! $self->{Ignore}) {		$oicq->ack_msg($self->seq, $plain);	}	return 1;}# Response to get_online_friends is a list of fixed length (38 bytes)# records, will update $oicq->{Info}, $event->{OnlineFriends}sub get_online_friends {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq = $self->{OICQ};	my @list = ();	my $info = $oicq->{Info};	for(my $i = 1; $i<length($plain); $i+=38) {		my $fid =  unpack('N', substr($plain, $i, 4));		my $addr = $oicq->show_address(substr($plain, $i+5, 6));		my $mode = ord(substr($plain, $i+12, 1));		my $key  = substr($plain, $i+13, 20);		defined $info->{$fid} or $info->{$fid} = {};		$info->{$fid}->{Key} = $key;		$info->{$fid}->{Mode} = $mode;		$info->{$fid}->{Addr} = $addr if $addr =~/[1-9]/;		push @list, $fid;	}	$self->{OnlineFriends} = \@list;	return 1;}sub recv_service_msg {	my ($self) = @_;	my $oicq = $self->{OICQ};	my ($code, $srcid, $myid, $mesg) = split(/$Net::OICQ::RS/, $self->{Data});	$self->{ServerCode} = $code;	$self->{SrcId} = $srcid;	$self->{DstId} = $myid;	$self->{Mesg} = $mesg;	if (defined $oicq->{Socket}) {		$oicq->ack_service_msg($code, $srcid, $self->seq);	}	my $comment;	if ($code eq "02" or $code eq "41") {		$comment = "$srcid asked to add $myid";	} elsif ($code eq "03") {		$comment = "$srcid accepted $myid";	} elsif ($code eq "04") {		$comment = "$srcid rejected $myid";	} elsif ($srcid == 10000) {		$comment = "garbage from $srcid";	} else {		$comment = "unknown";	}	$self->{Comment} = $comment;	$oicq->log_t("$comment:\n$mesg");	return 1;}# List of lists is stored in $event->{UserList}sub search_users {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq = $self->{OICQ};	my @list;	foreach my $line (split(/$Net::OICQ::RS/, $plain)) {		my @f = split(/$Net::OICQ::FS/, $line);		next unless defined $f[3];		$f[3] = $oicq->get_face($f[3]);		push @list, \@f;	}	$self->{UserList} = \@list;	return 1;}sub keep_alive {	my $self = shift;	my $oicq = $self->{OICQ};	my $plain = $self->{Data};	#my @field = split($Net::OICQ::RS, $plain);	#$oicq->{UserCount} = $field[2];	#$self->{ServerInfo} = \@field;	return 1;}sub get_contact_id {	my ($self, $seq) = @_;	my $event;	foreach my $e (@{$self->{OICQ}->{EventQueue}}) {		next unless ref($e) =~ /Client/;		if ($e->seq eq $seq) {			$event = $e;			last;		}	}	return 'Someone' unless defined $event;	my ($id) = $event->{Data} =~ /^(\d+)/;	return $id;}sub add_contact_1 {	my ($self) = @_;	my $plain = $self->{Data};	my ($id, $reply) = split(/$Net::OICQ::RS/, $plain);	$self->{Id} = $id;	$self->{Reply} = $reply;	my $srcid = $self->get_contact_id($self->seq);	if ($reply =~ /^\d+$/) {		if ($reply > 0) {			$self->{Comment} = "$srcid requires authentication message.";			return 0;		} elsif ($reply == 0) {			$self->{Comment} = "$srcid has accepted your request.";			return 1;		}	}	$self->{Comment} = "Unknown reply from add_contact_1 $srcid: $reply";	return;}sub add_contact_2 {}# get_friends_list provided by Chen Pengsub get_friends_list {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq = $self->{OICQ};	my $flag = substr($plain, 0, 2);	$self->{Flag} = unpack("H*", $flag);	my $p = 2;	my $len = length($plain);	while ($p < $len) {		my $fid = unpack('N', substr($plain, $p, 4));		$p += 4; # one 0x00 to seperate		my $face = $oicq->get_face(ord(substr($plain, $p+1, 1))); $p += 2;		my $age = ord(substr($plain, $p, 1)); $p += 1;		my $sex = ord(substr($plain, $p, 1)); $p += 1;		my $name_len = ord(substr($plain, $p, 1)); $p += 1;		my $nickname = substr($plain, $p, $name_len); $p += $name_len;		my $unknown =  unpack("H*", substr($plain, $p, 4)); $p += 4;		$oicq->{Info}->{$fid} = {} unless defined $oicq->{Info}->{$fid};		my $info =  $oicq->{Info}->{$fid};		$info->{Sex} = $sex;		$info->{Age} = $age;		$info->{Face} = $face;		$info->{Nickname} = $nickname;		$info->{Friend} = 1;		$info->{Unknown} = $unknown;	}	if ($flag ne "\xff\xff") {		$oicq->get_friends_list($flag);	}	return 1;}sub recv_friend_status {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq  = $self->{OICQ};	my $srcid = unpack('N', substr($plain,  0, 4));	my $addr = $oicq->show_address(substr($plain, 5, 6));	$self->{Mode}  = ord(substr($plain, 12, 1));	$self->{H13_33} = unpack("H*", substr($plain, 13, 20));	$self->{DstId} = unpack('N', substr($plain, 35, 4));	$self->{SrcId} = $srcid;	$oicq->{Info}->{$srcid} = {} unless defined $oicq->{Info}->{$srcid};	my $info = $oicq->{Info}->{$srcid};	if ($addr =~ /[1-9]/) {		$self->{Addr} = $addr;		$info->{Addr} = $addr;	}	$info->{Mode} = $self->{Mode};	return 1;}sub do_group {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq = $self->{OICQ};	my ($sub_cmd, $reply) = unpack('H2H2', substr($plain, 0, 2));	$self->{SubCmd} = $sub_cmd;	$self->{Reply} = $reply;	if ($reply ne '00'){		$self->{Error} = substr($plain, 2);		return;	}	if ($sub_cmd eq '06') { # search group		my ($search_type, $int_gid, $ext_gid, $gtype, $x, $owner_id) =			unpack('H2NNH2H8N', substr($plain, 2, 18));		my $gname_len = ord(substr($plain, 30, 1));		my $gname = substr($plain, 31, $gname_len);		my $gauth_type = unpack('H*', substr($plain, 33+$gname_len, 1));		my $gdesc_len = ord(substr($plain, 34+$gname_len, 1));		my $gdesc = substr($plain, 35+$gname_len, $gdesc_len);		$oicq->log_t("S_DO_GROUP $sub_cmd code $reply:\n", $oicq->hexdump($plain));		$self->{GrpIntId} = $int_gid;		$self->{GrpExtId} = $ext_gid;		$self->{GrpOwner} = $owner_id;		$self->{GrpName}  = $gname;		$self->{GrpDesc}  = $gdesc;		return 1;	}	if ($sub_cmd eq '04') { # group info		my ($int_gid, $ext_gid, $gtype, $owner_id, $gauth_type) =			unpack('NNH2NH2', substr($plain, 2, 14));		my $cat = unpack("n",substr($plain, 18, 2));		my $gname_len = ord(substr($plain, 24, 1));		my $gname = substr($plain, 25, $gname_len);		my $gnotice_len = ord(substr($plain, 27+$gname_len, 1));		my $gnotice = substr($plain, 28+$gname_len, $gnotice_len);		my $gdesc_len = ord(substr($plain, 28+$gname_len+$gnotice_len, 1));		my $gdesc = substr($plain, 29+$gname_len+$gnotice_len, $gdesc_len);		$self->{GrpIntId} = $int_gid;		$self->{GrpName}  = $gname;		$self->{GrpNotice} = $gnotice;		$self->{GrpDesc}  = $gdesc;		return 1;	}	if ($sub_cmd eq '0b') { # online group members		$self->{GrpIntId} = unpack('N', substr($plain, 2, 4));		my @online_members = length($plain) >= 11 ? unpack('N*', substr($plain, 7)) : ();		$self->{OnlineMembers} = \@online_members;		return 1;	}	$self->{Unknown} = unpack("H*", substr($plain, 2));	return;}sub req_file_key {	my ($self) = @_;	my $plain = $self->{Data};	my $oicq  = $self->{OICQ};	unless (unpack('H4', $plain) eq '0400' and length($plain) > 18) {		$oicq->log_t("Svr response to req_file_key:\n", $oicq->hexdump($plain));		return;	}	my $file_key = substr($plain, 2, 16);	$self->{FileKey} = $file_key;	$oicq->log_t("Received file transfer key from server: $file_key");}1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -