/* gcc `pkg-config --cflags --libs glib-2.0 gio-2.0` imap-conn.c -g -O0 -o imap-conn && ./imap-conn imap.googlemail.com 993 */ #include #include static gboolean read_stream_data (GIOStream *stream) { GInputStream *input; gchar buffer[2048 + 1]; gsize count; GError *error = NULL; input = g_io_stream_get_input_stream (stream); count = g_input_stream_read (input, buffer, G_N_ELEMENTS (buffer) - 1, NULL, &error); if (count == -1) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) { g_clear_error (&error); } else { g_printerr ("Failed to read data from the server: %s\n", error ? error->message : "Unknown error"); g_clear_error (&error); return FALSE; } } else { buffer[count] = 0; g_print ("Response: %s\n", buffer); } return TRUE; } static gboolean issue_command (GIOStream *stream, const gchar *command) { GOutputStream *output; gsize count, written = 0; GError *error = NULL; output = g_io_stream_get_output_stream (stream); count = strlen (command); if (!g_output_stream_write_all (output, command, count, &written, NULL, &error)) { g_printerr ("Failed to write command to the output stream: %s\n", error ? error->message : "Unknown error"); g_clear_error (&error); return FALSE; } if (written != count) { g_printerr ("Wrote only %d bytes, instead of %d\n", written, count); return FALSE; } if (!g_output_stream_write_all (output, "\r\n", 2, &written, NULL, &error)) { g_printerr ("Failed to write command end to the output stream: %s\n", error ? error->message : "Unknown error"); g_clear_error (&error); return FALSE; } if (written != 2) { g_printerr ("Wrote only %d bytes, instead of %d\n", written, 2); return FALSE; } if (!g_output_stream_flush (output, NULL, &error)) { g_printerr ("Failed to flush output stream\n", error ? error->message : "Unknown error"); g_clear_error (&error); return FALSE; } g_print ("Request: %s\n", command); return read_stream_data (stream); } static gint run_connection (const gchar *host, gushort port) { GSocketConnectable *connectable; GSocketConnection *connection; GSocketClient *client; gint ret = 0; GError *error = NULL; connectable = g_object_new (G_TYPE_NETWORK_ADDRESS, "scheme", "imap", "hostname", host, "port", port, NULL); client = g_socket_client_new (); g_socket_client_set_timeout (client, 10); g_socket_client_set_tls (client, TRUE); connection = g_socket_client_connect (client, connectable, NULL, &error); if (connection) { GSocket *socket; GIOStream *stream; g_print ("Connected to %s:%d\n", host, port); socket = g_socket_connection_get_socket (connection); if (socket) { g_socket_set_timeout (socket, 10); g_socket_set_keepalive (socket, TRUE); } stream = G_IO_STREAM (connection); if (!read_stream_data (stream)) ret = 3; else if (!issue_command (stream, "A01 CAPABILITY")) ret = 4; else if (!issue_command (stream, "A02 LOGOUT")) ret = 5; if (!g_io_stream_close (stream, NULL, &error)) { if (!ret) ret = 6; g_printerr ("Failed to close connection: %s\n", error ? error->message : "Unknown error"); g_clear_error (&error); } g_object_unref (connection); } else { g_printerr ("Failed to connect to %s:%d: %s\n", host, port, error ? error->message : "Unknown error"); g_clear_error (&error); ret = 2; } g_object_unref (connectable); g_object_unref (client); } gint main (gint argc, gchar *argv[]) { const gchar *host; gushort port; if (argc != 3) { g_printerr ("Requires two arguments, IMAP server host name and port, in this order\n"); return 1; } host = argv[1]; port = (gushort) g_ascii_strtoll (argv[2], NULL, 10); return run_connection (host, port); }