/* * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include #include "Protocol.h" #include "Response.h" #include "argv.h" struct cmd_entry { const char* name; void (*func)(int argc, char **argv); const char* help; }; static void do_help(int argc, char** argv); extern const char* __progname; static const char* kProgramName = __progname; static IMAP::Protocol sProtocol; static void error(const char* context, status_t status) { fprintf(stderr, "Error during %s: %s\n", context, strerror(status)); } static void usage() { printf("Usage: %s \n", kProgramName); exit(1); } // #pragma mark - static void do_select(int argc, char** argv) { const char* folder = "INBOX"; if (argc > 1) folder = argv[1]; IMAP::SelectCommand command(folder); status_t status = sProtocol.ProcessCommand(command); if (status == B_OK) { printf("Next UID: %" B_PRIu32 ", UID validity: %" B_PRIu32 "\n", command.NextUID(), command.UIDValidity()); } else error("select", status); } static void do_folders(int argc, char** argv) { IMAP::FolderList folders; BString separator; status_t status = sProtocol.GetFolders(folders, separator); if (status != B_OK) { error("folders", status); return; } for (size_t i = 0; i < folders.size(); i++) { printf(" %s %s\n", folders[i].subscribed ? "*" : " ", folders[i].folder.String()); } } static void do_fetch(int argc, char** argv) { uint32 from = 1; uint32 to; uint32 flags = IMAP::kFetchAll; if (argc < 2) { printf("usage: %s [] [] [header|body]\n", argv[0]); return; } if (argc > 2) { if (!strcasecmp(argv[argc - 1], "header")) { flags = IMAP::kFetchHeader; argc--; } else if (!strcasecmp(argv[argc - 1], "body")) { flags = IMAP::kFetchBody; argc--; } } if (argc > 2) { from = atoul(argv[1]); to = atoul(argv[2]); } else from = to = atoul(argv[1]); IMAP::FetchCommand command(from, to, flags | IMAP::kFetchFlags); // A fetch listener that dumps everything to stdout class Listener : public IMAP::FetchListener { public: virtual ~Listener() { } virtual bool FetchData(uint32 fetchFlags, BDataIO& stream, size_t& length) { fBuffer.SetSize(0); char buffer[65535]; while (length > 0) { ssize_t bytesRead = stream.Read(buffer, min_c(sizeof(buffer), length)); if (bytesRead <= 0) break; fBuffer.Write(buffer, bytesRead); length -= bytesRead; } // Null terminate the buffer char null = '\0'; fBuffer.Write(&null, 1); return true; } virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags) { printf("================= UID %ld, flags %lx =================\n", uid, flags); puts((const char*)fBuffer.Buffer()); } private: BMallocIO fBuffer; } listener; command.SetListener(&listener); status_t status = sProtocol.ProcessCommand(command); if (status != B_OK) { error("fetch", status); return; } } static void do_flags(int argc, char** argv) { uint32 from = 1; uint32 to; if (argc < 2) { printf("usage: %s [] []\n", argv[0]); return; } if (argc > 2) { from = atoul(argv[1]); to = atoul(argv[2]); } else to = atoul(argv[1]); IMAP::MessageEntryList entries; IMAP::FetchMessageEntriesCommand command(entries, from, to, true); status_t status = sProtocol.ProcessCommand(command); if (status != B_OK) { error("flags", status); return; } for (size_t i = 0; i < entries.size(); i++) { printf("%10lu %8lu bytes, flags: %#lx\n", entries[i].uid, entries[i].size, entries[i].flags); } } static void do_noop(int argc, char** argv) { IMAP::RawCommand command("NOOP"); status_t status = sProtocol.ProcessCommand(command); if (status != B_OK) error("noop", status); } static void do_raw(int argc, char** argv) { // build command back again char command[4096]; command[0] = '\0'; for (int i = 1; i < argc; i++) { if (i > 1) strlcat(command, " ", sizeof(command)); strlcat(command, argv[i], sizeof(command)); } class RawCommand : public IMAP::Command, public IMAP::Handler { public: RawCommand(const char* command) : fCommand(command) { } BString CommandString() { return fCommand; } bool HandleUntagged(IMAP::Response& response) { if (response.IsCommand(fCommand)) { printf("-> %s\n", response.ToString().String()); return true; } return false; } private: const char* fCommand; }; RawCommand rawCommand(command); status_t status = sProtocol.ProcessCommand(rawCommand); if (status != B_OK) error("raw", status); } static cmd_entry sBuiltinCommands[] = { {"select", do_select, "Selects a mailbox, defaults to INBOX"}, {"folders", do_folders, "List of existing folders"}, {"flags", do_flags, "List of all mail UIDs in the mailbox with their flags"}, {"fetch", do_fetch, "Fetch mails via UIDs"}, {"noop", do_noop, "Issue a NOOP command (will report new messages)"}, {"raw", do_raw, "Issue a raw command to the server"}, {"help", do_help, "prints this help text"}, {"quit", NULL, "exits the application"}, {NULL, NULL, NULL}, }; static void do_help(int argc, char** argv) { printf("Available commands:\n"); for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) { printf("%8s - %s\n", command->name, command->help); } } // #pragma mark - int main(int argc, char** argv) { if (argc < 4) usage(); const char* server = argv[1]; const char* user = argv[2]; const char* password = argv[3]; bool useSSL = argc > 4; uint16 port = useSSL ? 993 : 143; BNetworkAddress address(AF_INET, server, port); printf("Connecting to \"%s\" as %s%s, port %u\n", server, user, useSSL ? " with SSL" : "", address.Port()); status_t status = sProtocol.Connect(address, user, password, useSSL); if (status != B_OK) { error("connect", status); return 1; } while (true) { printf("> "); fflush(stdout); char line[1024]; if (fgets(line, sizeof(line), stdin) == NULL) break; argc = 0; argv = build_argv(line, &argc); if (argv == NULL || argc == 0) continue; if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit") || !strcmp(argv[0], "q")) break; int length = strlen(argv[0]); bool found = false; for (cmd_entry* command = sBuiltinCommands; command->name != NULL; command++) { if (!strncmp(command->name, argv[0], length)) { command->func(argc, argv); found = true; break; } } if (!found) { fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a " "list of commands.\n", argv[0]); } free(argv); } return 0; }