#include <stdlib.h>
#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 <server> <username> <password>\n", kProgramName);
exit(1);
}
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 [<from>] [<to>] [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);
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;
}
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 [<from>] [<to>]\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)
{
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);
}
}
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;
}