summary refs log tree commit diff
path: root/imap.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-12-04 00:25:51 -0500
committerJune McEnroe <june@causal.agency>2020-12-04 17:45:06 -0500
commit9acc21de7e4ede15ef846995428e6a394e230f2d (patch)
tree461629bc8e5f025bf73e4496744071de96455bae /imap.c
parentRefactor patch markup generation (diff)
downloadbubger-9acc21de7e4ede15ef846995428e6a394e230f2d.tar.gz
bubger-9acc21de7e4ede15ef846995428e6a394e230f2d.zip
Implement getservinfo for SRV lookup
Diffstat (limited to '')
-rw-r--r--imap.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/imap.c b/imap.c
index 10864aa..e21141d 100644
--- a/imap.c
+++ b/imap.c
@@ -26,12 +26,16 @@
  */
 
 #include <err.h>
+#include <netdb.h>
+#include <netinet/in.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/socket.h>
 #include <sysexits.h>
 #include <tls.h>
+#include <unistd.h>
 
 FILE *funopen(
 	const void *cookie,
@@ -43,6 +47,11 @@ FILE *funopen(
 
 #include "imap.h"
 
+int getservinfo(
+	const char *hostname, const char *servname,
+	const struct addrinfo *hints, struct addrinfo **res
+);
+
 const char *Atoms[AtomCap] = {
 #define X(id, str) [id] = str,
 	ENUM_ATOM
@@ -92,10 +101,36 @@ struct IMAP imapOpen(const char *host, const char *port) {
 	if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client));
 	tls_config_free(config);
 
-	error = tls_connect(client, host, port);
-	if (error) errx(EX_NOHOST, "tls_connect: %s", tls_error(client));
+	struct addrinfo *head;
+	struct addrinfo hints = {
+		.ai_family = PF_UNSPEC,
+		.ai_socktype = SOCK_STREAM,
+		.ai_protocol = IPPROTO_TCP,
+	};
+	error = getservinfo(host, port, &hints, &head);
+	if (error) errx(EX_NOHOST, "%s:%s: %s", host, port, gai_strerror(error));
+
+	int sock = -1;
+	for (struct addrinfo *ai = head; ai; ai = ai->ai_next) {
+		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sock < 0) err(EX_OSERR, "socket");
+
+		error = connect(sock, ai->ai_addr, ai->ai_addrlen);
+		if (!error) break;
+
+		close(sock);
+		sock = -1;
+	}
+	if (sock < 0) err(EX_UNAVAILABLE, "%s:%s", host, port);
+
+	error = tls_connect_socket(
+		client, sock, (head->ai_canonname ? head->ai_canonname : host)
+	);
+	if (error) errx(EX_SOFTWARE, "tls_connect_socket: %s", tls_error(client));
+	freeaddrinfo(head);
 
 	struct IMAP imap = {
+		.sock = sock,
 		.r = funopen(client, imapRead, NULL, NULL, NULL),
 		.w = funopen(client, NULL, imapWrite, NULL, imapClose),
 	};