Improve build procedure
This commit is contained in:
parent
d1c654a7e1
commit
04f20a21fb
|
@ -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
|
||||
|
|
17
Makefile.in
17
Makefile.in
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
120
c_src/sha_drv.c
120
c_src/sha_drv.c
|
@ -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;
|
||||
}
|
261
c_src/xml.c
261
c_src/xml.c
|
@ -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, "&", 5);
|
||||
break;
|
||||
case '<':
|
||||
buf_add_str(env, rbuf, "<", 4);
|
||||
break;
|
||||
case '>':
|
||||
buf_add_str(env, rbuf, ">", 4);
|
||||
break;
|
||||
case '"':
|
||||
buf_add_str(env, rbuf, """, 6);
|
||||
break;
|
||||
case '\'':
|
||||
buf_add_str(env, rbuf, "'", 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)
|
57
configure.ac
57
configure.ac
|
@ -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,
|
||||
|
|
|
@ -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">>).
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
114
src/sha.erl
114
src/sha.erl
|
@ -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).
|
433
src/xml.erl
433
src/xml.erl
|
@ -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
|
||||
$& -> <<"&">>;
|
||||
$< -> <<"<">>;
|
||||
$> -> <<">">>;
|
||||
$" -> <<""">>;
|
||||
$' -> <<"'">>;
|
||||
_ -> <<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)}.
|
|
@ -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.
|
Loading…
Reference in New Issue