summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-01-26 17:44:01 -0500
committerJune McEnroe <june@causal.agency>2020-01-26 17:44:01 -0500
commitc6b5de5e278e38bddc927f9801b0266f94b4f144 (patch)
tree93befd1bbfb7c62118acfc95e728bb4a34aff102
parentImplement IMAP flow outline (diff)
downloadnotemap-c6b5de5e278e38bddc927f9801b0266f94b4f144.tar.gz
notemap-c6b5de5e278e38bddc927f9801b0266f94b4f144.zip
Implement append
-rw-r--r--notemap.14
-rw-r--r--notemap.c82
2 files changed, 83 insertions, 3 deletions
diff --git a/notemap.1 b/notemap.1
index 8c66490..d2c7587 100644
--- a/notemap.1
+++ b/notemap.1
@@ -139,6 +139,10 @@ notemap -a -u june@causal.agency note.txt
 .Sh AUTHORS
 .An June Bug Aq Mt june@causal.agency
 .
+.Sh CAVEATS
+Notes are assumed to be plain UTF-8 text
+with LF line endings.
+.
 .Sh BUGS
 Send mail to
 .Aq Mt june@causal.agency
diff --git a/notemap.c b/notemap.c
index d05f9c0..963cd0a 100644
--- a/notemap.c
+++ b/notemap.c
@@ -198,8 +198,82 @@ static enum Atom atom(const char *str) {
 	return Unknown;
 }
 
-static void
-append(FILE *imap, const char *from, const char *uuid, const char *path) {
+static void append(
+	FILE *imap, const char *mailbox,
+	const char *from, const char *uuid, const char *path
+) {
+	FILE *note = fopen(path, "r");
+	if (!note) err(EX_NOINPUT, "%s", path);
+
+	struct stat status;
+	int error = fstat(fileno(note), &status);
+	if (error) err(EX_IOERR, "%s", path);
+
+	char date[sizeof("Mon, 00 Jan 0000 00:00:00 -0000")];
+	strftime(
+		date, sizeof(date), "%a, %e %b %Y %H:%M:%S %z",
+		localtime(&status.st_mtime)
+	);
+
+#define HEADERS \
+	"From: <%s>\r\n" \
+	"Subject: %s\r\n" \
+	"Date: %s\r\n" \
+	"X-Universally-Unique-Identifier: %s\r\n" \
+	"X-Uniform-Type-Identifier: com.apple.mail-note\r\n" \
+	"X-Mailer: notemap\r\n" \
+	"MIME-Version: 1.0\r\n" \
+	"Content-Type: text/plain; charset=\"utf-8\"\r\n" \
+	"Content-Transfer-Encoding: quoted-printable\r\n" \
+	"\r\n"
+
+	size_t max = sizeof(HEADERS)
+		+ strlen(from)
+		+ strlen(path)
+		+ strlen(date)
+		+ strlen(uuid)
+		+ 3 * status.st_size
+		+ 3 * status.st_size / 76;
+	char *buf = malloc(max);
+	if (!buf) err(EX_OSERR, "malloc");
+
+	FILE *msg = fmemopen(buf, max, "w");
+	if (!msg) err(EX_OSERR, "fmemopen");
+	fprintf(msg, HEADERS, from, path, date, uuid);
+#undef HEADERS
+
+	int ch;
+	int len = 0;
+	while (EOF != (ch = fgetc(note))) {
+		if (len == 76 && ch != '\n') {
+			fprintf(msg, "=\r\n");
+			len = 0;
+		}
+		if (ch == '\n') {
+			fprintf(msg, "\r\n");
+			len = 0;
+		} else if (ch == '\t' || (ch >= ' ' && ch <= '~' && ch != '=')) {
+			fprintf(msg, "%c", ch);
+			len++;
+		} else {
+			fprintf(msg, "=%02X", ch);
+			len += 3;
+		}
+	}
+	if (ferror(note)) err(EX_IOERR, "%s", path);
+	fclose(note);
+	fclose(msg);
+
+	buf[max - 1] = '\0';
+	fprintf(
+		imap, "%s APPEND %s (\\Seen) {%zu}\r\n",
+		Atoms[Append], mailbox, strlen(buf)
+	);
+	if (fgetc(imap) == '+') {
+		ungetc('+', imap);
+		fprintf(imap, "%s\r\n", buf);
+	}
+	free(buf);
 }
 
 int main(int argc, char *argv[]) {
@@ -320,6 +394,7 @@ int main(int argc, char *argv[]) {
 			break; case Next: {
 				ssize_t len;
 next:
+				// FIXME: Handle EOF.
 				len = getline(&entry, &entryCap, map);
 				if (len < 0) err(EX_IOERR, "%s", path);
 				if (entry[len - 1] == '\n') entry[len - 1] = '\0';
@@ -345,11 +420,12 @@ next:
 
 			break; case Fetch: {
 append:
-				append(imap, user, uuid, note);
+				append(imap, mailbox, user, uuid, note);
 			}
 
 			break; case Append: {
 				if (!seq) goto next;
+				// FIXME: Apparently we still get new flags back...
 				fprintf(
 					imap, "%s STORE %d +FLAGS.SILENT (\\Deleted)\r\n",
 					Atoms[Next], seq