コード例 #1
0
ファイル: module.py プロジェクト: dermorz/weboob
class BoursoramaModule(Module, CapBankTransferAddRecipient, CapProfile, CapContact):
    NAME = 'boursorama'
    MAINTAINER = u'Gabriel Kerneis'
    EMAIL = '*****@*****.**'
    VERSION = '1.3'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Boursorama'
    CONFIG = BackendConfig(ValueBackendPassword('login',      label='Identifiant', masked=False),
                           ValueBackendPassword('password',   label='Mot de passe'),
                           ValueBool('enable_twofactors',     label='Send validation sms', default=False),
                           Value('device',                    label='Device name', regexp='\w*', default=''),
                           Value('pin_code',                  label='Sms code', required=False),
                          )
    BROWSER = BoursoramaBrowser

    def create_default_browser(self):
        return self.create_browser(self.config)

    def iter_accounts(self):
        return self.browser.get_accounts_list()

    def get_account(self, _id):
        account = self.browser.get_account(_id)
        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        for tr in self.browser.get_history(account):
            if not tr._is_coming:
                yield tr

    def iter_coming(self, account):
        for tr in self.browser.get_history(account, coming=True):
            if tr._is_coming:
                yield tr

    def iter_investment(self, account):
        return self.browser.get_investment(account)

    def get_profile(self):
        return self.browser.get_profile()

    def iter_contacts(self):
        return self.browser.get_advisor()

    def iter_transfer_recipients(self, account):
        if not isinstance(account, Account):
            account = self.get_account(account)
        return self.browser.iter_transfer_recipients(account)

    def init_transfer(self, transfer, **kwargs):
        return self.browser.init_transfer(transfer, **kwargs)

    def new_recipient(self, recipient, **kwargs):
        return self.browser.new_recipient(recipient, **kwargs)

    def execute_transfer(self, transfer, **kwargs):
        return self.browser.execute_transfer(transfer, **kwargs)
コード例 #2
0
class BoursoramaModule(Module, CapBank):
    NAME = 'boursorama'
    MAINTAINER = u'Gabriel Kerneis'
    EMAIL = '*****@*****.**'
    VERSION = '1.2'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Boursorama'
    CONFIG = BackendConfig(ValueBackendPassword('login',      label='Identifiant', masked=False),
                           ValueBackendPassword('password',   label='Mot de passe'),
                           ValueBool('enable_twofactors',     label='Send validation sms', default=False),
                           Value('device',                    label='Device name', regexp='\w*', default=''),
                           Value('pin_code',                  label='Sms code', required=False),
                          )
    BROWSER = Boursorama

    def create_default_browser(self):
        return self.create_browser(self.config)

    def iter_accounts(self):
        return self.browser.get_accounts_list()

    def get_account(self, _id):
        with self.browser:
            account = self.browser.get_account(_id)
        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        return self.browser.get_history(account)

    def iter_investment(self, account):
        return self.browser.get_investment(account)
コード例 #3
0
class ZerobinModule(Module, CapPaste):
    NAME = 'zerobin'
    DESCRIPTION = u'ZeroBin/0bin/PrivateBin encrypted pastebin'
    MAINTAINER = u'Vincent A'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.6'
    CONFIG = BackendConfig(
        Value('url',
              label='URL of the zerobin/0bin/privatebin',
              regexp='https?://.*',
              default='https://zerobin.net'),
        ValueBool('discussion',
                  label='Allow paste comments (ZeroBin only)',
                  default=False),
    )

    BROWSER = ZerobinBrowser

    def create_default_browser(self):
        return self.create_browser(self.config['url'].get(),
                                   self.config['discussion'].get())

    def can_post(self, contents, title=None, public=None, max_age=None):
        """
        Checks if the paste can be pasted by this backend.
        Some properties are considered required (public/private, max_age) while others
        are just bonuses (language).

        contents: Can be used to check encodability, maximum length, etc.
        title: Can be used to check length, allowed characters. Should not be required.
        public: True must be public, False must be private, None do not care.
        max_age: Maximum time to live in seconds.

        A score of 0 means the backend is not suitable.
        A score of 1 means the backend is suitable.
        Higher scores means it is more suitable than others with a lower score.

        :rtype: int
        :returns: score
        """
        if public:
            return 0
        return self.browser.can_post(contents, max_age)

    def get_paste(self, id):
        if '#' not in id:
            return
        elif id.startswith('http://') or id.startswith('https://'):
            if not id.startswith(self.config['url'].get()):
                return
        return self.browser.get_paste(id)

    def new_paste(self, *args, **kwargs):
        return ZeroPaste(*args, **kwargs)

    def post_paste(self, paste, max_age=None):
        self.browser.post_paste(paste, max_age)
コード例 #4
0
ファイル: browser.py プロジェクト: guix77/weboob
    def new_recipient(self, recipient, **params):
        if 'code' in params:
            # for sms authentication
            return self.send_code(recipient, **params)

        # prepare commun data for all authentication method
        data = {}
        data['adresseBeneficiaire'] = ''
        data['iban'] = recipient.iban
        data['libelleBeneficiaire'] = recipient.label
        data['notification'] = True
        data['typeBeneficiaire'] = ''

        # provisional
        if self.digital_key:
            if 'digital_key' in params:
                return self.new_recipient_digital_key(recipient, data)

        # need to be on recipient page send sms or mobile notification
        # needed to get the phone number, enabling the possibility to send sms.
        # all users with validated phone number can receive sms code
        self.recipients.go(data=JSON({'type': 'TOUS'}))

        # check type of recipient activation
        type_activation = 'sms'

        # provisional
        if self.digital_key:
            if self.page.has_digital_key():
                # force users with digital key activated to use digital key authentication
                type_activation = 'digital_key'

        if type_activation == 'sms':
            # post recipient data sending sms with same request
            data['typeEnvoi'] = 'SMS'
            recipient = self.add_recip.go(data=json.dumps(data),
                                          headers={
                                              'Content-Type':
                                              'application/json'
                                          }).get_recipient(recipient)
            raise AddRecipientStep(
                recipient,
                Value('code', label='Saisissez le code reçu par SMS.'))
        elif type_activation == 'digital_key':
            # recipient validated with digital key are immediatly available
            recipient.enabled_date = datetime.today()
            raise AddRecipientStep(
                recipient,
                ValueBool(
                    'digital_key',
                    label=
                    'Validez pour recevoir une demande sur votre application bancaire. La validation de votre bénéficiaire peut prendre plusieurs minutes.'
                ))
コード例 #5
0
ファイル: transfer.py プロジェクト: linura/weboob
    def double_auth(self, recipient):
        try:
            form = self.get_form(id='formCache')
        except FormNotFound:
            raise AddRecipientError('form not found')

        self.browser.context = form['context']
        self.browser.dup = form['dup']
        self.browser.logged = 1

        getsigninfo_data = {}
        getsigninfo_data['b64_jeton_transaction'] = form['context']
        getsigninfo_data['action_level'] = self.get_action_level()
        r = self.browser.open(
            'https://particuliers.secure.societegenerale.fr/sec/getsigninfo.json',
            data=getsigninfo_data)
        assert r.page.doc['commun']['statut'] == 'ok'

        recipient = self.get_recipient_object(recipient, get_info=True)
        self.browser.page = None
        if r.page.doc['donnees']['sign_proc'] == 'csa':
            send_data = {}
            send_data['csa_op'] = 'sign'
            send_data['context'] = form['context']
            r = self.browser.open(
                'https://particuliers.secure.societegenerale.fr/sec/csa/send.json',
                data=send_data)
            assert r.page.doc['commun']['statut'] == 'ok'
            raise AddRecipientStep(
                recipient,
                Value(
                    'code',
                    label=
                    u'Cette opération doit être validée par un Code Sécurité.')
            )
        elif r.page.doc['donnees']['sign_proc'] == 'OOB':
            oob_data = {}
            oob_data['b64_jeton_transaction'] = form['context']
            r = self.browser.open(
                'https://particuliers.secure.societegenerale.fr/sec/oob_sendoob.json',
                data=oob_data)
            assert r.page.doc['commun']['statut'] == 'ok'
            self.browser.id_transaction = r.page.doc['donnees'][
                'id-transaction']
            raise AddRecipientStep(
                recipient,
                ValueBool(
                    'pass',
                    label=
                    u'Valider cette opération sur votre applicaton société générale'
                ))
        else:
            raise AddRecipientError('sign process unknown')
コード例 #6
0
 def send_notif_to_user(self, recipient):
     """Add recipient with 'pass sécurité' authentication"""
     data = {}
     data['b64_jeton_transaction'] = self.context
     r = self.open(self.absurl('/sec/oob_sendoob.json'), data=data)
     self.id_transaction = r.page.get_transaction_id()
     raise AddRecipientStep(
         recipient,
         ValueBool(
             'pass',
             label=
             'Valider cette opération sur votre applicaton société générale'
         ))
コード例 #7
0
ファイル: backend.py プロジェクト: lissyx/weboob
class BoursoramaBackend(BaseBackend, ICapBank):
    NAME = 'boursorama'
    MAINTAINER = u'Gabriel Kerneis'
    EMAIL = '*****@*****.**'
    VERSION = '0.h'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'Boursorama French bank website'
    CONFIG = BackendConfig(ValueBackendPassword('login',      label='Account ID', masked=False),
                           ValueBackendPassword('password',   label='Password'),
                           ValueBool('enable_twofactors',     label='Send validation sms', default=False),
                           Value('device',                    label='Device name', regexp='\w*', default=''),
                          )
    BROWSER = Boursorama

    def create_default_browser(self):
        return self.create_browser(
            self.config["device"].get()
            , self.config["enable_twofactors"].get()
            , self.config['login'].get()
            , self.config['password'].get())

    def iter_accounts(self):
        for account in self.browser.get_accounts_list():
            yield account

    def get_account(self, _id):
        if not _id.isdigit():
            raise AccountNotFound()
        with self.browser:
            account = self.browser.get_account(_id)
        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        with self.browser:
            for history in self.browser.get_history(account):
                yield history
コード例 #8
0
ファイル: module.py プロジェクト: yang2lalang/weboob
class DLFPModule(Module, CapMessages, CapMessagesPost, CapContent):
    NAME = 'dlfp'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '1.2'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = "Da Linux French Page news website"
    CONFIG = BackendConfig(Value('username',                label='Username', default=''),
                           ValueBackendPassword('password', label='Password', default=''),
                           ValueBool('get_news',            label='Get newspapers', default=True),
                           ValueBool('get_diaries',         label='Get diaries', default=False),
                           ValueBool('get_polls',           label='Get polls', default=False),
                           ValueBool('get_board',           label='Get board', default=False),
                           ValueBool('get_wiki',            label='Get wiki', default=False),
                           ValueBool('get_tracker',         label='Get tracker', default=False))
    STORAGE = {'seen': {}}
    BROWSER = DLFP

    FEEDS = {'get_news':     "https://linuxfr.org/news.atom",
             'get_diaries':  "https://linuxfr.org/journaux.atom",
             'get_polls':    "https://linuxfr.org/sondages.atom",
             'get_board':    "https://linuxfr.org/forums.atom",
             'get_wiki':     "https://linuxfr.org/wiki.atom",
             'get_tracker':  "https://linuxfr.org/suivi.atom",
            }

    def create_default_browser(self):
        username = self.config['username'].get()
        if username:
            password = self.config['password'].get()
        else:
            password = None
        return self.create_browser(username, password)

    def deinit(self):
        # don't need to logout if the browser hasn't been used.
        if not self._browser:
            return

        with self.browser:
            self.browser.close_session()

    #### CapMessages ##############################################

    def iter_threads(self):
        whats = set()
        for param, url in self.FEEDS.iteritems():
            if self.config[param].get():
                whats.add(url)

        for what in whats:
            for article in Newsfeed(what, rssid).iter_entries():
                if article.datetime and (datetime.now() - article.datetime) > timedelta(days=60):
                    continue
                thread = Thread(article.id, article.link)
                thread.title = article.title
                thread._rsscomment = article.rsscomment
                if article.datetime:
                    thread.date = article.datetime
                yield thread

    def get_thread(self, id, getseen=True):
        if not isinstance(id, Thread):
            thread = None
        else:
            thread = id
            id = thread.id

            if thread.date:
                self.storage.set('date', id, thread.date)
                self.storage.save()

        with self.browser:
            content = self.browser.get_content(id)

        if not content:
            return None

        if not thread:
            thread = Thread(content.id)

        flags = Message.IS_HTML
        if thread.id not in self.storage.get('seen', default={}):
            flags |= Message.IS_UNREAD

        thread.title = content.title
        if not thread.date:
            thread.date = content.date

        thread.root = Message(thread=thread,
                              id='0',  # root message
                              url=self.browser.absurl(id2url(content.id)),
                              title=content.title,
                              sender=content.author or u'',
                              receivers=None,
                              date=thread.date,
                              parent=None,
                              content=content.body,
                              signature='URL: %s' % self.browser.absurl(id2url(content.id)),
                              children=[],
                              flags=flags)

        for com in content.comments:
            self._insert_comment(com, thread.root, getseen)

        return thread

    def _insert_comment(self, com, parent, getseen=True):
        """"
        Insert 'com' comment and its children in the parent message.
        """
        flags = Message.IS_HTML
        if com.id not in self.storage.get('seen', parent.thread.id, 'comments', default=[]):
            flags |= Message.IS_UNREAD

        if getseen or flags & Message.IS_UNREAD:
            com.parse()
            message = Message(thread=parent.thread,
                              id=com.id,
                              url=com.url,
                              title=com.title,
                              sender=com.author or u'',
                              receivers=None,
                              date=com.date,
                              parent=parent,
                              content=com.body,
                              signature=com.signature +
                                        '<br />'.join(['Score: %d' % com.score,
                                                       'URL: %s' % com.url]),
                              children=[],
                              flags=flags)
        else:
            message = Message(thread=parent.thread,
                              id=com.id,
                              children=[],
                              parent=parent,
                              flags=flags)
        parent.children.append(message)
        for sub in com.comments:
            self._insert_comment(sub, message, getseen)

    def iter_unread_messages(self):
        for thread in self.iter_threads():
            # Check if we have seen all comments of this thread.
            with self.browser:
                oldhash = self.storage.get('hash', thread.id, default="")
                newhash = self.browser.get_hash(thread._rsscomment)
            if oldhash != newhash:
                self.storage.set('hash', thread.id, newhash)
                self.storage.save()

                self.fill_thread(thread, 'root', getseen=False)
                for m in thread.iter_all_messages():
                    if m.flags & m.IS_UNREAD:
                        yield m

    def set_message_read(self, message):
        self.storage.set('seen', message.thread.id, 'comments',
            self.storage.get('seen', message.thread.id, 'comments', default=[]) + [message.id])
        self.storage.save()

        lastpurge = self.storage.get('lastpurge', default=0)
        # 86400 = one day
        if time.time() - lastpurge > 86400:
            self.storage.set('lastpurge', time.time())
            self.storage.save()

            # we can't directly delete without a "RuntimeError: dictionary changed size during iteration"
            todelete = []

            for id in self.storage.get('seen', default={}):
                date = self.storage.get('date', id, default=0)
                # if no date available, create a new one (compatibility with "old" storage)
                if date == 0:
                    self.storage.set('date', id, datetime.now())
                elif datetime.now() - date > timedelta(days=60):
                    todelete.append(id)

            for id in todelete:
                self.storage.delete('hash', id)
                self.storage.delete('date', id)
                self.storage.delete('seen', id)
            self.storage.save()

    def fill_thread(self, thread, fields, getseen=True):
        return self.get_thread(thread, getseen)

    #### CapMessagesReply #########################################
    def post_message(self, message):
        if not self.browser.username:
            raise BrowserForbidden()
        if not message.parent:
            raise CantSendMessage('Posting news and diaries on DLFP is not supported yet')

        assert message.thread

        with self.browser:
            return self.browser.post_comment(message.thread.id,
                                             message.parent.id,
                                             message.title,
                                             message.content)

    #### CapContent ###############################################
    def get_content(self, _id, revision=None):
        if isinstance(_id, basestring):
            content = Content(_id)
        else:
            content = _id
            _id = content.id

        if revision:
            raise NotImplementedError('Website does not provide access to older revisions sources.')
        with self.browser:
            data = self.browser.get_wiki_content(_id)

        if data is None:
            return None

        content.content = data
        return content

    def push_content(self, content, message=None, minor=False):
        if not self.browser.username:
            raise BrowserForbidden()
        with self.browser:
            return self.browser.set_wiki_content(content.id, content.content, message)

    def get_content_preview(self, content):
        with self.browser:
            return self.browser.get_wiki_preview(content.id, content.content)

    OBJECTS = {Thread: fill_thread}
コード例 #9
0
class SenscritiqueModule(Module, CapCalendarEvent):
    NAME = 'senscritique'
    DESCRIPTION = u'senscritique website'
    MAINTAINER = u'Bezleputh'
    EMAIL = '*****@*****.**'
    LICENSE = 'AGPLv3+'
    VERSION = '1.1'
    ASSOCIATED_CATEGORIES = [CATEGORIES.TELE]
    BROWSER = SenscritiqueBrowser

    tv_settings_choices = OrderedDict([(k, u'%s' % (v))
                                       for k, v in sorted({
                                           '000000': u'-- Indifférent --',
                                           '9': u'TNT',
                                           '1': u'Canalsat',
                                           '2': u'Numericable',
                                           '10': u'Orange',
                                           '11': u'Free',
                                           '12': u'SFR',
                                           '15': u'Darty box via ADSL',
                                           '16': u'Bouygues',
                                       }.iteritems())])
    """
    dict that represents ids list of general-interest channels included in a tv package
    {'tv package id': ['general-interest channels ids list']}
    """
    general = {
        9: [46, 2, 48, 56],
        1: [
            49, 46, 21, 2, 36, 59, 54, 48, 56, 50, 32, 1, 51, 24, 38, 34, 37,
            6, 25, 11, 53, 26, 47
        ],
        2: [
            49, 46, 21, 2, 36, 59, 54, 48, 56, 50, 32, 1, 51, 24, 38, 34, 37,
            6, 25, 11, 53, 26, 47
        ],
        10: [46, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47],
        11: [46, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47],
        12: [49, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47],
        15: [49, 46, 2, 36, 32, 24, 34, 37, 53, 47],
        16: [49, 46, 2, 36, 59, 54, 32, 24, 34, 37, 53, 47],
    }
    """
    dict that represents ids list of cinema channels included in a tv package
    {'tv package id': ['cinema channels ids list']}
    """
    cinema = {
        9: [10, 7],
        1: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42,
            41, 43, 13, 12
        ],
        2: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42,
            41, 43, 13, 12
        ],
        10: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43,
            13, 12
        ],
        11: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42,
            41, 43, 13, 12
        ],
        12: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43,
            13, 12
        ],
        15: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 44, 3, 45, 42, 41, 43,
            13, 12
        ],
        16: [
            10, 7, 9, 8, 52, 19, 18, 17, 16, 20, 15, 14, 4055, 44, 3, 45, 42,
            41, 43, 13, 12
        ],
    }

    CONFIG = BackendConfig(
        Value('tv_settings',
              label=u'T.V. package',
              choices=tv_settings_choices),
        ValueBool('general', label='General', default=True),
        ValueBool('cinema', label='Cinema', default=False),
    )

    def get_package_and_channels(self):
        package = int(self.config['tv_settings'].get())
        channels = []
        if package:
            if self.config['general'].get():
                channels += self.general[package]

            if self.config['cinema'].get():
                channels += self.cinema[package]

        return package, channels

    def search_events(self, query):
        if self.has_matching_categories(query):
            package, channels = self.get_package_and_channels()
            return self.browser.list_events(query.start_date, query.end_date,
                                            package, channels)

    def list_events(self, date_from, date_to=None):
        items = []
        package, channels = self.get_package_and_channels()
        for item in self.browser.list_events(date_from, date_to, package,
                                             channels):
            items.append(item)

        items.sort(key=lambda o: o.start_date)
        return items

    def get_event(self, _id, event=None):
        package, channels = self.get_package_and_channels()
        return self.browser.get_event(_id,
                                      event,
                                      package=package,
                                      channels=channels)

    def fill_obj(self, event, fields):
        return self.get_event(event.id, event)

    OBJECTS = {SensCritiquenCalendarEvent: fill_obj}
コード例 #10
0
class AuMBackend(BaseBackend, ICapMessages, ICapMessagesPost, ICapDating,
                 ICapChat, ICapContact, ICapAccount):
    NAME = 'aum'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '0.h'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'"Adopte un Mec" French dating website'
    CONFIG = BackendConfig(
        Value('username', label='Username'),
        ValueBackendPassword('password', label='Password'),
        ValueBool('antispam', label='Enable anti-spam', default=False),
        ValueBool('baskets',
                  label='Get baskets with new messages',
                  default=True),
        Value('search_query', label='Search query', default=''))
    STORAGE = {
        'profiles_walker': {
            'viewed': []
        },
        'queries_queue': {
            'queue': []
        },
        's***s': {},
        'notes': {},
    }
    BROWSER = AuMBrowser

    MAGIC_ID_BASKET = 1

    def __init__(self, *args, **kwargs):
        BaseBackend.__init__(self, *args, **kwargs)
        if self.config['antispam'].get():
            self.antispam = AntiSpam()
        else:
            self.antispam = None

    def create_default_browser(self):
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get(),
                                   self.config['search_query'].get())

    def report_spam(self, id):
        with self.browser:
            pass
            #self.browser.delete_thread(id)
            # Do not report fakes to website, to let them to other guys :)
            #self.browser.report_fake(id)

    # ---- ICapDating methods ---------------------

    def init_optimizations(self):
        self.add_optimization(
            'PROFILE_WALKER',
            ProfilesWalker(self.weboob.scheduler, self.storage, self.browser))
        self.add_optimization('VISIBILITY',
                              Visibility(self.weboob.scheduler, self.browser))
        self.add_optimization(
            'QUERIES_QUEUE',
            QueriesQueue(self.weboob.scheduler, self.storage, self.browser))

    def iter_events(self):
        all_events = {}
        with self.browser:
            all_events[u'baskets'] = (self.browser.get_baskets,
                                      'You were put into %s\'s basket')
            all_events[u'flashs'] = (self.browser.get_flashs,
                                     'You sent a charm to %s')
            all_events[u'visits'] = (self.browser.get_visits, 'Visited by %s')
        for type, (events, message) in all_events.iteritems():
            for event in events():
                e = Event(event['who']['id'])

                e.date = parse_dt(event['date'])
                e.type = type
                if 'who' in event:
                    e.contact = self._get_partial_contact(event['who'])
                else:
                    e.contact = self._get_partial_contact(event)

                if not e.contact:
                    continue

                e.message = message % e.contact.name
                yield e

    # ---- ICapMessages methods ---------------------

    def fill_thread(self, thread, fields):
        return self.get_thread(thread)

    def iter_threads(self):
        with self.browser:
            threads = self.browser.get_threads_list()

        for thread in threads:
            #if thread['member'].get('isBan', thread['member'].get('dead', False)):
            #    with self.browser:
            #        self.browser.delete_thread(thread['member']['id'])
            #    continue
            if self.antispam and not self.antispam.check_thread(thread):
                self.logger.info('Skipped a spam-thread from %s' %
                                 thread['pseudo'])
                self.report_spam(thread['who']['id'])
                continue
            t = Thread(int(thread['who']['id']))
            t.flags = Thread.IS_DISCUSSION
            t.title = u'Discussion with %s' % to_unicode(
                thread['who']['pseudo'])
            yield t

    def get_thread(self, id, contacts=None, get_profiles=False):
        """
        Get a thread and its messages.

        The 'contacts' parameters is only used for internal calls.
        """
        thread = None
        if isinstance(id, Thread):
            thread = id
            id = thread.id

        if not thread:
            thread = Thread(int(id))
            thread.flags = Thread.IS_DISCUSSION
            full = False
        else:
            full = True

        with self.browser:
            mails = self.browser.get_thread_mails(id, 100)
            my_name = self.browser.get_my_name()

        child = None
        msg = None
        s**t = self._get_slut(id)
        if contacts is None:
            contacts = {}

        if not thread.title:
            thread.title = u'Discussion with %s' % mails['who']['pseudo']

        self.storage.set('s***s', int(thread.id), 'status', mails['status'])
        self.storage.save()

        for mail in mails['results']:
            flags = 0
            if self.antispam and not self.antispam.check_mail(mail):
                self.logger.info('Skipped a spam-mail from %s' %
                                 mails['who']['pseudo'])
                self.report_spam(thread.id)
                break

            if parse_dt(mail['date']) > s**t['lastmsg']:
                flags |= Message.IS_UNREAD

                if get_profiles:
                    if not mail['from'] in contacts:
                        try:
                            with self.browser:
                                contacts[mail['from']] = self.get_contact(
                                    mail['from'])
                        except BrowserHTTPNotFound:
                            pass
                    if self.antispam and mail[
                            'from'] in contacts and not self.antispam.check_contact(
                                contacts[mail['from']]):
                        self.logger.info(
                            'Skipped a spam-mail-profile from %s' %
                            mails['who']['pseudo'])
                        self.report_spam(thread.id)
                        break

            if int(mail['from']) == self.browser.my_id:
                if mails['remote_status'] == 'new' and msg is None:
                    flags |= Message.IS_NOT_RECEIVED
                else:
                    flags |= Message.IS_RECEIVED

            signature = u''
            #if mail.get('src', None):
            #    signature += u'Sent from my %s\n\n' % mail['src']
            if mail['from'] in contacts:
                signature += contacts[mail['from']].get_text()

            msg = Message(
                thread=thread,
                id=int(
                    time.strftime('%Y%m%d%H%M%S',
                                  parse_dt(mail['date']).timetuple())),
                title=thread.title,
                sender=to_unicode(my_name if int(mail['from']) == self.browser.
                                  my_id else mails['who']['pseudo']),
                receivers=[
                    to_unicode(my_name if int(mail['from']) != self.browser.
                               my_id else mails['who']['pseudo'])
                ],
                date=parse_dt(mail['date']),
                content=to_unicode(unescape(mail['message'] or '').strip()),
                signature=signature,
                children=[],
                flags=flags)
            if child:
                msg.children.append(child)
                child.parent = msg

            child = msg

        if full and msg:
            # If we have get all the messages, replace NotLoaded with None as
            # parent.
            msg.parent = None
        if not full and not msg:
            # Perhaps there are hidden messages
            msg = NotLoaded

        thread.root = msg

        return thread

    def iter_unread_messages(self):
        try:
            contacts = {}
            with self.browser:
                threads = self.browser.get_threads_list()
            for thread in threads:
                #if thread['member'].get('isBan', thread['member'].get('dead', False)):
                #    with self.browser:
                #        self.browser.delete_thread(int(thread['member']['id']))
                #    continue
                if self.antispam and not self.antispam.check_thread(thread):
                    self.logger.info('Skipped a spam-unread-thread from %s' %
                                     thread['who']['pseudo'])
                    self.report_spam(thread['member']['id'])
                    continue
                s**t = self._get_slut(thread['who']['id'])
                if parse_dt(
                        thread['date']
                ) > s**t['lastmsg'] or thread['status'] != s**t['status']:
                    t = self.get_thread(thread['who']['id'],
                                        contacts,
                                        get_profiles=True)
                    for m in t.iter_all_messages():
                        if m.flags & m.IS_UNREAD:
                            yield m

            if not self.config['baskets'].get():
                return

            # Send mail when someone added me in her basket.
            # XXX possibly race condition if a s**t adds me in her basket
            #     between the aum.nb_new_baskets() and aum.get_baskets().
            with self.browser:
                s**t = self._get_slut(-self.MAGIC_ID_BASKET)

                new_baskets = self.browser.nb_new_baskets()
                if new_baskets > 0:
                    baskets = self.browser.get_baskets()
                    my_name = self.browser.get_my_name()
                    for basket in baskets:
                        if parse_dt(basket['date']) <= s**t['lastmsg']:
                            continue
                        contact = self.get_contact(basket['who']['id'])
                        if self.antispam and not self.antispam.check_contact(
                                contact):
                            self.logger.info('Skipped a spam-basket from %s' %
                                             contact.name)
                            self.report_spam(basket['who']['id'])
                            continue

                        thread = Thread(int(basket['who']['id']))
                        thread.title = 'Basket of %s' % contact.name
                        thread.root = Message(
                            thread=thread,
                            id=self.MAGIC_ID_BASKET,
                            title=thread.title,
                            sender=contact.name,
                            receivers=[my_name],
                            date=parse_dt(basket['date']),
                            content='You are taken in her basket!',
                            signature=contact.get_text(),
                            children=[],
                            flags=Message.IS_UNREAD)
                        yield thread.root
        except BrowserUnavailable as e:
            self.logger.debug('No messages, browser is unavailable: %s' % e)
            pass  # don't care about waiting

    def set_message_read(self, message):
        if int(message.id) == self.MAGIC_ID_BASKET:
            # Save the last baskets checks.
            s**t = self._get_slut(-self.MAGIC_ID_BASKET)
            if s**t['lastmsg'] < message.date:
                s**t['lastmsg'] = message.date
                self.storage.set('s***s', -self.MAGIC_ID_BASKET, s**t)
                self.storage.save()
            return

        s**t = self._get_slut(message.thread.id)
        if s**t['lastmsg'] < message.date:
            s**t['lastmsg'] = message.date
            self.storage.set('s***s', int(message.thread.id), s**t)
            self.storage.save()

    def _get_slut(self, id):
        id = int(id)
        s***s = self.storage.get('s***s')
        if not s***s or not id in s***s:
            s**t = {'lastmsg': datetime.datetime(1970, 1, 1), 'status': None}
        else:
            s**t = self.storage.get('s***s', id)

        s**t['lastmsg'] = s**t.get('lastmsg', datetime.datetime(
            1970, 1, 1)).replace(tzinfo=tz.tzutc())
        s**t['status'] = s**t.get('status', None)
        return s**t

    # ---- ICapMessagesPost methods ---------------------

    def post_message(self, message):
        with self.browser:
            self.browser.post_mail(message.thread.id, message.content)

    # ---- ICapContact methods ---------------------

    def fill_contact(self, contact, fields):
        if 'profile' in fields:
            contact = self.get_contact(contact)
        if contact and 'photos' in fields:
            for name, photo in contact.photos.iteritems():
                with self.browser:
                    if photo.url and not photo.data:
                        data = self.browser.openurl(photo.url).read()
                        contact.set_photo(name, data=data)
                    if photo.thumbnail_url and not photo.thumbnail_data:
                        data = self.browser.openurl(photo.thumbnail_url).read()
                        contact.set_photo(name, thumbnail_data=data)

    def fill_photo(self, photo, fields):
        with self.browser:
            if 'data' in fields and photo.url and not photo.data:
                photo.data = self.browser.readurl(photo.url)
            if 'thumbnail_data' in fields and photo.thumbnail_url and not photo.thumbnail_data:
                photo.thumbnail_data = self.browser.readurl(
                    photo.thumbnail_url)
        return photo

    def get_contact(self, contact):
        with self.browser:
            if isinstance(contact, Contact):
                _id = contact.id
            elif isinstance(contact, (int, long, basestring)):
                _id = contact
            else:
                raise TypeError(
                    "The parameter 'contact' isn't a contact nor a int/long/str/unicode: %s"
                    % contact)

            profile = self.browser.get_full_profile(_id)
            if not profile:
                return None

            _id = profile['id']

            if isinstance(contact, Contact):
                contact.id = _id
                contact.name = profile['pseudo']
            else:
                contact = Contact(_id, profile['pseudo'],
                                  Contact.STATUS_ONLINE)
            contact.url = self.browser.id2url(_id)
            contact.parse_profile(profile, self.browser.get_consts())
            return contact

    def _get_partial_contact(self, contact):
        s = 0
        if contact.get('online', False):
            s = Contact.STATUS_ONLINE
        else:
            s = Contact.STATUS_OFFLINE

        c = Contact(contact['id'], to_unicode(contact['pseudo']), s)
        c.url = self.browser.id2url(contact['id'])
        if 'age' in contact:
            c.status_msg = u'%s old, %s' % (contact['age'], contact['city'])
        if contact['cover'] is not None:
            url = contact['cover'] + '/%(type)s'
        else:
            url = u'http://s.adopteunmec.com/www/img/thumb0.jpg'

        c.set_photo(u'image%s' % contact['cover'],
                    url=url % {'type': 'full'},
                    thumbnail_url=url % {'type': 'small'})
        return c

    def iter_contacts(self, status=Contact.STATUS_ALL, ids=None):
        with self.browser:
            threads = self.browser.get_threads_list(count=100)

        for thread in threads:
            c = self._get_partial_contact(thread['who'])
            if c and (c.status & status) and (not ids or c.id in ids):
                yield c

    def send_query(self, id):
        if isinstance(id, Contact):
            id = id.id

        queries_queue = None
        try:
            queries_queue = self.get_optimization('QUERIES_QUEUE')
        except OptimizationNotFound:
            pass

        if queries_queue and queries_queue.is_running():
            if queries_queue.enqueue_query(id):
                return Query(id, 'A charm has been sent')
            else:
                return Query(id, 'Unable to send charm: it has been enqueued')
        else:
            with self.browser:
                if not self.browser.send_charm(id):
                    raise QueryError('No enough charms available')
                return Query(id, 'A charm has been sent')

    def get_notes(self, id):
        if isinstance(id, Contact):
            id = id.id

        return self.storage.get('notes', id)

    def save_notes(self, id, notes):
        if isinstance(id, Contact):
            id = id.id

        self.storage.set('notes', id, notes)
        self.storage.save()

    # ---- ICapChat methods ---------------------

    def iter_chat_messages(self, _id=None):
        with self.browser:
            return self.browser.iter_chat_messages(_id)

    def send_chat_message(self, _id, message):
        with self.browser:
            return self.browser.send_chat_message(_id, message)

    #def start_chat_polling(self):
    #self._profile_walker = ProfilesWalker(self.weboob.scheduler, self.storage, self.browser)

    # ---- ICapAccount methods ---------------------

    ACCOUNT_REGISTER_PROPERTIES = ValuesDict(
        Value('username', label='Email address',
              regexp='^[^ ]+@[^ ]+\.[^ ]+$'),
        Value('password', label='Password', regexp='^[^ ]+$', masked=True),
        Value('sex', label='Sex', choices={
            'm': 'Male',
            'f': 'Female'
        }),
        Value('birthday',
              label='Birthday (dd/mm/yyyy)',
              regexp='^\d+/\d+/\d+$'),
        Value('zipcode', label='Zipcode'),
        Value('country',
              label='Country',
              choices={
                  'fr': 'France',
                  'be': 'Belgique',
                  'ch': 'Suisse',
                  'ca': 'Canada'
              },
              default='fr'),
        Value('godfather', label='Godfather', regexp='^\d*$', default=''),
    )

    @classmethod
    def register_account(klass, account):
        """
        Register an account on website

        This is a static method, it would be called even if the backend is
        instancied.

        @param account  an Account object which describe the account to create
        """
        browser = None
        bday, bmonth, byear = account.properties['birthday'].get().split(
            '/', 2)
        while not browser:
            try:
                browser = klass.BROWSER(account.properties['username'].get())
                browser.register(
                    password=account.properties['password'].get(),
                    sex=(0 if account.properties['sex'].get() == 'm' else 1),
                    birthday_d=int(bday),
                    birthday_m=int(bmonth),
                    birthday_y=int(byear),
                    zipcode=account.properties['zipcode'].get(),
                    country=account.properties['country'].get(),
                    godfather=account.properties['godfather'].get())
            except CaptchaError:
                getLogger('aum').info('Unable to resolve captcha. Retrying...')
                browser = None

    REGISTER_REGEXP = re.compile(
        '.*http://www.adopteunmec.com/register4.php\?([^\' ]*)\'')

    def confirm_account(self, mail):
        msg = email.message_from_string(mail)

        content = u''
        for part in msg.walk():
            s = part.get_payload(decode=True)
            content += unicode(s, 'iso-8859-15')

        url = None
        for s in content.split():
            m = self.REGISTER_REGEXP.match(s)
            if m:
                url = '/register4.php?' + m.group(1)
                break

        if url:
            browser = self.create_browser('')
            browser.openurl(url)
            return True

        return False

    def get_account(self):
        """
        Get the current account.
        """
        raise NotImplementedError()

    def update_account(self, account):
        """
        Update the current account.
        """
        raise NotImplementedError()

    def get_account_status(self):
        with self.browser:
            return (
                StatusField('myname', 'My name', self.browser.get_my_name()),
                StatusField('score', 'Score', self.browser.score()),
                StatusField('avcharms', 'Available charms',
                            self.browser.nb_available_charms()),
                StatusField('newvisits', 'New visits',
                            self.browser.nb_new_visites()),
            )

    OBJECTS = {
        Thread: fill_thread,
        Contact: fill_contact,
        ContactPhoto: fill_photo
    }
コード例 #11
0
ファイル: module.py プロジェクト: dkremer-ledger/weboob
class BNPorcModule(
    Module, CapBankWealth, CapBankTransferAddRecipient, CapMessages, CapContact, CapProfile, CapDocument
):
    NAME = 'bnporc'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '2.1'
    LICENSE = 'LGPLv3+'
    DESCRIPTION = 'BNP Paribas'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label=u'Numéro client', masked=False),
        ValueBackendPassword('password', label=u'Code secret', regexp='^(\d{6})$'),
        ValueBool('rotating_password', label=u'Automatically renew password every 100 connections', default=False),
        ValueBool('digital_key', label=u'User with digital key have to add recipient with digital key', default=False),
        Value(
            'website',
            label='Type de compte',
            default='pp',
            choices={
                'pp': 'Particuliers/Professionnels',
                'hbank': 'HelloBank',
                'ent': 'Entreprises',
                'ent2': 'Entreprises et PME (nouveau site)'
            }
        )
    )
    STORAGE = {'seen': []}

    accepted_document_types = (
        DocumentTypes.STATEMENT,
        DocumentTypes.REPORT,
        DocumentTypes.BILL,
        DocumentTypes.OTHER,
    )

    # Store the messages *list* for this duration
    CACHE_THREADS = timedelta(seconds=3 * 60 * 60)

    def __init__(self, *args, **kwargs):
        Module.__init__(self, *args, **kwargs)
        self._threads = None
        self._threads_age = datetime.utcnow()

    def create_default_browser(self):
        b = {'ent': BNPEnterprise, 'ent2': BNPCompany, 'pp': BNPPartPro, 'hbank': HelloBank}
        self.BROWSER = b[self.config['website'].get()]
        return self.create_browser(self.config)

    def iter_resources(self, objs, split_path):
        if Account in objs:
            self._restrict_level(split_path)
            return self.iter_accounts()
        if Subscription in objs:
            self._restrict_level(split_path)
            return self.iter_subscription()

    def iter_accounts(self):
        return self.browser.iter_accounts()

    def get_account(self, _id):
        account = self.browser.get_account(_id)
        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        return self.browser.iter_history(account)

    def iter_coming(self, account):
        return self.browser.iter_coming_operations(account)

    def iter_investment(self, account):
        return self.browser.iter_investment(account)

    def iter_transfer_recipients(self, origin_account):
        if self.config['website'].get() != 'pp':
            raise NotImplementedError()
        if isinstance(origin_account, Account):
            origin_account = origin_account.id
        return self.browser.iter_recipients(origin_account)

    def new_recipient(self, recipient, **params):
        if self.config['website'].get() != 'pp':
            raise NotImplementedError()
        # Recipient label has max 70 chars.
        recipient.label = ' '.join(w for w in re.sub('[^0-9a-zA-Z-,\.: ]+', '', recipient.label).split())[:70]
        return self.browser.new_recipient(recipient, **params)

    def init_transfer(self, transfer, **params):
        if self.config['website'].get() != 'pp':
            raise NotImplementedError()

        if transfer.label is None:
            raise TransferInvalidLabel()

        self.logger.info('Going to do a new transfer')
        if transfer.account_iban:
            account = find_object(self.iter_accounts(), iban=transfer.account_iban, error=AccountNotFound)
        else:
            account = find_object(self.iter_accounts(), id=transfer.account_id, error=AccountNotFound)

        recipient = strict_find_object(self.iter_transfer_recipients(account.id), iban=transfer.recipient_iban)
        if not recipient:
            recipient = strict_find_object(
                self.iter_transfer_recipients(account.id), id=transfer.recipient_id, error=RecipientNotFound
            )

        assert account.id.isdigit()
        # quantize to show 2 decimals.
        amount = Decimal(transfer.amount).quantize(Decimal(10) ** -2)

        return self.browser.init_transfer(account, recipient, amount, transfer.label, transfer.exec_date)

    def execute_transfer(self, transfer, **params):
        return self.browser.execute_transfer(transfer)

    def transfer_check_recipient_id(self, old, new):
        # external recipient id can change, check the iban in recipient id
        iban = re.search(r'([A-Z]{2}[A-Z\d]+)', old)
        if iban:
            # external recipients id
            iban = iban.group(1)
            return iban in new
        else:
            # iternal recipients id
            return old == new

    def iter_contacts(self):
        if not hasattr(self.browser, 'get_advisor'):
            raise NotImplementedError()

        for advisor in self.browser.get_advisor():
            yield advisor

    def get_profile(self):
        if not hasattr(self.browser, 'get_profile'):
            raise NotImplementedError()
        return self.browser.get_profile()

    def iter_threads(self, cache=False):
        """
        If cache is False, always fetch the threads from the website.
        """
        old = self._threads_age < datetime.utcnow() - self.CACHE_THREADS
        threads = self._threads
        if not cache or threads is None or old:
            threads = list(self.browser.iter_threads())
            # the website is stupid and does not have the messages in the proper order
            threads = sorted(threads, key=lambda t: t.date, reverse=True)
            self._threads = threads
        seen = self.storage.get('seen', default=[])
        for thread in threads:
            if thread.id not in seen:
                thread.root.flags |= thread.root.IS_UNREAD
            else:
                thread.root.flags &= ~thread.root.IS_UNREAD
            yield thread

    def fill_thread(self, thread, fields=None):
        if fields is None or 'root' in fields:
            return self.get_thread(thread)

    def get_thread(self, _id):
        if self.config['website'].get() != 'ppold':
            raise NotImplementedError()

        if isinstance(_id, Thread):
            thread = _id
            _id = thread.id
        else:
            thread = Thread(_id)
        thread = self.browser.get_thread(thread)
        return thread

    def iter_unread_messages(self):
        if self.config['website'].get() != 'ppold':
            raise NotImplementedError()

        threads = list(self.iter_threads(cache=True))
        for thread in threads:
            if thread.root.flags & thread.root.IS_UNREAD:
                thread = self.fillobj(thread) or thread
                yield thread.root

    def set_message_read(self, message):
        self.storage.get('seen', default=[]).append(message.thread.id)
        self.storage.save()

    def get_subscription(self, _id):
        return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound)

    def iter_documents(self, subscription):
        if not isinstance(subscription, Subscription):
            subscription = self.get_subscription(subscription)

        return self.browser.iter_documents(subscription)

    def iter_subscription(self):
        return self.browser.iter_subscription()

    def get_document(self, _id):
        subscription_id = _id.split('_')[0]
        subscription = self.get_subscription(subscription_id)
        return find_object(self.iter_documents(subscription), id=_id, error=DocumentNotFound)

    def download_document(self, document):
        if not isinstance(document, Document):
            document = self.get_document(document)

        return self.browser.open(document.url).content

    OBJECTS = {Thread: fill_thread}
コード例 #12
0
class OkCModule(Module, CapMessages, CapContact, CapMessagesPost, CapDating):
    NAME = 'okc'
    MAINTAINER = u'Roger Philibert'
    EMAIL = '*****@*****.**'
    VERSION = '2.1'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'OkCupid'
    CONFIG = BackendConfig(
        Value('username', label='Username'),
        ValueBackendPassword('password', label='Password'),
        ValueBool('facebook',
                  label='Do you login with Facebook?',
                  default=False))
    STORAGE = {
        'profiles_walker': {
            'viewed': []
        },
        's***s': {},
    }
    BROWSER = OkCBrowser

    def create_default_browser(self):
        if int(self.config['facebook'].get()):
            facebook = self.create_browser(klass=FacebookBrowser)
            facebook.login(self.config['username'].get(),
                           self.config['password'].get())
        else:
            facebook = None
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get(), facebook)

    # ---- CapDating methods ---------------------
    def init_optimizations(self):
        self.add_optimization(
            'PROFILE_WALKER',
            ProfilesWalker(self.weboob.scheduler, self.storage, self.browser))

    # ---- CapMessages methods ---------------------
    def fill_thread(self, thread, fields):
        return self.get_thread(thread)

    def iter_threads(self):
        threads = self.browser.get_threads_list()

        for thread in threads:
            t = Thread(thread['user']['userid'])
            t.flags = Thread.IS_DISCUSSION
            t.title = u'Discussion with %s' % thread['user']['userinfo'][
                'displayname']
            t.date = datetime.fromtimestamp(thread['time'])
            yield t

    def get_thread(self, thread):
        if not isinstance(thread, Thread):
            thread = Thread(thread)
            thread.flags = Thread.IS_DISCUSSION

        messages = self.browser.get_thread_messages(thread.id)

        contact = self.storage.get('s***s',
                                   thread.id,
                                   default={'lastmsg': datetime(1970, 1, 1)})
        thread.title = u'Discussion with %s' % messages['fields']['username']

        me = OkcContact(self.browser.get_profile(self.browser.me['userid']))
        other = OkcContact(self.browser.get_profile(thread.id))

        parent = None
        for message in messages['messages']:
            date = datetime.fromtimestamp(message['timestamp'])

            flags = 0
            if contact['lastmsg'] < date:
                flags = Message.IS_UNREAD

            if message['from'] == thread.id:
                sender = other
                receiver = me
            else:
                receiver = other
                sender = me
                if message.get('read', False):
                    flags |= Message.IS_RECEIVED
                    # Apply that flag on all previous messages as the 'read'
                    # attribute is only set on the last read message.
                    pmsg = parent
                    while pmsg:
                        if pmsg.flags & Message.IS_NOT_RECEIVED:
                            pmsg.flags |= Message.IS_RECEIVED
                            pmsg.flags &= ~Message.IS_NOT_RECEIVED
                        pmsg = pmsg.parent
                else:
                    flags |= Message.IS_NOT_RECEIVED

            msg = Message(thread=thread,
                          id=message['id'],
                          title=thread.title,
                          sender=sender.name,
                          receivers=[receiver.name],
                          date=date,
                          content=to_unicode(HTMLParser().unescape(
                              message['body'])),
                          children=[],
                          parent=parent,
                          signature=sender.get_text(),
                          flags=flags)

            if parent:
                parent.children = [msg]
            else:
                thread.root = msg

            parent = msg

        return thread

    def iter_unread_messages(self):
        for thread in self.iter_threads():
            contact = self.storage.get(
                's***s', thread.id, default={'lastmsg': datetime(1970, 1, 1)})
            if thread.date <= contact['lastmsg']:
                continue

            thread = self.get_thread(thread)
            for message in thread.iter_all_messages():
                if message.flags & message.IS_UNREAD:
                    yield message

    def set_message_read(self, message):
        contact = self.storage.get('s***s',
                                   message.thread.id,
                                   default={'lastmsg': datetime(1970, 1, 1)})
        if contact['lastmsg'] < message.date:
            contact['lastmsg'] = message.date
            self.storage.set('s***s', message.thread.id, contact)
            self.storage.save()

    # ---- CapMessagesPost methods ---------------------
    def post_message(self, message):
        self.browser.post_message(message.thread.id, message.content)

    # ---- CapContact methods ---------------------
    def fill_contact(self, contact, fields):
        if 'profile' in fields:
            contact = self.get_contact(contact)
        if contact and 'photos' in fields:
            for name, photo in contact.photos.items():
                if photo.url and not photo.data:
                    data = self.browser.open(photo.url).content
                    contact.set_photo(name, data=data)
                if photo.thumbnail_url and not photo.thumbnail_data:
                    data = self.browser.open(photo.thumbnail_url).content
                    contact.set_photo(name, thumbnail_data=data)

    def fill_photo(self, photo, fields):
        if 'data' in fields and photo.url and not photo.data:
            photo.data = self.browser.open(photo.url).content
        if 'thumbnail_data' in fields and photo.thumbnail_url and not photo.thumbnail_data:
            photo.thumbnail_data = self.browser.open(
                photo.thumbnail_url).content
        return photo

    def get_contact(self, user_id):
        if isinstance(user_id, Contact):
            user_id = user_id.id

        info = self.browser.get_profile(user_id)

        return OkcContact(info)

    def iter_contacts(self, status=Contact.STATUS_ALL, ids=None):
        threads = self.browser.get_threads_list()

        for thread in threads:
            c = self.get_contact(thread['user']['username'])
            if c and (c.status & status) and (not ids or c.id in ids):
                yield c

    OBJECTS = {
        Thread: fill_thread,
        Contact: fill_contact,
        ContactPhoto: fill_photo
    }
コード例 #13
0
ファイル: backend.py プロジェクト: eirmag/weboob
class CmbBackend(BaseBackend, ICapBank):
    NAME = 'cmb'
    MAINTAINER = u'Johann Broudin'
    EMAIL = '*****@*****.**'
    VERSION = '0.e'
    LICENSE = 'AGPLv3+'
    AUTH_CERT = os.path.dirname(__file__)
    AUTH_CERT += '/Verisign_Class_3_Public_Primary_Certification_Authority.pem'
    CERTHASH = '684d79eb02f59497b5a9c5dcc4c26db1ee637db12f29d703fdf6a80aafef892d'
    DESCRIPTION = u'Crédit Mutuel de Bretagne French bank website'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label='Account ID', masked=False),
        ValueBackendPassword('password', label='Password', masked=True),
        ValueBool('no_check', label='SSL Check ?', default=True))
    LABEL_PATTERNS = [
        (  # card
            compile('^CARTE (?P<text>.*)'), Transaction.TYPE_CARD, '%(text)s'),
        (  # order
            compile('^PRLV (?P<text>.*)'), Transaction.TYPE_ORDER, '%(text)s'),
        (  # withdrawal
            compile('^RET DAB (?P<text>.*)'), Transaction.TYPE_WITHDRAWAL,
            '%(text)s'),
        (  # loan payment
            compile('^ECH (?P<text>.*)'), Transaction.TYPE_LOAN_PAYMENT,
            '%(text)s'),
        (  # transfer
            compile('^VIR (?P<text>.*)'), Transaction.TYPE_TRANSFER,
            '%(text)s'),
        (  # payback
            compile('^ANN (?P<text>.*)'), Transaction.TYPE_PAYBACK,
            '%(text)s'),
        (  # bank
            compile('^F (?P<text>.*)'), Transaction.TYPE_BANK, '%(text)s')
    ]

    cookie = None
    headers = {
        'User-Agent':
        'Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OSX; en-us) ' +
        'AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405'
    }

    def sslCallBack(self, cert):
        pemcert = DER_cert_to_PEM_cert(cert)
        certhash = sha256(pemcert).hexdigest()
        return certhash == self.CERTHASH

    def login(self):
        params = urlencode({
            'codeEspace': 'NO',
            'codeEFS': '01',
            'codeSi': '001',
            'noPersonne': self.config['login'].get(),
            'motDePasse': self.config['password'].get()
        })
        if 'no_check' in self.config and self.config['no_check'].get() == "y":
            conn = HellHTTPS("www.cmb.fr")
        else:
            conn = HellHTTPS("www.cmb.fr",
                             ca_file=self.AUTH_CERT,
                             callBack=self.sslCallBack)
        conn.connect()
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        conn.request("POST", "/domiweb/servlet/Identification", params,
                     headers)
        response = conn.getresponse()
        conn.close()
        if response.status == 302:
            self.cookie = response.getheader('Set-Cookie').split(';')[0]
            self.cookie += ';'
            return True
        else:
            raise BrowserIncorrectPassword()
        return False

    def iter_accounts(self):
        if not self.cookie:
            self.login()

        def do_http():
            if 'no_check' in self.config and self.config['no_check'].get(
            ) == "y":
                conn = HellHTTPS("www.cmb.fr")
            else:
                conn = HellHTTPS("www.cmb.fr",
                                 ca_file=self.AUTH_CERT,
                                 callBack=self.sslCallBack)
            conn.connect()
            headers = self.headers
            headers['Cookie'] = self.cookie
            conn.request("GET",
                         '/domiweb/prive/particulier/releve/0-releve.act', {},
                         headers)
            response = conn.getresponse()
            data = response.read()
            conn.close()
            return data

        data = do_http()
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        table = tree.xpath('/html/body/table')
        if len(table) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = do_http()

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                table = tree.xpath('/html/body/table')
                if len(table) == 0:
                    raise BrokenPageError()
            else:
                raise BrokenPageError()

        for tr in table[1].getiterator('tr'):
            if tr.get('class') != 'LnTit' and tr.get('class') != 'LnTot':
                account = Account()
                td = tr.xpath('td')

                a = td[1].xpath('a')
                account.label = unicode(a[0].text).strip()
                href = a[0].get('href')
                m = match(r"javascript:releve\((.*),'(.*)','(.*)'\)", href)
                if not m:
                    continue
                account.id = unicode(m.group(1) + m.group(2) + m.group(3))
                account._cmbvaleur = m.group(1)
                account._cmbvaleur2 = m.group(2)
                account._cmbtype = m.group(3)

                balance = td[2].text
                balance = balance.replace(',', '.').replace(u"\xa0", '')
                account.balance = Decimal(balance)

                span = td[4].xpath('a/span')
                if len(span):
                    coming = span[0].text.replace(' ', '').replace(',', '.')
                    coming = coming.replace(u"\xa0", '')
                    account.coming = Decimal(coming)
                else:
                    account.coming = NotAvailable

                yield account

    def get_account(self, _id):
        for account in self.iter_accounts():
            if account.id == _id:
                return account

        raise AccountNotFound()

    def iter_history(self, account):
        if not self.cookie:
            self.login()

        page = "/domiweb/prive/particulier/releve/"
        if account._cmbtype == 'D':
            page += "10-releve.act"
        else:
            page += "2-releve.act"
        page += "?noPageReleve=1&indiceCompte="
        page += account._cmbvaleur
        page += "&typeCompte="
        page += account._cmbvaleur2
        page += "&deviseOrigineEcran=EUR"

        def do_http():
            if 'no_check' in self.config and self.config['no_check'].get(
            ) == "y":
                conn = HellHTTPS("www.cmb.fr")
            else:
                conn = HellHTTPS("www.cmb.fr",
                                 ca_file=self.AUTH_CERT,
                                 callBack=self.sslCallBack)
            conn.connect()
            headers = self.headers
            headers['Cookie'] = self.cookie
            conn.request("GET", page, {}, headers)
            response = conn.getresponse()
            data = response.read()
            conn.close
            return data

        data = do_http()
        parser = etree.HTMLParser()
        tree = etree.parse(StringIO(data), parser)

        tables = tree.xpath('/html/body/table')
        if len(tables) == 0:
            title = tree.xpath('/html/head/title')[0].text
            if title == u"Utilisateur non identifié":
                self.login()
                data = do_http()

                parser = etree.HTMLParser()
                tree = etree.parse(StringIO(data), parser)
                tables = tree.xpath('/html/body/table')
                if len(tables) == 0:
                    raise BrokenPageError()
            else:
                raise BrokenPageError()

        i = 0

        for table in tables:
            if table.get('id') != "tableMouvements":
                continue
            for tr in table.getiterator('tr'):
                if (tr.get('class') != 'LnTit' and tr.get('class') != 'LnTot'):
                    operation = Transaction(i)
                    td = tr.xpath('td')

                    div = td[1].xpath('div')
                    d = div[0].text.split('/')
                    operation.date = date(*reversed([int(x) for x in d]))

                    div = td[2].xpath('div')
                    label = div[0].xpath('a')[0].text.replace('\n', '')
                    operation.raw = unicode(' '.join(label.split()))
                    for pattern, _type, _label in self.LABEL_PATTERNS:
                        mm = pattern.match(operation.raw)
                        if mm:
                            operation.type = _type
                            operation.label = sub('[ ]+', ' ', _label %
                                                  mm.groupdict()).strip()
                            break

                    amount = td[3].text
                    if amount.count(',') != 1:
                        amount = td[4].text
                        amount = amount.replace(',', '.').replace(u'\xa0', '')
                        operation.amount = Decimal(amount)
                    else:
                        amount = amount.replace(',', '.').replace(u'\xa0', '')
                        operation.amount = -Decimal(amount)

                    i += 1
                    yield operation
コード例 #14
0
class AuMBackend(BaseBackend, ICapMessages, ICapMessagesPost, ICapDating,
                 ICapChat, ICapContact, ICapAccount):
    NAME = 'aum'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '0.e'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'"Adopte un Mec" French dating website'
    CONFIG = BackendConfig(
        Value('username', label='Username'),
        ValueBackendPassword('password', label='Password'),
        ValueBool('antispam', label='Enable anti-spam', default=False),
        ValueBool('baskets',
                  label='Get baskets with new messages',
                  default=True),
        Value('search_query', label='Search query', default=''))
    STORAGE = {
        'profiles_walker': {
            'viewed': []
        },
        'queries_queue': {
            'queue': []
        },
        's***s': {},
        'notes': {},
    }
    BROWSER = AuMBrowser

    MAGIC_ID_BASKET = 1

    def __init__(self, *args, **kwargs):
        BaseBackend.__init__(self, *args, **kwargs)
        if self.config['antispam'].get():
            self.antispam = AntiSpam()
        else:
            self.antispam = None

    def create_default_browser(self):
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get(),
                                   self.config['search_query'].get())

    def report_spam(self, id):
        with self.browser:
            pass
            #self.browser.delete_thread(id)
            # Do not report fakes to website, to let them to other guys :)
            #self.browser.report_fake(id)

    # ---- ICapDating methods ---------------------

    def init_optimizations(self):
        self.add_optimization(
            'PROFILE_WALKER',
            ProfilesWalker(self.weboob.scheduler, self.storage, self.browser))
        self.add_optimization('VISIBILITY',
                              Visibility(self.weboob.scheduler, self.browser))
        self.add_optimization(
            'QUERIES_QUEUE',
            QueriesQueue(self.weboob.scheduler, self.storage, self.browser))

    def iter_events(self):
        all_events = {}
        with self.browser:
            all_events[u'baskets'] = (self.browser.get_baskets,
                                      'You were put into %s\'s basket')
            all_events[u'flashs'] = (self.browser.get_flashs,
                                     'You sent a charm to %s')
            all_events[u'visits'] = (self.browser.get_visits, 'Visited by %s')
        for type, (events, message) in all_events.iteritems():
            for event in events():
                e = Event(event['who']['id'])

                e.date = parse_dt(event['date'])
                e.type = type
                if 'who' in event:
                    e.contact = self._get_partial_contact(event['who'])
                else:
                    e.contact = self._get_partial_contact(event)

                if not e.contact:
                    continue

                e.message = message % e.contact.name
                yield e

    # ---- ICapMessages methods ---------------------

    def fill_thread(self, thread, fields):
        return self.get_thread(thread)

    def iter_threads(self):
        with self.browser:
            threads = self.browser.get_threads_list()

        for thread in threads:
            #if thread['member'].get('isBan', thread['member'].get('dead', False)):
            #    with self.browser:
            #        self.browser.delete_thread(thread['member']['id'])
            #    continue
            if self.antispam and not self.antispam.check_thread(thread):
                self.logger.info('Skipped a spam-thread from %s' %
                                 thread['pseudo'])
                self.report_spam(thread['who']['id'])
                continue
            t = Thread(int(thread['who']['id']))
            t.flags = Thread.IS_DISCUSSION
            t.title = u'Discussion with %s' % to_unicode(
                thread['who']['pseudo'])
            yield t

    def get_thread(self, id, contacts=None, get_profiles=False):
        """
        Get a thread and its messages.

        The 'contacts' parameters is only used for internal calls.
        """
        thread = None
        if isinstance(id, Thread):
            thread = id
            id = thread.id

        if not thread:
            thread = Thread(int(id))
            thread.flags = Thread.IS_DISCUSSION
            full = False
        else:
            full = True

        with self.browser:
            mails = self.browser.get_thread_mails(id, 100)
            my_name = self.browser.get_my_name()

        child = None
        msg = None
        s**t = self._get_slut(id)
        if contacts is None:
            contacts = {}

        if not thread.title:
            thread.title = u'Discussion with %s' % mails['who']['pseudo']

        self.storage.set('s***s', int(thread.id), 'status', mails['status'])
        self.storage.save()

        for mail in mails['results']:
            flags = 0
            if self.antispam and not self.antispam.check_mail(mail):
                self.logger.info('Skipped a spam-mail from %s' %
                                 mails['who']['pseudo'])
                self.report_spam(thread.id)
                break

            if parse_dt(mail['date']) > s**t['lastmsg']:
                flags |= Message.IS_UNREAD

                if get_profiles:
                    if not mail['from'] in contacts:
                        with self.browser:
                            contacts[mail['from']] = self.get_contact(
                                mail['from'])
                    if self.antispam and not self.antispam.check_contact(
                            contacts[mail['from']]):
                        self.logger.info(
                            'Skipped a spam-mail-profile from %s' %
                            mails['who']['pseudo'])
                        self.report_spam(thread.id)
                        break

            if int(mail['from']) == self.browser.my_id:
                if mails['remote_status'] == 'new' and msg is None:
                    flags |= Message.IS_NOT_RECEIVED
                else:
                    flags |= Message.IS_RECEIVED

            signature = u''
            #if mail.get('src', None):
            #    signature += u'Sent from my %s\n\n' % mail['src']
            if mail['from'] in contacts:
                signature += contacts[mail['from']].get_text()

            msg = Message(
                thread=thread,
                id=int(
                    time.strftime('%Y%m%d%H%M%S',
                                  parse_dt(mail['date']).timetuple())),
                title=thread.title,
                sender=to_unicode(my_name if int(mail['from']) == self.browser.
                                  my_id else mails['who']['pseudo']),
                receivers=[
                    to_unicode(my_name if int(mail['from']) != self.browser.
                               my_id else mails['who']['pseudo'])
                ],
                date=parse_dt(mail['date']),
                content=to_unicode(unescape(mail['message'] or '').strip()),
                signature=signature,
                children=[],
                flags=flags)
            if child:
                msg.children.append(child)
                child.parent = msg

            child = msg

        if full and msg:
            # If we have get all the messages, replace NotLoaded with None as
            # parent.
            msg.parent = None
        if not full and not msg:
            # Perhaps there are hidden messages
            msg = NotLoaded

        thread.root = msg

        return thread

    def iter_unread_messages(self):
        try:
            contacts = {}
            with self.browser:
                threads = self.browser.get_threads_list()
            for thread in threads:
                #if thread['member'].get('isBan', thread['member'].get('dead', False)):
                #    with self.browser:
                #        self.browser.delete_thread(int(thread['member']['id']))
                #    continue
                if self.antispam and not self.antispam.check_thread(thread):
                    self.logger.info('Skipped a spam-unread-thread from %s' %
                                     thread['who']['pseudo'])
                    self.report_spam(thread['member']['id'])
                    continue
                s**t = self._get_slut(thread['who']['id'])
                if parse_dt(
                        thread['date']
                ) > s**t['lastmsg'] or thread['status'] != s**t['status']:
                    t = self.get_thread(thread['who']['id'],
                                        contacts,
                                        get_profiles=True)
                    for m in t.iter_all_messages():
                        if m.flags & m.IS_UNREAD:
                            yield m

            if not self.config['baskets'].get():
                return

            # Send mail when someone added me in her basket.
            # XXX possibly race condition if a s**t adds me in her basket
            #     between the aum.nb_new_baskets() and aum.get_baskets().
            with self.browser:
                s**t = self._get_slut(-self.MAGIC_ID_BASKET)

                new_baskets = self.browser.nb_new_baskets()
                if new_baskets > 0:
                    baskets = self.browser.get_baskets()
                    my_name = self.browser.get_my_name()
                    for basket in baskets:
                        if parse_dt(basket['date']) <= s**t['lastmsg']:
                            continue
                        contact = self.get_contact(basket['id'])
                        if self.antispam and not self.antispam.check_contact(
                                contact):
                            self.logger.info('Skipped a spam-basket from %s' %
                                             contact.name)
                            self.report_spam(basket['id'])
                            continue

                        thread = Thread(int(basket['id']))
                        thread.title = 'Basket of %s' % contact.name
                        thread.root = Message(
                            thread=thread,
                            id=self.MAGIC_ID_BASKET,
                            title=thread.title,
                            sender=contact.name,
                            receivers=[my_name],
                            date=parse_dt(basket['date']),
                            content='You are taken in her basket!',
                            signature=contact.get_text(),
                            children=[],
                            flags=Message.IS_UNREAD)
                        yield thread.root
        except BrowserUnavailable, e:
            self.logger.debug('No messages, browser is unavailable: %s' % e)
            pass  # don't care about waiting
コード例 #15
0
class AuMModule(Module, CapMessages, CapMessagesPost, CapDating, CapChat,
                CapContact, CapAccount):
    NAME = 'aum'
    MAINTAINER = u'Romain Bignon'
    EMAIL = '*****@*****.**'
    VERSION = '2.1'
    LICENSE = 'AGPLv3+'
    DESCRIPTION = u'"Adopte un Mec" French dating website'
    CONFIG = BackendConfig(
        Value('username', label='Username'),
        ValueBackendPassword('password', label='Password'),
        ValueBool('antispam', label='Enable anti-spam', default=False),
        ValueBool('baskets',
                  label='Get baskets with new messages',
                  default=True),
        Value('search_query', label='Search query', default=''))
    STORAGE = {
        'profiles_walker': {
            'viewed': []
        },
        'queries_queue': {
            'queue': []
        },
        'contacts': {},
        'notes': {},
    }
    BROWSER = AuMBrowser

    MAGIC_ID_BASKET = 1

    def __init__(self, *args, **kwargs):
        Module.__init__(self, *args, **kwargs)
        if self.config['antispam'].get():
            self.antispam = AntiSpam()
        else:
            self.antispam = None

    def create_default_browser(self):
        return self.create_browser(self.config['username'].get(),
                                   self.config['password'].get(),
                                   self.config['search_query'].get())

    def report_spam(self, id):
        pass
        #self.browser.delete_thread(id)
        # Do not report fakes to website, to let them to other guys :)
        #self.browser.report_fake(id)

    # ---- CapDating methods ---------------------

    def init_optimizations(self):
        self.add_optimization(
            'PROFILE_WALKER',
            ProfilesWalker(self.weboob.scheduler, self.storage, self.browser))
        self.add_optimization('VISIBILITY',
                              Visibility(self.weboob.scheduler, self.browser))
        self.add_optimization(
            'QUERIES_QUEUE',
            QueriesQueue(self.weboob.scheduler, self.storage, self.browser))

    def iter_events(self):
        all_events = {}
        all_events[u'baskets'] = (self.browser.get_baskets,
                                  'You were put into %s\'s basket')
        all_events[u'flashs'] = (self.browser.get_flashs,
                                 'You sent a charm to %s')
        all_events[u'visits'] = (self.browser.get_visits, 'Visited by %s')
        for type, (events, message) in all_events.items():
            for event in events():
                e = Event(event['who']['id'])

                e.date = parse_dt(event['date'])
                e.type = type
                if 'who' in event:
                    e.contact = self._get_partial_contact(event['who'])
                else:
                    e.contact = self._get_partial_contact(event)

                if not e.contact:
                    continue

                e.message = message % e.contact.name
                yield e

    def iter_new_contacts(self):
        for _id in self.browser.search_profiles(
        ):  #.difference(self.OPTIM_PROFILE_WALKER.visited_profiles):
            contact = Contact(_id, '', 0)
            yield contact

    # ---- CapMessages methods ---------------------

    def fill_thread(self, thread, fields):
        return self.get_thread(thread)

    def iter_threads(self):
        threads = self.browser.get_threads_list()

        for thread in threads:
            #if thread['member'].get('isBan', thread['member'].get('dead', False)):
            #    self.browser.delete_thread(thread['member']['id'])
            #    continue
            if self.antispam and not self.antispam.check_thread(thread):
                self.logger.info('Skipped a spam-thread from %s' %
                                 thread['pseudo'])
                self.report_spam(thread['who']['id'])
                continue
            t = Thread(int(thread['who']['id']))
            t.flags = Thread.IS_DISCUSSION
            t.title = u'Discussion with %s' % to_unicode(
                thread['who']['pseudo'])
            yield t

    def get_thread(self, id, contacts=None, get_profiles=False):
        """
        Get a thread and its messages.

        The 'contacts' parameters is only used for internal calls.
        """
        thread = None
        if isinstance(id, Thread):
            thread = id
            id = thread.id

        if not thread:
            thread = Thread(int(id))
            thread.flags = Thread.IS_DISCUSSION
            full = False
        else:
            full = True

        mails = self.browser.get_thread_mails(id, 100)
        my_name = self.browser.get_my_name()

        child = None
        msg = None
        contact = self._get_contact(id)
        if contacts is None:
            contacts = {}

        if not thread.title:
            thread.title = u'Discussion with %s' % mails['who']['pseudo']

        self.storage.set('contacts', int(thread.id), 'status', mails['status'])
        self.storage.save()

        for mail in mails['results']:
            flags = 0
            if self.antispam and not self.antispam.check_mail(mail):
                self.logger.info('Skipped a spam-mail from %s' %
                                 mails['who']['pseudo'])
                self.report_spam(thread.id)
                break

            if parse_dt(mail['date']) > contact['lastmsg']:
                flags |= Message.IS_UNREAD

                if get_profiles:
                    if mail['from'] not in contacts:
                        try:
                            contacts[mail['from']] = self.get_contact(
                                mail['from'])
                        except BrowserHTTPNotFound:
                            pass
                    if self.antispam and mail[
                            'from'] in contacts and not self.antispam.check_contact(
                                contacts[mail['from']]):
                        self.logger.info(
                            'Skipped a spam-mail-profile from %s' %
                            mails['who']['pseudo'])
                        self.report_spam(thread.id)
                        break

            if int(mail['from']) == self.browser.my_id:
                if mails['remote_status'] == 'new' and msg is None:
                    flags |= Message.IS_NOT_RECEIVED
                else:
                    flags |= Message.IS_RECEIVED

            signature = u''
            #if mail.get('src', None):
            #    signature += u'Sent from my %s\n\n' % mail['src']
            if mail['from'] in contacts:
                signature += contacts[mail['from']].get_text()

            msg = Message(
                thread=thread,
                id=int(
                    time.strftime('%Y%m%d%H%M%S',
                                  parse_dt(mail['date']).timetuple())),
                title=thread.title,
                sender=to_unicode(my_name if int(mail['from']) == self.browser.
                                  my_id else mails['who']['pseudo']),
                receivers=[
                    to_unicode(my_name if int(mail['from']) != self.browser.
                               my_id else mails['who']['pseudo'])
                ],
                date=parse_dt(mail['date']),
                content=to_unicode(HTMLParser().unescape(mail['message']
                                                         or '').strip()),
                signature=signature,
                children=[],
                flags=flags)
            if child:
                msg.children.append(child)
                child.parent = msg

            child = msg

        if full and msg:
            # If we have get all the messages, replace NotLoaded with None as
            # parent.
            msg.parent = None
        if not full and not msg:
            # Perhaps there are hidden messages
            msg = NotLoaded

        thread.root = msg

        return thread

    def iter_unread_messages(self):
        try:
            contacts = {}
            threads = self.browser.get_threads_list()
            for thread in threads:
                #if thread['member'].get('isBan', thread['member'].get('dead', False)):
                #    self.browser.delete_thread(int(thread['member']['id']))
                #    continue
                if self.antispam and not self.antispam.check_thread(thread):
                    self.logger.info('Skipped a spam-unread-thread from %s' %
                                     thread['who']['pseudo'])
                    self.report_spam(thread['member']['id'])
                    continue
                contact = self._get_contact(thread['who']['id'])
                if parse_dt(thread['date']) > contact['lastmsg'] or thread[
                        'status'] != contact['status']:
                    try:
                        t = self.get_thread(thread['who']['id'],
                                            contacts,
                                            get_profiles=True)
                    except BrowserUnavailable:
                        continue
                    for m in t.iter_all_messages():
                        if m.flags & m.IS_UNREAD:
                            yield m

            if not self.config['baskets'].get():
                return

            # Send mail when someone added me in her basket.
            # XXX possibly race condition if a contact adds me in her basket
            #     between the aum.nb_new_baskets() and aum.get_baskets().
            contact = self._get_contact(-self.MAGIC_ID_BASKET)

            new_baskets = self.browser.nb_new_baskets()
            if new_baskets > 0:
                baskets = self.browser.get_baskets()
                my_name = self.browser.get_my_name()
                for basket in baskets:
                    if parse_dt(basket['date']) <= contact['lastmsg']:
                        continue
                    contact = self.get_contact(basket['who']['id'])
                    if self.antispam and not self.antispam.check_contact(
                            contact):
                        self.logger.info('Skipped a spam-basket from %s' %
                                         contact.name)
                        self.report_spam(basket['who']['id'])
                        continue

                    thread = Thread(int(basket['who']['id']))
                    thread.title = 'Basket of %s' % contact.name
                    thread.root = Message(
                        thread=thread,
                        id=self.MAGIC_ID_BASKET,
                        title=thread.title,
                        sender=contact.name,
                        receivers=[my_name],
                        date=parse_dt(basket['date']),
                        content='You are taken in her basket!',
                        signature=contact.get_text(),
                        children=[],
                        flags=Message.IS_UNREAD)
                    yield thread.root
        except BrowserUnavailable as e:
            self.logger.debug('No messages, browser is unavailable: %s' % e)
            pass  # don't care about waiting

    def set_message_read(self, message):
        if int(message.id) == self.MAGIC_ID_BASKET:
            # Save the last baskets checks.
            contact = self._get_contact(-self.MAGIC_ID_BASKET)
            if contact['lastmsg'] < message.date:
                contact['lastmsg'] = message.date
                self.storage.set('contacts', -self.MAGIC_ID_BASKET, contact)
                self.storage.save()
            return

        contact = self._get_contact(message.thread.id)
        if contact['lastmsg'] < message.date:
            contact['lastmsg'] = message.date
            self.storage.set('contacts', int(message.thread.id), contact)
            self.storage.save()

    def _get_contact(self, id):
        id = int(id)
        contacts = self.storage.get('contacts')
        if not contacts or id not in contacts:
            contacts = self.storage.get(b64decode('c2x1dHM='))
        if not contacts or id not in contacts:
            contact = {
                'lastmsg': datetime.datetime(1970, 1, 1),
                'status': None
            }
        else:
            contact = contacts[id]

        contact['lastmsg'] = contact.get(
            'lastmsg', datetime.datetime(1970, 1,
                                         1)).replace(tzinfo=tz.tzutc())
        contact['status'] = contact.get('status', None)
        return contact

    # ---- CapMessagesPost methods ---------------------

    def post_message(self, message):
        self.browser.post_mail(message.thread.id, message.content)

    # ---- CapContact methods ---------------------

    def fill_contact(self, contact, fields):
        if 'profile' in fields:
            contact = self.get_contact(contact)
        if contact and 'photos' in fields:
            for name, photo in contact.photos.items():
                if photo.url and not photo.data:
                    data = self.browser.openurl(photo.url).read()
                    contact.set_photo(name, data=data)
                if photo.thumbnail_url and not photo.thumbnail_data:
                    data = self.browser.openurl(photo.thumbnail_url).read()
                    contact.set_photo(name, thumbnail_data=data)

    def fill_photo(self, photo, fields):
        if 'data' in fields and photo.url and not photo.data:
            photo.data = self.browser.open(photo.url).content
        if 'thumbnail_data' in fields and photo.thumbnail_url and not photo.thumbnail_data:
            photo.thumbnail_data = self.browser.open(
                photo.thumbnail_url).content
        return photo

    def get_contact(self, contact):
        if isinstance(contact, Contact):
            _id = contact.id
        elif isinstance(contact, (int, long, basestring)):
            _id = contact
        else:
            raise TypeError(
                "The parameter 'contact' isn't a contact nor a int/long/str/unicode: %s"
                % contact)

        profile = self.browser.get_full_profile(_id)
        if not profile:
            return None

        _id = profile['id']

        if isinstance(contact, Contact):
            contact.id = _id
            contact.name = profile['pseudo']
        else:
            contact = Contact(_id, profile['pseudo'], Contact.STATUS_ONLINE)
        contact.url = self.browser.id2url(_id)
        contact.parse_profile(profile, self.browser.get_consts())
        return contact

    def _get_partial_contact(self, contact):
        s = 0
        if contact.get('online', False):
            s = Contact.STATUS_ONLINE
        else:
            s = Contact.STATUS_OFFLINE

        c = Contact(contact['id'], to_unicode(contact['pseudo']), s)
        c.url = self.browser.id2url(contact['id'])
        if 'age' in contact:
            c.status_msg = u'%s old, %s' % (contact['age'], contact['city'])
        if contact['cover'] is not None:
            url = contact['cover'] + '/%(type)s'
        else:
            url = u'http://s.adopteunmec.com/www/img/thumb0.jpg'

        c.set_photo(u'image%s' % contact['cover'],
                    url=url % {'type': 'full'},
                    thumbnail_url=url % {'type': 'small'})
        return c

    def iter_contacts(self, status=Contact.STATUS_ALL, ids=None):
        threads = self.browser.get_threads_list(count=100)

        for thread in threads:
            c = self._get_partial_contact(thread['who'])
            if c and (c.status & status) and (not ids or c.id in ids):
                yield c

    def send_query(self, id):
        if isinstance(id, Contact):
            id = id.id

        queries_queue = None
        try:
            queries_queue = self.get_optimization('QUERIES_QUEUE')
        except OptimizationNotFound:
            pass

        if queries_queue and queries_queue.is_running():
            if queries_queue.enqueue_query(id):
                return Query(id, 'A charm has been sent')
            else:
                return Query(id, 'Unable to send charm: it has been enqueued')
        else:
            if not self.browser.send_charm(id):
                raise QueryError('No enough charms available')
            return Query(id, 'A charm has been sent')

    def get_notes(self, id):
        if isinstance(id, Contact):
            id = id.id

        return self.storage.get('notes', id)

    def save_notes(self, id, notes):
        if isinstance(id, Contact):
            id = id.id

        self.storage.set('notes', id, notes)
        self.storage.save()

    # ---- CapChat methods ---------------------

    def iter_chat_messages(self, _id=None):
        return self.browser.iter_chat_messages(_id)

    def send_chat_message(self, _id, message):
        return self.browser.send_chat_message(_id, message)

    #def start_chat_polling(self):
    #self._profile_walker = ProfilesWalker(self.weboob.scheduler, self.storage, self.browser)

    def get_account_status(self):
        return (
            StatusField(u'myname', u'My name',
                        unicode(self.browser.get_my_name())),
            StatusField(u'score', u'Score', unicode(self.browser.score())),
            StatusField(u'avcharms', u'Available charms',
                        unicode(self.browser.nb_available_charms())),
            StatusField(u'newvisits', u'New visits',
                        unicode(self.browser.nb_new_visites())),
        )

    OBJECTS = {
        Thread: fill_thread,
        Contact: fill_contact,
        ContactPhoto: fill_photo
    }
コード例 #16
0
ファイル: module.py プロジェクト: guix77/weboob
class BoursoramaModule(Module, CapBankWealth, CapBankTransferAddRecipient,
                       CapProfile, CapContact, CapCurrencyRate):
    NAME = 'boursorama'
    MAINTAINER = u'Gabriel Kerneis'
    EMAIL = '*****@*****.**'
    VERSION = '1.6'
    LICENSE = 'LGPLv3+'
    DESCRIPTION = u'Boursorama'
    CONFIG = BackendConfig(
        ValueBackendPassword('login', label='Identifiant', masked=False),
        ValueBackendPassword('password', label='Mot de passe'),
        ValueBool('enable_twofactors',
                  label='Send validation sms',
                  default=False),
        Value('device', label='Device name', regexp='\w*', default='weboob'),
        Value('pin_code', label='Sms code', required=False, default=''),
    )
    BROWSER = BoursoramaBrowser

    def create_default_browser(self):
        return self.create_browser(self.config)

    def iter_accounts(self):
        return self.browser.get_accounts_list()

    def get_account(self, _id):
        account = self.browser.get_account(_id)
        if account:
            return account
        else:
            raise AccountNotFound()

    def iter_history(self, account):
        for tr in self.browser.get_history(account):
            if not tr._is_coming:
                yield tr

    def iter_coming(self, account):
        for tr in self.browser.get_history(account, coming=True):
            if tr._is_coming:
                yield tr

    def iter_investment(self, account):
        return self.browser.get_investment(account)

    def get_profile(self):
        return self.browser.get_profile()

    def iter_contacts(self):
        return self.browser.get_advisor()

    def iter_transfer_recipients(self, account):
        if not isinstance(account, Account):
            account = self.get_account(account)
        return self.browser.iter_transfer_recipients(account)

    def init_transfer(self, transfer, **kwargs):
        return self.browser.init_transfer(transfer, **kwargs)

    def new_recipient(self, recipient, **kwargs):
        return self.browser.new_recipient(recipient, **kwargs)

    def execute_transfer(self, transfer, **kwargs):
        return self.browser.execute_transfer(transfer, **kwargs)

    def transfer_check_label(self, old, new):
        # In the confirm page the '<' is interpeted like a html tag
        # If no '>' is present the following chars are deleted
        # Else: inside '<>' chars are deleted
        old = re.sub(r'<[^>]*>', '', old).strip()
        old = old.split('<')[0]

        # replace � by ?, like the bank does
        old = old.replace('\ufffd', '?')
        return super(BoursoramaModule, self).transfer_check_label(old, new)

    def iter_currencies(self):
        return self.browser.iter_currencies()

    def get_rate(self, currency_from, currency_to):
        return self.browser.get_rate(currency_from, currency_to)