Improve build procedure

This commit is contained in:
Evgeniy Khramtsov 2013-05-01 21:02:29 +10:00
parent d1c654a7e1
commit 04f20a21fb
30 changed files with 928 additions and 3391 deletions

20
.gitignore vendored
View File

@ -16,23 +16,3 @@
/doc/*.toc
/doc/contributed_modules.tex
/doc/version.tex
/src/*.beam
/src/*.so
/src/*.so.dSYM
/src/*/*.beam
/src/*/Makefile
/src/Makefile
/src/XmppAddr.asn1db
/src/XmppAddr.erl
/src/XmppAddr.hrl
/src/aclocal.m4
/src/autom4te.cache
/src/config.log
/src/config.status
/src/ejabberd.init
/src/ejabberdctl.example
/src/eldap/ELDAPv3.asn1db
/src/eldap/ELDAPv3.erl
/src/eldap/ELDAPv3.hrl
/src/eldap/eldap_filter_yecc.erl
/src/epam

View File

@ -1,4 +1,4 @@
REBAR = @REBAR@
REBAR = rebar
INSTALL = @INSTALL@
SED = @SED@
ERL = @ERL@
@ -94,16 +94,25 @@ edoc:
'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
clean:
rebar clean
$(REBAR) clean
distclean: clean
rm -f config.status
rm -f config.log
rm -f rebar.config
rm -rf deps/*
rm -rf deps
rm -f Makefile
rm -rf rel/files
rm -rf rel/ejabberd
rm -f rel/reltool.config
rm -f src/ejabberd.app.src
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
rel:
mkdir -p rel ; cd rel ; rm -rf files ejabberd ; \
$(REBAR) create-node nodeid=ejabberd || exit 1; \
$(REBAR) generate
TAGS:
etags *.erl
@ -112,4 +121,4 @@ Makefile: Makefile.in
dialyzer: $(BEAMS)
@dialyzer -c .
.PHONY: src doc edoc dialyzer Makefile TAGS clean distclean
.PHONY: src doc edoc dialyzer Makefile TAGS clean distclean rel

View File

@ -1,316 +0,0 @@
/*
* ejabberd, Copyright (C) 2002-2013 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*
*/
#include <stdio.h>
#include <string.h>
#include <erl_driver.h>
#include <ei.h>
#include <expat.h>
#define XML_START 0
#define XML_END 1
#define XML_CDATA 2
#define XML_ERROR 3
#define PARSE_COMMAND 0
#define PARSE_FINAL_COMMAND 1
/*
* R15B changed several driver callbacks to use ErlDrvSizeT and
* ErlDrvSSizeT typedefs instead of int.
* This provides missing typedefs on older OTP versions.
*/
#if ERL_DRV_EXTENDED_MAJOR_VERSION < 2
typedef int ErlDrvSizeT;
typedef int ErlDrvSSizeT;
#endif
ei_x_buff event_buf;
ei_x_buff xmlns_buf;
typedef struct {
ErlDrvPort port;
XML_Parser parser;
} expat_data;
static XML_Memory_Handling_Suite ms;
void encode_name(const XML_Char *name)
{
char *name_start;
char *prefix_start;
char *buf;
int name_len, prefix_len, buf_len;
if ((name_start = strchr(name, '\n'))) {
if ((prefix_start = strchr(name_start+1, '\n'))) {
name_len = prefix_start - name_start;
prefix_len = strlen(prefix_start+1);
buf_len = prefix_len + name_len;
buf = driver_alloc(buf_len);
memcpy(buf, prefix_start+1, prefix_len);
memcpy(buf+prefix_len, name_start, name_len);
buf[prefix_len] = ':';
ei_x_encode_binary(&event_buf, buf, buf_len);
driver_free(buf);
} else {
ei_x_encode_binary(&event_buf, name_start+1, strlen(name_start+1));
};
} else {
ei_x_encode_binary(&event_buf, name, strlen(name));
}
}
void *erlXML_StartElementHandler(expat_data *d,
const XML_Char *name,
const XML_Char **atts)
{
int i;
ei_x_encode_list_header(&event_buf, 1);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_START);
ei_x_encode_tuple_header(&event_buf, 2);
encode_name(name);
ei_x_append(&event_buf, &xmlns_buf);
ei_x_free(&xmlns_buf);
ei_x_new(&xmlns_buf);
for (i = 0; atts[i]; i += 2) {}
if (i > 0)
{
ei_x_encode_list_header(&event_buf, i/2);
for (i = 0; atts[i]; i += 2)
{
ei_x_encode_tuple_header(&event_buf, 2);
encode_name(atts[i]);
ei_x_encode_binary(&event_buf, atts[i+1], strlen(atts[i+1]));
}
}
ei_x_encode_empty_list(&event_buf);
return NULL;
}
void *erlXML_EndElementHandler(expat_data *d,
const XML_Char *name)
{
ei_x_encode_list_header(&event_buf, 1);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_END);
encode_name(name);
return NULL;
}
void *erlXML_CharacterDataHandler(expat_data *d,
const XML_Char *s,
int len)
{
ei_x_encode_list_header(&event_buf, 1);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_CDATA);
ei_x_encode_binary(&event_buf, s, len);
return NULL;
}
void *erlXML_StartNamespaceDeclHandler(expat_data *d,
const XML_Char *prefix,
const XML_Char *uri)
{
int prefix_len;
char *buf;
/* From the expat documentation:
"For a default namespace declaration (xmlns='...'),
the prefix will be null ...
... The URI will be null for the case where
the default namespace is being unset."
FIXME: I'm not quite sure what all that means */
if (uri == NULL)
return NULL;
ei_x_encode_list_header(&xmlns_buf, 1);
ei_x_encode_tuple_header(&xmlns_buf, 2);
if (prefix) {
prefix_len = strlen(prefix);
buf = driver_alloc(7 + prefix_len);
strcpy(buf, "xmlns:");
strcpy(buf+6, prefix);
ei_x_encode_binary(&xmlns_buf, buf, strlen(buf));
driver_free(buf);
} else {
ei_x_encode_binary(&xmlns_buf, "xmlns", strlen("xmlns"));
};
ei_x_encode_binary(&xmlns_buf, uri, strlen(uri));
return NULL;
}
static ErlDrvData expat_erl_start(ErlDrvPort port, char *buff)
{
expat_data* d = (expat_data*)driver_alloc(sizeof(expat_data));
d->port = port;
d->parser = XML_ParserCreate_MM("UTF-8", &ms, "\n");
XML_SetUserData(d->parser, d);
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
XML_SetStartElementHandler(
d->parser, (XML_StartElementHandler)erlXML_StartElementHandler);
XML_SetEndElementHandler(
d->parser, (XML_EndElementHandler)erlXML_EndElementHandler);
XML_SetCharacterDataHandler(
d->parser, (XML_CharacterDataHandler)erlXML_CharacterDataHandler);
XML_SetStartNamespaceDeclHandler(
d->parser, (XML_StartNamespaceDeclHandler) erlXML_StartNamespaceDeclHandler);
XML_SetReturnNSTriplet(d->parser, 1);
XML_SetDefaultHandler(d->parser, NULL);
return (ErlDrvData)d;
}
static void expat_erl_stop(ErlDrvData handle)
{
XML_ParserFree(((expat_data *)handle)->parser);
driver_free((char*)handle);
}
static ErlDrvSSizeT expat_erl_control(ErlDrvData drv_data,
unsigned int command,
char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
expat_data* d = (expat_data*)drv_data;
int res, errcode;
char *errstring;
ErlDrvBinary *b;
size_t size;
switch (command)
{
case PARSE_COMMAND:
case PARSE_FINAL_COMMAND:
ei_x_new_with_version(&event_buf);
ei_x_new(&xmlns_buf);
#ifdef ENABLE_FLASH_HACK
/* Flash hack - Flash clients send a null byte after the stanza. Remove that... */
{
int i;
int found_null = 0;
/* Maybe the Flash client sent many stanzas in one packet.
If so, there is a null byte between every stanza. */
for (i = 0; i < len; i++) {
if (buf[i] == '\0') {
buf[i] = ' ';
found_null = 1;
}
}
/* And also remove the closing slash if this is a
flash:stream element. Assume that flash:stream is the
last element in the packet, and entirely contained in
it. This requires that a null byte has been found. */
if (found_null && strstr(buf, "<flash:stream"))
/* buf[len - 1] is an erased null byte.
buf[len - 2] is >
buf[len - 3] is / (maybe)
*/
if (buf[len - 3] == '/')
buf[len - 3] = ' ';
}
#endif /* ENABLE_FLASH_HACK */
res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND);
if(!res)
{
errcode = XML_GetErrorCode(d->parser);
errstring = (char *)XML_ErrorString(errcode);
ei_x_encode_list_header(&event_buf, 1);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_ERROR);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, errcode);
ei_x_encode_binary(&event_buf, errstring, strlen(errstring));
}
ei_x_encode_empty_list(&event_buf);
size = event_buf.index;
b = driver_alloc_binary(size);
memcpy(b->orig_bytes, event_buf.buff, size);
ei_x_free(&event_buf);
ei_x_free(&xmlns_buf);
*rbuf = (char *)b;
return size;
default:
return 0;
}
}
ErlDrvEntry expat_driver_entry = {
NULL, /* F_PTR init, N/A */
expat_erl_start, /* L_PTR start, called when port is opened */
expat_erl_stop, /* F_PTR stop, called when port is closed */
NULL, /* F_PTR output, called when erlang has sent */
NULL, /* F_PTR ready_input, called when input descriptor ready */
NULL, /* F_PTR ready_output, called when output descriptor ready */
"expat_erl", /* char *driver_name, the argument to open_port */
NULL, /* F_PTR finish, called when unloaded */
NULL, /* handle */
expat_erl_control, /* F_PTR control, port_command callback */
NULL, /* F_PTR timeout, reserved */
NULL, /* F_PTR outputv, reserved */
/* Added in Erlang/OTP R15B: */
NULL, /* ready_async */
NULL, /* flush */
NULL, /* call */
NULL, /* event */
ERL_DRV_EXTENDED_MARKER, /* extended_marker */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* major_version */
ERL_DRV_EXTENDED_MINOR_VERSION, /* minor_version */
0, /* driver_flags */
NULL, /* handle2 */
NULL, /* process_exit */
NULL /* stop_select */
};
DRIVER_INIT(expat_erl) /* must match name in driver_entry */
{
ms.malloc_fcn = driver_alloc;
ms.realloc_fcn = driver_realloc;
ms.free_fcn = driver_free;
return &expat_driver_entry;
}

View File

@ -1,120 +0,0 @@
/*
* ejabberd, Copyright (C) 2002-2013 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*
*/
#include <erl_driver.h>
#include <openssl/sha.h>
#ifdef HAVE_MD2
#include <openssl/md2.h>
#endif
/*
* R15B changed several driver callbacks to use ErlDrvSizeT and
* ErlDrvSSizeT typedefs instead of int.
* This provides missing typedefs on older OTP versions.
*/
#if ERL_DRV_EXTENDED_MAJOR_VERSION < 2
typedef int ErlDrvSizeT;
typedef int ErlDrvSSizeT;
#endif
static ErlDrvData sha_drv_start(ErlDrvPort port, char *buf)
{
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
return NULL;
}
static ErlDrvSSizeT sha_drv_control(ErlDrvData handle,
unsigned int command,
char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
ErlDrvBinary *b = NULL;
switch (command) {
#ifdef HAVE_MD2
case 2:
rlen = MD2_DIGEST_LENGTH;
b = driver_alloc_binary(rlen);
if (b) MD2((unsigned char*)buf, len, (unsigned char*)b->orig_bytes);
break;
#endif
case 224:
rlen = SHA224_DIGEST_LENGTH;
b = driver_alloc_binary(rlen);
if (b) SHA224((unsigned char*)buf, len, (unsigned char*)b->orig_bytes);
break;
case 256:
rlen = SHA256_DIGEST_LENGTH;
b = driver_alloc_binary(rlen);
if (b) SHA256((unsigned char*)buf, len, (unsigned char*)b->orig_bytes);
break;
case 384:
rlen = SHA384_DIGEST_LENGTH;
b = driver_alloc_binary(rlen);
if (b) SHA384((unsigned char*)buf, len, (unsigned char*)b->orig_bytes);
break;
case 512:
rlen = SHA512_DIGEST_LENGTH;
b = driver_alloc_binary(rlen);
if (b) SHA512((unsigned char*)buf, len, (unsigned char*)b->orig_bytes);
break;
};
if (b) {
*rbuf = (char *)b;
} else {
*rbuf = NULL;
rlen = 0;
};
return rlen;
}
ErlDrvEntry sha_driver_entry = {
NULL, /* F_PTR init, N/A */
sha_drv_start, /* L_PTR start, called when port is opened */
NULL, /* F_PTR stop, called when port is closed */
NULL, /* F_PTR output, called when erlang has sent */
NULL, /* F_PTR ready_input, called when input descriptor ready */
NULL, /* F_PTR ready_output, called when output descriptor ready */
"sha_drv", /* char *driver_name, the argument to open_port */
NULL, /* F_PTR finish, called when unloaded */
NULL, /* handle */
sha_drv_control, /* F_PTR control, port_command callback */
NULL, /* F_PTR timeout, reserved */
NULL, /* F_PTR outputv, reserved */
/* Added in Erlang/OTP R15B: */
NULL, /* ready_async */
NULL, /* flush */
NULL, /* call */
NULL, /* event */
ERL_DRV_EXTENDED_MARKER, /* extended_marker */
ERL_DRV_EXTENDED_MAJOR_VERSION, /* major_version */
ERL_DRV_EXTENDED_MINOR_VERSION, /* minor_version */
0, /* driver_flags */
NULL, /* handle2 */
NULL, /* process_exit */
NULL /* stop_select */
};
DRIVER_INIT(sha_drv) /* must match name in driver_entry */
{
return &sha_driver_entry;
}

View File

@ -1,261 +0,0 @@
#include <erl_nif.h>
#include <string.h>
#include <stdio.h>
#define SSL40
#ifdef SSL40
#define ENIF_ALLOC(SIZE) enif_alloc(SIZE)
#define ENIF_FREE(PTR) enif_free(PTR)
#define ENIF_REALLOC(PTR, SIZE) enif_realloc(PTR, SIZE)
#define ENIF_ALLOC_BINARY(SIZE, BIN) enif_alloc_binary(SIZE, BIN)
#define ENIF_COMPARE(TERM1, TERM2) enif_compare(TERM1, TERM2)
#else
#define ENIF_ALLOC(SIZE) enif_alloc(env, SIZE)
#define ENIF_FREE(PTR) enif_free(env, PTR)
#define ENIF_REALLOC(PTR, SIZE) enif_realloc(env, PTR, SIZE)
#define ENIF_ALLOC_BINARY(SIZE, BIN) enif_alloc_binary(env, SIZE, BIN)
#define ENIF_COMPARE(TERM1, TERM2) enif_compare(env, TERM1, TERM2)
#endif
static ERL_NIF_TERM atom_xmlelement;
static ERL_NIF_TERM atom_xmlcdata;
struct buf {
int limit;
int len;
unsigned char *b;
};
static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el);
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
atom_xmlelement = enif_make_atom(env, "xmlel");
atom_xmlcdata = enif_make_atom(env, "xmlcdata");
return 0;
}
static struct buf *init_buf(ErlNifEnv* env)
{
struct buf *rbuf = ENIF_ALLOC(sizeof(struct buf));
rbuf->limit = 1024;
rbuf->len = 0;
rbuf->b = ENIF_ALLOC(rbuf->limit);
return rbuf;
}
static void destroy_buf(ErlNifEnv* env, struct buf *rbuf)
{
if (rbuf) {
if (rbuf->b) {
ENIF_FREE(rbuf->b);
};
ENIF_FREE(rbuf);
};
}
inline void resize_buf(ErlNifEnv* env, struct buf *rbuf, int len_to_add)
{
int new_len = rbuf->len + len_to_add;
if (new_len > rbuf->limit) {
while (new_len > rbuf->limit)
rbuf->limit *= 2;
rbuf->b = ENIF_REALLOC(rbuf->b, rbuf->limit);
}
}
static void buf_add_char(ErlNifEnv* env, struct buf *rbuf, unsigned char c)
{
resize_buf(env, rbuf, 1);
(rbuf->b)[rbuf->len] = c;
rbuf->len += 1;
}
static void buf_add_str(ErlNifEnv* env, struct buf *rbuf, char *data, int len)
{
resize_buf(env, rbuf, len);
memcpy(rbuf->b + rbuf->len, data, len);
rbuf->len += len;
}
inline void crypt(ErlNifEnv* env, struct buf *rbuf, unsigned char *data, int len)
{
int i;
for (i = 0; i < len; i++) {
switch (data[i]) {
case '&':
buf_add_str(env, rbuf, "&amp;", 5);
break;
case '<':
buf_add_str(env, rbuf, "&lt;", 4);
break;
case '>':
buf_add_str(env, rbuf, "&gt;", 4);
break;
case '"':
buf_add_str(env, rbuf, "&quot;", 6);
break;
case '\'':
buf_add_str(env, rbuf, "&apos;", 6);
break;
default:
buf_add_char(env, rbuf, data[i]);
break;
};
};
}
static int make_elements(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM els)
{
ERL_NIF_TERM head, tail;
int ret = 0;
while (enif_get_list_cell(env, els, &head, &tail)) {
ret = make_element(env, rbuf, head);
if (ret) {
els = tail;
} else {
break;
};
};
return ret;
}
static int make_attrs(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM attrs)
{
ErlNifBinary name, data;
ERL_NIF_TERM head, tail;
const ERL_NIF_TERM *tuple;
int arity, ret = 1;
while (enif_get_list_cell(env, attrs, &head, &tail)) {
if (enif_get_tuple(env, head, &arity, &tuple)) {
if (arity == 2) {
if (enif_inspect_iolist_as_binary(env, tuple[0], &name) &&
enif_inspect_iolist_as_binary(env, tuple[1], &data)) {
buf_add_char(env, rbuf, ' ');
buf_add_str(env, rbuf, (char *)name.data, name.size);
buf_add_str(env, rbuf, "='", 2);
crypt(env, rbuf, data.data, data.size);
buf_add_char(env, rbuf, '\'');
attrs = tail;
} else {
ret = 0;
break;
};
} else {
ret = 0;
break;
};
} else {
ret = 0;
break;
};
};
return ret;
}
static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el)
{
ErlNifBinary cdata, name;
const ERL_NIF_TERM *tuple;
int arity, ret = 0;
if (enif_get_tuple(env, el, &arity, &tuple)) {
if (arity == 2) {
if (!ENIF_COMPARE(tuple[0], atom_xmlcdata)) {
if (enif_inspect_iolist_as_binary(env, tuple[1], &cdata)) {
crypt(env, rbuf, cdata.data, cdata.size);
ret = 1;
};
};
};
if (arity == 4) {
if (!ENIF_COMPARE(tuple[0], atom_xmlelement)) {
if (enif_inspect_iolist_as_binary(env, tuple[1], &name)) {
buf_add_char(env, rbuf, '<');
buf_add_str(env, rbuf, (char *)name.data, name.size);
ret = make_attrs(env, rbuf, tuple[2]);
if (ret) {
if (enif_is_empty_list(env, tuple[3])) {
buf_add_str(env, rbuf, "/>", 2);
} else {
buf_add_char(env, rbuf, '>');
ret = make_elements(env, rbuf, tuple[3]);
if (ret) {
buf_add_str(env, rbuf, "</", 2);
buf_add_str(env, rbuf, (char*)name.data, name.size);
buf_add_char(env, rbuf, '>');
};
};
};
};
};
};
};
return ret;
}
static ERL_NIF_TERM element_to(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[],
int as_string)
{
ErlNifBinary output;
ERL_NIF_TERM result;
struct buf *rbuf;
if (argc == 1) {
rbuf = init_buf(env);
if (make_element(env, rbuf, argv[0])) {
if (as_string) {
(rbuf->b)[rbuf->len] = 0;
result = enif_make_string(env, (char *) rbuf->b, ERL_NIF_LATIN1);
destroy_buf(env, rbuf);
return result;
} else {
if (ENIF_ALLOC_BINARY(rbuf->len, &output)) {
memcpy(output.data, rbuf->b, rbuf->len);
result = enif_make_binary(env, &output);
destroy_buf(env, rbuf);
return result;
};
};
};
destroy_buf(env, rbuf);
};
return enif_make_badarg(env);
}
#ifdef SSL40
static ERL_NIF_TERM element_to_string(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
return element_to(env, argc, argv, 1);
}
#endif
static ERL_NIF_TERM element_to_binary(ErlNifEnv* env, int argc,
const ERL_NIF_TERM argv[])
{
return element_to(env, argc, argv, 0);
}
static ErlNifFunc nif_funcs[] =
{
/* Stupid Erlang bug with enif_make_string() is fixed
in R14A only (OTP-8685), so we can't use
element_to_string in Erlang < R14A.*/
#ifdef SSL40
{"element_to_string", 1, element_to_string},
#endif
{"element_to_binary", 1, element_to_binary}
};
ERL_NIF_INIT(xml, nif_funcs, load, NULL, NULL, NULL)

2482
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -2,10 +2,10 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.53)
AC_INIT(ejabberd, m4_esyscmd([grep -o -E "\{vsn,.\".*\"\}" src/ejabberd.app.src | cut -d \" -f 2 | tr -d '\n']), [ejabberd@process-one.net], [ejabberd])
AC_PACKAGE_VERSION(3.0.0)
AC_INIT(ejabberd, 3.0.0, [ejabberd@process-one.net], [ejabberd])
# Checks for programs.
AC_PROG_CC
AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_SED
@ -22,44 +22,23 @@ AC_ERLANG_NEED_ERLC
AC_ERLANG_SUBST_ROOT_DIR
AC_ERLANG_SUBST_LIB_DIR
#locating rebar
AC_PATH_PROG([REBAR], [rebar], [])
#locating escript
AC_PATH_PROG([ESCRIPT], [escript], [])
#locating make
AC_CHECK_PROG([MAKE], [make], [make], [])
if test "x$REBAR" = "x"; then
AC_MSG_ERROR(['rebar' was not found])
if test "x$ESCRIPT" = "x"; then
AC_MSG_ERROR(['escript' was not found])
fi
if test "x$MAKE" = "x"; then
AC_MSG_ERROR(['make' was not found])
fi
#locating iconv
AM_ICONV
#locating libexpat
AM_WITH_EXPAT
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
# Check Erlang headers are installed
#AC_CHECK_HEADER(erl_driver.h,,[AC_MSG_ERROR([cannot find Erlang header files])])
# Change default prefix
AC_PREFIX_DEFAULT(/)
# Checks for library functions.
AC_FUNC_MALLOC
AC_HEADER_STDC
#locating zlib
AM_WITH_ZLIB
AC_MOD_ENABLE(pam, no)
#locating PAM
AM_WITH_PAM
AC_ARG_ENABLE(hipe,
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
[case "${enableval}" in
@ -124,25 +103,9 @@ esac],[nif=false])
AC_SUBST(nif)
AC_CONFIG_FILES([Makefile
rebar.config])
#openssl
AM_WITH_OPENSSL
# If ssl is kerberized it need krb5.h
# On RedHat and OpenBSD, krb5.h is in an unsual place:
KRB5_INCLUDE="`krb5-config --cflags 2>/dev/null`"
if test -n "$KRB5_INCLUDE" ; then
CPPFLAGS="$CPPFLAGS $KRB5_INCLUDE"
else
# For RedHat For BSD
for D in /usr/kerberos/include /usr/include/kerberos /usr/include/kerberosV
do
if test -d $D ; then
CPPFLAGS="$CPPFLAGS -I$D"
fi
done
fi
AC_CHECK_HEADER(krb5.h,,)
rebar.config
src/ejabberd.app.src
rel/reltool.config])
ENABLEUSER=""
AC_ARG_ENABLE(user,

View File

@ -27,7 +27,7 @@
-define(MYLANG, ejabberd_config:get_mylang()).
-define(MSGS_DIR, <<"msgs">>).
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
-define(CONFIG_PATH, <<"ejabberd.cfg">>).

View File

@ -215,6 +215,8 @@
-define(NS_BOB, <<"urn:xmpp:bob">>).
-include("xml.hrl").
-define(STANZA_ERROR(Code, Type, Condition),
#xmlel{name = <<"error">>,
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
@ -617,19 +619,6 @@
-type(ljid() :: {binary(), binary(), binary()}).
-record(xmlel,
{
name = <<"">> :: binary(),
attrs = [] :: [attr()],
children = [] :: [xmlel() | cdata()]
}).
-type(cdata() :: {xmlcdata, CData::binary()}).
-type(attr() :: {Name::binary(), Value::binary()}).
-type(xmlel() :: #xmlel{}).
-record(iq, {id = <<"">> :: binary(),
type = get :: get | set | result | error,
xmlns = <<"">> :: binary(),

BIN
rebar vendored Executable file

Binary file not shown.

View File

@ -1,8 +1,13 @@
{erl_opts, [debug_info, {i, "include"}, {i, "deps/logger/include"}]}.
{erl_opts, [debug_info,
{i, "include"},
{i, "deps/logger/include"},
{i, "deps/xml/include"}]}.
%%{src_dirs, [asn1, src, mod_pubsub_ng]}.
{src_dirs, [asn1, src]}.
{sub_dirs, ["rel"]}.
{deps, [{mysql, ".*", {git, "git://github.com/processone/mysql"}},
{pgsql, ".*", {git, "git://github.com/processone/pgsql"}},
{iconv, ".*", {git, "git://github.com/processone/eiconv"}},
@ -11,14 +16,14 @@
{tls, ".*", {git, "git://github.com/processone/tls"}},
{ezlib, ".*", {git, "git://github.com/processone/zlib"}},
{stun, ".*", {git, "git://github.com/processone/stun"}},
{stringprep, ".*", {git, "git://github.com/processone/stringprep"}},
{riakc, ".*", {git, "git://github.com/basho/riak-erlang-client"}},
{jiffy, ".*", {git, "git://github.com/davisp/jiffy"}},
{ibrowse, ".*", {git, "git://github.com/cmullaparthi/ibrowse"}},
{lhttpc, ".*", {git, "git://github.com/esl/lhttpc"}},
%%{xml, ".*", {git, "git://github.com/processone/xml"}},
{xmlrpc, ".*", {git, "git://github.com/etnt/xmlrpc"}}]}.
{port_env, [{"CFLAGS", "-g -O2 -Wall"}]}.
{port_specs, [{"priv/lib/sha_drv.so", ["c_src/sha_drv.c"]},
{"priv/lib/expat_erl.so", ["c_src/expat_erl.c"]},
{"priv/lib/xml.so", ["c_src/xml.c"]}]}.
%% Local Variables:
%% mode: erlang
%% End:

47
rel/reltool.config.in Normal file
View File

@ -0,0 +1,47 @@
{sys, [
{lib_dirs, []},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "@PACKAGE_NAME@", "@PACKAGE_VERSION@",
[
kernel,
stdlib,
sasl,
ejabberd
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "ejabberd"},
{profile, embedded},
{incl_cond, exclude},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, sasl, [{incl_cond, include}]},
{app, stdlib, [{incl_cond, include}]},
{app, kernel, [{incl_cond, include}]},
{app, ejabberd, [{incl_cond, include}, {lib_dir, ".."}]}
]}.
{target_dir, "ejabberd"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/ejabberd", "bin/ejabberd"},
{copy, "files/ejabberd.cmd", "bin/ejabberd.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
%%% Local Variables:
%%% mode: erlang
%%% End:
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker:

View File

@ -1,37 +0,0 @@
%% $Id$
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "3.0.0"},
{modules, []},
{registered, [ejabberd,
ejabberd_sup,
ejabberd_auth,
ejabberd_router,
ejabberd_router_multicast,
ejabberd_sm,
ejabberd_s2s,
ejabberd_local,
ejabberd_listeners,
ejabberd_iq_sup,
ejabberd_service_sup,
ejabberd_s2s_out_sup,
ejabberd_s2s_in_sup,
ejabberd_c2s_sup,
ejabberd_mod_roster,
ejabberd_mod_echo,
ejabberd_mod_pubsub,
ejabberd_mod_irc,
ejabberd_mod_muc,
ejabberd_offline,
random_generator
]},
{applications, [kernel, stdlib]},
{env, []},
{mod, {ejabberd_app, []}}]}.
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

16
src/ejabberd.app.src.in Normal file
View File

@ -0,0 +1,16 @@
%% $Id$
{application, ejabberd,
[{description, "@PACKAGE_NAME@"},
{vsn, "@PACKAGE_VERSION@"},
{modules, []},
{registered, []},
{applications, [kernel, stdlib]},
{env, []},
{mod, {ejabberd_app, []}}]}.
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -28,8 +28,9 @@
-author('alexey@process-one.net').
-export([start/0, stop/0,
get_pid_file/0,
get_so_path/0, get_bin_path/0]).
get_pid_file/0]).
-include("logger.hrl").
start() ->
%%ejabberd_cover:start(),
@ -39,32 +40,6 @@ stop() ->
application:stop(ejabberd).
%%ejabberd_cover:stop().
get_so_path() ->
case os:getenv("EJABBERD_SO_PATH") of
false ->
case code:priv_dir(ejabberd) of
{error, _} ->
".";
Path ->
filename:join([Path, "lib"])
end;
Path ->
Path
end.
get_bin_path() ->
case os:getenv("EJABBERD_BIN_PATH") of
false ->
case code:priv_dir(ejabberd) of
{error, _} ->
".";
Path ->
filename:join([Path, "bin"])
end;
Path ->
Path
end.
%% @spec () -> false | string()
get_pid_file() ->
case os:getenv("EJABBERD_PID_PATH") of

View File

@ -110,7 +110,7 @@ commands() ->
result = {res, rescode}},
#ejabberd_commands{name = get_loglevel, tags = [logs, server],
desc = "Get the current loglevel",
module = ejabberd_loglevel, function = get,
module = loglevel, function = get,
args = [],
result = {leveltuple, {tuple, [{levelnumber, integer},
{levelatom, atom},

View File

@ -34,20 +34,16 @@
-include("ejabberd.hrl").
-include("logger.hrl").
%%%
%%% Application API
%%%
start(normal, _Args) ->
ejabberd_loglevel:set(4),
loglevel:set(4),
write_pid_file(),
application:start(sasl),
start_apps(),
randoms:start(),
db_init(),
sha:start(),
stringprep_sup:start_link(),
xml:start(),
start(),
translate:start(),
acl:start(),
@ -109,19 +105,12 @@ init() ->
%error_logger:logfile({open, ?LOG_PATH}),
LogPath = get_log_path(),
error_logger:add_report_handler(ejabberd_logger_h, LogPath),
erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
case erl_ddll:load_driver(ejabberd:get_so_path(), expat_erl) of
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, "expat_erl"}, [binary]),
loop(Port).
loop().
loop(Port) ->
loop() ->
receive
_ ->
loop(Port)
loop()
end.
db_init() ->
@ -250,3 +239,11 @@ delete_pid_file() ->
PidFilename ->
file:delete(PidFilename)
end.
start_apps() ->
application:start(sasl),
application:start(ssl),
application:start(tls),
application:start(xml),
application:start(stringprep),
application:start(ezlib).

View File

@ -40,7 +40,7 @@
plain_password_required/0]).
start(_Host) ->
case epam:start() of
case application:start(epam) of
{ok, _} -> ok;
{error, {already_started, _}} -> ok;
Err -> Err

View File

@ -453,7 +453,7 @@ process_term(Term, State) ->
{ejabberdctl_access_commands, ACs} ->
add_option(ejabberdctl_access_commands, ACs, State);
{loglevel, Loglevel} ->
ejabberd_loglevel:set(Loglevel),
loglevel:set(Loglevel),
State;
{max_fsm_queue, N} ->
add_option(max_fsm_queue, N, State);

View File

@ -157,7 +157,7 @@ handle_call({compress, Data}, _From, State) ->
Reply = ok,
{reply, Reply,
State#socket_state{socket = ZlibSocket,
sockmod = ejabberd_zlib},
sockmod = ezlib},
?HIBERNATE_TIMEOUT};
handle_call(reset_stream, _From, State) ->
ejabberd_receiver:reset_stream(State#socket_state.receiver),

View File

@ -44,8 +44,8 @@
-include("logger.hrl").
-record(state,
{socket :: inet:socket() | tls:tls_socket() | ejabberd_zlib:zlib_socket(),
sock_mod = gen_tcp :: gen_tcp | tls | ejabberd_zlib,
{socket :: inet:socket() | tls:tls_socket() | ezlib:zlib_socket(),
sock_mod = gen_tcp :: gen_tcp | tls | ezlib,
shaper_state = none :: shaper:shaper(),
c2s_pid :: pid(),
max_stanza_size = infinity :: non_neg_integer() | infinity,
@ -99,7 +99,7 @@ starttls(Pid, TLSOpts, Data) ->
do_call(Pid, {starttls, TLSOpts, Data}).
-spec compress(pid(), iodata() | undefined) -> {error, any()} |
{ok, ejabberd_zlib:zlib_socket()}.
{ok, ezlib:zlib_socket()}.
compress(Pid, Data) -> do_call(Pid, {compress, Data}).
@ -171,7 +171,7 @@ handle_call({compress, Data}, _From,
c2s_pid = C2SPid, socket = Socket, sock_mod = SockMod,
max_stanza_size = MaxStanzaSize} =
State) ->
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(SockMod,
{ok, ZlibSocket} = ezlib:enable_zlib(SockMod,
Socket),
if Data /= undefined -> do_send(State, Data);
true -> ok
@ -180,9 +180,9 @@ handle_call({compress, Data}, _From,
NewXMLStreamState = xml_stream:new(C2SPid,
MaxStanzaSize),
NewState = State#state{socket = ZlibSocket,
sock_mod = ejabberd_zlib,
sock_mod = ezlib,
xml_stream_state = NewXMLStreamState},
case ejabberd_zlib:recv_data(ZlibSocket, <<"">>) of
case ezlib:recv_data(ZlibSocket, <<"">>) of
{ok, ZlibData} ->
{reply, {ok, ZlibSocket},
process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT};
@ -250,8 +250,8 @@ handle_info({Tag, _TCPSocket, Data},
?HIBERNATE_TIMEOUT};
{error, _Reason} -> {stop, normal, State}
end;
ejabberd_zlib ->
case ejabberd_zlib:recv_data(Socket, Data) of
ezlib ->
case ezlib:recv_data(Socket, Data) of
{ok, ZlibData} ->
{noreply, process_data(ZlibData, State),
?HIBERNATE_TIMEOUT};

View File

@ -43,11 +43,11 @@
-type sockmod() :: ejabberd_http_poll | ejabberd_bosh |
ejabberd_http_bind | ejabberd_http_bindjson |
ejabberd_http_ws | ejabberd_http_wsjson |
gen_tcp | tls | ejabberd_zlib.
gen_tcp | tls | ezlib.
-type receiver() :: pid () | atom().
-type socket() :: pid() | inet:socket() |
tls:tls_socket() |
ejabberd_zlib:zlib_socket() |
ezlib:zlib_socket() |
ejabberd_bosh:bosh_socket() |
ejabberd_http_ws:ws_socket() |
ejabberd_http_poll:poll_socket().
@ -152,7 +152,7 @@ compress(SocketData, Data) ->
ejabberd_receiver:compress(SocketData#socket_state.receiver,
Data),
SocketData#socket_state{socket = ZlibSocket,
sockmod = ejabberd_zlib}.
sockmod = ezlib}.
reset_stream(SocketData)
when is_pid(SocketData#socket_state.receiver) ->
@ -255,8 +255,8 @@ get_conn_type(#socket_state{sockmod = SockMod, socket = Socket}) ->
case SockMod of
gen_tcp -> c2s;
tls -> c2s_tls;
ejabberd_zlib ->
case ejabberd_zlib:get_sockmod(Socket) of
ezlib ->
case ezlib:get_sockmod(Socket) of
gen_tcp -> c2s_compressed;
tls -> c2s_compressed_tls
end;

View File

@ -430,7 +430,6 @@ get_handle(Name) when is_binary(Name) ->
%%%----------------------------------------------------------------------
init([Hosts, Port, Rootdn, Passwd, Opts]) ->
catch ssl:start(),
Encrypt = case gen_mod:get_opt(encrypt, Opts,
fun(tls) -> tls;
(starttls) -> starttls;

View File

@ -39,11 +39,10 @@
-ifdef(USE_IBROWSE).
start() ->
ibrowse:start(),
ssl:start().
application:start(ibrowse).
stop() ->
ibrowse:stop().
application:stop(ibrowse).
request(Method, URL, Hdrs, Body, Opts) ->
TimeOut = proplists:get_value(timeout, Opts, infinity),
@ -62,13 +61,10 @@ request(Method, URL, Hdrs, Body, Opts) ->
-ifdef(USE_LHTTPC).
start() ->
application:start(crypto),
application:start(ssl),
lhttpc:start().
application:start(lhttpc).
stop() ->
lhttpc:stop(),
application:stop(ssl).
application:stop(lhttpc).
request(Method, URL, Hdrs, Body, Opts) ->
TimeOut = proplists:get_value(timeout, Opts, infinity),
@ -86,12 +82,10 @@ request(Method, URL, Hdrs, Body, Opts) ->
-else.
start() ->
inets:start(),
ssl:start().
application:start(inets).
stop() ->
inets:stop(),
ssl:stop().
application:start(inets).
to_list(Str) when is_binary(Str) ->
binary_to_list(Str);

View File

@ -66,7 +66,6 @@ start_link(Host, Opts) ->
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
start(Host, Opts) ->
ssl:start(),
MyHosts = case catch gen_mod:get_opt(
hosts, Opts,
fun(L) when is_list(L) ->

View File

@ -69,7 +69,6 @@ preinit(Parent, State) ->
stop(_Host) -> ok.
init(State) ->
inets:start(),
ets:new(bl_c2s,
[named_table, public, {keypos, #bl_c2s.ip}]),
update_bl_c2s(),

View File

@ -99,7 +99,7 @@ stop(Host) ->
%%====================================================================
init([Host, Opts]) ->
iconv:start(),
application:start(iconv),
MyHost = gen_mod:get_opt_host(Host, Opts,
<<"irc.@HOST@">>),
case gen_mod:db_type(Opts) of

View File

@ -1,114 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : sha.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose :
%%% Created : 20 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(sha).
-author('alexey@process-one.net').
-export([start/0, sha/1, sha1/1, sha224/1, sha256/1,
sha384/1, sha512/1, to_hexlist/1]).
-ifdef(HAVE_MD2).
-export([md2/1]).
-endif.
-include("ejabberd.hrl").
-include("logger.hrl").
-define(DRIVER, sha_drv).
start() ->
crypto:start(),
Res = case erl_ddll:load_driver(ejabberd:get_so_path(),
?DRIVER)
of
ok -> ok;
{error, already_loaded} -> ok;
Err -> Err
end,
case Res of
ok ->
Port = open_port({spawn, atom_to_list(?DRIVER)},
[binary]),
register(?DRIVER, Port);
{error, Reason} ->
?CRITICAL_MSG("unable to load driver '~s': ~s",
[driver_path(), erl_ddll:format_error(Reason)])
end.
digit_to_xchar(D) when (D >= 0) and (D < 10) -> D + 48;
digit_to_xchar(D) -> D + 87.
-spec sha(binary()) -> binary().
sha(Text) ->
Bin = crypto:sha(Text),
to_hexlist(Bin).
-spec to_hexlist(binary()) -> binary().
to_hexlist(Bin) ->
iolist_to_binary(lists:reverse(ints_to_rxstr(binary_to_list(Bin), []))).
ints_to_rxstr([], Res) -> Res;
ints_to_rxstr([N | Ns], Res) ->
ints_to_rxstr(Ns,
[digit_to_xchar(N rem 16), digit_to_xchar(N div 16)
| Res]).
-spec sha1(binary()) -> binary().
-spec sha224(binary()) -> binary().
-spec sha256(binary()) -> binary().
-spec sha384(binary()) -> binary().
-spec sha512(binary()) -> binary().
sha1(Text) -> crypto:sha(Text).
sha224(Text) -> erlang:port_control(?DRIVER, 224, Text).
sha256(Text) -> erlang:port_control(?DRIVER, 256, Text).
sha384(Text) -> erlang:port_control(?DRIVER, 384, Text).
sha512(Text) -> erlang:port_control(?DRIVER, 512, Text).
-ifdef(HAVE_MD2).
-spec md2(binary()) -> binary().
md2(Text) -> erlang:port_control(?DRIVER, 2, Text).
-endif.
driver_path() ->
Suffix = case os:type() of
{win32, _} -> ".dll";
_ -> ".so"
end,
filename:join(ejabberd:get_so_path(),
atom_to_list(?DRIVER) ++ Suffix).

View File

@ -1,433 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : xml.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : XML utils
%%% Created : 20 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(xml).
-author('alexey@process-one.net').
-export([element_to_binary/1,
crypt/1, make_text_node/1, remove_cdata/1,
remove_subtags/3, get_cdata/1, get_tag_cdata/1,
get_attr/2, get_attr_s/2, get_tag_attr/2,
get_tag_attr_s/2, get_subtag/2, get_subtag_cdata/2,
append_subtags/2, get_path_s/2, start/0,
replace_tag_attr/3, to_xmlel/1]).
-include("jlib.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
%% Select at compile time how to escape characters in binary text
%% nodes.
%% Can be choosen with ./configure --enable-full-xml
-ifdef(FULL_XML_SUPPORT).
-define(ESCAPE_BINARY(CData), make_text_node(CData)).
-else.
-define(ESCAPE_BINARY(CData), crypt(CData)).
-endif.
%% Replace element_to_binary/1 with NIF
%% Can be choosen with ./configure --enable-nif
-ifdef(NIF).
start() ->
SOPath = filename:join(ejabberd:get_so_path(), "xml"),
case catch erlang:load_nif(SOPath, 0) of
ok -> ok;
Err -> ?WARNING_MSG("unable to load xml NIF: ~p", [Err])
end.
-else.
start() -> ok.
-endif.
%%
-spec(element_to_binary/1 ::
(
El :: xmlel() | cdata())
-> binary()
).
element_to_binary(El) ->
iolist_to_binary(element_to_string(El)).
%%
-spec(element_to_string/1 ::
(
El :: xmlel() | cdata())
-> string()
).
element_to_string(El) ->
case catch element_to_string_nocatch(El) of
{'EXIT', Reason} -> erlang:error({badxml, El, Reason});
Result -> Result
end.
-spec(element_to_string_nocatch/1 ::
(
El :: xmlel() | cdata())
-> iolist()
).
element_to_string_nocatch(El) ->
case El of
#xmlel{name = Name, attrs = Attrs, children = Els} ->
if Els /= [] ->
[$<, Name, attrs_to_list(Attrs), $>,
[element_to_string_nocatch(E) || E <- Els], $<, $/,
Name, $>];
true -> [$<, Name, attrs_to_list(Attrs), $/, $>]
end;
%% We do not crypt CDATA binary, but we enclose it in XML CDATA
{xmlcdata, CData} ->
?ESCAPE_BINARY(CData)
end.
attrs_to_list(Attrs) -> [attr_to_list(A) || A <- Attrs].
attr_to_list({Name, Value}) ->
[$\s, Name, $=, $', crypt(Value), $'].
crypt(S) ->
<< <<(case C of
$& -> <<"&amp;">>;
$< -> <<"&lt;">>;
$> -> <<"&gt;">>;
$" -> <<"&quot;">>;
$' -> <<"&apos;">>;
_ -> <<C>>
end)/binary>>
|| <<C>> <= S >>.
%%
-spec(make_text_node/1 ::
(
CData :: binary())
-> binary()
).
make_text_node(CData) ->
case cdata_need_escape(CData) of
cdata ->
CDATA1 = <<"<![CDATA[">>,
CDATA2 = <<"]]>">>,
iolist_to_binary([CDATA1, CData, CDATA2]);
none -> CData;
{cdata, EndTokens} ->
EscapedCData = escape_cdata(CData, EndTokens),
iolist_to_binary(EscapedCData)
end.
cdata_need_escape(CData) ->
cdata_need_escape(CData, 0, false, []).
cdata_need_escape(<<>>, _, false, _) -> none;
cdata_need_escape(<<>>, _, true, []) -> cdata;
cdata_need_escape(<<>>, _, true, CDataEndTokens) ->
{cdata, lists:reverse(CDataEndTokens)};
cdata_need_escape(<<$], $], $>, Rest/binary>>,
CurrentPosition, _XMLEscape, CDataEndTokens) ->
NewPosition = CurrentPosition + 3,
cdata_need_escape(Rest, NewPosition, true,
[CurrentPosition + 1 | CDataEndTokens]);
%% Only <, & need to be escaped in XML text node
%% See reference: http://www.w3.org/TR/xml11/#syntax
cdata_need_escape(<<$<, Rest/binary>>, CurrentPosition,
_XMLEscape, CDataEndTokens) ->
cdata_need_escape(Rest, CurrentPosition + 1, true,
CDataEndTokens);
cdata_need_escape(<<$&, Rest/binary>>, CurrentPosition,
_XMLEscape, CDataEndTokens) ->
cdata_need_escape(Rest, CurrentPosition + 1, true,
CDataEndTokens);
cdata_need_escape(<<_:8, Rest/binary>>, CurrentPosition,
XMLEscape, CDataEndTokens) ->
cdata_need_escape(Rest, CurrentPosition + 1, XMLEscape,
CDataEndTokens).
escape_cdata(CData, EndTokens) ->
escape_cdata(CData, 0, EndTokens, []).
escape_cdata(<<>>, _CurrentPosition, [], Acc) ->
lists:reverse(Acc);
escape_cdata(Rest, CurrentPosition, [], Acc) ->
CDATA1 = <<"<![CDATA[">>,
CDATA2 = <<"]]>">>,
escape_cdata(<<>>, CurrentPosition, [],
[CDATA2, Rest, CDATA1 | Acc]);
escape_cdata(CData, Index, [Pos | Positions], Acc) ->
CDATA1 = <<"<![CDATA[">>,
CDATA2 = <<"]]>">>,
Split = Pos - Index,
{Part, Rest} = split_binary(CData, Split + 1),
escape_cdata(Rest, Pos + 1, Positions,
[CDATA2, Part, CDATA1 | Acc]).
%%
-spec(remove_cdata_p/1 ::
(
El :: xmlel() | cdata())
-> boolean()
).
remove_cdata_p(#xmlel{}) -> true;
remove_cdata_p(_) -> false.
%%
-spec(remove_cdata/1 ::
(
L :: [xmlel() | cdata()])
-> [xmlel()]
).
remove_cdata(L) -> [E || E <- L, remove_cdata_p(E)].
-spec(remove_subtags/3 ::
(
Xmlel :: xmlel(),
Name :: binary(),
Attr :: attr())
-> Xmlel :: xmlel()
).
remove_subtags(#xmlel{name = TagName, attrs = TagAttrs, children = Els},
Name, Attr) ->
#xmlel{name = TagName, attrs = TagAttrs,
children = remove_subtags1(Els, [], Name, Attr)}.
%%
-spec(remove_subtags1/4 ::
(
Els :: [xmlel() | cdata()],
NewEls :: [xmlel()],
Name :: binary(),
Attr :: attr())
-> NewEls :: [xmlel()]
).
remove_subtags1([], NewEls, _Name, _Attr) ->
lists:reverse(NewEls);
remove_subtags1([El | Els], NewEls, Name,
{AttrName, AttrValue} = Attr) ->
case El of
#xmlel{name = Name, attrs = Attrs} ->
case get_attr(AttrName, Attrs) of
false ->
remove_subtags1(Els, [El | NewEls], Name, Attr);
{value, AttrValue} ->
remove_subtags1(Els, NewEls, Name, Attr);
_ -> remove_subtags1(Els, [El | NewEls], Name, Attr)
end;
_ -> remove_subtags1(Els, [El | NewEls], Name, Attr)
end.
-spec(get_cdata/1 ::
(
L :: [xmlel() | cdata()])
-> binary()
).
get_cdata(L) ->
(iolist_to_binary(get_cdata(L, <<"">>))).
-spec(get_cdata/2 ::
(
L :: [xmlel() | cdata()],
S :: binary() | iolist())
-> binary() | iolist()
).
get_cdata([{xmlcdata, CData} | L], S) ->
get_cdata(L, [S, CData]);
get_cdata([_ | L], S) -> get_cdata(L, S);
get_cdata([], S) -> S.
-spec(get_tag_cdata/1 ::
(
Xmlel :: xmlel())
-> binary()
).
get_tag_cdata(#xmlel{children = Els}) -> get_cdata(Els).
%%
-spec(get_attr/2 ::
(
AttrName :: binary(),
Attrs :: [attr()])
-> {value, binary()}
| false
).
get_attr(AttrName, Attrs) ->
case lists:keysearch(AttrName, 1, Attrs) of
{value, {_, Val}} -> {value, Val};
_ -> false
end.
%%
-spec(get_attr_s/2 ::
(
AttrName :: binary(),
Attrs :: [attr()])
-> Val :: binary()
).
get_attr_s(AttrName, Attrs) ->
case lists:keysearch(AttrName, 1, Attrs) of
{value, {_, Val}} -> Val;
_ -> <<"">>
end.
%%
-spec(get_tag_attr/2 ::
(
AttrName :: binary(),
Xmlel :: xmlel())
-> {value, binary()}
| false
).
get_tag_attr(AttrName, #xmlel{attrs = Attrs}) ->
get_attr(AttrName, Attrs).
%%
-spec(get_tag_attr_s/2 ::
(
AttrName :: binary(),
Xmlel :: xmlel())
-> binary()
).
get_tag_attr_s(AttrName, #xmlel{attrs = Attrs}) ->
get_attr_s(AttrName, Attrs).
%%
-spec(get_subtag/2 ::
(
Xmlel :: xmlel(),
Name :: binary())
-> xmlel() | false
).
get_subtag(#xmlel{children = Els}, Name) ->
get_subtag1(Els, Name).
%%
-spec(get_subtag1/2 ::
(
Els :: [xmlel() | cdata()],
Name :: binary())
-> xmlel() | false
).
get_subtag1([El | Els], Name) ->
case El of
#xmlel{name = Name} -> El;
_ -> get_subtag1(Els, Name)
end;
get_subtag1([], _) -> false.
%%
-spec(get_subtag_cdata/2 ::
(
Tag :: xmlel(),
Name :: binary())
-> binary()
).
get_subtag_cdata(Tag, Name) ->
case get_subtag(Tag, Name) of
false -> <<"">>;
Subtag -> get_tag_cdata(Subtag)
end.
%%
-spec(append_subtags/2 ::
(
Xmlel :: xmlel(),
SubTags2 :: [xmlel() | cdata()])
-> Xmlel :: xmlel()
).
append_subtags(#xmlel{name = Name, attrs = Attrs, children = SubTags1}, SubTags2) ->
#xmlel{name = Name, attrs = Attrs, children = SubTags1 ++ SubTags2}.
%%
-spec(get_path_s/2 ::
(
El :: xmlel(),
Path :: [{elem, Name::binary()}
|{attr, Name::binary()}
|cdata])
-> xmlel()
| binary()
).
get_path_s(El, []) -> El;
get_path_s(El, [{elem, Name} | Path]) ->
case get_subtag(El, Name) of
false -> <<"">>;
SubEl -> get_path_s(SubEl, Path)
end;
get_path_s(El, [{attr, Name}]) ->
get_tag_attr_s(Name, El);
get_path_s(El, [cdata]) -> get_tag_cdata(El).
%%
-spec(replace_tag_attr/3 ::
(
Name :: binary(),
Value :: binary(),
Xmlel :: xmlel())
-> Xmlel :: #xmlel{
name :: binary(),
attrs :: [attr(),...],
children :: [xmlel() | cdata()]
}
).
replace_tag_attr(Name, Value, Xmlel) ->
Xmlel#xmlel{
attrs = [{Name, Value} | lists:keydelete(Name, 1, Xmlel#xmlel.attrs)]
}.
-spec to_xmlel(xmlelement() | xmlel()) -> xmlel().
to_xmlel({_, Name, Attrs, Els}) ->
#xmlel{name = iolist_to_binary(Name),
attrs = [{iolist_to_binary(K), iolist_to_binary(V)}
|| {K, V} <- Attrs],
children = [to_xmlel(El) || El <- Els]};
to_xmlel({xmlcdata, CData}) ->
{xmlcdata, iolist_to_binary(CData)}.

View File

@ -1,246 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : xml_stream.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Parse XML streams
%%% Created : 17 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(xml_stream).
-author('alexey@process-one.net').
-export([new/1, new/2, parse/2, close/1,
change_callback_pid/2, parse_element/1]).
-define(XML_START, 0).
-define(XML_END, 1).
-define(XML_CDATA, 2).
-define(XML_ERROR, 3).
-define(PARSE_COMMAND, 0).
-define(PARSE_FINAL_COMMAND, 1).
-record(xml_stream_state,
{callback_pid = self() :: pid(),
port :: port(),
stack = [] :: stack(),
size = 0 :: non_neg_integer(),
maxsize = infinity :: non_neg_integer() | infinity}).
-type xml_stream_el() :: {xmlstreamraw, binary()} |
{xmlstreamcdata, binary()} |
{xmlstreamelement, xmlel()} |
{xmlstreamend, binary()} |
{xmlstreamstart, binary(), [attr()]} |
{xmlstreamerror, binary()}.
-type xml_stream_state() :: #xml_stream_state{}.
-type stack() :: [xmlel()].
-type event() :: {?XML_START, {binary(), [attr()]}} |
{?XML_END, binary()} |
{?XML_CDATA, binary()} |
{?XML_ERROR, binary()}.
-export_type([xml_stream_state/0, xml_stream_el/0]).
-include("jlib.hrl").
process_data(CallbackPid, Stack, Data) ->
case Data of
{?XML_START, {Name, Attrs}} ->
if
Stack == [] ->
catch gen_fsm:send_event(CallbackPid,
{xmlstreamstart, Name, Attrs}),
%% There is no need to store name or attributes of
%% stream opening element as it is not used
%% anymore.
[xmlstreamstart];
true ->
[#xmlel{name = Name, attrs = Attrs, children = []}
| Stack]
end;
{?XML_END, EndName} ->
case Stack of
[xmlstreamstart] ->
catch gen_fsm:send_event(CallbackPid,
{xmlstreamend, EndName}),
[];
[#xmlel{name = Name, attrs = Attrs, children = Els},
xmlstreamstart] ->
NewEl = #xmlel{name = Name, attrs = Attrs,
children = lists:reverse(Els)},
catch gen_fsm:send_event(CallbackPid,
{xmlstreamelement, NewEl}),
[xmlstreamstart];
[#xmlel{name = Name, attrs = Attrs, children = Els},
#xmlel{name = Name1, attrs = Attrs1, children = Els1}
| Tail] ->
NewEl = #xmlel{name = Name, attrs = Attrs,
children = lists:reverse(Els)},
[{xmlel, Name1, Attrs1, [NewEl | Els1]} | Tail]
end;
{?XML_CDATA, CData} ->
case Stack of
[xmlstreamstart] ->
catch gen_fsm:send_all_state_event(CallbackPid,
{xmlstreamcdata, CData}),
[xmlstreamstart];
%% Merge CDATA nodes if they are contiguous
%% This does not change the semantic: the split in
%% several CDATA nodes depends on the TCP/IP packet
%% fragmentation
[#xmlel{name = Name, attrs = Attrs,
children = [{xmlcdata, PreviousCData} | Els]}
| Tail] ->
[#xmlel{name = Name, attrs = Attrs,
children =
[{xmlcdata,
iolist_to_binary([PreviousCData, CData])}
| Els]}
| Tail];
%% No previous CDATA
[#xmlel{name = Name, attrs = Attrs, children = Els}
| Tail] ->
[#xmlel{name = Name, attrs = Attrs,
children = [{xmlcdata, CData} | Els]}
| Tail];
[] -> []
end;
{?XML_ERROR, Err} ->
catch gen_fsm:send_event(CallbackPid,
{xmlstreamerror, Err})
end.
-spec new(pid()) -> xml_stream_state().
new(CallbackPid) -> new(CallbackPid, infinity).
-spec new(pid(), non_neg_integer() | infinity) -> xml_stream_state().
new(CallbackPid, MaxSize) ->
Port = open_port({spawn, "expat_erl"}, [binary]),
#xml_stream_state{callback_pid = CallbackPid,
port = Port, stack = [], size = 0, maxsize = MaxSize}.
-spec change_callback_pid(xml_stream_state(), pid()) -> xml_stream_state().
change_callback_pid(State, CallbackPid) ->
State#xml_stream_state{callback_pid = CallbackPid}.
-spec parse(xml_stream_state(), iodata()) -> xml_stream_state().
parse(#xml_stream_state{callback_pid = CallbackPid,
port = Port, stack = Stack, size = Size,
maxsize = MaxSize} =
State,
Str) ->
StrSize = byte_size(Str),
Res = port_control(Port, ?PARSE_COMMAND, Str),
{NewStack, NewSize} = lists:foldl(fun (Data,
{St, Sz}) ->
NewSt = process_data(CallbackPid,
St, Data),
case NewSt of
[_] -> {NewSt, 0};
_ -> {NewSt, Sz}
end
end,
{Stack, Size + StrSize},
binary_to_term(Res)),
if NewSize > MaxSize ->
catch gen_fsm:send_event(CallbackPid,
{xmlstreamerror,
<<"XML stanza is too big">>});
true -> ok
end,
State#xml_stream_state{stack = NewStack,
size = NewSize}.
-spec close(xml_stream_state()) -> true.
close(#xml_stream_state{port = Port}) ->
port_close(Port).
-spec parse_element(iodata()) -> xmlel() |
{error, parse_error} |
{error, binary()}.
parse_element(Str) ->
Port = open_port({spawn, "expat_erl"}, [binary]),
Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str),
port_close(Port),
process_element_events(binary_to_term(Res)).
process_element_events(Events) ->
process_element_events(Events, []).
-spec process_element_events([event()], stack()) -> xmlel() |
{error, parse_error} |
{error, binary()}.
process_element_events([], _Stack) ->
{error, parse_error};
process_element_events([Event | Events], Stack) ->
case Event of
{?XML_START, {Name, Attrs}} ->
process_element_events(Events,
[#xmlel{name = Name, attrs = Attrs,
children = []}
| Stack]);
{?XML_END, _EndName} ->
case Stack of
[#xmlel{name = Name, attrs = Attrs, children = Els}
| Tail] ->
NewEl = #xmlel{name = Name, attrs = Attrs,
children = lists:reverse(Els)},
case Tail of
[] ->
if Events == [] -> NewEl;
true -> {error, parse_error}
end;
[#xmlel{name = Name1, attrs = Attrs1, children = Els1}
| Tail1] ->
process_element_events(Events,
[#xmlel{name = Name1,
attrs = Attrs1,
children = [NewEl | Els1]}
| Tail1])
end
end;
{?XML_CDATA, CData} ->
case Stack of
[#xmlel{name = Name, attrs = Attrs, children = Els}
| Tail] ->
process_element_events(Events,
[#xmlel{name = Name, attrs = Attrs,
children =
[{xmlcdata, CData} | Els]}
| Tail]);
[] -> process_element_events(Events, [])
end;
{?XML_ERROR, Err} -> {error, Err}
end.