Ejemplo n.º 1
0
 async def do_list(self, cmd: ListCommand):
     mailboxes, updates = await self.session.list_mailboxes(
         cmd.ref_name, cmd.filter, subscribed=cmd.only_subscribed,
         selected=self._selected)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     resp_type = LSubResponse if cmd.only_subscribed else ListResponse
     for name, sep, attrs in mailboxes:
         resp.add_untagged(resp_type(name, sep, attrs))
     return resp, updates
Ejemplo n.º 2
0
 async def do_list(self, cmd: ListCommand) -> _CommandRet:
     mailboxes, updates = await self.session.list_mailboxes(
         cmd.ref_name, cmd.filter, subscribed=cmd.only_subscribed,
         selected=self._selected)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     resp_type = LSubResponse if cmd.only_subscribed else ListResponse
     for name, sep, attrs in mailboxes:
         resp.add_untagged(resp_type(name, sep, attrs))
     return resp, updates
Ejemplo n.º 3
0
 async def do_fetch(self, cmd: FetchCommand):
     if not cmd.uid:
         self.selected.hide_expunged = True
     messages, updates = await self.session.fetch_messages(
         self.selected, cmd.sequence_set, frozenset(cmd.attributes))
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         msg_attrs = MessageAttributes(msg, self.selected)
         fetch_data = msg_attrs.get_all(cmd.attributes)
         resp.add_untagged(FetchResponse(msg_seq, fetch_data))
     return resp, updates
Ejemplo n.º 4
0
 async def do_fetch(self, cmd: FetchCommand) -> _CommandRet:
     if not cmd.uid:
         self.selected.hide_expunged = True
     set_seen = any(attr.set_seen for attr in cmd.attributes)
     messages, updates = await self.session.fetch_messages(
         self.selected, cmd.sequence_set, set_seen)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         msg_attrs = MessageAttributes(msg, self.selected, cmd.attributes)
         fetch_resp = FetchResponse(msg_seq, msg_attrs,
                                    writing_hook=msg_attrs.load_hook())
         resp.add_untagged(fetch_resp)
     return resp, updates
Ejemplo n.º 5
0
 async def do_search(self, cmd: SearchCommand) -> _CommandRet:
     if not cmd.uid:
         self.selected.hide_expunged = True
     messages, updates = await self.session.search_mailbox(
         self.selected, cmd.keys)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     msg_ids: List[int] = []
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         if cmd.uid:
             msg_ids.append(msg.uid)
         else:
             msg_ids.append(msg_seq)
     resp.add_untagged(SearchResponse(msg_ids))
     return resp, updates
Ejemplo n.º 6
0
 async def do_search(self, cmd: SearchCommand):
     if not cmd.uid:
         self.selected.hide_expunged = True
     messages, updates = await self.session.search_mailbox(
         self.selected, cmd.keys)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     msg_ids: List[int] = []
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         if cmd.uid:
             msg_ids.append(msg.uid)
         else:
             msg_ids.append(msg_seq)
     resp.add_untagged(SearchResponse(msg_ids))
     return resp, updates
Ejemplo n.º 7
0
 async def do_create(self, cmd: CreateCommand) -> _CommandRet:
     if cmd.mailbox == 'INBOX':
         return ResponseNo(cmd.tag, b'Cannot create INBOX.'), None
     mailbox_id, updates = await self.session.create_mailbox(
         cmd.mailbox, selected=self._selected)
     return ResponseOk(cmd.tag, cmd.command + b' completed.',
                       MailboxId(mailbox_id)), updates
Ejemplo n.º 8
0
 async def do_append(self, cmd: AppendCommand) -> _CommandRet:
     if len(cmd.messages) > 1 and b'MULTIAPPEND' not in self.capability:
         raise NotSupportedError('MULTIAPPEND is disabled.')
     if cmd.cancelled:
         return ResponseNo(cmd.tag, b'APPEND cancelled.'), None
     append_uid, updates = await self.session.append_messages(
         cmd.mailbox, cmd.messages, selected=self._selected)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.', append_uid)
     return resp, updates
Ejemplo n.º 9
0
 async def do_starttls(self, cmd: StartTLSCommand) -> _CommandRet:
     if self.ssl_context is None:
         raise ValueError('ssl_context is None')
     try:
         self._capability.remove(b'STARTTLS')
     except ValueError:
         raise NotSupportedError('STARTTLS not available.')
     self.auth = self.config.insecure_auth
     return ResponseOk(cmd.tag, b'Ready to handshake.'), None
Ejemplo n.º 10
0
 async def do_authenticate(self, cmd: _AuthCommands,
                           creds: Optional[AuthenticationCredentials]) \
         -> CommandResponse:
     if not creds:
         return ResponseNo(cmd.tag, b'Invalid authentication mechanism.')
     self._session = await self._login(creds)
     self._capability.extend(self.config.login_capability)
     return ResponseOk(cmd.tag, b'Authentication successful.',
                       self.capability)
Ejemplo n.º 11
0
 async def do_store(self, cmd: StoreCommand):
     if not cmd.uid:
         self.selected.hide_expunged = True
     if cmd.silent:
         self.selected.silence(cmd.sequence_set, cmd.flag_set, cmd.mode)
     messages, updates = await self.session.update_flags(
         self.selected, cmd.sequence_set, cmd.flag_set, cmd.mode)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     session_flags = self.selected.session_flags
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         elif cmd.silent:
             continue
         flags = msg.get_flags(session_flags)
         fetch_data: List[Tuple[FetchAttribute, MaybeBytes]] = [
             (_flags_attr, ListP(flags, sort=True))]
         if cmd.uid:
             fetch_data.append((_uid_attr, Number(msg.uid)))
         resp.add_untagged(FetchResponse(msg_seq, fetch_data))
     return resp, updates
Ejemplo n.º 12
0
 async def do_status(self, cmd: StatusCommand):
     mailbox, updates = await self.session.get_mailbox(
         cmd.mailbox, selected=self._selected)
     data: Dict[StatusAttribute, Number] = OrderedDict()
     for attr in cmd.status_list:
         if attr == b'MESSAGES':
             data[attr] = Number(mailbox.exists)
         elif attr == b'RECENT':
             if updates and updates.guid == mailbox.guid:
                 data[attr] = Number(updates.session_flags.recent)
             else:
                 data[attr] = Number(mailbox.recent)
         elif attr == b'UNSEEN':
             data[attr] = Number(mailbox.unseen)
         elif attr == b'UIDNEXT':
             data[attr] = Number(mailbox.next_uid)
         elif attr == b'UIDVALIDITY':
             data[attr] = Number(mailbox.uid_validity)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     resp.add_untagged(StatusResponse(cmd.mailbox, data))
     return resp, updates
Ejemplo n.º 13
0
 async def do_store(self, cmd: StoreCommand) -> _CommandRet:
     if not cmd.uid:
         self.selected.hide_expunged = True
     if cmd.silent:
         self.selected.silence(cmd.sequence_set, cmd.flag_set, cmd.mode)
     messages, updates = await self.session.update_flags(
         self.selected, cmd.sequence_set, cmd.flag_set, cmd.mode)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     session_flags = self.selected.session_flags
     for msg_seq, msg in messages:
         if msg.expunged:
             resp.code = ResponseCode.of(b'EXPUNGEISSUED')
         elif cmd.silent:
             continue
         flags = msg.get_flags(session_flags)
         fetch_data: List[FetchValue] = [
             FetchValue.of(_flags_attr, ListP(flags, sort=True))]
         if cmd.uid:
             fetch_data.append(
                 FetchValue.of(_uid_attr, Number(msg.uid)))
         resp.add_untagged(FetchResponse(msg_seq, fetch_data))
     return resp, updates
Ejemplo n.º 14
0
 async def do_status(self, cmd: StatusCommand) -> _CommandRet:
     mailbox, updates = await self.session.get_mailbox(
         cmd.mailbox, selected=self._selected)
     data: Dict[StatusAttribute, MaybeBytes] = OrderedDict()
     for attr in cmd.status_list:
         if attr == b'MESSAGES':
             data[attr] = Number(mailbox.exists)
         elif attr == b'RECENT':
             if updates and updates.mailbox_id == mailbox.mailbox_id:
                 data[attr] = Number(updates.session_flags.recent)
             else:
                 data[attr] = Number(mailbox.recent)
         elif attr == b'UNSEEN':
             data[attr] = Number(mailbox.unseen)
         elif attr == b'UIDNEXT':
             data[attr] = Number(mailbox.next_uid)
         elif attr == b'UIDVALIDITY':
             data[attr] = Number(mailbox.uid_validity)
         elif attr == b'MAILBOXID':
             data[attr] = mailbox.mailbox_id.parens
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     resp.add_untagged(StatusResponse(cmd.mailbox, data))
     return resp, updates
Ejemplo n.º 15
0
 async def do_capability(self, cmd: CapabilityCommand):
     response = ResponseOk(cmd.tag, b'Capabilities listed.')
     response.add_untagged(Response(b'*', self.capability.string))
     return response, None
Ejemplo n.º 16
0
 async def do_idle(self, cmd: IdleCommand) -> _CommandRet:
     if b'IDLE' not in self.capability:
         raise NotSupportedError('IDLE is disabled.')
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), None
Ejemplo n.º 17
0
 async def do_capability(self, cmd: CapabilityCommand) -> _CommandRet:
     response = ResponseOk(cmd.tag, b'Capabilities listed.')
     response.add_untagged(UntaggedResponse(self.capability.string))
     return response, None
Ejemplo n.º 18
0
 async def do_rename(self, cmd: RenameCommand) -> _CommandRet:
     if cmd.to_mailbox == 'INBOX':
         return ResponseNo(cmd.tag, b'Cannot rename to INBOX.'), None
     updates = await self.session.rename_mailbox(
         cmd.from_mailbox, cmd.to_mailbox, selected=self._selected)
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), updates
Ejemplo n.º 19
0
 def setUp(self) -> None:
     self.response = ResponseOk(b'.', b'testing')
Ejemplo n.º 20
0
 def setUp(self) -> None:
     self.response = ResponseOk(b'.', b'testing')
Ejemplo n.º 21
0
 async def do_close(self, cmd: CloseCommand) -> _CommandRet:
     await self.session.expunge_mailbox(self.selected)
     self._selected = None
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), None
Ejemplo n.º 22
0
 async def do_check(self, cmd: CheckCommand) -> _CommandRet:
     updates = await self.session.check_mailbox(
         self.selected, housekeeping=True)
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), updates
Ejemplo n.º 23
0
class TestSelectedMailbox(unittest.TestCase):

    def setUp(self) -> None:
        self.response = ResponseOk(b'.', b'testing')

    @classmethod
    def new_selected(cls, guid: bytes = b'test') -> SelectedMailbox:
        return SelectedMailbox(guid, False,
                               PermanentFlags([Seen, Flagged]),
                               SessionFlags([_Keyword]))

    @classmethod
    def set_messages(cls, selected: SelectedMailbox,
                     expunged, messages) -> None:
        updates = [BaseMessage(uid, flags, datetime.now())
                   for uid, flags in messages]
        selected.add_updates(updates, expunged)

    @property
    def command(self) -> SearchCommand:
        return SearchCommand(b'.', [], None)

    @property
    def uid_command(self) -> SearchCommand:
        return UidSearchCommand(b'.', [], None)

    def test_add_untagged_recent_equal(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [],
                          [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [],
                          [(1, []), (2, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_recent_increase(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [],
                          [(1, []), (2, []), (3, [])])
        forked, _ = selected.fork(self.command)
        forked.session_flags.add_recent(3)
        self.set_messages(forked, [], [])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 3 RECENT\r\n'
                         b'* 3 FETCH (FLAGS (\\Recent))\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_session_flag_add(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, [Seen]), (3, [])])
        forked, _ = selected.fork(self.command)
        forked.session_flags.update(2, [_Keyword], FlagOp.ADD)
        self.set_messages(forked, [], [])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 2 FETCH (FLAGS (\\Seen $Keyword))\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_recent_expunge(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [],
                          [(1, []), (2, []), (3, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [2, 3],
                          [(1, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 3 EXPUNGE\r\n'
                         b'* 2 EXPUNGE\r\n'
                         b'* 1 RECENT\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_equal(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [],
                          [(1, []), (2, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [],
                          [(2, [Seen]), (3, [Seen, Flagged]), (4, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 4 EXISTS\r\n'
                         b'* 2 FETCH (FLAGS (\\Seen))\r\n'
                         b'* 3 FETCH (FLAGS (\\Flagged \\Seen))\r\n'
                         b'* 4 FETCH (FLAGS ())\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch_uid(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, [])])
        forked, _ = selected.fork(self.uid_command)
        self.set_messages(forked, [],
                          [(2, [Seen]), (3, [Seen, Flagged]), (4, [])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 4 EXISTS\r\n'
                         b'* 2 FETCH (FLAGS (\\Seen) UID 2)\r\n'
                         b'* 3 FETCH (FLAGS (\\Flagged \\Seen) UID 3)\r\n'
                         b'* 4 FETCH (FLAGS () UID 4)\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch_silenced(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, []), (3, [Seen, Flagged]),
                           (4, [Seen, Flagged]), (5, [Flagged]), (6, [Seen])])
        forked, _ = selected.fork(self.uid_command)
        forked.silence(SequenceSet.build([1, 2]),
                       frozenset([Seen]), FlagOp.ADD)
        forked.silence(SequenceSet.build([3, 4]),
                       frozenset([Seen]), FlagOp.DELETE)
        forked.silence(SequenceSet.build([5, 6]),
                       frozenset([Seen]), FlagOp.REPLACE)
        self.set_messages(forked, [],
                          [(1, [Seen, Flagged]), (2, [Seen]), (3, []),
                           (4, [Flagged]), (5, [Seen, Flagged]), (6, [Seen])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 1 FETCH (FLAGS (\\Flagged \\Seen) UID 1)\r\n'
                         b'* 3 FETCH (FLAGS () UID 3)\r\n'
                         b'* 5 FETCH (FLAGS (\\Flagged \\Seen) UID 5)\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_expunge_hidden(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, []), (3, []), (4, [])])
        forked, _ = selected.fork(self.command)
        forked.hide_expunged = True
        self.set_messages(forked, [2, 3],
                          [(5, [Flagged])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 5 EXISTS\r\n'
                         b'* 5 FETCH (FLAGS (\\Flagged))\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_expunge(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, []), (2, []), (3, []), (4, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [2, 3],
                          [(5, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 3 EXPUNGE\r\n'
                         b'* 2 EXPUNGE\r\n'
                         b'* 3 EXISTS\r\n'
                         b'* 3 FETCH (FLAGS ())\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_all(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, [Flagged]), (2, []), (3, [])])
        forked, _ = selected.fork(self.uid_command)
        selected.session_flags.add_recent(6)
        self.set_messages(forked, [2, 3],
                          [(1, [Seen, Flagged]), (4, [Seen]), (5, [Seen]),
                           (6, [Flagged]), (7, [Seen])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* 3 EXPUNGE\r\n'
                         b'* 2 EXPUNGE\r\n'
                         b'* 5 EXISTS\r\n'
                         b'* 1 RECENT\r\n'
                         b'* 1 FETCH (FLAGS (\\Flagged \\Seen) UID 1)\r\n'
                         b'* 2 FETCH (FLAGS (\\Seen) UID 4)\r\n'
                         b'* 3 FETCH (FLAGS (\\Seen) UID 5)\r\n'
                         b'* 4 FETCH (FLAGS (\\Flagged \\Recent) UID 6)\r\n'
                         b'* 5 FETCH (FLAGS (\\Seen) UID 7)\r\n'
                         b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_deleted_bye(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [],
                          [(1, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [1],
                          [(2, [])])
        forked.set_deleted()
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'* BYE Selected mailbox no longer exists.\r\n'
                         b'. OK testing\r\n', bytes(self.response))
Ejemplo n.º 24
0
 async def do_unsubscribe(self, cmd: UnsubscribeCommand) -> _CommandRet:
     updates = await self.session.unsubscribe(
         cmd.mailbox, selected=self._selected)
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), updates
Ejemplo n.º 25
0
 async def do_select(self, cmd: SelectCommand) -> _CommandRet:
     self._selected = None
     mailbox, updates = await self.session.select_mailbox(
         cmd.mailbox, cmd.readonly)
     if updates.readonly:
         num_recent = mailbox.recent
         resp = ResponseOk(cmd.tag, b'Selected mailbox.',
                           ResponseCode.of(b'READ-ONLY'))
         resp.add_untagged_ok(b'Read-only mailbox.', PermanentFlags([]))
     else:
         num_recent = updates.session_flags.recent
         resp = ResponseOk(cmd.tag, b'Selected mailbox.',
                           ResponseCode.of(b'READ-WRITE'))
         resp.add_untagged_ok(b'Flags permitted.',
                              PermanentFlags(mailbox.permanent_flags))
     messages = updates.messages
     resp.add_untagged(FlagsResponse(mailbox.flags))
     resp.add_untagged(ExistsResponse(messages.exists))
     resp.add_untagged(RecentResponse(num_recent))
     resp.add_untagged_ok(b'Predicted next UID.',
                          UidNext(mailbox.next_uid))
     resp.add_untagged_ok(b'UIDs valid.',
                          UidValidity(mailbox.uid_validity))
     if mailbox.first_unseen:
         resp.add_untagged_ok(b'First unseen message.',
                              Unseen(mailbox.first_unseen))
     resp.add_untagged_ok(b'Object ID.', MailboxId(mailbox.mailbox_id))
     return resp, updates
Ejemplo n.º 26
0
 async def do_select(self, cmd: SelectCommand):
     self._selected = None
     mailbox, updates = await self.session.select_mailbox(
         cmd.mailbox, cmd.readonly)
     if updates.readonly:
         num_recent = mailbox.recent
         resp = ResponseOk(cmd.tag, b'Selected mailbox.',
                           ResponseCode.of(b'READ-ONLY'))
         resp.add_untagged_ok(b'Read-only mailbox.', PermanentFlags([]))
     else:
         num_recent = updates.session_flags.recent
         resp = ResponseOk(cmd.tag, b'Selected mailbox.',
                           ResponseCode.of(b'READ-WRITE'))
         resp.add_untagged_ok(b'Flags permitted.',
                              PermanentFlags(mailbox.permanent_flags))
     messages = updates.messages
     resp.add_untagged(FlagsResponse(mailbox.flags))
     resp.add_untagged(ExistsResponse(messages.exists))
     resp.add_untagged(RecentResponse(num_recent))
     resp.add_untagged_ok(b'Predicted next UID.',
                          UidNext(mailbox.next_uid))
     resp.add_untagged_ok(b'UIDs valid.',
                          UidValidity(mailbox.uid_validity))
     if mailbox.first_unseen:
         resp.add_untagged_ok(b'First unseen message.',
                              Unseen(mailbox.first_unseen))
     return resp, updates
Ejemplo n.º 27
0
 async def do_expunge(self, cmd: ExpungeCommand) -> _CommandRet:
     updates = await self.session.expunge_mailbox(
         self.selected, cmd.uid_set)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.')
     return resp, updates
Ejemplo n.º 28
0
 async def do_copy(self, cmd: CopyCommand) -> _CommandRet:
     copy_uid, updates = await self.session.copy_messages(
         self.selected, cmd.sequence_set, cmd.mailbox)
     resp = ResponseOk(cmd.tag, cmd.command + b' completed.', copy_uid)
     return resp, updates
Ejemplo n.º 29
0
class TestSelectedMailbox(unittest.TestCase):
    def setUp(self) -> None:
        self.response = ResponseOk(b'.', b'testing')

    @classmethod
    def new_selected(cls, guid: bytes = b'test') -> SelectedMailbox:
        return SelectedMailbox(ObjectId(guid), False,
                               PermanentFlags([Seen, Flagged]),
                               SessionFlags([_Keyword]))

    @classmethod
    def set_messages(cls, selected: SelectedMailbox, expunged,
                     messages) -> None:
        updates = [
            _Message(uid, datetime.now(), flags) for uid, flags in messages
        ]
        selected.add_updates(updates, expunged)

    @property
    def command(self) -> SearchCommand:
        return SearchCommand(b'.', [], None)

    @property
    def uid_command(self) -> SearchCommand:
        return UidSearchCommand(b'.', [], None)

    def test_add_untagged_recent_equal(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [], [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [], [(1, []), (2, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_recent_increase(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [], [(1, []), (2, []), (3, [])])
        forked, _ = selected.fork(self.command)
        forked.session_flags.add_recent(3)
        self.set_messages(forked, [], [])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 3 RECENT\r\n'
            b'* 3 FETCH (FLAGS (\\Recent))\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_session_flag_add(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, [Seen]), (3, [])])
        forked, _ = selected.fork(self.command)
        forked.session_flags.update(2, [_Keyword], FlagOp.ADD)
        self.set_messages(forked, [], [])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 2 FETCH (FLAGS (\\Seen $Keyword))\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_recent_expunge(self) -> None:
        selected = self.new_selected()
        selected.session_flags.add_recent(1)
        selected.session_flags.add_recent(2)
        self.set_messages(selected, [], [(1, []), (2, []), (3, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [2, 3], [(1, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 3 EXPUNGE\r\n'
            b'* 2 EXPUNGE\r\n'
            b'* 1 RECENT\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_equal(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [], [(1, []), (2, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [], [(2, [Seen]), (3, [Seen, Flagged]),
                                       (4, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 4 EXISTS\r\n'
            b'* 2 FETCH (FLAGS (\\Seen))\r\n'
            b'* 3 FETCH (FLAGS (\\Flagged \\Seen))\r\n'
            b'* 4 FETCH (FLAGS ())\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch_uid(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, [])])
        forked, _ = selected.fork(self.uid_command)
        self.set_messages(forked, [], [(2, [Seen]), (3, [Seen, Flagged]),
                                       (4, [])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 4 EXISTS\r\n'
            b'* 2 FETCH (FLAGS (\\Seen) UID 2)\r\n'
            b'* 3 FETCH (FLAGS (\\Flagged \\Seen) UID 3)\r\n'
            b'* 4 FETCH (FLAGS () UID 4)\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_fetch_silenced(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, []),
                                         (3, [Seen, Flagged]),
                                         (4, [Seen, Flagged]), (5, [Flagged]),
                                         (6, [Seen])])
        forked, _ = selected.fork(self.uid_command)
        forked.silence(SequenceSet.build([1, 2]), frozenset([Seen]),
                       FlagOp.ADD)
        forked.silence(SequenceSet.build([3, 4]), frozenset([Seen]),
                       FlagOp.DELETE)
        forked.silence(SequenceSet.build([5, 6]), frozenset([Seen]),
                       FlagOp.REPLACE)
        self.set_messages(forked, [], [(1, [Seen, Flagged]), (2, [Seen]),
                                       (3, []), (4, [Flagged]),
                                       (5, [Seen, Flagged]), (6, [Seen])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 1 FETCH (FLAGS (\\Flagged \\Seen) UID 1)\r\n'
            b'* 3 FETCH (FLAGS () UID 3)\r\n'
            b'* 5 FETCH (FLAGS (\\Flagged \\Seen) UID 5)\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_expunge_hidden(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, []), (3, []), (4, [])])
        forked, _ = selected.fork(self.command)
        forked.hide_expunged = True
        self.set_messages(forked, [2, 3], [(5, [Flagged])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 5 EXISTS\r\n'
            b'* 5 FETCH (FLAGS (\\Flagged))\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_expunge(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, []), (2, []), (3, []), (4, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [2, 3], [(5, [])])
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 3 EXPUNGE\r\n'
            b'* 2 EXPUNGE\r\n'
            b'* 3 EXISTS\r\n'
            b'* 3 FETCH (FLAGS ())\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_all(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, [Flagged]), (2, []), (3, [])])
        forked, _ = selected.fork(self.uid_command)
        selected.session_flags.add_recent(6)
        self.set_messages(forked, [2, 3], [(1, [Seen, Flagged]), (4, [Seen]),
                                           (5, [Seen]), (6, [Flagged]),
                                           (7, [Seen])])
        _, untagged = forked.fork(self.uid_command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* 3 EXPUNGE\r\n'
            b'* 2 EXPUNGE\r\n'
            b'* 5 EXISTS\r\n'
            b'* 1 RECENT\r\n'
            b'* 1 FETCH (FLAGS (\\Flagged \\Seen) UID 1)\r\n'
            b'* 2 FETCH (FLAGS (\\Seen) UID 4)\r\n'
            b'* 3 FETCH (FLAGS (\\Seen) UID 5)\r\n'
            b'* 4 FETCH (FLAGS (\\Flagged \\Recent) UID 6)\r\n'
            b'* 5 FETCH (FLAGS (\\Seen) UID 7)\r\n'
            b'. OK testing\r\n', bytes(self.response))

    def test_add_untagged_deleted_bye(self) -> None:
        selected = self.new_selected()
        self.set_messages(selected, [], [(1, [])])
        forked, _ = selected.fork(self.command)
        self.set_messages(forked, [1], [(2, [])])
        forked.set_deleted()
        _, untagged = forked.fork(self.command)
        self.response.add_untagged(*untagged)
        self.assertEqual(
            b'* BYE Selected mailbox no longer exists.\r\n'
            b'. OK testing\r\n', bytes(self.response))
Ejemplo n.º 30
0
 async def do_noop(self, cmd: NoOpCommand) -> _CommandRet:
     updates = None
     if self._selected and self._session:
         updates = await self.session.check_mailbox(self.selected)
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), updates
Ejemplo n.º 31
0
 def test_bytes(self):
     resp1 = ResponseOk(b'tag', b'ok response')
     self.assertEqual(b'tag OK ok response\r\n', bytes(resp1))
     resp2 = ResponseOk(b'tag', b'ok response', _alert)
     self.assertEqual(b'tag OK [ALERT] ok response\r\n', bytes(resp2))
Ejemplo n.º 32
0
 async def do_delete(self, cmd: DeleteCommand) -> _CommandRet:
     if cmd.mailbox == 'INBOX':
         return ResponseNo(cmd.tag, b'Cannot delete INBOX.'), None
     updates = await self.session.delete_mailbox(
         cmd.mailbox, selected=self._selected)
     return ResponseOk(cmd.tag, cmd.command + b' completed.'), updates