vfs: check userland buffers before reading them.
[haiku.git] / src / tests / add-ons / mail / imap / imap_tester.cpp
blob571bc818717de2f5ad7fe15e7e79aaf24013ed95
1 /*
2 * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <stdlib.h>
9 #include "Protocol.h"
10 #include "Response.h"
12 #include "argv.h"
15 struct cmd_entry {
16 const char* name;
17 void (*func)(int argc, char **argv);
18 const char* help;
22 static void do_help(int argc, char** argv);
25 extern const char* __progname;
26 static const char* kProgramName = __progname;
28 static IMAP::Protocol sProtocol;
31 static void
32 error(const char* context, status_t status)
34 fprintf(stderr, "Error during %s: %s\n", context, strerror(status));
38 static void
39 usage()
41 printf("Usage: %s <server> <username> <password>\n", kProgramName);
42 exit(1);
46 // #pragma mark -
49 static void
50 do_select(int argc, char** argv)
52 const char* folder = "INBOX";
53 if (argc > 1)
54 folder = argv[1];
56 IMAP::SelectCommand command(folder);
57 status_t status = sProtocol.ProcessCommand(command);
58 if (status == B_OK) {
59 printf("Next UID: %" B_PRIu32 ", UID validity: %" B_PRIu32 "\n",
60 command.NextUID(), command.UIDValidity());
61 } else
62 error("select", status);
66 static void
67 do_folders(int argc, char** argv)
69 IMAP::FolderList folders;
70 BString separator;
72 status_t status = sProtocol.GetFolders(folders, separator);
73 if (status != B_OK) {
74 error("folders", status);
75 return;
78 for (size_t i = 0; i < folders.size(); i++) {
79 printf(" %s %s\n", folders[i].subscribed ? "*" : " ",
80 folders[i].folder.String());
85 static void
86 do_fetch(int argc, char** argv)
88 uint32 from = 1;
89 uint32 to;
90 uint32 flags = IMAP::kFetchAll;
91 if (argc < 2) {
92 printf("usage: %s [<from>] [<to>] [header|body]\n", argv[0]);
93 return;
95 if (argc > 2) {
96 if (!strcasecmp(argv[argc - 1], "header")) {
97 flags = IMAP::kFetchHeader;
98 argc--;
99 } else if (!strcasecmp(argv[argc - 1], "body")) {
100 flags = IMAP::kFetchBody;
101 argc--;
104 if (argc > 2) {
105 from = atoul(argv[1]);
106 to = atoul(argv[2]);
107 } else
108 from = to = atoul(argv[1]);
110 IMAP::FetchCommand command(from, to, flags | IMAP::kFetchFlags);
112 // A fetch listener that dumps everything to stdout
113 class Listener : public IMAP::FetchListener {
114 public:
115 virtual ~Listener()
119 virtual bool FetchData(uint32 fetchFlags, BDataIO& stream,
120 size_t& length)
122 fBuffer.SetSize(0);
124 char buffer[65535];
125 while (length > 0) {
126 ssize_t bytesRead = stream.Read(buffer,
127 min_c(sizeof(buffer), length));
128 if (bytesRead <= 0)
129 break;
131 fBuffer.Write(buffer, bytesRead);
132 length -= bytesRead;
135 // Null terminate the buffer
136 char null = '\0';
137 fBuffer.Write(&null, 1);
139 return true;
142 virtual void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags)
144 printf("================= UID %ld, flags %lx =================\n",
145 uid, flags);
146 puts((const char*)fBuffer.Buffer());
149 private:
150 BMallocIO fBuffer;
151 } listener;
153 command.SetListener(&listener);
155 status_t status = sProtocol.ProcessCommand(command);
156 if (status != B_OK) {
157 error("fetch", status);
158 return;
163 static void
164 do_flags(int argc, char** argv)
166 uint32 from = 1;
167 uint32 to;
168 if (argc < 2) {
169 printf("usage: %s [<from>] [<to>]\n", argv[0]);
170 return;
172 if (argc > 2) {
173 from = atoul(argv[1]);
174 to = atoul(argv[2]);
175 } else
176 to = atoul(argv[1]);
178 IMAP::MessageEntryList entries;
179 IMAP::FetchMessageEntriesCommand command(entries, from, to, true);
180 status_t status = sProtocol.ProcessCommand(command);
181 if (status != B_OK) {
182 error("flags", status);
183 return;
186 for (size_t i = 0; i < entries.size(); i++) {
187 printf("%10lu %8lu bytes, flags: %#lx\n", entries[i].uid,
188 entries[i].size, entries[i].flags);
193 static void
194 do_noop(int argc, char** argv)
196 IMAP::RawCommand command("NOOP");
197 status_t status = sProtocol.ProcessCommand(command);
198 if (status != B_OK)
199 error("noop", status);
203 static void
204 do_raw(int argc, char** argv)
206 // build command back again
207 char command[4096];
208 command[0] = '\0';
210 for (int i = 1; i < argc; i++) {
211 if (i > 1)
212 strlcat(command, " ", sizeof(command));
213 strlcat(command, argv[i], sizeof(command));
216 class RawCommand : public IMAP::Command, public IMAP::Handler {
217 public:
218 RawCommand(const char* command)
220 fCommand(command)
224 BString CommandString()
226 return fCommand;
229 bool HandleUntagged(IMAP::Response& response)
231 if (response.IsCommand(fCommand)) {
232 printf("-> %s\n", response.ToString().String());
233 return true;
236 return false;
239 private:
240 const char* fCommand;
242 RawCommand rawCommand(command);
243 status_t status = sProtocol.ProcessCommand(rawCommand);
244 if (status != B_OK)
245 error("raw", status);
249 static cmd_entry sBuiltinCommands[] = {
250 {"select", do_select, "Selects a mailbox, defaults to INBOX"},
251 {"folders", do_folders, "List of existing folders"},
252 {"flags", do_flags,
253 "List of all mail UIDs in the mailbox with their flags"},
254 {"fetch", do_fetch,
255 "Fetch mails via UIDs"},
256 {"noop", do_noop, "Issue a NOOP command (will report new messages)"},
257 {"raw", do_raw, "Issue a raw command to the server"},
258 {"help", do_help, "prints this help text"},
259 {"quit", NULL, "exits the application"},
260 {NULL, NULL, NULL},
264 static void
265 do_help(int argc, char** argv)
267 printf("Available commands:\n");
269 for (cmd_entry* command = sBuiltinCommands; command->name != NULL;
270 command++) {
271 printf("%8s - %s\n", command->name, command->help);
276 // #pragma mark -
280 main(int argc, char** argv)
282 if (argc < 4)
283 usage();
285 const char* server = argv[1];
286 const char* user = argv[2];
287 const char* password = argv[3];
288 bool useSSL = argc > 4;
289 uint16 port = useSSL ? 993 : 143;
291 BNetworkAddress address(AF_INET, server, port);
292 printf("Connecting to \"%s\" as %s%s, port %u\n", server, user,
293 useSSL ? " with SSL" : "", address.Port());
295 status_t status = sProtocol.Connect(address, user, password, useSSL);
296 if (status != B_OK) {
297 error("connect", status);
298 return 1;
301 while (true) {
302 printf("> ");
303 fflush(stdout);
305 char line[1024];
306 if (fgets(line, sizeof(line), stdin) == NULL)
307 break;
309 argc = 0;
310 argv = build_argv(line, &argc);
311 if (argv == NULL || argc == 0)
312 continue;
314 if (!strcmp(argv[0], "quit")
315 || !strcmp(argv[0], "exit")
316 || !strcmp(argv[0], "q"))
317 break;
319 int length = strlen(argv[0]);
320 bool found = false;
322 for (cmd_entry* command = sBuiltinCommands; command->name != NULL;
323 command++) {
324 if (!strncmp(command->name, argv[0], length)) {
325 command->func(argc, argv);
326 found = true;
327 break;
331 if (!found) {
332 fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a "
333 "list of commands.\n", argv[0]);
336 free(argv);
340 return 0;