#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <curl/curl.h>

static const char cmd[] = "A1 IDLE\n";
static char buf[1024];

int main(int argc, char **argv)
{
	CURLM *mcurl;
	CURL *curl;
	int mrun, sock = CURL_SOCKET_BAD;
	time_t start = time(NULL);
	int state = 0;
	ssize_t pos = 0;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s imaps://mailserver.com user@mailserver.com password\n", argv[0]);
		return 1;
	}

	assert((mcurl = curl_multi_init()));
	assert((curl = curl_easy_init()));
	assert(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) == CURLE_OK);
	assert(curl_easy_setopt(curl, CURLOPT_URL, argv[1]) == CURLE_OK);
	if (argc > 2)
		assert(curl_easy_setopt(curl, CURLOPT_USERNAME, argv[2]) == CURLE_OK);
	if (argc > 3)
		assert(curl_easy_setopt(curl, CURLOPT_PASSWORD, argv[3]) == CURLE_OK);
	assert(curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L) == CURLE_OK);
	//assert(curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 1L) == CURLE_OK);

	assert(curl_multi_add_handle(mcurl, curl) == CURLM_OK);

	while (time(NULL) - start < 5) {
		struct curl_waitfd waitfd;

		assert(curl_multi_perform(mcurl, &mrun) == CURLM_OK);
		for (;;) {
			int i;
			struct CURLMsg *m = curl_multi_info_read(mcurl, &i);

			if (!m)
				break;
			if (m->msg == CURLMSG_DONE && m->easy_handle == curl) {
				assert(curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock) == CURLE_OK);
				assert(sock != CURL_SOCKET_BAD);
			}
		}

		if (sock >= 0) {
			waitfd.events = state ? CURL_WAIT_POLLIN : CURL_WAIT_POLLOUT;
			waitfd.revents = 0;
			assert(curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock) == CURLE_OK);
			waitfd.fd = sock;
		}
		assert(curl_multi_wait(mcurl, &waitfd, sock < 0 ? 0 : 1, 5000, &mrun) == CURLM_OK);
		if (sock >= 0 && (waitfd.revents & waitfd.events)) {
			size_t len = 0;

			if (!state) {
				assert(curl_easy_send(curl, cmd + pos, sizeof(cmd) - 1 - pos, &len) == CURLE_OK);
				if (len > 0)
					pos += len;
				else
					pos = 0;
				if (pos == sizeof(cmd) - 1) {
					state++;
					pos = 0;
				}
			} else if (pos < sizeof(buf)) {
				assert(curl_easy_recv(curl, buf + pos, sizeof(buf) - pos, &len) == CURLE_OK);
				if (len > 0)
					pos += len;
			}
			if (len <= 0)
				sock = -1;
		}
	}

	if (state) {
		fwrite(buf, pos, 1, stdout);
		putchar('\n');
	}

	assert(curl_multi_remove_handle(mcurl, curl) == CURLM_OK);
	curl_easy_cleanup(curl);
	curl_multi_cleanup(mcurl);

	return 0;
}

