Revision bump
[mmondor.git] / mmsoftware / mmmail / src / mmsmtpd / mmsmtpd.h
index 851dc1b..4d21fa2 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: mmsmtpd.h,v 1.24 2004/11/09 05:31:14 mmondor Exp $ */
+/* $Id: mmsmtpd.h,v 1.49 2009/01/17 03:48:20 mmondor Exp $ */
 
 /*
- * Copyright (C) 2001-2004, Matthew Mondor
+ * Copyright (C) 2001-2008, Matthew Mondor
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -18,6 +18,8 @@
  * 4. The name of Matthew Mondor may not be used to endorse or promote
  *    products derived from this software without specific prior written
  *    permission.
+ * 5. Redistribution of source code may not be released under the terms of
+ *    any GNU Public License derivate.
  *
  * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 /* HEADERS */
 
 #include <sys/types.h>
+#include <stdbool.h>
+#include <stdint.h>
 #include <time.h>
 
-#include <pth.h>
+#include <pthread.h>
+#include <mm_pthread_sleep.h>
 
 #include <mmtypes.h>
 #include <mmlist.h>
 #include <mmstat.h>
 #include <mmlimitrate.h>
 
+#include <libpq-fe.h>
+
 
 
 
 /* DEFINITIONS */
 #define DAEMON_NAME    "mmsmtpd"
-#define DAEMON_VERSION "mmmail-0.0.24/mmondor"
+#define DAEMON_VERSION "mmmail-0.3.2/mmondor"
 
 /* Negative states are used by the state swapper, others are real states */
 #define STATE_ERROR    -3
@@ -90,7 +97,9 @@ enum data_reason {
     DATA_SUBMIT = 0,
     DATA_OK,
     DATA_OVERFLOW,
+    DATA_TIMEOUT,
     DATA_HOPS,
+    DATA_HEADER,
     DATA_INTERNAL,
     DATA_MAX
 };
@@ -102,36 +111,41 @@ enum data_reason {
 
 /* Custom fdbreadbuf() return result */
 #define CFDBRB_HOPS    -1
+#define CFDBRB_HEADER  -2
 
 /* Asynchroneous functions we attach */
 #define ASYNC_RESQUERY 1
 
 /* Error registration macro */
-#define REGISTER_ERROR(x)      do { \
-    (x)->errors++; \
-       if (CONF.DELAY_ON_ERROR) \
-           pth_sleep((x)->errors); \
-} while(FALSE)
+#define REGISTER_ERROR(x)      do {                                    \
+    (x)->errors++;                                                     \
+       if (CONF.DELAY_ON_ERROR)                                        \
+           pthread_sleep((x)->errors);                                 \
+} while (/* CONSTCOND */0)
 
 /* Evaluates if a character is valid for addresses and hostnames */
-#define VALID_CHAR(c)          (((c) >= 'a' && (c) <= 'z') || \
-       ((c) >= '0' && (c) <= '9') || (c) == '.' || (c) == '-' || (c) == '_')
+#define VALID_ADDR_CHAR(c)     \
+   (valid_addr_char_table[(int)((unsigned char)(c))] != 0)
+#define VALID_HOST_CHAR(c)     \
+   (valid_addr_host_table[(int)((unsigned char)(c))] != 0)
 
 
 
 /* STRUCTURES */
+
 /* We store config file read results in this structure */
 typedef struct config {
-    char CHROOT_DIR[256], PID_PATH[256], USER[32], GROUPS[256],
-       LOG_FACILITY[32], SERVER_NAMES[1024], LISTEN_IPS[1024], DB_HOST[64],
-       DB_USER[32], DB_PASSWORD[32], DB_DATABASE[32], MAIL_DIR[256];
+    char LOCK_PATH[256], CHROOT_DIR[256], PID_PATH[256], USER[32], GROUPS[256],
+       LOG_FACILITY[32], SERVER_NAMES[1024], LISTEN_IPS[1024], DB_INFO[1024],
+       MAIL_DIR[256], MMRELAYD_SOCKET_PATH[256];
     long ALLOC_BUFFERS, LOG_LEVEL, LISTEN_PORT, MAX_ERRORS, MAX_IPS,
        MAX_PER_IP, CONNECTION_RATE, CONNECTION_PERIOD, INPUT_TIMEOUT,
        BANDWIDTH_IN, BANDWIDTH_OUT, GBANDWIDTH_IN, GBANDWIDTH_OUT, MAX_RCPTS,
        MAX_DATA_LINES, MAX_DATA_SIZE, MAX_HOPS, FLOOD_MESSAGES,
        FLOOD_EXPIRES, FLOOD_CACHE, ASYNC_PROCESSES;
-    bool RESOLVE_HOSTS, RESOLVE_HELO, RESOLVE_MX_MAIL, REQUIRE_HELO,
-       FLOOD_PROTECTION, STATFAIL_ADDRESS, STATFAIL_RELAY, STATFAIL_FLOOD,
+    bool RESOLVE_HOSTS, RESOLVE_HELO, RESOLVE_MX_MAIL, RESOLVE_MX_RCPT,
+       REQUIRE_HELO, FLOOD_PROTECTION, STATFAIL_HELO, STATFAIL_NOHELO,
+       STATFAIL_NOFROM, STATFAIL_ADDRESS, STATFAIL_RELAY, STATFAIL_FLOOD,
        STATFAIL_FULL, STATFAIL_TIMEOUT, STATFAIL_EOF, STATFAIL_FILTER,
        DELAY_ON_ERROR, RELAYING;
 } CONFIG;
@@ -149,20 +163,22 @@ typedef struct clientenv {
     long mesg_size;            /* Current cached message size in bytes */
     long errors;               /* Total number of errors that occured */
     int timeout;               /* Timeout in ms */
+    bool nofrom;               /* If empty MAIL FROM from allowed server */
     unsigned long id;          /* Our connection ID */
     unsigned long messages;    /* Messages user sent us */
     unsigned long rcpts;       /* Number of RCPT accepted */
     struct iface *iface;       /* Current interface user connected through */
-    struct async_clenv *aclenv;        /* Thread context for async_call() */
     list_t rcpt;               /* Cached recepients to send mail to */
-    mmstat_t vstat, pstat;     /* mmstat(3) handles */
+    struct async_clenv *aclenv;        /* Thread context for async_call() */
+    mmstat_t vstat, pstat;     /* Persistent mmstat(3) handles */
+    PGconn *pgconn;            /* Persistent pgsql connection */
 } clientenv;
 
 /* Used for RCPT addresses */
 typedef struct rcptnode {
     pnode_t node;
     char address[64], foraddress[64];
-    u_int64_t hash;
+    uint64_t hash;
     bool relay;                /* Non-local */
 } rcptnode;
 
@@ -178,13 +194,12 @@ typedef struct hostnode {
 
 struct hosts_expire_thread_iterator_udata {
     time_t current, soonest;
-    int cnt;
 };
 
 /* Used for mmfd thread support delegation/abstraction */
 struct mutexnode {
     pnode_t node;
-    pth_mutex_t mutex;
+    pthread_mutex_t mutex;
 };
 
 /* This defines a state */
@@ -203,13 +218,13 @@ typedef struct command {
 /* Information for a mailbox */
 struct box_info {
     long max_size, size, max_msgs, msgs;
-    bool filter;
+    bool filter, filter_type;
 };
 
 /* For fast command lookup */
 struct commandnode {
     hashnode_t node;
-    u_int32_t hash;
+    uint32_t hash;
     struct command *command;
     int index;
 };
@@ -223,7 +238,15 @@ struct reply_messages {
 /* Our validate_msg_line() context */
 struct validate_udata
 {
-    long hops, nhops;
+    /* Used to count number of Received: lines */
+    long hops;
+    /* Headers we consider mandatory, which we'll add if necessary */
+    bool msgid, date, from, to, subject, inreply;
+    /* Still considering to read the header */
+    bool header;
+    /* Internal linking */
+    clientenv *clenv;
+    char *h_from, *h_to, *h_subject, *h_id, *h_reply;
 };
 
 /* Our union for async_resquery() */
@@ -259,63 +282,65 @@ static int all_data(clientenv *);
 static int all_beer(clientenv *);
 
 static bool hash_commands(struct command *, size_t);
-static u_int32_t commandnode_keyhash(const void *, size_t);
+static uint32_t commandnode_keyhash(const void *, size_t);
 static int commandnode_keycmp(const void *, const void *, size_t);
 static bool reply(fdbuf *, int, bool, const char *, ...);
 
+static bool clientenv_constructor(pnode_t *);
+static void clientenv_destructor(pnode_t *);
+static void *utdata_constructor(void);
+static void utdata_destructor(void *);
 static clientenv *alloc_clientenv(void);
 static bool init_clientenv(clientenv *, bool);
 static clientenv *free_clientenv(clientenv *);
 static void empty_rcpts(list_t *);
-static bool check_alias(char *);
-static bool check_nofrom(const char *, const char *);
+static bool check_alias(clientenv *, char *);
+static bool check_nofrom(clientenv *);
+static int lock_check(const char *);
 static int best_match(const char *, const char *);
-static bool local_address(struct box_info *, const char *);
-static bool box_filter_allow(const char *, const char *);
+static bool local_address(clientenv *, struct box_info *, const char *);
+static bool box_filter_allow(clientenv *, const char *, const char *, bool);
 static void rfc_time(char *);
-static bool valid_address(clientenv *, char *, char *, int);
-static bool valid_host(clientenv *, char *, int, bool);
-static bool valid_ipaddress(const char *);
+static bool valid_address(clientenv *, char *, size_t, char *, int);
+static bool valid_host(clientenv *, char *, int, bool, bool);
+static bool valid_ipaddress(clientenv *, const char *);
 
 static int validate_msg_line(char *, ssize_t *, int *, void *);
 static bool do_data(clientenv *);
 inline static size_t do_data_received(char *, size_t, clientenv *, rcptnode *,
        const char *);
-inline static bool do_data_update(rcptnode *, size_t);
 static void do_data_stats(clientenv *, rcptnode *, size_t);
-#if defined(MMMAIL_MYSQL)
-static bool do_data_mysql(clientenv *, struct fdbrb_buffer *);
-#elif defined(MMMAIL_FILE)
 static bool address_relay_allow(clientenv *, int *, const char *);
 static void iso_time(char *);
 static bool message_write(char *, const char *, size_t, struct fdbrb_buffer *,
        const char *);
-static bool do_data_file(clientenv *, struct fdbrb_buffer *);
+static bool do_data_file(clientenv *, struct fdbrb_buffer *,
+               struct validate_udata *);
 static bool do_data_queue_box(clientenv *, const char *, size_t, struct
-       fdbrb_buffer *, rcptnode *);
+       fdbrb_buffer *, rcptnode *, struct validate_udata *);
 static bool do_data_queue_relay(clientenv *, const char *, size_t, struct
        fdbrb_buffer *, rcptnode *);
-#else
-#error "One of MMMAIL_MYSQL or MMMAIL_FILE must be #defined!"
-#endif
+static void do_data_queue_notify(clientenv *);
+static int do_data_queue_notify_connect(void);
 
 static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
-       struct async_clenv *);
+       struct async_clenv *, void *);
 
-static void *_pth_mutex_create(void);
-static void *_pth_mutex_destroy(void *);
-static void _pth_mutex_lock(void *);
-static void _pth_mutex_unlock(void *);
-static void _pth_thread_yield(void);
-static void _pth_thread_sleep(int);
-static bool _pth_eintr(void);
+static void thread_init(void);
+static void *thread_mutex_create(void);
+static void *thread_mutex_destroy(void *);
+static void thread_mutex_lock(void *);
+static void thread_mutex_unlock(void *);
+static bool thread_eintr(void);
 
 static void async_resquery(struct async_msg *);
-static int a_res_query(clientenv *, const char *, int, int, u_char *, int);
+static int a_res_query(clientenv *, const char *, int, int, char *, int);
 
 static void *hosts_expire_thread(void *);
 static bool hosts_expire_thread_iterator(hashnode_t *, void *);
 
+static void *db_gc_thread(void *);
+