Fwd: [PECL-CVS] cvs: pecl /cvsclient config.m4 cvsclient.c package.xml php_cvsclient.h

Jan Schneider <[email protected]>
Newsgroups gmane.comp.horde.chora
Message-ID <[email protected]>
This might become an interesting extension.

----- Weitergeleitete Nachricht von [email protected] -----
    Datum: Sun, 30 Nov 2003 01:53:38 -0000
    Von: Sara Golemon <[email protected]>
Antwort an: Sara Golemon <[email protected]>
 Betreff: [PECL-CVS] cvs: pecl /cvsclient config.m4 cvsclient.c package.xml
php_cvsclient.h
      An: [email protected]

pollita		Sat Nov 29 20:53:38 2003 EDT

  Added files:
    /pecl/cvsclient	config.m4 cvsclient.c package.xml php_cvsclient.h
  Log:
  Initial Release



----- Ende der weitergeleiteten Nachricht -----


Jan.

--
http://www.horde.org - The Horde Project
http://www.ammma.de - discover your knowledge
http://www.tip4all.de - Deine private Tippgemeinschaft

-- 
PECL CVS Mailing List 
To unsubscribe, visit: http://www.php.net/unsub.php


-- 
Chora mailing list
Frequently Asked Questions: http://horde.org/faq/
To unsubscribe, mail: [email protected]
pollita-20031129205338.txt (text/plain, 15 KB)
Index: pecl/cvsclient/config.m4
+++ pecl/cvsclient/config.m4
PHP_ARG_ENABLE(cvsclient, whether to enable the CVS client stream wrapper,
[  --enable-cvsclient      Enable PHP cvs:// wrapper.])

if test "$PHP_CVSCLIENT" != "no"; then
  AC_DEFINE(WITH_CVSCLIENT, 1, [Whether you want the CVS client])
  PHP_NEW_EXTENSION(cvsclient, cvsclient.c,
	$ext_shared,,)
fi

Index: pecl/cvsclient/cvsclient.c
+++ pecl/cvsclient/cvsclient.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2002 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          |
   | [email protected] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Sara Golemon <[email protected]>                               |
   +----------------------------------------------------------------------+
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"

#if WITH_CVSCLIENT

#include "php_cvsclient.h"
#include "php_globals.h"
#include "php_network.h"
#include "ext/standard/url.h"
#include "ext/standard/info.h"
#include <sys/socket.h>
#include <ctype.h>

#define PHP_CVSCLIENT_REQ_ARGUMENT		0x00000001
#define PHP_CVSCLIENT_REQ_ARGUMENTX		0x00000002
#define PHP_CVSCLIENT_REQ_DIRECTORY		0x00000004
#define PHP_CVSCLIENT_REQ_ROOT			0x00000008
#define PHP_CVSCLIENT_REQ_REPOSITORY	0x00000010
#define PHP_CVSCLIENT_REQ_UPDATE		0x00000020
#define PHP_CVSCLIENT_REQ_CI			0x00000040
#define PHP_CVSCLIENT_REQ_CO			0x00000080
#define PHP_CVSCLIENT_REQ_DIFF			0x00000100
#define PHP_CVSCLIENT_REQ_LOG			0x00000200
#define PHP_CVSCLIENT_REQ_ADD			0x00000400
#define PHP_CVSCLIENT_REQ_REMOVE		0x00000800
#define PHP_CVSCLIENT_REQ_HISTORY		0x00001000

typedef struct _php_cvsclient_requests {
	long request;
	char *label;
} php_cvsclient_requests;

static php_cvsclient_requests cvsclient_requests[] = {
	{ PHP_CVSCLIENT_REQ_ARGUMENT,		"argument"		},
	{ PHP_CVSCLIENT_REQ_ARGUMENTX,		"argumentx"		},
	{ PHP_CVSCLIENT_REQ_DIRECTORY,		"directory"		},
	{ PHP_CVSCLIENT_REQ_ROOT,			"root"			},
	{ PHP_CVSCLIENT_REQ_REPOSITORY,		"repository"	},
	{ PHP_CVSCLIENT_REQ_UPDATE,			"update"		},
	{ PHP_CVSCLIENT_REQ_CI,				"ci"			},
	{ PHP_CVSCLIENT_REQ_CO,				"co"			},
	{ PHP_CVSCLIENT_REQ_DIFF,			"diff"			},
	{ PHP_CVSCLIENT_REQ_LOG,			"log"			},
	{ PHP_CVSCLIENT_REQ_ADD,			"add"			},
	{ PHP_CVSCLIENT_REQ_REMOVE,			"remove"		},
	{ PHP_CVSCLIENT_REQ_HISTORY,		"history"		},
	{ 0,								NULL			}
};

static char cvs_encode[96] =
	{  32, 120,  53,  35,  36, 109,  72, 108,
	   70,  64,  76,  67, 116,  74,  68,  87,
	  111,  52,  75, 119,  49,  34,  82,  81,
	   95,  65, 112,  86, 118, 110, 122, 105,
	   64,  57,  83,  43,  46, 102,  40,  89,
	   38, 103,  45,  50,  42, 123,  91,  35,
	  125,  55,  54,  66, 124, 126,  59,  47,
	   92,  71, 115,  91,  92,  93,  94,  56,
	   96, 121, 117, 104, 101, 100,  69,  73,
	   99,  63,  94,  93,  39,  37,  61,  48,
	   58, 113,  32,  90,  44,  98,  60,  51,
	   33,  97,  62, 123, 124, 125, 126, 127 };

function_entry cvsclient_functions[] = {
	/* TODO: Resource based single-session access and committment */
	{NULL, NULL, NULL}
};

zend_module_entry cvsclient_module_entry = {
	STANDARD_MODULE_HEADER,
	"cvsclient",
	cvsclient_functions,
	PHP_MINIT(cvsclient),
	PHP_MSHUTDOWN(cvsclient),
	NULL, /* RINIT */
	NULL, /* RSHUTDOWN */
	PHP_MINFO(cvsclient),
	NO_VERSION_YET,
	STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_CVSCLIENT
ZEND_GET_MODULE(cvsclient)
#endif


/* {{{ php_cvsclient_do_connect */
static php_stream * php_cvsclient_do_connect(char *path, int options, php_stream_context *context, php_url **presource STREAMS_DC TSRMLS_DC)
{
	php_stream *stream = NULL;
	php_url *resource = NULL;

	resource = php_url_parse((char *) path);
	if (!resource || !resource->scheme || !resource->host) {
		goto connect_errexit;
	}

	if (strcasecmp("cvs", resource->scheme)) {
		goto connect_errexit;
	}

	/* use port 2401 if one wasn't specified */
	if (resource->port == 0) {
		resource->port = 2401;
	}

	stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, NULL, 0);
	if (stream == NULL) {
		goto connect_errexit;
	}

    php_stream_context_set(stream, context);
    php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

	if (presource) {
		*presource = resource;
	} else {
		php_url_free(resource);
	}

	return stream;

 connect_errexit:
	if (resource) {
		php_url_free(resource);
	}
	if (stream) {
		php_stream_close(stream);
	}

	return NULL;
}
/* }}} */

/* {{{ php_cvsclient_encode
 */
static char * php_cvsclient_encode(const char *orig)
{
	unsigned char *enc;
	int i;

	enc = estrdup(orig);
	for(i=0; i<strlen(enc); i++) {
		if (enc[i] >= 32 && enc[i] <= 127) {
			enc[i] = cvs_encode[enc[i] - 32];
		}
	}

	return enc;
}
/* }}} */

/* {{{ php_cvsclient_authenticate
 */
static int php_cvsclient_authenticate(php_stream *stream, const char *cvsroot, const char *user, const char *pass STREAMS_DC TSRMLS_DC)
{
	char *encpw;
	char response[128];

	encpw = php_cvsclient_encode(pass);
	
	php_stream_write_string(stream, "BEGIN AUTH REQUEST\n");
	php_stream_printf(stream TSRMLS_CC, "%s\n", cvsroot);
	php_stream_printf(stream TSRMLS_CC, "%s\n", user);
	php_stream_printf(stream TSRMLS_CC, "A%s\n", encpw);
	php_stream_write_string(stream, "END AUTH REQUEST\n");

	efree(encpw);

	/* Who do you love? */
	if (php_stream_gets(stream, response, sizeof(response)-1) == NULL) {
		return FAILURE;
	}
	if (strncmp(response, "I LOVE YOU", strlen("I LOVE YOU"))) {
		return FAILURE;
	}
	return SUCCESS;
}
/* }}} */

/* {{{ php_cvsclient_negotiate */
static int php_cvsclient_negotiate(php_stream *stream, const char *cvsroot STREAMS_DC TSRMLS_DC)
{
	php_cvsclient_requests *verbs = cvsclient_requests;
	char response[4096];
	int requests = 0, i;

	php_stream_printf(stream TSRMLS_CC, "Root %s\n", cvsroot);
	php_stream_printf(stream TSRMLS_CC, "Valid-responses %s %s %s\n",
		"Valid-requests New-entry Updated Created Update-existing Merged Rcs-diff Patched Mode Mod-time Checksum",
		"Copy-file Removed Remove-entry Set-static-directory Clear-static-directory Set-sticky Clear-sticky Template Set-checkin-prog",
		"Set-update-prog Notified Module-expansion Wrapper-rcsOption ok error Checked-in M E F MT");
	php_stream_write_string(stream, "valid-requests\n");

	if (php_stream_gets(stream, response, sizeof(response)-1) == NULL) {
		return 0;
	}

	for(i=0; i<strlen(response); i++) {
		response[i] = tolower(response[i]);
	}

	/* TODO: Improve this, we could (and probably do) get false positives */
	while (verbs->request && verbs->label) {
		if (strstr(response, verbs->label)) {
			requests |= verbs->request;
		}
		verbs++;
	}

	return requests;
}
/* }}} */

/* {{{ php_stream_url_wrap_cvsclient
 */
static php_stream * php_stream_url_wrap_cvsclient(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
{
	php_cvsclient_requests *verbs = cvsclient_requests;
	php_stream *stream, *memstream;
	php_url *resource = NULL;
	char *module = NULL;
	char *cvsroot = NULL;
	char *filepath = NULL;
	char *filename, *p;
	char response[4096];
	int valid_requests, i;
	long filesize;
	zval *wrapperdata = NULL;
	zval **tmpzval;

	if (strpbrk(mode, "awx+")) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "CVS wrapper does not support writeable connections (yet).");
		return NULL;
	}

	/* Connect */
	stream = php_cvsclient_do_connect(path, options, context, &resource STREAMS_CC TSRMLS_CC);
	if (!stream || !resource->path) {
		goto wrap_errexit;
	}
	p = strchr(resource->path + 1, '/');
	if (p) {
		cvsroot = estrndup(resource->path, p - resource->path);
		filename = p;
		p = strchr(filename + 1, '/');
		if (p) {
			module = estrndup(filename, p - filename);
			filename = p;
			p = strrchr(filename + 1, '/');
			if (p) {
				filepath = estrndup(filename, p - filename);
				filename = p + 1;
			} else {
				filename++;
			}
		} else {
			goto wrap_errexit;
		}
	} else {
		goto wrap_errexit;
	}

	/* Authenticate */
	if (resource && resource->user && resource->pass &&
		php_cvsclient_authenticate(stream, cvsroot, resource->user, resource->pass STREAMS_CC TSRMLS_CC) == FAILURE) {
		goto wrap_errexit;
	}

	/* Negotiate */
	if ((valid_requests = php_cvsclient_negotiate(stream, cvsroot STREAMS_CC TSRMLS_CC)) == 0) {
		goto wrap_errexit;
	}

	/* Request */
	if (context &&
		php_stream_context_get_option(context, "cvs", "revision", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_string_ex(tmpzval);
		php_stream_printf(stream TSRMLS_CC, "Argument -r\nArgument %s\n", Z_STRVAL_PP(tmpzval));
	}
	php_stream_printf(stream TSRMLS_CC, "Argument %s\n", filename);
	php_stream_write_string(stream, "Directory .\n");
	php_stream_printf(stream TSRMLS_CC, "%s%s%s\n", cvsroot, module, filepath ? filepath : "");
	php_stream_write_string(stream, "update\n");

	efree(cvsroot);
	cvsroot = NULL;
	efree(module);
	module = NULL;
	if (filepath) {
		efree(filepath);
		filepath = NULL;
	}

	/* Parse response */
	ALLOC_INIT_ZVAL(wrapperdata);
	array_init(wrapperdata);
	while (php_stream_gets(stream, response, sizeof(response)-1) != NULL) {
		if (strncasecmp(response, "error", 5) == 0) {
			goto wrap_errexit;
		}
		if (strncasecmp(response, "mod-time ", 9) == 0) {
			add_assoc_string(wrapperdata, "mod-time", response + 9, 1);
		}
		if ((strlen(response) > strlen(filename) + 4) && 
			response[0] == '/' && 
			strncmp(response + 1, filename, strlen(filename)) == 0 &&
			response[strlen(filename)+1] == '/') {
			p = response + strlen(filename) + 2;
			p = strchr(p, '/');
			if (p) {
				*p = '\0';
				p = response + strlen(filename) + 2;
				add_assoc_string(wrapperdata, "revision", p, 1);
			}
		}
		/* TODO: Parse other elements into wrapperdata */
		for(i=0; i<strlen(response); i++) {
			if (!isdigit(response[i]) && !iscntrl(response[i])) {
				goto header_loop;
			}
		}
		break;
 header_loop:
	}
	filesize = atoi(response);
	add_assoc_long(wrapperdata, "filesize", filesize);

	memstream = php_stream_fopen_tmpfile();
	if (!memstream) {
		goto wrap_errexit;
	}
	while (filesize) {
		int read;

		read = php_stream_read(stream, response, (filesize > (sizeof(response) - 1)) ? sizeof(response)-1 : filesize);
		php_stream_write(memstream, response, read);

		filesize -= read;
	}
	php_stream_rewind(memstream);
	php_stream_close(stream);

	memstream->wrapperdata = wrapperdata;

	php_url_free(resource);
	resource = NULL;

	return memstream;

 wrap_errexit:
	if (filepath) {
		efree(filepath);
	}
	if (module) {
		efree(module);
	}
	if (cvsroot) {
		efree(cvsroot);
	}
	if (wrapperdata) {
		zval_ptr_dtor(&wrapperdata);
	}
	if (resource) {
		php_url_free(resource);
	}
	if (stream) {
		php_stream_close(stream);
	}
	return NULL;
}
/* }}} */

/* {{{ php_stream_cvsclient_stat
 */
static int php_stream_cvsclient_stat(php_stream_wrapper *wrapper,
		php_stream *stream,
		php_stream_statbuf *ssb
		TSRMLS_DC)
{
	/* For now, we return with a failure code to prevent the underlying
	 * file's details from being used instead. */
	return -1;
}
/* }}} */

static php_stream_wrapper_ops cvsclient_stream_wops = {
	php_stream_url_wrap_cvsclient,
	NULL, /* stream_close */
	php_stream_cvsclient_stat,
	NULL, /* stat_url */
	NULL, /* opendir */
	"CVS"
#if PHP_MAJOR_VERSION >= 5
	,NULL /* unlink */
#endif
};

PHPAPI php_stream_wrapper php_stream_cvsclient_wrapper =  {
	&cvsclient_stream_wops,
	NULL,
	1 /* is_url */
};

PHP_MINIT_FUNCTION(cvsclient)
{
	/* TODO: Readonly support for cvs.log, cvs.history, etc... */
	return php_register_url_stream_wrapper("cvs", &php_stream_cvsclient_wrapper TSRMLS_CC);
}

PHP_MSHUTDOWN_FUNCTION(cvsclient)
{
	return php_unregister_url_stream_wrapper("cvs" TSRMLS_CC);
}


PHP_MINFO_FUNCTION(cvsclient)
{
	php_info_print_table_start();
	php_info_print_table_row(2, "CVS Client", "enabled");
	php_info_print_table_row(2, "Wrapper", "cvs://");
	php_info_print_table_end();
}

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: sw=4 ts=4 fdm=marker
 * vim<600: sw=4 ts=4
 */

Index: pecl/cvsclient/package.xml
+++ pecl/cvsclient/package.xml
<package version="1.0">
  <name>cvsclient</name>
  <summary>CVS pserver client</summary>
  <description>
    pserver client extension.  Current version has read-only streams wrapper.
    Later versions to include commit/diff/log support.
  </description>
  <license>PHP</license>
  <maintainers>
    <maintainer>
      <user>pollita</user>
      <name>Sara Golemon</name>
      <email>[email protected]</email>
      <role>lead</role>
    </maintainer>
  </maintainers>

  <release>
    <version>0.1</version>
    <state>alpha</state>
    <date>2003-11-29</date>
    <notes>Initial Release</notes>
    <filelist>
      <file role="src" name="config.m4"/>
      <file role="src" name="cvsclient.c"/>
      <file role="src" name="php_cvsclient.h"/>      
    </filelist>
  </release>

  <deps>
    <dep type="php" rel="ge">4.3.0</dep>
  </deps>
</package>

Index: pecl/cvsclient/php_cvsclient.h
+++ pecl/cvsclient/php_cvsclient.h
/* 
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2002 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          |
   | [email protected] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Sara Golemon <[email protected]>                               |
   +----------------------------------------------------------------------+
*/

#ifndef PHP_CVSCLIENT_H
#define PHP_CVSCLIENT_H

#if WITH_CVSCLIENT

extern zend_module_entry cvsclient_module_entry;
#define phpext_cvsclient_ptr &cvsclient_module_entry

PHP_MINIT_FUNCTION(cvsclient);
PHP_MSHUTDOWN_FUNCTION(cvsclient);
PHP_MINFO_FUNCTION(cvsclient);

#else

#define phpext_cvsclient_ptr NULL

#endif /* WITH_CVSCLIENT */

#endif /* PHP_CVSCLIENT_H */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.