+/*
+ * Send an APPEND to the server, which requires some extra semantics
+ */
+
+static int
+send_append(netsec_context *nsc, struct imap_msg *imsg, char **errstr)
+{
+ FILE *f;
+ bool nonsynlit = false;
+ char *status = NULL, *line = NULL;
+ size_t linesize = 0;
+ ssize_t rc;
+
+ /*
+ * If we have the LITERAL+ extension, or we have LITERAL- and our
+ * message is 4096 bytes or less, we can do it all in one message.
+ * Otherwise we have to wait for a contination marker (+).
+ */
+
+ if (capability_set("LITERAL+") ||
+ (capability_set("LITERAL-") && imsg->msgsize <= 4096)) {
+ nonsynlit = true;
+ }
+
+ /*
+ * Send our APPEND command
+ */
+
+ if (send_imap_command(nsc, nonsynlit, errstr, "APPEND \"%s\" {%u%s}",
+ imsg->folder, (unsigned int) imsg->msgsize,
+ nonsynlit ? "+" : "") != OK)
+ return NOTOK;
+
+ /*
+ * If we need to wait for a syncing literal, do that now
+ */
+
+ if (! nonsynlit) {
+ if (get_imap_response(nsc, NULL, NULL, &status, true,
+ true, errstr) != OK) {
+ imsg->queue = true; /* XXX Sigh */
+ fprintf(stderr, "APPEND command failed: %s\n", *errstr);
+ free(*errstr);
+ return OK;
+ }
+ if (!(status && has_prefix(status, "+"))) {
+ netsec_err(errstr, "Expected contination (+), but got: %s", status);
+ free(status);
+ return NOTOK;
+ }
+ free(status);
+ }
+
+ /*
+ * Now write the message out, but make sure we end each line with \r\n
+ */
+
+ if ((f = fopen(imsg->command, "r")) == NULL) {
+ netsec_err(errstr, "Unable to open %s: %s", imsg->command,
+ strerror(errno));
+ return NOTOK;
+ }
+
+ while ((rc = getline(&line, &linesize, f)) > 0) {
+ if (rc > 1 && line[rc - 1] == '\n' && line[rc - 2] == '\r') {
+ if (netsec_write(nsc, line, rc, errstr) != OK) {
+ free(line);
+ fclose(f);
+ return NOTOK;
+ }
+ } else {
+ if (line[rc - 1] == '\n')
+ rc--;
+ if (netsec_write(nsc, line, rc, errstr) != OK) {
+ free(line);
+ fclose(f);
+ return NOTOK;
+ }
+ if (netsec_write(nsc, "\r\n", 2, errstr) != OK) {
+ free(line);
+ fclose(f);
+ return NOTOK;
+ }
+ }
+ }
+
+ free(line);
+
+ if (! feof(f)) {
+ netsec_err(errstr, "Error reading %s: %s", imsg->command,
+ strerror(errno));
+ fclose(f);
+ return NOTOK;
+ }
+
+ fclose(f);
+
+ /*
+ * Send a final \r\n for the end of the command
+ */
+
+ if (netsec_write(nsc, "\r\n", 2, errstr) != OK)
+ return NOTOK;
+
+ if (! imsg->queue)
+ return netsec_flush(nsc, errstr);
+
+ return OK;
+}
+