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
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