예제 #1
0
    def process_inbox(self, origpastuids):
        """Run spamassassin in the folder for spam."""
        sa_proc = Sa_Process()

        spamlist = []
        spamdeletelist = []

        # select inbox
        self.imap.select(self.imapsets.inbox, 1)

        # get the uids of all mails with a size less then the maxsize
        _, uids = self.imap.uid("SEARCH", None, "SMALLER", str(self.maxsize))

        uids, sa_proc.newpastuids = SpamAssassin.get_formated_uids(
            uids, origpastuids, self.partialrun)

        self.logger.debug(__('Got {} mails to check'.format(len(uids))))

        if self.dryrun:
            processednum = 0
            fakespammax = 1
            processmax = 5

        # Main loop that iterates over each new uid we haven't seen before
        for uid in uids:
            # Retrieve the entire message
            mail = imaputils.get_message(self.imap,
                                         uid,
                                         sa_proc.uids,
                                         logger=self.logger)

            # Unwrap spamassassin reports
            unwrapped = sa_unwrap.unwrap(mail)
            if unwrapped is not None and unwrapped:  # len(unwrapped) > 0
                mail = unwrapped[0]

            # Feed it to SpamAssassin in test mode
            if self.dryrun:
                if processednum > processmax:
                    break
                if processednum < fakespammax:
                    self.logger.info("Faking spam mail")
                    score = "10/10"
                    code = 1
                else:
                    self.logger.info("Faking ham mail")
                    score = "0/10"
                    code = 0
                processednum = processednum + 1
            else:
                score, code, spamassassin_result = test_mail(mail,
                                                             cmd=self.cmd_test)
                if score == "-9999":
                    self.logger.exception(
                        __('{} error for mail {}'.format(self.cmd_test, uid)))
                    self.logger.debug(repr(mail))
                    uids.remove(uid)
                    continue

            if score == "0/0\n":
                raise isbg.ISBGError(isbg.__exitcodes__['spamc'],
                                     "spamc -> spamd error - aborting")

            self.logger.debug(
                __("Score for uid {}: {}".format(uid, score.strip())))

            if code != 0:
                # Message is spam, delete it or move it to spaminbox
                # (optionally with report)
                if not self._process_spam(uid, score, mail, spamdeletelist,
                                          code, spamassassin_result):
                    continue
                spamlist.append(uid)

        sa_proc.nummsg = len(uids)
        sa_proc.spamdeleted = len(spamdeletelist)
        sa_proc.numspam = len(spamlist) + sa_proc.spamdeleted

        # If we found any spams, now go and mark the original messages
        if sa_proc.numspam or sa_proc.spamdeleted:
            if self.dryrun:
                self.logger.info('Skipping labelling/expunging of mails ' +
                                 ' because of --dryrun')
            else:
                self.imap.select(self.imapsets.inbox)
                # Only set message flags if there are any
                if self.spamflags:  # len(self.smpamflgs) > 0
                    for uid in spamlist:
                        self.imap.uid("STORE", uid, self.spamflagscmd,
                                      imaputils.imapflags(self.spamflags))
                        sa_proc.newpastuids.append(uid)
                # If its gmail, and --delete was passed, we actually copy!
                if self.delete and self.gmail:
                    for uid in spamlist:
                        self.imap.uid("COPY", uid, "[Gmail]/Trash")
                # Set deleted flag for spam with high score
                for uid in spamdeletelist:
                    if self.gmail is True:
                        self.imap.uid("COPY", uid, "[Gmail]/Trash")
                    else:
                        self.imap.uid("STORE", uid, self.spamflagscmd,
                                      "(\\Deleted)")
                if self.expunge:
                    self.imap.expunge()

        return sa_proc
예제 #2
0
    def learn(self, folder, learn_type, move_to, origpastuids):
        """Learn the spams (and if requested deleted or move them).

        Args:
            folder (str): The IMAP folder.
            leart_type (str): ```spam``` to learn spam, ```ham``` to learn
                nonspam.
            move_to (str): If not ```None```, the imap folder where the emails
                will be moved.
            origpastuids (list(int)): ``uids`` to not process.
        Returns:
            Sa_Learn:
                It contains the information about the result of the process.

            It will call ``spamc`` to learn the emails.

        Raises:
            isbg.ISBGError: if learn_type is unknown.


        TODO:
            Add suport to ``learn_type=forget``.

        """
        sa_learning = Sa_Learn()

        # Sanity checks:
        if learn_type not in ['spam', 'ham']:
            raise isbg.ISBGError(-1, message="Unknown learn_type")
        if self.imap is None:
            raise isbg.ISBGError(-1, message="Imap is required")

        self.logger.debug(
            __("Teach {} to SA from: {}".format(learn_type, folder)))

        self.imap.select(folder)
        if self.learnunflagged:
            _, uids = self.imap.uid("SEARCH", None, "UNFLAGGED")
        elif self.learnflagged:
            _, uids = self.imap.uid("SEARCH", None, "(FLAGGED)")
        else:
            _, uids = self.imap.uid("SEARCH", None, "ALL")

        uids, sa_learning.newpastuids = SpamAssassin.get_formated_uids(
            uids, origpastuids, self.partialrun)

        sa_learning.tolearn = len(uids)

        for uid in uids:
            mail = imaputils.get_message(self.imap, uid, logger=self.logger)

            # Unwrap spamassassin reports
            unwrapped = sa_unwrap.unwrap(mail)
            if unwrapped is not None:
                self.logger.debug(
                    __("{} Unwrapped: {}".format(
                        uid,
                        utils.shorten(imaputils.mail_content(unwrapped[0]),
                                      140))))

            if unwrapped is not None and unwrapped:  # len(unwrapped)>0
                mail = unwrapped[0]

            if self.dryrun:
                self.logger.warning("Skipped learning due to dryrun!")
                continue
            else:
                code, code_orig = learn_mail(mail, learn_type)

            if code == -9999:  # error processing email, try next.
                self.logger.exception(__(
                    'spamc error for mail {}'.format(uid)))
                self.logger.debug(repr(imaputils.mail_content(mail)))
                continue

            if code in [69, 74]:
                raise isbg.ISBGError(
                    isbg.__exitcodes__['flags'],
                    "spamassassin is misconfigured (use --allow-tell)")

            if code == 5:  # learned.
                sa_learning.learned += 1
                self.logger.debug(
                    __("Learned {} (spamc return code {})".format(
                        uid, code_orig)))

            elif code == 6:  # already learned.
                self.logger.debug(
                    __("Already learned {} (spamc return code {})".format(
                        uid, code_orig)))

            elif code == 98:  # too big.
                self.logger.warning(
                    __("{} is too big (spamc return code {})".format(
                        uid, code_orig)))

            else:
                raise isbg.ISBGError(-1, ("{}: Unknown return code {} from " +
                                          "spamc").format(uid, code_orig))

            sa_learning.uids.append(int(uid))

            if not self.dryrun:
                if self.learnthendestroy:
                    if self.gmail:
                        self.imap.uid("COPY", uid, "[Gmail]/Trash")
                    else:
                        self.imap.uid("STORE", uid, self.spamflagscmd,
                                      "(\\Deleted)")
                elif move_to is not None:
                    self.imap.uid("COPY", uid, move_to)
                elif self.learnthenflag:
                    self.imap.uid("STORE", uid, self.spamflagscmd,
                                  "(\\Flagged)")

        return sa_learning