Back to index

php5  5.3.10
php_milter.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Harald Radi <phanto@php.net>                                 |
00016    |         Parts based on CGI SAPI Module by                            |
00017    |         Rasmus Lerdorf, Stig Bakken and Zeev Suraski                 |
00018    +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: php_milter.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include "php.h"
00024 #include "php_globals.h"
00025 #include "php_variables.h"
00026 #include "zend_modules.h"
00027 
00028 #ifndef ZTS
00029 #error SRM sapi module is only useable in thread-safe mode
00030 #endif
00031 
00032 #include "SAPI.h"
00033 
00034 #include <stdio.h>
00035 #include "php.h"
00036 #if HAVE_SYS_TIME_H
00037 #include <sys/time.h>
00038 #endif
00039 #if HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 #if HAVE_SIGNAL_H
00043 #include <signal.h>
00044 #endif
00045 #if HAVE_SETLOCALE
00046 #include <locale.h>
00047 #endif
00048 #include "zend.h"
00049 #include "zend_extensions.h"
00050 #include "php_ini.h"
00051 #include "php_globals.h"
00052 #include "php_main.h"
00053 #include "fopen_wrappers.h"
00054 #include "ext/standard/php_standard.h"
00055 
00056 #ifdef __riscos__
00057 #include <unixlib/local.h>
00058 #endif
00059 
00060 #include "zend_compile.h"
00061 #include "zend_execute.h"
00062 #include "zend_highlight.h"
00063 #include "zend_indent.h"
00064 
00065 #include "libmilter/mfapi.h"
00066 
00067 #include "php_getopt.h"
00068 
00069 #define OPTSTRING "ac:d:Def:hnp:vVz:?"
00070 #define MG(v)  TSRMG(milter_globals_id, zend_milter_globals *, v)
00071 
00072 #define IS_NONE "%s(): This function must not be called outside of a milter callback function's scope"
00073 #define NOT_EOM "%s(): This function can only be used inside the milter_eom callback's scope"
00074 #define NOT_INIT "%s(): This function can only be used inside the milter_init callback's scope"
00075 
00076 #define MLFI_NONE           0
00077 #define MLFI_CONNECT 1
00078 #define MLFI_HELO           2
00079 #define MLFI_ENVFROM 3
00080 #define MLFI_ENVRCPT 4
00081 #define MLFI_HEADER         5
00082 #define MLFI_EOH            6
00083 #define MLFI_BODY           7
00084 #define MLFI_EOM            8
00085 #define MLFI_ABORT          9
00086 #define MLFI_CLOSE          10
00087 #define MLFI_INIT           11
00088 
00089 /* {{{ globals
00090  */
00091 extern char *ap_php_optarg;
00092 extern int ap_php_optind;
00093 
00094 static int flag_debug=0;
00095 static char *filename = NULL;
00096 
00097 /* per thread */
00098 ZEND_BEGIN_MODULE_GLOBALS(milter)
00099        SMFICTX *ctx;
00100        int state;
00101        int initialized;
00102 ZEND_END_MODULE_GLOBALS(milter)
00103 
00104 ZEND_DECLARE_MODULE_GLOBALS(milter)
00105 /* }}} */
00106 
00107 /* this method is called only once when the milter starts */
00108 /* {{{ Init Milter
00109 */
00110 static int mlfi_init()
00111 {
00112        int ret = 0;
00113        zend_file_handle file_handle;
00114        zval function_name, retval;
00115        int status;
00116        TSRMLS_FETCH();
00117 
00118        /* request startup */
00119        if (php_request_startup(TSRMLS_C)==FAILURE) {
00120               SG(headers_sent) = 1;
00121               SG(request_info).no_headers = 1;
00122               php_request_shutdown((void *) 0);
00123 
00124               return -1;
00125        }
00126        
00127        /* disable headers */
00128        SG(headers_sent) = 1;
00129        SG(request_info).no_headers = 1;
00130         
00131        if (filename == NULL) {
00132               php_printf("No input file specified");
00133               return SMFIS_TEMPFAIL;
00134        }
00135 
00136        if (!(file_handle.handle.fp = VCWD_FOPEN(filename, "rb"))) {
00137               php_printf("Could not open input file: %s\n", filename);
00138               return SMFIS_TEMPFAIL;
00139        }
00140 
00141        file_handle.type = ZEND_HANDLE_FP;
00142        file_handle.filename = filename;
00143        file_handle.free_filename = 0;
00144        file_handle.opened_path = NULL;
00145 
00146        php_execute_script(&file_handle TSRMLS_CC);
00147        
00148        /* call userland */
00149        INIT_ZVAL(function_name);
00150 
00151        ZVAL_STRING(&function_name, "milter_init", 0);
00152 
00153        /* set the milter context for possible use in API functions */
00154        MG(state) = MLFI_INIT;
00155 
00156        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
00157 
00158        MG(state) = MLFI_NONE;
00159        MG(initialized) = 1;
00160 
00161        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00162               ret = Z_LVAL(retval);
00163        }
00164        
00165        php_request_shutdown((void *) 0);
00166        
00167        return ret;
00168 }
00169 /* }}} */
00170 
00171 /* {{{ Milter callback functions
00172  */
00173 
00174 /* connection info filter, is called whenever sendmail connects to the milter */
00175 /* {{{ mlfi_connect()
00176 */
00177 static sfsistat      mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
00178 {
00179        zend_file_handle file_handle;
00180        zval function_name, retval, *param[1];
00181        int status;
00182        TSRMLS_FETCH();
00183 
00184        /* request startup */
00185        if (php_request_startup(TSRMLS_C)==FAILURE) {
00186               SG(headers_sent) = 1;
00187               SG(request_info).no_headers = 1;
00188               php_request_shutdown((void *) 0);
00189 
00190               return SMFIS_TEMPFAIL;
00191        }
00192        
00193        /* disable headers */
00194        SG(headers_sent) = 1;
00195        SG(request_info).no_headers = 1;
00196        
00197        if (filename == NULL) {
00198               php_printf("No input file specified");
00199               return SMFIS_TEMPFAIL;
00200        }
00201        
00202        if (!(file_handle.handle.fp = VCWD_FOPEN(filename, "rb"))) {
00203               php_printf("Could not open input file: %s\n", filename);
00204               return SMFIS_TEMPFAIL;
00205        }
00206 
00207        file_handle.type = ZEND_HANDLE_FP;
00208        file_handle.filename = filename;
00209        file_handle.free_filename = 0;
00210        file_handle.opened_path = NULL;
00211 
00212        php_execute_script(&file_handle TSRMLS_CC);
00213        
00214        /* call userland */
00215        INIT_ZVAL(function_name);
00216 
00217        ALLOC_ZVAL(param[0]);
00218        INIT_PZVAL(param[0]);
00219 
00220        ZVAL_STRING(&function_name, "milter_connect", 0);
00221        ZVAL_STRING(param[0], hostname, 1);
00222 
00223        /* set the milter context for possible use in API functions */
00224        MG(ctx) = ctx;
00225        MG(state) = MLFI_CONNECT;
00226 
00227        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
00228 
00229        MG(state) = MLFI_NONE;
00230        zval_ptr_dtor(param);
00231        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00232               return Z_LVAL(retval);
00233        }
00234        
00235        return SMFIS_CONTINUE;
00236 }
00237 /* }}} */
00238 
00239 /* SMTP HELO command filter */
00240 /* {{{ mlfi_helo()
00241 */
00242 static sfsistat mlfi_helo(SMFICTX *ctx, char *helohost)
00243 {
00244        zval function_name, retval, *param[1];
00245        int status;
00246        TSRMLS_FETCH();
00247 
00248        /* call userland */
00249        INIT_ZVAL(function_name);
00250        
00251        ALLOC_ZVAL(param[0]);
00252        INIT_PZVAL(param[0]);
00253 
00254        ZVAL_STRING(&function_name, "milter_helo", 0);
00255        ZVAL_STRING(param[0], helohost, 1);
00256 
00257        /* set the milter context for possible use in API functions */
00258        MG(ctx) = ctx;
00259        MG(state) = MLFI_HELO;
00260        
00261        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
00262 
00263        MG(state) = MLFI_NONE;
00264        zval_ptr_dtor(param);
00265        
00266        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00267               return Z_LVAL(retval);
00268        }
00269        
00270        return SMFIS_CONTINUE;
00271 }
00272 /* }}} */
00273 
00274 /* envelope sender filter */
00275 /* {{{ mlfi_envform()
00276 */
00277 static sfsistat mlfi_envfrom(SMFICTX *ctx, char **argv)
00278 {
00279        zval function_name, retval, *param[1];
00280        int status;
00281        TSRMLS_FETCH();
00282 
00283        /* call userland */
00284        INIT_ZVAL(function_name);
00285        
00286        ALLOC_ZVAL(param[0]);
00287        INIT_PZVAL(param[0]);
00288 
00289        ZVAL_STRING(&function_name, "milter_envfrom", 0);
00290        array_init(param[0]);
00291 
00292        while (*argv) {
00293               add_next_index_string(param[0], *argv, 1);
00294               argv++;
00295        }
00296 
00297        /* set the milter context for possible use in API functions */
00298        MG(ctx) = ctx;
00299        MG(state) = MLFI_ENVFROM;
00300        
00301        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
00302 
00303        MG(state) = MLFI_NONE;
00304        zval_ptr_dtor(param);
00305        
00306        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00307               return Z_LVAL(retval);
00308        }
00309 
00310        return SMFIS_CONTINUE;
00311 }
00312 /* }}} */
00313 
00314 /* envelope recipient filter */
00315 /* {{{ mlfi_envrcpt()
00316 */
00317 static sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv)
00318 {
00319        zval function_name, retval, *param[1];
00320        int status;
00321        TSRMLS_FETCH();
00322 
00323        /* call userland */
00324        INIT_ZVAL(function_name);
00325        
00326        ALLOC_ZVAL(param[0]);
00327        INIT_PZVAL(param[0]);
00328 
00329        ZVAL_STRING(&function_name, "milter_envrcpt", 0);
00330        array_init(param[0]);
00331 
00332        while (*argv) {
00333               add_next_index_string(param[0], *argv, 1);
00334               argv++;
00335        }
00336 
00337        /* set the milter context for possible use in API functions */
00338        MG(ctx) = ctx;
00339        MG(state) = MLFI_ENVRCPT;
00340        
00341        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
00342 
00343        MG(state) = MLFI_NONE;
00344        
00345        zval_ptr_dtor(param);
00346        
00347        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00348               return Z_LVAL(retval);
00349        }
00350 
00351        return SMFIS_CONTINUE;
00352 }
00353 /* }}} */
00354 
00355 /* header filter */
00356 /* {{{ mlfi_header()
00357 */
00358 static sfsistat mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
00359 {
00360        zval function_name, retval, *param[2];
00361        int status;
00362        TSRMLS_FETCH();
00363 
00364        /* call userland */
00365        INIT_ZVAL(function_name);
00366        
00367        ALLOC_ZVAL(param[0]);
00368        ALLOC_ZVAL(param[1]);
00369        INIT_PZVAL(param[0]);
00370        INIT_PZVAL(param[1]);
00371        
00372        ZVAL_STRING(&function_name, "milter_header", 0);
00373        ZVAL_STRING(param[0], headerf, 1);
00374        ZVAL_STRING(param[1], headerv, 1);
00375 
00376        /* set the milter context for possible use in API functions */
00377        MG(ctx) = ctx;
00378        MG(state) = MLFI_HEADER;
00379        
00380        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 2, param TSRMLS_CC);
00381 
00382        MG(state) = MLFI_NONE;
00383        
00384        zval_ptr_dtor(&param[0]);
00385        zval_ptr_dtor(&param[1]);   
00386        
00387        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00388               return Z_LVAL(retval);
00389        }
00390        
00391        return SMFIS_CONTINUE;
00392 }
00393 /* }}} */
00394 
00395 /* end of header */
00396 /* {{{ mlfi_eoh()
00397 */
00398 static sfsistat mlfi_eoh(SMFICTX *ctx)
00399 {
00400        zval function_name, retval;
00401        int status;
00402        TSRMLS_FETCH();
00403 
00404        /* call userland */
00405        INIT_ZVAL(function_name);
00406        ZVAL_STRING(&function_name, "milter_eoh", 0);
00407 
00408        /* set the milter context for possible use in API functions */
00409        MG(ctx) = ctx;
00410        MG(state) = MLFI_EOH;
00411        
00412        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
00413 
00414        MG(state) = MLFI_NONE;
00415        
00416        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00417               return Z_LVAL(retval);
00418        }
00419 
00420        return SMFIS_CONTINUE;
00421 }
00422 /* }}} */
00423 
00424 /* body block */
00425 /* {{{ mlfi_body()
00426 */
00427 static sfsistat mlfi_body(SMFICTX *ctx, u_char *bodyp, size_t len)
00428 {
00429        zval function_name, retval, *param[1];
00430        int status;
00431        TSRMLS_FETCH();
00432 
00433        /* call userland */
00434        INIT_ZVAL(function_name);
00435        
00436        ALLOC_ZVAL(param[0]);
00437        INIT_PZVAL(param[0]);
00438 
00439        ZVAL_STRING(&function_name, "milter_body", 0);
00440        ZVAL_STRINGL(param[0], (char*)bodyp, len, 1); /*alex*/
00441        
00442        /* set the milter context for possible use in API functions */
00443        MG(ctx) = ctx;
00444        MG(state) = MLFI_BODY;
00445        
00446        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 1, param TSRMLS_CC);
00447 
00448        MG(state) = MLFI_NONE;
00449        
00450        zval_ptr_dtor(param);       
00451 
00452        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00453               return Z_LVAL(retval);
00454        }
00455 
00456        return SMFIS_CONTINUE;
00457 }
00458 /* }}} */
00459 
00460 /* end of message */
00461 /* {{{ mlfi_eom()
00462 */
00463 static sfsistat mlfi_eom(SMFICTX *ctx)
00464 {
00465        zval function_name, retval;
00466        int status;
00467        TSRMLS_FETCH();
00468 
00469        /* call userland */
00470        INIT_ZVAL(function_name);
00471        ZVAL_STRING(&function_name, "milter_eom", 0);
00472        
00473        /* set the milter context for possible use in API functions */
00474        MG(ctx) = ctx;
00475        MG(state) = MLFI_EOM;
00476 
00477        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
00478 
00479        MG(state) = MLFI_NONE;
00480        
00481        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00482               return Z_LVAL(retval);
00483        }
00484 
00485        return SMFIS_CONTINUE;
00486 }
00487 /* }}} */
00488 
00489 /* message aborted */
00490 /* {{{ mlfi_abort()
00491 */
00492 static sfsistat mlfi_abort(SMFICTX *ctx)
00493 {
00494        zval function_name, retval;
00495        int status;
00496        TSRMLS_FETCH();
00497 
00498        /* call userland */
00499        INIT_ZVAL(function_name);
00500        ZVAL_STRING(&function_name, "milter_abort", 0);
00501        
00502        /* set the milter context for possible use in API functions */
00503        MG(ctx) = ctx;
00504        MG(state) = MLFI_ABORT;
00505        
00506        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
00507 
00508        MG(state) = MLFI_NONE;
00509        
00510        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00511               return Z_LVAL(retval);
00512        }
00513 
00514        return SMFIS_CONTINUE;
00515 }
00516 /* }}} */
00517 
00518 /* connection cleanup */
00519 /* {{{ mlfi_close()
00520 */
00521 static sfsistat mlfi_close(SMFICTX *ctx)
00522 {
00523        int ret = SMFIS_CONTINUE;
00524        zval function_name, retval;
00525        int status;
00526        TSRMLS_FETCH();
00527 
00528        /* call userland */
00529        INIT_ZVAL(function_name);
00530        ZVAL_STRING(&function_name, "milter_close", 0);
00531        
00532        /* set the milter context for possible use in API functions */
00533        MG(ctx) = ctx;
00534        MG(state) = MLFI_CLOSE;
00535        
00536        status = call_user_function(CG(function_table), NULL, &function_name, &retval, 0, NULL TSRMLS_CC);
00537 
00538        MG(state) = MLFI_NONE;
00539        
00540        if (status == SUCCESS && Z_TYPE(retval) == IS_LONG) {
00541               ret = Z_LVAL(retval);
00542        }
00543        
00544        php_request_shutdown((void *) 0);
00545 
00546        return ret;
00547 }
00548 /* }}} */
00549 /* }}} */
00550 
00551 /* {{{ Milter entry struct
00552  */
00553 struct smfiDesc smfilter = {
00554     "php-milter",    /* filter name */
00555     SMFI_VERSION,   /* version code -- leave untouched */
00556     0,                      /* flags */
00557     mlfi_connect,    /* info filter callback */
00558     mlfi_helo,              /* HELO filter callback */
00559     mlfi_envfrom,    /* envelope filter callback */
00560     mlfi_envrcpt,    /* envelope recipient filter callback */
00561     mlfi_header,     /* header filter callback */
00562     mlfi_eoh,        /* end of header callback */
00563     mlfi_body,              /* body filter callback */
00564     mlfi_eom,        /* end of message callback */
00565     mlfi_abort,             /* message aborted callback */
00566     mlfi_close,             /* connection cleanup callback */
00567 };
00568 /* }}} */
00569 
00570 /* {{{ PHP Milter API
00571  */
00572 
00573 /* {{{ proto void smfi_setflags(long flags)
00574    Sets the flags describing the actions the filter may take. */      
00575 PHP_FUNCTION(smfi_setflags)
00576 {
00577        long flags;
00578        
00579        /* valid only in the init callback */
00580        if (MG(state) != MLFI_INIT) {
00581               php_error(E_WARNING, NOT_INIT, get_active_function_name(TSRMLS_C));
00582        } else if (zend_parse_parameters(1 TSRMLS_CC, "l", &flags) == SUCCESS) {
00583               flags = flags & (SMFIF_ADDHDRS|SMFIF_CHGHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT);
00584               smfilter.xxfi_flags = flags;
00585        }      
00586 }
00587 /* }}} */
00588 
00589 /* {{{ proto void smfi_settimeout(long timeout)
00590    Sets the number of seconds libmilter will wait for an MTA connection before timing out a socket. */   
00591 PHP_FUNCTION(smfi_settimeout)
00592 {
00593        long timeout;
00594        
00595        /* valid only in the init callback */
00596        if (MG(state) != MLFI_INIT) {
00597               php_error(E_WARNING, NOT_INIT, get_active_function_name(TSRMLS_C));
00598        } else if (zend_parse_parameters(1 TSRMLS_CC, "l", &timeout) == SUCCESS) {
00599               smfi_settimeout(timeout);
00600        }      
00601 }
00602 /* }}} */
00603 
00604 /* {{{ proto string smfi_getsymval(string macro)
00605    Returns the value of the given macro or NULL if the macro is not defined. */     
00606 PHP_FUNCTION(smfi_getsymval)
00607 {
00608        char *symname, *ret;
00609        int len;
00610 
00611        /* valid in any callback */
00612        if (MG(state) == MLFI_NONE) {
00613               php_error(E_WARNING, IS_NONE, get_active_function_name(TSRMLS_C));
00614        } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &symname, &len) == SUCCESS) {
00615               if ((ret = smfi_getsymval(MG(ctx), symname)) != NULL) {
00616                      RETURN_STRING(ret, 1);
00617               }
00618        }
00619 
00620        RETURN_NULL();
00621 }
00622 /* }}} */
00623 
00624 /* {{{ proto bool smfi_setreply(string rcode, string xcode, string message)
00625    Directly set the SMTP error reply code for this connection.
00626    This code will be used on subsequent error replies resulting from actions taken by this filter. */    
00627 PHP_FUNCTION(smfi_setreply)
00628 {
00629        char *rcode, *xcode, *message;
00630        int len;
00631        
00632        /* valid in any callback */
00633        if (MG(state) == MLFI_NONE) {
00634               php_error(E_WARNING, IS_NONE, get_active_function_name(TSRMLS_C));
00635        } else if (zend_parse_parameters(3 TSRMLS_CC, "sss", &rcode, &len, &xcode, &len, &message, &len) == SUCCESS) {
00636               if (smfi_setreply(MG(ctx), rcode, xcode, message) == MI_SUCCESS) {
00637                      RETURN_TRUE;
00638               }
00639        }
00640        
00641        RETURN_FALSE;
00642 }
00643 /* }}} */
00644 
00645 /* {{{ proto bool smfi_addheader(string headerf, string headerv)
00646    Adds a header to the current message. */      
00647 PHP_FUNCTION(smfi_addheader)
00648 {
00649        char *f, *v;
00650        int len;
00651        
00652        /* valid only in milter_eom */
00653        if (MG(state) != MLFI_EOM) {
00654               php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
00655        } else if (zend_parse_parameters(2 TSRMLS_CC, "ss", &f, &len, &v, &len) == SUCCESS) {
00656               if (smfi_addheader(MG(ctx), f, v) == MI_SUCCESS) {
00657                      RETURN_TRUE;
00658               }
00659        }
00660        
00661        RETURN_FALSE;
00662 }
00663 /* }}} */
00664 
00665 /* {{{ proto bool smfi_chgheader(string headerf, string headerv)
00666    Changes a header's value for the current message. */ 
00667 PHP_FUNCTION(smfi_chgheader)
00668 {
00669        char *f, *v;
00670        long idx;
00671        int len;
00672        
00673        /* valid only in milter_eom */
00674        if (MG(state) != MLFI_EOM) {
00675               php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
00676        } else if (zend_parse_parameters(3 TSRMLS_CC, "sls", &f, &len, &idx, &v, &len) == SUCCESS) {
00677               if (smfi_chgheader(MG(ctx), f, idx, v) == MI_SUCCESS) {
00678                      RETURN_TRUE;
00679               }
00680        }
00681        
00682        RETURN_FALSE;
00683 }
00684 /* }}} */
00685 
00686 /* {{{ proto bool smfi_addrcpt(string rcpt)
00687    Add a recipient to the message envelope. */   
00688 PHP_FUNCTION(smfi_addrcpt)
00689 {
00690        char *rcpt;
00691        int len;
00692        
00693        /* valid only in milter_eom */
00694        if (MG(state) != MLFI_EOM) {
00695               php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
00696        } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &rcpt, &len) == SUCCESS) {
00697               if (smfi_addrcpt(MG(ctx), rcpt) == MI_SUCCESS) {
00698                      RETURN_TRUE;
00699               }
00700        }
00701        
00702        RETURN_FALSE;
00703 }
00704 /* }}} */
00705 
00706 /* {{{ proto bool smfi_delrcpt(string rcpt)
00707    Removes the named recipient from the current message's envelope. */       
00708 PHP_FUNCTION(smfi_delrcpt)
00709 {
00710        char *rcpt;
00711        int len;
00712        
00713        /* valid only in milter_eom */
00714        if (MG(state) != MLFI_EOM) {
00715               php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
00716        } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &rcpt, &len) == SUCCESS) {
00717               if (smfi_delrcpt(MG(ctx), rcpt) == MI_SUCCESS) {
00718                      RETURN_TRUE;
00719               }
00720        }
00721        
00722        RETURN_FALSE;
00723 }
00724 /* }}} */
00725 
00726 /* {{{ proto bool smfi_replacebody(string body)
00727    Replaces the body of the current message. If called more than once,
00728    subsequent calls result in data being appended to the new body. */ 
00729 PHP_FUNCTION(smfi_replacebody)
00730 {
00731        char *body;
00732        int len;
00733        
00734        /* valid only in milter_eom */
00735        if (MG(state) != MLFI_EOM) {
00736               php_error(E_WARNING, NOT_EOM, get_active_function_name(TSRMLS_C));
00737        } else if (zend_parse_parameters(1 TSRMLS_CC, "s", &body, &len) == SUCCESS) {
00738               if (smfi_replacebody(MG(ctx), (u_char*)body, len) == MI_SUCCESS) {
00739                      RETURN_TRUE;
00740               }
00741        }
00742        
00743        RETURN_FALSE;
00744 }
00745 /* }}} */
00746 
00747 /* {{{ PHP_MINIT_FUNCTION
00748  */
00749 PHP_MINIT_FUNCTION(milter)
00750 {
00751        REGISTER_LONG_CONSTANT("SMFIS_CONTINUE",  SMFIS_CONTINUE,      CONST_CS | CONST_PERSISTENT);
00752        REGISTER_LONG_CONSTANT("SMFIS_REJECT",           SMFIS_REJECT, CONST_CS | CONST_PERSISTENT);
00753        REGISTER_LONG_CONSTANT("SMFIS_DISCARD",          SMFIS_DISCARD,       CONST_CS | CONST_PERSISTENT);
00754        REGISTER_LONG_CONSTANT("SMFIS_ACCEPT",           SMFIS_ACCEPT, CONST_CS | CONST_PERSISTENT);
00755        REGISTER_LONG_CONSTANT("SMFIS_TEMPFAIL",  SMFIS_TEMPFAIL,      CONST_CS | CONST_PERSISTENT);
00756 
00757        REGISTER_LONG_CONSTANT("SMFIF_ADDHDRS",          SMFIF_ADDHDRS,       CONST_CS | CONST_PERSISTENT);
00758        REGISTER_LONG_CONSTANT("SMFIF_CHGHDRS",          SMFIF_CHGHDRS,       CONST_CS | CONST_PERSISTENT);
00759        REGISTER_LONG_CONSTANT("SMFIF_CHGBODY",          SMFIF_CHGBODY,       CONST_CS | CONST_PERSISTENT);
00760        REGISTER_LONG_CONSTANT("SMFIF_ADDRCPT",          SMFIF_ADDRCPT,       CONST_CS | CONST_PERSISTENT);
00761        REGISTER_LONG_CONSTANT("SMFIF_DELRCPT",          SMFIF_DELRCPT,       CONST_CS | CONST_PERSISTENT);
00762 
00763        ZEND_INIT_MODULE_GLOBALS(milter, NULL, NULL);
00764 
00765        MG(state) = MLFI_NONE;
00766        MG(initialized) = 0;
00767        return SUCCESS;
00768 }
00769 /* }}} */
00770 
00771 /* {{{ PHP_MINFO_FUNCTION
00772  */
00773 PHP_MINFO_FUNCTION(milter)
00774 {
00775        php_info_print_table_start();
00776        php_info_print_table_header(2, "Milter support", "enabled");
00777        php_info_print_table_end();
00778 }
00779 /* }}} */
00780 /* }}} */
00781 
00782 /* {{{ arginfo */
00783 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_setflags, 0, 0, 1)
00784        ZEND_ARG_INFO(0, flags)
00785 ZEND_END_ARG_INFO()
00786 
00787 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_settimeout, 0, 0, 1)
00788        ZEND_ARG_INFO(0, timeout)
00789 ZEND_END_ARG_INFO()
00790 
00791 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_getsymval, 0, 0, 1)
00792        ZEND_ARG_INFO(0, macro)
00793 ZEND_END_ARG_INFO()
00794 
00795 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_setreply, 0, 0, 3)
00796        ZEND_ARG_INFO(0, rcode)
00797        ZEND_ARG_INFO(0, xcode)
00798        ZEND_ARG_INFO(0, message)
00799 ZEND_END_ARG_INFO()
00800 
00801 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_addheader, 0, 0, 2)
00802        ZEND_ARG_INFO(0, headerf)
00803        ZEND_ARG_INFO(0, headerv)
00804 ZEND_END_ARG_INFO()
00805 
00806 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_chgheader, 0, 0, 2)
00807        ZEND_ARG_INFO(0, headerf)
00808        ZEND_ARG_INFO(0, headerv)
00809 ZEND_END_ARG_INFO()
00810 
00811 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_addrcpt, 0, 0, 1)
00812        ZEND_ARG_INFO(0, rcpt)
00813 ZEND_END_ARG_INFO()
00814 
00815 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_delrcpt, 0, 0, 1)
00816        ZEND_ARG_INFO(0, rcpt)
00817 ZEND_END_ARG_INFO()
00818 
00819 ZEND_BEGIN_ARG_INFO_EX(arginfo_smfi_replacebody, 0, 0, 1)
00820        ZEND_ARG_INFO(0, body)
00821 ZEND_END_ARG_INFO()
00822 /* }}} */
00823 
00824 /* {{{ milter_functions[]
00825 */
00826 const static zend_function_entry milter_functions[] = {
00827        PHP_FE(smfi_setflags,              arginfo_smfi_setflags)
00828        PHP_FE(smfi_settimeout,     arginfo_smfi_settimeout)
00829        PHP_FE(smfi_getsymval,             arginfo_smfi_getsymval)
00830        PHP_FE(smfi_setreply,              arginfo_smfi_setreply)
00831        PHP_FE(smfi_addheader,             arginfo_smfi_addheader)
00832        PHP_FE(smfi_chgheader,             arginfo_smfi_chgheader)
00833        PHP_FE(smfi_addrcpt,               arginfo_smfi_addrcpt)
00834        PHP_FE(smfi_delrcpt,               arginfo_smfi_delrcpt)
00835        PHP_FE(smfi_replacebody,    arginfo_smfi_replacebody)
00836        PHP_FE_END
00837 };
00838 /* }}} */
00839 
00840 /* {{{ Zend module entry
00841 */
00842 static zend_module_entry php_milter_module = {
00843        STANDARD_MODULE_HEADER,
00844        "Milter",
00845        milter_functions,
00846        PHP_MINIT(milter),
00847        NULL,
00848        NULL,
00849        NULL,
00850        PHP_MINFO(milter),
00851        "0.1.0",
00852        STANDARD_MODULE_PROPERTIES
00853 };
00854 /* }}} */
00855 
00856 /* {{{ Milter SAPI
00857 */
00858 static int sapi_milter_ub_write(const char *str, uint str_length TSRMLS_DC)
00859 {
00860        return str_length;
00861 }
00862 
00863 static void sapi_milter_flush(void *server_context)
00864 {
00865 }
00866 
00867 static void sapi_milter_register_variables(zval *track_vars_array TSRMLS_DC)
00868 {
00869        php_register_variable ("SERVER_SOFTWARE", "Sendmail Milter", track_vars_array TSRMLS_CC);
00870 }
00871 
00872 static int sapi_milter_post_read(char *buf, uint count_bytes TSRMLS_DC)
00873 {
00874        return 0;
00875 }
00876 
00877 static char* sapi_milter_read_cookies(TSRMLS_D)
00878 {
00879        return NULL;
00880 }
00881 
00882 static int sapi_milter_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00883 {
00884        return SAPI_HEADER_SENT_SUCCESSFULLY;
00885 }
00886 
00887 static int php_milter_startup(sapi_module_struct *sapi_module)
00888 {
00889        if (php_module_startup(sapi_module, &php_milter_module, 1) == FAILURE) {
00890               return FAILURE;
00891        }
00892        return SUCCESS;
00893 }
00894 /* }}} */
00895 
00896 /* {{{ sapi_module_struct milter_sapi_module
00897 */
00898 static sapi_module_struct milter_sapi_module = {
00899        "milter",                                        /* name */
00900        "Sendmail Milter SAPI",                   /* pretty name */
00901 
00902        php_milter_startup,                       /* startup */
00903        php_module_shutdown_wrapper,       /* shutdown */
00904 
00905        NULL,                                            /* activate */
00906        NULL,                                            /* deactivate */
00907 
00908        sapi_milter_ub_write,                     /* unbuffered write */
00909        sapi_milter_flush,                        /* flush */
00910        NULL,                                            /* get uid */
00911        NULL,                                            /* getenv */
00912 
00913        php_error,                                       /* error handler */
00914 
00915        NULL,                                            /* header handler */
00916        sapi_milter_send_headers,          /* send headers handler */
00917        NULL,                                            /* send header handler */
00918 
00919        sapi_milter_post_read,                    /* read POST data */
00920        sapi_milter_read_cookies,          /* read Cookies */
00921 
00922        sapi_milter_register_variables,    /* register server variables */
00923        NULL,                                            /* Log message */
00924        NULL,                                            /* Get request time */
00925        NULL,                                            /* Child terminate */
00926 
00927        NULL,                                            /* Block interruptions */
00928        NULL,                                            /* Unblock interruptions */
00929 
00930        STANDARD_SAPI_MODULE_PROPERTIES
00931 };
00932 /* }}} */
00933 
00934 /****
00935 * ripped from cli, has to be cleaned up !
00936 */
00937 
00938 /* {{{ php_milter_usage
00939 */
00940 static void php_milter_usage(char *argv0)
00941 {
00942        char *prog;
00943 
00944        prog = strrchr(argv0, '/');
00945        if (prog) {
00946               prog++;
00947        } else {
00948               prog = "php-milter";
00949        }
00950 
00951        printf(     "Usage: %s [options] [-f] <file> [args...]\n"
00952                    "       %s [options] [-- args...]\n"
00953                             "  -a               Run interactively\n"
00954                             "  -c <path>|<file> Look for php.ini file in this directory\n"
00955                             "  -n               No php.ini file will be used\n"
00956                             "  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
00957                             "  -D               run as daemon\n"
00958                             "  -e               Generate extended information for debugger/profiler\n"
00959                             "  -f <file>        Parse <file>.\n"
00960                             "  -h               This help\n"
00961                             "  -p <socket>      path to create socket\n"
00962                             "  -v               Version number\n"
00963                             "  -V <n>           set debug level to n (1 or 2).\n"
00964                             "  -z <file>        Load Zend extension <file>.\n"
00965                             "  args...          Arguments passed to script. Use -- args when first argument \n"
00966                             "                   starts with - or script is read from stdin\n"
00967                             , prog, prog);
00968 }
00969 /* }}} */
00970 
00971 static void define_command_line_ini_entry(char *arg) /* {{{ */
00972 {
00973        char *name, *value;
00974 
00975        name = arg;
00976        value = strchr(arg, '=');
00977        if (value) {
00978               *value = 0;
00979               value++;
00980        } else {
00981               value = "1";
00982        }
00983        zend_alter_ini_entry(name, strlen(name)+1, value, strlen(value), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
00984 }
00985 /* }}} */
00986 
00987 /* {{{ main
00988 */
00989 int main(int argc, char *argv[])
00990 {
00991     char *sock = NULL;
00992        int dofork = 0;
00993 
00994        int exit_status = SUCCESS;
00995        int c;
00996 /* temporary locals */
00997        int orig_optind=ap_php_optind;
00998        char *orig_optarg=ap_php_optarg;
00999        int interactive=0;
01000        char *param_error=NULL;
01001 /* end of temporary locals */
01002 
01003        void ***tsrm_ls;
01004 
01005 #ifdef HAVE_SIGNAL_H
01006 #if defined(SIGPIPE) && defined(SIG_IGN)
01007        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
01008                                                         that sockets created via fsockopen()
01009                                                         don't kill PHP if the remote site
01010                                                         closes it.  in apache|apxs mode apache
01011                                                         does that for us!  thies@thieso.net
01012                                                         20000419 */
01013 #endif
01014 #endif
01015 
01016 
01017        tsrm_startup(1, 1, 0, NULL);
01018        sapi_startup(&milter_sapi_module);
01019        
01020        while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) {
01021               switch (c) {
01022               case 'c':
01023                      milter_sapi_module.php_ini_path_override = strdup(ap_php_optarg);
01024                      break;
01025               case 'n':
01026                      milter_sapi_module.php_ini_ignore = 1;
01027                      break;
01028               }
01029        }
01030        ap_php_optind = orig_optind;
01031        ap_php_optarg = orig_optarg;
01032 
01033        milter_sapi_module.executable_location = argv[0];
01034 
01035        tsrm_ls = ts_resource(0);
01036 
01037        sapi_module.startup(&milter_sapi_module);
01038 
01039        zend_first_try {
01040               while ((c=ap_php_getopt(argc, argv, OPTSTRING))!=-1) {
01041                      switch (c) {
01042                      case '?':
01043                             php_output_startup();
01044                             php_output_activate(TSRMLS_C);
01045                             SG(headers_sent) = 1;
01046                             php_milter_usage(argv[0]);
01047                             php_end_ob_buffers(1 TSRMLS_CC);
01048                             exit(1);
01049                             break;
01050                      }
01051               }
01052               ap_php_optind = orig_optind;
01053               ap_php_optarg = orig_optarg;
01054 
01055         /* Set some CLI defaults */
01056               SG(options) |= SAPI_OPTION_NO_CHDIR;
01057               zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
01058               zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
01059 
01060               zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
01061 
01062               while ((c = ap_php_getopt(argc, argv, OPTSTRING)) != -1) {
01063                      switch (c) {
01064 
01065                      case 'a':     /* interactive mode */
01066                             printf("Interactive mode enabled\n\n");
01067                             interactive=1;
01068                             break;
01069 
01070                      case 'C': /* don't chdir to the script directory */
01071                             /* This is default so NOP */
01072                             break;
01073                      case 'd': /* define ini entries on command line */
01074                             define_command_line_ini_entry(ap_php_optarg);
01075                             break;
01076 
01077                      case 'D': /* daemon */
01078                             dofork = 1;
01079                             break;
01080 
01081                      case 'e': /* enable extended info output */
01082                             CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
01083                             break;
01084 
01085                      case 'f': /* parse file */
01086                             filename = ap_php_optarg;
01087                             break;
01088 
01089                      case 'h': /* help & quit */
01090                      case '?':
01091                             php_output_startup();
01092                             php_output_activate(TSRMLS_C);
01093                             SG(headers_sent) = 1;
01094                             php_milter_usage(argv[0]);
01095                             php_end_ob_buffers(1 TSRMLS_CC);
01096                             exit(1);
01097                             break;
01098 
01099                      case 'p': /* socket */
01100                             sock = strdup(ap_php_optarg);
01101                             break;
01102 
01103                      case 'v': /* show php version & quit */
01104                             if (php_request_startup(TSRMLS_C)==FAILURE) {
01105                                    zend_ini_deactivate(TSRMLS_C);
01106                                    php_module_shutdown(TSRMLS_C);
01107                                    sapi_shutdown();
01108                                    tsrm_shutdown();
01109 
01110                                    exit(1);
01111                             }
01112                             SG(headers_sent) = 1;
01113                             SG(request_info).no_headers = 1;
01114                             php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
01115                             php_end_ob_buffers(1 TSRMLS_CC);
01116                             exit(1);
01117                             break;
01118 
01119                      case 'V': /* verbose */
01120                             flag_debug = atoi(ap_php_optarg);
01121                             break;
01122 
01123                      case 'z': /* load extension file */
01124                             zend_load_extension(ap_php_optarg);
01125                             break;
01126 
01127                      default:
01128                             break;
01129                      }
01130               }
01131 
01132               if (param_error) {
01133                      SG(headers_sent) = 1;
01134                      SG(request_info).no_headers = 1;
01135                      PUTS(param_error);
01136                      exit(1);
01137               }
01138 
01139               CG(interactive) = interactive;
01140 
01141               /* only set script_file if not set already and not in direct mode and not at end of parameter list */
01142               if (argc > ap_php_optind && !filename) {
01143                      filename=argv[ap_php_optind];
01144                      ap_php_optind++;
01145               }
01146 
01147               /* check if file exists, exit else */
01148               
01149               if (dofork) {
01150                      switch(fork()) {
01151                             case -1: /* Uh-oh, we have a problem forking. */
01152                                    fprintf(stderr, "Uh-oh, couldn't fork!\n");
01153                                    exit(errno);
01154                                    break;
01155                             case 0: /* Child */
01156                                    break;
01157                             default: /* Parent */
01158                                    exit(0);
01159                      }
01160               }
01161                      
01162               if (sock) {
01163                      struct stat junk;
01164                      if (stat(sock,&junk) == 0) unlink(sock);
01165               }
01166 
01167               openlog("php-milter", LOG_PID, LOG_MAIL);
01168               
01169               if ((exit_status = mlfi_init())) {
01170                      syslog(1, "mlfi_init failed.");
01171                      closelog();
01172                      goto err;
01173               }
01174 
01175               smfi_setconn(sock);
01176               if (smfi_register(smfilter) == MI_FAILURE) {
01177                      syslog(1, "smfi_register failed.");
01178                      fprintf(stderr, "smfi_register failed\n");
01179                      closelog();
01180                      goto err;
01181               } else {
01182                      exit_status = smfi_main();
01183               }                    
01184 
01185               closelog();
01186 
01187               if (milter_sapi_module.php_ini_path_override) {
01188                      free(milter_sapi_module.php_ini_path_override);
01189               }
01190 
01191        } zend_catch {
01192               exit_status = EG(exit_status);
01193        } zend_end_try();
01194 
01195 err:
01196        php_module_shutdown(TSRMLS_C);
01197        sapi_shutdown();
01198        tsrm_shutdown();
01199 
01200        exit(exit_status);
01201 }
01202 /* }}} */
01203 
01204 /*
01205  * Local variables:
01206  * tab-width: 4
01207  * c-basic-offset: 4
01208  * End:
01209  * vim600: sw=4 ts=4 fdm=marker
01210  * vim<600: sw=4 ts=4
01211  */