2005-11-09 [colin] 1.9.100cvs5
[claws.git] / src / common / ssl.c
index b8c401e7e46e88bf77938fc985505fbedb0660ab..31bfafe39d26b85b70f89aee8dafd26ed5dd9cdd 100644 (file)
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "defs.h"
 
 #include <glib.h>
+#include <glib/gi18n.h>
 
-#include "intl.h"
+#include "sylpheed.h"
 #include "utils.h"
 #include "ssl.h"
-#include "log.h"
 #include "ssl_certificate.h"
 
+#ifdef HAVE_LIBETPAN
+#include <libetpan/mailstream_ssl.h>
+#endif
+
+#ifdef USE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifdef USE_PTHREAD
+typedef struct _thread_data {
+       SSL *ssl;
+       gboolean done;
+} thread_data;
+#endif
+
+
 static SSL_CTX *ssl_ctx;
 
 void ssl_init(void)
 {
        SSL_METHOD *meth;
-       FILE *cert_test;
 
        /* Global system initialization*/
        SSL_library_init();
        SSL_load_error_strings();
-       
+
+#ifdef HAVE_LIBETPAN
+       mailstream_openssl_init_not_required();
+#endif 
+
        /* Create our context*/
        meth = SSLv23_client_method();
        ssl_ctx = SSL_CTX_new(meth);
@@ -51,17 +70,8 @@ void ssl_init(void)
        /* Set default certificate paths */
        SSL_CTX_set_default_verify_paths(ssl_ctx);
        
-       /* this problem seems quite common */
-       cert_test = fopen (X509_get_default_cert_file(), "r");
-       if (cert_test != NULL)
-               fclose(cert_test);
-       else {
-               printf("ssl_init: warning, can't open %s\n", X509_get_default_cert_file());
-               printf("ssl_init: it means that certificates' signatures won't appear as Correct,\n");
-               printf("ssl_init: even if they should. Check your openssl install.\n");
-       }
 #if (OPENSSL_VERSION_NUMBER < 0x0090600fL)
-       SSL_CTX_set_verify_depth(ctx,1);
+       SSL_CTX_set_verify_depth(ssl_ctx,1);
 #endif
 }
 
@@ -73,6 +83,52 @@ void ssl_done(void)
        SSL_CTX_free(ssl_ctx);
 }
 
+#ifdef USE_PTHREAD
+void *SSL_connect_thread(void *data)
+{
+       thread_data *td = (thread_data *)data;
+       int result = SSL_connect(td->ssl);
+       td->done = TRUE; /* let the caller thread join() */
+       return GINT_TO_POINTER(result);
+}
+#endif
+
+gint SSL_connect_nb(SSL *ssl)
+{
+#if (defined USE_PTHREAD && defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)))
+       thread_data *td = g_new0(thread_data, 1);
+       pthread_t pt;
+       void *res = NULL;
+       
+       td->ssl  = ssl;
+       td->done = FALSE;
+       
+       /* try to create a thread to initialize the SSL connection,
+        * fallback to blocking method in case of problem 
+        */
+       if (pthread_create(&pt, PTHREAD_CREATE_JOINABLE, 
+                       SSL_connect_thread, td) != 0)
+               return SSL_connect(ssl);
+       
+       debug_print("waiting for SSL_connect thread...\n");
+       while(!td->done) {
+               /* don't let the interface freeze while waiting */
+               sylpheed_do_idle();
+       }
+
+       /* get the thread's return value and clean its resources */
+       pthread_join(pt, &res);
+       g_free(td);
+
+       debug_print("SSL_connect thread returned %d\n", 
+                       GPOINTER_TO_INT(res));
+       
+       return GPOINTER_TO_INT(res);
+#else
+       return SSL_connect(ssl);
+#endif
+}
+
 gboolean ssl_init_socket(SockInfo *sockinfo)
 {
        return ssl_init_socket_with_method(sockinfo, SSL_METHOD_SSLv23);
@@ -85,7 +141,7 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
 
        ssl = SSL_new(ssl_ctx);
        if (ssl == NULL) {
-               log_warning(_("Error creating ssl context\n"));
+               g_warning(_("Error creating ssl context\n"));
                return FALSE;
        }
 
@@ -103,15 +159,16 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
        }
 
        SSL_set_fd(ssl, sockinfo->sock);
-       if (SSL_connect(ssl) == -1) {
-               log_warning(_("SSL connect failed (%s)\n"),
+       if (SSL_connect_nb(ssl) == -1) {
+               g_warning(_("SSL connect failed (%s)\n"),
                            ERR_error_string(ERR_get_error(), NULL));
                SSL_free(ssl);
                return FALSE;
        }
 
        /* Get the cipher */
-       log_print(_("SSL connection using %s\n"), SSL_get_cipher(ssl));
+
+       debug_print("SSL connection using %s\n", SSL_get_cipher(ssl));
 
        /* Get server's certificate (note: beware of dynamic allocation) */
        if ((server_cert = SSL_get_peer_certificate(ssl)) == NULL) {
@@ -120,12 +177,14 @@ gboolean ssl_init_socket_with_method(SockInfo *sockinfo, SSLMethod method)
                return FALSE;
        }
 
+
        if (!ssl_certificate_check(server_cert, sockinfo->hostname, sockinfo->port)) {
                X509_free(server_cert);
                SSL_free(ssl);
                return FALSE;
        }
 
+
        X509_free(server_cert);
        sockinfo->ssl = ssl;