You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

patch-exim-src_spam.c.diff 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. diff --git a/src/OS/os.h-Linux b/src/OS/os.h-Linux
  2. index 3fead17..03fea75 100644
  3. --- a/src/OS/os.h-Linux
  4. +++ b/src/OS/os.h-Linux
  5. @@ -20,7 +20,7 @@ performance on outgoing mail a bit. Note: With older glibc versions
  6. this setting will conflict with the _FILE_OFFSET_BITS=64 setting
  7. defined as part of the Linux CFLAGS. */
  8. -/* #define HAVE_LINUX_SENDFILE */
  9. +#define HAVE_LINUX_SENDFILE
  10. #define F_FREESP O_TRUNC
  11. typedef struct flock flock_t;
  12. diff --git a/src/src/expand.c b/src/src/expand.c
  13. index 1da2225..7da567a 100644
  14. --- a/src/src/expand.c
  15. +++ b/src/src/expand.c
  16. @@ -618,6 +618,7 @@ static var_entry var_table[] = {
  17. { "sn8", vtype_filter_int, &filter_sn[8] },
  18. { "sn9", vtype_filter_int, &filter_sn[9] },
  19. #ifdef WITH_CONTENT_SCAN
  20. + { "spam_action", vtype_stringptr, &spam_action },
  21. { "spam_bar", vtype_stringptr, &spam_bar },
  22. { "spam_report", vtype_stringptr, &spam_report },
  23. { "spam_score", vtype_stringptr, &spam_score },
  24. diff --git a/src/src/globals.c b/src/src/globals.c
  25. index 74b6edb..e6f02fb 100644
  26. --- a/src/src/globals.c
  27. +++ b/src/src/globals.c
  28. @@ -1212,6 +1212,7 @@ BOOL smtp_use_size = FALSE;
  29. uschar *spamd_address = US"127.0.0.1 783";
  30. uschar *spam_bar = NULL;
  31. uschar *spam_report = NULL;
  32. +uschar *spam_action = NULL;
  33. uschar *spam_score = NULL;
  34. uschar *spam_score_int = NULL;
  35. #endif
  36. diff --git a/src/src/globals.h b/src/src/globals.h
  37. index db436c0..fc4d9f6 100644
  38. --- a/src/src/globals.h
  39. +++ b/src/src/globals.h
  40. @@ -769,6 +769,7 @@ extern BOOL smtp_use_size; /* Global for passed connections */
  41. extern uschar *spamd_address; /* address for the spamassassin daemon */
  42. extern uschar *spam_bar; /* the spam "bar" (textual representation of spam_score) */
  43. extern uschar *spam_report; /* the spamd report (multiline) */
  44. +extern uschar *spam_action; /* the spamd action */
  45. extern uschar *spam_score; /* the spam score (float) */
  46. extern uschar *spam_score_int; /* spam_score * 10 (int) */
  47. #endif
  48. diff --git a/src/src/spam.c b/src/src/spam.c
  49. index 63395f2..41fd4ac 100644
  50. --- a/src/src/spam.c
  51. +++ b/src/src/spam.c
  52. @@ -14,12 +14,20 @@
  53. uschar spam_score_buffer[16];
  54. uschar spam_score_int_buffer[16];
  55. uschar spam_bar_buffer[128];
  56. +uschar spam_action_buffer[32];
  57. uschar spam_report_buffer[32600];
  58. uschar prev_user_name[128] = "";
  59. int spam_ok = 0;
  60. int spam_rc = 0;
  61. uschar *prev_spamd_address_work = NULL;
  62. +/* push formatted line into vector */
  63. +static int spam_push_line(struct iovec *iov, int i, const char *fmt, ...);
  64. +/* write io vector to the socket */
  65. +static int spam_write_vector(int sock, size_t size, struct iovec *iov, time_t now);
  66. +/* poll socket to obtain write readiness */
  67. +static int spam_poll_socket (int sock, time_t start);
  68. +
  69. int spam(uschar **listptr) {
  70. int sep = 0;
  71. uschar *list = *listptr;
  72. @@ -29,10 +37,11 @@ int spam(uschar **listptr) {
  73. FILE *mbox_file;
  74. int spamd_sock = -1;
  75. uschar spamd_buffer[32600];
  76. - int i, j, offset, result;
  77. + int i, j, offset, result, is_rspamd;
  78. uschar spamd_version[8];
  79. + uschar spamd_short_result[8];
  80. uschar spamd_score_char;
  81. - double spamd_threshold, spamd_score;
  82. + double spamd_threshold, spamd_score, spamd_reject_score;
  83. int spamd_report_offset;
  84. uschar *p,*q;
  85. int override = 0;
  86. @@ -126,8 +135,15 @@ int spam(uschar **listptr) {
  87. spamd_address_container *this_spamd =
  88. (spamd_address_container *)store_get(sizeof(spamd_address_container));
  89. + /* Check for spamd variant */
  90. + if( Ustrstr(address, "variant=rspamd") != NULL ) {
  91. + this_spamd->is_rspamd = 1;
  92. + }
  93. + else {
  94. + this_spamd->is_rspamd = 0;
  95. + }
  96. /* grok spamd address and port */
  97. - if( sscanf(CS address, "%s %u", this_spamd->tcp_addr, &(this_spamd->tcp_port)) != 2 ) {
  98. + if( sscanf(CS address, "%s %hu", this_spamd->tcp_addr, &(this_spamd->tcp_port)) != 2 ) {
  99. log_write(0, LOG_MAIN,
  100. "spam acl condition: warning - invalid spamd address: '%s'", address);
  101. continue;
  102. @@ -171,6 +187,7 @@ int spam(uschar **listptr) {
  103. spamd_address_vector[current_server]->tcp_port,
  104. 5 ) > -1) {
  105. /* connection OK */
  106. + is_rspamd = spamd_address_vector[current_server]->is_rspamd;
  107. break;
  108. };
  109. @@ -207,12 +224,28 @@ int spam(uschar **listptr) {
  110. }
  111. server.sun_family = AF_UNIX;
  112. - Ustrcpy(server.sun_path, spamd_address_work);
  113. + p = Ustrstr(spamd_address_work, "variant=rspamd");
  114. + if( p != NULL ) {
  115. + is_rspamd = TRUE;
  116. + /* strip spaces */
  117. + p --;
  118. + while (p > spamd_address_work && isspace (*p)) {
  119. + p --;
  120. + }
  121. + Ustrncpy(server.sun_path, spamd_address_work, p - spamd_address_work + 1);
  122. + /* zero terminate */
  123. + server.sun_path[p - spamd_address_work + 1] = 0;
  124. + }
  125. + else {
  126. + is_rspamd = FALSE;
  127. + Ustrcpy(server.sun_path, spamd_address_work);
  128. + }
  129. +
  130. if (connect(spamd_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
  131. log_write(0, LOG_MAIN|LOG_PANIC,
  132. "malware acl condition: spamd: unable to connect to UNIX socket %s (%s)",
  133. - spamd_address_work, strerror(errno) );
  134. + server.sun_path, strerror(errno) );
  135. (void)fclose(mbox_file);
  136. (void)close(spamd_sock);
  137. return DEFER;
  138. @@ -228,22 +261,67 @@ int spam(uschar **listptr) {
  139. return DEFER;
  140. }
  141. + (void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
  142. /* now we are connected to spamd on spamd_sock */
  143. - (void)string_format(spamd_buffer,
  144. - sizeof(spamd_buffer),
  145. - "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
  146. - user_name,
  147. - mbox_size);
  148. -
  149. - /* send our request */
  150. - if (send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) {
  151. - (void)close(spamd_sock);
  152. - log_write(0, LOG_MAIN|LOG_PANIC,
  153. - "spam acl condition: spamd send failed: %s", strerror(errno));
  154. - (void)fclose(mbox_file);
  155. - (void)close(spamd_sock);
  156. - return DEFER;
  157. - };
  158. + if (is_rspamd) {
  159. + /* rspamd variant */
  160. + int r, request_p = 0;
  161. + const char *helo;
  162. + struct iovec *request_v;
  163. +
  164. + request_v = store_get(sizeof(struct iovec) * (8 + recipients_count));
  165. + if (request_v == NULL) {
  166. + (void)close(spamd_sock);
  167. + log_write(0, LOG_MAIN|LOG_PANIC,
  168. + "spam acl condition: store_get failed: %s", strerror(errno));
  169. + (void)fclose(mbox_file);
  170. + (void)close(spamd_sock);
  171. + return DEFER;
  172. + }
  173. + r = 0;
  174. + r += spam_push_line(request_v, request_p++, "CHECK RSPAMC/1.3\r\n");
  175. + r += spam_push_line(request_v, request_p++, "Content-length: %lu\r\n", mbox_size);
  176. + r += spam_push_line(request_v, request_p++, "Queue-Id: %s\r\n", message_id);
  177. + r += spam_push_line(request_v, request_p++, "From: <%s>\r\n", sender_address);
  178. + r += spam_push_line(request_v, request_p++, "Recipient-Number: %d\r\n", recipients_count);
  179. + /* copy all recipients as well */
  180. + for (i = 0; i < recipients_count; i ++)
  181. + r += spam_push_line(request_v, request_p++, "Rcpt: <%s>\r\n", recipients_list[i].address);
  182. + if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0')
  183. + r += spam_push_line(request_v, request_p++, "Helo: %s\r\n", helo);
  184. + if (sender_host_address != NULL)
  185. + r += spam_push_line(request_v, request_p++, "IP: %s\r\n", sender_host_address);
  186. + r += spam_push_line(request_v, request_p++, "\r\n");
  187. + if (spam_write_vector (spamd_sock, request_p, request_v, start) < 0) {
  188. + (void)close(spamd_sock);
  189. + log_write(0, LOG_MAIN|LOG_PANIC,
  190. + "spam acl condition: spamd (rspamd) send failed: %s", strerror(errno));
  191. + (void)fclose(mbox_file);
  192. + (void)close(spamd_sock);
  193. + return DEFER;
  194. + }
  195. + }
  196. + else {
  197. + /* spamassassin variant */
  198. + struct iovec req_iov;
  199. + (void)string_format(spamd_buffer,
  200. + sizeof(spamd_buffer),
  201. + "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
  202. + user_name,
  203. + mbox_size);
  204. + /* send our request */
  205. + req_iov.iov_len = Ustrlen(spamd_buffer);
  206. + req_iov.iov_base = spamd_buffer;
  207. + if (spam_write_vector (spamd_sock, 1, &req_iov, start) < 0) {
  208. + (void)close(spamd_sock);
  209. + log_write(0, LOG_MAIN|LOG_PANIC,
  210. + "spam acl condition: spamd send failed: %s", strerror(errno));
  211. + (void)fclose(mbox_file);
  212. + (void)close(spamd_sock);
  213. + return DEFER;
  214. + };
  215. + }
  216. +
  217. /* now send the file */
  218. /* spamd sometimes accepts conections but doesn't read data off
  219. @@ -255,41 +333,53 @@ int spam(uschar **listptr) {
  220. * Note: poll() is not supported in OSX 10.2 and is reported to be
  221. * broken in more recent versions (up to 10.4).
  222. */
  223. -#ifndef NO_POLL_H
  224. - pollfd.fd = spamd_sock;
  225. - pollfd.events = POLLOUT;
  226. -#endif
  227. - (void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
  228. +#ifdef HAVE_LINUX_SENDFILE
  229. + ssize_t copied = 0;
  230. + int mbox_fd;
  231. + off_t off = 0, size;
  232. + struct stat st;
  233. +
  234. + mbox_fd = fileno(mbox_file);
  235. + if( fstat(mbox_fd, &st) == -1 ) {
  236. + log_write(0, LOG_MAIN|LOG_PANIC,
  237. + "spam acl condition: %s on scan file", strerror(errno));
  238. + (void)close(spamd_sock);
  239. + (void)fclose(mbox_file);
  240. + return DEFER;
  241. + }
  242. + size = st.st_size;
  243. + for (;;) {
  244. + if (spam_poll_socket(spamd_sock, start) == -1) {
  245. + (void)close(spamd_sock);
  246. + (void)fclose(mbox_file);
  247. + return DEFER;
  248. + }
  249. + copied = sendfile(spamd_sock, mbox_fd, &offset, (size - offset));
  250. + if (copied < 0) {
  251. + if (errno == EINTR)
  252. + continue;
  253. +
  254. + log_write(0, LOG_MAIN|LOG_PANIC,
  255. + "spam acl condition: %s on spamd socket", strerror(errno));
  256. + (void)close(spamd_sock);
  257. + (void)fclose(mbox_file);
  258. + return DEFER;
  259. + }
  260. + else {
  261. + size -= copied;
  262. + if (size == 0) {
  263. + /* the whole file has been sent */
  264. + break;
  265. + }
  266. + }
  267. + }
  268. +#else
  269. do {
  270. read = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
  271. if (read > 0) {
  272. offset = 0;
  273. again:
  274. -#ifndef NO_POLL_H
  275. - result = poll(&pollfd, 1, 1000);
  276. -
  277. -/* Patch posted by Erik ? for OS X and applied by PH */
  278. -#else
  279. - select_tv.tv_sec = 1;
  280. - select_tv.tv_usec = 0;
  281. - FD_ZERO(&select_fd);
  282. - FD_SET(spamd_sock, &select_fd);
  283. - result = select(spamd_sock+1, NULL, &select_fd, NULL, &select_tv);
  284. -#endif
  285. -/* End Erik's patch */
  286. -
  287. - if (result == -1 && errno == EINTR)
  288. - goto again;
  289. - else if (result < 1) {
  290. - if (result == -1)
  291. - log_write(0, LOG_MAIN|LOG_PANIC,
  292. - "spam acl condition: %s on spamd socket", strerror(errno));
  293. - else {
  294. - if (time(NULL) - start < SPAMD_TIMEOUT)
  295. - goto again;
  296. - log_write(0, LOG_MAIN|LOG_PANIC,
  297. - "spam acl condition: timed out writing spamd socket");
  298. - }
  299. + if (spam_poll_socket(spamd_sock, start) == -1) {
  300. (void)close(spamd_sock);
  301. (void)fclose(mbox_file);
  302. return DEFER;
  303. @@ -318,6 +408,7 @@ again:
  304. (void)fclose(mbox_file);
  305. return DEFER;
  306. }
  307. +#endif /* HAVE_LINUX_SENDFILE */
  308. (void)fclose(mbox_file);
  309. @@ -346,60 +437,103 @@ again:
  310. /* reading done */
  311. (void)close(spamd_sock);
  312. - /* dig in the spamd output and put the report in a multiline header, if requested */
  313. - if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
  314. - spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  315. + if (!is_rspamd) {
  316. + /* dig in the spamd output and put the report in a multiline header, if requested */
  317. + if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
  318. + spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  319. - /* try to fall back to pre-2.50 spamd output */
  320. - if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
  321. - spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  322. - log_write(0, LOG_MAIN|LOG_PANIC,
  323. - "spam acl condition: cannot parse spamd output");
  324. - return DEFER;
  325. + /* try to fall back to pre-2.50 spamd output */
  326. + if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
  327. + spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
  328. + log_write(0, LOG_MAIN|LOG_PANIC,
  329. + "spam acl condition: cannot parse spamd output");
  330. + return DEFER;
  331. + };
  332. };
  333. - };
  334. - /* Create report. Since this is a multiline string,
  335. - we must hack it into shape first */
  336. - p = &spamd_buffer[spamd_report_offset];
  337. - q = spam_report_buffer;
  338. - while (*p != '\0') {
  339. - /* skip \r */
  340. - if (*p == '\r') {
  341. - p++;
  342. - continue;
  343. - };
  344. - *q = *p;
  345. - q++;
  346. - if (*p == '\n') {
  347. - /* add an extra space after the newline to ensure
  348. - that it is treated as a header continuation line */
  349. - *q = ' ';
  350. - q++;
  351. + /* Create report. Since this is a multiline string,
  352. + we must hack it into shape first */
  353. + p = &spamd_buffer[spamd_report_offset];
  354. + q = spam_report_buffer;
  355. + while (*p != '\0') {
  356. + /* skip \r */
  357. + if (*p == '\r') {
  358. + p++;
  359. + continue;
  360. + };
  361. + *q = *p;
  362. + q++;
  363. + if (*p == '\n') {
  364. + /* add an extra space after the newline to ensure
  365. + that it is treated as a header continuation line */
  366. + *q = ' ';
  367. + q++;
  368. + };
  369. + p++;
  370. };
  371. - p++;
  372. - };
  373. - /* NULL-terminate */
  374. - *q = '\0';
  375. - q--;
  376. - /* cut off trailing leftovers */
  377. - while (*q <= ' ') {
  378. + /* NULL-terminate */
  379. *q = '\0';
  380. q--;
  381. - };
  382. + /* cut off trailing leftovers */
  383. + while (*q <= ' ') {
  384. + *q = '\0';
  385. + q--;
  386. + };
  387. + if( spamd_score >= spamd_threshold ) {
  388. + Ustrcpy(spam_action_buffer, "reject");
  389. + }
  390. + else {
  391. + Ustrcpy(spam_action_buffer, "no action");
  392. + }
  393. + }
  394. + else {
  395. + /* rspamd variant of reply */
  396. + int r;
  397. + if( (r = sscanf(CS spamd_buffer,"RSPAMD/%7s 0 EX_OK\r\nMetric: default; %7s %lf / %lf / %lf\r\n%n",
  398. + spamd_version,spamd_short_result,&spamd_score,&spamd_threshold,&spamd_reject_score,&spamd_report_offset)) != 5 ) {
  399. + log_write(0, LOG_MAIN|LOG_PANIC,
  400. + "spam acl condition: cannot parse spamd output: %d", r);
  401. + return DEFER;
  402. + };
  403. + /* now parse action */
  404. + p = &spamd_buffer[spamd_report_offset];
  405. +
  406. + if( Ustrncmp(p, "Action: ", sizeof("Action: ") - 1) == 0 ) {
  407. + p += sizeof("Action: ") - 1;
  408. + q = &spam_action_buffer[0];
  409. + while (*p && *p != '\r' && (q - spam_action_buffer) < sizeof(spam_action_buffer) - 1) {
  410. + *q++ = *p++;
  411. + }
  412. + *q = '\0';
  413. + }
  414. + /* make a simple report */
  415. + if( spamd_score >= spamd_threshold ) {
  416. + p = "likely spam";
  417. + }
  418. + else if ( Ustrcmp (spam_action_buffer, "no action") == 0 ) {
  419. + p = "unlikely spam";
  420. + }
  421. + else {
  422. + p = "probably spam";
  423. + }
  424. + string_format(spam_report_buffer, sizeof(spam_report_buffer), "This message is %s.", p);
  425. + }
  426. +
  427. + /* common spamd actions */
  428. spam_report = spam_report_buffer;
  429. + spam_action = spam_action_buffer;
  430. /* create spam bar */
  431. spamd_score_char = spamd_score > 0 ? '+' : '-';
  432. j = abs((int)(spamd_score));
  433. i = 0;
  434. if( j != 0 ) {
  435. - while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
  436. - spam_bar_buffer[i++] = spamd_score_char;
  437. + while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
  438. + spam_bar_buffer[i++] = spamd_score_char;
  439. }
  440. else{
  441. - spam_bar_buffer[0] = '/';
  442. - i = 1;
  443. + spam_bar_buffer[0] = '/';
  444. + i = 1;
  445. }
  446. spam_bar_buffer[i] = '\0';
  447. spam_bar = spam_bar_buffer;
  448. @@ -415,12 +549,12 @@ again:
  449. /* compare threshold against score */
  450. if (spamd_score >= spamd_threshold) {
  451. - /* spam as determined by user's threshold */
  452. - spam_rc = OK;
  453. + /* spam as determined by user's threshold */
  454. + spam_rc = OK;
  455. }
  456. else {
  457. - /* not spam */
  458. - spam_rc = FAIL;
  459. + /* not spam */
  460. + spam_rc = FAIL;
  461. };
  462. /* remember expanded spamd_address if needed */
  463. @@ -440,4 +574,126 @@ again:
  464. };
  465. }
  466. +#ifdef __GNUC__
  467. +static int
  468. +spam_push_line(struct iovec *iov, const int i, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
  469. +#endif
  470. +static int
  471. +spam_push_line(struct iovec *iov, const int i, const char *fmt, ...)
  472. +{
  473. + va_list ap;
  474. + size_t len;
  475. + char buf[512];
  476. +
  477. + va_start(ap, fmt);
  478. + len = vsnprintf(buf, sizeof(buf), fmt, ap);
  479. + va_end(ap);
  480. +
  481. + iov[i].iov_base = string_copy(US buf);
  482. + iov[i].iov_len = len;
  483. +
  484. + if (len >= sizeof(buf)) {
  485. + log_write(0, LOG_MAIN, "rspam: error, string was longer than %d", (int)sizeof(buf));
  486. + return (-1);
  487. + }
  488. +
  489. + return 0;
  490. +}
  491. +
  492. +static int
  493. +spam_write_vector(int sock, size_t size, struct iovec *iov, time_t start)
  494. +{
  495. + int r, i;
  496. +
  497. + for (;;) {
  498. + if (spam_poll_socket(sock, start) == -1) {
  499. + return -1;
  500. + }
  501. + r = writev(sock, iov, size);
  502. + if (r == -1) {
  503. + if (errno == EINTR)
  504. + continue;
  505. +
  506. + log_write(0, LOG_MAIN|LOG_PANIC,
  507. + "spam acl condition: %s on spamd socket", strerror(errno));
  508. + return -1;
  509. + }
  510. + else {
  511. + /* check for partial writev */
  512. + for (i = 0; i < size; i ++) {
  513. + if (r >= iov[i].iov_len) {
  514. + r -= iov[i].iov_len;
  515. + }
  516. + else {
  517. + /* partial iov write */
  518. + iov[i].iov_base += r;
  519. + break;
  520. + }
  521. + if (r == 0)
  522. + break;
  523. + }
  524. +
  525. + if (i == size - 1 && r == 0) {
  526. + /* we have written everything */
  527. + break;
  528. + }
  529. + else {
  530. + /* move iov to the last unreaded element */
  531. + iov = &iov[i];
  532. + size -= i;
  533. + }
  534. + }
  535. + }
  536. +
  537. + return 0;
  538. +
  539. +}
  540. +
  541. +static int
  542. +spam_poll_socket (int sock, time_t start)
  543. +{
  544. +#ifndef NO_POLL_H
  545. + struct pollfd pollfd;
  546. +#else /* Patch posted by Erik ? for OS X */
  547. + struct timeval select_tv; /* and applied by PH */
  548. + fd_set select_fd;
  549. +#endif
  550. + int r;
  551. +
  552. +#ifndef NO_POLL_H
  553. + pollfd.fd = sock;
  554. + pollfd.events = POLLOUT;
  555. +#endif
  556. + for (;;) {
  557. +#ifndef NO_POLL_H
  558. + r = poll(&pollfd, 1, 1000);
  559. +
  560. +/* Patch posted by Erik ? for OS X and applied by PH */
  561. +#else
  562. + select_tv.tv_sec = 1;
  563. + select_tv.tv_usec = 0;
  564. + FD_ZERO(&select_fd);
  565. + FD_SET(sock, &select_fd);
  566. + r = select(sock+1, NULL, &select_fd, NULL, &select_tv);
  567. +#endif
  568. +/* End Erik's patch */
  569. +
  570. + if (r == -1 && errno == EINTR)
  571. + continue;
  572. + else if (r < 1) {
  573. + if (r == -1)
  574. + log_write(0, LOG_MAIN|LOG_PANIC,
  575. + "spam acl condition: %s on spamd socket", strerror(errno));
  576. + else {
  577. + if (time(NULL) - start < SPAMD_TIMEOUT)
  578. + continue;
  579. +
  580. + log_write(0, LOG_MAIN|LOG_PANIC,
  581. + "spam acl condition: timed out writing spamd socket");
  582. + }
  583. + }
  584. + return r;
  585. + }
  586. +}
  587. +
  588. #endif
  589. diff --git a/src/src/spam.h b/src/src/spam.h
  590. index ba700c8..6047c59 100644
  591. --- a/src/src/spam.h
  592. +++ b/src/src/spam.h
  593. @@ -22,7 +22,8 @@
  594. typedef struct spamd_address_container {
  595. uschar tcp_addr[24];
  596. - unsigned int tcp_port;
  597. + unsigned short int tcp_port;
  598. + unsigned is_rspamd:1;
  599. } spamd_address_container;
  600. #endif