about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--imbox.16
-rw-r--r--imbox.c66
2 files changed, 69 insertions, 3 deletions
diff --git a/imbox.1 b/imbox.1
index c91abd8..a1efa90 100644
--- a/imbox.1
+++ b/imbox.1
@@ -67,7 +67,9 @@ Connect to IMAP on
 .Ar host .
 The default host is determined by SRV record lookup
 on the domain name of
-.Ar user .
+.Ar user ,
+or simply the domain name
+if no SRV record exists.
 .
 .It Fl m Ar mailbox
 Export messages from
@@ -95,7 +97,7 @@ Read the password from standard input.
 .
 .Sh EXAMPLES
 .Bd -literal
-imbox june@causal.agency | git am
+imbox -T list@example.org june@causal.agency | git am
 .Ed
 .
 .Sh SEE ALSO
diff --git a/imbox.c b/imbox.c
index 0328c34..f2c65e8 100644
--- a/imbox.c
+++ b/imbox.c
@@ -26,6 +26,14 @@
 #include <tls.h>
 #include <unistd.h>
 
+#ifndef DIG_PATH
+#	ifdef __FreeBSD__
+#		define DIG_PATH "/usr/bin/drill"
+#	else
+#		define DIG_PATH "dig"
+#	endif
+#endif
+
 static void compile(regex_t *regex, const char *pattern) {
 	if (regex->re_nsub) return;
 	int error = regcomp(regex, pattern, REG_EXTENDED | REG_NEWLINE);
@@ -83,6 +91,56 @@ static void mboxrd(const char *headers, const char *body) {
 #undef MATCH
 }
 
+static void lookup(const char **host, const char **port, const char *domain) {
+	static char buf[1024];
+	snprintf(buf, sizeof(buf), "_imaps._tcp.%s", domain);
+
+	int rw[2];
+	int error = pipe(rw);
+	if (error) err(EX_OSERR, "pipe");
+
+	pid_t pid = fork();
+	if (pid < 0) err(EX_OSERR, "fork");
+
+	if (!pid) {
+		close(rw[0]);
+		dup2(rw[1], STDOUT_FILENO);
+		dup2(rw[1], STDERR_FILENO);
+		close(rw[1]);
+		execlp(DIG_PATH, DIG_PATH, "-t", "SRV", "-q", buf, "+short", NULL);
+		err(EX_CONFIG, "%s", DIG_PATH);
+	}
+
+	int status;
+	pid = wait(&status);
+	if (pid < 0) err(EX_OSERR, "wait");
+
+	close(rw[1]);
+	FILE *pipe = fdopen(rw[0], "r");
+	if (!pipe) err(EX_IOERR, "fdopen");
+
+	fgets(buf, sizeof(buf), pipe);
+	if (ferror(pipe)) err(EX_IOERR, "fgets");
+	fclose(pipe);
+
+	if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+		fprintf(stderr, "%s", buf);
+		exit(WEXITSTATUS(status));
+	}
+
+	char *ptr = buf;
+	char *dot = strrchr(ptr, '.');
+	if (dot) *dot = '\0';
+	strsep(&ptr, " \n"); // priority
+	strsep(&ptr, " \n"); // weight
+	*port = strsep(&ptr, " \n");
+	*host = strsep(&ptr, " \n");
+	if (!*host) {
+		*host = domain;
+		*port = "imaps";
+	}
+}
+
 static bool verbose;
 
 int tlsRead(void *_tls, char *ptr, int len) {
@@ -165,7 +223,7 @@ static char *readLiteral(FILE *imap, const char *line) {
 }
 
 int main(int argc, char *argv[]) {
-	const char *host = "imap.fastmail.com";
+	const char *host = NULL;
 	const char *port = "imaps";
 	const char *mailbox = "INBOX";
 	const char *subject = "[PATCH";
@@ -193,6 +251,12 @@ int main(int argc, char *argv[]) {
 	const char *user = argv[optind];
 	if (!user) errx(EX_USAGE, "username required");
 
+	if (!host) {
+		const char *domain = strchr(user, '@');
+		if (!domain) errx(EX_USAGE, "no domain in username");
+		lookup(&host, &port, &domain[1]);
+	}
+
 	char buf[1024];
 	char *pass = readpassphrase(
 		(rppFlags & RPP_STDIN ? "" : "Password: "),