import random import sys import types import os import xmpp import struct import datetime import time import socket from mmptypes import * import re import mrim import zlib import base64 import cStringIO import xmpp import hashlib conf = mrim.conf ENCODING = 'utf-8' xmpp.NS_GATEWAY = 'jabber:iq:gateway' xmpp.NS_STATS = 'http://jabber.org/protocol/stats' xmpp.NS_ROSTERX = 'http://jabber.org/protocol/rosterx' xmpp.NS_NICK = 'http://jabber.org/protocol/nick' xmpp.NS_RECEIPTS = 'urn:xmpp:receipts' xmpp.NS_CHATSTATES = 'http://jabber.org/protocol/chatstates' xmpp.NS_NEW_DELAY = 'urn:xmpp:delay' xmpp.NS_NEW_TIME = 'urn:xmpp:time' xmpp.NS_PING = 'urn:xmpp:ping' xmpp.NS_CAPS = 'http://jabber.org/protocol/caps' common_features = [ xmpp.NS_DISCO_INFO, xmpp.NS_DISCO_ITEMS, xmpp.NS_VCARD, xmpp.NS_COMMANDS, xmpp.NS_CAPS] client_features = common_features + [ xmpp.NS_RECEIPTS, xmpp.NS_CHATSTATES] server_features = common_features + [ xmpp.NS_STATS, xmpp.NS_SEARCH, xmpp.NS_REGISTER, xmpp.NS_TIME, xmpp.NS_VERSION, xmpp.NS_LAST, xmpp.NS_GATEWAY, xmpp.NS_NEW_TIME, xmpp.NS_DELAY, xmpp.NS_NEW_DELAY, xmpp.NS_PING] mail_pattern = re.compile( '[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,35}@(mail\.ru|inbox\.ru|bk\.ru|list\.ru|corp\.mail\.ru|chat\.agent)$' ) password_pattern = re.compile('[\040-\176]{4,}$') number_pattern = re.compile('\+{0,1}[0-9]+$') upper_ascii_pattern = re.compile('[\200-\377]+') invalid_chars = re.compile( '[\000-\011\013\014\016-\037\202\204-\207\210\211\213\221-\227\230\231\233\271]' ) RTF_H = '{\\rtf1\\ansi\\ansicpg1251\\deff0\\deflang1049{\\fonttbl{\\f0\\fnil\\fcharset204 Tahoma;}}\r\n{\\colortbl ;\\red0\\green0\\blue0;}\r\n\\viewkind4\\uc1\\pard\\cf1\\f0\\fs18 ' RTF_T = '\\par\r\n}\r\n' INTRANSTBL = [chr(i) for i in range(0x0,0x09)+range(0x0b,0x0d)+range(0x7f,256)] OUTTRANSTBL = [hex(ord(i)).replace('0x',"\\'") for i in INTRANSTBL] INSYMS = ['\\','\r','\n','\t','{','}'] OUTSYMS = ['\\\\','','\\par\r\n','\\tab','\\{','\\}'] INSMILES = [ ':)',';)',':-))',';-P','8-)','):-D','}:o)','$-)', ":-'",'):-(','8-(',":'(",":''()",'S:-o','(:-o','8-0', '8-[o]','):-p',':-(','):-$',':-D',':-E',':devil:',':vampire:', ':-][',':-|','B-j',':~o','(_I_)',':heart:',':-*',':sleepy:', ':cool:',':viva:',':ok:',':yo:',':suxx:',':think:',':figu:',':kulak:',':fuck:' ] OUTSMILES = [ '<###20###img010>','<###20###img011>','<###20###img012>','<###20###img013>', '<###20###img014>','<###20###img030>','<###20###img016>','<###20###img017>', '<###20###img018>','<###20###img028>','<###20###img020>','<###20###img021>', '<###20###img022>','<###20###img023>','<###20###img024>','<###20###img025>', '<###20###img026>','<###20###img027>','<###20###img019>','<###20###img029>', '<###20###img015>','<###20###img031>','<###20###img032>','<###20###img033>', '<###20###img034>','<###20###img035>','<###20###img036>','<###20###img037>', '<###20###img038>','<###20###img039>','<###20###img040>','<###20###img041>', '<###20###img000>','<###20###img001>','<###20###img002>','<###20###img003>', '<###20###img005>','<###20###img006>','<###20###img007>','<###20###img008>', '<###20###img009>' ] INCHARS = tuple(INSYMS+INTRANSTBL) OUTCHARS = tuple(OUTSYMS+OUTTRANSTBL) IN_TRANSLIT_TBL = tuple(["'",chr(0xa8),chr(0xb8)] + [chr(i) for i in range(0xc0,256)]) _lat = [ 'a','b','v','g','d','e','zh','z','i','jj','k','l','m','n','o','p','r', 's','t','u','f','kh','c','ch','sh','shh','"','y',"'",'eh','yu','ya' ] OUT_TRANSLIT_TBL = tuple(['*','Jo','jo'] + [x[0].upper()+x[1:] for x in _lat] + _lat) UPPER_ASCII = tuple([chr(i) for i in range(128,256)]) NULL_ASCII = tuple(['' for i in range(128,256)]) try: import xml.dom.ext import xml.dom.minidom import cStringIO def pretty_xml(xml_string): io_string = cStringIO.StringIO() xml_string = ''+xml_string+'' xml.dom.ext.PrettyPrint( root = xml.dom.minidom.parseString(xml_string), stream = io_string, indent = ' ' ) io_string.seek(0) res = [] for x in io_string.readlines()[2:-1]: if x.startswith(' '): res.append(x[4:]) else: res.append(x) sum = '' for i in res: sum += i return sum.strip('\n') except: def pretty_xml(xml_string): return xml_string def is_valid_email(mail): if mail_pattern.match(mail): return True else: return False def is_valid_password(password): if password_pattern.match(password): return True else: return False def is_valid_sms_number(number): if number_pattern.match(number): return True else: return False def is_valid_sms_text(text): has_not_ascii = upper_ascii_pattern.search(text) if has_not_ascii and len(text)<=37: return True elif (not has_not_ascii) and len(text)<=137: return True else: return False def dump_packet(p): print "--- Begin of dump ---" print "Header: %s" % p.getHeader().__repr__() print "Body: %s" % p.getBody().__repr__() print "---- End of dump ----\n" def seq(): return long(random.random()*100000) def str2win(s): if type(s) == types.StringType: r = unicode(s, ENCODING).encode('cp1251', 'replace') elif type(s) == types.UnicodeType: r = s.encode('cp1251', 'replace') else: raise TypeError('value %s is neither unicode nor string' % s) return r def translate(s, t1, t2): for i in range(len(t1)): s = s.replace(t1[i], t2[i]) return s def winrtf(s): return translate(s, INCHARS, OUTCHARS) def translit(s): en = translate(s, IN_TRANSLIT_TBL, OUT_TRANSLIT_TBL) return translate(en, UPPER_ASCII, NULL_ASCII) def win2str(s): t = invalid_chars.sub(' ',s) u_s = unicode(t, 'cp1251') #return unicode(u_s.encode(ENCODING, 'replace'),'utf-8') return u_s.encode(ENCODING, 'replace') def log_handler(f, typ): print "Invoke method %s for %s packet" % (f,hex(typ)) def get_proto_major(p): return (p & 0xFFFF0000L) >> 16 def get_proto_minor(p): return (p & 0x0000FFFFL) def mail2jid(e_mail): return e_mail.replace('@', '%') + '@' + conf.name def jid2mail(jid): return jid.split('@')[0].replace('%', '@') def dec2bin(n): bStr = '' if n < 0: raise ValueError, "must be a positive integer" if n == 0: return '0' while n > 0: bStr = str(n % 2) + bStr n = n >> 1 return bStr def decode_auth_string(enc_str): try: s = base64.decodestring(enc_str) num = struct.unpack('I', s[:4])[0] name, txt = '','' if num>1: try: nlen = struct.unpack('I', s[4:8])[0] name = s[8:8+nlen] tlen = struct.unpack('I', s[8+nlen:12+nlen])[0] txt = s[12+nlen:12+nlen+tlen] if not name.strip(): name = '' if not txt.strip(): txt = '' except: pass name = win2str(name) txt = win2str(txt) except: name, txt = '','' return (name,txt) def encode_auth_string(name, text): name = str2win(name) text = str2win(text) num = struct.pack('I', 2) nlen = struct.pack('I', len(name)) tlen = struct.pack('I', len(text)) return base64.encodestring(num+nlen+name+tlen+text) class MoscowTimeZone(datetime.tzinfo): def __init__(self): self.HOUR = datetime.timedelta(hours=1) self.ZERO = datetime.timedelta(0) self.DSTSTART = datetime.datetime(1, 3, 25, 2) self.DSTEND = datetime.datetime(1, 10, 25, 3) def utcoffset(self, dt): return datetime.timedelta(hours=3) + self.dst(dt) def dst(self, dt): start = self.first_sunday_on_or_after(self.DSTSTART.replace(year=dt.year)) end = self.first_sunday_on_or_after(self.DSTEND.replace(year=dt.year)) if start <= dt.replace(tzinfo=None) < end: return self.HOUR else: return self.ZERO def first_sunday_on_or_after(self, dt): days_to_go = 6 - dt.weekday() if days_to_go: dt += datetime.timedelta(days_to_go) return dt def msk2utc(t): tz = MoscowTimeZone() T = t[:6]+(0,tz) d = datetime.datetime(*T) return d.utctimetuple() def socket_error(e): if len(e.args)>1: err_txt = e.args[1] else: err_txt = e.args[0] return err_txt def gettime(): T = {} if time.daylight: T['tz'] = time.tzname[1] else: T['tz'] = time.tzname[0] T['utc'] = time.strftime('%Y%m%dT%H:%M:%S', time.gmtime()) T['display'] = time.asctime() return T def uptime(T): t = int(T) days, s = (t/86400, t % 86400) hours, s = (s/3600, s % 3600) minutes, secs = (s/60, s % 60) return "%s days, %s hours %s minutes %s secs" % (days, hours, minutes, secs) def xep_202_time(): if time.daylight != 0: offset = time.altzone else: offset = time.timezone hours, reminder = divmod(abs(offset), 3600) mins, secs = divmod(reminder, 60) if offset >= 0: tzo = "%.2d:%.2d" % (hours, mins) else: tzo = "-%.2d:%.2d" % (hours, mins) utc = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) return (tzo, utc) def show2status(show): if show in [None, 'chat']: status = STATUS_ONLINE elif show in ['dnd','xa','away']: status = STATUS_AWAY else: status = STATUS_UNDETERMINATED return status def status2show(status): typ, show = None, None if status == STATUS_AWAY: show = 'away' elif status == STATUS_FLAG_INVISIBLE: show = None elif status != STATUS_ONLINE: typ = 'unavailable' return (typ,show) def unpack_rtf(s): res = [s, ()] try: decoded = base64.decodestring(s) unzipped = zlib.decompress(decoded) body = cStringIO.StringIO(unzipped) number = struct.unpack('I', body.read(4))[0] text = body.read(struct.unpack('I', body.read(4))[0]) color = struct.unpack('I', body.read( struct.unpack('I', body.read(4))[0] ) )[0] R = color & 0xFF G = (color & 0xFF00) >> 8 B = (color & 0xFF0000) >> 16 res = [text, (R,G,B)] except: pass return res def pack_rtf(s): enc = winrtf(s) io_s = cStringIO.StringIO() io_s.write(struct.pack('I', 2)) text = RTF_H+enc+RTF_T io_s.write(struct.pack('I',len(text))) io_s.write(text) io_s.write(struct.pack('I', 4)) io_s.write(struct.pack('I', 0x00ffffff)) io_s.seek(0) gzipped = zlib.compress(io_s.read()) return base64.encodestring(gzipped).replace('\n','') def get_proxy(proxy_str): host, port = proxy_str.split('http://')[1].split(':') return (host, int(port)) def encode_caps_ver(category, typ, features, algo="sha-1"): features.sort() h = "" s = category + '/' + typ + '<' for feature in features: s += feature + '<' if algo == "md5": h = hashlib.md5(s).digest() elif algo == "sha-1" or not algo: h = hashlib.sha1(s).digest() elif algo == "sha-224": h = hashlib.sha224(s).digest() elif algo == "sha-256": h = hashlib.sha256(s).digest() elif algo == "sha-384": h = hashlib.sha384(s).digest() elif algo == "sha-512": h = hashlib.sha512(s).digest() return base64.b64encode(h) def decode_caps_ver((ver, algo)): try: h = base64.b64decode(ver) if (algo == "md5" and len(h) == 16) or \ (algo == "sha-1" and len(h) == 20) or \ (algo == "sha-224" and len(h) == 28) or \ (algo == "sha-256" and len(h) == 32) or \ (algo == "sha-384" and len(h) == 48) or \ (algo == "sha-512" and len(h) == 64): return h else: return except: return SERVER_CAPS = encode_caps_ver('gateway', 'mrim', server_features, "sha-384") CLIENT_CAPS = encode_caps_ver('client', 'pc', client_features, "sha-384") NODE = "http://svn.xmpp.ru/repos/mrim" def add_caps_c(presence): presence.setTag('c', namespace=xmpp.NS_CAPS, attrs={'node':'none','hash':'sha-384','ver':CLIENT_CAPS}) def add_caps_s(presence): presence.setTag('c', namespace=xmpp.NS_CAPS, attrs={'node':NODE,'hash':'sha-384','ver':SERVER_CAPS})