예제 #1
0
    def run(self, notification):
        # call super for some basic notification processing
        (notification, jobs) = super(MessageHandlerBase, self).run(notification)

        relevant = False

        if 'archive' in self.features:
            relevant = True

        if 'backup' in self.features:
            relevant = True

        if not relevant:
            return (notification, jobs)

        # Insert the URI UID (if it exists) in to uidset for further handlers
        if notification.has_key('uri') and notification.has_key('uidset'):
            uri = parse_imap_uri(notification['uri'])

            if uri.has_key('UID'):
                notification['uidset'] = [ uri['UID'] ]

        # message notifications require message headers
        if not notification.has_key('messageHeaders'):
            self.log.debug("Adding HEADER job for " + self.event, level=8)
            jobs.append(b"HEADER")
            return (notification, jobs)

        return (notification, jobs)
예제 #2
0
 def test_parse_imap_uri(self):
     url = parse_imap_uri("imap://[email protected]@kolab.example.org/Calendar/Personal%20Calendar;UIDVALIDITY=1411487702/;UID=3")
     self.assertEqual(url['host'],   'kolab.example.org')
     self.assertEqual(url['user'],   'john.doe')
     self.assertEqual(url['domain'], 'example.org')
     self.assertEqual(url['path'],   'Calendar/Personal Calendar')
     self.assertEqual(url['UID'],    '3')
예제 #3
0
    def get_imap_folder_acl(self, notification):
        notification = json.loads(notification)
        log.debug("GETACL for %r" % (notification), level=9)

        # split the uri parameter into useful parts
        uri = parse_imap_uri(notification['uri'])
        folder_path = imap_folder_path(uri)

        # get folder acls using pykolab's imap module
        acls = {}
        try:
            self.imap.connect()
            acls = self.imap.list_acls(folder_path)
            self.imap.disconnect()
        except Exception, e:
            log.warning("Failed to get ACLs for %r: %r", folder_path, e)
예제 #4
0
    def get_imap_folder_metadata(self, notification):
        notification = json.loads(notification)
        log.debug("GETMETADATA for %r" % (notification), level=9)

        # split the uri parameter into useful parts
        uri = parse_imap_uri(notification['uri'])
        folder_path = imap_folder_path(uri)

        # get metadata using pykolab's imap module
        metadata = {}
        try:
            self.imap.connect()
            metadata = self.imap.get_metadata(folder_path)[folder_path]
            self.imap.disconnect()
        except Exception, e:
            log.warning("Failed to get metadata for %r: %r", folder_path, e)
    def notificaton2folder(self, notification, attrib='uri'):
        """
            Turn the given notification record into a folder document.
            including the computation of a unique identifier which is a
            checksum of the (relevant) folder properties.
        """
        # split the uri parameter into useful parts
        uri = parse_imap_uri(notification[attrib])

        # re-compose folder uri
        templ = "imap://%(user)s@%(domain)s@%(host)s/"
        if uri['user'] is None:
            templ = "imap://%(host)s/"
        folder_uri = templ % uri + urllib.quote(uri['path'])

        if not notification.has_key('metadata'):
            return False

        if not notification.has_key('folder_uniqueid') and \
                notification['metadata'].has_key(
                        '/shared/vendor/cmu/cyrus-imapd/uniqueid'
                    ):

            notification['folder_uniqueid'] = notification['metadata']['/shared/vendor/cmu/cyrus-imapd/uniqueid']

        if not notification.has_key('folder_uniqueid'):
            notification['folder_uniqueid'] = hashlib.md5(
                    notification[attrib]
                ).hexdigest()

        body = {
                '@version': bonnie.API_VERSION,
                '@timestamp': datetime.datetime.now(
                        tzutc()
                    ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),

                'uniqueid': notification['folder_uniqueid'],
                'metadata': notification['metadata'],
                'acl': dict(
                        (self.resolve_username(k, force=True),v) for k,v in notification['acl'].iteritems()
                    ),

                'type': notification['metadata']['/shared/vendor/kolab/folder-type'] if notification['metadata'].has_key('/shared/vendor/kolab/folder-type') else 'mail',

                'owner': uri['user'] + '@' + uri['domain'] if uri['user'] is not None else 'nobody',
                'server': uri['host'],
                'name': re.sub('@.+$', '', uri['path']),
                'uri': folder_uri,
            }

        # compute folder object signature and the unique identifier
        ignore_metadata = [
                '/shared/vendor/cmu/cyrus-imapd/lastupdate',
                '/shared/vendor/cmu/cyrus-imapd/pop3newuidl',
                '/shared/vendor/cmu/cyrus-imapd/size'
            ]

        signature = {
                '@version': bonnie.API_VERSION,
                'owner': body['owner'],
                'server': body['server'],
                'uniqueid': notification['folder_uniqueid'],
                'metadata': [
                        (k,v) for k,v in sorted(body['metadata'].iteritems()) if k not in ignore_metadata
                    ],

                'acl': [
                        (k,v) for k,v in sorted(body['acl'].iteritems())
                    ],
            }

        serialized = ";".join(
                "%s:%s" % (k,v) for k,v in sorted(signature.iteritems())
            )

        folder_id = hashlib.md5(serialized).hexdigest()

        return dict(id=folder_id, body=body)
예제 #6
0
    def _retrieve_contents_for_messages(self, notification, headers_only=False):
        """
            Helper method to deliver message contents/headers
        """
        messageContents = {}
        messageHeaders = {}

        # split the uri parameter into useful parts
        uri = parse_imap_uri(notification['uri'])

        if notification.has_key('uidset'):
            message_uids = expand_uidset(notification['uidset'])
        elif notification.has_key('vnd.cmu.oldUidset'):
            message_uids = expand_uidset(notification['vnd.cmu.oldUidset'])
        elif uri.has_key('UID'):
            message_uids = [ uri['UID'] ]
            notification['uidset'] = ','.join(message_uids)

        # resolve uri into a mailbox path on the local file stystem
        mailbox_path = utils.imap_mailbox_fs_path(uri)

        log.debug("Using mailbox path: %r" % (mailbox_path), level=8)

        # mailbox exists, try reading the message files
        if os.path.exists(mailbox_path):
            for message_uid in message_uids:
                # using message file path like /var/spool/imap/domain/e/example.org/k/lists/kolab^org/devel/lists/kolab.org/[email protected]/1.
                message_file_path = "%s/%s." % (mailbox_path, message_uid)

                log.debug("Open message file: %r" % (message_file_path), level=8)

                attempts = 5
                while attempts > 0:
                    attempts -= 1

                    if os.access(message_file_path, os.R_OK):
                        fp = open(message_file_path, 'r')

                        if headers_only:
                            data = ''
                            for line in fp:
                                data += line
                                if line.strip() == '':
                                    break;
                            data += "\r\n"
                        else:
                            data = fp.read()

                        fp.close()

                        # use email lib to parse message headers
                        try:
                            # find header delimiter
                            pos = data.find("\r\n\r\n")
                            message = message_from_string(data[0:pos])
                            headers = decode_message_headers(message)
                        except:
                            headers = dict()
                            messageHeaders[message_uid] = headers

                        # append raw message data and parsed headers
                        messageContents[message_uid] = data
                        messageHeaders[message_uid] = headers
                        break

                    elif attempts > 0:
                        log.debug("Failed to open message file %r; retry %d more times" % (
                            message_file_path, attempts
                        ), level=5)
                    else:
                        log.warning("Failed to open message file %r for uri=%s; uid=%s" % (
                            message_file_path, notification, message_uid
                        ))

                    time.sleep(1)
                # end while
            # end for
        else:
            log.warning("Mailbox path %r does not exits for uri=%s" % (mailbox_path, notification['uri']))

        return (messageContents, messageHeaders)