]> Pileus Git - ~andy/fetchmail/blobdiff - socket.c
Bug fixes and internationalization improvements.
[~andy/fetchmail] / socket.c
index 9501b1ebdca8aef1027a11ee2bb5c04b9cf0e94b..fd8e246ed6563b148160a0dfd6ef047f9be6af2f 100644 (file)
--- a/socket.c
+++ b/socket.c
 #include <memory.h>
 #endif /* HAVE_MEMORY_H */
 #include <sys/types.h>
+#ifndef HAVE_NET_SOCKET_H
 #include <sys/socket.h>
+#else
+#include <net/socket.h>
+#endif
 #include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
 #include <netdb.h>
 #if defined(STDC_HEADERS)
 #include <stdlib.h>
 #include "fetchmail.h"
 #include "i18n.h"
 
+/* Defines to allow BeOS to play nice... */
+#ifdef __BEOS__
+static char peeked;
+#define fm_close(a)  closesocket(a)
+#define fm_write(a,b,c)  send(a,b,c,0)
+#define fm_peek(a,b,c)   recv(a,b,c,0)
+#define fm_read(a,b,c)   recv(a,b,c,0)
+#else
+#define fm_close(a)  close(a)
+#define fm_write(a,b,c)  write(a,b,c)
+#define fm_peek(a,b,c)   recv(a,b,c, MSG_PEEK)
+#define fm_read(a,b,c)   read(a,b,c)
+#endif
+
 /* We need to define h_errno only if it is not already */
 #ifndef h_errno
 
@@ -50,11 +70,55 @@ static int h_errno;
 #endif /* NET_SECURITY */
 
 #ifdef HAVE_SOCKETPAIR
+const char **parse_plugin(const char *plugin, const char *host, const char *service)
+{      const char **argvec;
+       char *c, *p, *plugin_copy;
+       unsigned int s = 2 * sizeof(char*), i;
+
+       plugin_copy = strdup(plugin);
+       if (!plugin_copy)
+       {
+               report(stderr, _("fetchmail: malloc failed\n"));
+               return NULL;
+       }
+       for (c = p = plugin_copy; *c; c++)
+       {       if (isspace(*c) && !isspace(*p))
+                       s += sizeof(char*);
+               p = c;
+       }
+       argvec = malloc(s);
+       if (!argvec)
+       {
+               report(stderr, _("fetchmail: malloc failed\n"));
+               return NULL;
+       }
+       memset(argvec, 0, s);
+       for (c = p = plugin_copy, i = 0; *c; c++)
+       {       if ((!isspace(*c)) && (c == p ? 1 : isspace(*p))) {
+                       argvec[i] = c;
+                       i++;
+               }
+               p = c;
+       }
+       for (c = plugin_copy; *c; c++)
+       {       if (isspace(*c))
+                       *c = 0;
+       }
+       for (i = 0; argvec[i]; i++)
+       {       if (strcmp(argvec[i], "%h") == 0)
+                       argvec[i] = host;
+               if (strcmp(argvec[i], "%p") == 0)
+                       argvec[i] = service;
+       }
+       return argvec;
+}
+
 static int handle_plugin(const char *host,
                         const char *service, const char *plugin)
 /* get a socket mediated through a given external command */
 {
     int fds[2];
+    char *const *argvec;
     if (socketpair(AF_UNIX,SOCK_STREAM,0,fds))
     {
        report(stderr, _("fetchmail: socketpair failed\n"));
@@ -78,8 +142,9 @@ static int handle_plugin(const char *host,
                (void) close(fds[0]);
                if (outlevel >= O_VERBOSE)
                    report(stderr, _("running %s %s %s\n"), plugin, host, service);
-               execlp(plugin,plugin,host,service,0);
-               report(stderr, _("execl(%s) failed\n"), plugin);
+               argvec = (char *const *)parse_plugin(plugin,host,service);
+               execvp(*argvec, argvec);
+               report(stderr, _("execvp(%s) failed\n"), *argvec);
                exit(0);
                break;
        default:        /* parent */
@@ -121,7 +186,7 @@ int SockCheckOpen(int fd)
 int SockOpen(const char *host, const char *service, const char *options,
             const char *plugin)
 {
-    struct addrinfo *ai, req;
+    struct addrinfo *ai, *ai0, req;
     int i;
 #if NET_SECURITY
     void *request = NULL;
@@ -135,10 +200,10 @@ int SockOpen(const char *host, const char *service, const char *options,
     memset(&req, 0, sizeof(struct addrinfo));
     req.ai_socktype = SOCK_STREAM;
 
-    if (getaddrinfo(host, service, &req, &ai)) {
+    if (getaddrinfo(host, service, &req, &ai0)) {
        report(stderr, _("fetchmail: getaddrinfo(%s.%s)\n"), host,service);
        return -1;
-    };
+    }
 
 #if NET_SECURITY
     if (!options)
@@ -147,32 +212,36 @@ int SockOpen(const char *host, const char *service, const char *options,
        if (net_security_strtorequest((char *)options, &request, &requestlen))
            goto ret;
 
-    i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
+    i = inner_connect(ai0, request, requestlen, NULL, NULL, "fetchmail", NULL);
     if (request)
        free(request);
 
  ret:
 #else /* NET_SECURITY */
 #ifdef HAVE_INNER_CONNECT
-    i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
+    i = inner_connect(ai0, NULL, 0, NULL, NULL, "fetchmail", NULL);
+    if (i >= 0)
+       break;
 #else
-    i = socket(ai->ai_family, ai->ai_socktype, 0);
-    if (i < 0) {
-       freeaddrinfo(ai);
-       return -1;
-    }
-    if (connect(i, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) {
-       freeaddrinfo(ai);
-       close(i);       /* don't use SockClose, no traffic yet */
-       return -1;
+    i = -1;
+    for (ai = ai0; ai; ai = ai->ai_next) {
+       i = socket(ai->ai_family, ai->ai_socktype, 0);
+       if (i < 0)
+           continue;
+       if (connect(i, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) {
+           fm_close(i);
+           i = -1;
+           continue;
+       }
+       break;
     }
 #endif
 #endif /* NET_SECURITY */
 
-    freeaddrinfo(ai);
+    freeaddrinfo(ai0);
 
     return i;
-};
+}
 #else /* INET6_ENABLE */
 #ifndef HAVE_INET_ATON
 #ifndef  INADDR_NONE
@@ -226,7 +295,7 @@ int SockOpen(const char *host, int clientPort, const char *options,
         if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
         {
             int olderr = errno;
-            close(sock);       /* don't use SockClose, no traffic yet */
+            fm_close(sock);    /* don't use SockClose, no traffic yet */
             h_errno = 0;
             errno = olderr;
             return -1;
@@ -272,19 +341,20 @@ int SockOpen(const char *host, int clientPort, const char *options,
            memcpy(&ad.sin_addr, *pptr, sizeof(struct in_addr));
            if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) == 0)
                break; /* success */
-           close(sock);        /* don't use SockClose, no traffic yet */
+           fm_close(sock);     /* don't use SockClose, no traffic yet */
            memset(&ad, 0, sizeof(ad));
            ad.sin_family = AF_INET;
        }
        if(*pptr == NULL)
        {
            int olderr = errno;
-           close(sock);        /* don't use SockClose, no traffic yet */
+           fm_close(sock);     /* don't use SockClose, no traffic yet */
            h_errno = 0;
            errno = olderr;
            return -1;
        }
     }
+
     return(sock);
 }
 #endif /* INET6_ENABLE */
@@ -319,10 +389,10 @@ va_dcl {
 }
 
 #ifdef SSL_ENABLE
-#include "ssl.h"
-#include "err.h"
-#include "pem.h"
-#include "x509.h"
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#include "openssl/pem.h"
+#include "openssl/x509.h"
 
 static SSL_CTX *_ctx = NULL;
 static SSL *_ssl_context[FD_SETSIZE];
@@ -343,9 +413,9 @@ int SockWrite(int sock, char *buf, int len)
        if( NULL != ( ssl = SSLGetContext( sock ) ) )
                n = SSL_write(ssl, buf, len);
        else
-               n = write(sock, buf, len);
+               n = fm_write(sock, buf, len);
 #else
-        n = write(sock, buf, len);
+        n = fm_write(sock, buf, len);
 #endif
         if (n <= 0)
             return -1;
@@ -366,6 +436,14 @@ int SockRead(int sock, char *buf, int len)
 
     if (--len < 1)
        return(-1);
+#ifdef __BEOS__
+    if (peeked != 0){
+        (*bp) = peeked;
+        bp++;
+        len--;
+        peeked = 0;
+    }
+#endif        
     do {
        /* 
         * The reason for these gymnastics is that we want two things:
@@ -418,20 +496,27 @@ int SockRead(int sock, char *buf, int len)
                        newline = bp;
                }
        } else {
-               if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
+               if ((n = fm_peek(sock, bp, len)) <= 0)
                        return(-1);
                if ((newline = memchr(bp, '\n', n)) != NULL)
                        n = newline - bp + 1;
-               if ((n = read(sock, bp, n)) == -1)
+               if ((n = fm_read(sock, bp, n)) == -1)
                        return(-1);
        }
 #else
-       if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
-           return(-1);
+
+#ifdef __BEOS__
+    if ((n = fm_read(sock, bp, 1)) <= 0)
+#else
+    if ((n = fm_peek(sock, bp, len)) <= 0)
+#endif
+        return (-1);
        if ((newline = memchr(bp, '\n', n)) != NULL)
            n = newline - bp + 1;
-       if ((n = read(sock, bp, n)) == -1)
+#ifndef __BEOS__
+       if ((n = fm_read(sock, bp, n)) == -1)
            return(-1);
+#endif /* __BEOS__ */
 #endif
        bp += n;
        len -= n;
@@ -475,15 +560,20 @@ int SockPeek(int sock)
                        return 0;       /* Give him a '\0' character */
                }
        } else {
-               n = recv(sock, &ch, 1, MSG_PEEK);
+               n = fm_peek(sock, &ch, 1);
        }
 #else
-       n = recv(sock, &ch, 1, MSG_PEEK);
-#endif
+
+        n = fm_peek(sock, &ch, 1);
+
+#endif /* SSL_ENABLE */
        if (n == -1)
                return -1;
-       else
-               return(ch);
+
+#ifdef __BEOS__
+    peeked = ch;
+#endif
+    return(ch);
 }
 
 #ifdef SSL_ENABLE
@@ -557,7 +647,7 @@ int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx )
                                report(stdout, "Server CommonName: %s\n", cbuf );
                        /* Should we have some wildcarding here? */
                        if ( NULL != _ssl_server_cname
-                            && 0 != strcmp( cbuf, _ssl_server_cname ) ) {
+                            && 0 != strcasecmp( cbuf, _ssl_server_cname ) ) {
                                report(stdout,
                                       "Server CommonName mismatch: %s != %s\n",
                                       cbuf, _ssl_server_cname );
@@ -571,15 +661,15 @@ int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx )
        switch (ctx->error) {
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
                X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
-               report(stdout, "unknown issuer= %s", buf);
+               report(stdout, _("unknown issuer= %s"), buf);
                break;
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-               report(stderr, "Server Certificate not yet valid");
+               report(stderr, _("Server Certificate not yet valid"));
                break;
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-               report(stderr, "Server Certificate expired");
+               report(stderr, _("Server Certificate expired"));
                break;
        }
        /* We are not requiring or validating server or issuer id's as yet */
@@ -653,7 +743,6 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *servercname )
 int SockClose(int sock)
 /* close a socket gracefully */
 {
-    char ch;
 #ifdef SSL_ENABLE
     SSL *ssl;
 
@@ -664,23 +753,32 @@ int SockClose(int sock)
     }
 #endif
 
-    /* Half-close the connection first so the other end gets notified.
+#ifdef __UNUSED__
+    /* 
+     * This hangs in RedHat 6.2 after fetchmail runs for a while a
+     * FIN_WAIT2 comes up in netstat and fetchmail never returns from
+     * the recv system call. (Reported from jtnews
+     * <jtnews@bellatlantic.net>, Wed, 24 May 2000 21:26:02.)
+     *
+     * Half-close the connection first so the other end gets notified.
      *
      * This stops sends but allows receives (effectively, it sends a
-     * TCP <FIN>).
-     */
-    if (shutdown(sock, 1) == SUCCESS)
+     * TCP <FIN>).  */
+    if (shutdown(sock, 1) == 0) {
+       char ch;
        /* If there is any data still waiting in the queue, discard it.
         * Call recv() until either it returns 0 (meaning we received a FIN)
         * or any error occurs.  This makes sure all data sent by the other
         * side is acknowledged at the TCP level.
         */
-       if (recv(sock, &ch, 1, MSG_PEEK) > 0)
-           while (read(sock, &ch, 1) > 0)
+       if (fm_peek(sock, &ch, 1) > 0)
+           while (fm_read(sock, &ch, 1) > 0)
                continue;
+    }
+#endif /* __UNUSED__ */
 
     /* if there's an error closing at this point, not much we can do */
-    return(close(sock));       /* this is guarded */
+    return(fm_close(sock));    /* this is guarded */
 }
 
 #ifdef MAIN