This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

php pastebin - collaborative irc debugging view php source

Paste #85

Posted by: nul
Posted on: 2026-02-08 22:27:56
Age: 2 hrs ago
Views: 8
#!/usr/bin/env python
# -*- coding: utf-8 -*-

__licence__ = """
Copyright (C) 2009 Mikhail Ryzhov <rymiser@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
"""

"""
	Mail.ru agent protocol implementation with Python
"""

LIB_VERSION = '0.02'
__version__ = LIB_VERSION

MRIM_ENCODING='cp1251'

import socket
import struct
import threading
import select
import time
import base64
import zlib
import email
from traceback import print_exc
import urllib

#try:
#	import syslog
#	syslog.openlog('MRIM')
#
#	log = syslog.syslog
#except:
def log(msg):
	import sys
	import datetime
	print >>sys.stderr, "[MRIM %s] %s" % (datetime.datetime.now().ctime(), msg)

class MRIMError(Exception):
	pass

PROTO_VERSION_MAJOR = 1
PROTO_VERSION_MINOR = 9
PROTO_VERSION = (PROTO_VERSION_MAJOR << 16) | PROTO_VERSION_MINOR
CS_MAGIC = 0xDEADBEEF
STATUS_OFFLINE =	0x00000000
STATUS_ONLINE =		0x00000001
STATUS_AWAY =		0x00000002
STATUS_UNDETERMINATED =	0x00000003
STATUS_FLAG_INVISIBLE =	0x80000000

MRIM_CS_HELLO = 0x1001
MRIM_CS_HELLO_ACK = 0x1002
MRIM_LOGIN2 = 0x1038
MRIM_LOGIN_ACK = 0x1004
MRIM_LOGIN_REJ = 0x1005
MRIM_CS_PING = 0x1006
MRIM_CS_MESSAGE = 0x1008

MESSAGE_FLAG_OFFLINE =		0x00000001
MESSAGE_FLAG_NORECV =		0x00000004
MESSAGE_FLAG_AUTHORIZE =	0x00000008
MESSAGE_FLAG_SYSTEM =		0x00000040
MESSAGE_FLAG_RTF =		0x00000080
MESSAGE_FLAG_CONTACT =		0x00000200
MESSAGE_FLAG_NOTIFY =		0x00000400
MESSAGE_FLAG_MULTICAST =	0x00001000
MAX_MULTICAST_RECIPIENTS = 50
MESSAGE_USERFLAGS_MASK =	0x000036A8

MRIM_CS_MESSAGE_ACK = 0x1009
MRIM_CS_MESSAGE_RECV = 0x1011
MRIM_CS_MESSAGE_STATUS = 0x1012
MESSAGE_DELIVERED = 0x0000
MESSAGE_REJECTED_NOUSER = 0x8001
MESSAGE_REJECTED_INTERR = 0x8003
MESSAGE_REJECTED_LIMIT_EXCEEDED = 0x8004
MESSAGE_REJECTED_TOO_LARGE = 0x8005
MESSAGE_REJECTED_DENY_OFFMSG = 0x8006
MRIM_CS_USER_STATUS = 0x100F
MRIM_CS_LOGOUT = 0x1013
LOGOUT_NO_RELOGIN_FLAG = 0x0010
MRIM_CS_CONNECTION_PARAMS = 0x1014
MRIM_CS_USER_INFO = 0x1015
MRIM_CS_ADD_CONTACT = 0x1019
CONTACT_FLAG_REMOVED = 0x00000001
CONTACT_FLAG_GROUP = 0x00000002
CONTACT_FLAG_INVISIBLE = 0x00000004
CONTACT_FLAG_VISIBLE = 0x00000008
CONTACT_FLAG_IGNORE = 0x00000010
CONTACT_FLAG_SHADOW = 0x00000020
MRIM_CS_ADD_CONTACT_ACK = 0x101A
CONTACT_OPER_SUCCESS =		0x0000
CONTACT_OPER_ERROR =		0x0001
CONTACT_OPER_INTERR =		0x0002
CONTACT_OPER_NO_SUCH_USER =	0x0003
CONTACT_OPER_INVALID_INFO =	0x0004
CONTACT_OPER_USER_EXISTS =	0x0005
CONTACT_OPER_GROUP_LIMIT =	0x6
MRIM_CS_MODIFY_CONTACT = 0x101B
MRIM_CS_MODIFY_CONTACT_ACK = 0x101C
MRIM_CS_OFFLINE_MESSAGE_ACK = 0x101D
MRIM_CS_DELETE_OFFLINE_MESSAGE = 0x101E
MRIM_CS_AUTHORIZE = 0x1020
MRIM_CS_AUTHORIZE_ACK = 0x1021
MRIM_CS_CHANGE_STATUS =	0x1022
MRIM_CS_GET_MPOP_SESSION = 0x1024
MRIM_CS_MPOP_SESSION = 0x1025
MRIM_GET_SESSION_FAIL = 0
MRIM_GET_SESSION_SUCCESS = 1
MRIM_CS_WP_REQUEST = 0x1029
PARAMS_NUMBER_LIMIT = 50
PARAM_VALUE_LENGTH_LIMIT = 64
(
  MRIM_CS_WP_REQUEST_PARAM_USER,
  MRIM_CS_WP_REQUEST_PARAM_DOMAIN,
  MRIM_CS_WP_REQUEST_PARAM_NICKNAME,
  MRIM_CS_WP_REQUEST_PARAM_FIRSTNAME,
  MRIM_CS_WP_REQUEST_PARAM_LASTNAME,
  MRIM_CS_WP_REQUEST_PARAM_SEX,
  MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY,
  MRIM_CS_WP_REQUEST_PARAM_DATE1,
  MRIM_CS_WP_REQUEST_PARAM_DATE2,
  MRIM_CS_WP_REQUEST_PARAM_ONLINE,
  MRIM_CS_WP_REQUEST_PARAM_STATUS,
  MRIM_CS_WP_REQUEST_PARAM_CITY_ID,
  MRIM_CS_WP_REQUEST_PARAM_ZODIAC,
  MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_MONTH,
  MRIM_CS_WP_REQUEST_PARAM_BIRTHDAY_DAY,
  MRIM_CS_WP_REQUEST_PARAM_COUNTRY_ID,
  MRIM_CS_WP_REQUEST_PARAM_MAX
) = range(17)

MRIM_CS_ANKETA_INFO = 0x1028
MRIM_ANKETA_INFO_STATUS_OK = 1
MRIM_ANKETA_INFO_STATUS_NOUSER = 0
MRIM_ANKETA_INFO_STATUS_DBERR = 2
MRIM_ANKETA_INFO_STATUS_RATELIMERR = 3
MRIM_CS_MAILBOX_STATUS = 0x1033	
MRIM_CS_CONTACT_LIST2 = 0x1037
GET_CONTACTS_OK = 0x0000
GET_CONTACTS_ERROR = 0x0001
GET_CONTACTS_INTERR = 0x0002
CONTACT_INTFLAG_NOT_AUTHORIZED = 0x0001

def PROTO_MAJOR(p):
	return (((p)&0xFFFF0000)>>16)

def PROTO_MINOR(p):
	return ((p)&0x0000FFFF)
###############################################################################

class MRIMData(object):
	"""
	MRIMData ojects can work as any of mrim data types using format. Format is sequence (name, type, name, type, ...).
For example:
(
	'from', 'LPS',
	'msg_id', 'UL'
) is data of cs_message_recv. You can use simple form:
	msg.data['from'] = 'nobody@mail.ru' and et.c. for manipulating this parameters.
	Defined types are:
		UL - unsigned long
		UIDL - unique message ID (8 bytes)
		LPS - string encoded as length:data
		LPSO - optional string
		LPSA - array of LPS
	"""
	def __init__(self, fmt = None):
		self.fmt = []
		self.data = {}

		if fmt:
			self.set_format(fmt)

	def set_format(self, fmt):
		" set format for data "
		self.fmt = list(fmt)[:] # Copy

		self.data = {}
		par = True
		for i in fmt:
			if par:
				self.data[i] = None
			par = not par

	def encode(self):
		" encode data into string "
		name = None
		type = None
		par = True

		str = ''

		for f in self.fmt:
			if par:
				name = f
			else:
				type = f

				str += self.encode_type(type, self.data[name])
			par = not par

		return str

	def decode(self, data):
		" decode data from string "
		name = None
		type = None
		par = True

		for f in self.fmt:
			if par:
				name = f
			else:
				type = f
				data, self.data[name] = self.decode_type(type, data)

			par = not par

	def encode_type(self, type, val):
		" encode value val of type type "
		if type == 'UL':
			return struct.pack('<L', int(val))
		elif type == 'LPS':
			if isinstance(val, unicode):
				val = val.encode(MRIM_ENCODING, 'replace')
			return struct.pack('<L%ds'%len(val), len(val), val)
		elif type == 'UIDL':
			if len(val) != 8:
				raise MRIMError, "Invalid parameter passed to UIDL"
			return val
		elif type == 'LPSO': # Optional LPS
			if not val:
				return ""
			else:
				return self.encode_type('LPS', val)
		elif type == 'LPSA': # Array of LPS
			return "".join([self.encode_type('LPS', lps) for lps in val])
		else:
			raise MRIMError, "Unknon type: %s" % type

	def decode_type(self, type, data):
		" decode value of type from data "
		if type == 'UL':
			return (data[4:], struct.unpack('<L', data[:4])[0])
		elif type == 'LPS':
			ln = struct.unpack('<L', data[:4])[0]
			return (data[ln+4:], data[4:ln+4])
		elif type == 'LPSO':
			if len(data) > 0:
				return self.decode_type('LPS', data)
			else:
				return (data, "")
		elif type == 'LPSA':
			r = []
			while len(data) > 0:
				try:
					data, val = self.decode_type('LPS', data)
					r.append(val)
				except:
					break
			return (data, r)
		elif type == 'UIDL':
			return (data[8:], data[:8])
		else:
			raise MRIMError, "Unknown type: %s" % type

class MRIMPacket(object):
	" Low-level MRIM message "
	LEN = struct.calcsize('<7l16s')

	def __init__(self, magic = CS_MAGIC, proto = PROTO_VERSION, msg = None, fromaddr = 0, fromport = 0, data = None):
		self.magic = magic
		self.proto = proto
		self.seq = 0
		self.msg = msg

		self.data = data
		self.fromaddr = fromaddr
		self.fromport = fromport
		self.reserved = '\0'*16

	def __reverse(self, i):
		" reverse i bytes "
		return (((i&0xFF) << 24) | ((i&0xFF00) << 8) | ((i&0xFF0000)>>8) | ((i&0xFF000000)>>24))

	def encode(self):
		" encode data to send it over network: "
		if len(self.reserved) == 16:
			res = self.reserved
		else:
			res = '\0'*16

		if not self.data:
			d = ''
		else:
			d = self.data
		return struct.pack('<7L16s%ds'%len(d), self.magic, self.proto, self.seq, self.msg, len(d), self.__reverse(self.fromaddr), self.__reverse(self.fromport), res, d)

	def send(self, sock):
		" send MRIMPacket over network. addr and port will be calculated at this point "
		self.fromaddr, self.fromport = sock.getsockname()
		self.fromaddr = struct.unpack('>l', socket.inet_aton(self.fromaddr))[0]

		str = self.encode()

		while len(str) > 0:
			l = sock.send(str)
			if l < 0:
				raise MRIMError, "Network problems"
			str = str[l:]

	def recv(self, sock):
		" receive data header from socket "
		ln = self.LEN

		# read len bytes:
		str = ''
		while len(str) < ln:
			d = sock.recv(ln - len(str))
			if len(d) == 0:
				raise MRIMError, "Connection closed"
			str += d

		self.decode(str)

		if self.dlen:
			# read data from socket:
			str = ''
			while len(str) < self.dlen:
				d = sock.recv(self.dlen - len(str))
				if len(d) == 0:
					raise MRIMError, "Connection closed"
				str += d

			self.data = str
		else:
			self.data = ''

	def decode(self, str):
		" decode header "
		self.magic, self.proto, self.seq, self.msg, self.dlen, fromaddr, fromport, res = struct.unpack('<7l16s', str)
		self.fromaddr = socket.ntohl(fromaddr)
		self.fromport = socket.ntohl(fromport)
		self.data = None

	def __repr__(self):
		return "MRIM Message { type: %x, seq: %d }" % (self.msg, self.seq)


class MRIMMessage(object):
	def __init__(self, msg = u"", xml_msg = None, rtf_msg = None, flags = 0, mrim = None, address = None):
		" Create new message "
		self.msg = msg
		self.xml_msg = xml_msg
		self.rtf_msg = rtf_msg
		self.flags = flags
		self.mrim = None
		self.uidl = None
		self.msg_id = None
		self.address = address

	def encode(self):
		" Encode message for sending "
		# TODO: RTF part
		D = MRIMData( ('flags', 'UL', 'to', 'LPS', 'txt', 'LPS', 'rtf', 'LPSO') )
		D.data['flags'] = self.flags
		D.data['to'] = self.address
		D.data['txt'] = self.msg
		if not self.rtf_msg:
			self.rtf_msg = ' ' # Mail.Ru don't do it, but we will

		if self.rtf_msg:
			R = MRIMData( ('lpscnt', 'UL', 'rtf', 'LPS', 'bgcolor', 'UL') )
			R.data['lpscnt'] = 2
			R.data['rtf'] = self.rtf_msg
			R.data['bgcolor'] = 0x00FFFFFF
			D.data['rtf'] = base64.b64encode(zlib.compress(R.encode()))
		else:
			D.data['rtf'] = None

		return D.encode()

	def decode(self, data):
		" Decode online message "
		D = MRIMData((
			'msg_id', 'UL',
			'flags', 'UL',
			'from',  'LPS',
			'message', 'LPS',
			'rtf', 'LPSO'
			))
		D.decode(data)

		self.flags = D.data['flags']
		if self.flags & MESSAGE_FLAG_RTF:
			R = MRIMData( ('lpscnt', 'UL', 'rtf', 'LPS', 'bgcolor', 'UL') )
			t = R.decode(zlib.decompress(base64.b64decode(D.data['rtf'])))
			self.rtf_msg = R.data['rtf']
		else:
			self.rtf_msg = None

		self.msg = D.data['message'].decode(MRIM_ENCODING, 'replace')
		self.address = D.data['from']
		self.msg_id = D.data['msg_id']

		self._make_xml()

	def decode_offline(self, rfc822):
		" Decode MRIM offline message "
		D = MRIMData( ('uidl', 'UIDL', 'message', 'LPS') )
		D.decode(rfc822)
		M = email.message_from_string(D.data['message'])

		# Process message:
		self.address = M['from']
		self.flags = int(M['X-MRIM-Flags']) | MESSAGE_FLAG_OFFLINE
		text_part = None
		rtf_part = None
		for part in M.walk():
			if part.get_content_maintype() == 'text':
				if not text_part:
					text_part = part.get_payload(decode = True)
				else:
					rtf_part = part.get_payload(decode = True)

		self.msg = ""
		for s in text_part.split('\n'):
			if not s.startswith('--'):
				self.msg += "%s\n" % s
		self.msg = self.msg.decode(MRIM_ENCODING, 'replace')
		try:
			if rtf_part:
				self.rtf_msg = zlib.decompress(base64.b64decode(rtf_part))
		except:
			self.rtf_msg = None

		self.uidl = D.data['uidl']
		self.msg_id = None

		self._make_xml()

	def submit(self):
		" If this is offline message - then delete it, else sens MSG_RECV to server "
		if self.flags & MESSAGE_FLAG_OFFLINE:
			log("Delete offline message...")
			D = MRIMData( ("uidl", "UIDL") )
			M = MRIMPacket(msg = MRIM_CS_DELETE_OFFLINE_MESSAGE)
			D.data['uidl'] = self.uidl
			M.data = D.encode()

			self.mrim.send_msg(M)
		elif not (self.flags & MESSAGE_FLAG_NORECV):
			log("Sending message received MRIMPacket...")
			D = MRIMData( ('from', 'LPS', 'msgid', 'UL') )
			D.data['from'] = self.address
			D.data['msgid'] = self.msg_id

			M = MRIMPacket(msg = MRIM_CS_MESSAGE_RECV)
			M.data = D.encode()

			self.mrim.send_msg(M)

	def authorize(self):
		" Authorize user: "
		if not self.is_authorization():
			raise MRIMError, "It is not authorization request"
		log("Authorize user: %s..." % self.address)
		D = MRIMData( ('user', 'LPS' ) )
		D.data['user'] = self.address
		M = MRIMPacket(msg = MRIM_CS_AUTHORIZE)
		M.data = D.encode()
		self.mrim.send_msg(M)

	def is_authorization(self):
		" Is message authorization request "
		return ((self.flags & MESSAGE_FLAG_AUTHORIZE) != 0)

	def is_offline(self):
		" Is message delivered offline "
		return ((self.flags & MESSAGE_FLAG_OFFLINE) != 0)

	def set_flag(self, flag):
		" Set flags to message "
		self.flags |= flag

	def _make_xml(self):
		if not self.rtf_msg:
			self.xml_msg = self.msg
		else:
			# TODO: process RTF
			# self.msg = self.rtf_msg.decode(MRIM_ENCODING)
			self.xml_msg = self.msg

class MRIMPlugin(object):
	def message_received(self, message):
		" Callback of received message "
		pass
	
	def message_sent(self, message):
		" Called, when message sent. (Don't work at this time) "
		pass

	def register(self, mrim):
		" This method will be call'ed for register this plugin "
		self.mrim = mrim

	def is_my_message(self, mrim_type):
		" Return is message supported by plugin "
		if hasattr(self, 'MESSAGE'):
			return mrim_type == self.MESSAGE
		return False

class ContactList(object):
	" Contact list object represent MRIMContact list. "
	def __init__(self, mrim):
		self.mrim = mrim
		self.mrim.add_handler('contact_list', self._contact_list_rec)
		self.mrim.add_handler('user_status', self._user_status)
		self.groups = []
		self.contacts = []
		self._operations = [] # Operation is [ seq, type, args, descr ]

	def _contact_list_rec(self, groups, contacts):
		self.groups = groups
		self.contacts = contacts
		self._update()

	def _operation_result(self, seq, res, contact_id = None):
		oper = None
		for o in self._operations:
			if o[0] == seq:
				oper = o
				break

		if not oper:
			return

		if res == CONTACT_OPER_USER_EXIST:
			# It is not error
			return

		if res == CONTACT_OPER_SUCCESS:
			self._process_operation(oper, contact_id)
		else:
			raise MRIMError, "Operation failed: %s" % oper[3]

	def _process_operation(self, oper, contact_id = None):
		if oper[1] == 'AC': # Add contact:
			gid, name, nick = oper[2]
			self.contacts.append( { 'group': gid, 'address': name, 'nick': nick, 'status': 0, 'flags': 0, 'id': contact_id } )
		elif oper[1] == 'RC': # remove contact
			name = oper[2]
			for c in self.contacts:
				if c['address'] == name:
					self.contacts.remove(c)
					break
		else:
			# Unknown operation
			log("Strange: unknown operation: %s" % oper[1])
			return

		self.mrim.call_action('contact_list_updated', (self.groups, self.contacts))

	def _user_status(self, email, status):
		for c in self.contacts:
			if c['address'] == email:
				c['status'] = status

		self._update()

	def _update(self):
		self.mrim.call_action('contact_list_updated', (self.groups, self.contacts))

	def list_contacts(self, group = None):
		return [c for c in self.contacts if not group or c['group'] == group]
		# for c in self.contacts:
		# 	if not group or c['group'] == group:
		# 		yield c

	def add_group(self, group_name):
		" Add new group to contact list "
		pass

	def add_contact(self, user, group, flags = 0):
		" Add new contact to contact list "
		seq = self.mrim.add_contact(user, group, flags)

		self._operations.append([seq, 'AC', (group, user, user), 'Add user %s' % user])

	def modify_contact(self, user, group = None, contact = None, name = None):
		" Modify contact "
		pass

	def remove_contact(self, user):
		" Remove contact from contact list "
		pass

	def remove_group(self, user):
		" Remove group from contact list "
		pass

SESSION_OPENED = 1
LOGGED_IN = 2

class MailRuAgent(object):
	" main class for protocol "

	def __init__(self, no_load_plugins = False):
		self.sock = None
		self.address = None # My address
		self.ping_period = 30
		self.seq = 1
		self.plugins = {}
		self.methods = {}
		self.actions = {}
		self._queue = []
		self._buf = ""
		self.autoreconnect = True
		self.state = 0
		self.last_ping = time.time()

		if not no_load_plugins:
			import mrim_plugins
			self.load_plugins(mrim_plugins.PLUGINS_ALL)

	def load_plugins(self, plugins):
		" Load all plugins from plugins list "
		for p in plugins:
			plug = self.plugins[p.__name__] = p()
			plug.register(self)

	def call_action(self, name, args):
		" Call action name with args: "
		log("Action <%s>" % name)
		if self.actions.has_key(name):
			for h in self.actions[name]:
				try:
					if not h(*args):
						return False
				except:
					log("Error: Action handler failed")
					print_exc()
		return True

	def add_handler(self, name, func, method = "append"):
		" Add action handler "
		if not self.actions.has_key(name):
			self.actions[name] = []

		if method == 'append':
			self.actions[name].append(func)
		elif method == 'prepend':
			self.actions[name].insert(0, func)
		else:
			raise MRIMError, "Unknown method: %s" % method

	def add_method(self, name, func):
		if self.methods.has_key(name):
			raise MRIMError, "Duplicate method definition: %s" % name
		self.methods[name] = func

	def connect(self, server = 'mrim.mail.ru', port = 443):
		" Connect to mail.ru server "
		# Get IP:Port from mail.ru server:
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
		sock.connect((server, port))

		str = ''
		a = 'a'
		while len(a) > 0:
			a = sock.recv(256)
			str += a
		sock.close()

		self._addr, self._port = str.split(':')

		log('Connecting to %s:%s' %(self._addr, self._port))
		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
		self.sock.connect((self._addr, int(self._port)))

		# Send hello:
		log('Sending hello...')
		
		msg = MRIMPacket(msg = MRIM_CS_HELLO)
		msg.seq = self.seq
		msg.send(self)
		self.seq += 1

	def login(self, user, password, status = STATUS_ONLINE):
		" Login to server "
		# Send login and password:
		l = MRIMData( ('login', 'LPS', 'password', 'LPS', 'status', 'UL', 'description', 'LPS') )
		l.data['login'] = user
		l.data['password'] = password
		l.data['status'] = status
		l.data['description'] = 'MRIM Python library v%s. <rymis@mail.ru>' % LIB_VERSION
		l.data['description'] = "myagent-im"


		log('Sending login...')
		msg = MRIMPacket(msg = MRIM_LOGIN2)
		msg.data = l.encode()
		self.send_msg(msg)
		self.address = user

	def send_msg(self, msg, seq = None):
		" Send message to server "
		if not seq:
			msg.seq = self.seq
			self.seq += 1
		msg.send(self)
		return msg.seq

	def is_connected(self):
		return self.sock != None

	def close(self):
		" Logout and close connection "
		from traceback import print_stack
		print_stack()
		if self.sock:
			self.sock.close()
			self.sock = None
			self.call_action('connection_closed', [])

	def send(self, data):
		" Append data to queue "
		self._queue.append(data)
		return len(data)

	def getsockname(self):
		" Socket interface functions "
		return self.sock.getsockname()

	def _send(self):
		" This function send message from queue to network "
		log('Sending message to network...')

		if len(self._queue) == 0:
			return

		l = self.sock.send(self._queue[0])
		if l < 0:
			raise MRIMError, "Network problems"
		if l == len(self._queue[0]):
			del self._queue[0]
		else:
			self._queue[0] = self._queue[0][l:]

	def dataReceived(self, data):
		" You must call this function if data received on socket. Or call idle "
		self._buf += data
		self._processBuf()

	def idle(self):
		" this function will try to read server message, and if present call action handler. Also if need ping processed. "
		if not self.sock:
			return

		self.ping()

		(r, w, x) = select.select([self.sock], [self.sock], [], 0)

		if len(w) > 0:
			self._send()
		if len(r) > 0:
			self._read()

	def ping(self):
		" Send ping if need "
		if not self.sock:
			return
		t = time.time()
		if abs(t - self.last_ping) > self.ping_period:
			self._ping()
			self.last_ping = time.time()

	def _read(self):
		buf = self.sock.recv(1024)
		if len(buf) == 0:
			# Connection closed
			self.close()
		self.dataReceived(buf)


	def _processBuf(self):
		while True:
			msg = MRIMPacket()
			if len(self._buf) >= msg.LEN:
				msg.decode(self._buf[:msg.LEN])
				if msg.dlen + msg.LEN <= len(self._buf):
					msg.data = self._buf[msg.LEN: msg.LEN + msg.dlen]
					self._buf = self._buf[msg.LEN + msg.dlen:]
					log("New message from server: %s"% repr(msg))

					for pn in self.plugins:
						p = self.plugins[pn]
						if p.is_my_message(msg.msg):
							log("Plugin %s: processing message..." % pn)
							p.message_received(msg)
				else:
					break
			else:
				break


	def _ping(self):
		msg = MRIMPacket(msg = MRIM_CS_PING)
		seq = self.seq
		self.seq += 1
		msg.seq = seq
		msg.send(self)

	def change_status(self, status):
		" Change user status "
		log("Change status to %d" % status)
		msg = MRIMPacket(msg = MRIM_CS_CHANGE_STATUS)
		seq = self.seq = self.seq + 1
		seq -= 1
		msg.seq = seq
		l = MRIMData(('status', 'UL'))
		l.data['status'] = status
		msg.data = l.encode()

		msg.send(self)

		if status == STATUS_OFFLINE:
			self.close()

	def send_message(self, msg, addr = None):
		" Send message. msg is MRIMMessage or string. If string user, then addr must be specified "
		if not isinstance(msg, MRIMMessage):
			txt = msg
			if not addr:
				raise MRIMError, "Not enought params in send_message "
			msg = MRIMMessage(msg = txt, flags = MESSAGE_FLAG_NORECV, address = addr)

		M = MRIMPacket(msg = MRIM_CS_MESSAGE)
		M.seq = self.seq
		self.seq += 1
		M.data = msg.encode()

		M.send(self)

		return M.seq

	def request_user_info(self, user):
		" Send user-info-request "
		D = MRIMData( ('field1', 'UL', 'user', 'LPS', 'field2', 'UL', 'domain', 'LPS') )
		(name, domain) = user.split('@')
		l = domain.rfind('/')
		if l > 0:
			domain = domain[:l]

		D.data['field1'] = MRIM_CS_WP_REQUEST_PARAM_USER
		D.data['field2'] = MRIM_CS_WP_REQUEST_PARAM_DOMAIN
		D.data['user'] = name
		D.data['domain'] = domain
		print name, domain

		p = MRIMPacket(msg = MRIM_CS_WP_REQUEST)
		p.data = D.encode()

		return self.send_msg(p)

	def process_message(self, msg):
		" Check message flags and call actions "
		if not self.call_action("raw_message", [msg]):
			return False

		if msg.flags & MESSAGE_FLAG_AUTHORIZE:
			return self.call_action("authorization_request", [msg])
		elif msg.flags & MESSAGE_FLAG_CONTACT:
			return self.call_action("contact_list_message", [msg])
		else:
			return self.call_action("message", [msg])

	def pollRegister(self, poll):
		if not self.sock:
			return
		if len(self._queue) > 0:
			w_f = self._send
		else:
			w_f = None

		poll.register(self.sock, read_f = self._read, write_f = w_f)

	def fileno(self):
		return self.sock.fileno()

	def add_contact(self, user, groupid, flags = 0):
		" Add new contact to contact list "
		msg = MRIMPacket(msg = MRIM_CS_ADD_CONTACT)
		D = MRIMData( ('flags', 'UL', 'group', 'UL', 'name', 'LPS', 'unused', 'LPS') )
		D.data['flags'] = flags
		D.data['group'] = groupid
		D.data['name'] = user
		D.data['unused'] = ""
		msg.data = D.encode()

		seq = self.mrim.send_msg(msg)

		return seq

	def remove_contact(self, userid):
		" Remove contact with specified id from contact list "
		msg = MRIMPacket(msg = MRIM_CS_MODIFY_CONTACT)

def load_avatar(email, domain):
	" Loading avatar from HTTP "
	url = "http://obraz.foto.mail.ru/%s/%s/_mrimavatarsmall" % (domain, email)
	f = urllib.urlopen(url)
	tp = f.info().gettype()
	dt = f.read()
	f.close()

	return (tp, dt)

if __name__ == '__main__':
	d = MRIMData(('name', 'LPS', 'value', 'UL'))
	d.data['name'] = 'yo'
	d.data['value'] = 123
	s = d.encode()
	print s
	d.decode(s)
	print d.data

Download raw | Create new paste

© BitByByte, 2026.
Downgrade Counter