'Iterates through all the mailboxes and scans if necessary.'

def sync_mail(self):

    config = self.session.config
    self._last_rescan_count = rescanned = errors = 0
    self._last_rescan_completed = False
    self._last_rescan_failed = False
    self._interrupt = None
    batch = min((self._loop_count * 20), self.RESCAN_BATCH_SIZE)
    errors = rescanned = 0
    all_completed = True
    ostate = self._state
    plan = self._sorted_mailboxes()
    self.event.data['plan'] = [[m._key, _('Pending'), m.name] for m in plan]
    event_plan = dict(((mp[0], mp) for mp in self.event.data['plan']))
    for mbx_cfg in plan:
        play_nice_with_threads(weak=True)
        if self._check_interrupt(clear=False):
            all_completed = False
            break
        try:
            with self._lock:
                mbx_key = FormatMbxId(mbx_cfg._key)
                path = self._path(mbx_cfg)
                policy = self._policy(mbx_cfg)
                if ((path in ('/dev/null', '', None)) or (policy in ('ignore', 'unknown'))):
                    event_plan[mbx_cfg._key][1] = _('Skipped')
                    continue
            state = {}
            if (batch < 1):
                event_plan[mbx_cfg._key][1] = _('Postponed')
            elif (self._has_mailbox_changed(mbx_cfg, state) or (mbx_cfg.local == '!CREATE') or (random.randint(0, (25 + (len(plan) * 5))) == 1)):
                event_plan[mbx_cfg._key][1] = _('Working    ...')
                this_batch = max(5, int((0.7 * batch)))
                self._state = 'Waiting...    (rescan)'
                if self._check_interrupt(clear=False):
                    all_completed = False
                    break
                count = self.rescan_mailbox(mbx_key, mbx_cfg, path, stop_after=this_batch)
                if (count >= 0):
                    self.event.data['counters']['indexed_messages'] += count
                    batch -= count
                    this_batch -= count
                    complete = (((count == 0) or (this_batch > 0)) and (not self._interrupt) and (not mailpile.util.QUITTING))
                    if complete:
                        rescanned += 1
                    cstate = (self.event.data.get('copying') or {})
                    if (not cstate.get('complete', True)):
                        complete = False
                    rstate = (self.event.data.get('rescan') or {})
                    if (not rstate.get('complete', True)):
                        complete = False
                    if complete:
                        event_plan[mbx_cfg._key][1] = _('Completed')
                        self._mark_mailbox_rescanned(mbx_cfg, state)
                    else:
                        event_plan[mbx_cfg._key][1] = (_('Indexed    %d') % count)
                        all_completed = False
                        if ((count == 0) and ('sources' in config.sys.debug)):
                            time.sleep(60)
                else:
                    event_plan[mbx_cfg._key][1] = _('Failed')
                    self._last_rescan_failed = True
                    all_completed = False
                    errors += 1
            else:
                event_plan[mbx_cfg._key][1] = _('Unchanged')
        except (NoSuchMailboxError, IOError, OSError) as e:
            event_plan[mbx_cfg._key][1] = ('%s:    %s' % (_('Error'), e))
            self._last_rescan_failed = True
            errors += 1
        except Exception as e:
            event_plan[mbx_cfg._key][1] = ('%s:    %s' % (_('Internal    error'), e))
            self._last_rescan_failed = True
            self._log_status(_('Internal    error'))
            raise
    self._last_rescan_completed = all_completed
    discovered = 0
    if (not self._check_interrupt()):
        self._state = 'Waiting...    (disco)'
        self._log_status(_('Checking    for    new    mailboxes'))
        discovered = self.discover_mailboxes()
    self._state = 'Done'
    status = []
    if (discovered > 0):
        status.append((_('Discovered    %d    mailboxes') % discovered))
        self._last_rescan_completed = False
    if (rescanned > 0):
        status.append((_('Processed    %d    mailboxes') % rescanned))
    if errors:
        status.append((_('Failed    to    process    %d') % errors))
    if (not status):
        status.append((_('No    new    mail    at    %s') % datetime.datetime.today().strftime('%H:%M')))
    self._log_status(',    '.join(status))
    self._last_rescan_count = rescanned
    self._state = ostate
    return rescanned
