Add the Cyrus IMAP extension to PHP's CVS (Manual editing of the news file to occur).

This commit is contained in:
Sterling Hughes 2001-08-05 17:43:03 +00:00
parent c4ca84d3a1
commit 294e19cd5c
5 changed files with 630 additions and 0 deletions

2
ext/cyrus/CREDITS Normal file
View File

@ -0,0 +1,2 @@
Cyrus
Sterling Hughes

8
ext/cyrus/Makefile.in Normal file
View File

@ -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

45
ext/cyrus/config.m4 Normal file
View File

@ -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

497
ext/cyrus/cyrus.c Normal file
View File

@ -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 <sterling@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_cyrus.h"
#if HAVE_CYRUS
#include <cyrus/imclient.h>
#include <pwd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
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:
*/

78
ext/cyrus/php_cyrus.h Normal file
View File

@ -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 <sterling@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_CYRUS_H
#define PHP_CYRUS_H
#include "php.h"
#if HAVE_CYRUS
#include <cyrus/imclient.h>
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:
*/