// vim: set ft=c: #define IMAP_ROUTINE(name) \ name: { \ return imap_routine_##name(cmd, node, ssl, state); \ } #define IMAP_ROUTINE_BAD_TAG \ imap_write(node, ssl, "%s BAD\n", cmd.tag); #define IMAP_ROUTINE_BAD \ imap_write(node, ssl, "* BAD\n"); #define IMAP_CHECK_ARGS(x) \ if (cmd.p_count != x) { \ IMAP_ROUTINE_BAD_TAG \ return IMAP_FAIL; \ } #define IMAP_ROUTINE_END imap_flush(node, ssl); #define IMAP_ROUTINE_OK(routine) \ imap_write(node, ssl, "%s OK " #routine " completed\n", cmd.tag); #define IMAP_ROUTINE_NO(routine) \ imap_write(node, ssl, "%s NO " #routine " completed\n", cmd.tag); #define IMAP_STRING(fmt, ...) \ imap_write(node, ssl, fmt, ##__VA_ARGS__); #define IMAP_NLINE imap_write(node, ssl, "\n"); #define IMAP_CHECK_STATE(s) \ if (state != IMAP_STATE_##s) { \ IMAP_ROUTINE_BAD \ return IMAP_FAIL; \ } static inline uint8_t imap_routine_capability(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { char *cap; IMAP_STRING("* CAPABILITY") if (!ssl) { for (int i=0; (cap = imap_capabilities[i]); i++) { IMAP_STRING(" %s", cap) } } else { for (int i=0; (cap = imaps_capabilities[i]); i++) { IMAP_STRING(" %s", cap) } } IMAP_NLINE; IMAP_ROUTINE_OK(CAPABILITY) IMAP_ROUTINE_END return IMAP_SUCCESS; } static inline uint8_t imap_routine_noop(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { IMAP_ROUTINE_OK(NOOP) IMAP_ROUTINE_END return IMAP_SUCCESS; } static inline uint8_t imap_routine_logout(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { IMAP_STRING("* BYE IMAP4rev1 Server logging out\n") IMAP_ROUTINE_OK(LOGOUT) IMAP_ROUTINE_END return IMAP_LOGOUT; } static inline uint8_t imap_routine_starttls(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { IMAP_CHECK_STATE(NO_AUTH) IMAP_STRING("%s OK Begin TLS negotiation now\n", cmd.tag) IMAP_ROUTINE_END return IMAP_STARTTLS; } static inline uint8_t imap_routine_auth(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { IMAP_CHECK_STATE(NO_AUTH) IMAP_CHECK_ARGS(1) int bytes; if (strcmp(cmd.params[0], "plain") == 0) { IMAP_STRING("+\n"); if ((bytes = imap_read(node, buf, CMD_MAX_SIZE, ssl)) < 0) { perror("recv"); syslog(LOG_ERR, "Failed to receive data."); } else if (bytes == 0) { return IMAP_LOGOUT; } else { buf[bytes] = '\0'; printf("%s\n", buf); } } else { IMAP_ROUTINE_BAD_TAG } IMAP_ROUTINE_END return IMAP_SUCCESS; } static inline uint8_t imap_routine_login(imap_cmd cmd, client_list *node, uint8_t ssl, uint8_t state) { IMAP_CHECK_STATE(NO_AUTH) IMAP_CHECK_ARGS(2) size_t users = sizeof(imap_users)/sizeof(struct user); uint8_t found = 0; for (size_t i=0; i < users; i++) { if (strcmp(cmd.params[0], imap_users[i].username) == 0) { char hash[65]; auth_sha256(cmd.params[1], hash); if (strcmp(hash, imap_users[i].password) == 0) { IMAP_ROUTINE_OK(LOGIN) found = 1; } } } if (!found) { IMAP_ROUTINE_NO(LOGIN) } IMAP_ROUTINE_END return IMAP_SUCCESS; }