From: Sterling Hughes Date: Sun, 5 Aug 2001 17:43:03 +0000 (+0000) Subject: Add the Cyrus IMAP extension to PHP's CVS (Manual editing of the news file to occur). X-Git-Tag: PRE_ENGINE2_SPLIT~31 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=294e19cd5c37ba8e62adddff90e6b7de845e887a;p=php Add the Cyrus IMAP extension to PHP's CVS (Manual editing of the news file to occur). --- diff --git a/ext/cyrus/CREDITS b/ext/cyrus/CREDITS new file mode 100644 index 0000000000..74371fa716 --- /dev/null +++ b/ext/cyrus/CREDITS @@ -0,0 +1,2 @@ +Cyrus +Sterling Hughes diff --git a/ext/cyrus/Makefile.in b/ext/cyrus/Makefile.in new file mode 100644 index 0000000000..8d09befebb --- /dev/null +++ b/ext/cyrus/Makefile.in @@ -0,0 +1,8 @@ +# $Id$ + +LTLIBRARY_NAME = libcyrus.la +LTLIBRARY_SOURCES = cyrus.c +LTLIBRARY_SHARED_NAME = cyrus.la +LTLIBRARY_SHARED_LIBADD = $(CYRUS_SHARED_LIBADD) + +include $(top_srcdir)/build/dynlib.mk diff --git a/ext/cyrus/config.m4 b/ext/cyrus/config.m4 new file mode 100644 index 0000000000..3da4b01cf7 --- /dev/null +++ b/ext/cyrus/config.m4 @@ -0,0 +1,45 @@ +dnl config.m4 for extension cyrus + +PHP_ARG_WITH(cyrus, for cyrus imap support, +[ --with-cyrus Include cyrus imap support]) + +if test "$PHP_CYRUS" != "no"; then + found_cyrus=no + found_sasl=no + found_openssl=no + for i in /usr /usr/local $PHP_CYRUS; do + if test -r $i/include/cyrus/imclient.h && test "$found_cyrus" = "no"; then + PHP_ADD_INCLUDE($i/include) + PHP_SUBST(CYRUS_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH(cyrus, $i/lib, CYRUS_SHARED_LIBADD) + found_cyrus=yes + fi + if test -r $i/include/sasl.h && test "$found_sasl" = "no"; then + PHP_ADD_INCLUDE($i/include) + PHP_SUBST(SASL_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH(sasl, $i/lib, SASL_SHARED_LIBADD) + found_sasl=yes + fi + if test -r $i/include/openssl/ssl.h && test "$found_openssl" = "no" && test "$PHP_OPENSSL" = "no"; then + PHP_SUBST(OPENSSL_SHARED_LIBADD) + PHP_SUBST(CRYPTO_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH(ssl, $i/lib, OPENSSL_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH(crypto, $i/lib, CRYPTO_SHARED_LIBADD) + found_openssl=yes + fi + done + + if test "$found_cyrus" = "no"; then + AC_MSG_RESULT(not found) + AC_MSG_ERROR(Please Re-install the cyrus distribution) + fi + + if test "$found_sasl" = "no"; then + AC_MSG_RESULT(sasl not found) + AC_MSG_ERROR(Please Re-install the cyrus distribution) + fi + + AC_DEFINE(HAVE_CYRUS,1,[ ]) + + PHP_EXTENSION(cyrus, $ext_shared) +fi diff --git a/ext/cyrus/cyrus.c b/ext/cyrus/cyrus.c new file mode 100644 index 0000000000..b06fe9fa86 --- /dev/null +++ b/ext/cyrus/cyrus.c @@ -0,0 +1,497 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2001 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Sterling Hughes | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_cyrus.h" + +#if HAVE_CYRUS + +#include + +#include +#include +#include +#include + +static int le_cyrus; +#define le_cyrus_name "Cyrus IMAP connection" + +function_entry cyrus_functions[] = { + PHP_FE(cyrus_connect, NULL) + PHP_FE(cyrus_authenticate, NULL) + PHP_FE(cyrus_bind, NULL) + PHP_FE(cyrus_unbind, NULL) + PHP_FE(cyrus_query, NULL) + PHP_FE(cyrus_close, NULL) + {NULL, NULL, NULL} +}; + +zend_module_entry cyrus_module_entry = { + "cyrus", + cyrus_functions, + PHP_MINIT(cyrus), + NULL, + NULL, + NULL, + PHP_MINFO(cyrus), + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_CYRUS +ZEND_GET_MODULE(cyrus) +#endif + +static void cyrus_free(zend_rsrc_list_entry *rsrc) +{ + php_cyrus *conn = (php_cyrus *) rsrc->ptr; + + if (conn->client) + imclient_close(conn->client); + + if (conn->host) + efree(conn->host); + + if (conn->port) + efree(conn->port); + + efree(conn); +} + +PHP_MINIT_FUNCTION(cyrus) +{ + le_cyrus = zend_register_list_destructors_ex(cyrus_free, NULL, + le_cyrus_name, module_number); + + REGISTER_LONG_CONSTANT("CYRUS_CONN_NOSYNCLITERAL", + IMCLIENT_CONN_NOSYNCLITERAL, + CONST_CS_ | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CYRUS_CONN_INITIALRESPONSE", + IMCLIENT_CONN_INITIALRESPONSE, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CYRUS_CALLBACK_NUMBERED", CALLBACK_NUMBERED, + CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CYRUS_CALLBACK_NOLITERAL", CALLBACK_NOLITERAL, + CONST_CS | CONST_PERSISTENT); + + return SUCCESS; +} + +PHP_MINFO_FUNCTION(cyrus) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "Cyrus IMAP support", "enabled"); + php_info_print_table_end(); +} + +extern void fatal(char *s, int exit) +{ + php_error(E_ERROR, s); +} + +PHP_FUNCTION(cyrus_connect) +{ + zval **z_host; + zval **z_port; + zval **z_flags; + php_cyrus *conn; + struct imclient *client; + char *host; + char *port = NULL; + int flags = 0; + int error; + int argc = ZEND_NUM_ARGS(); + + if (argc < 0 || argc > 3 || + zend_get_parameters_ex(argc, &z_host, &z_port, &z_flags) == FAILURE) { + WRONG_PARAM_COUNT; + } + + if (argc > 0) { + convert_to_string_ex(z_host); + host = estrndup(Z_STRVAL_PP(z_host), Z_STRLEN_PP(z_host)); + } + else { + host = estrndup("localhost", sizeof("localhost") - 1); + } + + if (argc > 1) { + convert_to_string_ex(z_port); + port = estrndup(Z_STRVAL_PP(z_port), Z_STRLEN_PP(z_port)); + } + + if (argc > 2) { + convert_to_long_ex(z_flags); + flags = Z_LVAL_PP(z_flags); + } + + error = imclient_connect(&client, host, port, NULL); + switch (error) { + case 0: + if (client) { + conn = ecalloc(1, sizeof *conn); + conn->client = client; + conn->host = host; + conn->port = port; + + if (flags) { + imclient_setflags(conn->client, flags); + conn->flags = flags; + } + } + + break; + + case -1: + php_error(E_WARNING, "Invalid hostname: %s", host); + RETURN_FALSE; + + case -2: + php_error(E_WARNING, "Invalid port: %d", port); + RETURN_FALSE; + } + + ZEND_REGISTER_RESOURCE(return_value, conn, le_cyrus); + conn->id = Z_LVAL_P(return_value); +} + +static void cyrus_capable_callback(struct imclient *client, void *rock, + struct imclient_reply *reply) +{ + char *token = NULL; + char *token_buf; + char *mechanism = rock; + + + /* We need to split the reply up by the whitespace */ + token = php_strtok_r(reply->text, " ", &token_buf); + while (token != NULL) { + if (! strncmp(token, "AUTH=", 5)) { + memcpy(mechanism, token + 5, strlen(token) - 5); + break; + } + + token = php_strtok_r(NULL, " ", &token_buf); + } +} + +PHP_FUNCTION(cyrus_authenticate) +{ + zval **z_conn; + zval **z_mechlist; + zval **z_service; + zval **z_user; + zval **z_minssf; + zval **z_maxssf; + php_cyrus *conn; + char *mechlist; + char *service; + char *user; + int minssf; + int maxssf; + int argc = ZEND_NUM_ARGS(); + + if (argc < 1 || argc > 6 || + zend_get_parameters_ex(argc, &z_conn, &z_mechlist, &z_service, &z_user, &z_minssf, &z_maxssf) == FAILURE) { + WRONG_PARAM_COUNT; + } + ZEND_FETCH_RESOURCE(conn, php_cyrus *, z_conn, -1, le_cyrus_name, le_cyrus); + + /* Determine support mechanisms */ + if (argc > 1 && Z_TYPE_PP(z_mechlist) != IS_NULL) { + convert_to_string_ex(z_mechlist); + + mechlist = estrndup(Z_STRVAL_PP(z_mechlist), Z_STRLEN_PP(z_mechlist)); + } + else { + char tmp_mechlist[100]; + int pos = 0; + + /* NULL out the buffer, ensures it has a safe ending and allows us to + * test properly for the end of the buffer + */ + memset(tmp_mechlist, 0, sizeof tmp_mechlist); + + /* We'll be calling the "CAPABILITY" command, which will give us a list + * of the types of authorization the server is capable of + */ + imclient_addcallback(conn->client, "CAPABILITY", 0, + cyrus_capable_callback, (void *) tmp_mechlist, 0); + imclient_send(conn->client, NULL, NULL, "CAPABILITY"); + + /* Grab the end of string position into pos */ + while (tmp_mechlist[pos++] != 0) + ; + + /* Tack on PLAIN to whatever the auth string is */ + memcpy(tmp_mechlist + pos, " PLAIN", 6); + + /* Copy it onto the main buffer */ + mechlist = estrndup(tmp_mechlist, pos + 6); + } + + /* Determine the service type */ + if (argc > 2 && Z_TYPE_PP(z_service) != IS_NULL) { + convert_to_string_ex(z_service); + service = estrndup(Z_STRVAL_PP(z_service), Z_STRLEN_PP(z_service)); + } + else { + service = estrndup("imap", 4); + } + + /* Determine the user */ + if (argc > 3 && Z_TYPE_PP(z_user) != IS_NULL) { + convert_to_string_ex(z_user); + user = estrndup(Z_STRVAL_PP(z_user), Z_STRLEN_PP(z_user)); + } + else { + /* XXX: UGLY, but works, determines the username to use */ + user = sapi_getenv("USER", 4); + if (! user) { + user = getenv("USER"); + if (! user) { + user = sapi_getenv("LOGNAME", 7); + if (! user) { + user = getenv("LOGNAME"); + if (! user) { + struct passwd *pwd = getpwuid(getuid()); + if (! pwd) { + php_error(E_WARNING, "Couldn't determine user id"); + RETURN_FALSE; + } + + user = estrdup(pwd->pw_name); + } + } + } + } + } + + /* Determine the minssf */ + if (argc > 4 && Z_TYPE_PP(z_minssf) != NULL) { + convert_to_long_ex(z_minssf); + minssf = Z_LVAL_PP(z_minssf); + } + else { + minssf = 0; + } + + /* Determine the maxssf */ + if (argc > 5 && Z_TYPE_PP(z_maxssf) != NULL) { + convert_to_long_ex(z_maxssf); + maxssf = Z_LVAL_PP(z_maxssf); + } + else { + maxssf = 1000; + } + + imclient_authenticate(conn->client, mechlist, service, + user, minssf, maxssf); + + efree(mechlist); + efree(service); + efree(user); +} + +static void cyrus_generic_callback(struct imclient *client, + void *rock, + struct imclient_reply *reply) +{ + php_cyrus_callback *callback = rock; + + if (client) { + zval **argv[4]; + zval *retval; + zval *cyrus; + zval *keyword; + zval *text; + zval *msgno; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(cyrus); + MAKE_STD_ZVAL(keyword); + MAKE_STD_ZVAL(text); + MAKE_STD_ZVAL(msgno); + + ZVAL_RESOURCE(cyrus, callback->le); + zend_list_addref(callback->le); + + ZVAL_STRING(keyword, reply->keyword, 1); + ZVAL_STRING(text, reply->text, 1); + ZVAL_LONG(msgno, reply->msgno); + + argv[0] = &cyrus; + argv[1] = &keyword; + argv[2] = &text; + argv[3] = &msgno; + + if (call_user_function_ex(EG(function_table), NULL, callback->function, + &retval, 4, argv, 0, NULL) == FAILURE) { + php_error(E_WARNING, "Couldn't call the %s handler", + callback->trigger); + } + + zval_ptr_dtor(argv[0]); + zval_ptr_dtor(argv[1]); + zval_ptr_dtor(argv[2]); + zval_ptr_dtor(argv[3]); + + efree(argv); + } + else { + return; + } +} + + + +PHP_FUNCTION(cyrus_bind) +{ + zval **z_conn; + zval **z_callback; + zval **tmp; + HashTable *hash; + php_cyrus *conn; + php_cyrus_callback callback; + char *string_key; + ulong num_key; + + if (ZEND_NUM_ARGS() != 3 || + zend_get_parameters_ex(3, &z_conn, &z_callback) == FAILURE) { + WRONG_PARAM_COUNT; + } + + ZEND_FETCH_RESOURCE(conn, php_cyrus *, z_conn, -1, le_cyrus_name, le_cyrus); + + hash = HASH_OF(*z_callback); + if (! hash) { + php_error(E_WARNING, + "Second argument to cyrus_bind() must be an array or object"); + RETURN_FALSE; + } + + for (zend_hash_internal_pointer_reset(hash); + zend_hash_get_current_data(hash, (void **) &tmp) == SUCCESS; + zend_hash_move_forward(hash)) { + SEPARATE_ZVAL(tmp); + zend_hash_get_current_key(hash, &string_key, &num_key, 0); + if (! string_key) + continue; + + if (! strcasecmp(string_key, "trigger")) { + convert_to_string_ex(tmp); + callback.trigger = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } + else if (! strcasecmp(string_key, "function")) { + callback.function = *tmp; + zval_add_ref(&callback.function); + } + else if (! strcasecmp(string_key, "flags")) { + convert_to_long_ex(tmp); + callback.flags |= Z_LVAL_PP(tmp); + } + } + + if (! callback.trigger) { + php_error(E_WARNING, "You must specify a trigger in your callback"); + RETURN_FALSE; + } + + if (! callback.function) { + php_error(E_WARNING, "You must specify a function in your callback"); + RETURN_FALSE; + } + + callback.le = conn->id; + + imclient_addcallback(conn->client, callback.trigger, callback.flags, + cyrus_generic_callback, (void **) &callback, 0); + + RETURN_TRUE; +} + +PHP_FUNCTION(cyrus_unbind) +{ + zval **z_conn; + zval **trigger_name; + php_cyrus *conn; + + if (ZEND_NUM_ARGS() != 2 || + zend_get_parameters_ex(2, &z_conn, &trigger_name) == FAILURE) { + WRONG_PARAM_COUNT; + } + ZEND_FETCH_RESOURCE(conn, php_cyrus *, z_conn, -1, le_cyrus_name, le_cyrus); + convert_to_string_ex(trigger_name); + + imclient_addcallback(conn->client, Z_STRVAL_PP(trigger_name), 0, + NULL, NULL, 0); + + RETURN_TRUE; +} + +PHP_FUNCTION(cyrus_query) +{ + zval **z_conn; + zval **query; + php_cyrus *conn; + + if (ZEND_NUM_ARGS() != 2 || + zend_get_parameters_ex(2, &z_conn, &query) == FAILURE) { + WRONG_PARAM_COUNT; + } + ZEND_FETCH_RESOURCE(conn, php_cyrus *, z_conn, -1, le_cyrus_name, le_cyrus); + convert_to_string_ex(query); + + if (imclient_send(conn->client, NULL, NULL, Z_STRVAL_PP(query)) != 0) + RETURN_FALSE; + + RETURN_TRUE; +} + + +PHP_FUNCTION(cyrus_close) +{ + zval **z_conn; + php_cyrus *conn; + + if (ZEND_NUM_ARGS() != 1 || + zend_get_parameters_ex(1, &z_conn) == FAILURE) { + WRONG_PARAM_COUNT; + } + ZEND_FETCH_RESOURCE(conn, php_cyrus *, z_conn, -1, le_cyrus_name, le_cyrus); + + zend_list_delete(Z_LVAL_PP(z_conn)); + + RETURN_TRUE; +} + +#endif + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/ext/cyrus/php_cyrus.h b/ext/cyrus/php_cyrus.h new file mode 100644 index 0000000000..ca153d2720 --- /dev/null +++ b/ext/cyrus/php_cyrus.h @@ -0,0 +1,78 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2001 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Sterling Hughes | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef PHP_CYRUS_H +#define PHP_CYRUS_H + +#include "php.h" + +#if HAVE_CYRUS + +#include + +extern zend_module_entry cyrus_module_entry; +#define phpext_cyrus_ptr &cyrus_module_entry + +#ifdef PHP_WIN32 +#define PHP_CYRUS_API __declspec(dllexport) +#else +#define PHP_CYRUS_API +#endif + +PHP_MINIT_FUNCTION(cyrus); +PHP_MINFO_FUNCTION(cyrus); + +PHP_FUNCTION(cyrus_connect); +PHP_FUNCTION(cyrus_authenticate); +PHP_FUNCTION(cyrus_bind); +PHP_FUNCTION(cyrus_unbind); +PHP_FUNCTION(cyrus_query); +PHP_FUNCTION(cyrus_close); + +typedef struct { + struct imclient *client; + char *host; + char *port; + int flags; + int id; +} +php_cyrus; + +typedef struct { + zval *function; + char *trigger; + long le; + int flags; +} +php_cyrus_callback; + +#endif + + +#endif + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */