+ int c;
+
+ do {
+ c = sm_fgetc(f);
+
+ if (c == EOF)
+ return RP_EOF;
+
+ if (c == -2)
+ return NOTOK;
+
+ *buffer++ = c;
+ } while (size > 1 && c != '\n');
+
+ *buffer = '\0';
+
+ return RP_OK;
+}
+
+
+#if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
+/*
+ * Read from the network, but do SASL or TLS encryption
+ */
+
+static int
+sm_fgetc(FILE *f)
+{
+ char tmpbuf[BUFSIZ], *retbuf;
+ unsigned int retbufsize = 0;
+ int cc, result;
+
+ /*
+ * If we have leftover data, return it
+ */
+
+ if (sasl_inbuflen) {
+ sasl_inbuflen--;
+ return (int) *sasl_inptr++;
+ }
+
+ /*
+ * If not, read from the network until we have some data to return
+ */
+
+ while (retbufsize == 0) {
+
+#ifdef TLS_SUPPORT
+ if (tls_active) {
+ cc = SSL_read(ssl, tmpbuf, sizeof(tmpbuf));
+
+ if (cc == 0) {
+ result = SSL_get_error(ssl, cc);
+
+ if (result != SSL_ERROR_ZERO_RETURN) {
+ sm_ierror("TLS peer aborted connection");
+ }
+
+ return EOF;
+ }
+
+ if (cc < 0) {
+ sm_ierror("SSL_read failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -2;
+ }
+ } else
+#endif /* TLS_SUPPORT */
+
+ cc = read(fileno(f), tmpbuf, sizeof(tmpbuf));
+
+ if (cc == 0)
+ return EOF;
+
+ if (cc < 0) {
+ sm_ierror("Unable to read from network: %s", strerror(errno));
+ return -2;
+ }
+
+ /*
+ * Don't call sasl_decode unless sasl is complete and we have
+ * encryption working
+ */
+
+ if (sasl_complete == 0 || sasl_ssf == 0) {
+ retbuf = tmpbuf;
+ retbufsize = cc;
+ } else {
+ result = sasl_decode(conn, tmpbuf, cc, (const char **) &retbuf,
+ &retbufsize);
+
+ if (result != SASL_OK) {
+ sm_ierror("Unable to decode SASL network data: %s",
+ sasl_errdetail(conn));
+ return -2;
+ }
+ }
+ }
+
+ if (retbufsize > SASL_MAXRECVBUF) {
+ sm_ierror("Received data (%d bytes) is larger than the buffer "
+ "size (%d bytes)", retbufsize, SASL_MAXRECVBUF);
+ return -2;
+ }
+
+ memcpy(sasl_inbuffer, retbuf, retbufsize);
+ sasl_inptr = sasl_inbuffer + 1;
+ sasl_inbuflen = retbufsize - 1;
+
+ return (int) sasl_inbuffer[0];
+}
+#endif /* CYRUS_SASL || TLS_SUPPORT */
+
+static int
+sm_rerror (int rc)
+{
+ if (sm_mts == MTS_SMTP)
+ sm_reply.length =
+ strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
+ : sm_alarmed ? "read from socket timed out"
+ : rc == RP_EOF ? "premature end-of-file on socket"
+ : "error reading from socket"));
+ else
+ sm_reply.length =
+ strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened"
+ : sm_alarmed ? "read from pipe timed out"
+ : rc == RP_EOF ? "premature end-of-file on pipe"
+ : "error reading from pipe"));