[Exim] patch for XMLRPC support (Exim 4.10)

Top Page
Delete this message
Reply to this message
Author: Joel Vandal
Date:  
To: exim-users
Subject: [Exim] patch for XMLRPC support (Exim 4.10)
This is a multi-part message in MIME format.
--
[ Picked text/plain from multipart/alternative ]
Hi,

Here is a patch that add XMLRPC functionnality to Exim 4.10. The only requirement is the xmlrpc-c (http://xmlrpc-c.sourceforge.net) library and an XMLRPC server & script. (I will post in a few day my XMLRPC modules w/ mySQL caching, etc...)

It work exactly like the ${perl{arg1}{arg2}} syntax then you can use the ${xmlrpc{function}{arg1}{arg2}..{arg8}} tag anywhere on exim.conf.

Documentation, tutorial, examples, etc.. are currently missing but I will have more time on the following day (or week <g>)

--
Joel Vandal
Infoteck Internet
Trois-Rivières, QC / CAN

====CUT====


diff -Nur  exim-4.10/OS/Makefile-Base exim-4.10xmlrpc/OS/Makefile-Base
--- exim-4.10/OS/Makefile-Base 2002-07-22 04:59:45.000000000 -0400
+++ exim-4.10xmlrpc/OS/Makefile-Base 2002-11-12 10:49:21.000000000 -0500
@@ -244,7 +244,7 @@
         rda.o readconf.o receive.o retry.o rewrite.o \
         route.o search.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
         store.o string.o tls.o tod.o transport.o tree.o verify.o \
-        local_scan.o $(EXIM_PERL)
+        local_scan.o $(EXIM_PERL) $(EXIM_XMLRPC)


 exim:   pcre/libpcre.a lookups/lookups.a auths/auths.a \
         routers/routers.a transports/transports.a \
@@ -259,7 +259,8 @@
    routers/routers.a transports/transports.a lookups/lookups.a \
    auths/auths.a \
    $(LIBRESOLV) $(LIBS) $(LIBS_EXIM) $(IPV6_LIBS) $(EXTRALIBS) \
-   $(EXTRALIBS_EXIM) $(DBMLIB) $(LOOKUP_LIBS) $(PERL_LIBS) $(TLS_LIBS)
+   $(EXTRALIBS_EXIM) $(DBMLIB) $(LOOKUP_LIBS) $(PERL_LIBS) \
+   $(XMLRPC_LIBS) $(TLS_LIBS)
  @if [ x"$(STRIP_COMMAND)" != x"" ]; then \
    echo $(STRIP_COMMAND) exim; \
    $(STRIP_COMMAND) exim; \
@@ -397,6 +398,11 @@
 perl.o:          $(HDRS) perl.c
  $(PERL_CC) $(PERL_CCOPTS) $(INCLUDE) -c perl.c


+# Compile instructions for xmlrpc.o for when EXIM_XMLRPC is set
+
+xmlrpc.o:          $(HDRS) xmlrpc.c
+ $(CC) $(CFLAGS) $(INCLUDE) -c xmlrpc.c
+
 # Compile instructions for the database utility modules


 exim_dumpdb.o:   $(HDRS) exim_dbutil.c
diff -Nur  exim-4.10/scripts/MakeLinks exim-4.10xmlrpc/scripts/MakeLinks
--- exim-4.10/scripts/MakeLinks 2002-07-22 04:59:47.000000000 -0400
+++ exim-4.10xmlrpc/scripts/MakeLinks 2002-11-12 10:48:51.000000000 -0500
@@ -213,5 +213,6 @@
 ln -s ../src/tree.c            tree.c
 ln -s ../src/verify.c          verify.c
 ln -s ../src/version.c         version.c
+ln -s ../src/xmlrpc.c          xmlrpc.c


# End of MakeLinks
diff -Nur exim-4.10/src/EDITME exim-4.10xmlrpc/src/EDITME
--- exim-4.10/src/EDITME 2002-07-22 04:59:47.000000000 -0400
+++ exim-4.10xmlrpc/src/EDITME 2002-11-13 23:02:24.000000000 -0500
@@ -426,6 +426,20 @@


#------------------------------------------------------------------------------
+# Compiling in support for embedded XML-RPC client : If you want to be
+# able to use XMLRPC call, set EXIM_XMLRPC to xmlrpc.o.
+
+# EXIM_XMLRPC=xmlrpc.o
+
+
+#------------------------------------------------------------------------------
+# If you have specified EXIM_XMLRPC=xmlrpc.o you must uncomment the
+# following line to link xmlrpc-c library
+
+# XMLRPC_LIBS=`xmlrpc-c-config libwww-client --libs`
+
+
+#------------------------------------------------------------------------------
# Exim has support for PAM (Pluggable Authentication Modules), a facility
# which is available in the latest releases of Solaris and in some GNU/Linux
# distributions (see http://ftp.kernel.org/pub/linux/libs/pam/). The Exim
@@ -730,4 +744,5 @@

# SUPPORT_MOVE_FROZEN_MESSAGES=yes

+
 # End of EDITME for Exim 4.
diff -Nur  exim-4.10/src/config.h.defaults exim-4.10xmlrpc/src/config.h.defaults
--- exim-4.10/src/config.h.defaults 2002-07-22 04:59:48.000000000 -0400
+++ exim-4.10xmlrpc/src/config.h.defaults 2002-11-07 11:38:20.000000000 -0500
@@ -33,6 +33,7 @@
 #define EXIMDB_MODE                0640


#define EXIM_PERL
+#define EXIM_XMLRPC

 /* Both uid and gid are triggered by this */
 #define EXIM_UID
diff -Nur  exim-4.10/src/expand.c exim-4.10xmlrpc/src/expand.c
--- exim-4.10/src/expand.c 2002-07-22 04:59:48.000000000 -0400
+++ exim-4.10xmlrpc/src/expand.c 2002-11-12 20:12:38.000000000 -0500
@@ -48,6 +48,9 @@
   #ifdef EXIM_PERL
   US"perl",
   #endif
+  #ifdef EXIM_XMLRPC
+  US"xmlrpc",
+  #endif
   US"readfile",
   US"run",
   US"sg",
@@ -60,6 +63,9 @@
   #ifdef EXIM_PERL
   EITEM_PERL,
   #endif
+  #ifdef EXIM_XMLRPC
+  EITEM_XMLRPC,
+  #endif
   EITEM_READFILE,
   EITEM_RUN,
   EITEM_SG,
@@ -1596,6 +1602,7 @@
    ${if cond {s1} {s2}}    conditional; the yielded string is expanded
                            {s2} can be replaced by "fail" or be omitted
    ${perl{sub}{a1}...      call Perl (if configured)
+   ${xmlrpc{sub}{a1}...    call Perl (if configured)
    ${sg {source}{s1}{s2}}  global substitution
    ${tr {source}{s1}{s2}}  translate characters


@@ -2172,25 +2179,108 @@

       if (new_yield == NULL)
         {
-        if (expand_string_message == NULL)
-          {
-          expand_string_message =
-            string_sprintf("Perl subroutine \"%s\" returned undef to force "
-              "failure", sub_arg[0]);
-          expand_string_forcedfail = TRUE;
-          }
-        goto EXPAND_FAILED;
-        }
-
-      /* Yield succeeded. Ensure forcedfail is unset, just in case it got
-      set during a callback from Perl. */
-
-      expand_string_forcedfail = FALSE;
-      yield = new_yield;
-      continue;
+    if (expand_string_message == NULL)
+      {
+ expand_string_message =
+   string_sprintf("Perl subroutine \"%s\" returned undef to force "
+ "failure", sub_arg[0]);
+ expand_string_forcedfail = TRUE;
+      }
+    goto EXPAND_FAILED;
+        }
+
+ /* Yield succeeded. Ensure forcedfail is unset, just in case it got
+   set during a callback from Perl. */
+
+ expand_string_forcedfail = FALSE;
+ yield = new_yield;
+ continue;
       }
-    #endif /* EXIM_PERL */
-
+#endif /* EXIM_PERL */
+
+       /* If XMLRPC support is configured, handle calling xmlrpc subroutines,
+ unless locked out at this time. Syntax is ${xmlrpc{sub}} or
+ ${xmlrpc{sub}{arg}} or ${xmlrpc{sub}{arg1}{arg2}} or up to a maximum of
+ EXIM_XMLRPC_MAX_ARGS arguments (defined below). */
+
+#ifdef EXIM_XMLRPC
+#define EXIM_XMLRPC_MAX_ARGS 8
+
+     case EITEM_XMLRPC:
+ {
+     uschar *sub_arg[EXIM_XMLRPC_MAX_ARGS + 2];
+     uschar *new_yield;
+     uschar *initerror;
+     DEBUG(D_any) debug_printf("Entering XMLRPC\n");
+
+     if ((expand_forbid & RDO_XMLRPC) != 0)
+       {
+ expand_string_message = US"XMLRPC calls are not permitted";
+ goto EXPAND_FAILED;
+       }
+
+     switch(read_subs(sub_arg, EXIM_XMLRPC_MAX_ARGS + 1, 1, &s, skipping))
+       {
+        case 1: goto EXPAND_FAILED_CURLY;
+        case 2: expand_string_message =
+    string_sprintf("Too many arguments passed to XMLRPC "
+   "subroutine \"%s\" (max is %d)", sub_arg[0],
+   EXIM_XMLRPC_MAX_ARGS);
+        case 3: goto EXPAND_FAILED;
+       }
+
+     /* If skipping, we don't actually do anything */
+
+     if (skipping) continue;
+
+     /* Start the interpreter if necessary */
+
+     if (xmlrpc_servers == NULL)
+       {
+ expand_string_message = US"A setting of xmlrpc_servers is needed when "
+    "using the XMLRPC module";
+ goto EXPAND_FAILED;
+       }
+     DEBUG(D_any) debug_printf("Starting XMLRPC\n");
+     initerror = init_xmlrpc(xmlrpc_servers);
+     if (initerror != NULL)
+       {
+ expand_string_message =
+    string_sprintf("error in xmlrpc code: %s\n", initerror);
+ goto EXPAND_FAILED;
+       }
+
+     /* Call the function */
+
+     sub_arg[EXIM_XMLRPC_MAX_ARGS + 1] = NULL;
+     new_yield = call_xmlrpc_cat(yield, &size, &ptr, &expand_string_message,
+ sub_arg[0], sub_arg + 1);
+
+     /* NULL yield indicates failure; if the message pointer has been set to
+      NULL, the yield was undef, indicating a forced failure. Otherwise the
+      message will indicate some kind of Perl error. */
+
+     if (new_yield == NULL)
+       {
+ if (expand_string_message == NULL)
+    {
+       expand_string_message =
+ string_sprintf("XMLRPC subroutine \"%s\" returned undef to force "
+        "failure", sub_arg[0]);
+       expand_string_forcedfail = TRUE;
+    }
+ goto EXPAND_FAILED;
+       }
+
+     /* Yield succeeded. Ensure forcedfail is unset, just in case it got
+      set during a callback from Perl. */
+
+     expand_string_forcedfail = FALSE;
+     yield = new_yield;
+     continue;
+ }
+#endif /* EXIM_XMLRPC */
+
     /* Handle "readfile" to insert an entire file */


     case EITEM_READFILE:
diff -Nur  exim-4.10/src/functions.h exim-4.10xmlrpc/src/functions.h
--- exim-4.10/src/functions.h 2002-07-22 04:59:48.000000000 -0400
+++ exim-4.10xmlrpc/src/functions.h 2002-11-07 15:25:45.000000000 -0500
@@ -19,6 +19,13 @@
 extern uschar *init_perl(uschar *);
 #endif


+#ifdef EXIM_XMLRPC
+extern uschar *call_xmlrpc_cat(uschar *, int *, int *, uschar **, uschar *,
+                 uschar **);
+extern void    cleanup_xmlrpc(void);
+extern uschar *init_xmlrpc(uschar *);
+#endif
+


 #ifdef SUPPORT_TLS
 extern BOOL    tls_client_start(int, host_item *, address_item *, uschar *,
diff -Nur  exim-4.10/src/globals.c exim-4.10xmlrpc/src/globals.c
--- exim-4.10/src/globals.c 2002-07-22 04:59:48.000000000 -0400
+++ exim-4.10xmlrpc/src/globals.c 2002-11-12 15:04:31.000000000 -0500
@@ -58,6 +58,10 @@
 BOOL    opt_perl_started       = FALSE;
 #endif


+#ifdef EXIM_XMLRPC
+uschar *xmlrpc_servers          = NULL;
+#endif
+
 #ifdef LOOKUP_LDAP
 uschar *ldap_default_servers   = NULL;
 #endif
@@ -317,7 +321,8 @@
   { US"tls",            D_tls },
   { US"transport",      D_transport },
   { US"uid",            D_uid },
-  { US"verify",         D_verify }
+  { US"verify",         D_verify },
+  { US"xmlrpc",         D_xmlrpc }
 };
 int     debug_options_count    = sizeof(debug_options)/sizeof(bit_table);
 pid_t   debug_pid              = 0;
diff -Nur  exim-4.10/src/globals.h exim-4.10xmlrpc/src/globals.h
--- exim-4.10/src/globals.h 2002-07-22 04:59:49.000000000 -0400
+++ exim-4.10xmlrpc/src/globals.h 2002-11-07 13:37:47.000000000 -0500
@@ -23,6 +23,10 @@
 extern BOOL    opt_perl_started;       /* Set once interpreter started */
 #endif


+#ifdef EXIM_XMLRPC
+extern uschar *xmlrpc_servers;          /* List of servers and connect info */
+#endif
+
 #ifdef LOOKUP_LDAP
 extern uschar *ldap_default_servers;   /* List of default servers */
 #endif
diff -Nur  exim-4.10/src/macros.h exim-4.10xmlrpc/src/macros.h
--- exim-4.10/src/macros.h 2002-07-22 04:59:49.000000000 -0400
+++ exim-4.10xmlrpc/src/macros.h 2002-11-12 14:10:23.000000000 -0500
@@ -304,6 +304,7 @@
 #define D_transport                  0x01000000
 #define D_uid                        0x02000000
 #define D_verify                     0x04000000
+#define D_xmlrpc                     0x08000000


 #define D_all                        0xffffffff
 #define D_any                        0xfffffffe   /* Excludes D_v */
@@ -442,6 +443,8 @@
 #define RDO_RUN        0x00002000  /* Forbid "run" in expansion in filter */
 #define RDO_REALLOG    0x00004000  /* Really do log (not testing/verifying) */
 #define RDO_REWRITE    0x00008000  /* Rewrite generated addresses */
+#define RDO_XMLRPC     0x00010000  /* Forbid "xmlrpc" in expansion in filter */
+


/* As well as the RDO bits themselves, we need the bit numbers in order to
access (most of) the individual bits as separate options. This could be
@@ -449,7 +452,7 @@

enum { RDON_BLACKHOLE, RDON_DEFER, RDON_EACCES, RDON_ENOTDIR, RDON_EXISTS,
RDON_FAIL, RDON_FILTER, RDON_FREEZE, RDON_INCLUDE, RDON_LOG, RDON_LOOKUP,
- RDON_PERL, RDON_READFILE, RDON_RUN, RDON_REALLOG, RDON_REWRITE };
+ RDON_PERL, RDON_READFILE, RDON_RUN, RDON_REALLOG, RDON_REWRITE, RDON_XMLRPC };

/* Results of filter or forward file processing. Some are only from a filter;
some are only from a forward file. */
diff -Nur exim-4.10/src/rda.c exim-4.10xmlrpc/src/rda.c
--- exim-4.10/src/rda.c 2002-07-22 04:59:50.000000000 -0400
+++ exim-4.10xmlrpc/src/rda.c 2002-11-12 20:14:23.000000000 -0500
@@ -349,8 +349,8 @@
DEBUG(D_route) debug_printf("data is a filter program\n");

   expand_forbid =
-    (expand_forbid & ~(RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_RUN)) |
-    (options & (RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_RUN));
+    (expand_forbid & ~(RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_RUN|RDO_XMLRPC)) |
+    (options & (RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_RUN|RDO_XMLRPC));
   frc = filter_interpret(data, options, generated, error);
   expand_forbid = old_expand_forbid;
   return frc;
diff -Nur  exim-4.10/src/readconf.c exim-4.10xmlrpc/src/readconf.c
--- exim-4.10/src/readconf.c 2002-07-22 04:59:50.000000000 -0400
+++ exim-4.10xmlrpc/src/readconf.c 2002-11-07 13:36:26.000000000 -0500
@@ -210,7 +210,10 @@
   { "untrusted_set_sender",     opt_stringptr,   &untrusted_set_sender },
   { "uucp_from_pattern",        opt_stringptr,   &uucp_from_pattern },
   { "uucp_from_sender",         opt_stringptr,   &uucp_from_sender },
-  { "warn_message_file",        opt_stringptr,   &warn_message_file }
+  { "warn_message_file",        opt_stringptr,   &warn_message_file },
+#ifdef EXIM_XMLRPC
+  { "xmlrpc_servers",             opt_stringptr,   &xmlrpc_servers },
+#endif
 };


 static int optionlist_config_size =
diff -Nur  exim-4.10/src/xmlrpc.c exim-4.10xmlrpc/src/xmlrpc.c
--- exim-4.10/src/xmlrpc.c 1969-12-31 19:00:00.000000000 -0500
+++ exim-4.10xmlrpc/src/xmlrpc.c 2002-11-13 23:38:33.000000000 -0500
@@ -0,0 +1,150 @@
+/*************************************************
+ *     Exim - an Internet mail transport agent    *
+ *************************************************/
+
+/* Copyright (c) 2002 Infoteck Internet <webmaster@???> */
+/* Copyright (c) 2002 Joel Vandal <jvandal@???> */
+
+/* This xmlrpc add-on can be distributed under the same terms as Exim itself. */
+/* See the file NOTICE for conditions of use and distribution. */
+
+#include "exim.h"
+
+/* Include XMLRPC headers */
+
+#include <xmlrpc.h>
+#include <xmlrpc_client.h>
+
+#define XMLRPC_CLIENT_NAME    "EXIM-XMLRPC"
+#define XMLRPC_CLIENT_VERSION "4.10"
+
+#define EXIM_TRUE TRUE
+#undef TRUE
+
+#define EXIM_FALSE FALSE
+#undef FALSE
+
+void xmlrpc_clean(xmlrpc_env *env);
+
+uschar * init_xmlrpc(uschar *xmlrpcservers)
+{
+   return 0;
+}
+
+uschar * call_xmlrpc_cat(uschar *yield, int *sizep, int *ptrp,
+ uschar **errstrp, uschar *name, uschar **arg)
+{
+   uschar *str;
+   uschar *res;
+   int len;
+
+   xmlrpc_env *env;
+   xmlrpc_value *result;
+   xmlrpc_value *list;
+   xmlrpc_value *item;
+
+   /* Start up our XML-RPC client library. */
+   xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, XMLRPC_CLIENT_NAME, XMLRPC_CLIENT_VERSION);
+
+   env=(xmlrpc_env *)malloc(sizeof(xmlrpc_env));
+   xmlrpc_env_init(env);
+
+   list = xmlrpc_build_value (env, "()");
+   if (check_xmlrpc_fault(env))
+     {
+ xmlrpc_clean(env);
+ return 0;
+     }
+
+   while (*arg != 0)
+     {
+ item=xmlrpc_build_value(env, "s",*arg++);
+ if(check_xmlrpc_fault(env))
+   {
+      xmlrpc_clean(env);
+      return 0;
+   }
+
+ xmlrpc_array_append_item(env, list, item);
+ xmlrpc_DECREF(item);
+ if(check_xmlrpc_fault(env))
+   {
+      xmlrpc_clean(env);
+      return 0;
+   }
+
+     }
+
+   /* Send the XMLRPC request (an array of string) to the server */
+   if((result = xmlrpc_client_call(env,xmlrpc_servers,name, "(V)", list))==0)
+     {
+ DEBUG(D_xmlrpc) debug_printf("Error occured while calling XMLRPC server\n");
+ xmlrpc_clean(env);
+ return 0;
+     }
+
+   if(check_xmlrpc_fault(env))
+     {
+ xmlrpc_clean(env);
+ return 0;
+     }
+
+   DEBUG(D_xmlrpc) debug_printf("called XMLRPC server\n");
+
+   if(result)
+     {
+ DEBUG(D_xmlrpc) debug_printf("XMLRPC returned result is OK\n");
+
+ /* The XMLRPC result is an array of string */
+ xmlrpc_parse_value(env, result, "(s#)", &res, &len) ;
+
+ if(check_xmlrpc_fault(env))
+   {
+      xmlrpc_clean(env);
+      return 0;
+   }
+
+ DEBUG(D_xmlrpc) debug_printf("XMLRPC check result passed... value: %s len: %d\n", res, len);
+
+     }
+   else
+     {
+ xmlrpc_clean(env);
+ return 0;
+     }
+
+   DEBUG(D_xmlrpc) debug_printf("Finished sending the query via XMLRPC\n");
+
+   yield = string_cat(yield, sizep, ptrp, res, (int)strlen(res));
+
+   /* Dispose of our result value. */
+   xmlrpc_DECREF(result);
+
+   /* Shutdown our XML-RPC client library. */
+   xmlrpc_clean(env);
+
+   return yield;
+
+}
+
+void xmlrpc_clean(xmlrpc_env *env)
+{
+       xmlrpc_env_clean(env);
+       /* Shutdown our XML-RPC client library. */
+       xmlrpc_client_cleanup();
+       free(env);
+}
+
+int check_xmlrpc_fault (xmlrpc_env *env)
+{
+   /* Check our error-handling environment for an XML-RPC fault. */
+   if (env->fault_occurred)
+     {
+ DEBUG(D_xmlrpc) debug_printf("XMLRPC Fault: %s (%d)", env->fault_string, env->fault_code);
+ return 1;
+     }
+
+   return 0;
+}
+
+/* End of xmlrpc.c */


--