Iterable IDLE context manager: start IDLE & produce untagged responses. An object of this type is returned by the IMAP4.idle() method. Note: The name and structure of this class are subject to change.
| 1422 | |
| 1423 | |
| 1424 | class Idler: |
| 1425 | """Iterable IDLE context manager: start IDLE & produce untagged responses. |
| 1426 | |
| 1427 | An object of this type is returned by the IMAP4.idle() method. |
| 1428 | |
| 1429 | Note: The name and structure of this class are subject to change. |
| 1430 | """ |
| 1431 | |
| 1432 | def __init__(self, imap, duration=None): |
| 1433 | if 'IDLE' not in imap.capabilities: |
| 1434 | raise imap.error("Server does not support IMAP4 IDLE") |
| 1435 | if duration is not None and not imap.sock: |
| 1436 | # IMAP4_stream pipes don't support timeouts |
| 1437 | raise imap.error('duration requires a socket connection') |
| 1438 | self._duration = duration |
| 1439 | self._deadline = None |
| 1440 | self._imap = imap |
| 1441 | self._tag = None |
| 1442 | self._saved_state = None |
| 1443 | |
| 1444 | def __enter__(self): |
| 1445 | imap = self._imap |
| 1446 | assert not imap._idle_responses |
| 1447 | assert not imap._idle_capture |
| 1448 | |
| 1449 | if __debug__ and imap.debug >= 4: |
| 1450 | imap._mesg(f'idle start duration={self._duration}') |
| 1451 | |
| 1452 | # Start capturing untagged responses before sending IDLE, |
| 1453 | # so we can deliver via iteration any that arrive while |
| 1454 | # the IDLE command continuation request is still pending. |
| 1455 | imap._idle_capture = True |
| 1456 | |
| 1457 | try: |
| 1458 | self._tag = imap._command('IDLE') |
| 1459 | # As with any command, the server is allowed to send us unrelated, |
| 1460 | # untagged responses before acting on IDLE. These lines will be |
| 1461 | # returned by _get_response(). When the server is ready, it will |
| 1462 | # send an IDLE continuation request, indicated by _get_response() |
| 1463 | # returning None. We therefore process responses in a loop until |
| 1464 | # this occurs. |
| 1465 | while resp := imap._get_response(): |
| 1466 | if imap.tagged_commands[self._tag]: |
| 1467 | typ, data = imap.tagged_commands.pop(self._tag) |
| 1468 | if typ == 'NO': |
| 1469 | raise imap.error(f'idle denied: {data}') |
| 1470 | raise imap.abort(f'unexpected status response: {resp}') |
| 1471 | |
| 1472 | if __debug__ and imap.debug >= 4: |
| 1473 | prompt = imap.continuation_response |
| 1474 | imap._mesg(f'idle continuation prompt: {prompt}') |
| 1475 | except BaseException: |
| 1476 | imap._idle_capture = False |
| 1477 | raise |
| 1478 | |
| 1479 | if self._duration is not None: |
| 1480 | self._deadline = time.monotonic() + self._duration |
| 1481 |