Added the CAPA support (to determine any protocol extension).
Showing
1 changed file
with
86 additions
and
22 deletions
... | @@ -79,6 +79,7 @@ enum pop_state | ... | @@ -79,6 +79,7 @@ enum pop_state |
79 | POP_NO_STATE, POP_STATE_DONE, | 79 | POP_NO_STATE, POP_STATE_DONE, |
80 | POP_OPEN_CONNECTION, | 80 | POP_OPEN_CONNECTION, |
81 | POP_GREETINGS, | 81 | POP_GREETINGS, |
82 | POP_CAPA, POP_CAPA_ACK, | ||
82 | POP_APOP, POP_APOP_ACK, | 83 | POP_APOP, POP_APOP_ACK, |
83 | POP_DELE, POP_DELE_ACK, | 84 | POP_DELE, POP_DELE_ACK, |
84 | POP_LIST, POP_LIST_ACK, POP_LIST_RX, | 85 | POP_LIST, POP_LIST_ACK, POP_LIST_RX, |
... | @@ -87,6 +88,7 @@ enum pop_state | ... | @@ -87,6 +88,7 @@ enum pop_state |
87 | POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY, | 88 | POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY, |
88 | POP_RSET, POP_RSET_ACK, | 89 | POP_RSET, POP_RSET_ACK, |
89 | POP_STAT, POP_STAT_ACK, | 90 | POP_STAT, POP_STAT_ACK, |
91 | POP_STLS, POP_STLS_ACK, | ||
90 | POP_TOP, POP_TOP_ACK, POP_TOP_RX, | 92 | POP_TOP, POP_TOP_ACK, POP_TOP_RX, |
91 | POP_UIDL, POP_UIDL_ACK, | 93 | POP_UIDL, POP_UIDL_ACK, |
92 | POP_AUTH, POP_AUTH_DONE, | 94 | POP_AUTH, POP_AUTH_DONE, |
... | @@ -94,6 +96,19 @@ enum pop_state | ... | @@ -94,6 +96,19 @@ enum pop_state |
94 | POP_AUTH_PASS, POP_AUTH_PASS_ACK | 96 | POP_AUTH_PASS, POP_AUTH_PASS_ACK |
95 | }; | 97 | }; |
96 | 98 | ||
99 | /* POP3 capabilities */ | ||
100 | #define CAPA_TOP 0x00000001 | ||
101 | #define CAPA_USER 0x00000002 | ||
102 | #define CAPA_UIDL 0x00000004 | ||
103 | #define CAPA_RESP_CODES 0x00000008 | ||
104 | #define CAPA_LOGIN_DELAY 0x00000010 | ||
105 | #define CAPA_PIPELINING 0x00000020 | ||
106 | #define CAPA_EXPIRE 0x00000040 | ||
107 | #define CAPA_SASL 0x00000080 | ||
108 | #define CAPA_STLS 0x00000100 | ||
109 | #define CAPA_IMPLEMENTATION 0x00000200 | ||
110 | static unsigned long capa; | ||
111 | |||
97 | static void pop_destroy __P ((mailbox_t)); | 112 | static void pop_destroy __P ((mailbox_t)); |
98 | 113 | ||
99 | /* Functions/Methods that implements the mailbox_t API. */ | 114 | /* Functions/Methods that implements the mailbox_t API. */ |
... | @@ -540,9 +555,7 @@ _pop_apop (authority_t auth) | ... | @@ -540,9 +555,7 @@ _pop_apop (authority_t auth) |
540 | } | 555 | } |
541 | 556 | ||
542 | 557 | ||
543 | /* Open the connection to the sever, and send the authentication. | 558 | /* Open the connection to the sever, and send the authentication. */ |
544 | FIXME: Should also send the CAPA command to detect for example the suport | ||
545 | for TOP, APOP, ... and DTRT(Do The Right Thing). */ | ||
546 | static int | 559 | static int |
547 | pop_open (mailbox_t mbox, int flags) | 560 | pop_open (mailbox_t mbox, int flags) |
548 | { | 561 | { |
... | @@ -633,9 +646,60 @@ pop_open (mailbox_t mbox, int flags) | ... | @@ -633,9 +646,60 @@ pop_open (mailbox_t mbox, int flags) |
633 | { | 646 | { |
634 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); | 647 | CHECK_ERROR_CLOSE (mbox, mpd, EACCES); |
635 | } | 648 | } |
636 | mpd->state = POP_AUTH; | 649 | status = pop_writeline (mpd, "CAPA\r\n"); |
650 | CHECK_ERROR (mpd, status); | ||
651 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
652 | mpd->state = POP_CAPA; | ||
637 | } | 653 | } |
638 | 654 | ||
655 | case POP_CAPA: | ||
656 | status = pop_write (mpd); | ||
657 | CHECK_EAGAIN (mpd, status); | ||
658 | mpd->state = POP_CAPA_ACK; | ||
659 | |||
660 | case POP_CAPA_ACK: | ||
661 | status = pop_read_ack (mpd); | ||
662 | CHECK_EAGAIN (mpd, status); | ||
663 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
664 | |||
665 | if (!strncasecmp (mpd->buffer, "+OK", 3)) | ||
666 | { | ||
667 | capa = 0; | ||
668 | do | ||
669 | { | ||
670 | status = pop_read_ack (mpd); | ||
671 | MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer); | ||
672 | |||
673 | /* Here we check some common capabilities like TOP, USER, UIDL, | ||
674 | and STLS. The rest are ignored. Please note that some | ||
675 | capabilities might have an extra arguments. For instance, | ||
676 | SASL can have CRAM-MD5 and/or KERBEROS_V4, and etc. | ||
677 | This is why I suggest adding (in a future) an extra variable, | ||
678 | for example `capa_sasl'. It would hold the following flags: | ||
679 | SASL_CRAM_MD5, SASL_KERBEROS_V4, and so on. Also the EXPIRE | ||
680 | and LOGIN-DELAY capabilities have an extra arguments! | ||
681 | Note that there is no APOP capability, even though APOP | ||
682 | is an optional command in POP3. -- W.P. */ | ||
683 | |||
684 | if (!strncasecmp (mpd->buffer, "TOP", 3)) | ||
685 | capa |= CAPA_TOP; | ||
686 | else if (!strncasecmp (mpd->buffer, "USER", 4)) | ||
687 | capa |= CAPA_USER; | ||
688 | else if (!strncasecmp (mpd->buffer, "UIDL", 4)) | ||
689 | capa |= CAPA_UIDL; | ||
690 | else if (!strncasecmp (mpd->buffer, "STLS", 4)) | ||
691 | capa |= CAPA_STLS; | ||
692 | } | ||
693 | while (mpd->nl); | ||
694 | } | ||
695 | /* else | ||
696 | mu_error ("CAPA not implemented\n"); */ /* FIXME */ | ||
697 | |||
698 | case POP_STLS: | ||
699 | case POP_STLS_ACK: | ||
700 | |||
701 | mpd->state = POP_AUTH; | ||
702 | |||
639 | case POP_AUTH: | 703 | case POP_AUTH: |
640 | case POP_AUTH_USER: | 704 | case POP_AUTH_USER: |
641 | case POP_AUTH_USER_ACK: | 705 | case POP_AUTH_USER_ACK: |
... | @@ -1317,7 +1381,7 @@ pop_uid (message_t msg, size_t *puid) | ... | @@ -1317,7 +1381,7 @@ pop_uid (message_t msg, size_t *puid) |
1317 | 1381 | ||
1318 | /* Get the UIDL. Client should be prepare since it may fail. UIDL is | 1382 | /* Get the UIDL. Client should be prepare since it may fail. UIDL is |
1319 | optional on many POP servers. | 1383 | optional on many POP servers. |
1320 | FIXME: We should check this with CAPA and fall back to a md5 scheme ? | 1384 | FIXME: We should check the "capa & CAPA_UIDL" and fall back to a md5 scheme ? |
1321 | Or maybe check for "X-UIDL" a la Qpopper ? */ | 1385 | Or maybe check for "X-UIDL" a la Qpopper ? */ |
1322 | static int | 1386 | static int |
1323 | pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | 1387 | pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
... | @@ -1419,7 +1483,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) | ... | @@ -1419,7 +1483,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten) |
1419 | } | 1483 | } |
1420 | 1484 | ||
1421 | /* How we retrieve the headers. If it fails we jump to the pop_retr() | 1485 | /* How we retrieve the headers. If it fails we jump to the pop_retr() |
1422 | code .i.e send a RETR and skip the body, ugly. | 1486 | code i.e. send a RETR and skip the body, ugly. |
1423 | NOTE: if the offset is different, flag an error, offset is meaningless | 1487 | NOTE: if the offset is different, flag an error, offset is meaningless |
1424 | on a socket but we better warn them, some stuff like mime_t may try to | 1488 | on a socket but we better warn them, some stuff like mime_t may try to |
1425 | read ahead, for example for the headers. */ | 1489 | read ahead, for example for the headers. */ |
... | @@ -1454,13 +1518,20 @@ pop_top (header_t header, char *buffer, size_t buflen, | ... | @@ -1454,13 +1518,20 @@ pop_top (header_t header, char *buffer, size_t buflen, |
1454 | switch (mpd->state) | 1518 | switch (mpd->state) |
1455 | { | 1519 | { |
1456 | case POP_NO_STATE: | 1520 | case POP_NO_STATE: |
1457 | /* TOP is an optionnal command, if we want to be compliant we can not | 1521 | if (capa & CAPA_TOP) |
1458 | count on it to exists. So we should be prepare when it fails and | 1522 | { |
1459 | fall to a second scheme. */ | 1523 | status = pop_writeline (mpd, "TOP %d 0\r\n", mpm->num); |
1460 | status = pop_writeline (mpd, "TOP %d 0\r\n", mpm->num); | 1524 | CHECK_ERROR (mpd, status); |
1461 | CHECK_ERROR (mpd, status); | 1525 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1462 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); | 1526 | mpd->state = POP_TOP; |
1463 | mpd->state = POP_TOP; | 1527 | } |
1528 | else /* Fall back to RETR call. */ | ||
1529 | { | ||
1530 | mpd->state = POP_NO_STATE; | ||
1531 | mpm->skip_header = 0; | ||
1532 | mpm->skip_body = 1; | ||
1533 | return pop_retr (mpm, buffer, buflen, offset, pnread); | ||
1534 | } | ||
1464 | 1535 | ||
1465 | case POP_TOP: | 1536 | case POP_TOP: |
1466 | /* Send the TOP. */ | 1537 | /* Send the TOP. */ |
... | @@ -1473,15 +1544,8 @@ pop_top (header_t header, char *buffer, size_t buflen, | ... | @@ -1473,15 +1544,8 @@ pop_top (header_t header, char *buffer, size_t buflen, |
1473 | status = pop_read_ack (mpd); | 1544 | status = pop_read_ack (mpd); |
1474 | CHECK_EAGAIN (mpd, status); | 1545 | CHECK_EAGAIN (mpd, status); |
1475 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); | 1546 | MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer); |
1476 | if (strncasecmp (mpd->buffer, "+OK", 3) != 0) | 1547 | /* if (strncasecmp (mpd->buffer, "+OK", 3) != 0) |
1477 | { | 1548 | mu_error ("TOP not implemented\n"); */ /* FIXME */ |
1478 | /* mu_error ("TOP not implemented\n"); */ | ||
1479 | /* Fall back to RETR call. */ | ||
1480 | mpd->state = POP_NO_STATE; | ||
1481 | mpm->skip_header = 0; | ||
1482 | mpm->skip_body = 1; | ||
1483 | return pop_retr (mpm, buffer, buflen, offset, pnread); | ||
1484 | } | ||
1485 | mpd->state = POP_TOP_RX; | 1549 | mpd->state = POP_TOP_RX; |
1486 | 1550 | ||
1487 | case POP_TOP_RX: | 1551 | case POP_TOP_RX: | ... | ... |
-
Please register or sign in to post a comment