#include #include #include #include #include #include "imapfilter.h" #include "session.h" #include "buffer.h" extern options opts; buffer obuf; /* Output buffer. */ static int tag = 0x1000; /* Every IMAP command is prefixed with a * unique [:alnum:] string. */ int send_command(session *ssn, char *cmd, char *alt); void prepare_command(const char *fmt,...); /* * Sends to server data; a command. */ int send_command(session *ssn, char *cmd, char *alt) { if (ssn->socket == -1) return -1; debug("sending command (%d):\n\n%s\n", ssn->socket, (opts.debug == 1 && alt ? alt : cmd)); verbose("C (%d): %s", ssn->socket, (alt ? alt : cmd)); if (socket_write(ssn, cmd, strlen(cmd)) == -1) return -1; if (tag == 0xFFFF) /* Tag always between 0x1000 and 0xFFFF. */ tag = 0x0FFF; return tag++; } /* * Prepares data for sending and check that the output buffer size is * sufficient. */ void prepare_command(const char *fmt,...) { int n; va_list args; va_start(args, fmt); buffer_reset(&obuf); n = vsnprintf(obuf.data, obuf.size + 1, fmt, args); if (n > (int)obuf.size) { buffer_check(&obuf, n); vsnprintf(obuf.data, obuf.size + 1, fmt, args); } va_end(args); } /* * Sends a response to a command continuation request. */ int imap_continuation(session *ssn, const char *cont, size_t len) { if (ssn->socket == -1) return -1; if (socket_write(ssn, cont, len) == -1 || socket_write(ssn, "\r\n", strlen("\r\n")) == -1) return -1; if (opts.debug > 0) { unsigned int i; debug("sending continuation data (%d):\n\n", ssn->socket); for (i = 0; i < len; i++) debugc(cont[i]); debug("\r\n\n"); } return 0; } /* * IMAP CAPABILITY: requests listing of capabilities that the server supports. */ int imap_capability(session *ssn) { prepare_command("%04X CAPABILITY\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP NOOP: does nothing always succeeds. */ int imap_noop(session *ssn) { prepare_command("%04X NOOP\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP LOGOUT: informs server that client is done. */ int imap_logout(session *ssn) { prepare_command("%04X LOGOUT\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP STARTTLS: begins TLS negotiation. */ int imap_starttls(session *ssn) { prepare_command("%04X STARTTLS\r\n", tag); return send_command(ssn, obuf.data, NULL); } #ifndef NO_CRAMMD5 /* * IMAP AUTHENTICATE: indicates authentication mechanism and performs an * authentication protocol exchange. */ int imap_authenticate(session *ssn, const char *auth) { prepare_command("%04X AUTHENTICATE %s\r\n", tag, auth); return send_command(ssn, obuf.data, NULL); } #endif /* * IMAP LOGIN: identifies client to server. */ int imap_login(session *ssn, const char *user, const char *pass) { int n, r; char c; char *s; /* Command to send to server. */ prepare_command("%04X LOGIN \"%s\" \"%s\"\r\n", tag, user, pass); /* Alternate command with password shrouded for safe printing. */ n = snprintf(&c, 1, "%04X LOGIN \"%s\" *\r\n", tag, user); s = (char *)xmalloc((n + 1) * sizeof(char)); snprintf(s, n + 1, "%04X LOGIN \"%s\" *\r\n", tag, user); r = send_command(ssn, obuf.data, s); xfree(s); return r; } /* * IMAP SELECT: accesses a mailbox in READ-WRITE mode. */ int imap_select(session *ssn, const char *mbox) { prepare_command("%04X SELECT \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP EXAMINE: accesses a mailbox in READ-ONLY mode. */ int imap_examine(session *ssn, const char *mbox) { prepare_command("%04X EXAMINE \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP CREATE: creates mailbox. */ int imap_create(session *ssn, const char *mbox) { prepare_command("%04X CREATE \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP DELETE: deletes mailbox. */ int imap_delete(session *ssn, const char *mbox) { prepare_command("%04X DELETE \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP RENAME: renames mailbox. */ int imap_rename(session *ssn, const char *oldmbox, const char *newmbox) { prepare_command("%04X RENAME \"%s\" \"%s\"\r\n", tag, oldmbox, newmbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP SUBSCRIBE: adds the specified mailbox name to the server's set of * "active" or "subscribed" mailboxes. */ int imap_subscribe(session *ssn, const char *mbox) { prepare_command("%04X SUBSCRIBE \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP UNSUBSCRIBE: removes the specified mailbox name to the server's set of * "active" or "subscribed" mailboxes. */ int imap_unsubscribe(session *ssn, const char *mbox) { prepare_command("%04X UNSUBSCRIBE \"%s\"\r\n", tag, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP LIST: returns a subset of names from the complete set of all names * available. */ int imap_list(session *ssn, const char *refer, const char *name) { prepare_command("%04X LIST \"%s\" \"%s\"\r\n", tag, refer, name); return send_command(ssn, obuf.data, NULL); } /* * IMAP LSUB: returns a subset of names from the set of names that the user has * declared as being "active" or "subscribed". */ int imap_lsub(session *ssn, const char *refer, const char *name) { prepare_command("%04X LSUB \"%s\" \"%s\"\r\n", tag, refer, name); return send_command(ssn, obuf.data, NULL); } /* * IMAP STATUS: requests status of the indicated mailbox. */ int imap_status(session *ssn, const char *mbox, const char *items) { prepare_command("%04X STATUS \"%s\" (%s)\r\n", tag, mbox, items); return send_command(ssn, obuf.data, NULL); } /* * IMAP APPEND: append message to the end of a mailbox. */ int imap_append(session *ssn, const char *mbox, const char *flags, const char *date, unsigned int size) { prepare_command("%04X APPEND \"%s\"%s%s%s%s%s%s {%d}\r\n", tag, mbox, (flags ? " (" : ""), (flags ? flags : ""), (flags ? ")" : ""), (date ? " \"" : ""), (date ? date : ""), (date ? "\"" : ""), size); return send_command(ssn, obuf.data, NULL); } /* * IMAP CHECK: requests a checkpoint of the currently selected mailbox. */ int imap_check(session *ssn) { prepare_command("%04X CHECK\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP CLOSE: deletes messages and returns to authenticated state. */ int imap_close(session *ssn) { prepare_command("%04X CLOSE\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP EXPUNGE: permanently removes any messages with the \Deleted flag set. */ int imap_expunge(session *ssn) { prepare_command("%04X EXPUNGE\r\n", tag); return send_command(ssn, obuf.data, NULL); } /* * IMAP SEARCH: searches the mailbox for messages that match certain criteria. */ int imap_search(session *ssn, const char *charset, const char *criteria) { if (charset != NULL && *charset != '\0') prepare_command("%04X UID SEARCH CHARSET \"%s\" %s\r\n", tag, charset, criteria); else prepare_command("%04X UID SEARCH %s\r\n", tag, criteria); return send_command(ssn, obuf.data, NULL); } /* * IMAP FETCH: retrieves data associated with a message. */ int imap_fetch(session *ssn, const char *mesg, const char *items) { prepare_command("%04X UID FETCH %s %s\r\n", tag, mesg, items); return send_command(ssn, obuf.data, NULL); } /* * IMAP STORE: alters data associated with a message. */ int imap_store(session *ssn, const char *mesg, const char *mode, const char *flags) { prepare_command("%04X UID STORE %s %sFLAGS.SILENT (%s)\r\n", tag, mesg, (!strncasecmp(mode, "add", 3) ? "+" : !strncasecmp(mode, "remove", 6) ? "-" : ""), flags); return send_command(ssn, obuf.data, NULL); } /* * IMAP COPY: copy messages to mailbox. */ int imap_copy(session *ssn, const char *mesg, const char *mbox) { prepare_command("%04X UID COPY %s \"%s\"\r\n", tag, mesg, mbox); return send_command(ssn, obuf.data, NULL); } /* * IMAP NAMESPACE: discovers the prefix and delimeter of namespaces used by the * server for mailboxes (RFC 2342). */ int imap_namespace(session *ssn) { prepare_command("%04X NAMESPACE\r\n", tag); return send_command(ssn, obuf.data, NULL); }