+ current_server = spamd_get_server(spamd_address_vector, num_servers);
+ sd = spamd_address_vector[current_server];
+ for(;;)
+ {
+ uschar * errstr;
+
+ DEBUG(D_acl) debug_printf_indent("spamd: trying server %s\n", sd->hostspec);
+
+ for (;;)
+ {
+ if ( (spamd_sock = ip_streamsocket(sd->hostspec, &errstr, 5)) >= 0
+ || sd->retry <= 0
+ )
+ break;
+ DEBUG(D_acl) debug_printf_indent("spamd: server %s: retry conn\n", sd->hostspec);
+ while (sd->retry > 0) sd->retry = sleep(sd->retry);
+ }
+ if (spamd_sock >= 0)
+ break;
+
+ log_write(0, LOG_MAIN, "%s spamd: %s", loglabel, errstr);
+ sd->is_failed = TRUE;
+
+ current_server = spamd_get_server(spamd_address_vector, num_servers);
+ if (current_server < 0)
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "%s all spamd servers failed", loglabel);
+ goto defer;
+ }
+ sd = spamd_address_vector[current_server];
+ }
+ }
+
+(void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
+/* now we are connected to spamd on spamd_sock */
+if (sd->is_rspamd)
+ { /* rspamd variant */
+ uschar *req_str;
+ const uschar * helo;
+ const uschar * fcrdns;
+ const uschar * authid;
+
+ req_str = string_sprintf("CHECK RSPAMC/1.3\r\nContent-length: %lu\r\n"
+ "Queue-Id: %s\r\nFrom: <%s>\r\nRecipient-Number: %d\r\n",
+ mbox_size, message_id, sender_address, recipients_count);
+ for (i = 0; i < recipients_count; i ++)
+ req_str = string_sprintf("%sRcpt: <%s>\r\n", req_str, recipients_list[i].address);
+ if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0')
+ req_str = string_sprintf("%sHelo: %s\r\n", req_str, helo);
+ if ((fcrdns = expand_string(US"$sender_host_name")) != NULL && *fcrdns != '\0')
+ req_str = string_sprintf("%sHostname: %s\r\n", req_str, fcrdns);
+ if (sender_host_address != NULL)
+ req_str = string_sprintf("%sIP: %s\r\n", req_str, sender_host_address);
+ if ((authid = expand_string(US"$authenticated_id")) != NULL && *authid != '\0')
+ req_str = string_sprintf("%sUser: %s\r\n", req_str, authid);
+ req_str = string_sprintf("%s\r\n", req_str);
+ wrote = send(spamd_sock, req_str, Ustrlen(req_str), 0);
+ }
+else
+ { /* spamassassin variant */
+ (void)string_format(spamd_buffer,
+ sizeof(spamd_buffer),
+ "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
+ user_name,
+ mbox_size);
+ /* send our request */
+ wrote = send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0);
+ }
+
+if (wrote == -1)
+ {
+ (void)close(spamd_sock);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s spamd %s send failed: %s", loglabel, callout_address, strerror(errno));
+ goto defer;
+ }
+
+/* now send the file */
+/* spamd sometimes accepts connections but doesn't read data off
+ * the connection. We make the file descriptor non-blocking so
+ * that the write will only write sufficient data without blocking
+ * and we poll the descriptor to make sure that we can write without
+ * blocking. Short writes are gracefully handled and if the whole
+ * transaction takes too long it is aborted.
+ * Note: poll() is not supported in OSX 10.2 and is reported to be
+ * broken in more recent versions (up to 10.4).
+ */
+#ifndef NO_POLL_H
+pollfd.fd = spamd_sock;
+pollfd.events = POLLOUT;
+#endif
+(void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
+do
+ {
+ read = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
+ if (read > 0)
+ {
+ offset = 0;
+again:
+#ifndef NO_POLL_H
+ result = poll(&pollfd, 1, 1000);
+
+/* Patch posted by Erik ? for OS X and applied by PH */
+#else
+ select_tv.tv_sec = 1;
+ select_tv.tv_usec = 0;
+ FD_ZERO(&select_fd);
+ FD_SET(spamd_sock, &select_fd);
+ result = select(spamd_sock+1, NULL, &select_fd, NULL, &select_tv);
+#endif
+/* End Erik's patch */
+
+ if (result == -1 && errno == EINTR)
+ goto again;
+ else if (result < 1)
+ {
+ if (result == -1)
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s %s on spamd %s socket", loglabel, callout_address, strerror(errno));
+ else
+ {
+ if (time(NULL) - start < sd->timeout)
+ goto again;
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s timed out writing spamd %s, socket", loglabel, callout_address);
+ }
+ (void)close(spamd_sock);
+ goto defer;
+ }
+
+ wrote = send(spamd_sock,spamd_buffer + offset,read - offset,0);
+ if (wrote == -1)
+ {