xref: /haiku/src/tests/add-ons/mail/imap/imap_tester.cpp (revision c1f779e3500b6157de46ccdf7ddccd70850beab9)
1 /*
2  * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <stdlib.h>
8 
9 #include "Protocol.h"
10 #include "Response.h"
11 
12 #include "argv.h"
13 
14 
15 struct cmd_entry {
16 	const char*	name;
17 	void		(*func)(int argc, char **argv);
18 	const char*	help;
19 };
20 
21 
22 static void do_help(int argc, char** argv);
23 
24 
25 extern const char* __progname;
26 static const char* kProgramName = __progname;
27 
28 static IMAP::Protocol sProtocol;
29 
30 
31 static void
error(const char * context,status_t status)32 error(const char* context, status_t status)
33 {
34 	fprintf(stderr, "Error during %s: %s\n", context, strerror(status));
35 }
36 
37 
38 static void
usage()39 usage()
40 {
41 	printf("Usage: %s <server> <username> <password>\n", kProgramName);
42 	exit(1);
43 }
44 
45 
46 // #pragma mark -
47 
48 
49 static void
do_select(int argc,char ** argv)50 do_select(int argc, char** argv)
51 {
52 	const char* folder = "INBOX";
53 	if (argc > 1)
54 		folder = argv[1];
55 
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);
63 }
64 
65 
66 static void
do_folders(int argc,char ** argv)67 do_folders(int argc, char** argv)
68 {
69 	IMAP::FolderList folders;
70 	BString separator;
71 
72 	status_t status = sProtocol.GetFolders(folders, separator);
73 	if (status != B_OK) {
74 		error("folders", status);
75 		return;
76 	}
77 
78 	for (size_t i = 0; i < folders.size(); i++) {
79 		printf(" %s %s\n", folders[i].subscribed ? "*" : " ",
80 			folders[i].folder.String());
81 	}
82 }
83 
84 
85 static void
do_fetch(int argc,char ** argv)86 do_fetch(int argc, char** argv)
87 {
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;
94 	}
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--;
102 		}
103 	}
104 	if (argc > 2) {
105 		from = atoul(argv[1]);
106 		to = atoul(argv[2]);
107 	} else
108 		from = to = atoul(argv[1]);
109 
110 	IMAP::FetchCommand command(from, to, flags | IMAP::kFetchFlags);
111 
112 	// A fetch listener that dumps everything to stdout
113 	class Listener : public IMAP::FetchListener {
114 	public:
115 		virtual ~Listener()
116 		{
117 		}
118 
119 		virtual	bool FetchData(uint32 fetchFlags, BDataIO& stream,
120 			size_t& length)
121 		{
122 			fBuffer.SetSize(0);
123 
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;
130 
131 				fBuffer.Write(buffer, bytesRead);
132 				length -= bytesRead;
133 			}
134 
135 			// Null terminate the buffer
136 			char null = '\0';
137 			fBuffer.Write(&null, 1);
138 
139 			return true;
140 		}
141 
142 		virtual	void FetchedData(uint32 fetchFlags, uint32 uid, uint32 flags)
143 		{
144 			printf("================= UID %ld, flags %lx =================\n",
145 				uid, flags);
146 			puts((const char*)fBuffer.Buffer());
147 		}
148 
149 	private:
150 		BMallocIO	fBuffer;
151 	} listener;
152 
153 	command.SetListener(&listener);
154 
155 	status_t status = sProtocol.ProcessCommand(command);
156 	if (status != B_OK) {
157 		error("fetch", status);
158 		return;
159 	}
160 }
161 
162 
163 static void
do_flags(int argc,char ** argv)164 do_flags(int argc, char** argv)
165 {
166 	uint32 from = 1;
167 	uint32 to;
168 	if (argc < 2) {
169 		printf("usage: %s [<from>] [<to>]\n", argv[0]);
170 		return;
171 	}
172 	if (argc > 2) {
173 		from = atoul(argv[1]);
174 		to = atoul(argv[2]);
175 	} else
176 		to = atoul(argv[1]);
177 
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;
184 	}
185 
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);
189 	}
190 }
191 
192 
193 static void
do_noop(int argc,char ** argv)194 do_noop(int argc, char** argv)
195 {
196 	IMAP::RawCommand command("NOOP");
197 	status_t status = sProtocol.ProcessCommand(command);
198 	if (status != B_OK)
199 		error("noop", status);
200 }
201 
202 
203 static void
do_raw(int argc,char ** argv)204 do_raw(int argc, char** argv)
205 {
206 	// build command back again
207 	char command[4096];
208 	command[0] = '\0';
209 
210 	for (int i = 1; i < argc; i++) {
211 		if (i > 1)
212 			strlcat(command, " ", sizeof(command));
213 		strlcat(command, argv[i], sizeof(command));
214 	}
215 
216 	class RawCommand : public IMAP::Command, public IMAP::Handler {
217 	public:
218 		RawCommand(const char* command)
219 			:
220 			fCommand(command)
221 		{
222 		}
223 
224 		BString CommandString()
225 		{
226 			return fCommand;
227 		}
228 
229 		bool HandleUntagged(IMAP::Response& response)
230 		{
231 			if (response.IsCommand(fCommand)) {
232 				printf("-> %s\n", response.ToString().String());
233 				return true;
234 			}
235 
236 			return false;
237 		}
238 
239 	private:
240 		const char* fCommand;
241 	};
242 	RawCommand rawCommand(command);
243 	status_t status = sProtocol.ProcessCommand(rawCommand);
244 	if (status != B_OK)
245 		error("raw", status);
246 }
247 
248 
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},
261 };
262 
263 
264 static void
do_help(int argc,char ** argv)265 do_help(int argc, char** argv)
266 {
267 	printf("Available commands:\n");
268 
269 	for (cmd_entry* command = sBuiltinCommands; command->name != NULL;
270 			command++) {
271 		printf("%8s - %s\n", command->name, command->help);
272 	}
273 }
274 
275 
276 // #pragma mark -
277 
278 
279 int
main(int argc,char ** argv)280 main(int argc, char** argv)
281 {
282 	if (argc < 4)
283 		usage();
284 
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;
290 
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());
294 
295 	status_t status = sProtocol.Connect(address, user, password, useSSL);
296 	if (status != B_OK) {
297 		error("connect", status);
298 		return 1;
299 	}
300 
301 	while (true) {
302 		printf("> ");
303 		fflush(stdout);
304 
305 		char line[1024];
306 		if (fgets(line, sizeof(line), stdin) == NULL)
307 			break;
308 
309         argc = 0;
310         argv = build_argv(line, &argc);
311         if (argv == NULL || argc == 0)
312             continue;
313 
314 		if (!strcmp(argv[0], "quit")
315 			|| !strcmp(argv[0], "exit")
316 			|| !strcmp(argv[0], "q"))
317 			break;
318 
319         int length = strlen(argv[0]);
320 		bool found = false;
321 
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;
328 			}
329 		}
330 
331 		if (!found) {
332 			fprintf(stderr, "Unknown command \"%s\". Type \"help\" for a "
333 				"list of commands.\n", argv[0]);
334 		}
335 
336 		free(argv);
337 	}
338 
339 
340 	return 0;
341 }
342