summaryrefslogtreecommitdiffstats
path: root/errors.c
diff options
context:
space:
mode:
Diffstat (limited to 'errors.c')
-rw-r--r--errors.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/errors.c b/errors.c
new file mode 100644
index 0000000..c327a55
--- /dev/null
+++ b/errors.c
@@ -0,0 +1,296 @@
+/*
+ * This file is part of libESMTP, a library for submission of RFC 2822
+ * formatted electronic mail messages using the SMTP protocol described
+ * in RFC 2821.
+ *
+ * Copyright (C) 2001,2002 Brian Stafford <brian@stafford.uklinux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _SVID_SOURCE 1 /* Need this to get strerror_r() */
+
+#include <missing.h> /* declarations for missing library functions */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#if HAVE_LWRES_NETDB_H
+# include <lwres/netdb.h>
+#elif !HAVE_GETADDRINFO
+# include "getaddrinfo.h"
+#else
+# include <netdb.h>
+#endif
+#include "libesmtp-private.h"
+#include "api.h"
+
+struct errno_vars
+ {
+ int error;
+ int herror;
+ };
+
+static inline void
+set_error_internal (struct errno_vars *err, int code)
+{
+ err->error = code;
+ err->herror = 0;
+}
+
+static inline void
+set_herror_internal (struct errno_vars *err, int code)
+{
+ err->herror = code;
+ if (err->herror == EAI_SYSTEM)
+ err->error = errno;
+}
+
+/* Map error codes from getaddrinfo to/from those used by libESMTP. RFC
+ 2553 is silent on whether these values are +ve, -ve, how they sort or
+ even whether they are contiguous so the mapping is done with a
+ switch. NB EAI_SYSTEM is *not* mapped. */
+
+static int
+eai_to_libesmtp (int code)
+{
+#define MAP(code) case code: return SMTP_ERR_##code;
+ switch (code)
+ {
+ MAP(EAI_AGAIN)
+ MAP(EAI_FAIL)
+ MAP(EAI_MEMORY)
+#ifdef EAI_ADDRFAMILY /* it seems OSX does not define this */
+ MAP(EAI_ADDRFAMILY)
+#endif
+#ifdef EAI_NODATA /* it seems OSX does not define this */
+ MAP(EAI_NODATA)
+#endif
+ MAP(EAI_FAMILY)
+ MAP(EAI_BADFLAGS)
+ MAP(EAI_NONAME)
+ MAP(EAI_SERVICE)
+ MAP(EAI_SOCKTYPE)
+ default: return SMTP_ERR_INVAL;
+ }
+#undef MAP
+}
+
+static int
+libesmtp_to_eai (int code)
+{
+#define MAP(code) case SMTP_ERR_##code: return code;
+ switch (code)
+ {
+ MAP(EAI_AGAIN)
+ MAP(EAI_FAIL)
+ MAP(EAI_MEMORY)
+#ifdef EAI_ADDRFAMILY
+ MAP(EAI_ADDRFAMILY)
+#endif
+#ifdef EAI_NODATA
+ MAP(EAI_NODATA)
+#endif
+ MAP(EAI_FAMILY)
+ MAP(EAI_BADFLAGS)
+ MAP(EAI_NONAME)
+ MAP(EAI_SERVICE)
+ MAP(EAI_SOCKTYPE)
+ default: return 0;
+ }
+#undef MAP
+}
+
+static inline int
+get_error_internal (struct errno_vars *err)
+{
+ if (err->herror == 0 || err->herror == EAI_SYSTEM)
+ return err->error;
+ return eai_to_libesmtp (err->herror);
+}
+
+#ifndef USE_PTHREADS
+
+static struct errno_vars libesmtp_errno;
+
+void
+set_error (int code)
+{
+ set_error_internal (&libesmtp_errno, code);
+}
+
+void
+set_herror (int code)
+{
+ set_herror_internal (&libesmtp_errno, code);
+}
+
+int
+smtp_errno (void)
+{
+ return get_error_internal (&libesmtp_errno);
+}
+
+#else
+
+#include <pthread.h>
+
+static pthread_key_t libesmtp_errno;
+static pthread_once_t libesmtp_errno_once = PTHREAD_ONCE_INIT;
+
+static void
+errno_destroy (void *value)
+{
+ if (value != NULL)
+ free (value);
+}
+
+static void
+errno_alloc (void)
+{
+ pthread_key_create (&libesmtp_errno, errno_destroy);
+}
+
+static struct errno_vars *
+errno_ptr (void)
+{
+ struct errno_vars *value;
+
+ pthread_once (&libesmtp_errno_once, errno_alloc);
+ value = pthread_getspecific (libesmtp_errno);
+ if (value == NULL)
+ {
+ value = malloc (sizeof (struct errno_vars));
+ /* FIXME: check for NULL malloc */
+ memset (value, 0, sizeof (struct errno_vars));
+ pthread_setspecific (libesmtp_errno, value);
+ }
+ return value;
+}
+
+void
+set_error (int code)
+{
+ struct errno_vars *value = errno_ptr ();
+
+ if (value != NULL)
+ set_error_internal (value, code);
+}
+
+void
+set_herror (int code)
+{
+ struct errno_vars *value = errno_ptr ();
+
+ if (value != NULL)
+ set_herror_internal (value, code);
+}
+
+int
+smtp_errno (void)
+{
+ struct errno_vars *value = errno_ptr ();
+
+ return (value != NULL) ? get_error_internal (value) : ENOMEM;
+}
+
+#endif
+
+/* store the value of errno in libESMTP's error variable. */
+void
+set_errno (int code)
+{
+ set_error (-code);
+}
+
+static const char *libesmtp_errors[] =
+ {
+ "No Error",
+ "",
+ "Nothing to do", /* NOTHING_TO_DO */
+ "SMTP server dropped connection", /* DROPPED_CONNECTION */
+ "Invalid SMTP syntax in server response", /* INVALID_RESPONSE_SYNTAX */
+ "SMTP Status code mismatch on continuation line", /* STATUS_MISMATCH */
+ "Invalid SMTP status code in server response", /* INVALID_RESPONSE_STATUS */
+ "Invalid API function argument", /* INVAL */
+ "Requested SMTP extension not available", /* EXTENSION_NOT_AVAILABLE */
+ /* Next 10 codes handled by gai_strerror() */
+ NULL, /* EAI_ADDRFAMILY */
+ NULL, /* EAI_NODATA */
+ NULL, /* EAI_FAIL */
+ NULL, /* EAI_AGAIN */
+ NULL, /* EAI_MEMORY */
+ NULL, /* EAI_FAMILY */
+ NULL, /* EAI_BADFLAGS */
+ NULL, /* EAI_NONAME */
+ NULL, /* EAI_SERVICE */
+ NULL, /* EAI_SOCKTYPE */
+ "Unterminated server response", /* UNTERMINATED_RESPONSE */
+ "Client error", /* CLIENT_ERROR */
+ };
+
+char *
+smtp_strerror (int error, char buf[], size_t buflen)
+{
+ const char *text;
+ int len;
+ int map;
+
+ SMTPAPI_CHECK_ARGS (buf != NULL && buflen > 0, NULL);
+
+ if (error < 0)
+#if HAVE_WORKING_STRERROR_R
+ return strerror_r (-error, buf, buflen);
+#elif HAVE_STRERROR_R
+ {
+ /* Assume the broken OSF1 strerror_r which returns an int. */
+ int n = strerror_r (-error, buf, buflen);
+
+ return n >= 0 ? buf : NULL;
+ }
+#else
+ /* Could end up here when threading is enabled but a working
+ strerror_r() is not found. There will be a critical section
+ of code until the returned string is copied to the supplied
+ buffer. This could be solved using a mutex but its hardly
+ worth it since even if libESMTP is protected against itself
+ the application could still call strerror anyway. */
+ text = strerror (-error);
+#endif
+ else if ((map = libesmtp_to_eai (error)) != 0)
+ text = gai_strerror (map);
+ else if (error < (int) (sizeof libesmtp_errors / sizeof libesmtp_errors[0]))
+ text = libesmtp_errors[error];
+ else
+ text = (const char *) 0;
+
+ if (text == (const char *) 0)
+ len = snprintf (buf, buflen, "Error %d", error);
+ else
+ {
+ len = strlen (text);
+ if (len > (int) buflen - 1)
+ len = buflen - 1;
+ if (len > 0)
+ memcpy (buf, text, len);
+ buf[len] = '\0';
+ }
+ return len >= 0 ? buf : NULL;
+}