[Buzilla 376] Preliminary DKIM support
[exim.git] / src / src / spam.c
index 0f6ad1434d8c22448399eadbd17960d37026a1fa..99c6d0c5a473f599ea8709cfad50350c0c227c09 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/spam.c,v 1.5 2005/04/27 10:00:18 ph10 Exp $ */
+/* $Cambridge: exim/src/src/spam.c,v 1.14 2007/05/14 18:56:25 magnus Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -40,7 +40,15 @@ int spam(uschar **listptr) {
   time_t start;
   size_t read, wrote;
   struct sockaddr_un server;
+#ifndef NO_POLL_H
   struct pollfd pollfd;
+#else                               /* Patch posted by Erik ? for OS X */
+  struct timeval select_tv;         /* and applied by PH */
+  fd_set select_fd;
+#endif
+
+  /* stop compiler warning */
+  result = 0;
 
   /* find the username from the option list */
   if ((user_name = string_nextinlist(&list, &sep,
@@ -118,7 +126,7 @@ int spam(uschar **listptr) {
     if (!num_servers) {
       log_write(0, LOG_MAIN|LOG_PANIC,
          "spam acl condition: no useable spamd server addresses in spamd_address configuration option.");
-      fclose(mbox_file);
+      (void)fclose(mbox_file);
       return DEFER;
     };
 
@@ -134,7 +142,7 @@ int spam(uschar **listptr) {
       if ( (spamd_sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
         log_write(0, LOG_MAIN|LOG_PANIC,
            "spam acl condition: error creating IP socket for spamd");
-        fclose(mbox_file);
+        (void)fclose(mbox_file);
         return DEFER;
       };
 
@@ -157,8 +165,8 @@ int spam(uschar **listptr) {
         current_server = 0;
       if (current_server == start_server) {
         log_write(0, LOG_MAIN|LOG_PANIC, "spam acl condition: all spamd servers failed");
-        fclose(mbox_file);
-        close(spamd_sock);
+        (void)fclose(mbox_file);
+        (void)close(spamd_sock);
         return DEFER;
       };
     };
@@ -171,7 +179,7 @@ int spam(uschar **listptr) {
       log_write(0, LOG_MAIN|LOG_PANIC,
                 "malware acl condition: spamd: unable to acquire socket (%s)",
                 strerror(errno));
-      fclose(mbox_file);
+      (void)fclose(mbox_file);
       return DEFER;
     }
 
@@ -182,15 +190,15 @@ int spam(uschar **listptr) {
       log_write(0, LOG_MAIN|LOG_PANIC,
                 "malware acl condition: spamd: unable to connect to UNIX socket %s (%s)",
                 spamd_address, strerror(errno) );
-      fclose(mbox_file);
-      close(spamd_sock);
+      (void)fclose(mbox_file);
+      (void)close(spamd_sock);
       return DEFER;
     }
 
   }
 
   /* now we are connected to spamd on spamd_sock */
-  snprintf(CS spamd_buffer,
+  (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,
@@ -198,11 +206,11 @@ int spam(uschar **listptr) {
 
   /* send our request */
   if (send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) {
-    close(spamd_sock);
+    (void)close(spamd_sock);
     log_write(0, LOG_MAIN|LOG_PANIC,
          "spam acl condition: spamd send failed: %s", strerror(errno));
-    fclose(mbox_file);
-    close(spamd_sock);
+    (void)fclose(mbox_file);
+    (void)close(spamd_sock);
     return DEFER;
   };
 
@@ -213,18 +221,34 @@ int spam(uschar **listptr) {
    * and we poll the desciptor to make sure that we can write without
    * blocking.  Short writes are gracefully handled and if the whole
    * trasaction 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;
-  fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
+#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)
-        continue;
+        goto again;
       else if (result < 1) {
         if (result == -1)
           log_write(0, LOG_MAIN|LOG_PANIC,
@@ -235,11 +259,20 @@ again:
           log_write(0, LOG_MAIN|LOG_PANIC,
             "spam acl condition: timed out writing spamd socket");
         }
-        close(spamd_sock);
-        fclose(mbox_file);
+        (void)close(spamd_sock);
+        (void)fclose(mbox_file);
         return DEFER;
       }
+
       wrote = send(spamd_sock,spamd_buffer + offset,read - offset,0);
+      if (wrote == -1)
+      {
+          log_write(0, LOG_MAIN|LOG_PANIC,
+            "spam acl condition: %s on spamd socket", strerror(errno));
+        (void)close(spamd_sock);
+        (void)fclose(mbox_file);
+        return DEFER;
+      }
       if (offset + wrote != read) {
         offset += wrote;
         goto again;
@@ -250,12 +283,12 @@ again:
   if (ferror(mbox_file)) {
     log_write(0, LOG_MAIN|LOG_PANIC,
       "spam acl condition: error reading spool file: %s", strerror(errno));
-    close(spamd_sock);
-    fclose(mbox_file);
+    (void)close(spamd_sock);
+    (void)fclose(mbox_file);
     return DEFER;
   }
 
-  fclose(mbox_file);
+  (void)fclose(mbox_file);
 
   /* we're done sending, close socket for writing */
   shutdown(spamd_sock,SHUT_WR);
@@ -275,19 +308,19 @@ again:
   if((i <= 0) && (errno != 0)) {
     log_write(0, LOG_MAIN|LOG_PANIC,
          "spam acl condition: error reading from spamd socket: %s", strerror(errno));
-    close(spamd_sock);
+    (void)close(spamd_sock);
     return DEFER;
   }
 
   /* reading done */
-  close(spamd_sock);
+  (void)close(spamd_sock);
 
   /* dig in the spamd output and put the report in a multiline header, if requested */
-  if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
+  if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
              spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
 
     /* try to fall back to pre-2.50 spamd output */
-    if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
+    if( sscanf(CS spamd_buffer,"SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
                spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
       log_write(0, LOG_MAIN|LOG_PANIC,
          "spam acl condition: cannot parse spamd output");
@@ -344,12 +377,12 @@ again:
   spam_bar = spam_bar_buffer;
 
   /* create "float" spam score */
-  snprintf(CS spam_score_buffer, sizeof(spam_score_buffer),"%.1f", spamd_score);
+  (void)string_format(spam_score_buffer, sizeof(spam_score_buffer),"%.1f", spamd_score);
   spam_score = spam_score_buffer;
 
   /* create "int" spam score */
   j = (int)((spamd_score + 0.001)*10);
-  snprintf(CS spam_score_int_buffer, sizeof(spam_score_int_buffer), "%d", j);
+  (void)string_format(spam_score_int_buffer, sizeof(spam_score_int_buffer), "%d", j);
   spam_score_int = spam_score_int_buffer;
 
   /* compare threshold against score */