home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2012 January / maximum-cd-2012-01.iso / DiscContents / digsby_setup.exe / lib / msn / p21 / MSNP21Conversation.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-10-05  |  18.8 KB  |  516 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. import sys
  5. import time
  6. import datetime
  7. import struct
  8. import logging
  9. import traceback
  10. import email
  11. import util.allow_once as once
  12. import util.callbacks as callbacks
  13. from util import callsback, RoundRobinProducer, strip_html, Timer
  14. from util.primitives.funcs import get
  15. from util.Events import event
  16. import common
  17. from util.observe import ObservableDict
  18. from common import Conversation, pref
  19. import msn
  20. import msn.AddressBook as MSNAB
  21. import msn.SOAP.services as SOAPServices
  22. from msn.P2P.P2PData2 import P2PTransport
  23. from msn import NSSBAdapter, oim
  24. import msn.MSNCommands as MSNC
  25. from msn.MSNCommands import MSNTextMessage
  26. log = logging.getLogger('msn.p21.conv')
  27.  
  28. class CircleNotReadyException(Exception):
  29.     pass
  30.  
  31.  
  32. class MSNP21Conversation(Conversation, P2PTransport):
  33.     events = P2PTransport.events | set(('send_p2p_msg',))
  34.     
  35.     def __init__(self, msn, to_invite = (), **k):
  36.         self.client = msn
  37.         self._to_invite = set(to_invite)
  38.         self._closed = False
  39.         self._waschat = len(self._to_invite) > 1
  40.         Conversation.__init__(self, msn)
  41.         self.protocol.register_conv(self)
  42.         log.info("Added %r to msn's conversation list", self)
  43.         if len(to_invite) >= 1:
  44.             self._chatbuddy = to_invite[0]
  45.             if len(to_invite) == 1:
  46.                 self._chat_target_name = to_invite[0]
  47.                 cinfo = self.protocol.get_contact_info(self._chat_target_name)
  48.                 if cinfo is None:
  49.                     self._chat_target_type = MSNAB.ClientType.to_int(MSNAB.ClientType.ChatMember)
  50.                 else:
  51.                     self._chat_target_type = cinfo.type
  52.             else:
  53.                 self._chat_target_name = None
  54.                 self._chat_target_type = MSNAB.ClientType.to_int(MSNAB.ClientType.ChatMember)
  55.         else:
  56.             self._chatbuddy = None
  57.         self.buddies = { }
  58.         self.typing_status = ObservableDict()
  59.         self._pending_invite_callbacks = { }
  60.         P2PTransport.__init__(self, msn)
  61.         self.room_list.append(self.self_buddy)
  62.         if self.ischat:
  63.             cb = self.client.circle_buddies[self._chatbuddy]
  64.             self.client.ns.JoinCircleConversation(self._chatbuddy)
  65.             for bname in cb.buddy_names:
  66.                 if bname.lower().startswith(str(cb.guid).lower()):
  67.                     continue
  68.                 
  69.                 self.buddy_join(bname)
  70.             
  71.         
  72.  
  73.     chat_room_name = None
  74.     
  75.     def connected(self):
  76.         if self.protocol.ns is not None:
  77.             pass
  78.         return self.protocol.ns.connected()
  79.  
  80.     
  81.     def Disconnect(self):
  82.         log.info('Disconnecting. unregistering %r from client (%r)', self, self.client)
  83.         self.client.unregister_conv(self)
  84.  
  85.     
  86.     def exit(self, force_close = False):
  87.         log.info('%r exiting', self)
  88.         self._closed = True
  89.         Conversation.exit(self)
  90.  
  91.     
  92.     def name(self):
  93.         names = self._clean_list()
  94.         count = len(names)
  95.         aliases = _[1]
  96.         if count == 2:
  97.             who = aliases[0]
  98.         elif count == 3:
  99.             who = '%s and %s' % tuple(sorted(aliases))
  100.         else:
  101.             who = '%d people' % (count - 1)
  102.         return who
  103.  
  104.     name = property(name)
  105.     
  106.     def chat_id(self):
  107.         if self._chat_target_name is None:
  108.             raise CircleNotReadyException()
  109.         self._chat_target_name is None
  110.         return '%s:%s' % (self._chat_target_type, self._chat_target_name)
  111.  
  112.     chat_id = property(chat_id)
  113.     
  114.     def ischat(self):
  115.         destination_type = int(self.chat_id.split(':', 1)[0])
  116.         return MSNAB.ClientType.from_int(destination_type) in (MSNAB.ClientType.ChatMember, MSNAB.ClientType.CircleMember)
  117.  
  118.     ischat = property(ischat)
  119.     
  120.     def buddy(self):
  121.         l = self._clean_list()
  122.         
  123.         try:
  124.             l.remove(self.self_buddy.name)
  125.         except ValueError:
  126.             pass
  127.  
  128.         if len(l) == 1:
  129.             answer = l[0]
  130.             if isinstance(answer, basestring):
  131.                 answer = self.protocol.get_buddy(answer)
  132.             
  133.             return answer
  134.         return self.protocol.get_buddy(self._chatbuddy)
  135.  
  136.     buddy = property(buddy)
  137.     
  138.     def _clean_list(self):
  139.         l = set((lambda .0: for x in .0:
  140. x.name)(self.room_list)) | set(self._to_invite)
  141.         circle = self.client.circle_buddies.get(self._chatbuddy, None)
  142.         if circle is not None:
  143.             l.update(circle.buddy_names)
  144.         
  145.         return list(l)
  146.  
  147.     
  148.     def self_buddy(self):
  149.         return self.protocol.self_buddy
  150.  
  151.     self_buddy = property(self_buddy)
  152.     
  153.     def _send_message(self, text, callback = None, **k):
  154.         pass
  155.  
  156.     _send_message = callbacks.callsback(_send_message)
  157.     
  158.     def invite(self, buddy, callback = None):
  159.         name = getattr(buddy, 'name', buddy)
  160.         self._pending_invite_callbacks[name] = callback
  161.         
  162.         def do_invites(circle_name):
  163.             circle = self.protocol.circle_buddies[circle_name]
  164.             old_name = self._chatbuddy
  165.             self._chatbuddy = circle_name
  166.             self._chat_target_name = circle_name
  167.             self._chat_target_type = None if getattr(circle, 'circle', None) is not None else MSNAB.IMAddressInfoType.TemporaryGroup
  168.             if old_name != self._chatbuddy:
  169.                 self.protocol.ns.invite_to_circle(circle_name, old_name)
  170.             
  171.             self.protocol.ns.invite_to_circle(circle_name, name)
  172.  
  173.         if self._chat_target_type not in (MSNAB.IMAddressInfoType.Circle, MSNAB.IMAddressInfoType.TemporaryGroup):
  174.             self.protocol.ns.make_temp_circle(success = do_invites, error = callback.error)
  175.         else:
  176.             do_invites(self._chatbuddy)
  177.  
  178.     invite = callbacks.callsback(invite)
  179.     
  180.     def on_message_recv(self, name, msg, sms = False):
  181.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  182.         self.typing_status[buddy] = None
  183.         if hasattr(msg, 'html'):
  184.             message = msg.html().replace('\n', '<br />')
  185.             content_type = 'text/html'
  186.         else:
  187.             message = msg
  188.             content_type = 'text/plain'
  189.         did_receive = self.received_message(buddy, message, sms = sms, content_type = content_type)
  190.         if name != self.self_buddy.name and did_receive:
  191.             Conversation.incoming_message(self)
  192.         
  193.  
  194.     
  195.     def on_action_recv(self, name, action_type, action_text):
  196.         if action_type == 'custom':
  197.             text = action_text
  198.         else:
  199.             text = dict(wink = _('winked at you!'), nudge = _('nudged you!')).get(action_type, None)
  200.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  201.         if text is not None:
  202.             message = '%s %s' % (buddy.alias, text)
  203.         
  204.         self.system_message(message)
  205.  
  206.     
  207.     def on_typing_notification(self, name, typing):
  208.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  209.         self.typing_status[buddy] = None if typing else None
  210.         None(log.info, '%s is %styping', name if typing else 'not ')
  211.  
  212.     
  213.     def buddy_join(self, name):
  214.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  215.         if buddy is not self.self_buddy and self.self_buddy not in self.room_list:
  216.             self.on_buddy_join(self.self_buddy.name)
  217.         
  218.         if buddy not in self.room_list:
  219.             self.room_list.append(buddy)
  220.         
  221.         if not self._chatbuddy:
  222.             self._chatbuddy = name
  223.         
  224.         self.event('contacts_changed')
  225.         log.info('Got buddy join event (%s). self.ischat = %r', name, self.ischat)
  226.         self.notify('ischat')
  227.         super(MSNP21Conversation, self).buddy_join(buddy)
  228.         self.invite_success(name)
  229.  
  230.     
  231.     def invite_success(self, name):
  232.         cb = self._pending_invite_callbacks.pop(name, None)
  233.         if cb is not None:
  234.             cb.success()
  235.         
  236.  
  237.     
  238.     def invite_failure(self, name):
  239.         cb = self._pending_invite_callbacks.pop(name, None)
  240.         if cb is not None:
  241.             cb.error()
  242.         
  243.  
  244.     
  245.     def on_buddy_leave(self, name, notify = True):
  246.         self._type_override = None
  247.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  248.         
  249.         try:
  250.             self.room_list.remove(buddy)
  251.         except ValueError:
  252.             log.info("Buddy %r wasn't in room but left anyway (?)", name)
  253.  
  254.         in_room = set(self._clean_list()) - self._to_invite
  255.         in_room.discard(self.self_buddy.name)
  256.         self.typing_status.pop(buddy, None)
  257.         self.event('contacts_changed')
  258.         super(MSNP21Conversation, self).buddy_leave(buddy)
  259.         self.notify('ischat')
  260.  
  261.     
  262.     def fed_message(self, msg):
  263.         self.recv_msg(msg)
  264.  
  265.     
  266.     def recv_msg(self, msg):
  267.         if msg.name not in self.room_list:
  268.             if not self.ischat:
  269.                 self.buddy_join(msg.name)
  270.             
  271.         
  272.         
  273.         try:
  274.             getattr(self, 'recv_msg_%s' % msg.type, self.recv_msg_unknown)(msg)
  275.         except Exception:
  276.             e = None
  277.             import traceback
  278.             traceback.print_exc()
  279.             log.error('Exception handling MSG: %r, msg = %r', e, msg)
  280.  
  281.  
  282.     
  283.     def recv_msg_control_typing(self, msg, typing = True):
  284.         name = msg.name
  285.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  286.         self.typing_status[buddy] = None if typing else None
  287.         None(log.info, '%s is %styping', name if typing else 'not ')
  288.  
  289.     
  290.     def recv_msg_unknown(self, msg):
  291.         log.info('Got an unknown message: %r (%r)', msg.type, str(msg))
  292.  
  293.     
  294.     def recv_msg_signal_forceabchsync(self, msg):
  295.         if msg.name == self.self_buddy.name:
  296.             payload = msg.get_payload()
  297.             log.info('Got addressbook sync signal from a different endpoint: %r', payload)
  298.             doc = etree.fromstring(payload)
  299.             self.protocol.ns._sync_addressbook(abid = doc.find('.//Service').attrib['id'])
  300.         
  301.  
  302.     
  303.     def recv_msg_wink(self, msg):
  304.         self.on_action_recv(msg.name, 'wink', None)
  305.  
  306.     
  307.     def recv_msg_nudge(self, msg):
  308.         self.on_action_recv(msg.name, 'nudge', None)
  309.  
  310.     
  311.     def recv_msg_text(self, msg):
  312.         name = msg.name
  313.         textmsg = MSNTextMessage.from_net(msg.payload)
  314.         buddy = self.buddies[name] = self.protocol.get_buddy(name)
  315.         self.typing_status[buddy] = None
  316.         if hasattr(textmsg, 'html'):
  317.             message = textmsg.html().replace('\n', '<br />')
  318.             content_type = 'text/html'
  319.         else:
  320.             message = textmsg
  321.             content_type = 'text/plain'
  322.         service_channel = offline = msg.payload.get('Service-Channel', None)
  323.         sms = service_channel == 'IM/Mobile'
  324.         offline = service_channel == 'IM/Offline'
  325.         timestamp_str = msg.payload.get('Original-Arrival-Time', None)
  326.         if timestamp_str is None:
  327.             timestamp = None
  328.         else:
  329.             timestamp = datetime.datetime.fromtimestamp(SOAPServices.strptime_highres(timestamp_str))
  330.         did_receive = self.received_message(buddy, message, sms = sms, content_type = content_type, offline = offline, timestamp = timestamp)
  331.         if name != self.self_buddy.name and did_receive:
  332.             Conversation.incoming_message(self)
  333.         
  334.  
  335.     
  336.     def recv_msg_data(self, msg):
  337.         return self.recv_msg_signal_p2p(msg)
  338.  
  339.     
  340.     def recv_msg_signal_p2p(self, msg):
  341.         from_header = msg.payload.get('From')
  342.         from_name = from_header.split(':', 1)[-1].split(';epid=', 1)[0]
  343.         return None
  344.         self.on_p2p_recv(from_name, msg.payload.get_payload())
  345.  
  346.     
  347.     def send(self, *a, **k):
  348.         return self.protocol.ns.socket.send(*a, **k)
  349.  
  350.     
  351.     def message_header(self, first = None, second = None):
  352.         lines = [
  353.             'Routing: 1.0',
  354.             'To: %s;path=IM' % self.chat_id,
  355.             'From: 1:%s;epid={%s}' % (self.protocol.self_buddy.name, str(self.protocol.get_machine_guid()).lower())]
  356.         if first is not None:
  357.             lines.extend(first)
  358.         
  359.         lines.extend([
  360.             '',
  361.             'Reliability: 1.0'])
  362.         if second is not None:
  363.             lines.extend(first)
  364.         
  365.         lines.extend([
  366.             '',
  367.             ''])
  368.         return '\r\n'.join(lines)
  369.  
  370.     
  371.     def send_typing_status(self, status):
  372.         if status != 'typing':
  373.             return None
  374.         if not self.buddy.online:
  375.             return None
  376.         lines = [
  377.             'Messaging: 2.0',
  378.             'Message-Type: Control/Typing',
  379.             'Content-Length: 0',
  380.             '',
  381.             '']
  382.         data = '\r\n'.join(lines)
  383.         self.send(MSNC.SDG(payload = self.message_header() + data), trid = True, callback = sentinel)
  384.  
  385.     
  386.     def send_text_message(self, body, callback = None):
  387.         log.info('message body: %r, %r', type(body), body)
  388.         body_parts = body.split('\r\n')
  389.         body_parts[0] = 'Content-Length: %d' % len(body_parts[-1])
  390.         lines = [
  391.             'Messaging: 2.0',
  392.             'Message-Type: Text',
  393.             'IM-Display-Name: %s' % self.protocol.self_buddy.remote_alias.encode('utf8')]
  394.         lines.extend(body_parts)
  395.         data = '\r\n'.join(lines)
  396.         header_args = []
  397.         if not self.buddy.online:
  398.             header_args.append('Service-Channel: IM/Offline')
  399.         elif self.buddy.mobile and self.buddy.sms:
  400.             header_args.append('Service-Channel: IM/Mobile')
  401.         
  402.         self.send(MSNC.SDG(payload = self.message_header(header_args) + data), trid = True, callback = callback)
  403.  
  404.     send_text_message = callbacks.callsback(send_text_message)
  405.     
  406.     def _send_message(self, msg, callback = None, **k):
  407.         cl = set(self._clean_list())
  408.         cl -= set([
  409.             self.self_buddy.name])
  410.         if not cl:
  411.             callback.error()
  412.             self.system_message("You can't message yourself using MSN.")
  413.             return None
  414.         body = msg.format_as('msn')
  415.         
  416.         def check_nak(sck, emsg):
  417.             log.error('Error sending message: %r', emsg)
  418.             cmd = getattr(emsg, 'cmd', None)
  419.             if cmd == 'NAK':
  420.                 self._send_message_im(msg, callback = callback)
  421.             elif cmd == '217':
  422.                 self.system_message('Offline messaging not yet supported')
  423.             else:
  424.                 callback.error(emsg)
  425.  
  426.         self.send_text_message(body, error = check_nak)
  427.         callback.success()
  428.  
  429.     _send_message = callbacks.callsback(_send_message)
  430.     
  431.     def on_p2p_recv(self, name, data):
  432.         log.info('Got p2p data: %r', data)
  433.         self.event('recv_data', self, name, data)
  434.  
  435.     
  436.     def p2p_rating(self):
  437.         return 0
  438.  
  439.     p2p_rating = property(p2p_rating)
  440.     
  441.     def p2p_max_msg_size(self):
  442.         return sys.maxint
  443.  
  444.     p2p_max_msg_size = property(p2p_max_msg_size)
  445.     
  446.     def p2p_overhead(self):
  447.         return 40
  448.  
  449.     p2p_overhead = property(p2p_overhead)
  450.     
  451.     def p2p_peers(self):
  452.         if self.ischat:
  453.             return []
  454.         return [
  455.             self.buddy.name]
  456.  
  457.     p2p_peers = property(p2p_peers)
  458.     
  459.     def push_with_producer(self, prod, callback = None):
  460.         data = prod.more()
  461.         if data is not None:
  462.             self.p2p_send(data, callback = callback)
  463.         
  464.  
  465.     push_with_producer = callbacks.callsback(push_with_producer)
  466.     
  467.     def p2p_send(self, data, callback = None):
  468.         from_id = '1:%s;epid={%s}' % (self.self_buddy.name, str(self.protocol.get_machine_guid()).lower())
  469.         body = MSNP2PMessage(self.chat_id, from_id, data)
  470.         log.info('P2Psend: %r', str(body))
  471.         cmd = msn.MSNCommands.SDG(payload = str(body))
  472.         self.send(cmd, trid = True, callback = callback)
  473.         self.event('send_p2p_msg', body)
  474.  
  475.     p2p_send = callbacks.callsback(p2p_send)
  476.     
  477.     def build_data(self, header, body, footer):
  478.         return header + body + footer
  479.  
  480.  
  481.  
  482. class MSNP2PMessage(object):
  483.     
  484.     def __init__(self, to_id, from_id, body, offset_size = 1254):
  485.         self.to_id = to_id
  486.         self.from_id = from_id
  487.         self.body = body
  488.         self.offset_size = offset_size
  489.  
  490.     
  491.     def __str__(self):
  492.         sz = 0
  493.         offsets = []
  494.         while sz < len(self.body):
  495.             offsets.append(str(sz))
  496.             sz += self.offset_size
  497.         return '\r\n'.join([
  498.             'Routing: 1.0',
  499.             'To: %(to_id)s',
  500.             'From: %(from_id)s',
  501.             'Options: 0',
  502.             'Service-Channel: PE',
  503.             '',
  504.             'Reliability: 1.0',
  505.             '',
  506.             'Messaging: 2.0',
  507.             'Message-Type: Data',
  508.             'Content-Transfer-Encoding: binary',
  509.             'Content-Type: application/x-msnmsgrp2p',
  510.             'Bridging-Offsets: %s' % ','.join(offsets),
  511.             'Content-Length: %d' % len(self.body),
  512.             '',
  513.             '%(body)s']) % vars(self)
  514.  
  515.  
  516.