home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / common / Buddy.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  22.2 KB  |  722 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. from threading import RLock
  6. from util.callbacks import callsback
  7. from traceback import print_exc
  8. from util.threads import threaded
  9. from util.primitives.error_handling import traceguard
  10. from util.primitives.funcs import do, readonly
  11. from util.primitives.mapping import Storage
  12. from util.primitives.synchronization import lock
  13. from digsby_chatlogs.interfaces import IAliasProvider
  14. import traceback
  15. import os.path as os
  16. import wx
  17. import cPickle
  18. import stat
  19. from os.path import isfile, join as pathjoin, exists as pathexists
  20. from cStringIO import StringIO
  21. from util import Timer
  22. import stdpaths
  23. from path import path
  24. from util.observe import Observable, ObservableProperty as oproperty
  25. from common.actions import ObservableActionMeta, action
  26. from common import profile
  27. from PIL import Image
  28. from time import time
  29. from gui.toolbox import calllimit
  30. from logging import getLogger
  31. log = getLogger('Buddy')
  32. info = log.info
  33. from common.buddyicon import _rate_limited_icon_get
  34.  
  35. class FileTransferException(Exception):
  36.     pass
  37.  
  38. ICON_HASH_FILE = 'iconhashes.dat'
  39.  
  40. def load_hashes():
  41.     global hashes, cache_path, hashes
  42.     hashes = { }
  43.     wx.GetApp().PreShutdown.append(write_hashes)
  44.     cache_path = pathjoin(stdpaths.userlocaldata, 'cache')
  45.     if not pathexists(cache_path):
  46.         os.makedirs(cache_path)
  47.     elif pathexists(cache_path):
  48.         hash_filename = pathjoin(cache_path, ICON_HASH_FILE)
  49.     None if not pathexists(hash_filename) else None<EXCEPTION MATCH>Exception
  50.  
  51. hash_lock = RLock()
  52.  
  53. def buddy_icon_key(buddy):
  54.     return buddy.service
  55.  
  56.  
  57. def write_hashes():
  58.     if 'hashes' not in globals():
  59.         load_hashes()
  60.     
  61.     log.info('writing icon hashes')
  62.     hash_lock.__enter__()
  63.     
  64.     try:
  65.         
  66.         try:
  67.             f = _[1]
  68.             cPickle.dump(hashes, f)
  69.         finally:
  70.             pass
  71.  
  72.     except Exception:
  73.         hash_lock.__exit__
  74.         hash_lock.__exit__
  75.         hash_lock
  76.         log.critical('error writing icon hashes')
  77.         print_exc()
  78.     except:
  79.         hash_lock.__exit__
  80.     finally:
  81.         pass
  82.  
  83.  
  84. write_hashes = calllimit(5)(write_hashes)
  85.  
  86. def icon_path_for(buddy):
  87.     if 'cache_path' not in globals():
  88.         load_hashes()
  89.     
  90.     bname = buddy.name
  91.     if isinstance(bname, bytes):
  92.         bname = bname.decode('fuzzy utf8').encode('filesys')
  93.     elif isinstance(bname, unicode):
  94.         bname = bname.encode('filesys')
  95.     
  96.     return pathjoin(cache_path, buddy_icon_key(buddy), '%s_ICON.dat' % bname).decode('filesys')
  97.  
  98.  
  99. def get_disk_icon_hash(buddy):
  100.     if 'hashes' not in globals():
  101.         load_hashes()
  102.     
  103.     protoname = buddy_icon_key(buddy)
  104.     
  105.     try:
  106.         protohashes = hashes[protoname]
  107.     except KeyError:
  108.         return None
  109.  
  110.     return protohashes.get(buddy.name, None)
  111.  
  112.  
  113. def get_cached_icon(buddy):
  114.     if 'hashes' not in globals():
  115.         load_hashes()
  116.     
  117.     icon_path = icon_path_for(buddy)
  118.     if not isfile(icon_path):
  119.         return (None, None)
  120.     
  121.     try:
  122.         icon_file = open(icon_path, 'rb')
  123.         data = icon_file.read()
  124.     except Exception:
  125.         isfile(icon_path)
  126.         isfile(icon_path)
  127.         print_exc()
  128.         return (None, None)
  129.  
  130.     icon_file.close()
  131.     if buddy.name not in hashes.setdefault(buddy_icon_key(buddy), { }):
  132.         return (None, None)
  133.     hash = hashes[buddy_icon_key(buddy)][buddy.name]
  134.     if len(data) == 0:
  135.         return ('empty', hash)
  136.     
  137.     try:
  138.         img = Image.open(StringIO(data))
  139.     except Exception:
  140.         len(data) == 0
  141.         len(data) == 0
  142.         buddy.name not in hashes.setdefault(buddy_icon_key(buddy), { })
  143.         log.critical('%s was not an icon, removing it', icon_path)
  144.         
  145.         try:
  146.             os.remove(icon_path)
  147.         except Exception:
  148.             isfile(icon_path)
  149.             isfile(icon_path)
  150.             log.critical('could not remove nonimage icon %s', icon_path)
  151.         except:
  152.             isfile(icon_path)
  153.  
  154.         return (None, None)
  155.         isfile(icon_path)
  156.  
  157.     img.path = unicode(icon_path) + unicode(time())
  158.     return (img, hash)
  159.  
  160.  
  161. def save_cached_icon(buddy, imgdata, imghash):
  162.     full_path = icon_path_for(buddy)
  163.     (dir, file) = os.path.split(full_path)
  164.     if not pathexists(dir):
  165.         
  166.         try:
  167.             os.makedirs(dir)
  168.         except Exception:
  169.             traceback.print_exc()
  170.         except:
  171.             None<EXCEPTION MATCH>Exception
  172.         
  173.  
  174.     None<EXCEPTION MATCH>Exception
  175.     
  176.     try:
  177.         
  178.         try:
  179.             f = _[1]
  180.             f.write(imgdata)
  181.         finally:
  182.             pass
  183.  
  184.     except Exception:
  185.         traceback.print_exc()
  186.  
  187.     hash_lock.__enter__()
  188.     
  189.     try:
  190.         hashes.setdefault(buddy_icon_key(buddy), { })[buddy.name] = imghash
  191.     finally:
  192.         pass
  193.  
  194.  
  195.  
  196. def get_bname(b):
  197.     
  198.     try:
  199.         return b.name
  200.     except AttributeError:
  201.         return str(b)
  202.  
  203.  
  204. available_fix = {
  205.     'online': 'available',
  206.     'normal': 'available' }
  207.  
  208. def get_status_orb(contact):
  209.     st = contact.status.lower()
  210.     st = available_fix.get(st, st)
  211.     if st == 'unknown':
  212.         pass
  213.     elif contact.mobile:
  214.         st = 'mobile'
  215.     elif not contact.online:
  216.         st = 'offline'
  217.     elif st == 'idle' or contact.idle:
  218.         st = 'idle'
  219.     elif contact.away:
  220.         st = 'away'
  221.     
  222.     return st
  223.  
  224.  
  225. def get_log_size(buddy):
  226.     return get_log_size_tup(buddy.name, buddy.service)
  227.  
  228.  
  229. def get_log_size_tup(name, service):
  230.     return profile.logger.logsize_for_nameservice(name, service)
  231.  
  232.  
  233. class LogSizeDict(dict):
  234.     
  235.     def __init__(self):
  236.         dict.__init__(self)
  237.         self.needed = dict()
  238.         self.triggered = False
  239.  
  240.     
  241.     def __missing__(self, key, initialize = True):
  242.         if initialize:
  243.             self.needed[key] = []
  244.         
  245.         self.__setitem__(key, 0)
  246.         if not self.triggered:
  247.             self.triggered = True
  248.             self.trigger()
  249.         
  250.         return 0
  251.  
  252.     __missing__ = lock(__missing__)
  253.     
  254.     def trigger(self):
  255.         Timer(0.1, self.do_disk_access, success = self.update).start()
  256.  
  257.     
  258.     def do_disk_access(self):
  259.         self._lock.__enter__()
  260.         
  261.         try:
  262.             needed = self.needed
  263.             self.needed = dict()
  264.         finally:
  265.             pass
  266.  
  267.         retval = dict()
  268.         for key in needed:
  269.             retval[key] = get_log_size_tup(*key)
  270.         
  271.         log.info('getting %d log sizes: %r', len(needed), needed)
  272.         return (retval, needed)
  273.  
  274.     do_disk_access = threaded(do_disk_access)
  275.     
  276.     def update(self, d):
  277.         self._lock.__enter__()
  278.         
  279.         try:
  280.             (newvals, retrieved) = d
  281.             for key in newvals:
  282.                 self.needed.pop(key, None)
  283.             
  284.             if not self.needed:
  285.                 self.triggered = False
  286.             else:
  287.                 self.trigger()
  288.         finally:
  289.             pass
  290.  
  291.         
  292.         try:
  293.             retval = dict.update(self, newvals)
  294.         except Exception:
  295.             self._lock.__exit__
  296.             self._lock.__exit__
  297.             self._lock
  298.             raise 
  299.         except:
  300.             self._lock.__exit__
  301.         else:
  302.             for val in retrieved.values():
  303.                 for buddy in val:
  304.                     traceguard.__enter__()
  305.                     
  306.                     try:
  307.                         buddy.notify('log_size')
  308.                     finally:
  309.                         pass
  310.  
  311.                 
  312.             
  313.             return retval
  314.         return None
  315.  
  316.  
  317.     
  318.     def notify_get(self, key, buddy):
  319.         if key in self.needed:
  320.             self.needed[key].append(buddy)
  321.             return self[key]
  322.         if key not in self:
  323.             self.needed[key] = [
  324.                 buddy]
  325.             return self.__missing__(key, initialize = False)
  326.         return self[key]
  327.  
  328.     notify_get = lock(notify_get)
  329.     
  330.     def __getitem__(self, key):
  331.         return dict.__getitem__(self, key)
  332.  
  333.     __getitem__ = lock(__getitem__)
  334.     
  335.     def __setitem__(self, key, value):
  336.         return dict.__setitem__(self, key, value)
  337.  
  338.     __setitem__ = lock(__setitem__)
  339.  
  340.  
  341. class Buddy(Observable):
  342.     __metaclass__ = ObservableActionMeta
  343.     _icon_requests = 0
  344.     _get_image_min_once = False
  345.     
  346.     def __init__(self, name, protocol):
  347.         Observable.__init__(self)
  348.         self.add_observer(self.store_remote_alias, 'remote_alias')
  349.         self.name = name
  350.         self.protocol = protocol
  351.         self._notify_dirty = True
  352.         self.entering = self.leaving = False
  353.         (do,)((lambda .0: for s in .0:
  354. setattr(self, s, None))([
  355.             'icon_bitmap']))
  356.         self.icon_hash = self.get_icon_hash()
  357.         self._getting_image = False
  358.         self._cached_hash = None
  359.         self.icon_disabled = False
  360.         
  361.         try:
  362.             register = profile.account_manager.buddywatcher.register
  363.         except AttributeError:
  364.             log.debug('No buddy watcher to register with')
  365.             return None
  366.  
  367.         register(self)
  368.  
  369.     
  370.     def store_remote_alias(self, obj, attr, old, new):
  371.         if attr is None or attr == 'remote_alias':
  372.             IAliasProvider(profile()).set_alias(self.name, self.service, protocol = self.protocol.service, alias = self.alias)
  373.         
  374.  
  375.     
  376.     def raise_proto_impl_err(self, prop = ''):
  377.         raise NotImplementedError('%s has not implemented a required property %s' % (getattr(self, '__class__', str(self)), prop))
  378.  
  379.     
  380.     def __repr__(self):
  381.         return '<%s %s>' % (self.__class__.__name__, self.name)
  382.  
  383.     nice_name = readonly('name')
  384.     
  385.     def online(self):
  386.         self.raise_proto_impl_err('online')
  387.  
  388.     online = property(online)
  389.     
  390.     def mobile(self):
  391.         self.raise_proto_impl_err('mobile')
  392.  
  393.     mobile = property(mobile)
  394.     
  395.     def status_message(self):
  396.         self.raise_proto_impl_err('status_message')
  397.  
  398.     status_message = property(status_message)
  399.     
  400.     def stripped_msg(self):
  401.         if not self.status_message:
  402.             pass
  403.         return u''
  404.  
  405.     stripped_msg = property(stripped_msg)
  406.     
  407.     def idle(self):
  408.         self.raise_proto_impl_err('idle')
  409.  
  410.     idle = property(idle)
  411.     
  412.     def away(self):
  413.         self.raise_proto_impl_err('away')
  414.  
  415.     away = property(away)
  416.     
  417.     def blocked(self):
  418.         self.raise_proto_impl_err('blocked')
  419.  
  420.     blocked = property(blocked)
  421.     
  422.     def _set_isbot(self, isbot):
  423.         caps = caps
  424.         import common
  425.         if isbot:
  426.             self.caps.add(caps.BOT)
  427.         else:
  428.             self.caps.discard(caps.BOT)
  429.  
  430.     
  431.     def isbot(self):
  432.         caps = caps
  433.         import common
  434.         return caps.BOT in self.caps
  435.  
  436.     isbot = property(isbot)
  437.     bot = isbot
  438.     
  439.     def service(self):
  440.         return self.protocol.name
  441.  
  442.     service = property(service)
  443.     
  444.     def serviceicon(self):
  445.         skin = skin
  446.         import gui
  447.         return skin.get('serviceicons.%s' % self.service)
  448.  
  449.     serviceicon = property(serviceicon)
  450.     
  451.     def pending_auth(self):
  452.         return False
  453.  
  454.     pending_auth = property(pending_auth)
  455.     
  456.     def sms(self):
  457.         return False
  458.  
  459.     sms = property(sms)
  460.     
  461.     def get_caps(self):
  462.         caps = caps
  463.         import common
  464.         if self.sms:
  465.             return set([
  466.                 caps.SMS])
  467.         buddy_caps = set(self.protocol.caps)
  468.         if not self.online:
  469.             buddy_caps.discard(caps.FILES)
  470.             buddy_caps.discard(caps.VIDEO)
  471.         
  472.         return buddy_caps
  473.  
  474.     caps = property(get_caps)
  475.     
  476.     def imwin_mode(self, mode):
  477.         begin_conversation = begin_conversation
  478.         import gui.imwin
  479.         begin_conversation(self, mode = mode)
  480.  
  481.     
  482.     def chat(self):
  483.         self.imwin_mode('im')
  484.  
  485.     chat = action((lambda self: 'IM' in self.caps))(chat)
  486.     
  487.     def buddy_info(self):
  488.         self.imwin_mode('info')
  489.  
  490.     buddy_info = action((lambda self: 'INFO' in self.caps))(buddy_info)
  491.     
  492.     def send_email(self):
  493.         self.imwin_mode('email')
  494.  
  495.     send_email = action((lambda self: 'EMAIL' in self.caps))(send_email)
  496.     
  497.     def send_sms(self):
  498.         self.imwin_mode('sms')
  499.  
  500.     send_sms = action((lambda self: 'SMS' in self.caps))(send_sms)
  501.     
  502.     def idstr(self):
  503.         return '/'.join([
  504.             self.protocol.name,
  505.             self.protocol.username,
  506.             self.name])
  507.  
  508.     
  509.     def alias(self):
  510.         a = profile.get_contact_info(self, 'alias')
  511.         if a:
  512.             return a
  513.         a = getattr(self, 'local_alias', None)
  514.         if a:
  515.             return a
  516.         a = getattr(self, 'remote_alias', None)
  517.         if a:
  518.             return a
  519.         return self.name
  520.  
  521.     alias = property(alias)
  522.     
  523.     def local_alias(self):
  524.         return profile.blist.get_contact_info(self, 'alias')
  525.  
  526.     local_alias = property(local_alias)
  527.     
  528.     def block(self, set_blocked = True, callback = None):
  529.         self.raise_proto_impl_err('block')
  530.  
  531.     block = action((lambda self: if self.blocked:
  532. NoneTrue))(callsback(block))
  533.     
  534.     def equals_chat_buddy(self, chat_buddy):
  535.         return self == chat_buddy
  536.  
  537.     
  538.     def unblock(self, callback = None):
  539.         self.raise_proto_impl_err('unblock')
  540.  
  541.     unblock = action((lambda self: if self.blocked:
  542. True))(callsback(unblock))
  543.     
  544.     def send_file(self, filepath = None):
  545.         if filepath is None:
  546.             Hub = Hub
  547.             import hub
  548.             filepath = Hub.getInstance().get_file('Sending file to %s' % self.name)
  549.         
  550.         if filepath:
  551.             finfo = fileinfo(filepath)
  552.             if finfo.size:
  553.                 if self.online:
  554.                     xfer = self.protocol.send_file(self, finfo)
  555.                     profile.xfers.insert(0, xfer)
  556.                 
  557.             else:
  558.                 Hub = Hub
  559.                 import hub
  560.                 Hub.getInstance().on_error(FileTransferException('%s is an empty file' % finfo.name))
  561.         
  562.  
  563.     send_file = action((lambda self: if self.online:
  564. pass'FILES' in self.caps))(send_file)
  565.     
  566.     def send_folder(self, dirpath = None):
  567.         Hub = Hub
  568.         import hub
  569.         if dirpath is None:
  570.             dirpath = Hub.getInstance().get_dir('Choose a directory to send to %s.' % self.name)
  571.         
  572.         if dirpath:
  573.             finfo = fileinfo(dirpath)
  574.             if len(finfo.files) == 0:
  575.                 Hub.getInstance().on_error(ValueError('No files in that directory.'))
  576.             elif finfo.size == 0:
  577.                 Hub.getInstance().on_error(ValueError('There are zero bytes in that directory.'))
  578.             else:
  579.                 self.protocol.send_file(self, finfo)
  580.         
  581.  
  582.     
  583.     def remove(self, protocol_obj):
  584.         self.protocol.remove_buddy(protocol_obj)
  585.  
  586.     remove = action()(remove)
  587.     
  588.     def icon_path(self):
  589.         return path(icon_path_for(self))
  590.  
  591.     icon_path = property(icon_path)
  592.     
  593.     def num_online(self):
  594.         return int(self.online)
  595.  
  596.     num_online = property(num_online)
  597.     
  598.     def notify(self, attr = None, *a, **k):
  599.         self._notify_dirty = True
  600.         profile.blist.buddy_changed(self, attr)
  601.         return Observable.notify(self, attr, *a, **k)
  602.  
  603.     
  604.     def cache_path(self):
  605.         proto = self.protocol
  606.         return pathjoin(proto.name, self.name) + '.dat'
  607.  
  608.     cache_path = property(cache_path)
  609.     
  610.     def info_key(self):
  611.         return self.name + '_' + self.service
  612.  
  613.     info_key = property(info_key)
  614.     email_hint = property((lambda self: self.protocol.email_hint(self)))
  615.     
  616.     def history(self):
  617.         return profile.logger.history_for_safe(self.protocol, self)
  618.  
  619.     history = property(history)
  620.     
  621.     def icon(self):
  622.         if self.icon_disabled:
  623.             return None
  624.         nh = self.icon_hash
  625.         if self.icon_bitmap is not None and self.icon_bitmap is not -1:
  626.             if not (self._getting_image) and nh is not None and nh != self._cached_hash:
  627.                 self._getting_image = True
  628.                 _rate_limited_icon_get(self)
  629.             
  630.         elif (nh or self._get_image_min_once) and not (self._getting_image):
  631.             self._getting_image = True
  632.             _rate_limited_icon_get(self)
  633.         
  634.         if self.icon_bitmap is not None and self.icon_bitmap is not -1:
  635.             if isinstance(self.icon_bitmap, str) and self.icon_bitmap == 'empty':
  636.                 return None
  637.             return self.icon_bitmap
  638.         self.icon_bitmap is not -1
  639.         return None
  640.  
  641.     icon = property(icon)
  642.     
  643.     def cache_icon(self, icon_data, icon_hash):
  644.         self.icon_bitmap = None
  645.         self._cached_hash = None
  646.         self._getting_image = False
  647.         save_cached_icon(self, icon_data, icon_hash)
  648.         wx.CallAfter(write_hashes)
  649.         self.notify('icon')
  650.  
  651.     
  652.     def get_icon_hash(self):
  653.         return get_disk_icon_hash(self)
  654.  
  655.     
  656.     def log_size(self):
  657.         return profile.log_sizes.notify_get((self.name, self.service), self)
  658.  
  659.     log_size = property(log_size)
  660.     
  661.     def increase_log_size(self, num_bytes):
  662.         profile.log_sizes[(self.name, self.service)] += num_bytes
  663.         self.notify('log_size')
  664.  
  665.     
  666.     def __eq__(self, b):
  667.         s = object()
  668.         if getattr(b, 'name', s) == self.name:
  669.             pass
  670.         return getattr(b, 'protocol') is self.protocol
  671.  
  672.     
  673.     def __ne__(self, other):
  674.         return not self.__eq__(other)
  675.  
  676.     
  677.     def __hash__(self):
  678.         return hash(self.info_key)
  679.  
  680.     status_notifies = { }
  681.     
  682.     def _set_status(self, status):
  683.         status = {
  684.             'online': 'available' }.get(status, status)
  685.         self.setnotifyif('status', status)
  686.  
  687.     status_orb = oproperty((lambda self: get_status_orb(self)), observe = 'status')
  688.     
  689.     def sightly_status(self):
  690.         return self.status.title()
  691.  
  692.     sightly_status = property(sightly_status)
  693.     
  694.     def pretty_profile(self):
  695.         return u''
  696.  
  697.     pretty_profile = property(pretty_profile)
  698.     
  699.     def buddy_icon(self):
  700.         get_buddy_icon = get_buddy_icon
  701.         import gui.buddylist.renderers
  702.         return get_buddy_icon(self, 32, False)
  703.  
  704.     buddy_icon = property(buddy_icon)
  705.     
  706.     def view_past_chats(self, fromacct = None):
  707.         if fromacct is None:
  708.             fromacct = self.protocol
  709.         
  710.         buddypath = profile.logger.pathfor(fromacct, self)
  711.         PastBrowser = PastBrowser
  712.         import gui.pastbrowser
  713.         PastBrowser.MakeOrShowAndSelect(buddypath)
  714.  
  715.  
  716.  
  717. def fileinfo(filepath):
  718.     filestats = os.stat(filepath)
  719.     s = Storage(size = os.path.getsize(filepath), modtime = filestats[stat.ST_MTIME], ctime = filestats[stat.ST_CTIME], name = os.path.split(filepath)[1], path = path(filepath))
  720.     return s
  721.  
  722.