home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 February / maximum-cd-2011-02.iso / DiscContents / digsby_setup85.exe / lib / plugins / msim / MSIMProtocol.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-11-24  |  34.5 KB  |  930 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. NETWORK_FLAG = 'NETWORK_FLAG'
  5. import sys
  6. import traceback
  7. import collections
  8. import wx
  9. import logging
  10. import urllib2
  11. import cookielib
  12. import time
  13. import simplejson as json
  14. import lxml.html as html
  15. log = logging.getLogger('msim.protocol')
  16. from base64 import b64encode
  17. import common
  18. import common.asynchttp as asynchttp
  19. import contacts
  20. import util
  21. import util.net as net
  22. import util.Events as events
  23. import util.httptools as httptools
  24. import util.callbacks as callbacks
  25. import util.htmlutils as htmlutils
  26. import util.observe as observe
  27. from util import myips, try_this, threaded
  28. from util.primitives.funcs import get, Delegate
  29. from util.cacheable import urlcacheopen
  30. from MSIMUtil import msmsg, crypt, roflcopter, pipe_list, pipe_dict, msdict
  31. from MSIMApi import MSIM_Api
  32. import MSIMUtil as msimutil
  33. import MSIMContacts as msimcontacts
  34. import MSIMConversation
  35. from MSIMSocket import myspace_socket
  36. from common import pref
  37.  
  38. def needs_user_id(f):
  39.     
  40.     def _wrapper(self, buddy_name_or_email, *a, **k):
  41.         log.info('doing user search for %r', buddy_name_or_email)
  42.         if util.is_email(buddy_name_or_email):
  43.             email = buddy_name_or_email
  44.             name = None
  45.         else:
  46.             name = buddy_name_or_email
  47.             email = None
  48.         
  49.         def success(sent, recvd):
  50.             log.info('got success for usersearch! %r, %r', sent, recvd)
  51.             body = recvd.get('body', { })
  52.             buddy_id = body.get('UserID', body.get('ContactID'))
  53.             if buddy_id is None:
  54.                 log.error("buddy_id for %r not found! probably doesn't exist", buddy_name_or_email)
  55.             
  56.             f(self, buddy_id, *a, **k)
  57.  
  58.         self.api.user_search(username = name, email = email, success = success)
  59.  
  60.     return _wrapper
  61.  
  62.  
  63. class MyspaceIM(common.protocol):
  64.     name = service = protocol = 'msim'
  65.     
  66.     def __init__(self, username, password, user, server = None, login_as = 'online', **options):
  67.         common.protocol.__init__(self, username, password, user)
  68.         self.api = None
  69.         self.challenges = []
  70.         self.root_group = contacts.Group('__msimroot__', self, '__msimroot__')
  71.         self.buddies = observe.ObservableDict()
  72.         self.conversations = { }
  73.         self.server = server
  74.         self.groups = { }
  75.         self.block_list = []
  76.         self.has_added_friends = options.get('has_added_friends', False)
  77.         self._self_buddy = None
  78.  
  79.     
  80.     def caps(self):
  81.         return [
  82.             common.caps.IM,
  83.             common.caps.INFO,
  84.             common.caps.VIDEO]
  85.  
  86.     caps = property(caps)
  87.     
  88.     def add_group(self, name, callback = None):
  89.         if self.groups.values():
  90.             new_position = max((lambda .0: for None in .0:
  91. x = None(util.try_this,)((lambda : int(x.Position)), 0)
  92.                 
  93. )(self.groups.values())) + 1
  94.         else:
  95.             new_position = 0
  96.         
  97.         def success(sent, recvd):
  98.             
  99.             def new_group_listener(g_info):
  100.                 if g_info.get('GroupName') == name:
  101.                     callback.success(self.get_group(name))
  102.                     self.api.unbind('got_group', new_group_listener)
  103.                 
  104.  
  105.             self.api.bind('got_group', new_group_listener)
  106.             self.request_group_list()
  107.  
  108.         self.api.set_group_details(id = None, name = name.encode('utf8'), flag = 0, position = new_position, success = success, error = callback.error)
  109.  
  110.     add_group = callbacks.callsback(add_group)
  111.     
  112.     def remove_group(self, group_id, callback = None):
  113.         
  114.         def success(*a, **k):
  115.             self.request_group_list()
  116.             callback.success()
  117.  
  118.         self.api.delete_group(group_id, success = success, error = callback.error)
  119.  
  120.     remove_group = callbacks.callsback(remove_group)
  121.     
  122.     def remove_buddy(self, buddy_id, group_id = None):
  123.         self.api.deletebuddy(buddy_id)
  124.         self.api.delete_contact_info(buddy_id)
  125.         self.edit_privacy_list(remove_from_block = [
  126.             buddy_id], remove_from_allow = [
  127.             buddy_id])
  128.         self.buddy_deleted(buddy_id)
  129.  
  130.     
  131.     def buddy_deleted(self, id, sort = True):
  132.         buddy = self.get_buddy(id)
  133.         group = self.get_group(buddy.GroupID)
  134.         if not group:
  135.             for group in self.groups.values():
  136.                 if buddy in group:
  137.                     break
  138.                     continue
  139.             
  140.         
  141.         if group is not None and buddy in group:
  142.             log.info('removing %r from %r', buddy, group)
  143.             while buddy in group:
  144.                 group.remove(buddy)
  145.             if sort:
  146.                 group.sort(key = (lambda b: b.Position))
  147.                 group.notify()
  148.                 self.root_group.notify()
  149.             
  150.         elif buddy in self.root_group:
  151.             while buddy in self.root_group:
  152.                 self.root_group.remove(buddy)
  153.             self.root_group.notify()
  154.         else:
  155.             log.info('No group found for %r or buddy %r not in group', buddy.GroupName, buddy)
  156.  
  157.     
  158.     def get_group(self, group_id):
  159.         group = self.groups.get(group_id)
  160.         if group is None:
  161.             group = self.get_group_by_name(group_id)
  162.         
  163.         return group
  164.  
  165.     
  166.     def get_group_by_name(self, name):
  167.         for group in self.groups.values():
  168.             if group.name == name:
  169.                 return group
  170.         
  171.  
  172.     
  173.     def group_for(self, buddy):
  174.         return buddy.GroupName
  175.  
  176.     
  177.     def _get_self_buddy(self):
  178.         if self._self_buddy is None:
  179.             self._self_buddy = self.get_buddy(self.api.userid)
  180.         
  181.         return self._self_buddy
  182.  
  183.     
  184.     def _set_self_buddy(self, _val):
  185.         pass
  186.  
  187.     self_buddy = property(_get_self_buddy, _set_self_buddy)
  188.     
  189.     def get_groups(self):
  190.         return _[1]
  191.  
  192.     
  193.     def get_buddy(self, buddy_id):
  194.         if isinstance(buddy_id, tuple):
  195.             buddy_id = buddy_id[0]
  196.         
  197.         if not isinstance(buddy_id, str):
  198.             buddy_id = str(buddy_id)
  199.         
  200.         return self.buddies.get(buddy_id)
  201.  
  202.     
  203.     def has_buddy_on_list(self, buddy):
  204.         return self.get_buddy(buddy.name) is not None
  205.  
  206.     
  207.     def connection_closed(self, socket = None):
  208.         if self.state == self.Statuses.OFFLINE:
  209.             log.info('socket closed normally')
  210.             reason = self.Reasons.NONE
  211.         else:
  212.             log.info('socket closed unexpectedly (-> CONN_LOST)')
  213.             reason = self.Reasons.CONN_LOST
  214.         self.Disconnect(reason)
  215.         self.on_connect = Delegate()
  216.  
  217.     
  218.     def connection_failed(self):
  219.         log.error('socket error. disconnecting with reason CONN_LOST')
  220.         self.Disconnect(self.Reasons.CONN_LOST)
  221.         self.on_connect = Delegate()
  222.  
  223.     
  224.     def _bind_events(self, api = None):
  225.         if api is None:
  226.             api = self.api
  227.         
  228.         if api is None:
  229.             return None
  230.         api.bind('connect_failed', self.connection_failed)
  231.         api.bind('connection_closed', self.connection_closed)
  232.         api.bind('login_challenge', self.on_login_challenge)
  233.         api.bind('login_success', self.session_start)
  234.         api.bind('on_error', self.on_api_error)
  235.         api.bind('got_buddy', self._got_buddy)
  236.         api.bind('got_buddies', self._got_buddies)
  237.         api.bind('got_group', self._got_group)
  238.         api.bind('got_groups', self._got_groups)
  239.         api.bind('got_contact_info', self._got_contact_info)
  240.         api.bind('got_group_info', self._got_group_info)
  241.         api.bind('got_webchallenge_info', self._got_webchallenges)
  242.         api.bind('got_im', self._got_im)
  243.         api.bind('got_zap', self._got_zap)
  244.         api.bind('got_typing', self._got_typing)
  245.         api.bind('got_groupmsg', self._got_groupmsg)
  246.         api.bind('got_buddy_presence', self.on_buddy_presence)
  247.  
  248.     
  249.     def _unbind_events(self, api = None):
  250.         if api is None:
  251.             api = self.api
  252.         
  253.         if api is None:
  254.             return None
  255.         api.unbind('connect_failed', self.connection_failed)
  256.         api.unbind('connection_closed', self.connection_closed)
  257.         api.unbind('login_challenge', self.on_login_challenge)
  258.         api.unbind('login_success', self.session_start)
  259.         api.unbind('on_error', self.on_api_error)
  260.         api.unbind('got_buddy', self._got_buddy)
  261.         api.unbind('got_buddies', self._got_buddies)
  262.         api.unbind('got_group', self._got_group)
  263.         api.unbind('got_groups', self._got_groups)
  264.         api.unbind('got_contact_info', self._got_contact_info)
  265.         api.unbind('got_group_info', self._got_group_info)
  266.         api.unbind('got_im', self._got_im)
  267.         api.unbind('got_zap', self._got_zap)
  268.         api.unbind('got_typing', self._got_typing)
  269.         api.unbind('got_groupmsg', self._got_groupmsg)
  270.         api.unbind('got_buddy_presence', self.on_buddy_presence)
  271.  
  272.     
  273.     def _got_contact_info(self, id, info, info_type):
  274.         self._got_buddy(id, info)
  275.         b = self.get_buddy(id)
  276.         b.notify()
  277.         log.info('got %r info for buddy %r. info = %r', info_type, b, info)
  278.         self._process_queued_ims(id)
  279.         if 'Position' in info:
  280.             group = self.get_group_by_name(info.get('GroupName'))
  281.             if group is not None:
  282.                 group.sort(key = (lambda b: b.Position))
  283.                 group.notify()
  284.                 self.root_group.sort(key = (lambda b: b.Position))
  285.                 self.root_group.notify()
  286.             
  287.         
  288.  
  289.     
  290.     def _got_group_info(self, gid, info):
  291.         g = self.get_group(gid)
  292.         g.update_info(info)
  293.         g.notify()
  294.         self.root_group.sort(key = (lambda b: b.Position))
  295.         self.root_group.notify()
  296.  
  297.     
  298.     def _update_pending_buddy_properties(self, id, props, notify):
  299.         self._pending_props[str(id)].update(props)
  300.         self._pending_notify[str(id)] |= notify
  301.  
  302.     
  303.     def _apply_pending_buddy_properties(self, id):
  304.         props = self._pending_props.pop(str(id), { })
  305.         if props:
  306.             log.info('applying pending properties for %r: %r', id, props)
  307.             notify = self._pending_notify.pop(str(id), False)
  308.             self._update_buddy_properties(id, props, notify)
  309.         
  310.  
  311.     
  312.     def _update_buddy_properties(self, id, props, notify = False):
  313.         buddy = self.get_buddy(id)
  314.         if buddy is None:
  315.             self._update_pending_buddy_properties(id, props, notify)
  316.             log.info('applying properties to %r later. props = %r', id, props)
  317.             return None
  318.         for key, val in props.items():
  319.             setattr(buddy, key, val)
  320.         
  321.         if notify:
  322.             for key, val in props.items():
  323.                 buddy.notify(key)
  324.             
  325.         
  326.  
  327.     
  328.     def on_buddy_presence(self, id, status, status_message):
  329.         should_notify = True
  330.         if not status_message:
  331.             pass
  332.         self._update_buddy_properties(id, {
  333.             'status': status,
  334.             'status_message': None }, notify = should_notify)
  335.  
  336.     
  337.     def Connect(self, *a, **k):
  338.         if self.state == self.Statuses.OFFLINE or self.api is None:
  339.             self._queued_ims = collections.defaultdict(list)
  340.             self._pending_props = collections.defaultdict(dict)
  341.             self._pending_notify = collections.defaultdict(bool)
  342.             del self.challenges[:]
  343.             self.change_reason(self.Reasons.NONE)
  344.             self.change_state(self.Statuses.CONNECTING)
  345.             log.debug('connecting myspace')
  346.             self._init_api()
  347.             self.api.connect(self.server)
  348.             return None
  349.         log.critical('Not connecting. state=%r, reason=%r', self.state, self.offline_reason)
  350.  
  351.     Connect = common.action((lambda self: if self.state == self.Statuses.OFFLINE:
  352. True))(Connect)
  353.     
  354.     def _init_api(self):
  355.         api = MSIM_Api()
  356.         self._bind_events(api)
  357.         self.api = api
  358.  
  359.     
  360.     def _send_logout(self):
  361.         if self.api is not None:
  362.             self.api.logout()
  363.         
  364.  
  365.     
  366.     def Disconnect(self, reason = None):
  367.         log.info('Disconnecting. state=%r, reason=%r', self.state, self.offline_reason)
  368.         if self.state != self.Statuses.OFFLINE:
  369.             self._unregister_buddies()
  370.             self.groups.clear()
  371.             self.root_group[:] = []
  372.             self.challenges[:] = []
  373.             
  374.             try:
  375.                 del self.sesskey
  376.             except AttributeError:
  377.                 pass
  378.  
  379.             self.set_offline(reason)
  380.             self._send_logout()
  381.             if self.api is not None:
  382.                 api = self.api
  383.                 self.api = None
  384.                 self._unbind_events(api)
  385.                 api.disconnect()
  386.             
  387.             common.protocol.Disconnect(self)
  388.         
  389.  
  390.     
  391.     def on_api_error(self, reason):
  392.         real_reason = {
  393.             'connection_lost': self.Reasons.CONN_LOST,
  394.             'session_expired': self.Reasons.CONN_LOST,
  395.             'auth_error': self.Reasons.BAD_PASSWORD,
  396.             'other_user': self.Reasons.OTHER_USER }.get(reason)
  397.         self.Disconnect(real_reason)
  398.  
  399.     
  400.     def on_login_challenge(self, nonce):
  401.         self.change_state(self.Statuses.AUTHENTICATING)
  402.         self.api.send_login_response(self.username, self.password, nonce)
  403.  
  404.     
  405.     def session_start(self):
  406.         log.info('session started')
  407.         self.change_state(self.Statuses.LOADING_CONTACT_LIST)
  408.         self.request_self_buddy_info()
  409.         self.request_group_list()
  410.  
  411.     
  412.     def request_group_list(self, callback = None):
  413.         self.api.request_group_list(callback = callback)
  414.  
  415.     request_group_list = callbacks.callsback(request_group_list)
  416.     
  417.     def request_contact_list(self):
  418.         self.api.request_contact_list()
  419.  
  420.     
  421.     def _got_webchallenges(self, challenges):
  422.         self.challenges.extend((lambda .0: for x in .0:
  423. Challenge(**x))(challenges))
  424.  
  425.     
  426.     def _got_group(self, g_info):
  427.         group = self.get_group_by_name(g_info.get('GroupName'))
  428.         if group is None:
  429.             group = msimcontacts.MSIM_Group(g_info, self)
  430.             self.groups[group.id] = group
  431.         
  432.         if group not in self.root_group:
  433.             self.root_group.append(group)
  434.         
  435.  
  436.     
  437.     def _got_groups(self, all_groups):
  438.         group_ids = set((lambda .0: for g in .0:
  439. g['GroupID'])(all_groups))
  440.         log.info('Got groups!')
  441.         for group_id in self.groups.keys():
  442.             if group_id not in group_ids:
  443.                 old_group = self.groups.pop(group_id)
  444.                 if old_group in self.root_group:
  445.                     self.root_group.remove(old_group)
  446.                 
  447.             old_group in self.root_group
  448.         
  449.         self.root_group.sort(key = (lambda b: b.Position))
  450.         self.root_group.notify()
  451.         self.request_contact_list()
  452.  
  453.     
  454.     def _got_buddy(self, id, info):
  455.         buddy = self.get_buddy(id)
  456.         if buddy is None:
  457.             buddy = msimcontacts.MSIM_Buddy(info, self)
  458.             self.buddies[id] = buddy
  459.         else:
  460.             buddy.update_info(info)
  461.         self.buddy_added(id)
  462.         self._apply_pending_buddy_properties(id)
  463.  
  464.     
  465.     def buddy_added(self, id):
  466.         buddy = self.get_buddy(id)
  467.         if buddy.visible:
  468.             group = self.get_group_by_name(buddy.GroupName)
  469.             if group is None:
  470.                 group = self.root_group
  471.             
  472.             if buddy not in group:
  473.                 group.append(buddy)
  474.             
  475.             for g in self.groups.values():
  476.                 if g is not group:
  477.                     while buddy in g:
  478.                         g.remove(buddy)
  479.                     continue
  480.             
  481.         
  482.  
  483.     
  484.     def _got_buddies(self, all_buddies):
  485.         buddy_ids = set((lambda .0: for b in .0:
  486. b.get('ContactID', b.get('UserID')))(all_buddies))
  487.         for buddy_id in self.buddies.keys():
  488.             buddy = self.get_buddy(buddy_id)
  489.             if not buddy.visible and buddy_id in buddy_ids:
  490.                 self.buddy_deleted(buddy_id, sort = False)
  491.                 continue
  492.         
  493.         for group in list(self.groups.values()):
  494.             group.sort(key = (lambda b: b.Position))
  495.             group.notify()
  496.         
  497.         self.root_group.notify()
  498.         self._on_login()
  499.  
  500.     
  501.     def convo_for(self, buddy):
  502.         buddy_id = getattr(buddy, 'id', buddy)
  503.         
  504.         try:
  505.             return self.conversations[buddy_id]
  506.         except KeyError:
  507.             c = MSIMConversation.MSIMConversation(self, buddy_id)
  508.             self.conversations[buddy_id] = c
  509.             return c
  510.  
  511.  
  512.     chat_with = convo_for
  513.     
  514.     def _got_im(self, buddy_id, message):
  515.         log.info('incoming IM from %r: %r', buddy_id, message)
  516.         if not isinstance(buddy_id, tuple):
  517.             queue_id = buddy_id = str(buddy_id)
  518.             buddy = self.get_buddy(buddy_id)
  519.         else:
  520.             buddy = self.get_buddy(buddy_id[-1])
  521.             buddy_id = buddy_id[:2]
  522.         if buddy is None or buddy.alias == buddy_id:
  523.             self._queue_im(queue_id, message)
  524.             self.request_buddy_info(buddy_id)
  525.         else:
  526.             c = self.convo_for(buddy_id)
  527.             c.received_message(buddy, message)
  528.  
  529.     
  530.     def _queue_im(self, buddy_id, message):
  531.         self._queued_ims[buddy_id].append(message)
  532.  
  533.     
  534.     def _process_queued_ims(self, who):
  535.         ims = self._queued_ims.pop(who, [])
  536.         for im in ims:
  537.             self._got_im(who, im)
  538.         
  539.  
  540.     
  541.     def _got_zap(self, buddy_id, zaptxt):
  542.         buddy = self.get_buddy(buddy_id)
  543.         c = self.convo_for(buddy)
  544.         c.received_zap(buddy, zaptxt)
  545.  
  546.     
  547.     def _got_typing(self, buddy_id, is_typing):
  548.         buddy = self.get_buddy(buddy_id)
  549.         c = self.convo_for(buddy)
  550.         c.received_typing(buddy, is_typing)
  551.  
  552.     
  553.     def _got_groupmsg(self, source_id, group_id, actor_id, msg_text):
  554.         log.info('incoming group IM from (%r, %r, %r): %r', source_id, group_id, actor_id, msg_text)
  555.         c = self.convo_for(source_id)
  556.         c.received_group_message(group_id, actor_id, msg_text)
  557.  
  558.     
  559.     def user_search(self, username = None, email = None):
  560.         self.api.user_search(username, email)
  561.  
  562.     
  563.     def send_typing(self, who, typing):
  564.         self.api.send_typing(who, typing)
  565.  
  566.     
  567.     def send_message(self, buddy, message, callback = None, **kwds):
  568.         log.info_s('Sending message to %r. message = %r, format = %r, kwds = %r', buddy, message, format, kwds)
  569.         self.api.send_im(buddy.id, message, callback = callback)
  570.  
  571.     send_message = callbacks.callsback(send_message)
  572.     
  573.     def request_self_buddy_info(self):
  574.         self.api.request_self_im_info()
  575.         self.api.request_self_social_info()
  576.  
  577.     
  578.     def request_buddy_info(self, userid):
  579.         
  580.         def _do_request():
  581.             self.api.request_contact_general_info(userid)
  582.             self.api.request_contact_im_info(userid)
  583.             self.api.request_contact_social_info(userid)
  584.  
  585.         _do_request = (None, common.netcall)(_do_request)
  586.  
  587.     
  588.     def _on_login(self):
  589.         self.change_state(self.Statuses.ONLINE)
  590.         if not self.has_added_friends:
  591.             acct = common.profile.find_account(self.username, self.protocol)
  592.             if acct is not None:
  593.                 self.has_added_friends = acct.has_added_friends = True
  594.                 common.profile.update_account(acct)
  595.             
  596.             import wx
  597.             wx.CallAfter(self.ask_add_buddies)
  598.         
  599.  
  600.     
  601.     def ask_add_buddies(self):
  602.         import msim.myspacegui.prompts as prompts
  603.         prompts.AddBuddiesPrompt(success = self.autoadd_buddies)
  604.  
  605.     
  606.     def autoadd_buddies(self, which):
  607.         if which == 'cancel':
  608.             return None
  609.         if which == 'all':
  610.             self.api.add_all_friends(GroupName = 'IM Friends')
  611.         elif which == 'top':
  612.             self.api.add_top_friends(GroupName = 'IM Friends')
  613.         
  614.  
  615.     
  616.     def request_challenges(self):
  617.         self.api.request_webchlg()
  618.  
  619.     
  620.     def set_buddy_icon(self, icondata):
  621.         pass
  622.  
  623.     
  624.     def on_login(self):
  625.         self.change_state(self.Statuses.ONLINE)
  626.  
  627.     
  628.     def add_buddy(self, buddy_id, group_id, service = None, reason = u''):
  629.         self.api.addbuddy(buddy_id, reason.encode('utf8'))
  630.         self.edit_privacy_list(remove_from_block = [
  631.             buddy_id], add_to_allow = [
  632.             buddy_id])
  633.         buddy = self.get_buddy(buddy_id)
  634.         group = self.get_group(group_id)
  635.         infodict = buddy.get_infodict()
  636.         infodict.update(Visibility = '1', GroupName = group.GroupName, Position = '1000', NameSelect = '0')
  637.         self.api.set_contact_info(buddy_id, infodict)
  638.         buddy.update_info(infodict, 'im')
  639.         self.buddy_added(buddy_id)
  640.         group.sort(key = (lambda b: b.Position))
  641.         group.notify()
  642.         if group is not self.root_group:
  643.             while buddy in self.root_group:
  644.                 self.root_group.remove(buddy)
  645.         
  646.         self.root_group.notify()
  647.  
  648.     add_buddy = needs_user_id(add_buddy)
  649.     
  650.     def block(self, buddy, block = True):
  651.         if block:
  652.             self.edit_privacy_list(remove_from_allow = [
  653.                 buddy.id], add_to_block = [
  654.                 buddy.id])
  655.         else:
  656.             self.edit_privacy_list(add_to_allow = [
  657.                 buddy.id], remove_from_block = [
  658.                 buddy.id])
  659.  
  660.     
  661.     def move_buddy(self, contact, to_gname, from_gname, index, callback = None):
  662.         start_group = self.get_group(from_gname)
  663.         end_group = self.get_group(to_gname)
  664.         log.info('Moving %r from %r to %r (at position %r)', contact, to_gname, from_gname, index)
  665.         if end_group is None:
  666.             log.info("Group %r doesn't exist, bailing", to_gname)
  667.             return None
  668.         if end_group is not None:
  669.             buddies_to_shift = end_group[index:]
  670.             for buddy in reversed(buddies_to_shift):
  671.                 new_pos = str(end_group.index(buddy) + 1)
  672.                 d = {
  673.                     'ContactID': buddy.id,
  674.                     'Position': new_pos,
  675.                     'GroupName': buddy.GroupName }
  676.                 self.api.set_contact_info(buddy.id, d)
  677.                 buddy.update_info(d, 'im')
  678.             
  679.         
  680.         d = {
  681.             'ContactID': contact.id,
  682.             'Position': str(index),
  683.             'GroupName': end_group.GroupName }
  684.         self.api.set_contact_info(contact.id, d)
  685.         contact.update_info(d, 'im')
  686.         end_group.insert(index, contact)
  687.         if start_group is not None:
  688.             old_position = start_group.index(contact)
  689.             buddies_to_shift = start_group[old_position + 1:]
  690.             for buddy in buddies_to_shift:
  691.                 new_pos = str(start_group.index(buddy) - 1)
  692.                 d = {
  693.                     'ContactID': buddy.id,
  694.                     'Position': new_pos,
  695.                     'GroupName': buddy.GroupName }
  696.                 self.api.set_contact_info(buddy.id, d)
  697.                 buddy.update_info(d, 'im')
  698.             
  699.             while contact in start_group:
  700.                 start_group.remove(contact)
  701.         
  702.         while contact in self.root_group:
  703.             self.root_group.remove(contact)
  704.         if start_group is not None:
  705.             start_group.sort(key = (lambda b: b.Position))
  706.             start_group.notify()
  707.         
  708.         if end_group is not None:
  709.             end_group.sort(key = (lambda b: b.Position))
  710.             end_group.notify()
  711.         
  712.         self.root_group.sort(key = (lambda b: b.Position))
  713.         self.root_group.notify()
  714.         callback.success()
  715.  
  716.     move_buddy = callbacks.callsback(move_buddy)
  717.     
  718.     def edit_privacy_list(self, add_to_block = None, add_to_allow = None, remove_from_block = None, remove_from_allow = None, presence_vis = None, contact_vis = None):
  719.         self.api.edit_privacy_list(add_to_block = add_to_block, add_to_allow = add_to_allow, remove_from_block = remove_from_block, remove_from_allow = remove_from_allow, presence_vis = presence_vis, contact_vis = contact_vis)
  720.  
  721.     
  722.     def popupids(self):
  723.         return set((self,))
  724.  
  725.     popupids = property(popupids)
  726.     
  727.     def get_buddy_icon(self, buddy_name, callback = None):
  728.         b = self.get_buddy(buddy_name)
  729.         if b is None:
  730.             return callback.error(Exception('no buddy named %r', buddy_name))
  731.         if not b.icon_hash:
  732.             return callback.success(None)
  733.         url = b.icon_hash
  734.         
  735.         def success(req, resp):
  736.             b.cache_icon(resp.read(), url)
  737.             b.notify('icon')
  738.             log.error('got buddy icon for %r: %r', b, resp)
  739.             callback.success()
  740.  
  741.         
  742.         def error(req, exc):
  743.             log.error('error requesting buddy icon for %r: %r', b, exc)
  744.             callback.error(exc)
  745.  
  746.         asynchttp.httpopen(url, headers = {
  747.             'User-Agent': 'AsyncDownloadMgr' }, success = success, error = error)
  748.  
  749.     get_buddy_icon = callbacks.callsback(get_buddy_icon)
  750.     
  751.     def set_message(self, message = '', status = '', format = None, **k):
  752.         self._set_status(status, message.encode('utf8'))
  753.  
  754.     
  755.     def set_idle(self, idle):
  756.         log.info('set_idle(%r)', idle)
  757.         if idle:
  758.             self._old_status = self._status
  759.             self._set_status('idle')
  760.         elif not getattr(self, '_old_status', None):
  761.             pass
  762.         self._set_status(1)
  763.         self._old_status = None
  764.  
  765.     
  766.     def set_invisible(self, invis):
  767.         if invis:
  768.             self._old_status = self._status
  769.             self._set_status('invisible')
  770.         elif not getattr(self, '_old_status', None):
  771.             pass
  772.         self._set_status(1)
  773.         self._old_status = None
  774.  
  775.     
  776.     def _set_status(self, status, status_string = None, locstring = None):
  777.         log.info_s('_set_status(%r, %r, %r)', status, status_string, locstring)
  778.         if status_string is None:
  779.             status_string = getattr(self, '_status_string', '')
  780.         
  781.         if locstring is None:
  782.             locstring = getattr(self, '_loc_string', '')
  783.         
  784.         self._status = status
  785.         self._status_string = status_string
  786.         self._loc_string = locstring
  787.         if status is None:
  788.             log.info('got None for _set_status')
  789.             return None
  790.         self.api.set_status(msimutil.status_to_int(status), status_string, locstring)
  791.  
  792.     
  793.     def alert_update(self):
  794.         log.info('Sending update request')
  795.         self.api.request_social_alerts()
  796.  
  797.     
  798.     def launchbrowser(self, url):
  799.         wx.LaunchDefaultBrowser(url)
  800.  
  801.     
  802.     def openurl(self, name, userid = None):
  803.         if get(self, 'sesskey', False) and pref('privacy.www_auto_signin', False):
  804.             url = self.getURL(name, userid)
  805.         else:
  806.             url = 'http://www.myspace.com'
  807.         self.launchbrowser(url)
  808.  
  809.     
  810.     def make_chl_response(self, s):
  811.         return b64encode(msimutil.crypt(s, self.password.lower())).strip('=')
  812.  
  813.     
  814.     def getURL(self, s, userid = None, pop = True):
  815.         if userid is None:
  816.             
  817.             try:
  818.                 userid = self.api.userid
  819.             except AttributeError:
  820.                 return 'http://www.myspace.com'
  821.             
  822.  
  823.         None<EXCEPTION MATCH>AttributeError
  824.         chl = self.next_chl(pop)
  825.         if chl is None:
  826.             return 'http://www.myspace.com'
  827.         n = msimutil.roflcopter(chl.key, self.api.sesskey, self.api.userid)
  828.         return net.UrlQuery('http://home.myspace.com/Modules/IM/Pages/UrlRedirector.aspx', challenge = '%s-%s-%s' % (n, self.api.userid, self.api.sesskey), response = str(self.make_chl_response(chl.data)), target = s, targetid = userid)
  829.  
  830.     
  831.     def next_chl(self, pop = True):
  832.         
  833.         try:
  834.             if pop:
  835.                 f = list.pop
  836.             else:
  837.                 f = list.__getitem__
  838.             return f(self.challenges, 0)
  839.         except IndexError:
  840.             return None
  841.         finally:
  842.             if len(self.challenges) == 3:
  843.                 log.info('requesting more challenges')
  844.                 self.request_challenges()
  845.             
  846.  
  847.  
  848.     
  849.     def get_privacy_panel_class(cls):
  850.         import msim.myspacegui.privacy as priv_gui
  851.         return priv_gui.MSIMPrivacyPanel
  852.  
  853.     get_privacy_panel_class = classmethod(get_privacy_panel_class)
  854.     
  855.     def save_userinfo(self, settings = None):
  856.         if settings is None:
  857.             settings = self.self_buddy.IMSettings
  858.         
  859.         self.self_buddy.update_info(settings)
  860.         self.api.set_user_prefs(settings)
  861.  
  862.     
  863.     def set_userpref(self, **k):
  864.         self.save_userinfo(k)
  865.  
  866.     
  867.     def rename_group(self, group_id, new_name):
  868.         group = self.get_group(group_id)
  869.         group.GroupName = new_name
  870.         info = group.get_infodict()
  871.         self.api.set_group_details(info)
  872.         self.root_group.notify()
  873.  
  874.     
  875.     def send_exitchat(self, buddy_id, group_id):
  876.         self.api.send_exitchat(buddy_id, group_id)
  877.  
  878.  
  879.  
  880. class Challenge(object):
  881.     
  882.     def __init__(self, Challenge, ChallengeData):
  883.         self.key = int(Challenge)
  884.         self.data = ChallengeData
  885.  
  886.     
  887.     def __repr__(self):
  888.         return '<Challenge key=%s data=%s>' % (self.key, self.data)
  889.  
  890.  
  891. import gui.infobox.providers as gui_providers
  892. import gui.infobox.interfaces as gui_interfaces
  893. import protocols
  894.  
  895. class MSIMBuddyIB(gui_providers.InfoboxProviderBase):
  896.     javascript_libs = []
  897.     protocols.advise(asAdapterForTypes = [
  898.         msimcontacts.MSIM_Buddy], instancesProvide = [
  899.         gui_interfaces.IInfoboxHTMLProvider])
  900.     
  901.     def __init__(self, buddy):
  902.         gui_providers.InfoboxProviderBase.__init__(self)
  903.         self.buddy = buddy
  904.  
  905.     
  906.     def get_html(self, *a, **opts):
  907.         self.buddy._dirty = False
  908.         return gui_providers.InfoboxProviderBase.get_html(self, **opts)
  909.  
  910.     
  911.     def get_app_context(self, ctxt_class):
  912.         import path
  913.         return ctxt_class(path.path(__file__).parent.parent, self.buddy.protocol.name)
  914.  
  915.     
  916.     def get_context(self):
  917.         import gui.skin as gui
  918.         import gui.buddylist.renderers as renderers
  919.         ctxt = gui_providers.InfoboxProviderBase.get_context(self)
  920.         proto = self.buddy.protocol
  921.         ctxt.update(proto = proto, self_buddy = proto.self_buddy, buddy = self.buddy, skin = gui.skin, renderers = renderers, common = common)
  922.         return ctxt
  923.  
  924.     
  925.     def _dirty(self):
  926.         return getattr(self.buddy, '_dirty', True)
  927.  
  928.     _dirty = property(_dirty)
  929.  
  930.