Commit 9878019a authored by Alain Takoudjou's avatar Alain Takoudjou

Merge branch 'davstorage-ajaxplorer' into grid-computing

parents 26db4381 31c3b8b7
...@@ -21,9 +21,9 @@ md5sum = ffee70a111fd07372982b0550bbb14b7 ...@@ -21,9 +21,9 @@ md5sum = ffee70a111fd07372982b0550bbb14b7
[apr-util] [apr-util]
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
version = 1.5.1 version = 1.5.2
url = http://mir2.ovh.net/ftp.apache.org/dist/apr/apr-util-${:version}.tar.bz2 url = http://mir2.ovh.net/ftp.apache.org/dist/apr/apr-util-${:version}.tar.bz2
md5sum = 9c1db8606e520f201c451ec9a0b095f6 md5sum = 89c1348aa79e898d7c34a6206311c9c2
[apache] [apache]
# inspired on http://old.aclark.net/team/aclark/blog/a-lamp-buildout-for-wordpress-and-other-php-apps/ # inspired on http://old.aclark.net/team/aclark/blog/a-lamp-buildout-for-wordpress-and-other-php-apps/
......
...@@ -11,9 +11,43 @@ parts = postfix ...@@ -11,9 +11,43 @@ parts = postfix
[postfix] [postfix]
recipe = slapos.recipe.cmmi recipe = slapos.recipe.cmmi
url = ftp://ftp.porcupine.org/mirrors/postfix-release/official/postfix-2.8.3.tar.gz url = http://cdn.postfix.johnriley.me/mirrors/postfix-release/official/postfix-2.10.0.tar.gz
md5sum = b3922ededd3fd6051f759e58a4ada3ae #md5sum = b3922ededd3fd6051f759e58a4ada3ae
location = ${buildout:parts-directory}/${:_buildout_section_name_} location = ${buildout:parts-directory}/${:_buildout_section_name_}
configure-command = make configure-command = make
configure-options = makefiles CCARGS='-DUSE_TLS -DHAS_PCRE -DHAS_DB -I${libdb:location}/include -I${pcre:location}/include -I${openssl:location}/include' AUXLIBS='-L${openssl:location}/lib -L${pcre:location}/lib -L${libdb:location}/lib -lssl -lpcre -ldb -lcrypto -Wl,-rpath=${openssl:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${libdb:location}/lib' configure-options = makefiles CCARGS='-DUSE_TLS -DHAS_PCRE -DHAS_DB -I${libdb:location}/include -I${pcre:location}/include -I${openssl:location}/include' AUXLIBS='-L${openssl:location}/lib -L${pcre:location}/lib -L${libdb:location}/lib -lssl -lpcre -ldb -lcrypto -Wl,-rpath=${openssl:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${libdb:location}/lib'
make-targets = non-interactive-package install_root=${:location} make-targets = non-interactive-package install_root=${:location}
patch-options = -p1
patches =
${initgroups.patch:location}/${initgroups.patch:filename}
${session.patch:location}/${session.patch:filename}
${noroot.patch:location}/${noroot.patch:filename}
${libdb.patch:location}/${libdb.patch:filename}
[initgroups.patch]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
filename = initgroups.patch
download-only = true
md5sum = b1e509d978c566d1b4b5c8415dfe2f91
[session.patch]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
filename = session.patch
download-only = true
md5sum = 41af4ac75d9bafc85385f0688727bf45
[noroot.patch]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
filename = noroot.patch
download-only = true
md5sum = 2e73b29c4e07bc7c933b62ab5fae20de
[libdb.patch]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
filename = libdb.patch
download-only = true
#md5sum = 9ecec894597f35a38bdaded881af561b
--- a/src/util/chroot_uid.c
+++ b/src/util/chroot_uid.c
@@ -57,8 +57,8 @@ void chroot_uid(const char *root_dir, const char *user_name)
gid = pwd->pw_gid;
if (setgid(gid) < 0)
msg_fatal("setgid(%ld): %m", (long) gid);
- if (initgroups(user_name, gid) < 0)
- msg_fatal("initgroups: %m");
+ /*if (initgroups(user_name, gid) < 0)
+ msg_fatal("initgroups: %m");*/
}
/*
diff --git a/makedefs b/makedefs
index 93b5949..9209a61 100644
--- a/makedefs
+++ b/makedefs
@@ -290,7 +290,6 @@ case "$SYSTEM.$RELEASE" in
# by including <db.h> and by linking with -ldb
echo "No <db.h> include file found." 1>&2
echo "Install the appropriate db*-devel package first." 1>&2
- exit 1
fi
SYSLIBS="-ldb"
;;
@@ -361,7 +360,6 @@ EOF
# by including <db.h> and by linking with -ldb
echo "No <db.h> include file found." 1>&2
echo "Install the appropriate db*-devel package first." 1>&2
- exit 1
fi
SYSLIBS="-ldb"
;;
--- a/src/util/set_ugid.c
+++ b/src/util/set_ugid.c
@@ -44,7 +44,7 @@
void set_ugid(uid_t uid, gid_t gid)
{
- int saved_errno = errno;
+/* int saved_errno = errno;
if (geteuid() != 0)
if (seteuid(0) < 0)
@@ -58,4 +58,4 @@ void set_ugid(uid_t uid, gid_t gid)
if (msg_verbose > 1)
msg_info("setugid: uid %ld gid %ld", (long) uid, (long) gid);
errno = saved_errno;
-}
+*/}
--- a/src/util/set_eugid.c
+++ b/src/util/set_eugid.c
@@ -53,7 +53,7 @@
void set_eugid(uid_t euid, gid_t egid)
{
- int saved_errno = errno;
+/* int saved_errno = errno;
if (geteuid() != 0)
if (seteuid(0))
@@ -67,4 +67,4 @@ void set_eugid(uid_t euid, gid_t egid)
if (msg_verbose)
msg_info("set_eugid: euid %ld egid %ld", (long) euid, (long) egid);
errno = saved_errno;
-}
+*/}
--- a/src/postfix/postfix.c
+++ b/src/postfix/postfix.c
@@ -448,12 +448,12 @@ int main(int argc, char **argv)
* privileges for selected operations. That's right - it takes privileges
* to toss privileges.
*/
- if (getuid() != 0) {
+ /*if (getuid() != 0) {
msg_error("to submit mail, use the Postfix sendmail command");
msg_fatal("the postfix command is reserved for the superuser");
}
if (unsafe() != 0)
- msg_fatal("the postfix command must not run as a set-uid process");
+ msg_fatal("the postfix command must not run as a set-uid process");*/
/*
* Parse switches.
--- a/src/global/mail_params.c
+++ b/src/global/mail_params.c
@@ -709,7 +709,9 @@ void mail_params_init()
check_default_privs();
check_mail_owner();
check_sgid_group();
+ /*
check_overlap();
+ */
#ifdef HAS_DB
dict_db_cache_size = var_db_read_buf;
#endif
--- a/src/master/master.c
+++ b/src/master/master.c
@@ -315,10 +315,10 @@ int main(int argc, char **argv)
* privileges for selected operations. That's right - it takes privileges
* to toss privileges.
*/
- if (getuid() != 0)
+ /*if (getuid() != 0)
msg_fatal("the master command is reserved for the superuser");
if (unsafe() != 0)
- msg_fatal("the master command must not run as a set-uid process");
+ msg_fatal("the master command must not run as a set-uid process");*/
/*
* Process JCL.
--- a/src/postsuper/postsuper.c
+++ b/src/postsuper/postsuper.c
@@ -1150,10 +1150,10 @@ int main(int argc, char **argv)
* the secondary groups, the process environment, and so on. Otherwise,
* accidents can happen. If not with Postfix, then with other software.
*/
- if (unsafe() != 0)
+ /*if (unsafe() != 0)
msg_fatal("this postfix command must not run as a set-uid process");
if (getuid())
- msg_fatal("use of this command is reserved for the superuser");
+ msg_fatal("use of this command is reserved for the superuser");*/
/*
* Parse JCL.
--- a/src/master/master.c
+++ b/src/master/master.c
@@ -392,8 +392,10 @@ int main(int argc, char **argv)
* all MTA processes cleanly. Give up if we can't separate from our
* parent process. We're not supposed to blow away the parent.
*/
+ /*
if (debug_me == 0 && master_detach != 0 && setsid() == -1 && getsid(0) != getpid())
msg_fatal("unable to set session and process group ID: %m");
+ */
/*
* Make some room for plumbing with file descriptors. XXX This breaks
...@@ -84,6 +84,7 @@ setup(name=name, ...@@ -84,6 +84,7 @@ setup(name=name,
'certificate_authority = slapos.recipe.certificate_authority:Recipe', 'certificate_authority = slapos.recipe.certificate_authority:Recipe',
'certificate_authority.request = slapos.recipe.certificate_authority:Request', 'certificate_authority.request = slapos.recipe.certificate_authority:Request',
'check_page_content = slapos.recipe.check_page_content:Recipe', 'check_page_content = slapos.recipe.check_page_content:Recipe',
'check_page_content_phantomjs = slapos.recipe.check_page_content:PhantomJSRecipe',
'check_port_listening = slapos.recipe.check_port_listening:Recipe', 'check_port_listening = slapos.recipe.check_port_listening:Recipe',
'check_url_available = slapos.recipe.check_url_available:Recipe', 'check_url_available = slapos.recipe.check_url_available:Recipe',
'cloud9 = slapos.recipe.cloud9:Recipe', 'cloud9 = slapos.recipe.cloud9:Recipe',
......
...@@ -49,3 +49,26 @@ class Recipe(GenericBaseRecipe): ...@@ -49,3 +49,26 @@ class Recipe(GenericBaseRecipe):
) )
return [promise] return [promise]
class PhantomJSRecipe(GenericBaseRecipe):
"""
Create script for checking page content at url with js script
"""
def install(self):
config = {
'script-path': self.options['script-path'].strip(),
'dash-path': self.options['dash-path'].strip(),
'phantomjs-path': self.options['phantomjs-path'].strip(),
'phantomjs-options': self.options.get('phantomjs-options','')
}
promise = self.createExecutable(
self.options['path'].strip(),
self.substituteTemplate(
self.getTemplateFilename('check_page_content_phantomjs.in'),
config
)
)
return [promise]
\ No newline at end of file
#!%(dash-path)s
# BEWARE: This file is operated by slapgrid
# BEWARE: It will be overwritten automatically
%(phantomjs-path)s %(phantomjs-options)s %(script-path)s
if [ $? != 0 ]; then
echo "PhantomJS script returned non zero output" >&2
exit 1
fi
\ No newline at end of file
...@@ -34,9 +34,6 @@ from slapos.recipe.librecipe import GenericBaseRecipe ...@@ -34,9 +34,6 @@ from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe): class Recipe(GenericBaseRecipe):
def _options(self, options):
options['password'] = self.generatePassword()
def install(self): def install(self):
path_list = [] path_list = []
......
...@@ -13,11 +13,16 @@ extends = ...@@ -13,11 +13,16 @@ extends =
../../component/lxml-python/buildout.cfg ../../component/lxml-python/buildout.cfg
../../component/python-2.7/buildout.cfg ../../component/python-2.7/buildout.cfg
../../component/gzip/buildout.cfg ../../component/gzip/buildout.cfg
../../component/postfix/buildout.cfg
../../component/phantomjs/buildout.cfg
find-links += find-links +=
http://www.nexedi.org/static/packages/source/slapos.buildout/ http://www.nexedi.org/static/packages/source/slapos.buildout/
http://www.nexedi.org/static/packages/source/ http://www.nexedi.org/static/packages/source/
http://www.nexedi.org/static/packages/source/hexagonit.recipe.download/ http://www.nexedi.org/static/packages/source/hexagonit.recipe.download/
# SlapOS eggs directory can be used (for libnetworkcache especially)
# when there is no access to pypi
/opt/slapos/eggs/
# Use only quite well working sites. # Use only quite well working sites.
allow-hosts += allow-hosts +=
...@@ -37,9 +42,23 @@ allow-hosts += ...@@ -37,9 +42,23 @@ allow-hosts +=
www.owlfish.com www.owlfish.com
parts = parts =
postfix
apache-php apache-php
application application
template template
bootstrap-conf
boot-conf-manifest
configuration-js-template
core-ajaxplorer-manifest
mailer-plugin-template
share-url-generation-template
postfix-service-template
sendmail-script-template
postfix-conf-template
postfix-master-conf-template
test-ajaxplorer-js-template
test-sendmail-php-template
postfix-promise-template
lxml-python lxml-python
eggs eggs
instance-recipe-egg instance-recipe-egg
...@@ -61,8 +80,8 @@ eggs = ${instance-recipe:egg} ...@@ -61,8 +80,8 @@ eggs = ${instance-recipe:egg}
[application] [application]
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
url = http://garr.dl.sourceforge.net/project/ajaxplorer/ajaxplorer/dev-channel/4.3.4/ajaxplorer-core-4.3.4.tar.gz url = http://downloads.sourceforge.net/project/ajaxplorer/ajaxplorer/stable-channel/5.0.2/ajaxplorer-core-5.0.2.tar.gz
md5sum = 2f2ff8bda7bbe841ef0e870c724eb74f md5sum = ac5490921b877cd99ba302938b3cfbc7
strip-top-level-dir = true strip-top-level-dir = true
[template] [template]
...@@ -76,9 +95,117 @@ mode = 0644 ...@@ -76,9 +95,117 @@ mode = 0644
[instance-davstorage] [instance-davstorage]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-davstorage.cfg url = ${:_profile_base_location_}/instance-davstorage.cfg
md5sum = 699ecf4678386667f58a3391bab7af0f md5sum = 740875e43048b25278e0ebbfa9b56af7
output = ${buildout:directory}/template-davstorage.cfg output = ${buildout:directory}/template-davstorage.cfg
mode = 0644 mode = 0644
[bootstrap-conf]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/${:filename}
filename = bootstrap_conf.php
translation = fr_FR.UTF-8
output = ${application:location}/conf/${:filename}
mode = 0644
md5sum = f8bbf14507f9c22d7b69696345e57c2e
[boot-conf-manifest]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/${:filename}
filename = boot-conf-manifest.xml.in
language = fr
mode = 0644
md5sum = 856e39c6bf42dd28a593c45b966b97d1
output = ${application:location}/plugins/boot.conf/manifest.xml
[core-ajaxplorer-manifest]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/${:filename}
filename = core-ajaxplorer-manifest.xml.in
language = fr
php-cli-location = ${apache-php:location}/bin/php
mode = 0644
md5sum = ebdd3789aa65ed33130481c487018d6e
output = ${application:location}/plugins/core.ajaxplorer/manifest.xml
[configuration-js-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = configuration.js
mode = 0644
md5sum = 792917aea5bafdc9a973a9071ae89ec6
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[mailer-plugin-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = class.phpmailer-lite.php
mode = 0644
md5sum = 4649b152e1f639873a03149eccc70aaf
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[share-url-generation-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = class.AJXP_Utils.php
mode = 0644
md5sum = f681c0a0a17f4b2a0896b952e53239ed
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[postfix-service-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = postfix.in
mode = 0755
md5sum = 9f136d6c217f26e06f7437ceeb7b0c42
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[sendmail-script-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = sendmail.in
mode = 0755
md5sum = d2ea9ecfd653dcb0bd06c06bcaabc5df
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[postfix-conf-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = main.cf.in
mode = 0644
md5sum = a72b679c523f587422f95d295de27876
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[postfix-master-conf-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = master.cf.in
mode = 0644
md5sum = de33aa9ef530ef3c7661b914d2d1fbef
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[test-ajaxplorer-js-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = test-boot.js
mode = 0644
md5sum = a6a98bf3c9fcb6c330dea513d13eb054
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[test-sendmail-php-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = test-sendmail.php
mode = 0644
md5sum = ab19eff22b50fbab18879f7b96ae7e8e
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[postfix-promise-template]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = test-postfix.sh.in
mode = 0644
md5sum = d725575994cd871e6c6c419603605fe5
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[lxml-python] [lxml-python]
python = python2.7 python = python2.7
...@@ -31,64 +31,3 @@ update-command = ${:command} ...@@ -31,64 +31,3 @@ update-command = ${:command}
command = command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link && grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
[versions]
zc.buildout = 1.6.0-dev-SlapOS-002
Jinja2 = 2.6
Werkzeug = 0.8.3
buildout-versions = 1.7
hexagonit.recipe.cmmi = 1.6
hexagonit.recipe.download = 1.6nxd002
meld3 = 0.6.10
openssl = 1.0.1c
# Required by:
# slapos.core
Flask = 0.9
# Required by:
# slapos.cookbook
PyXML = 0.8.4
slapos.recipe.template = 2.4.2
# Required by:
# slapos.cookbook==0.24
# slapos.core==0.14
# xml-marshaller==0.9.7
lxml = 3.1.0
# Required by:
# slapos.cookbook==0.24
netaddr = 0.7.10
# Required by:
# slapos.core==0.14
netifaces = 0.8
# Required by:
# slapos.cookbook==0.24
# slapos.core==0.14
# zc.buildout==1.5.3-dev-SlapOS-009
# zc.recipe.egg==1.3.2
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.cookbook==0.73.1
slapos.core = 0.35.1
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.cookbook==0.73.1
xml-marshaller = 0.9.7
# Required by:
# slapos.cookbook==0.24
zc.recipe.egg = 1.3.2
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
...@@ -8,7 +8,17 @@ parts = ...@@ -8,7 +8,17 @@ parts =
cron-entry-logrotate cron-entry-logrotate
logrotate logrotate
logrotate-entry-davstorage logrotate-entry-davstorage
request-frontend copy-app
mailer-plugin
share-url-generation
configuration-promise
postfix-conf
postfix-users
postfix-master-conf
postfix-service
ajaxplorer-load-promise
test-sendmail-php
postfix-promise
eggs-directory = ${buildout:eggs-directory} eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory} develop-eggs-directory = ${buildout:develop-eggs-directory}
...@@ -16,15 +26,20 @@ offline = true ...@@ -16,15 +26,20 @@ offline = true
[publish-connection-informations] [publish-connection-informations]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
webdav_access = https://$${request-frontend:connection-domain} webdav_access = $${request-frontend:config-url}
url = https://$${request-frontend-ajaxupload:connection-domain} url = $${request-frontend-ajaxupload:config-url}
webdav_user = $${davstorage:user} webdav_user = $${davstorage:user}
webdav_password = $${davstorage:password} webdav_password = $${davstorage:password}
[pass-generation]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:etc}/.passwd
bytes = 4
[davstorage] [davstorage]
recipe = slapos.cookbook:davstorage recipe = slapos.cookbook:davstorage
user = user user = user
password = insecure password = $${pass-generation:passwd}
port_webdav = 8080 port_webdav = 8080
port_ajax = 8070 port_ajax = 8070
ip = $${slap-network-information:global-ipv6} ip = $${slap-network-information:global-ipv6}
...@@ -157,6 +172,146 @@ cronstamps = $${rootdirectory:etc}/cronstamps/ ...@@ -157,6 +172,146 @@ cronstamps = $${rootdirectory:etc}/cronstamps/
cronoutput = $${basedirectory:log}/cron/ cronoutput = $${basedirectory:log}/cron/
php-ini-dir = $${rootdirectory:etc}/php php-ini-dir = $${rootdirectory:etc}/php
tmp-php = $${rootdirectory:tmp}/php tmp-php = $${rootdirectory:tmp}/php
postfix-conf = $${rootdirectory:etc}/postfix
spool = $${rootdirectory:var}/spool/postfix
data = $${rootdirectory:var}/lib/postfix
maildrop = $${directory:spool}/maildrop
active = $${directory:spool}/active
bounce = $${directory:spool}/bounce
corrupt = $${directory:spool}/corrupt
defer = $${directory:spool}/defer
deferred = $${directory:spool}/deferred
flush = $${directory:spool}/flush
hold = $${directory:spool}/hold
incoming = $${directory:spool}/incoming
private = $${directory:spool}/private
public = $${directory:spool}/public
pid = $${directory:spool}/pid
saved = $${directory:spool}/saved
trace = $${directory:spool}/trace
promise-js = $${rootdirectory:etc}/js/
[copy-app]
recipe = plone.recipe.command
update-command = command
command = cp -R ${application:location}/* $${directory:htdocs}
[mailer-plugin]
recipe = slapos.recipe.template
url = ${mailer-plugin-template:location}/${mailer-plugin-template:filename}
sendmail-script = $${sendmail-script:output}
output = $${directory:htdocs}/plugins/mailer.phpmailer-lite/lib/${mailer-plugin-template:filename}
mode = 0644
md5sum = 4649b152e1f639873a03149eccc70aaf
[share-url-generation]
recipe = slapos.recipe.template
url = ${share-url-generation-template:location}/${share-url-generation-template:filename}
output = $${directory:htdocs}/core/classes/${share-url-generation-template:filename}
mode = 0644
md5sum = f681c0a0a17f4b2a0896b952e53239ed
[configuration-js]
recipe = slapos.recipe.template
url = ${configuration-js-template:location}/${configuration-js-template:filename}
content-url = https://[$${davstorage:ip}]:$${davstorage:port_ajax}/
user = $${davstorage:user}
password = $${davstorage:password}
storage-type = serial
output = $${directory:promise-js}/${configuration-js-template:filename}
mode = 0644
md5sum = 792917aea5bafdc9a973a9071ae89ec6
[configuration-promise]
recipe = slapos.cookbook:check_page_content_phantomjs
path = $${basedirectory:promises}/configuration-promise
dash-path = ${dash:location}/bin/dash
phantomjs-path = ${phantomjs:location}/phantomjs-slapos
phantomjs-options = --ignore-ssl-errors=true
script-path = $${configuration-js:output}
[postfix-service]
recipe = slapos.recipe.template
url = ${postfix-service-template:location}/${postfix-service-template:filename}
python-location = ${python2.7:executable}
postfix-location = ${postfix:location}/usr/sbin/postfix
postfix-config-dir = $${directory:postfix-conf}
pid-location = $${directory:pid}/master.pid
output = $${basedirectory:services}/postfix
mode = 0755
md5sum = 9f136d6c217f26e06f7437ceeb7b0c42
[sendmail-script]
recipe = slapos.recipe.template
url = ${sendmail-script-template:location}/${sendmail-script-template:filename}
sendmail-location = ${postfix:location}/usr/sbin/sendmail
postfix-config-dir = $${directory:postfix-conf}
output = $${rootdirectory:bin}/sendmail
mode = 0755
md5sum = d2ea9ecfd653dcb0bd06c06bcaabc5df
[postfix-conf]
recipe = slapos.recipe.template
url = ${postfix-conf-template:location}/${postfix-conf-template:filename}
queue-directory = $${directory:spool}
command-directory = ${postfix:location}/usr/sbin
bin-directory = ${postfix:location}/usr/bin
daemon-directory = ${postfix:location}/usr/libexec/postfix
data-directory = $${directory:data}
mail-owner = $${slap-connection:partition-id}
mail-group = $${slap-connection:partition-id}
ipv4 = $${slap-network-information:global-ipv6}
output = $${directory:postfix-conf}/main.cf
mode = 0644
md5sum = a72b679c523f587422f95d295de27876
[postfix-users]
recipe = plone.recipe.command
update-command = $${:command}
command = sed 's/ slappart/ slapuser/g' $${postfix-conf:output} > main.tmp && mv main.tmp $${postfix-conf:output}
[postfix-master-conf]
recipe = slapos.recipe.template
url = ${postfix-master-conf-template:location}/${postfix-master-conf-template:filename}
port = 2525
output = $${directory:postfix-conf}/master.cf
mode = 0644
md5sum = de33aa9ef530ef3c7661b914d2d1fbef
[ajaxplorer-load-js]
recipe = slapos.recipe.template
url = ${test-ajaxplorer-js-template:location}/${test-ajaxplorer-js-template:filename}
content-url = https://[$${davstorage:ip}]:$${davstorage:port_ajax}/
mode = 0644
md5sum = a6a98bf3c9fcb6c330dea513d13eb054
output = $${directory:promise-js}/test-boot.js
[ajaxplorer-load-promise]
recipe = slapos.cookbook:check_page_content_phantomjs
path = $${basedirectory:promises}/ajaxplorer-load-promise
dash-path = ${dash:location}/bin/dash
phantomjs-path = ${phantomjs:location}/phantomjs-slapos
phantomjs-options = --ignore-ssl-errors=true
script-path = $${ajaxplorer-load-js:output}
[test-sendmail-php]
recipe = slapos.recipe.template
url = ${test-sendmail-php-template:location}/${test-sendmail-php-template:filename}
php-location = ${apache-php:location}/bin/php
htdocs-location = $${directory:htdocs}
output = $${rootdirectory:bin}/test-sendmail.php
mode = 0755
md5sum = ab19eff22b50fbab18879f7b96ae7e8e
[postfix-promise]
recipe = slapos.recipe.template
url = ${postfix-promise-template:location}/${postfix-promise-template:filename}
dash-path = ${dash:location}/bin/dash
test-sendmail-php-location = $${test-sendmail-php:output}
sendmail-binary = $${sendmail-script:output}
output = $${basedirectory:promises}/postfix-promise
md5sum = d725575994cd871e6c6c419603605fe5
mode = 0755
# Request frontend # Request frontend
[request-frontend-ajaxupload] [request-frontend-ajaxupload]
...@@ -182,11 +337,3 @@ config = url https-only ...@@ -182,11 +337,3 @@ config = url https-only
config-https-only = true config-https-only = true
config-url = https://$${davstorage:user}:$${davstorage:password}@[$${davstorage:ip}]:$${davstorage:port_webdav}/ config-url = https://$${davstorage:user}:$${davstorage:password}@[$${davstorage:ip}]:$${davstorage:port_webdav}/
return = domain return = domain
# XXX Vivien: promise not working for now
#[frontend-ajaxupload-promise]
#recipe = slapos.cookbook:check_url_available
#path = $${basedirectory:promises}/frontend-ajaxupload
#url = $${request-frontend-ajaxupload:connection-site_url}
#dash_path = ${dash:location}/bin/dash
#curl_path = ${curl:location}/bin/curl
\ No newline at end of file
...@@ -15,14 +15,15 @@ develop = ...@@ -15,14 +15,15 @@ develop =
[slapos.cookbook-repository] [slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git repository = http://git.erp5.org/repos/slapos.git
branch = davstorage-ajaxplorer
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
revision = 7600ecfc14371d6e056c1183599071dbdbd2e422
[slapos.toolbox-repository] [slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = master #branch = master
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
revision = fc91b7f26c2fd69cedafcef9de3c8b22a50f8976
[check-recipe] [check-recipe]
recipe = plone.recipe.command recipe = plone.recipe.command
...@@ -32,6 +33,67 @@ command = ...@@ -32,6 +33,67 @@ command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link && grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Cedric de Saint Martin
# Test Agent
# Vivien Alger
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIACQp7qF07DMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtODA2MCAXDTEzMDgxNDA3NTk1OFoYDzIxMTMwNzIxMDc1OTU4WjAT
MREwDwYDVQQDDAhDT01QLTgwNjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
yHenWBs1C3Rvni+EhIczG1skTm7o7f0MCIcyai7vFYzIDcgZxDM7fw//NEPGwVJG
4qtBCxYpJuNROrKtzAXRWaUGIrDpo+yhBnJgNTeNs5KQwJmex0cBFr+/dWSC2jmz
qmOS1Lk0hCq32rXgHmZlceUy+oLcdM2MahVxPYFN3CcCAwEAAaNQME4wHQYDVR0O
BBYEFMDgRs2W21Y+ptHYLE5MQ/85LOckMB8GA1UdIwQYMBaAFMDgRs2W21Y+ptHY
LE5MQ/85LOckMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAmyLpm5GA
hj1U8xwPVCLRPLg5vNjA+3jvCIFUJV602Vt+t+8V4CzKWNP7BOAIeDcsjCmtYah6
75NWNr2sleZYOdSuA5hSv09q9EZX35gMvMZK0Ha3xKI09HT6W+sfT8hcRBq/x1Sc
Z7G7Dhp4H3B+Vo8J4ngYb6YWPfCI4qsJZC0=
-----END CERTIFICATE-----
[versions] [versions]
zc.buildout = 1.6.0-dev-SlapOS-002 zc.buildout = 1.6.0-dev-SlapOS-002
Jinja2 = 2.6 Jinja2 = 2.6
......
<?xml version="1.0" encoding="UTF-8"?>
<ajxp_plugin label="CONF_MESSAGE[]" description="CONF_MESSAGE[]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="file:../core.ajaxplorer/ajxp_registry.xsd" mixins="dibidriver_provider" id="boot.conf">
<class_definition classname="BootConfLoader" filename="plugins/boot.conf/class.BootConfLoader.php" />
<client_settings>
<resources>
<i18n namespace="installer" path="plugins/boot.conf/i18n"/>
</resources>
</client_settings>
<server_settings>
<global_param group="&lt;span class='icon-key'&gt;&lt;/span&gt; Admin access" name="adminLegend" type="legend" label="" description="Please set up a login and password for the administrator user. This step is necessary to let you login the first time. You can create more administrators later by going to the 'Settings' workspace."/>
<global_param group="&lt;span class='icon-key'&gt;&lt;/span&gt; Admin access" name="ADMIN_USER_LOGIN" type="string" label="Admin Login" description="Alphanumeric login" mandatory="true"/>
<global_param group="&lt;span class='icon-key'&gt;&lt;/span&gt; Admin access" name="ADMIN_USER_NAME" type="string" label="Admin Display Name" description="User-friendly name of the user" mandatory="true"/>
<global_param group="&lt;span class='icon-key'&gt;&lt;/span&gt; Admin access" name="ADMIN_USER_PASS" type="password" label="Admin Password" description="Password" mandatory="true"/>
<global_param group="&lt;span class='icon-key'&gt;&lt;/span&gt; Admin access" name="ADMIN_USER_PASS2" type="password" label="Confirm" description="Confirm password" mandatory="true"/>
<global_param group="&lt;span class='icon-cogs'&gt;&lt;/span&gt; Global options" name="sysLegend" type="legend" label="" description="Set up some application parameters. If you enable Emails, please use the Test button to check if your php is correctly configured."/>
<global_param group="&lt;span class='icon-cogs'&gt;&lt;/span&gt; Global options" name="APPLICATION_TITLE" type="string" label="Application Title" description="Your system title" default="AjaXplorer" mandatory="false"/>
<global_param group="&lt;span class='icon-cogs'&gt;&lt;/span&gt; Global options" name="APPLICATION_WELCOME" type="textarea" label="Welcome Message" description="An additional message displayed at startup, on the splash screen and the login screen." default="" mandatory="false"/>
<global_param group="&lt;span class='icon-cogs'&gt;&lt;/span&gt; Global options" name="APPLICATION_LANGUAGE" type="select" choices="AJXP_AVAILABLE_LANGUAGES" label="Default Language" description="Select a language activated by default( users will still be able to switch)" default="${:language}" mandatory="true"/>
<global_param group="&lt;span class='icon-cogs'&gt;&lt;/span&gt; Global options" name="MAILER_ENABLE" type="group_switch:mailer" label="Enable emails" description="Set up system to send emails" default="no" mandatory="true"/>
<global_param group_switch_name="mailer" group_switch_value="no" group_switch_label="No (you can enable mails later)" name="status" type="hidden" label="No" description="s" default="no"/>
<global_param group_switch_name="mailer" group_switch_value="yes" group_switch_label="Yes (requires a correct PHP configuration)" name="status" type="hidden" label="Yes" description="s" default="yes"/>
<global_param group_switch_name="mailer" group_switch_value="yes" group_switch_label="Yes" name="MAILER_SYSTEM" type="select" label="Php Mailer" description="Set up the correct value to send emails" choices="mail|Mail,sendmail|Sendmail" default="mail" mandatory="true"/>
<global_param group_switch_name="mailer" group_switch_value="yes" group_switch_label="Yes" name="MAILER_ADMIN" type="string" label="Administrator Email" description="Default 'From' email used to send emails." mandatory="true"/>
<global_param group_switch_name="mailer" group_switch_label="yes" group_switch_value="yes" type="button" name="TEST_MAILER" choices="boot_test_mailer" label="CONF_MESSAGE[Test Mailer]" description="CONF_MESSAGE[Try sending an email with the configured data]" mandatory="false"/>
<global_param group="&lt;span class='icon-save'&gt;&lt;/span&gt; Configurations storage" name="StorageLegend" type="legend" label="" description="How the application configuration data will be stored (users, plugins, etc. &lt;b&gt;not&lt;/b&gt; how your actual documents are managed). To get started rapidly, select No Database. To enable more advanced features, configure a database connexion."/>
<global_param group="&lt;span class='icon-save'&gt;&lt;/span&gt; Configurations storage" name="STORAGE_TYPE" type="group_switch:storage_type" label="Storage Type" description="Select how the configurations will be stored." mandatory="false"/>
<global_param group_switch_name="storage_type" group_switch_label="No Database (Quick Start)" group_switch_value="serial" name="type" default="serial" label="No Database" description="h" type="hidden" mandatory="true"/>
<global_param group_switch_name="storage_type" group_switch_label="Database (Requires MySQL or SQLite)" group_switch_value="db" name="type" default="db" label="Database" description="Driver type (do not touch)" type="hidden" mandatory="true"/>
<global_param group_switch_name="storage_type" group_switch_label="Enable Notifications" group_switch_value="db" name="notifications" default="true" label="Enable Notifications" description="Log all events and alerts" type="boolean" mandatory="false"/>
<global_param group_switch_name="storage_type" group_switch_label="Database" group_switch_value="db" name="db_type" default="mysql" label="Database" description="Driver type (do not touch)" type="group_switch:dibi_provider" mandatory="true" choices="mysql|MySQL,sqlite3|Sqlite 3"/>
<global_param group_switch_name="storage_type" group_switch_label="Database" group_switch_value="db" type="button" name="TEST_SQL" choices="boot_test_sql_connexion" label="CONF_MESSAGE[Test SQL Connexion]" description="CONF_MESSAGE[Try connecting to the database]" mandatory="false"/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="usersLegend" type="legend" label="" description="Create users for your organization right now. You can do this later by going to the Settings workspace."/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="USER_LOGIN" type="string" label="Login" replicationGroup="users" description="Alphanumeric login"/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="USER_MAIL" type="string" label="User Email" replicationGroup="users" description="User-friendly name of the user"/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="USER_NAME" type="string" label="User Name" replicationGroup="users" description="User-friendly name of the user"/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="USER_PASS" type="password" label="Password" replicationGroup="users" description="Password"/>
<global_param group="&lt;span class='icon-group'&gt;&lt;/span&gt; Add some users" name="USER_PASS2" type="password" label="Confirm" replicationGroup="users" description="Confirm password"/>
</server_settings>
<registry_contributions>
<actions>
<action name="load_installer_form">
<processing><serverCallback methodName="loadInstallerForm"/></processing>
</action>
<action name="boot_test_sql_connexion">
<processing><serverCallback methodName="testConnexions"/></processing>
</action>
<action name="boot_test_mailer">
<processing><serverCallback methodName="testConnexions"/></processing>
</action>
<action name="apply_installer_form">
<processing><serverCallback methodName="applyInstallerForm"/></processing>
</action>
<action name="ajxp_installer">
<gui iconClass="icon-magic" src="" text="installer.1" title="installer.1">
<context dir="" recycle="false" selection="false" actionBar="true" actionBarGroup="user"/>
</gui>
<rightsContext adminOnly="false" noUser="false" read="false" userLogged="false" write="false"/>
<processing>
<clientCallback dialogOpenForm="installer_form" dialogSkipButtons="true" prepareModal="true">
<dialogOnOpen><![CDATA[
ResourcesManager.prototype.loadJSResource('plugins/boot.conf/class.AjxpInstaller.js', 'AjxpInstaller');
var installer = new AjxpInstaller(modal.getForm().down('#installer_form'), {});
]]></dialogOnOpen>
<dialogOnComplete><![CDATA[
]]></dialogOnComplete>
</clientCallback>
<clientForm id="installer_form"><![CDATA[
<div id="installer_form" box_padding="0" box_resize="true" box_width="560" overlayStyle='{"backgroundColor":"white","opacity":10,"backgroundImage":"url(\"AJXP_THEME_FOLDER/images/grid_t.png\")"}' style="padding: 10px; overflow:auto; background-color: white;">
<img src="plugins/gui.ajax/AjxpLogo250.png" style="display:block;">
<div class="dialogLegend installerWelcome"> Thank you for installing AjaXplorer!<br> This tool will make sure your new sharing platform is up and running in no time: browse through the various sections to set up the general behaviour of the application. You can fly over the fields labels with your mouse to get more information. <br>Are you ready ? <span id="start_button">Start wizard!</span></div>
<div id="the_form" style="display:none; margin:0 5px;"></div>
<div id="configuration_progress" class="dialogLegend installerWelcome" style="display:none; margin:0 5px;">
Please wait while AjaXplorer 5 is being configured! It will be up and running in a couple of seconds...
<div style="margin: 20px auto; width: 40px;">
<span class="icon-spinner rotating spinner_large"></span>
</div>
</div>
<div style="margin-top:20px;">
<div id="save_button" class="SF_input SF_inlineButton disabled"><span class="icon-play-circle"></span>Install AjaXplorer Now!</div>
</div>
</div>
<style type="text/css">
#installer_form #save_button{
font-size: 17px;
clear: left;
width: 220px !important;
padding: 5px !important;
margin: 5px 174px !important;
}
#installer_form #save_button.disabled{
color: #ccc;
cursor: default;
}
.installerWelcome{
font-size: 15px;
line-height: 21px;
padding: 7px;
padding-bottom: 0;
}
#installer_form .accordion_toggle{
border: 1px solid #fff;
padding-top: 7px;
border-bottom: 0;
background-position-y: 2px;
}
#installer_form .accordion_toggle_active{
border: 1px solid rgb(117, 128, 139);
border-radius: 4px 4px 0 0;
border-bottom: 0;
}
#installer_form .accordion_content{
border: 1px solid rgb(117, 128, 139);
border-radius: 0 0 4px 4px;
border-top: 0;
padding-bottom: 9px;
}
#installer_form #start_button{
cursor: pointer;
text-decoration: underline;
font-weight: bold;
}
</style>
]]></clientForm>
<clientListener name="init"><![CDATA[
ajaxplorer.actionBar.fireAction("ajxp_installer");
]]></clientListener>
</processing>
</action>
</actions>
</registry_contributions>
</ajxp_plugin>
\ No newline at end of file
<?php
/*
* Copyright 2007-2011 Charles du Jeu <contact (at) cdujeu.me>
* This file is part of AjaXplorer.
*
* AjaXplorer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AjaXplorer 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with AjaXplorer. If not, see <http://www.gnu.org/licenses/>.
*
* The latest code can be found at <http://www.ajaxplorer.info/>.
*
* These configuration must be set at the very root loading of the framework
*/
/*
* If you have a charset warning, or problems displaying filenames with accented characters,
* check your system locale and set it in the form lang_country.charset
* Example : fr_FR.UTF-8, fr_FR.ISO-8859-1, fr_FR.CP1252 (windows), en_EN.UTF-8, etc.
*
* Windows users may define an empty string
* define("AJXP_LOCALE", "");
*/
define("AJXP_LOCALE", "${:translation}");
//define("AJXP_LOCALE", "");
/*
* If you encounter problems writing to the standard php tmp directory, you can
* define your own tmp dir here. Suggested value is ajxp_path/data/tmp/
* AJXP_DATA_PATH, AJXP_INSTALL_PATH are replaced automatically.
*
* See php.ini settings below for the session.save_path value as well.
*/
//define("AJXP_TMP_DIR", AJXP_DATA_PATH."/tmp");
/*
* Additionnal php.ini settings
* > Problems with tmp dir : set your own session tmp dir (create it and make it writeable!)
* > Concurrent versions of AjaXplorer : use session.cookie_path to differentiate them.
*/
$AJXP_INISET = array();
//$AJXP_INISET["session.save_path"] = AJXP_DATA_PATH."/tmp/sessions";
//$AJXP_INISET["session.cookie_path"] = "/ajaxplorer";
/*
* If you want to force the https, uncomment the line below. This will automatically
* redirect all calls to ajaxplorer via http to the same URL with https
*/
//define("AJXP_FORCE_SSL_REDIRECT", true);
\ No newline at end of file
<?php
/*
* Copyright 2007-2011 Charles du Jeu <contact (at) cdujeu.me>
* This file is part of AjaXplorer.
*
* AjaXplorer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AjaXplorer 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with AjaXplorer. If not, see <http://www.gnu.org/licenses/>.
*
* The latest code can be found at <http://www.ajaxplorer.info/>.
*/
defined('AJXP_EXEC') or die('Access not allowed');
define('AJXP_SANITIZE_HTML', 1);
define('AJXP_SANITIZE_HTML_STRICT', 2);
define('AJXP_SANITIZE_ALPHANUM', 3);
define('AJXP_SANITIZE_EMAILCHARS', 4);
/**
* Various functions used everywhere, static library
* @package AjaXplorer
* @subpackage Core
*/
class AJXP_Utils
{
/**
* Performs a natural sort on the array keys.
* Behaves the same as ksort() with natural sorting added.
*
* @param Array $array The array to sort
* @return boolean
*/
static function natksort(&$array)
{
uksort($array, 'strnatcasecmp');
return true;
}
/**
* Performs a reverse natural sort on the array keys
* Behaves the same as krsort() with natural sorting added.
*
* @param Array $array The array to sort
* @return boolean
*/
static function natkrsort(&$array)
{
natksort($array);
$array = array_reverse($array, TRUE);
return true;
}
/**
* Remove all "../../" tentatives, replace double slashes
* @static
* @param string $path
* @return string
*/
static function securePath($path)
{
if ($path == null) $path = "";
//
// REMOVE ALL "../" TENTATIVES
//
$dirs = explode('/', $path);
for ($i = 0; $i < count($dirs); $i++)
{
if ($dirs[$i] == '.' or $dirs[$i] == '..') {
$dirs[$i] = '';
}
}
// rebuild safe directory string
$path = implode('/', $dirs);
//
// REPLACE DOUBLE SLASHES
//
while (preg_match('/\/\//', $path))
{
$path = str_replace('//', '/', $path);
}
return $path;
}
/**
* Function to clean a string from specific characters
*
* @static
* @param string $s
* @param int $level Can be AJXP_SANITIZE_ALPHANUM, AJXP_SANITIZE_EMAILCHARS, AJXP_SANITIZE_HTML, AJXP_SANITIZE_HTML_STRICT
* @param string $expand
* @return mixed|string
*/
public static function sanitize($s, $level = AJXP_SANITIZE_HTML, $expand = 'script|style|noframes|select|option')
{
/**/ //prep the string
$s = ' ' . $s;
if ($level == AJXP_SANITIZE_ALPHANUM) {
return preg_replace("/[^a-zA-Z0-9_\-\.]/", "", $s);
} else if ($level == AJXP_SANITIZE_EMAILCHARS) {
return preg_replace("/[^a-zA-Z0-9_\-\.@!%\+=|~\?]/", "", $s);
}
//begin removal
/**/ //remove comment blocks
while (stripos($s, '<!--') > 0) {
$pos[1] = stripos($s, '<!--');
$pos[2] = stripos($s, '-->', $pos[1]);
$len[1] = $pos[2] - $pos[1] + 3;
$x = substr($s, $pos[1], $len[1]);
$s = str_replace($x, '', $s);
}
/**/ //remove tags with content between them
if (strlen($expand) > 0) {
$e = explode('|', $expand);
for ($i = 0; $i < count($e); $i++) {
while (stripos($s, '<' . $e[$i]) > 0) {
$len[1] = strlen('<' . $e[$i]);
$pos[1] = stripos($s, '<' . $e[$i]);
$pos[2] = stripos($s, $e[$i] . '>', $pos[1] + $len[1]);
$len[2] = $pos[2] - $pos[1] + $len[1];
$x = substr($s, $pos[1], $len[2]);
$s = str_replace($x, '', $s);
}
}
}
$s = strip_tags($s);
if ($level == AJXP_SANITIZE_HTML_STRICT) {
$s = preg_replace("/[\",;\/`<>:\*\|\?!\^\\\]/", "", $s);
} else {
$s = str_replace(array("<", ">"), array("&lt;", "&gt;"), $s);
}
return trim($s);
}
/**
* Perform standard urldecode, sanitization, securepath and magicDequote
* @static
* @param $data
* @param int $sanitizeLevel
* @return string
*/
public static function decodeSecureMagic($data, $sanitizeLevel = AJXP_SANITIZE_HTML)
{
return SystemTextEncoding::fromUTF8(AJXP_Utils::sanitize(AJXP_Utils::securePath(SystemTextEncoding::magicDequote($data)), $sanitizeLevel));
}
/**
* Try to load the tmp dir from the CoreConf AJXP_TMP_DIR, or the constant AJXP_TMP_DIR,
* or the sys_get_temp_dir
* @static
* @return mixed|null|string
*/
public static function getAjxpTmpDir()
{
if (ConfService::getCoreConf("AJXP_TMP_DIR") != null) {
return ConfService::getCoreConf("AJXP_TMP_DIR");
}
if (defined("AJXP_TMP_DIR") && AJXP_TMP_DIR != "") {
return AJXP_TMP_DIR;
}
return realpath(sys_get_temp_dir());
}
public static function detectApplicationFirstRun(){
return !file_exists(AJXP_CACHE_DIR."/first_run_passed");
}
public static function setApplicationFirstRunPassed(){
@file_put_contents(AJXP_CACHE_DIR."/first_run_passed", "true");
}
/**
* Parse a Comma-Separated-Line value
* @static
* @param $string
* @param bool $hash
* @return array
*/
public static function parseCSL($string, $hash = false)
{
$exp = array_map("trim", explode(",", $string));
if (!$hash) return $exp;
$assoc = array();
foreach ($exp as $explVal) {
$reExp = explode("|", $explVal);
if (count($reExp) == 1) $assoc[$reExp[0]] = $reExp[0];
else $assoc[$reExp[0]] = $reExp[1];
}
return $assoc;
}
/**
* Parse the $fileVars[] PHP errors
* @static
* @param $boxData
* @return array|null
*/
static function parseFileDataErrors($boxData)
{
$mess = ConfService::getMessages();
$userfile_error = $boxData["error"];
$userfile_tmp_name = $boxData["tmp_name"];
$userfile_size = $boxData["size"];
if ($userfile_error != UPLOAD_ERR_OK) {
$errorsArray = array();
$errorsArray[UPLOAD_ERR_FORM_SIZE] = $errorsArray[UPLOAD_ERR_INI_SIZE] = array(409, "File is too big! Max is" . ini_get("upload_max_filesize"));
$errorsArray[UPLOAD_ERR_NO_FILE] = array(410, "No file found on server!");
$errorsArray[UPLOAD_ERR_PARTIAL] = array(410, "File is partial");
$errorsArray[UPLOAD_ERR_INI_SIZE] = array(410, "No file found on server!");
if ($userfile_error == UPLOAD_ERR_NO_FILE) {
// OPERA HACK, do not display "no file found error"
if (!ereg('Opera', $_SERVER['HTTP_USER_AGENT'])) {
return $errorsArray[$userfile_error];
}
}
else
{
return $errorsArray[$userfile_error];
}
}
if ($userfile_tmp_name == "none" || $userfile_size == 0) {
return array(410, $mess[31]);
}
return null;
}
/**
* Utilitary to pass some parameters directly at startup :
* + repository_id / folder
* + compile & skipDebug
* + update_i18n, extract, create
* + external_selector_type
* + skipIOS
* + gui
* @static
* @param $parameters
* @param $output
* @param $session
* @return void
*/
public static function parseApplicationGetParameters($parameters, &$output, &$session)
{
$output["EXT_REP"] = "/";
if (isSet($parameters["repository_id"]) && isSet($parameters["folder"]) || isSet($parameters["goto"])) {
if(isSet($parameters["goto"])){
$repoId = array_shift(explode("/", ltrim($parameters["goto"], "/")));
$parameters["folder"] = str_replace($repoId, "", ltrim($parameters["goto"], "/"));
}else{
$repoId = $parameters["repository_id"];
}
$repository = ConfService::getRepositoryById($repoId);
if ($repository == null) {
$repository = ConfService::getRepositoryByAlias($repoId);
if ($repository != null) {
$parameters["repository_id"] = $repository->getId();
}
}
require_once(AJXP_BIN_FOLDER . "/class.SystemTextEncoding.php");
if (AuthService::usersEnabled()) {
$loggedUser = AuthService::getLoggedUser();
if ($loggedUser != null && $loggedUser->canSwitchTo($parameters["repository_id"])) {
$output["EXT_REP"] = SystemTextEncoding::toUTF8(urldecode($parameters["folder"]));
$loggedUser->setArrayPref("history", "last_repository", $parameters["repository_id"]);
$loggedUser->setPref("pending_folder", SystemTextEncoding::toUTF8(AJXP_Utils::decodeSecureMagic($parameters["folder"])));
$loggedUser->save("user");
AuthService::updateUser($loggedUser);
} else {
$session["PENDING_REPOSITORY_ID"] = $parameters["repository_id"];
$session["PENDING_FOLDER"] = SystemTextEncoding::toUTF8(AJXP_Utils::decodeSecureMagic($parameters["folder"]));
}
} else {
ConfService::switchRootDir($parameters["repository_id"]);
$output["EXT_REP"] = SystemTextEncoding::toUTF8(urldecode($parameters["folder"]));
}
}
if (isSet($parameters["skipDebug"])) {
ConfService::setConf("JS_DEBUG", false);
}
if (ConfService::getConf("JS_DEBUG") && isSet($parameters["compile"])) {
require_once(AJXP_BIN_FOLDER . "/class.AJXP_JSPacker.php");
AJXP_JSPacker::pack();
}
if (ConfService::getConf("JS_DEBUG") && isSet($parameters["update_i18n"])) {
if (isSet($parameters["extract"])) {
self::extractConfStringsFromManifests();
}
self::updateAllI18nLibraries((isSet($parameters["create"]) ? $parameters["create"] : ""));
}
if (ConfService::getConf("JS_DEBUG") && isSet($parameters["clear_plugins_cache"])) {
@unlink(AJXP_PLUGINS_CACHE_FILE);
@unlink(AJXP_PLUGINS_REQUIRES_FILE);
}
if (AJXP_SERVER_DEBUG && isSet($parameters["extract_application_hooks"])){
self::extractHooksToDoc();
}
if (isSet($parameters["external_selector_type"])) {
$output["SELECTOR_DATA"] = array("type" => $parameters["external_selector_type"], "data" => $parameters);
}
if (isSet($parameters["skipIOS"])) {
setcookie("SKIP_IOS", "true");
}
if (isSet($parameters["skipANDROID"])) {
setcookie("SKIP_ANDROID", "true");
}
if (isSet($parameters["gui"])) {
setcookie("AJXP_GUI", $parameters["gui"]);
if ($parameters["gui"] == "light") $session["USE_EXISTING_TOKEN_IF_EXISTS"] = true;
} else {
if (isSet($session["USE_EXISTING_TOKEN_IF_EXISTS"])) {
unset($session["USE_EXISTING_TOKEN_IF_EXISTS"]);
}
setcookie("AJXP_GUI", null);
}
}
/**
* Remove windows carriage return
* @static
* @param $fileContent
* @return mixed
*/
static function removeWinReturn($fileContent)
{
$fileContent = str_replace(chr(10), "", $fileContent);
$fileContent = str_replace(chr(13), "", $fileContent);
return $fileContent;
}
/**
* Get the filename extensions using ConfService::getRegisteredExtensions()
* @static
* @param string $fileName
* @param string $mode "image" or "text"
* @param bool $isDir
* @return string Returns the icon name ("image") or the mime label ("text")
*/
static function mimetype($fileName, $mode, $isDir)
{
$mess = ConfService::getMessages();
$fileName = strtolower($fileName);
$EXTENSIONS = ConfService::getRegisteredExtensions();
if ($isDir) {
$mime = $EXTENSIONS["ajxp_folder"];
} else {
foreach ($EXTENSIONS as $ext) {
if (preg_match("/\.$ext[0]$/", $fileName)) {
$mime = $ext;
break;
}
}
}
if (!isSet($mime)) {
$mime = $EXTENSIONS["ajxp_empty"];
}
if (is_numeric($mime[2]) || array_key_exists($mime[2], $mess)) {
$mime[2] = $mess[$mime[2]];
}
return (($mode == "image" ? $mime[1] : $mime[2]));
}
static $registeredExtensions;
static function mimeData($fileName, $isDir){
$fileName = strtolower($fileName);
if(self::$registeredExtensions == null){
self::$registeredExtensions = ConfService::getRegisteredExtensions();
}
if ($isDir) {
$mime = self::$registeredExtensions["ajxp_folder"];
} else {
$pos = strrpos($fileName, ".");
if($pos !== false){
$fileExt = substr($fileName, $pos + 1);
if(!empty($fileExt) && array_key_exists($fileExt, self::$registeredExtensions) && $fileExt != "ajxp_folder" && $fileExt != "ajxp_empty"){
$mime = self::$registeredExtensions[$fileExt];
}
}
}
if (!isSet($mime)) {
$mime = self::$registeredExtensions["ajxp_empty"];
}
return array($mime[2], $mime[1]);
}
/**
* Gather a list of mime that must be treated specially. Used for dynamic replacement in XML mainly.
* @static
* @param string $keyword "editable", "image", "audio", "zip"
* @return string
*/
static function getAjxpMimes($keyword)
{
if ($keyword == "editable") {
// Gather editors!
$pServ = AJXP_PluginsService::getInstance();
$plugs = $pServ->getPluginsByType("editor");
//$plugin = new AJXP_Plugin();
$mimes = array();
foreach ($plugs as $plugin) {
$node = $plugin->getManifestRawContent("/editor/@mimes", "node");
$openable = $plugin->getManifestRawContent("/editor/@openable", "node");
if ($openable->item(0) && $openable->item(0)->value == "true" && $node->item(0)) {
$mimestring = $node->item(0)->value;
$mimesplit = explode(",", $mimestring);
foreach ($mimesplit as $value) {
$mimes[$value] = $value;
}
}
}
return implode(",", array_values($mimes));
} else if ($keyword == "image") {
return "png,bmp,jpg,jpeg,gif";
} else if ($keyword == "audio") {
return "mp3";
} else if ($keyword == "zip") {
if (ConfService::zipEnabled()) {
return "zip,ajxp_browsable_archive";
} else {
return "none_allowed";
}
}
return "";
}
/**
* Whether a file is to be considered as an image or not
* @static
* @param $fileName
* @return bool
*/
static function is_image($fileName)
{
if (preg_match("/\.png$|\.bmp$|\.jpg$|\.jpeg$|\.gif$/i", $fileName)) {
return 1;
}
return 0;
}
/**
* Whether a file is to be considered as an mp3... Should be DEPRECATED
* @static
* @param string $fileName
* @return bool
* @deprecated
*/
static function is_mp3($fileName)
{
if (preg_match("/\.mp3$/i", $fileName)) return 1;
return 0;
}
/**
* Static image mime type headers
* @static
* @param $fileName
* @return string
*/
static function getImageMimeType($fileName)
{
if (preg_match("/\.jpg$|\.jpeg$/i", $fileName)) {
return "image/jpeg";
}
else if (preg_match("/\.png$/i", $fileName)) {
return "image/png";
}
else if (preg_match("/\.bmp$/i", $fileName)) {
return "image/bmp";
}
else if (preg_match("/\.gif$/i", $fileName)) {
return "image/gif";
}
}
/**
* Headers to send when streaming
* @static
* @param $fileName
* @return bool|string
*/
static function getStreamingMimeType($fileName)
{
if (preg_match("/\.mp3$/i", $fileName)) {
return "audio/mp3";
}
else if (preg_match("/\.wav$/i", $fileName)) {
return "audio/wav";
}
else if (preg_match("/\.aac$/i", $fileName)) {
return "audio/aac";
}
else if (preg_match("/\.m4a$/i", $fileName)) {
return "audio/m4a";
}
else if (preg_match("/\.aiff$/i", $fileName)) {
return "audio/aiff";
}
else if (preg_match("/\.mp4$/i", $fileName)) {
return "video/mp4";
}
else if (preg_match("/\.mov$/i", $fileName)) {
return "video/quicktime";
}
else if (preg_match("/\.m4v$/i", $fileName)) {
return "video/x-m4v";
}
else if (preg_match("/\.3gp$/i", $fileName)) {
return "video/3gpp";
}
else if (preg_match("/\.3g2$/i", $fileName)) {
return "video/3gpp2";
}
else return false;
}
static $sizeUnit;
/**
* Display a human readable string for a bytesize (1MB, 2,3Go, etc)
* @static
* @param $filesize
* @param bool $phpConfig
* @return string
*/
static function roundSize($filesize, $phpConfig = false)
{
if(self::$sizeUnit == null){
$mess = ConfService::getMessages();
self::$sizeUnit = $mess["byte_unit_symbol"];
}
if ($filesize < 0) {
$filesize = sprintf("%u", $filesize);
}
if ($filesize >= 1073741824) {
$filesize = round($filesize / 1073741824 * 100) / 100 . ($phpConfig ? "G" : " G" . self::$sizeUnit);
}
elseif ($filesize >= 1048576) {
$filesize = round($filesize / 1048576 * 100) / 100 . ($phpConfig ? "M" : " M" . self::$sizeUnit);
}
elseif ($filesize >= 1024) {
$filesize = round($filesize / 1024 * 100) / 100 . ($phpConfig ? "K" : " K" . self::$sizeUnit);
}
else {
$filesize = $filesize . " " . self::$sizeUnit;
}
if ($filesize == 0) {
$filesize = "-";
}
return $filesize;
}
/**
* Hidden files start with dot
* @static
* @param string $fileName
* @return bool
*/
static function isHidden($fileName)
{
return (substr($fileName, 0, 1) == ".");
}
/**
* Whether a file is a browsable archive
* @static
* @param string $fileName
* @return int
*/
static function isBrowsableArchive($fileName)
{
return preg_match("/\.zip$/i", $fileName);
}
/**
* Convert a shorthand byte value from a PHP configuration directive to an integer value
* @param string $value
* @return int
*/
static function convertBytes($value)
{
if (is_numeric($value)) {
return intval($value);
}
else
{
$value_length = strlen($value);
$qty = substr($value, 0, $value_length - 1);
$unit = strtolower(substr($value, $value_length - 1));
switch ($unit)
{
case 'k':
$qty *= 1024;
break;
case 'm':
$qty *= 1048576;
break;
case 'g':
$qty *= 1073741824;
break;
}
return $qty;
}
}
//Relative Date Function
public static function relativeDate($time, $messages) {
$today = strtotime(date('M j, Y'));
$reldays = ($time - $today)/86400;
$relTime = date($messages['date_relative_time_format'], $time);
if ($reldays >= 0 && $reldays < 1) {
return str_replace("TIME", $relTime, $messages['date_relative_today']);
} else if ($reldays >= 1 && $reldays < 2) {
return str_replace("TIME", $relTime, $messages['date_relative_tomorrow']);
} else if ($reldays >= -1 && $reldays < 0) {
return str_replace("TIME", $relTime, $messages['date_relative_yesterday']);
}
if (abs($reldays) < 7) {
if ($reldays > 0) {
$reldays = floor($reldays);
return str_replace("%s", $reldays, $messages['date_relative_days_ahead']);
//return 'In ' . $reldays . ' day' . ($reldays != 1 ? 's' : '');
} else {
$reldays = abs(floor($reldays));
return str_replace("%s", $reldays, $messages['date_relative_days_ago']);
//return $reldays . ' day' . ($reldays != 1 ? 's' : '') . ' ago';
}
}
return str_replace("DATE", date($messages["date_relative_date_format"], $time ? $time : time()), $messages["date_relative_date"]);
}
/**
* Replace specific chars by their XML Entities, for use inside attributes value
* @static
* @param $string
* @param bool $toUtf8
* @return mixed|string
*/
static function xmlEntities($string, $toUtf8 = false)
{
$xmlSafe = str_replace(array("&", "<", ">", "\"", "\n", "\r"), array("&amp;", "&lt;", "&gt;", "&quot;", "&#13;", "&#10;"), $string);
if ($toUtf8 && SystemTextEncoding::getEncoding() != "UTF-8") {
return SystemTextEncoding::toUTF8($xmlSafe);
} else {
return $xmlSafe;
}
}
/**
* Replace specific chars by their XML Entities, for use inside attributes value
* @static
* @param $string
* @param bool $toUtf8
* @return mixed|string
*/
static function xmlContentEntities($string, $toUtf8 = false)
{
$xmlSafe = str_replace(array("&", "<", ">", "\""), array("&amp;", "&lt;", "&gt;", "&quot;"), $string);
if ($toUtf8) {
return SystemTextEncoding::toUTF8($xmlSafe);
} else {
return $xmlSafe;
}
}
/**
* Search include path for a given file
* @static
* @param string $file
* @return bool
*/
static public function searchIncludePath($file)
{
$ps = explode(PATH_SEPARATOR, ini_get('include_path'));
foreach ($ps as $path)
{
if (@file_exists($path . DIRECTORY_SEPARATOR . $file)) return true;
}
if (@file_exists($file)) return true;
return false;
}
/**
* @static
* @param $from
* @param $to
* @return string
*/
static public function getTravelPath($from, $to)
{
$from = explode('/', $from);
$to = explode('/', $to);
$relPath = $to;
foreach($from as $depth => $dir) {
// find first non-matching dir
if($dir === $to[$depth]) {
// ignore this directory
array_shift($relPath);
} else {
// get number of remaining dirs to $from
$remaining = count($from) - $depth;
if($remaining > 1) {
// add traversals up to first matching dir
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
} else {
$relPath[0] = './' . $relPath[0];
}
}
}
return implode('/', $relPath);
}
/**
* Build the current server URL
* @param bool $withURI
* @internal param bool $witchURI
* @static
* @return string
*/
static function detectServerURL($withURI = false)
{
$setUrl = ConfService::getCoreConf("SERVER_URL");
if(!empty($setUrl)){
return $setUrl;
}
if(php_sapi_name() == "cli"){
AJXP_Logger::debug("WARNING, THE SERVER_URL IS NOT SET, WE CANNOT BUILD THE MAIL ADRESS WHEN WORKING IN CLI");
}
$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
$port = (($protocol === 'http' && $_SERVER['SERVER_PORT'] == 80 || $protocol === 'https' && $_SERVER['SERVER_PORT'] == 443)
? "" : ":" . $_SERVER['SERVER_PORT']);
$name = $_SERVER["SERVER_NAME"];
// removed $port after $name because it interfered with apache frontend
if(!$withURI){
return "$protocol://$name";
}else{
return "$protocol://$name".dirname($_SERVER["REQUEST_URI"]);
}
}
/**
* Modifies a string to remove all non ASCII characters and spaces.
* @param string $text
* @return string
*/
static public function slugify($text)
{
if (empty($text)) return "";
// replace non letter or digits by -
$text = preg_replace('~[^\\pL\d]+~u', '-', $text);
// trim
$text = trim($text, '-');
// transliterate
if (function_exists('iconv')) {
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
}
// lowercase
$text = strtolower($text);
// remove unwanted characters
$text = preg_replace('~[^-\w]+~', '', $text);
if (empty($text)) {
return 'n-a';
}
return $text;
}
static function getHooksFile(){
return AJXP_INSTALL_PATH."/".AJXP_DOCS_FOLDER."/hooks.json";
}
static function extractHooksToDoc(){
$docFile = self::getHooksFile();
if(is_file($docFile)){
copy($docFile, $docFile.".bak");
$existingHooks = json_decode(file_get_contents($docFile), true);
}else{
$existingHooks = array();
}
$allPhpFiles = glob_recursive(AJXP_INSTALL_PATH."/*.php");
$hooks = array();
foreach($allPhpFiles as $phpFile){
$fileContent = file($phpFile);
foreach($fileContent as $lineNumber => $line){
if(preg_match_all('/AJXP_Controller::applyHook\("([^"]+)", (.*)\)/', $line, $matches)){
$names = $matches[1];
$params = $matches[2];
foreach($names as $index => $hookName){
if(!isSet($hooks[$hookName])) $hooks[$hookName] = array("TRIGGERS" => array(), "LISTENERS" => array());
$hooks[$hookName]["TRIGGERS"][] = array("FILE" => substr($phpFile, strlen(AJXP_INSTALL_PATH)), "LINE" => $lineNumber);
$hooks[$hookName]["PARAMETER_SAMPLE"] = $params[$index];
}
}
}
}
$registryHooks = AJXP_PluginsService::getInstance()->searchAllManifests("//hooks/serverCallback", "xml", false, false, true);
$regHooks = array();
foreach($registryHooks as $xmlHook){
$name = $xmlHook->getAttribute("hookName");
$method = $xmlHook->getAttribute("methodName");
$pluginId = $xmlHook->getAttribute("pluginId");
if($pluginId == "") $pluginId = $xmlHook->parentNode->parentNode->parentNode->getAttribute("id");
if(!isSet($regHooks[$name])) $regHooks[$name] = array();
$regHooks[$name][] = array("PLUGIN_ID" => $pluginId, "METHOD" => $method);
}
foreach($hooks as $h => $data) {
if(isSet($regHooks[$h])){
$data["LISTENERS"] = $regHooks[$h];
}
if(isSet($existingHooks[$h])){
$existingHooks[$h]["TRIGGERS"] = $data["TRIGGERS"];
$existingHooks[$h]["LISTENERS"] = $data["LISTENERS"];
$existingHooks[$h]["PARAMETER_SAMPLE"] = $data["PARAMETER_SAMPLE"];
}else{
$existingHooks[$h] = $data;
}
}
file_put_contents($docFile, self::prettyPrintJSON(json_encode($existingHooks)));
}
/**
* Indents a flat JSON string to make it more human-readable.
*
* @param string $json The original JSON string to process.
*
* @return string Indented version of the original JSON string.
*/
function prettyPrintJSON($json) {
$result = '';
$pos = 0;
$strLen = strlen($json);
$indentStr = ' ';
$newLine = "\n";
$prevChar = '';
$outOfQuotes = true;
for ($i=0; $i<=$strLen; $i++) {
// Grab the next character in the string.
$char = substr($json, $i, 1);
// Are we inside a quoted string?
if ($char == '"' && $prevChar != '\\') {
$outOfQuotes = !$outOfQuotes;
// If this character is the end of an element,
// output a new line and indent the next line.
} else if(($char == '}' || $char == ']') && $outOfQuotes) {
$result .= $newLine;
$pos --;
for ($j=0; $j<$pos; $j++) {
$result .= $indentStr;
}
}
// Add the character to the result string.
$result .= $char;
// If the last character was the beginning of an element,
// output a new line and indent the next line.
if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) {
$result .= $newLine;
if ($char == '{' || $char == '[') {
$pos ++;
}
for ($j = 0; $j < $pos; $j++) {
$result .= $indentStr;
}
}
$prevChar = $char;
}
return $result;
}
/**
* i18n utilitary for extracting the CONF_MESSAGE[] strings out of the XML files
* @static
* @return void
*/
static function extractConfStringsFromManifests()
{
$plugins = AJXP_PluginsService::getInstance()->getDetectedPlugins();
$plug = new AJXP_Plugin("", "");
foreach ($plugins as $pType => $plugs) {
foreach ($plugs as $plug) {
$lib = $plug->getManifestRawContent("//i18n", "nodes");
if (!$lib->length) continue;
$library = $lib->item(0);
$namespace = $library->getAttribute("namespace");
$path = $library->getAttribute("path");
$xml = $plug->getManifestRawContent();
// for core, also load mixins
$refFile = AJXP_INSTALL_PATH . "/" . $path . "/conf/en.php";
$reference = array();
if (preg_match_all("/CONF_MESSAGE(\[.*?\])/", $xml, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$match[1] = str_replace(array("[", "]"), "", $match[1]);
$reference[$match[1]] = $match[1];
}
}
if ($namespace == "") {
$mixXml = file_get_contents(AJXP_INSTALL_PATH . "/" . AJXP_PLUGINS_FOLDER . "/core.ajaxplorer/ajxp_mixins.xml");
if (preg_match_all("/MIXIN_MESSAGE(\[.*?\])/", $mixXml, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$match[1] = str_replace(array("[", "]"), "", $match[1]);
$reference[$match[1]] = $match[1];
}
}
}
if (count($reference)) {
self::updateI18nFromRef($refFile, $reference);
}
}
}
}
/**
* Browse the i18n libraries and update the languages with the strings missing
* @static
* @param string $createLanguage
* @return void
*/
static function updateAllI18nLibraries($createLanguage = "")
{
// UPDATE EN => OTHER LANGUAGES
$nodes = AJXP_PluginsService::getInstance()->searchAllManifests("//i18n", "nodes");
foreach ($nodes as $node) {
$nameSpace = $node->getAttribute("namespace");
$path = AJXP_INSTALL_PATH . "/" . $node->getAttribute("path");
if ($nameSpace == "") {
self::updateI18nFiles($path, false, $createLanguage);
self::updateI18nFiles($path . "/conf", true, $createLanguage);
} else {
self::updateI18nFiles($path, true, $createLanguage);
self::updateI18nFiles($path . "/conf", true, $createLanguage);
}
}
}
/**
* Patch the languages files of an i18n library with the references strings from the "en" file.
* @static
* @param $baseDir
* @param bool $detectLanguages
* @param string $createLanguage
* @return
*/
static function updateI18nFiles($baseDir, $detectLanguages = true, $createLanguage = "")
{
if (!is_dir($baseDir) || !is_file($baseDir . "/en.php")) return;
if ($createLanguage != "" && !is_file($baseDir . "/$createLanguage.php")) {
@copy(AJXP_INSTALL_PATH . "/plugins/core.ajaxplorer/i18n-template.php", $baseDir . "/$createLanguage.php");
}
if (!$detectLanguages) {
$languages = ConfService::listAvailableLanguages();
$filenames = array();
foreach ($languages as $key => $value) {
$filenames[] = $baseDir . "/" . $key . ".php";
}
} else {
$filenames = glob($baseDir . "/*.php");
}
include($baseDir . "/en.php");
$reference = $mess;
foreach ($filenames as $filename) {
self::updateI18nFromRef($filename, $reference);
}
}
/**
* i18n Utilitary
* @static
* @param $filename
* @param $reference
* @return
*/
static function updateI18nFromRef($filename, $reference)
{
if (!is_file($filename)) return;
include($filename);
$missing = array();
foreach ($reference as $messKey => $message) {
if (!array_key_exists($messKey, $mess)) {
$missing[] = "\"$messKey\" => \"$message\",";
}
}
//print_r($missing);
if (count($missing)) {
$header = array();
$currentMessages = array();
$footer = array();
$fileLines = file($filename);
$insideArray = false;
foreach ($fileLines as $line) {
if (strstr($line, "\"") !== false) {
$currentMessages[] = trim($line);
$insideArray = true;
} else {
if (!$insideArray && strstr($line, ");") !== false) $insideArray = true;
if (!$insideArray) {
$header[] = trim($line);
} else {
$footer[] = trim($line);
}
}
}
$currentMessages = array_merge($header, $currentMessages, $missing, $footer);
file_put_contents($filename, join("\n", $currentMessages));
}
}
/**
* Generate an HTML table for the tests results. We should use a template somewhere...
* @static
* @param $outputArray
* @param $testedParams
* @param bool $showSkipLink
* @return string
*/
static function testResultsToTable($outputArray, $testedParams, $showSkipLink = true)
{
$dumpRows = "";
$passedRows = array();
$warnRows = "";
$errRows = "";
$errs = $warns = 0;
$ALL_ROWS = array(
"error" => array(),
"warning" => array(),
"dump" => array(),
"passed" => array(),
);
$TITLES = array(
"error" => "Failed Tests",
"warning" => "Warnings",
"dump" => "Server Information",
"passed" => "Other tests passed",
);
foreach ($outputArray as $item)
{
// A test is output only if it hasn't succeeded (doText returned FALSE)
$result = $item["result"] ? "passed" : ($item["level"] == "info" ? "dump" : ($item["level"] == "warning"
? "warning" : "error"));
$success = $result == "passed";
if($result == "dump") $result = "passed";
$ALL_ROWS[$result][$item["name"]] = $item["info"];
}
include(AJXP_INSTALL_PATH."/core/tests/startup.phtml");
}
/**
* @static
* @param $outputArray
* @param $testedParams
* @return bool
*/
static function runTests(&$outputArray, &$testedParams)
{
// At first, list folder in the tests subfolder
chdir(AJXP_TESTS_FOLDER);
$files = glob('*.php');
$outputArray = array();
$testedParams = array();
$passed = true;
foreach ($files as $file)
{
require_once($file);
// Then create the test class
$testName = str_replace(".php", "", substr($file, 5));
if(!class_exists($testName)) continue;
$class = new $testName();
$result = $class->doTest();
if (!$result && $class->failedLevel != "info") $passed = false;
$outputArray[] = array(
"name" => $class->name,
"result" => $result,
"level" => $class->failedLevel,
"info" => $class->failedInfo);
if (count($class->testedParams)) {
$testedParams = array_merge($testedParams, $class->testedParams);
}
}
// PREPARE REPOSITORY LISTS
$repoList = array();
require_once("../classes/class.ConfService.php");
require_once("../classes/class.Repository.php");
include(AJXP_CONF_PATH . "/bootstrap_repositories.php");
foreach ($REPOSITORIES as $index => $repo) {
$repoList[] = ConfService::createRepositoryFromArray($index, $repo);
}
// Try with the serialized repositories
if (is_file(AJXP_DATA_PATH . "/plugins/conf.serial/repo.ser")) {
$fileLines = file(AJXP_DATA_PATH . "/plugins/conf.serial/repo.ser");
$repos = unserialize($fileLines[0]);
$repoList = array_merge($repoList, $repos);
}
// NOW TRY THE PLUGIN TESTS
chdir(AJXP_INSTALL_PATH . "/" . AJXP_PLUGINS_FOLDER);
$files = glob('access.*/test.*.php');
foreach ($files as $file)
{
require_once($file);
// Then create the test class
list($accessFolder, $testFileName) = explode("/", $file);
$testName = str_replace(".php", "", substr($testFileName, 5) . "Test");
$class = new $testName();
foreach ($repoList as $repository) {
if($repository->isTemplate || $repository->getParentId() != null) continue;
$result = $class->doRepositoryTest($repository);
if ($result === false || $result === true) {
if (!$result && $class->failedLevel != "info") {
$passed = false;
}
$outputArray[] = array(
"name" => $class->name . "\n Testing repository : " . $repository->getDisplay(),
"result" => $result,
"level" => $class->failedLevel,
"info" => $class->failedInfo);
if (count($class->testedParams)) {
$testedParams = array_merge($testedParams, $class->testedParams);
}
}
}
}
return $passed;
}
/**
* @static
* @param $outputArray
* @param $testedParams
* @return void
*/
static function testResultsToFile($outputArray, $testedParams)
{
ob_start();
echo '$diagResults = ';
var_export($testedParams);
echo ';';
echo '$outputArray = ';
var_export($outputArray);
echo ';';
$content = '<?php ' . ob_get_contents() . ' ?>';
ob_end_clean();
//print_r($content);
file_put_contents(TESTS_RESULT_FILE, $content);
}
static function isStream($path){
$wrappers = stream_get_wrappers();
$wrappers_re = '(' . join('|', $wrappers) . ')';
return preg_match( "!^$wrappers_re://!", $path ) === 1;
}
/**
* Load an array stored serialized inside a file.
*
* @param String $filePath Full path to the file
* @param Boolean $skipCheck do not test for file existence before opening
* @return Array
*/
static function loadSerialFile($filePath, $skipCheck = false, $format="ser")
{
$filePath = AJXP_VarsFilter::filter($filePath);
$result = array();
if($skipCheck){
$fileLines = @file($filePath);
if($fileLines !== false) {
if($format == "ser") $result = unserialize(implode("", $fileLines));
else if($format == "json") $result = json_decode(implode("", $fileLines), true);
}
return $result;
}
if (is_file($filePath)) {
$fileLines = file($filePath);
if($format == "ser") $result = unserialize(implode("", $fileLines));
else if($format == "json") $result = json_decode(implode("", $fileLines), true);
}
return $result;
}
/**
* Stores an Array as a serialized string inside a file.
*
* @param String $filePath Full path to the file
* @param Array|Object $value The value to store
* @param Boolean $createDir Whether to create the parent folder or not, if it does not exist.
* @param bool $silent Silently write the file, are throw an exception on problem.
* @param string $format
* @throws Exception
*/
static function saveSerialFile($filePath, $value, $createDir = true, $silent = false, $format="ser", $jsonPrettyPrint = false)
{
$filePath = AJXP_VarsFilter::filter($filePath);
if ($createDir && !is_dir(dirname($filePath))){
@mkdir(dirname($filePath), 0755, true);
if(!is_dir(dirname($filePath))){
// Creation failed
if($silent) return;
else throw new Exception("[AJXP_Utils::saveSerialFile] Cannot write into " . dirname(dirname($filePath)));
}
}
try {
$fp = fopen($filePath, "w");
if($format == "ser") $content = serialize($value);
else if($format == "json") {
$content = json_encode($value);
if($jsonPrettyPrint) $content = self::prettyPrintJSON($content);
}
fwrite($fp, $content);
fclose($fp);
} catch (Exception $e) {
if ($silent) return;
else throw $e;
}
}
/**
* Detect mobile browsers
* @static
* @return bool
*/
public static function userAgentIsMobile()
{
$isMobile = false;
$op = strtolower($_SERVER['HTTP_X_OPERAMINI_PHONE'] OR "");
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
$ac = strtolower($_SERVER['HTTP_ACCEPT']);
$isMobile = strpos($ac, 'application/vnd.wap.xhtml+xml') !== false
|| $op != ''
|| strpos($ua, 'sony') !== false
|| strpos($ua, 'symbian') !== false
|| strpos($ua, 'nokia') !== false
|| strpos($ua, 'samsung') !== false
|| strpos($ua, 'mobile') !== false
|| strpos($ua, 'android') !== false
|| strpos($ua, 'windows ce') !== false
|| strpos($ua, 'epoc') !== false
|| strpos($ua, 'opera mini') !== false
|| strpos($ua, 'nitro') !== false
|| strpos($ua, 'j2me') !== false
|| strpos($ua, 'midp-') !== false
|| strpos($ua, 'cldc-') !== false
|| strpos($ua, 'netfront') !== false
|| strpos($ua, 'mot') !== false
|| strpos($ua, 'up.browser') !== false
|| strpos($ua, 'up.link') !== false
|| strpos($ua, 'audiovox') !== false
|| strpos($ua, 'blackberry') !== false
|| strpos($ua, 'ericsson,') !== false
|| strpos($ua, 'panasonic') !== false
|| strpos($ua, 'philips') !== false
|| strpos($ua, 'sanyo') !== false
|| strpos($ua, 'sharp') !== false
|| strpos($ua, 'sie-') !== false
|| strpos($ua, 'portalmmm') !== false
|| strpos($ua, 'blazer') !== false
|| strpos($ua, 'avantgo') !== false
|| strpos($ua, 'danger') !== false
|| strpos($ua, 'palm') !== false
|| strpos($ua, 'series60') !== false
|| strpos($ua, 'palmsource') !== false
|| strpos($ua, 'pocketpc') !== false
|| strpos($ua, 'smartphone') !== false
|| strpos($ua, 'rover') !== false
|| strpos($ua, 'ipaq') !== false
|| strpos($ua, 'au-mic,') !== false
|| strpos($ua, 'alcatel') !== false
|| strpos($ua, 'ericy') !== false
|| strpos($ua, 'up.link') !== false
|| strpos($ua, 'vodafone/') !== false
|| strpos($ua, 'wap1.') !== false
|| strpos($ua, 'wap2.') !== false;
/*
$isBot = false;
$ip = $_SERVER['REMOTE_ADDR'];
$isBot = $ip == '66.249.65.39'
|| strpos($ua, 'googlebot') !== false
|| strpos($ua, 'mediapartners') !== false
|| strpos($ua, 'yahooysmcm') !== false
|| strpos($ua, 'baiduspider') !== false
|| strpos($ua, 'msnbot') !== false
|| strpos($ua, 'slurp') !== false
|| strpos($ua, 'ask') !== false
|| strpos($ua, 'teoma') !== false
|| strpos($ua, 'spider') !== false
|| strpos($ua, 'heritrix') !== false
|| strpos($ua, 'attentio') !== false
|| strpos($ua, 'twiceler') !== false
|| strpos($ua, 'irlbot') !== false
|| strpos($ua, 'fast crawler') !== false
|| strpos($ua, 'fastmobilecrawl') !== false
|| strpos($ua, 'jumpbot') !== false
|| strpos($ua, 'googlebot-mobile') !== false
|| strpos($ua, 'yahooseeker') !== false
|| strpos($ua, 'motionbot') !== false
|| strpos($ua, 'mediobot') !== false
|| strpos($ua, 'chtml generic') !== false
|| strpos($ua, 'nokia6230i/. fast crawler') !== false;
*/
return $isMobile;
}
/**
* Detect iOS browser
* @static
* @return bool
*/
public static function userAgentIsIOS()
{
if (stripos($_SERVER["HTTP_USER_AGENT"], "iphone") !== false) return true;
if (stripos($_SERVER["HTTP_USER_AGENT"], "ipad") !== false) return true;
if (stripos($_SERVER["HTTP_USER_AGENT"], "ipod") !== false) return true;
return false;
}
/**
* Detect Android UA
* @static
* @return bool
*/
public static function userAgentIsAndroid()
{
return (stripos($_SERVER["HTTP_USER_AGENT"], "android") !== false);
}
/**
* Try to remove a file without errors
* @static
* @param $file
* @return void
*/
public static function silentUnlink($file)
{
@unlink($file);
}
/**
* Try to set an ini config, without errors
* @static
* @param string $paramName
* @param string $paramValue
* @return void
*/
public static function safeIniSet($paramName, $paramValue)
{
$current = ini_get($paramName);
if ($current == $paramValue) return;
@ini_set($paramName, $paramValue);
}
/**
* @static
* @param string $url
* @return bool|mixed|string
*/
public static function getRemoteContent($url){
if(ini_get("allow_url_fopen")){
return file_get_contents($url);
}else if(function_exists("curl_init")){
$ch = curl_init();
$timeout = 30; // set to zero for no timeout
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$return = curl_exec($ch);
curl_close($ch);
return $return;
}else{
$i = parse_url($url);
$httpClient = new HttpClient($i["host"]);
$httpClient->timeout = 30;
return $httpClient->quickGet($url);
}
}
public static function parseStandardFormParameters(&$repDef, &$options, $userId = null, $prefix = "DRIVER_OPTION_", $binariesContext = null){
if($binariesContext === null){
$binariesContext = array("USER" => (AuthService::getLoggedUser()!= null)?AuthService::getLoggedUser()->getId():"shared");
}
$replicationGroups = array();
$switchesGroups = array();
foreach ($repDef as $key => $value)
{
$value = SystemTextEncoding::magicDequote($value);
if( ( ( !empty($prefix) && strpos($key, $prefix)!== false && strpos($key, $prefix)==0 ) || empty($prefix) )
&& strpos($key, "ajxptype") === false
&& strpos($key, "_original_binary") === false
&& strpos($key, "_replication") === false
&& strpos($key, "_checkbox") === false){
if(isSet($repDef[$key."_ajxptype"])){
$type = $repDef[$key."_ajxptype"];
if($type == "boolean"){
$value = ($value == "true"?true:false);
}else if($type == "integer"){
$value = intval($value);
}else if($type == "array"){
$value = explode(",", $value);
}else if($type == "password" && $userId!=null){
if (trim($value != "") && function_exists('mcrypt_encrypt'))
{
// The initialisation vector is only required to avoid a warning, as ECB ignore IV
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);
// We encode as base64 so if we need to store the result in a database, it can be stored in text column
$value = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($userId."\1CDAFx¨op#"), $value, MCRYPT_MODE_ECB, $iv));
}
}else if($type == "binary" && $binariesContext !== null){
if(!empty($value)){
if($value == "ajxp-remove-original"){
if(!empty($repDef[$key."_original_binary"])){
ConfService::getConfStorageImpl()->deleteBinary($binariesContext, $repDef[$key."_original_binary"]);
}
$value = "";
}else{
$file = AJXP_Utils::getAjxpTmpDir()."/".$value;
if(file_exists($file)){
$id= !empty($repDef[$key."_original_binary"]) ? $repDef[$key."_original_binary"] : null;
$id=ConfService::getConfStorageImpl()->saveBinary($binariesContext, $file, $id);
$value = $id;
}
}
}else if(!empty($repDef[$key."_original_binary"])){
$value = $repDef[$key."_original_binary"];
}
}else if(strpos($type,"group_switch:") === 0){
$tmp = explode(":", $type);
$gSwitchName = $tmp[1];
$switchesGroups[substr($key, strlen($prefix))] = $gSwitchName;
}else if($type == "text/json"){
$value = json_decode($value, true);
}
if(!in_array($type, array("textarea", "boolean", "text/json"))){
$value = AJXP_Utils::sanitize($value, AJXP_SANITIZE_HTML);
}
unset($repDef[$key."_ajxptype"]);
}
if(isSet($repDef[$key."_checkbox"])){
$checked = $repDef[$key."_checkbox"] == "checked";
unset($repDef[$key."_checkbox"]);
if(!$checked) continue;
}
if(isSet($repDef[$key."_replication"])){
$repKey = $repDef[$key."_replication"];
if(!is_array($replicationGroups[$repKey])) $replicationGroups[$repKey] = array();
$replicationGroups[$repKey][] = $key;
}
$options[substr($key, strlen($prefix))] = $value;
unset($repDef[$key]);
}else{
if($key == "DISPLAY"){
$value = SystemTextEncoding::fromUTF8(AJXP_Utils::securePath($value));
}
$repDef[$key] = $value;
}
}
// DO SOMETHING WITH REPLICATED PARAMETERS?
if(count($switchesGroups)){
foreach($switchesGroups as $fieldName => $groupName){
if(isSet($options[$fieldName])){
$gValues = array();
$radic = $groupName."_".$options[$fieldName]."_";
foreach($options as $optN => $optV){
if(strpos($optN, $radic) === 0){
$newName = substr($optN, strlen($radic));
$gValues[$newName] = $optV;
}
}
}
$options[$fieldName."_group_switch"] = $options[$fieldName];
$options[$fieldName] = $gValues;
}
}
}
public static function cleanDibiDriverParameters($params){
if(!is_array($params)) return $params;
$value = $params["group_switch_value"];
if(isSet($value)){
if($value == "core"){
$bootStorage = ConfService::getBootConfStorageImpl();
$configs = $bootStorage->loadPluginConfig("core", "conf");
$params = $configs["DIBI_PRECONFIGURATION"];
}else{
unset($params["group_switch_value"]);
}
foreach($params as $k => $v){
$params[array_pop(explode("_", $k, 2))] = AJXP_VarsFilter::filter($v);
unset($params[$k]);
}
}
return $params;
}
public static function runCreateTablesQuery($p, $file){
require_once(AJXP_BIN_FOLDER."/dibi.compact.php");
$result = array();
if($p["driver"] == "sqlite" || $p["driver"] == "sqlite3"){
if(!file_exists(dirname($p["database"]))){
@mkdir(dirname($p["database"]), 0755, true);
}
dibi::connect($p);
$file = dirname($file) ."/". str_replace(".sql", ".sqlite", basename($file) );
$sql = file_get_contents($file);
dibi::begin();
$parts = explode("CREATE TABLE", $sql);
foreach($parts as $createPart){
if(empty($createPart)) continue;
$sqlPart = trim("CREATE TABLE".$createPart);
try{
dibi::nativeQuery($sqlPart);
$resKey = str_replace("\n", "", substr($sqlPart, 0, 50))."...";
$result[] = "OK: $resKey executed successfully";
}catch (DibiException $e){
$result[] = "ERROR! $sqlPart failed";
}
}
$message = implode("\n", $result);
dibi::commit();
dibi::disconnect();
}else{
dibi::connect($p);
$sql = file_get_contents($file);
$parts = explode("CREATE TABLE", $sql);
foreach($parts as $createPart){
if(empty($createPart)) continue;
$sqlPart = trim("CREATE TABLE".$createPart);
try{
dibi::nativeQuery($sqlPart);
$resKey = str_replace("\n", "", substr($sqlPart, 0, 50))."...";
$result[] = "OK: $resKey executed successfully";
}catch (DibiException $e){
$result[] = "ERROR! $sqlPart failed";
}
}
$message = implode("\n", $result);
dibi::disconnect();
}
if(strpos($message, "ERROR!")) return $message;
else return "SUCCESS:".$message;
}
}
\ No newline at end of file
<?php
/*~ class.phpmailer-lite.php
.---------------------------------------------------------------------------.
| Software: PHPMailer Lite - PHP email class |
| Version: 5.1 |
| Contact: via sourceforge.net support pages (also www.codeworxtech.com) |
| Info: http://phpmailer.sourceforge.net |
| Support: http://sourceforge.net/projects/phpmailer/ |
| ------------------------------------------------------------------------- |
| Admin: Andy Prevost (project admininistrator) |
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
| Founder: Brent R. Matzelle (original founder) |
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
| Copyright (c) 2001-2003, Brent R. Matzelle |
| ------------------------------------------------------------------------- |
| License: Distributed under the Lesser General Public License (LGPL) |
| http://www.gnu.org/copyleft/lesser.html |
| This program is distributed in the hope that it will be useful - WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. |
| ------------------------------------------------------------------------- |
| We offer a number of paid services (www.codeworxtech.com): |
| - Web Hosting on highly optimized fast and secure servers |
| - Technology Consulting |
| - Oursourcing (highly qualified programmers and graphic designers) |
'---------------------------------------------------------------------------'
*/
/**
* PHPMailer Lite - PHP email transport class
* NOTE: Requires PHP version 5 or later
* @package PHPMailer Lite
* @author Andy Prevost
* @author Marcus Bointon
* @copyright 2004 - 2009 Andy Prevost
* @version $Id: class.phpmailer-lite.php 447 2009-09-12 13:21:38Z codeworxtech $
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
*/
if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
class PHPMailerLite {
/////////////////////////////////////////////////
// PROPERTIES, PUBLIC
/////////////////////////////////////////////////
/**
* Email priority (1 = High, 3 = Normal, 5 = low).
* @var int
*/
public $Priority = 3;
/**
* Sets the CharSet of the message.
* @var string
*/
public $CharSet = 'iso-8859-1';
/**
* Sets the Content-type of the message.
* @var string
*/
public $ContentType = 'text/plain';
/**
* Sets the Encoding of the message. Options for this are
* "8bit", "7bit", "binary", "base64", and "quoted-printable".
* @var string
*/
public $Encoding = '8bit';
/**
* Holds the most recent mailer error message.
* @var string
*/
public $ErrorInfo = '';
/**
* Sets the From email address for the message.
* @var string
*/
public $From = 'root@localhost';
/**
* Sets the From name of the message.
* @var string
*/
public $FromName = 'Root User';
/**
* Sets the Sender email (Return-Path) of the message. If not empty,
* will be sent via -f to sendmail
* @var string
*/
public $Sender = '';
/**
* Sets the Subject of the message.
* @var string
*/
public $Subject = '';
/**
* Sets the Body of the message. This can be either an HTML or text body.
* If HTML then run IsHTML(true).
* @var string
*/
public $Body = '';
/**
* Sets the text-only body of the message. This automatically sets the
* email to multipart/alternative. This body can be read by mail
* clients that do not have HTML email capability such as mutt. Clients
* that can read HTML will view the normal Body.
* @var string
*/
public $AltBody = '';
/**
* Sets word wrapping on the body of the message to a given number of
* characters.
* @var int
*/
public $WordWrap = 0;
/**
* Method to send mail: ("mail", or "sendmail").
* @var string
*/
public $Mailer = 'sendmail';
/**
* Sets the path of the sendmail program.
* @var string
*/
public $Sendmail = '${:sendmail-script}';
/**
* Sets the email address that a reading confirmation will be sent.
* @var string
*/
public $ConfirmReadingTo = '';
/**
* Sets the hostname to use in Message-Id and Received headers
* and as default HELO string. If empty, the value returned
* by SERVER_NAME is used or 'localhost.localdomain'.
* @var string
*/
public $Hostname = '';
/**
* Sets the message ID to be used in the Message-Id header.
* If empty, a unique id will be generated.
* @var string
*/
public $MessageID = '';
/**
* Provides the ability to have the TO field process individual
* emails, instead of sending to entire TO addresses
* @var bool
*/
public $SingleTo = true;
/**
* If SingleTo is true, this provides the array to hold the email addresses
* @var bool
*/
public $SingleToArray = array();
/**
* Provides the ability to change the line ending
* @var string
*/
public $LE = "\n";
/**
* Used with DKIM DNS Resource Record
* @var string
*/
public $DKIM_selector = 'phpmailer';
/**
* Used with DKIM DNS Resource Record
* optional, in format of email address 'you@yourdomain.com'
* @var string
*/
public $DKIM_identity = '';
/**
* Used with DKIM DNS Resource Record
* required, in format of base domain 'yourdomain.com'
* @var string
*/
public $DKIM_domain = '';
/**
* Used with DKIM Digital Signing process
* optional
* @var string
*/
public $DKIM_passphrase = '';
/**
* Used with DKIM DNS Resource Record
* required, private key (read from /.htprivkey)
* @var string
*/
public $DKIM_private = '';
/**
* Callback Action function name
* the function that handles the result of the send email action. Parameters:
* bool $result result of the send action
* string $to email address of the recipient
* string $cc cc email addresses
* string $bcc bcc email addresses
* string $subject the subject
* string $body the email body
* @var string
*/
public $action_function = ''; //'callbackAction';
/**
* Sets the PHPMailer Version number
* @var string
*/
public $Version = 'Lite 5.1';
/////////////////////////////////////////////////
// PROPERTIES, PRIVATE AND PROTECTED
/////////////////////////////////////////////////
private $to = array();
private $cc = array();
private $bcc = array();
private $ReplyTo = array();
private $all_recipients = array();
private $attachment = array();
private $CustomHeader = array();
private $message_type = '';
private $boundary = array();
protected $language = array();
private $error_count = 0;
private $sign_cert_file = "";
private $sign_key_file = "";
private $sign_key_pass = "";
private $exceptions = false;
/////////////////////////////////////////////////
// CONSTANTS
/////////////////////////////////////////////////
const STOP_MESSAGE = 0; // message only, continue processing
const STOP_CONTINUE = 1; // message?, likely ok to continue processing
const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
/////////////////////////////////////////////////
// METHODS, VARIABLES
/////////////////////////////////////////////////
/**
* Constructor
* @param boolean $exceptions Should we throw external exceptions?
*/
public function __construct($exceptions = false) {
$this->exceptions = ($exceptions == true);
}
/**
* Sets message type to HTML.
* @param bool $ishtml
* @return void
*/
public function IsHTML($ishtml = true) {
if ($ishtml) {
$this->ContentType = 'text/html';
} else {
$this->ContentType = 'text/plain';
}
}
/**
* Sets Mailer to send message using PHP mail() function.
* @return void
*/
public function IsMail() {
$this->Mailer = 'mail';
}
/**
* Sets Mailer to send message using the $Sendmail program.
* @return void
*/
public function IsSendmail() {
if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
$this->Sendmail = '/var/qmail/bin/sendmail';
}
$this->Mailer = 'sendmail';
}
/**
* Sets Mailer to send message using the qmail MTA.
* @return void
*/
public function IsQmail() {
if (stristr(ini_get('sendmail_path'), 'qmail')) {
$this->Sendmail = '/var/qmail/bin/sendmail';
}
$this->Mailer = 'sendmail';
}
/////////////////////////////////////////////////
// METHODS, RECIPIENTS
/////////////////////////////////////////////////
/**
* Adds a "To" address.
* @param string $address
* @param string $name
* @return boolean true on success, false if address already used
*/
public function AddAddress($address, $name = '') {
return $this->AddAnAddress('to', $address, $name);
}
/**
* Adds a "Cc" address.
* Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
* @param string $address
* @param string $name
* @return boolean true on success, false if address already used
*/
public function AddCC($address, $name = '') {
return $this->AddAnAddress('cc', $address, $name);
}
/**
* Adds a "Bcc" address.
* Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
* @param string $address
* @param string $name
* @return boolean true on success, false if address already used
*/
public function AddBCC($address, $name = '') {
return $this->AddAnAddress('bcc', $address, $name);
}
/**
* Adds a "Reply-to" address.
* @param string $address
* @param string $name
* @return boolean
*/
public function AddReplyTo($address, $name = '') {
return $this->AddAnAddress('ReplyTo', $address, $name);
}
/**
* Adds an address to one of the recipient arrays
* Addresses that have been added already return false, but do not throw exceptions
* @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
* @param string $address The email address to send to
* @param string $name
* @return boolean true on success, false if address already used or invalid in some way
* @access private
*/
private function AddAnAddress($kind, $address, $name = '') {
if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
echo 'Invalid recipient array: ' . kind;
return false;
}
$address = trim($address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
if (!self::ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
echo $this->Lang('invalid_address').': '.$address;
return false;
}
if ($kind != 'ReplyTo') {
if (!isset($this->all_recipients[strtolower($address)])) {
array_push($this->$kind, array($address, $name));
$this->all_recipients[strtolower($address)] = true;
return true;
}
} else {
if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
$this->ReplyTo[strtolower($address)] = array($address, $name);
return true;
}
}
return false;
}
/**
* Set the From and FromName properties
* @param string $address
* @param string $name
* @return boolean
*/
public function SetFrom($address, $name = '',$auto=1) {
$address = trim($address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
if (!self::ValidateAddress($address)) {
$this->SetError($this->Lang('invalid_address').': '. $address);
if ($this->exceptions) {
throw new phpmailerException($this->Lang('invalid_address').': '.$address);
}
echo $this->Lang('invalid_address').': '.$address;
return false;
}
$this->From = $address;
$this->FromName = $name;
if ($auto) {
if (empty($this->ReplyTo)) {
$this->AddAnAddress('ReplyTo', $address, $name);
}
if (empty($this->Sender)) {
$this->Sender = $address;
}
}
return true;
}
/**
* Check that a string looks roughly like an email address should
* Static so it can be used without instantiation
* Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
* Conforms approximately to RFC2822
* @link http://www.hexillion.com/samples/#Regex Original pattern found here
* @param string $address The email address to check
* @return boolean
* @static
* @access public
*/
public static function ValidateAddress($address) {
if (function_exists('filter_var')) { //Introduced in PHP 5.2
if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
return false;
} else {
return true;
}
} else {
return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
}
}
/////////////////////////////////////////////////
// METHODS, MAIL SENDING
/////////////////////////////////////////////////
/**
* Creates message and assigns Mailer. If the message is
* not sent successfully then it returns false. Use the ErrorInfo
* variable to view description of the error.
* @return bool
*/
public function Send() {
try {
if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
}
// Set whether the message is multipart/alternative
if(!empty($this->AltBody)) {
$this->ContentType = 'multipart/alternative';
}
$this->error_count = 0; // reset errors
$this->SetMessageType();
$header = $this->CreateHeader();
$body = $this->CreateBody();
if (empty($this->Body)) {
throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
}
// digitally sign with DKIM if enabled
if ($this->DKIM_domain && $this->DKIM_private) {
$header_dkim = $this->DKIM_Add($header,$this->Subject,$body);
$header = str_replace("\r\n","\n",$header_dkim) . $header;
}
// Choose the mailer and send through it
switch($this->Mailer) {
case 'sendmail':
$sendAction = $this->SendmailSend($header, $body);
return $sendAction;
default:
$sendAction = $this->MailSend($header, $body);
return $sendAction;
}
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
echo $e->getMessage()."\n";
return false;
}
}
/**
* Sends mail using the $Sendmail program.
* @param string $header The message headers
* @param string $body The message body
* @access protected
* @return bool
*/
protected function SendmailSend($header, $body) {
if ($this->Sender != '') {
$sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
} else {
$sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
}
if ($this->SingleTo === true) {
foreach ($this->SingleToArray as $key => $val) {
if(!@$mail = popen($sendmail, 'w')) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fputs($mail, "To: " . $val . "\n");
fputs($mail, $header);
fputs($mail, $body);
$result = pclose($mail);
// implement call back function if it exists
$isSent = ($result == 0) ? 1 : 0;
$this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
if($result != 0) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
} else {
if(!@$mail = popen($sendmail, 'w')) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fputs($mail, $header);
fputs($mail, $body);
$result = pclose($mail);
// implement call back function if it exists
$isSent = ($result == 0) ? 1 : 0;
$this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
if($result != 0) {
throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
return true;
}
/**
* Sends mail using the PHP mail() function.
* @param string $header The message headers
* @param string $body The message body
* @access protected
* @return bool
*/
protected function MailSend($header, $body) {
$toArr = array();
foreach($this->to as $t) {
$toArr[] = $this->AddrFormat($t);
}
$to = implode(', ', $toArr);
$params = sprintf("-oi -f %s", $this->Sender);
if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
$old_from = ini_get('sendmail_from');
ini_set('sendmail_from', $this->Sender);
if ($this->SingleTo === true && count($toArr) > 1) {
foreach ($toArr as $key => $val) {
$rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
}
} else {
$rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
}
} else {
if ($this->SingleTo === true && count($toArr) > 1) {
foreach ($toArr as $key => $val) {
$rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
}
} else {
$rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
// implement call back function if it exists
$isSent = ($rt == 1) ? 1 : 0;
$this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
}
}
if (isset($old_from)) {
ini_set('sendmail_from', $old_from);
}
if(!$rt) {
throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
}
return true;
}
/**
* Sets the language for all class error messages.
* Returns false if it cannot load the language file. The default language is English.
* @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
* @param string $lang_path Path to the language file directory
* @access public
*/
function SetLanguage($langcode = 'en', $lang_path = 'language/') {
//Define full set of translatable strings
$PHPMAILER_LANG = array(
'provide_address' => 'You must provide at least one recipient email address.',
'mailer_not_supported' => ' mailer is not supported.',
'execute' => 'Could not execute: ',
'instantiate' => 'Could not instantiate mail function.',
'from_failed' => 'The following From address failed: ',
'file_access' => 'Could not access file: ',
'file_open' => 'File Error: Could not open file: ',
'encoding' => 'Unknown encoding: ',
'signing' => 'Signing Error: ',
'empty_message' => 'Message body empty',
'invalid_address' => 'Invalid address',
'variable_set' => 'Cannot set or reset variable: '
);
//Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
$l = true;
if ($langcode != 'en') { //There is no English translation file
$l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
}
$this->language = $PHPMAILER_LANG;
return ($l == true); //Returns false if language not found
}
/**
* Return the current array of language strings
* @return array
*/
public function GetTranslations() {
return $this->language;
}
/////////////////////////////////////////////////
// METHODS, MESSAGE CREATION
/////////////////////////////////////////////////
/**
* Creates recipient headers.
* @access public
* @return string
*/
public function AddrAppend($type, $addr) {
$addr_str = $type . ': ';
$addresses = array();
foreach ($addr as $a) {
$addresses[] = $this->AddrFormat($a);
}
$addr_str .= implode(', ', $addresses);
$addr_str .= $this->LE;
return $addr_str;
}
/**
* Formats an address correctly.
* @access public
* @return string
*/
public function AddrFormat($addr) {
if (empty($addr[1])) {
return $this->SecureHeader($addr[0]);
} else {
return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
}
}
/**
* Wraps message for use with mailers that do not
* automatically perform wrapping and for quoted-printable.
* Original written by philippe.
* @param string $message The message to wrap
* @param integer $length The line length to wrap to
* @param boolean $qp_mode Whether to run in Quoted-Printable mode
* @access public
* @return string
*/
public function WrapText($message, $length, $qp_mode = false) {
$soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
// If utf-8 encoding is used, we will need to make sure we don't
// split multibyte characters when we wrap
$is_utf8 = (strtolower($this->CharSet) == "utf-8");
$message = $this->FixEOL($message);
if (substr($message, -1) == $this->LE) {
$message = substr($message, 0, -1);
}
$line = explode($this->LE, $message);
$message = '';
for ($i=0 ;$i < count($line); $i++) {
$line_part = explode(' ', $line[$i]);
$buf = '';
for ($e = 0; $e<count($line_part); $e++) {
$word = $line_part[$e];
if ($qp_mode and (strlen($word) > $length)) {
$space_left = $length - strlen($buf) - 1;
if ($e != 0) {
if ($space_left > 20) {
$len = $space_left;
if ($is_utf8) {
$len = $this->UTF8CharBoundary($word, $len);
} elseif (substr($word, $len - 1, 1) == "=") {
$len--;
} elseif (substr($word, $len - 2, 1) == "=") {
$len -= 2;
}
$part = substr($word, 0, $len);
$word = substr($word, $len);
$buf .= ' ' . $part;
$message .= $buf . sprintf("=%s", $this->LE);
} else {
$message .= $buf . $soft_break;
}
$buf = '';
}
while (strlen($word) > 0) {
$len = $length;
if ($is_utf8) {
$len = $this->UTF8CharBoundary($word, $len);
} elseif (substr($word, $len - 1, 1) == "=") {
$len--;
} elseif (substr($word, $len - 2, 1) == "=") {
$len -= 2;
}
$part = substr($word, 0, $len);
$word = substr($word, $len);
if (strlen($word) > 0) {
$message .= $part . sprintf("=%s", $this->LE);
} else {
$buf = $part;
}
}
} else {
$buf_o = $buf;
$buf .= ($e == 0) ? $word : (' ' . $word);
if (strlen($buf) > $length and $buf_o != '') {
$message .= $buf_o . $soft_break;
$buf = $word;
}
}
}
$message .= $buf . $this->LE;
}
return $message;
}
/**
* Finds last character boundary prior to maxLength in a utf-8
* quoted (printable) encoded string.
* Original written by Colin Brown.
* @access public
* @param string $encodedText utf-8 QP text
* @param int $maxLength find last character boundary prior to this length
* @return int
*/
public function UTF8CharBoundary($encodedText, $maxLength) {
$foundSplitPos = false;
$lookBack = 3;
while (!$foundSplitPos) {
$lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
$encodedCharPos = strpos($lastChunk, "=");
if ($encodedCharPos !== false) {
// Found start of encoded character byte within $lookBack block.
// Check the encoded byte value (the 2 chars after the '=')
$hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
$dec = hexdec($hex);
if ($dec < 128) { // Single byte character.
// If the encoded char was found at pos 0, it will fit
// otherwise reduce maxLength to start of the encoded char
$maxLength = ($encodedCharPos == 0) ? $maxLength :
$maxLength - ($lookBack - $encodedCharPos);
$foundSplitPos = true;
} elseif ($dec >= 192) { // First byte of a multi byte character
// Reduce maxLength to split at start of character
$maxLength = $maxLength - ($lookBack - $encodedCharPos);
$foundSplitPos = true;
} elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
$lookBack += 3;
}
} else {
// No encoded character found
$foundSplitPos = true;
}
}
return $maxLength;
}
/**
* Set the body wrapping.
* @access public
* @return void
*/
public function SetWordWrap() {
if($this->WordWrap < 1) {
return;
}
switch($this->message_type) {
case 'alt':
case 'alt_attachments':
$this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
break;
default:
$this->Body = $this->WrapText($this->Body, $this->WordWrap);
break;
}
}
/**
* Assembles message header.
* @access public
* @return string The assembled header
*/
public function CreateHeader() {
$result = '';
// Set the boundaries
$uniq_id = md5(uniqid(time()));
$this->boundary[1] = 'b1_' . $uniq_id;
$this->boundary[2] = 'b2_' . $uniq_id;
$result .= $this->HeaderLine('Date', self::RFCDate());
if($this->Sender == '') {
$result .= $this->HeaderLine('Return-Path', trim($this->From));
} else {
$result .= $this->HeaderLine('Return-Path', trim($this->Sender));
}
// To be created automatically by mail()
if($this->Mailer != 'mail') {
if ($this->SingleTo === true) {
foreach($this->to as $t) {
$this->SingleToArray[] = $this->AddrFormat($t);
}
} else {
if(count($this->to) > 0) {
$result .= $this->AddrAppend('To', $this->to);
} elseif (count($this->cc) == 0) {
$result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
}
}
}
$from = array();
$from[0][0] = trim($this->From);
$from[0][1] = $this->FromName;
$result .= $this->AddrAppend('From', $from);
// sendmail and mail() extract Cc from the header before sending
if(count($this->cc) > 0) {
$result .= $this->AddrAppend('Cc', $this->cc);
}
// sendmail and mail() extract Bcc from the header before sending
if(count($this->bcc) > 0) {
$result .= $this->AddrAppend('Bcc', $this->bcc);
}
if(count($this->ReplyTo) > 0) {
$result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
}
// mail() sets the subject itself
if($this->Mailer != 'mail') {
$result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
}
if($this->MessageID != '') {
$result .= $this->HeaderLine('Message-ID',$this->MessageID);
} else {
$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
}
$result .= $this->HeaderLine('X-Priority', $this->Priority);
$result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.codeworxtech.com)');
if($this->ConfirmReadingTo != '') {
$result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
}
// Add custom headers
for($index = 0; $index < count($this->CustomHeader); $index++) {
$result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
}
if (!$this->sign_key_file) {
$result .= $this->HeaderLine('MIME-Version', '1.0');
$result .= $this->GetMailMIME();
}
return $result;
}
/**
* Returns the message MIME.
* @access public
* @return string
*/
public function GetMailMIME() {
$result = '';
switch($this->message_type) {
case 'plain':
$result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
$result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
break;
case 'attachments':
case 'alt_attachments':
if($this->InlineImageExists()){
$result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
} else {
$result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
$result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
}
break;
case 'alt':
$result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
$result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
break;
}
if($this->Mailer != 'mail') {
$result .= $this->LE.$this->LE;
}
return $result;
}
/**
* Assembles the message body. Returns an empty string on failure.
* @access public
* @return string The assembled message body
*/
public function CreateBody() {
$body = '';
if ($this->sign_key_file) {
$body .= $this->GetMailMIME();
}
$this->SetWordWrap();
switch($this->message_type) {
case 'alt':
$body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->EndBoundary($this->boundary[1]);
break;
case 'plain':
$body .= $this->EncodeString($this->Body, $this->Encoding);
break;
case 'attachments':
$body .= $this->GetBoundary($this->boundary[1], '', '', '');
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE;
$body .= $this->AttachAll();
break;
case 'alt_attachments':
$body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
$body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
$body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
$body .= $this->EncodeString($this->AltBody, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
$body .= $this->EncodeString($this->Body, $this->Encoding);
$body .= $this->LE.$this->LE;
$body .= $this->EndBoundary($this->boundary[2]);
$body .= $this->AttachAll();
break;
}
if ($this->IsError()) {
$body = '';
} elseif ($this->sign_key_file) {
try {
$file = tempnam('', 'mail');
file_put_contents($file, $body); //TODO check this worked
$signed = tempnam("", "signed");
if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
@unlink($file);
@unlink($signed);
$body = file_get_contents($signed);
} else {
@unlink($file);
@unlink($signed);
throw new phpmailerException($this->Lang("signing").openssl_error_string());
}
} catch (phpmailerException $e) {
$body = '';
if ($this->exceptions) {
throw $e;
}
}
}
return $body;
}
/**
* Returns the start of a message boundary.
* @access private
*/
private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
$result = '';
if($charSet == '') {
$charSet = $this->CharSet;
}
if($contentType == '') {
$contentType = $this->ContentType;
}
if($encoding == '') {
$encoding = $this->Encoding;
}
$result .= $this->TextLine('--' . $boundary);
$result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
$result .= $this->LE;
$result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
$result .= $this->LE;
return $result;
}
/**
* Returns the end of a message boundary.
* @access private
*/
private function EndBoundary($boundary) {
return $this->LE . '--' . $boundary . '--' . $this->LE;
}
/**
* Sets the message type.
* @access private
* @return void
*/
private function SetMessageType() {
if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
$this->message_type = 'plain';
} else {
if(count($this->attachment) > 0) {
$this->message_type = 'attachments';
}
if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
$this->message_type = 'alt';
}
if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
$this->message_type = 'alt_attachments';
}
}
}
/**
* Returns a formatted header line.
* @access public
* @return string
*/
public function HeaderLine($name, $value) {
return $name . ': ' . $value . $this->LE;
}
/**
* Returns a formatted mail line.
* @access public
* @return string
*/
public function TextLine($value) {
return $value . $this->LE;
}
/////////////////////////////////////////////////
// CLASS METHODS, ATTACHMENTS
/////////////////////////////////////////////////
/**
* Adds an attachment from a path on the filesystem.
* Returns false if the file could not be found
* or accessed.
* @param string $path Path to the attachment.
* @param string $name Overrides the attachment name.
* @param string $encoding File encoding (see $Encoding).
* @param string $type File extension (MIME) type.
* @return bool
*/
public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
try {
if ( !@is_file($path) ) {
throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
}
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
}
$this->attachment[] = array(
0 => $path,
1 => $filename,
2 => $name,
3 => $encoding,
4 => $type,
5 => false, // isStringAttachment
6 => 'attachment',
7 => 0
);
} catch (phpmailerException $e) {
$this->SetError($e->getMessage());
if ($this->exceptions) {
throw $e;
}
echo $e->getMessage()."\n";
if ( $e->getCode() == self::STOP_CRITICAL ) {
return false;
}
}
return true;
}
/**
* Return the current array of attachments
* @return array
*/
public function GetAttachments() {
return $this->attachment;
}
/**
* Attaches all fs, string, and binary attachments to the message.
* Returns an empty string on failure.
* @access private
* @return string
*/
private function AttachAll() {
// Return text of body
$mime = array();
$cidUniq = array();
$incl = array();
// Add all attachments
foreach ($this->attachment as $attachment) {
// Check for string attachment
$bString = $attachment[5];
if ($bString) {
$string = $attachment[0];
} else {
$path = $attachment[0];
}
if (in_array($attachment[0], $incl)) { continue; }
$filename = $attachment[1];
$name = $attachment[2];
$encoding = $attachment[3];
$type = $attachment[4];
$disposition = $attachment[6];
$cid = $attachment[7];
$incl[] = $attachment[0];
if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
$cidUniq[$cid] = true;
$mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
$mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
$mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
if($disposition == 'inline') {
$mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
}
$mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
// Encode as string attachment
if($bString) {
$mime[] = $this->EncodeString($string, $encoding);
if($this->IsError()) {
return '';
}
$mime[] = $this->LE.$this->LE;
} else {
$mime[] = $this->EncodeFile($path, $encoding);
if($this->IsError()) {
return '';
}
$mime[] = $this->LE.$this->LE;
}
}
$mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
return join('', $mime);
}
/**
* Encodes attachment in requested format.
* Returns an empty string on failure.
* @param string $path The full path to the file
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
* @see EncodeFile()
* @access private
* @return string
*/
private function EncodeFile($path, $encoding = 'base64') {
try {
if (!is_readable($path)) {
throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
}
if (function_exists('get_magic_quotes')) {
function get_magic_quotes() {
return false;
}
}
if (PHP_VERSION < 6) {
$magic_quotes = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
}
$file_buffer = file_get_contents($path);
$file_buffer = $this->EncodeString($file_buffer, $encoding);
if (PHP_VERSION < 6) { set_magic_quotes_runtime($magic_quotes); }
return $file_buffer;
} catch (Exception $e) {
$this->SetError($e->getMessage());
return '';
}
}
/**
* Encodes string to requested format.
* Returns an empty string on failure.
* @param string $str The text to encode
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
* @access public
* @return string
*/
public function EncodeString ($str, $encoding = 'base64') {
$encoded = '';
switch(strtolower($encoding)) {
case 'base64':
$encoded = chunk_split(base64_encode($str), 76, $this->LE);
break;
case '7bit':
case '8bit':
$encoded = $this->FixEOL($str);
//Make sure it ends with a line break
if (substr($encoded, -(strlen($this->LE))) != $this->LE)
$encoded .= $this->LE;
break;
case 'binary':
$encoded = $str;
break;
case 'quoted-printable':
$encoded = $this->EncodeQP($str);
break;
default:
$this->SetError($this->Lang('encoding') . $encoding);
break;
}
return $encoded;
}
/**
* Encode a header string to best (shortest) of Q, B, quoted or none.
* @access public
* @return string
*/
public function EncodeHeader($str, $position = 'text') {
$x = 0;
switch (strtolower($position)) {
case 'phrase':
if (!preg_match('/[\200-\377]/', $str)) {
// Can't use addslashes as we don't know what value has magic_quotes_sybase
$encoded = addcslashes($str, "\0..\37\177\\\"");
if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
return ($encoded);
} else {
return ("\"$encoded\"");
}
}
$x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
break;
case 'comment':
$x = preg_match_all('/[()"]/', $str, $matches);
// Fall-through
case 'text':
default:
$x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
break;
}
if ($x == 0) {
return ($str);
}
$maxlen = 75 - 7 - strlen($this->CharSet);
// Try to select the encoding which should produce the shortest output
if (strlen($str)/3 < $x) {
$encoding = 'B';
if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
// Use a custom function which correctly encodes and wraps long
// multibyte strings without breaking lines within a character
$encoded = $this->Base64EncodeWrapMB($str);
} else {
$encoded = base64_encode($str);
$maxlen -= $maxlen % 4;
$encoded = trim(chunk_split($encoded, $maxlen, "\n"));
}
} else {
$encoding = 'Q';
$encoded = $this->EncodeQ($str, $position);
$encoded = $this->WrapText($encoded, $maxlen, true);
$encoded = str_replace('='.$this->LE, "\n", trim($encoded));
}
$encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
$encoded = trim(str_replace("\n", $this->LE, $encoded));
return $encoded;
}
/**
* Checks if a string contains multibyte characters.
* @access public
* @param string $str multi-byte text to wrap encode
* @return bool
*/
public function HasMultiBytes($str) {
if (function_exists('mb_strlen')) {
return (strlen($str) > mb_strlen($str, $this->CharSet));
} else { // Assume no multibytes (we can't handle without mbstring functions anyway)
return false;
}
}
/**
* Correctly encodes and wraps long multibyte strings for mail headers
* without breaking lines within a character.
* Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
* @access public
* @param string $str multi-byte text to wrap encode
* @return string
*/
public function Base64EncodeWrapMB($str) {
$start = "=?".$this->CharSet."?B?";
$end = "?=";
$encoded = "";
$mb_length = mb_strlen($str, $this->CharSet);
// Each line must have length <= 75, including $start and $end
$length = 75 - strlen($start) - strlen($end);
// Average multi-byte ratio
$ratio = $mb_length / strlen($str);
// Base64 has a 4:3 ratio
$offset = $avgLength = floor($length * $ratio * .75);
for ($i = 0; $i < $mb_length; $i += $offset) {
$lookBack = 0;
do {
$offset = $avgLength - $lookBack;
$chunk = mb_substr($str, $i, $offset, $this->CharSet);
$chunk = base64_encode($chunk);
$lookBack++;
}
while (strlen($chunk) > $length);
$encoded .= $chunk . $this->LE;
}
// Chomp the last linefeed
$encoded = substr($encoded, 0, -strlen($this->LE));
return $encoded;
}
/**
* Encode string to quoted-printable.
* Only uses standard PHP, slow, but will always work
* @access public
* @param string $string the text to encode
* @param integer $line_max Number of chars allowed on a line before wrapping
* @return string
*/
public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
$lines = preg_split('/(?:\r\n|\r|\n)/', $input);
$eol = "\r\n";
$escape = '=';
$output = '';
while( list(, $line) = each($lines) ) {
$linlen = strlen($line);
$newline = '';
for($i = 0; $i < $linlen; $i++) {
$c = substr( $line, $i, 1 );
$dec = ord( $c );
if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
$c = '=2E';
}
if ( $dec == 32 ) {
if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
$c = '=20';
} else if ( $space_conv ) {
$c = '=20';
}
} elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
$h2 = floor($dec/16);
$h1 = floor($dec%16);
$c = $escape.$hex[$h2].$hex[$h1];
}
if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
$output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
$newline = '';
// check if newline first character will be point or not
if ( $dec == 46 ) {
$c = '=2E';
}
}
$newline .= $c;
} // end of for
$output .= $newline.$eol;
} // end of while
return $output;
}
/**
* Encode string to RFC2045 (6.7) quoted-printable format
* Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
* Also results in same content as you started with after decoding
* @see EncodeQPphp()
* @access public
* @param string $string the text to encode
* @param integer $line_max Number of chars allowed on a line before wrapping
* @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
* @return string
* @author Marcus Bointon
*/
public function EncodeQP($string, $line_max = 76, $space_conv = false) {
if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
return quoted_printable_encode($string);
}
$filters = stream_get_filters();
if (!in_array('convert.*', $filters)) { //Got convert stream filter?
return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
}
$fp = fopen('php://temp/', 'r+');
$string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
$params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
$s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
fputs($fp, $string);
rewind($fp);
$out = stream_get_contents($fp);
stream_filter_remove($s);
$out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
fclose($fp);
return $out;
}
/**
* Encode string to q encoding.
* @link http://tools.ietf.org/html/rfc2047
* @param string $str the text to encode
* @param string $position Where the text is going to be used, see the RFC for what that means
* @access public
* @return string
*/
public function EncodeQ ($str, $position = 'text') {
// There should not be any EOL in the string
$encoded = preg_replace('/[\r\n]*/', '', $str);
switch (strtolower($position)) {
case 'phrase':
$encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
break;
case 'comment':
$encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
case 'text':
default:
// Replace every high ascii, control =, ? and _ characters
//TODO using /e (equivalent to eval()) is probably not a good idea
$encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
"'='.sprintf('%02X', ord('\\1'))", $encoded);
break;
}
// Replace every spaces to _ (more readable than =20)
$encoded = str_replace(' ', '_', $encoded);
return $encoded;
}
/**
* Adds a string or binary attachment (non-filesystem) to the list.
* This method can be used to attach ascii or binary data,
* such as a BLOB record from a database.
* @param string $string String attachment data.
* @param string $filename Name of the attachment.
* @param string $encoding File encoding (see $Encoding).
* @param string $type File extension (MIME) type.
* @return void
*/
public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
// Append to $attachment array
$this->attachment[] = array(
0 => $string,
1 => $filename,
2 => basename($filename),
3 => $encoding,
4 => $type,
5 => true, // isStringAttachment
6 => 'attachment',
7 => 0
);
}
/**
* Adds an embedded attachment. This can include images, sounds, and
* just about any other document. Make sure to set the $type to an
* image type. For JPEG images use "image/jpeg" and for GIF images
* use "image/gif".
* @param string $path Path to the attachment.
* @param string $cid Content ID of the attachment. Use this to identify
* the Id for accessing the image in an HTML form.
* @param string $name Overrides the attachment name.
* @param string $encoding File encoding (see $Encoding).
* @param string $type File extension (MIME) type.
* @return bool
*/
public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
if ( !@is_file($path) ) {
$this->SetError($this->Lang('file_access') . $path);
return false;
}
$filename = basename($path);
if ( $name == '' ) {
$name = $filename;
}
// Append to $attachment array
$this->attachment[] = array(
0 => $path,
1 => $filename,
2 => $name,
3 => $encoding,
4 => $type,
5 => false, // isStringAttachment
6 => 'inline',
7 => $cid
);
return true;
}
/**
* Returns true if an inline attachment is present.
* @access public
* @return bool
*/
public function InlineImageExists() {
foreach($this->attachment as $attachment) {
if ($attachment[6] == 'inline') {
return true;
}
}
return false;
}
/////////////////////////////////////////////////
// CLASS METHODS, MESSAGE RESET
/////////////////////////////////////////////////
/**
* Clears all recipients assigned in the TO array. Returns void.
* @return void
*/
public function ClearAddresses() {
foreach($this->to as $to) {
unset($this->all_recipients[strtolower($to[0])]);
}
$this->to = array();
}
/**
* Clears all recipients assigned in the CC array. Returns void.
* @return void
*/
public function ClearCCs() {
foreach($this->cc as $cc) {
unset($this->all_recipients[strtolower($cc[0])]);
}
$this->cc = array();
}
/**
* Clears all recipients assigned in the BCC array. Returns void.
* @return void
*/
public function ClearBCCs() {
foreach($this->bcc as $bcc) {
unset($this->all_recipients[strtolower($bcc[0])]);
}
$this->bcc = array();
}
/**
* Clears all recipients assigned in the ReplyTo array. Returns void.
* @return void
*/
public function ClearReplyTos() {
$this->ReplyTo = array();
}
/**
* Clears all recipients assigned in the TO, CC and BCC
* array. Returns void.
* @return void
*/
public function ClearAllRecipients() {
$this->to = array();
$this->cc = array();
$this->bcc = array();
$this->all_recipients = array();
}
/**
* Clears all previously set filesystem, string, and binary
* attachments. Returns void.
* @return void
*/
public function ClearAttachments() {
$this->attachment = array();
}
/**
* Clears all custom headers. Returns void.
* @return void
*/
public function ClearCustomHeaders() {
$this->CustomHeader = array();
}
/////////////////////////////////////////////////
// CLASS METHODS, MISCELLANEOUS
/////////////////////////////////////////////////
/**
* Adds the error message to the error container.
* @access protected
* @return void
*/
protected function SetError($msg) {
$this->error_count++;
$this->ErrorInfo = $msg;
}
/**
* Returns the proper RFC 822 formatted date.
* @access public
* @return string
* @static
*/
public static function RFCDate() {
$tz = date('Z');
$tzs = ($tz < 0) ? '-' : '+';
$tz = abs($tz);
$tz = (int)($tz/3600)*100 + ($tz%3600)/60;
$result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
return $result;
}
/**
* Returns the server hostname or 'localhost.localdomain' if unknown.
* @access private
* @return string
*/
private function ServerHostname() {
if (!empty($this->Hostname)) {
$result = $this->Hostname;
} elseif (isset($_SERVER['SERVER_NAME'])) {
$result = $_SERVER['SERVER_NAME'];
} else {
$result = 'localhost.localdomain';
}
return $result;
}
/**
* Returns a message in the appropriate language.
* @access private
* @return string
*/
private function Lang($key) {
if(count($this->language) < 1) {
$this->SetLanguage('en'); // set the default language
}
if(isset($this->language[$key])) {
return $this->language[$key];
} else {
return 'Language string failed to load: ' . $key;
}
}
/**
* Returns true if an error occurred.
* @access public
* @return bool
*/
public function IsError() {
return ($this->error_count > 0);
}
/**
* Changes every end of line from CR or LF to CRLF.
* @access private
* @return string
*/
private function FixEOL($str) {
$str = str_replace("\r\n", "\n", $str);
$str = str_replace("\r", "\n", $str);
$str = str_replace("\n", $this->LE, $str);
return $str;
}
/**
* Adds a custom header.
* @access public
* @return void
*/
public function AddCustomHeader($custom_header) {
$this->CustomHeader[] = explode(':', $custom_header, 2);
}
/**
* Evaluates the message and returns modifications for inline images and backgrounds
* @access public
* @return $message
*/
public function MsgHTML($message, $basedir = '') {
preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
if(isset($images[2])) {
foreach($images[2] as $i => $url) {
// do not change urls for absolute images (thanks to corvuscorax)
if (!preg_match('#^[A-z]+://#',$url)) {
$filename = basename($url);
$directory = dirname($url);
($directory == '.')?$directory='':'';
$cid = 'cid:' . md5($filename);
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$mimeType = self::_mime_types($ext);
if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
$message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
}
}
}
}
$this->IsHTML(true);
$this->Body = $message;
$textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
if (!empty($textMsg) && empty($this->AltBody)) {
$this->AltBody = html_entity_decode($textMsg);
}
if (empty($this->AltBody)) {
$this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
}
}
/**
* Gets the MIME type of the embedded or inline image
* @param string File extension
* @access public
* @return string MIME type of ext
* @static
*/
public static function _mime_types($ext = '') {
$mimes = array(
'hqx' => 'application/mac-binhex40',
'cpt' => 'application/mac-compactpro',
'doc' => 'application/msword',
'bin' => 'application/macbinary',
'dms' => 'application/octet-stream',
'lha' => 'application/octet-stream',
'lzh' => 'application/octet-stream',
'exe' => 'application/octet-stream',
'class' => 'application/octet-stream',
'psd' => 'application/octet-stream',
'so' => 'application/octet-stream',
'sea' => 'application/octet-stream',
'dll' => 'application/octet-stream',
'oda' => 'application/oda',
'pdf' => 'application/pdf',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
'smi' => 'application/smil',
'smil' => 'application/smil',
'mif' => 'application/vnd.mif',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'wbxml' => 'application/vnd.wap.wbxml',
'wmlc' => 'application/vnd.wap.wmlc',
'dcr' => 'application/x-director',
'dir' => 'application/x-director',
'dxr' => 'application/x-director',
'dvi' => 'application/x-dvi',
'gtar' => 'application/x-gtar',
'php' => 'application/x-httpd-php',
'php4' => 'application/x-httpd-php',
'php3' => 'application/x-httpd-php',
'phtml' => 'application/x-httpd-php',
'phps' => 'application/x-httpd-php-source',
'js' => 'application/x-javascript',
'swf' => 'application/x-shockwave-flash',
'sit' => 'application/x-stuffit',
'tar' => 'application/x-tar',
'tgz' => 'application/x-tar',
'xhtml' => 'application/xhtml+xml',
'xht' => 'application/xhtml+xml',
'zip' => 'application/zip',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mpga' => 'audio/mpeg',
'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'aif' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'ram' => 'audio/x-pn-realaudio',
'rm' => 'audio/x-pn-realaudio',
'rpm' => 'audio/x-pn-realaudio-plugin',
'ra' => 'audio/x-realaudio',
'rv' => 'video/vnd.rn-realvideo',
'wav' => 'audio/x-wav',
'bmp' => 'image/bmp',
'gif' => 'image/gif',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'png' => 'image/png',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'css' => 'text/css',
'html' => 'text/html',
'htm' => 'text/html',
'shtml' => 'text/html',
'txt' => 'text/plain',
'text' => 'text/plain',
'log' => 'text/plain',
'rtx' => 'text/richtext',
'rtf' => 'text/rtf',
'xml' => 'text/xml',
'xsl' => 'text/xml',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
'avi' => 'video/x-msvideo',
'movie' => 'video/x-sgi-movie',
'doc' => 'application/msword',
'word' => 'application/msword',
'xl' => 'application/excel',
'eml' => 'message/rfc822'
);
return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
}
/**
* Set (or reset) Class Objects (variables)
*
* Usage Example:
* $page->set('X-Priority', '3');
*
* @access public
* @param string $name Parameter Name
* @param mixed $value Parameter Value
* NOTE: will not work with arrays, there are no arrays to set/reset
* @todo Should this not be using __set() magic function?
*/
public function set($name, $value = '') {
try {
if (isset($this->$name) ) {
$this->$name = $value;
} else {
throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
}
} catch (Exception $e) {
$this->SetError($e->getMessage());
if ($e->getCode() == self::STOP_CRITICAL) {
return false;
}
}
return true;
}
/**
* Strips newlines to prevent header injection.
* @access public
* @param string $str String
* @return string
*/
public function SecureHeader($str) {
$str = str_replace("\r", '', $str);
$str = str_replace("\n", '', $str);
return trim($str);
}
/**
* Set the private key file and password to sign the message.
*
* @access public
* @param string $key_filename Parameter File Name
* @param string $key_pass Password for private key
*/
public function Sign($cert_filename, $key_filename, $key_pass) {
$this->sign_cert_file = $cert_filename;
$this->sign_key_file = $key_filename;
$this->sign_key_pass = $key_pass;
}
/**
* Set the private key file and password to sign the message.
*
* @access public
* @param string $key_filename Parameter File Name
* @param string $key_pass Password for private key
*/
public function DKIM_QP($txt) {
$tmp="";
$line="";
for ($i=0;$i<strlen($txt);$i++) {
$ord=ord($txt[$i]);
if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
$line.=$txt[$i];
} else {
$line.="=".sprintf("%02X",$ord);
}
}
return $line;
}
/**
* Generate DKIM signature
*
* @access public
* @param string $s Header
*/
public function DKIM_Sign($s) {
$privKeyStr = file_get_contents($this->DKIM_private);
if ($this->DKIM_passphrase!='') {
$privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase);
} else {
$privKey = $privKeyStr;
}
if (openssl_sign($s, $signature, $privKey)) {
return base64_encode($signature);
}
}
/**
* Generate DKIM Canonicalization Header
*
* @access public
* @param string $s Header
*/
public function DKIM_HeaderC($s) {
$s=preg_replace("/\r\n\s+/"," ",$s);
$lines=explode("\r\n",$s);
foreach ($lines as $key=>$line) {
list($heading,$value)=explode(":",$line,2);
$heading=strtolower($heading);
$value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces
$lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value
}
$s=implode("\r\n",$lines);
return $s;
}
/**
* Generate DKIM Canonicalization Body
*
* @access public
* @param string $body Message Body
*/
public function DKIM_BodyC($body) {
if ($body == '') return "\r\n";
// stabilize line endings
$body=str_replace("\r\n","\n",$body);
$body=str_replace("\n","\r\n",$body);
// END stabilize line endings
while (substr($body,strlen($body)-4,4) == "\r\n\r\n") {
$body=substr($body,0,strlen($body)-2);
}
return $body;
}
/**
* Create the DKIM header, body, as new header
*
* @access public
* @param string $headers_line Header lines
* @param string $subject Subject
* @param string $body Body
*/
public function DKIM_Add($headers_line,$subject,$body) {
$DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
$DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
$DKIMquery = 'dns/txt'; // Query method
$DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
$subject_header = "Subject: $subject";
$headers = explode("\r\n",$headers_line);
foreach($headers as $header) {
if (strpos($header,'From:') === 0) {
$from_header=$header;
} elseif (strpos($header,'To:') === 0) {
$to_header=$header;
}
}
$from = str_replace('|','=7C',$this->DKIM_QP($from_header));
$to = str_replace('|','=7C',$this->DKIM_QP($to_header));
$subject = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
$body = $this->DKIM_BodyC($body);
$DKIMlen = strlen($body) ; // Length of body
$DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
$ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
$dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
"\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
"\th=From:To:Subject;\r\n".
"\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
"\tz=$from\r\n".
"\t|$to\r\n".
"\t|$subject;\r\n".
"\tbh=" . $DKIMb64 . ";\r\n".
"\tb=";
$toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
$signed = $this->DKIM_Sign($toSign);
return "X-PHPMAILER-DKIM: phpmailer.sourceforge.net\r\n".$dkimhdrs.$signed."\r\n";
}
protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) {
if (!empty($this->action_function) && function_exists($this->action_function)) {
$params = array($isSent,$to,$cc,$bcc,$subject,$body);
call_user_func_array($this->action_function,$params);
}
}
}
class phpmailerException extends Exception {
public function errorMessage() {
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
return $errorMsg;
}
}
?>
\ No newline at end of file
var page = require('webpage').create();
var url = '${:content-url}';
page.open(url, function(status){
page.evaluate(function(){
function eventFire(el, etype){
if (el.fireEvent) {
(el.fireEvent('on' + etype));
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(etype, true, false);
el.dispatchEvent(evObj);
}
}
eventFire(document.getElementById('start_button'),'click');
document.getElementsByName('ADMIN_USER_LOGIN')[0].setValue('${:user}');
document.getElementsByName('ADMIN_USER_NAME')[0].setValue('${:user}');
document.getElementsByName('ADMIN_USER_PASS')[0].setValue('${:password}');
document.getElementsByName('ADMIN_USER_PASS2')[0].setValue('${:password}');
document.getElementsByName('STORAGE_TYPE')[0].setValue('${:storage-type}');
var button = document.getElementById('save_button')
button.removeClassName('disabled');
eventFire(button,'click');
});
phantom.exit();
});
<?xml version="1.0" encoding="UTF-8"?>
<ajxpcore id="core.ajaxplorer" label="CONF_MESSAGE[AjaXplorer Main Options]"
description="CONF_MESSAGE[Main container for core AjaXplorer settings (application title, sharing, webdav server config, etc...)]"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="file:../core.ajaxplorer/ajxp_registry.xsd"
>
<plugin_info>
<plugin_author>Charles du Jeu</plugin_author>
<plugin_version>follow</plugin_version>
<plugin_uri>http://ajaxplorer.info/plugins/core/ajaxplorer</plugin_uri>
<core_relation packaged="true" tested_version="follow_core"/>
</plugin_info>
<client_settings>
<resources>
<i18n namespace="" path="plugins/core.ajaxplorer/i18n"/>
</resources>
</client_settings>
<server_settings>
<global_param name="APPLICATION_TITLE" group="CONF_MESSAGE[Main]" type="string" label="CONF_MESSAGE[App Title]" description="CONF_MESSAGE[Your application title]" mandatory="true" default="AjaXplorer" expose="true"/>
<global_param name="DEFAULT_LANGUAGE" group="CONF_MESSAGE[Main]" type="select" choices="AJXP_AVAILABLE_LANGUAGES" label="CONF_MESSAGE[Default Language]" description="CONF_MESSAGE[Default language when a user does not have set his/her own.]" mandatory="true" default="${:language}"/>
<global_param name="SERVER_URL" group="CONF_MESSAGE[Main]" type="string" label="CONF_MESSAGE[Server URL]" description="CONF_MESSAGE[Server URL used to build share links and notifications. It will be detected if empty.]" mandatory="false"/>
<global_param name="PUBLIC_DOWNLOAD_FOLDER" group="CONF_MESSAGE[Sharing]" type="string" label="CONF_MESSAGE[Download Folder]" description="CONF_MESSAGE[Absolute path to the public folder where temporary download links will be created. Setting this empty will disable the sharing feature.]" mandatory="false" default="AJXP_INSTALL_PATH/data/public"/>
<global_param name="PUBLIC_DOWNLOAD_URL" group="CONF_MESSAGE[Sharing]" type="string" label="CONF_MESSAGE[Download URL]" description="CONF_MESSAGE[If not inferred directly from the current ajaxplorer URI plus the public download folder name, replace the public access URL here.]" mandatory="false" default=""/>
<global_param name="WEBDAV_ENABLE" group="CONF_MESSAGE[WebDAV Server]" type="boolean" label="CONF_MESSAGE[Enable WebDAV]" description="CONF_MESSAGE[Enable the webDAV support. Please READ THE DOC to safely use this feature.]" mandatory="false" default="false"/>
<global_param name="WEBDAV_BASEURI" group="CONF_MESSAGE[WebDAV Server]" type="string" label="CONF_MESSAGE[Shares URI]" description="CONF_MESSAGE[Common URI to access the shares. Please READ THE DOC to safely use this feature.]" mandatory="false" default="/ajaxplorer/shares"/>
<global_param name="WEBDAV_BASEHOST" group="CONF_MESSAGE[WebDAV Server]" type="string" label="CONF_MESSAGE[Shares Host]" description="CONF_MESSAGE[Host used in webDAV protocol. Should be detected by default. Please READ THE DOC to safely use this feature.]" mandatory="false" default=""/>
<global_param name="WEBDAV_DIGESTREALM" group="CONF_MESSAGE[WebDAV Server]" type="string" label="CONF_MESSAGE[Digest Realm]" description="CONF_MESSAGE[Default realm for authentication. Please READ THE DOC to safely use this feature.]" mandatory="false" default="ajxp_webdav_realm"/>
<global_param name="WEBDAV_FORCE_BASIC" group="CONF_MESSAGE[WebDAV Server]" type="boolean" label="CONF_MESSAGE[Force Basic Auth]" description="CONF_MESSAGE[This authentication mechanism is less secure, but will avoid the users having to re-enter a password in some case.]" mandatory="false" default="false"/>
<global_param name="WEBDAV_BROWSER_LISTING" group="CONF_MESSAGE[WebDAV Server]" type="boolean" label="CONF_MESSAGE[Browser Access]" description="CONF_MESSAGE[Display the list of files and folder when accessing through the browser]" mandatory="false" default="false"/>
<global_param name="CMDLINE_ACTIVE" group="CONF_MESSAGE[Command Line]" type="boolean" label="CONF_MESSAGE[Command-line Active]" description="CONF_MESSAGE[Use AjaXplorer framework via the command line, allowing CRONTAB jobs or background actions.]" mandatory="false" default="false"/>
<global_param name="CLI_PHP" group="CONF_MESSAGE[Command Line]" type="string" label="CONF_MESSAGE[Command-line PHP]" description="CONF_MESSAGE[On specific hosts, you may have to use a specific path to access the php command line]" mandatory="false" default="${:php-cli-location}"/>
<global_param name="CLI_USE_COM" group="CONF_MESSAGE[Command Line]" type="boolean" label="CONF_MESSAGE[Use COM class]" description="CONF_MESSAGE[On Windows running IIS, set this option to true if the COM extension is loaded, this may enable the use of the php command line.]" mandatory="false" default="false"/>
<global_param name="GZIP_COMPRESSION" group="CONF_MESSAGE[Compression Features]" type="boolean" label="CONF_MESSAGE[Gzip Download]" description="CONF_MESSAGE[Gzip files on-the-fly before downloading. Disabled by default, as it's generally useful only on small files, and decreases performances on big files. This has nothing to see with the Zip Creation feature, it's just a on-the-fly compression applied on a unique file at download.]" mandatory="false" default="false"/>
<global_param name="GZIP_LIMIT" group="CONF_MESSAGE[Compression Features]" type="string" label="CONF_MESSAGE[Gzip Limit]" description="CONF_MESSAGE[If activated, a default limit should be set above when files are no more compressed.]" mandatory="false" default="1048576"/>
<global_param name="ZIP_CREATION" expose="true" group="CONF_MESSAGE[Compression Features]" type="boolean" label="CONF_MESSAGE[Zip Creation]" description="CONF_MESSAGE[If you encounter problems with online zip creation or multiple files downloading, you can disable the feature.]" mandatory="false" default="true"/>
<global_param name="NODENAME_MAX_LENGTH" expose="true" group="CONF_MESSAGE[Miscalleneous]" type="integer" label="CONF_MESSAGE[Filename length]" description="CONF_MESSAGE[Maximum characters length of new files or folders]" mandatory="false" default="255"/>
<global_param name="AJXP_TMP_DIR" group="CONF_MESSAGE[Miscalleneous]" type="string" label="CONF_MESSAGE[Temporary Folder]" description="CONF_MESSAGE[This is necessary only if you have errors concerning the tmp dir access or writeability : most probably, they are due to PHP SAFE MODE (should disappear in php6) or various OPEN_BASEDIR restrictions. In that case, create and set writeable a tmp folder somewhere at the root of your hosting (but above the web/ or www/ or http/ if possible!!) and enter here the full path to this folder]" mandatory="false" default=""/>
</server_settings>
</ajxpcore>
\ No newline at end of file
# Global Postfix configuration file. This file lists only a subset
# of all parameters. For the syntax, and for a complete parameter
# list, see the postconf(5) manual page (command: "man 5 postconf").
#
# For common configuration examples, see BASIC_CONFIGURATION_README
# and STANDARD_CONFIGURATION_README. To find these documents, use
# the command "postconf html_directory readme_directory", or go to
# http://www.postfix.org/.
#
# For best results, change no more than 2-3 parameters at a time,
# and test if Postfix still works after every change.
# SOFT BOUNCE
#
# The soft_bounce parameter provides a limited safety net for
# testing. When soft_bounce is enabled, mail will remain queued that
# would otherwise bounce. This parameter disables locally-generated
# bounces, and prevents the SMTP server from rejecting mail permanently
# (by changing 5xx replies into 4xx replies). However, soft_bounce
# is no cure for address rewriting mistakes or mail routing mistakes.
#
#soft_bounce = no
# LOCAL PATHNAME INFORMATION
#
# The queue_directory specifies the location of the Postfix queue.
# This is also the root directory of Postfix daemons that run chrooted.
# See the files in examples/chroot-setup for setting up Postfix chroot
# environments on different UNIX systems.
#
queue_directory = ${:queue-directory}
# The command_directory parameter specifies the location of all
# postXXX commands.
#
command_directory = ${:command-directory}
# The daemon_directory parameter specifies the location of all Postfix
# daemon programs (i.e. programs listed in the master.cf file). This
# directory must be owned by root.
#
daemon_directory = ${:daemon-directory}
# The data_directory parameter specifies the location of Postfix-writable
# data files (caches, random numbers). This directory must be owned
# by the mail_owner account (see below).
#
data_directory = ${:data-directory}
# QUEUE AND PROCESS OWNERSHIP
#
# The mail_owner parameter specifies the owner of the Postfix queue
# and of most Postfix daemon processes. Specify the name of a user
# account THAT DOES NOT SHARE ITS USER OR GROUP ID WITH OTHER ACCOUNTS
# AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In
# particular, don't specify nobody or daemon. PLEASE USE A DEDICATED
# USER.
#
mail_owner = ${:mail-owner}
# The default_privs parameter specifies the default rights used by
# the local delivery agent for delivery to external file or command.
# These rights are used in the absence of a recipient user context.
# DO NOT SPECIFY A PRIVILEGED USER OR THE POSTFIX OWNER.
#
#default_privs = nobody
# INTERNET HOST AND DOMAIN NAMES
#
# The myhostname parameter specifies the internet hostname of this
# mail system. The default is to use the fully-qualified domain name
# from gethostname(). $myhostname is used as a default value for many
# other configuration parameters.
#
#myhostname = host.domain.tld
#myhostname = virtual.domain.tld
# The mydomain parameter specifies the local internet domain name.
# The default is to use $myhostname minus the first component.
# $mydomain is used as a default value for many other configuration
# parameters.
#
#mydomain = domain.tld
# SENDING MAIL
#
# The myorigin parameter specifies the domain that locally-posted
# mail appears to come from. The default is to append $myhostname,
# which is fine for small sites. If you run a domain with multiple
# machines, you should (1) change this to $mydomain and (2) set up
# a domain-wide alias database that aliases each user to
# user@that.users.mailhost.
#
# For the sake of consistency between sender and recipient addresses,
# myorigin also specifies the default domain name that is appended
# to recipient addresses that have no @domain part.
#
#myorigin = $myhostname
#myorigin = $mydomain
# RECEIVING MAIL
# The inet_interfaces parameter specifies the network interface
# addresses that this mail system receives mail on. By default,
# the software claims all active interfaces on the machine. The
# parameter also controls delivery of mail to user@[ip.address].
#
# See also the proxy_interfaces parameter, for network addresses that
# are forwarded to us via a proxy or network address translator.
#
# Note: you need to stop/start Postfix when this parameter changes.
#
#inet_interfaces = all
inet_interfaces = ${:ipv4}
#inet_interfaces = $myhostname, localhost
# The proxy_interfaces parameter specifies the network interface
# addresses that this mail system receives mail on by way of a
# proxy or network address translation unit. This setting extends
# the address list specified with the inet_interfaces parameter.
#
# You must specify your proxy/NAT addresses when your system is a
# backup MX host for other domains, otherwise mail delivery loops
# will happen when the primary MX host is down.
#
#proxy_interfaces =
#proxy_interfaces = 1.2.3.4
# The mydestination parameter specifies the list of domains that this
# machine considers itself the final destination for.
#
# These domains are routed to the delivery agent specified with the
# local_transport parameter setting. By default, that is the UNIX
# compatible delivery agent that lookups all recipients in /etc/passwd
# and /etc/aliases or their equivalent.
#
# The default is $myhostname + localhost.$mydomain. On a mail domain
# gateway, you should also include $mydomain.
#
# Do not specify the names of virtual domains - those domains are
# specified elsewhere (see VIRTUAL_README).
#
# Do not specify the names of domains that this machine is backup MX
# host for. Specify those names via the relay_domains settings for
# the SMTP server, or use permit_mx_backup if you are lazy (see
# STANDARD_CONFIGURATION_README).
#
# The local machine is always the final destination for mail addressed
# to user@[the.net.work.address] of an interface that the mail system
# receives mail on (see the inet_interfaces parameter).
#
# Specify a list of host or domain names, /file/name or type:table
# patterns, separated by commas and/or whitespace. A /file/name
# pattern is replaced by its contents; a type:table is matched when
# a name matches a lookup key (the right-hand side is ignored).
# Continue long lines by starting the next line with whitespace.
#
# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
#
#mydestination = $myhostname, localhost.$mydomain, localhost
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
# mail.$mydomain, www.$mydomain, ftp.$mydomain
# REJECTING MAIL FOR UNKNOWN LOCAL USERS
#
# The local_recipient_maps parameter specifies optional lookup tables
# with all names or addresses of users that are local with respect
# to $mydestination, $inet_interfaces or $proxy_interfaces.
#
# If this parameter is defined, then the SMTP server will reject
# mail for unknown local users. This parameter is defined by default.
#
# To turn off local recipient checking in the SMTP server, specify
# local_recipient_maps = (i.e. empty).
#
# The default setting assumes that you use the default Postfix local
# delivery agent for local delivery. You need to update the
# local_recipient_maps setting if:
#
# - You define $mydestination domain recipients in files other than
# /etc/passwd, /etc/aliases, or the $virtual_alias_maps files.
# For example, you define $mydestination domain recipients in
# the $virtual_mailbox_maps files.
#
# - You redefine the local delivery agent in master.cf.
#
# - You redefine the "local_transport" setting in main.cf.
#
# - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
# feature of the Postfix local delivery agent (see local(8)).
#
# Details are described in the LOCAL_RECIPIENT_README file.
#
# Beware: if the Postfix SMTP server runs chrooted, you probably have
# to access the passwd file via the proxymap service, in order to
# overcome chroot restrictions. The alternative, having a copy of
# the system passwd file in the chroot jail is just not practical.
#
# The right-hand side of the lookup tables is conveniently ignored.
# In the left-hand side, specify a bare username, an @domain.tld
# wild-card, or specify a user@domain.tld address.
#
#local_recipient_maps = unix:passwd.byname $alias_maps
#local_recipient_maps = proxy:unix:passwd.byname $alias_maps
#local_recipient_maps =
# The unknown_local_recipient_reject_code specifies the SMTP server
# response code when a recipient domain matches $mydestination or
# $proxy/$inet_interfaces, while $local_recipient_maps is non-empty
# and the recipient address or address local-part is not found.
#
# The default setting is 550 (reject mail) but it is safer to start
# with 450 (try again later) until you are certain that your
# local_recipient_maps settings are OK.
#
unknown_local_recipient_reject_code = 550
# TRUST AND RELAY CONTROL
# The mynetworks parameter specifies the list of "trusted" SMTP
# clients that have more privileges than "strangers".
#
# In particular, "trusted" SMTP clients are allowed to relay mail
# through Postfix. See the smtpd_recipient_restrictions parameter
# in postconf(5).
#
# You can specify the list of "trusted" network addresses by hand
# or you can let Postfix do it for you (which is the default).
#
# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
# clients in the same IP subnetworks as the local machine.
# On Linux, this does works correctly only with interfaces specified
# with the "ifconfig" command.
#
# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
# clients in the same IP class A/B/C networks as the local machine.
# Don't do this with a dialup site - it would cause Postfix to "trust"
# your entire provider's network. Instead, specify an explicit
# mynetworks list by hand, as described below.
#
# Specify "mynetworks_style = host" when Postfix should "trust"
# only the local machine.
#
#mynetworks_style = class
#mynetworks_style = subnet
#mynetworks_style = host
# Alternatively, you can specify the mynetworks list by hand, in
# which case Postfix ignores the mynetworks_style setting.
#
# Specify an explicit list of network/netmask patterns, where the
# mask specifies the number of bits in the network part of a host
# address.
#
# You can also specify the absolute pathname of a pattern file instead
# of listing the patterns here. Specify type:table for table-based lookups
# (the value on the table right-hand side is not used).
#
#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks
#mynetworks = hash:/etc/postfix/network_table
# The relay_domains parameter restricts what destinations this system will
# relay mail to. See the smtpd_recipient_restrictions description in
# postconf(5) for detailed information.
#
# By default, Postfix relays mail
# - from "trusted" clients (IP address matches $mynetworks) to any destination,
# - from "untrusted" clients to destinations that match $relay_domains or
# subdomains thereof, except addresses with sender-specified routing.
# The default relay_domains value is $mydestination.
#
# In addition to the above, the Postfix SMTP server by default accepts mail
# that Postfix is final destination for:
# - destinations that match $inet_interfaces or $proxy_interfaces,
# - destinations that match $mydestination
# - destinations that match $virtual_alias_domains,
# - destinations that match $virtual_mailbox_domains.
# These destinations do not need to be listed in $relay_domains.
#
# Specify a list of hosts or domains, /file/name patterns or type:name
# lookup tables, separated by commas and/or whitespace. Continue
# long lines by starting the next line with whitespace. A file name
# is replaced by its contents; a type:name table is matched when a
# (parent) domain appears as lookup key.
#
# NOTE: Postfix will not automatically forward mail for domains that
# list this system as their primary or backup MX host. See the
# permit_mx_backup restriction description in postconf(5).
#
#relay_domains = $mydestination
# INTERNET OR INTRANET
# The relayhost parameter specifies the default host to send mail to
# when no entry is matched in the optional transport(5) table. When
# no relayhost is given, mail is routed directly to the destination.
#
# On an intranet, specify the organizational domain name. If your
# internal DNS uses no MX records, specify the name of the intranet
# gateway host instead.
#
# In the case of SMTP, specify a domain, host, host:port, [host]:port,
# [address] or [address]:port; the form [host] turns off MX lookups.
#
# If you're connected via UUCP, see also the default_transport parameter.
#
#relayhost = $mydomain
#relayhost = [gateway.my.domain]
#relayhost = [mailserver.isp.tld]
#relayhost = uucphost
#relayhost = [an.ip.add.ress]
# REJECTING UNKNOWN RELAY USERS
#
# The relay_recipient_maps parameter specifies optional lookup tables
# with all addresses in the domains that match $relay_domains.
#
# If this parameter is defined, then the SMTP server will reject
# mail for unknown relay users. This feature is off by default.
#
# The right-hand side of the lookup tables is conveniently ignored.
# In the left-hand side, specify an @domain.tld wild-card, or specify
# a user@domain.tld address.
#
#relay_recipient_maps = hash:/etc/postfix/relay_recipients
# INPUT RATE CONTROL
#
# The in_flow_delay configuration parameter implements mail input
# flow control. This feature is turned on by default, although it
# still needs further development (it's disabled on SCO UNIX due
# to an SCO bug).
#
# A Postfix process will pause for $in_flow_delay seconds before
# accepting a new message, when the message arrival rate exceeds the
# message delivery rate. With the default 100 SMTP server process
# limit, this limits the mail inflow to 100 messages a second more
# than the number of messages delivered per second.
#
# Specify 0 to disable the feature. Valid delays are 0..10.
#
#in_flow_delay = 1s
# ADDRESS REWRITING
#
# The ADDRESS_REWRITING_README document gives information about
# address masquerading or other forms of address rewriting including
# username->Firstname.Lastname mapping.
# ADDRESS REDIRECTION (VIRTUAL DOMAIN)
#
# The VIRTUAL_README document gives information about the many forms
# of domain hosting that Postfix supports.
# "USER HAS MOVED" BOUNCE MESSAGES
#
# See the discussion in the ADDRESS_REWRITING_README document.
# TRANSPORT MAP
#
# See the discussion in the ADDRESS_REWRITING_README document.
# ALIAS DATABASE
#
# The alias_maps parameter specifies the list of alias databases used
# by the local delivery agent. The default list is system dependent.
#
# On systems with NIS, the default is to search the local alias
# database, then the NIS alias database. See aliases(5) for syntax
# details.
#
# If you change the alias database, run "postalias /etc/aliases" (or
# wherever your system stores the mail alias file), or simply run
# "newaliases" to build the necessary DBM or DB file.
#
# It will take a minute or so before changes become visible. Use
# "postfix reload" to eliminate the delay.
#
#alias_maps = dbm:/etc/aliases
#alias_maps = hash:/etc/aliases
#alias_maps = hash:/etc/aliases, nis:mail.aliases
#alias_maps = netinfo:/aliases
# The alias_database parameter specifies the alias database(s) that
# are built with "newaliases" or "sendmail -bi". This is a separate
# configuration parameter, because alias_maps (see above) may specify
# tables that are not necessarily all under control by Postfix.
#
#alias_database = dbm:/etc/aliases
#alias_database = dbm:/etc/mail/aliases
#alias_database = hash:/etc/aliases
#alias_database = hash:/etc/aliases, hash:/opt/majordomo/aliases
# ADDRESS EXTENSIONS (e.g., user+foo)
#
# The recipient_delimiter parameter specifies the separator between
# user names and address extensions (user+foo). See canonical(5),
# local(8), relocated(5) and virtual(5) for the effects this has on
# aliases, canonical, virtual, relocated and .forward file lookups.
# Basically, the software tries user+foo and .forward+foo before
# trying user and .forward.
#
#recipient_delimiter = +
# DELIVERY TO MAILBOX
#
# The home_mailbox parameter specifies the optional pathname of a
# mailbox file relative to a user's home directory. The default
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
# "Maildir/" for qmail-style delivery (the / is required).
#
#home_mailbox = Mailbox
#home_mailbox = Maildir/
# The mail_spool_directory parameter specifies the directory where
# UNIX-style mailboxes are kept. The default setting depends on the
# system type.
#
#mail_spool_directory = /var/mail
#mail_spool_directory = /var/spool/mail
# The mailbox_command parameter specifies the optional external
# command to use instead of mailbox delivery. The command is run as
# the recipient with proper HOME, SHELL and LOGNAME environment settings.
# Exception: delivery for root is done as $default_user.
#
# Other environment variables of interest: USER (recipient username),
# EXTENSION (address extension), DOMAIN (domain part of address),
# and LOCAL (the address localpart).
#
# Unlike other Postfix configuration parameters, the mailbox_command
# parameter is not subjected to $parameter substitutions. This is to
# make it easier to specify shell syntax (see example below).
#
# Avoid shell meta characters because they will force Postfix to run
# an expensive shell process. Procmail alone is expensive enough.
#
# IF YOU USE THIS TO DELIVER MAIL SYSTEM-WIDE, YOU MUST SET UP AN
# ALIAS THAT FORWARDS MAIL FOR ROOT TO A REAL USER.
#
#mailbox_command = /some/where/procmail
#mailbox_command = /some/where/procmail -a "$EXTENSION"
# The mailbox_transport specifies the optional transport in master.cf
# to use after processing aliases and .forward files. This parameter
# has precedence over the mailbox_command, fallback_transport and
# luser_relay parameters.
#
# Specify a string of the form transport:nexthop, where transport is
# the name of a mail delivery transport defined in master.cf. The
# :nexthop part is optional. For more details see the sample transport
# configuration file.
#
# NOTE: if you use this feature for accounts not in the UNIX password
# file, then you must update the "local_recipient_maps" setting in
# the main.cf file, otherwise the SMTP server will reject mail for
# non-UNIX accounts with "User unknown in local recipient table".
#
# Cyrus IMAP over LMTP. Specify ``lmtpunix cmd="lmtpd"
# listen="/var/imap/socket/lmtp" prefork=0'' in cyrus.conf.
#mailbox_transport = lmtp:unix:/var/imap/socket/lmtp
#
# Cyrus IMAP via command line. Uncomment the "cyrus...pipe" and
# subsequent line in master.cf.
#mailbox_transport = cyrus
# The fallback_transport specifies the optional transport in master.cf
# to use for recipients that are not found in the UNIX passwd database.
# This parameter has precedence over the luser_relay parameter.
#
# Specify a string of the form transport:nexthop, where transport is
# the name of a mail delivery transport defined in master.cf. The
# :nexthop part is optional. For more details see the sample transport
# configuration file.
#
# NOTE: if you use this feature for accounts not in the UNIX password
# file, then you must update the "local_recipient_maps" setting in
# the main.cf file, otherwise the SMTP server will reject mail for
# non-UNIX accounts with "User unknown in local recipient table".
#
#fallback_transport = lmtp:unix:/file/name
#fallback_transport = cyrus
#fallback_transport =
# The luser_relay parameter specifies an optional destination address
# for unknown recipients. By default, mail for unknown@$mydestination,
# unknown@[$inet_interfaces] or unknown@[$proxy_interfaces] is returned
# as undeliverable.
#
# The following expansions are done on luser_relay: $user (recipient
# username), $shell (recipient shell), $home (recipient home directory),
# $recipient (full recipient address), $extension (recipient address
# extension), $domain (recipient domain), $local (entire recipient
# localpart), $recipient_delimiter. Specify $name?value or
# $name:value to expand value only when $name does (does not) exist.
#
# luser_relay works only for the default Postfix local delivery agent.
#
# NOTE: if you use this feature for accounts not in the UNIX password
# file, then you must specify "local_recipient_maps =" (i.e. empty) in
# the main.cf file, otherwise the SMTP server will reject mail for
# non-UNIX accounts with "User unknown in local recipient table".
#
#luser_relay = $user@other.host
#luser_relay = $local@other.host
#luser_relay = admin+$local
# JUNK MAIL CONTROLS
#
# The controls listed here are only a very small subset. The file
# SMTPD_ACCESS_README provides an overview.
# The header_checks parameter specifies an optional table with patterns
# that each logical message header is matched against, including
# headers that span multiple physical lines.
#
# By default, these patterns also apply to MIME headers and to the
# headers of attached messages. With older Postfix versions, MIME and
# attached message headers were treated as body text.
#
# For details, see "man header_checks".
#
#header_checks = regexp:/etc/postfix/header_checks
# FAST ETRN SERVICE
#
# Postfix maintains per-destination logfiles with information about
# deferred mail, so that mail can be flushed quickly with the SMTP
# "ETRN domain.tld" command, or by executing "sendmail -qRdomain.tld".
# See the ETRN_README document for a detailed description.
#
# The fast_flush_domains parameter controls what destinations are
# eligible for this service. By default, they are all domains that
# this server is willing to relay mail to.
#
#fast_flush_domains = $relay_domains
# SHOW SOFTWARE VERSION OR NOT
#
# The smtpd_banner parameter specifies the text that follows the 220
# code in the SMTP server's greeting banner. Some people like to see
# the mail version advertised. By default, Postfix shows no version.
#
# You MUST specify $myhostname at the start of the text. That is an
# RFC requirement. Postfix itself does not care.
#
#smtpd_banner = $myhostname ESMTP $mail_name
#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
# PARALLEL DELIVERY TO THE SAME DESTINATION
#
# How many parallel deliveries to the same user or domain? With local
# delivery, it does not make sense to do massively parallel delivery
# to the same user, because mailbox updates must happen sequentially,
# and expensive pipelines in .forward files can cause disasters when
# too many are run at the same time. With SMTP deliveries, 10
# simultaneous connections to the same domain could be sufficient to
# raise eyebrows.
#
# Each message delivery transport has its XXX_destination_concurrency_limit
# parameter. The default is $default_destination_concurrency_limit for
# most delivery transports. For the local delivery agent the default is 2.
#local_destination_concurrency_limit = 2
#default_destination_concurrency_limit = 20
# DEBUGGING CONTROL
#
# The debug_peer_level parameter specifies the increment in verbose
# logging level when an SMTP client or server host name or address
# matches a pattern in the debug_peer_list parameter.
#
debug_peer_level = 2
# The debug_peer_list parameter specifies an optional list of domain
# or network patterns, /file/name patterns or type:name tables. When
# an SMTP client or server host name or address matches a pattern,
# increase the verbose logging level by the amount specified in the
# debug_peer_level parameter.
#
#debug_peer_list = 127.0.0.1
#debug_peer_list = some.domain
# The debugger_command specifies the external command that is executed
# when a Postfix daemon program is run with the -D option.
#
# Use "command .. & sleep 5" so that the debugger can attach before
# the process marches on. If you use an X-based debugger, be sure to
# set up your XAUTHORITY environment variable before starting Postfix.
#
debugger_command =
PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
ddd $daemon_directory/$process_name $process_id & sleep 5
# If you can't use X, use this to capture the call stack when a
# daemon crashes. The result is in a file in the configuration
# directory, and is named after the process name and the process ID.
#
# debugger_command =
# PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont;
# echo where) | gdb $daemon_directory/$process_name $process_id 2>&1
# >$config_directory/$process_name.$process_id.log & sleep 5
#
# Another possibility is to run gdb under a detached screen session.
# To attach to the screen sesssion, su root and run "screen -r
# <id_string>" where <id_string> uniquely matches one of the detached
# sessions (from "screen -list").
#
# debugger_command =
# PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH; screen
# -dmS $process_name gdb $daemon_directory/$process_name
# $process_id & sleep 1
# INSTALL-TIME CONFIGURATION INFORMATION
#
# The following parameters are used when installing a new Postfix version.
#
# sendmail_path: The full pathname of the Postfix sendmail command.
# This is the Sendmail-compatible mail posting interface.
#
sendmail_path = ${:command-directory}/sendmail
# newaliases_path: The full pathname of the Postfix newaliases command.
# This is the Sendmail-compatible command to build alias databases.
#
newaliases_path = ${:bin-directory}/newaliases
# mailq_path: The full pathname of the Postfix mailq command. This
# is the Sendmail-compatible mail queue listing command.
#
mailq_path = ${:bin-directory}/mailq
# setgid_group: The group for mail submission and queue management
# commands. This must be a group name with a numerical group ID that
# is not shared with other accounts, not even with the Postfix account.
#
setgid_group = ${:mail-group}
# html_directory: The location of the Postfix HTML documentation.
#
html_directory = no
# manpage_directory: The location of the Postfix on-line manual pages.
#
manpage_directory = /usr/local/man
# sample_directory: The location of the Postfix sample configuration files.
# This parameter is obsolete as of Postfix 2.1.
#
sample_directory = /etc/postfix
# readme_directory: The location of the Postfix README files.
#
readme_directory = no
inet_protocols = all
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
${:port} inet n - n - - smtpd
#smtp inet n - n - 1 postscreen
#smtpd pass - - n - - smtpd
#dnsblog unix - - n - 0 dnsblog
#tlsproxy unix - - n - 0 tlsproxy
#submission inet n - n - - smtpd
# -o syslog_name=postfix/submission
# -o smtpd_tls_security_level=encrypt
# -o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
#smtps inet n - n - - smtpd
# -o syslog_name=postfix/smtps
# -o smtpd_tls_wrappermode=yes
# -o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
#628 inet n - n - - qmqpd
pickup unix n - n 60 1 pickup
cleanup unix n - n - 0 cleanup
qmgr unix n - n 300 1 qmgr
#qmgr unix n - n 300 1 oqmgr
tlsmgr unix - - n 1000? 1 tlsmgr
rewrite unix - - n - - trivial-rewrite
bounce unix - - n - 0 bounce
defer unix - - n - 0 bounce
trace unix - - n - 0 bounce
verify unix - - n - 1 verify
flush unix n - n 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - n - - smtp
relay unix - - n - - smtp
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq unix n - n - - showq
error unix - - n - - error
retry unix - - n - - error
discard unix - - n - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
anvil unix - - n - 1 anvil
scache unix - - n - 1 scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent. See the pipe(8) man page for information about $recipient
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
#maildrop unix - n n - - pipe
# flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d $recipient
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
# mailbox_transport = lmtp:inet:localhost
# virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus unix - n n - - pipe
# user=cyrus argv=/cyrus/bin/deliver -e -r $sender -m $extension $user
#
# ====================================================================
#
# Old example of delivery via Cyrus.
#
#old-cyrus unix - n n - - pipe
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m $extension $user
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
#uucp unix - n n - - pipe
# flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# ====================================================================
#
# Other external delivery methods.
#
#ifmail unix - n n - - pipe
# flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
#
#bsmtp unix - n n - - pipe
# flags=Fq. user=bsmtp argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
#
#scalemail-backend unix - n n - 2 pipe
# flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store
# $nexthop $user $extension
#
#mailman unix - n n - - pipe
# flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
# $nexthop $user
#!${:python-location}
import subprocess
import signal
import time
def handler(signum,frame):
pid_file = open("${:pid-location}","r")
pid = pid_file.read().strip()
subprocess.call(["kill", "-9", pid])
subprocess.call(["${:postfix-location}", "-c", "${:postfix-config-dir}", "start"])
signal.signal(signal.SIGINT,handler)
while True:
time.sleep(120)
#!/bin/sh
${:sendmail-location} -C ${:postfix-config-dir} $*
\ No newline at end of file
var page = require('webpage').create();
var url = '${:content-url}'
page.open(url,function(status){
var form = page.evaluate(function(){
return document.getElementById('login_form');
});
if(form === null){
phantom.exit(1);
} else {
phantom.exit();
}
});
#!${:dash-path}
${:test-sendmail-php-location} > /dev/null
RETURN=$(${:sendmail-binary} -bp)
if [ "$RETURN" != "Mail queue is empty" ]; then
exit 0
else
exit 1
fi
\ No newline at end of file
#!${:php-location}
<?php
require_once("${:htdocs-location}/plugins/mailer.phpmailer-lite/lib/class.phpmailer-lite.php");
$mailer = new PHPMailerLite(true);
$mailer->SetFrom('test@couscous.com');
$mailer->AddAddress('couscous@test.com');
$mailer->Subject = 'test';
$mailer->Body = 'test';
$mailer->Send();
?>
\ No newline at end of file
...@@ -16,13 +16,18 @@ extends = ...@@ -16,13 +16,18 @@ extends =
../../component/git/buildout.cfg ../../component/git/buildout.cfg
../../component/nodejs/buildout.cfg ../../component/nodejs/buildout.cfg
../../component/postgresql/buildout.cfg ../../component/postgresql/buildout.cfg
../../component/phantomjs/buildout.cfg
parts = parts =
postgresql postgresql
nodejs nodejs
phantomjs
etherpad-lite-repository etherpad-lite-repository
install-deps install-deps
template template
template-html10n
template-index-promise-js
template-pad-promise-js
lxml-python lxml-python
eggs eggs
instance-recipe-egg instance-recipe-egg
...@@ -45,8 +50,8 @@ eggs = ${instance-recipe:egg} ...@@ -45,8 +50,8 @@ eggs = ${instance-recipe:egg}
[etherpad-lite-repository] [etherpad-lite-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = http://github.com/ether/etherpad-lite.git repository = http://github.com/ether/etherpad-lite.git
branch = develop
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
revision = cb3ab51ee14aefb2f9e71bdd9907c0a83c3aebb3
[template] [template]
# Default template for the instance. # Default template for the instance.
...@@ -59,16 +64,24 @@ mode = 0644 ...@@ -59,16 +64,24 @@ mode = 0644
[instance-etherpad-lite] [instance-etherpad-lite]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-etherpad-lite.cfg url = ${:_profile_base_location_}/instance-etherpad-lite.cfg
md5sum = fd7249be8988155110234c7bb877abb9 md5sum = dea0ee49ff3a87bd146e3d6bd6d68167
output = ${buildout:directory}/template-etherpad-lite.cfg output = ${buildout:directory}/template-etherpad-lite.cfg
mode = 0644 mode = 0644
[template-html10n]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/${:filename}
filename = html10n.js
mode = 0644
md5sum = 6f90afdcc50bb5020896c95162d83834
output = ${etherpad-lite-repository:location}/src/static/js/${:filename}
[template-conf] [template-conf]
recipe = slapos.recipe.download recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename} url = ${:_profile_base_location_}/templates/${:filename}
mode = 0644 mode = 0644
filename = settings.json.in filename = settings.json.in
md5sum = 19ab39e6b3256c82fd54ce074488b136 md5sum = d95264e66e2691b094d40a65d88ce681
location = ${buildout:parts-directory}/${:_buildout_section_name_} location = ${buildout:parts-directory}/${:_buildout_section_name_}
[template-run-script] [template-run-script]
...@@ -96,5 +109,21 @@ recipe = plone.recipe.command ...@@ -96,5 +109,21 @@ recipe = plone.recipe.command
command = ${template-deps-script:output} command = ${template-deps-script:output}
update-command = command update-command = command
[template-index-promise-js]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = test-index.js.in
mode = 0644
md5sum = 7ee12b1c284c2c6260689b21bb35176e
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[template-pad-promise-js]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
filename = test-pad.js.in
mode = 0644
md5sum = 43dc2ee94e65cc7f5fa4c3d6a868eebe
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[lxml-python] [lxml-python]
python = python2.7 python = python2.7
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
parts = parts =
etherpad-lite etherpad-lite
publish-connection-informations publish-connection-informations
# frontend-etherpad check-index-promise
# XXX-Vivien: postponed till we can make it fast enough
# check-pad-promise
eggs-directory = ${buildout:eggs-directory} eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory} develop-eggs-directory = ${buildout:develop-eggs-directory}
...@@ -28,10 +30,11 @@ promises = $${rootdirectory:etc}/promise/ ...@@ -28,10 +30,11 @@ promises = $${rootdirectory:etc}/promise/
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
etherpad-conf = $${rootdirectory:etc}/etherpad/ etherpad-conf = $${rootdirectory:etc}/etherpad/
etherpad-repository-location = $${buildout:directory}/parts/etherpad-lite-repository etherpad-repository-location = $${buildout:directory}/parts/etherpad-lite-repository
promise-js = $${rootdirectory:etc}/js/
[publish-connection-informations] [publish-connection-informations]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
url = $${request-frontend:connection-site_url} url = $${request-frontend:config-url}
[etherpad-conf-generation] [etherpad-conf-generation]
recipe = slapos.recipe.template recipe = slapos.recipe.template
...@@ -39,6 +42,7 @@ url = ${template-conf:location}/${template-conf:filename} ...@@ -39,6 +42,7 @@ url = ${template-conf:location}/${template-conf:filename}
ip = $${slap-network-information:global-ipv6} ip = $${slap-network-information:global-ipv6}
dirtydb-location = $${rootdirectory:var}/dirty.db dirtydb-location = $${rootdirectory:var}/dirty.db
port = 9001 port = 9001
welcome-message = Bienvenue sur Etherpad!\n\nLe texte que vous écrivez est synchronisez en ce moment même, pour que tout le monde puisse voir la page avec le même texte. Cela vous permet de collaborer sur des documents sans aucun problème!\n
mode = 0644 mode = 0644
output = $${directory:etherpad-conf}/settings.json output = $${directory:etherpad-conf}/settings.json
...@@ -68,12 +72,34 @@ name = Frontend ...@@ -68,12 +72,34 @@ name = Frontend
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true slave = true
config = url config = url
config-url = http://$${etherpad-conf-generation:ip}:$${etherpad-conf-generation:port} config-url = http://[$${etherpad-conf-generation:ip}]:$${etherpad-conf-generation:port}
return = site_url return = site_url
[frontend-etherpad] [index-promise-js]
recipe = slapos.cookbook:check_url_available recipe = slapos.recipe.template
path = $${basedirectory:promises}/frontend-etherpad url = ${template-index-promise-js:location}/${template-index-promise-js:filename}
url = $${request-frontend:connection-site_url} content-url = $${publish-connection-informations:url}
dash_path = ${dash:location}/bin/dash mode = 0644
curl_path = ${curl:location}/bin/curl output = $${directory:promise-js}/test-index.js
\ No newline at end of file
[pad-promise-js]
recipe = slapos.recipe.template
url = ${template-pad-promise-js:location}/${template-pad-promise-js:filename}
content-url = $${publish-connection-informations:url}
welcome-message = $${etherpad-conf-generation:welcome-message}
mode = 0644
output = $${directory:promise-js}/test-pad.js
[check-index-promise]
recipe = slapos.cookbook:check_page_content_phantomjs
path = $${basedirectory:promises}/check-index-promise
dash-path = ${dash:location}/bin/dash
phantomjs-path = ${phantomjs:location}/phantomjs-slapos
script-path = $${index-promise-js:output}
[check-pad-promise]
recipe = slapos.cookbook:check_page_content_phantomjs
path = $${basedirectory:promises}/check-pad-promise
dash-path = ${dash:location}/bin/dash
phantomjs-path = ${phantomjs:location}/phantomjs-slapos
script-path = $${pad-promise-js:output}
\ No newline at end of file
...@@ -14,14 +14,16 @@ develop = ...@@ -14,14 +14,16 @@ develop =
[slapos.cookbook-repository] [slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git repository = http://git.erp5.org/repos/slapos.git
branch = etherpad-lite
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
#revision = 45243101321daeecaf755b9788b11259dd6bdfff
branch = etherpad-lite
[slapos.toolbox-repository] [slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = master branch = master
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
revision = fc91b7f26c2fd69cedafcef9de3c8b22a50f8976
[check-recipe] [check-recipe]
recipe = plone.recipe.command recipe = plone.recipe.command
...@@ -29,4 +31,64 @@ stop-on-error = true ...@@ -29,4 +31,64 @@ stop-on-error = true
update-command = ${:command} update-command = ${:command}
command = command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link && grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
\ No newline at end of file
[versions]
Jinja2 = 2.7
MarkupSafe = 0.18
Werkzeug = 0.9.3
buildout-versions = 1.7
itsdangerous = 0.22
meld3 = 0.6.10
plone.recipe.command = 1.1
slapos.recipe.build = 0.11.6
slapos.recipe.cmmi = 0.2
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.3
# Required by:
# slapos.core==0.35.1
Flask = 0.10.1
# Required by:
# slapos.cookbook==0.78.2.dev
inotifyx = 0.2.0-1
# Required by:
# slapos.cookbook==0.78.2.dev
lock-file = 2.0
# Required by:
# slapos.cookbook==0.78.2.dev
# slapos.core==0.35.1
# xml-marshaller==0.9.7
lxml = 3.2.3
# Required by:
# slapos.cookbook==0.78.2.dev
netaddr = 0.7.10
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.3
# Required by:
# slapos.cookbook==0.78.2.dev
pytz = 2013b
# Required by:
# slapos.cookbook==0.78.2.dev
# slapos.core==0.35.1
# zc.buildout==1.6.0-dev-SlapOS-010
# zc.recipe.egg==1.3.2
setuptools = 0.9.8
# Required by:
# slapos.cookbook==0.78.2.dev
slapos.core = 0.35.1
# Required by:
# slapos.core==0.35.1
supervisor = 3.0
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.cookbook==0.78.2.dev
xml-marshaller = 0.9.7
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
\ No newline at end of file
/**
* Copyright (c) 2012 Marcel Klehr
* Copyright (c) 2011-2012 Fabien Cazenave, Mozilla
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
function html10n (window, document, undefined) {
// fix console
var console = null
function interceptConsole(method){
if (!console) return function() {}
var original = console[method]
// do sneaky stuff
if (original.bind){
// Do this for normal browsers
return original.bind(console)
}else{
return function() {
// Do this for IE
var message = Array.prototype.slice.apply(arguments).join(' ')
original(message)
}
}
}
var consoleLog = interceptConsole('log')
, consoleWarn = interceptConsole('warn')
, consoleError = interceptConsole('warn')
// fix Array#forEach in IE
// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(fn, scope) {
for(var i = 0, len = this.length; i < len; ++i) {
if (i in this) {
fn.call(scope, this[i], i, this);
}
}
};
}
// fix Array#indexOf in, guess what, IE! <3
// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
/**
* MicroEvent - to make any js object an event emitter (server or browser)
*/
var MicroEvent = function(){}
MicroEvent.prototype = {
bind : function(event, fct){
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(fct);
},
unbind : function(event, fct){
this._events = this._events || {};
if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1);
},
trigger : function(event /* , args... */){
this._events = this._events || {};
if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1))
}
}
};
/**
* mixin will delegate all MicroEvent.js function in the destination object
* @param {Object} the object which will support MicroEvent
*/
MicroEvent.mixin = function(destObject){
var props = ['bind', 'unbind', 'trigger'];
if(!destObject) return;
for(var i = 0; i < props.length; i ++){
destObject[props[i]] = MicroEvent.prototype[props[i]];
}
}
/**
* Loader
* The loader is responsible for loading
* and caching all necessary resources
*/
function Loader(resources) {
this.resources = resources
this.cache = {} // file => contents
this.langs = {} // lang => strings
}
Loader.prototype.load = function(lang, cb) {
if(this.langs[lang]) return cb()
if (this.resources.length > 0) {
var reqs = 0;
for (var i=0, n=this.resources.length; i < n; i++) {
this.fetch(this.resources[i], lang, function(e) {
reqs++;
if(e) consoleWarn(e)
if (reqs < n) return;// Call back once all reqs are completed
cb && cb()
})
}
}
}
Loader.prototype.fetch = function(href, lang, cb) {
var that = this
if (this.cache[href]) {
this.parse(lang, href, this.cache[href], cb)
return;
}
var xhr = new XMLHttpRequest()
xhr.open('GET', href, /*async: */true)
if (xhr.overrideMimeType) {
xhr.overrideMimeType('application/json; charset=utf-8');
}
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status === 0) {
var data = JSON.parse(xhr.responseText)
that.cache[href] = data
// Pass on the contents for parsing
that.parse(lang, href, data, cb)
} else {
cb(new Error('Failed to load '+href))
}
}
};
xhr.send(null);
}
Loader.prototype.parse = function(lang, currHref, data, cb) {
if ('object' != typeof data) {
cb(new Error('A file couldn\'t be parsed as json.'))
return
}
if (!data[lang]) {
cb(new Error('Couldn\'t find translations for '+lang))
return
}
if ('string' == typeof data[lang]) {
// Import rule
// absolute path
var importUrl = data[lang]
// relative path
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
importUrl = currHref+"/../"+data[lang]
}
this.fetch(importUrl, lang, cb)
return
}
if ('object' != typeof data[lang]) {
cb(new Error('Translations should be specified as JSON objects!'))
return
}
this.langs[lang] = data[lang]
// TODO: Also store accompanying langs
cb()
}
/**
* The html10n object
*/
var html10n =
{ language : null
}
MicroEvent.mixin(html10n)
html10n.macros = {}
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"]
/**
* Get rules for plural forms (shared with JetPack), see:
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
* https://github.com/mozilla/addon-sdk/blob/master/python-lib/plural-rules-generator.p
*
* @param {string} lang
* locale (language) used.
*
* @return {Function}
* returns a function that gives the plural form name for a given integer:
* var fun = getPluralRules('en');
* fun(1) -> 'one'
* fun(0) -> 'other'
* fun(1000) -> 'other'.
*/
function getPluralRules(lang) {
var locales2rules = {
'af': 3,
'ak': 4,
'am': 4,
'ar': 1,
'asa': 3,
'az': 0,
'be': 11,
'bem': 3,
'bez': 3,
'bg': 3,
'bh': 4,
'bm': 0,
'bn': 3,
'bo': 0,
'br': 20,
'brx': 3,
'bs': 11,
'ca': 3,
'cgg': 3,
'chr': 3,
'cs': 12,
'cy': 17,
'da': 3,
'de': 3,
'dv': 3,
'dz': 0,
'ee': 3,
'el': 3,
'en': 3,
'eo': 3,
'es': 3,
'et': 3,
'eu': 3,
'fa': 0,
'ff': 5,
'fi': 3,
'fil': 4,
'fo': 3,
'fr': 5,
'fur': 3,
'fy': 3,
'ga': 8,
'gd': 24,
'gl': 3,
'gsw': 3,
'gu': 3,
'guw': 4,
'gv': 23,
'ha': 3,
'haw': 3,
'he': 2,
'hi': 4,
'hr': 11,
'hu': 0,
'id': 0,
'ig': 0,
'ii': 0,
'is': 3,
'it': 3,
'iu': 7,
'ja': 0,
'jmc': 3,
'jv': 0,
'ka': 0,
'kab': 5,
'kaj': 3,
'kcg': 3,
'kde': 0,
'kea': 0,
'kk': 3,
'kl': 3,
'km': 0,
'kn': 0,
'ko': 0,
'ksb': 3,
'ksh': 21,
'ku': 3,
'kw': 7,
'lag': 18,
'lb': 3,
'lg': 3,
'ln': 4,
'lo': 0,
'lt': 10,
'lv': 6,
'mas': 3,
'mg': 4,
'mk': 16,
'ml': 3,
'mn': 3,
'mo': 9,
'mr': 3,
'ms': 0,
'mt': 15,
'my': 0,
'nah': 3,
'naq': 7,
'nb': 3,
'nd': 3,
'ne': 3,
'nl': 3,
'nn': 3,
'no': 3,
'nr': 3,
'nso': 4,
'ny': 3,
'nyn': 3,
'om': 3,
'or': 3,
'pa': 3,
'pap': 3,
'pl': 13,
'ps': 3,
'pt': 3,
'rm': 3,
'ro': 9,
'rof': 3,
'ru': 11,
'rwk': 3,
'sah': 0,
'saq': 3,
'se': 7,
'seh': 3,
'ses': 0,
'sg': 0,
'sh': 11,
'shi': 19,
'sk': 12,
'sl': 14,
'sma': 7,
'smi': 7,
'smj': 7,
'smn': 7,
'sms': 7,
'sn': 3,
'so': 3,
'sq': 3,
'sr': 11,
'ss': 3,
'ssy': 3,
'st': 3,
'sv': 3,
'sw': 3,
'syr': 3,
'ta': 3,
'te': 3,
'teo': 3,
'th': 0,
'ti': 4,
'tig': 3,
'tk': 3,
'tl': 4,
'tn': 3,
'to': 0,
'tr': 0,
'ts': 3,
'tzm': 22,
'uk': 11,
'ur': 3,
've': 3,
'vi': 0,
'vun': 3,
'wa': 4,
'wae': 3,
'wo': 0,
'xh': 3,
'xog': 3,
'yo': 0,
'zh': 0,
'zu': 3
};
// utility functions for plural rules methods
function isIn(n, list) {
return list.indexOf(n) !== -1;
}
function isBetween(n, start, end) {
return start <= n && n <= end;
}
// list of all plural rules methods:
// map an integer to the plural form name to use
var pluralRules = {
'0': function(n) {
return 'other';
},
'1': function(n) {
if ((isBetween((n % 100), 3, 10)))
return 'few';
if (n === 0)
return 'zero';
if ((isBetween((n % 100), 11, 99)))
return 'many';
if (n == 2)
return 'two';
if (n == 1)
return 'one';
return 'other';
},
'2': function(n) {
if (n !== 0 && (n % 10) === 0)
return 'many';
if (n == 2)
return 'two';
if (n == 1)
return 'one';
return 'other';
},
'3': function(n) {
if (n == 1)
return 'one';
return 'other';
},
'4': function(n) {
if ((isBetween(n, 0, 1)))
return 'one';
return 'other';
},
'5': function(n) {
if ((isBetween(n, 0, 2)) && n != 2)
return 'one';
return 'other';
},
'6': function(n) {
if (n === 0)
return 'zero';
if ((n % 10) == 1 && (n % 100) != 11)
return 'one';
return 'other';
},
'7': function(n) {
if (n == 2)
return 'two';
if (n == 1)
return 'one';
return 'other';
},
'8': function(n) {
if ((isBetween(n, 3, 6)))
return 'few';
if ((isBetween(n, 7, 10)))
return 'many';
if (n == 2)
return 'two';
if (n == 1)
return 'one';
return 'other';
},
'9': function(n) {
if (n === 0 || n != 1 && (isBetween((n % 100), 1, 19)))
return 'few';
if (n == 1)
return 'one';
return 'other';
},
'10': function(n) {
if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19)))
return 'few';
if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19)))
return 'one';
return 'other';
},
'11': function(n) {
if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
return 'few';
if ((n % 10) === 0 ||
(isBetween((n % 10), 5, 9)) ||
(isBetween((n % 100), 11, 14)))
return 'many';
if ((n % 10) == 1 && (n % 100) != 11)
return 'one';
return 'other';
},
'12': function(n) {
if ((isBetween(n, 2, 4)))
return 'few';
if (n == 1)
return 'one';
return 'other';
},
'13': function(n) {
if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
return 'few';
if (n != 1 && (isBetween((n % 10), 0, 1)) ||
(isBetween((n % 10), 5, 9)) ||
(isBetween((n % 100), 12, 14)))
return 'many';
if (n == 1)
return 'one';
return 'other';
},
'14': function(n) {
if ((isBetween((n % 100), 3, 4)))
return 'few';
if ((n % 100) == 2)
return 'two';
if ((n % 100) == 1)
return 'one';
return 'other';
},
'15': function(n) {
if (n === 0 || (isBetween((n % 100), 2, 10)))
return 'few';
if ((isBetween((n % 100), 11, 19)))
return 'many';
if (n == 1)
return 'one';
return 'other';
},
'16': function(n) {
if ((n % 10) == 1 && n != 11)
return 'one';
return 'other';
},
'17': function(n) {
if (n == 3)
return 'few';
if (n === 0)
return 'zero';
if (n == 6)
return 'many';
if (n == 2)
return 'two';
if (n == 1)
return 'one';
return 'other';
},
'18': function(n) {
if (n === 0)
return 'zero';
if ((isBetween(n, 0, 2)) && n !== 0 && n != 2)
return 'one';
return 'other';
},
'19': function(n) {
if ((isBetween(n, 2, 10)))
return 'few';
if ((isBetween(n, 0, 1)))
return 'one';
return 'other';
},
'20': function(n) {
if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(
isBetween((n % 100), 10, 19) ||
isBetween((n % 100), 70, 79) ||
isBetween((n % 100), 90, 99)
))
return 'few';
if ((n % 1000000) === 0 && n !== 0)
return 'many';
if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92]))
return 'two';
if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91]))
return 'one';
return 'other';
},
'21': function(n) {
if (n === 0)
return 'zero';
if (n == 1)
return 'one';
return 'other';
},
'22': function(n) {
if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99)))
return 'one';
return 'other';
},
'23': function(n) {
if ((isBetween((n % 10), 1, 2)) || (n % 20) === 0)
return 'one';
return 'other';
},
'24': function(n) {
if ((isBetween(n, 3, 10) || isBetween(n, 13, 19)))
return 'few';
if (isIn(n, [2, 12]))
return 'two';
if (isIn(n, [1, 11]))
return 'one';
return 'other';
}
};
// return a function that gives the plural form name for a given integer
var index = locales2rules[lang.replace(/-.*$/, '')];
if (!(index in pluralRules)) {
consoleWarn('plural form unknown for [' + lang + ']');
return function() { return 'other'; };
}
return pluralRules[index];
}
/**
* pre-defined 'plural' macro
*/
html10n.macros.plural = function(key, param, opts) {
var str
, n = parseFloat(param);
if (isNaN(n))
return;
// initialize _pluralRules
if (!this._pluralRules)
this._pluralRules = getPluralRules(html10n.language);
var index = this._pluralRules(n);
// try to find a [zero|one|two] key if it's defined
if (n === 0 && ('zero') in opts) {
str = opts['zero'];
} else if (n == 1 && ('one') in opts) {
str = opts['one'];
} else if (n == 2 && ('two') in opts) {
str = opts['two'];
} else if (index in opts) {
str = opts[index];
}
return str;
};
/**
* Localize a document
* @param langs An array of lang codes defining fallbacks
*/
html10n.localize = function(langs) {
var that = this
// if only one string => create an array
if ('string' == typeof langs) langs = [langs]
// Expand two-part locale specs
var i=0
langs.forEach(function(lang) {
if(!lang) return
langs[i++] = lang
if(~lang.indexOf('-')) langs[i++] = lang.substr(0, lang.indexOf('-'))
})
this.build(langs, function(er, translations) {
html10n.translations = translations
html10n.translateElement(translations)
that.trigger('localized')
})
}
/**
* Triggers the translation process
* for an element
* @param translations A hash of all translation strings
* @param element A DOM element, if omitted, the document element will be used
*/
html10n.translateElement = function(translations, element) {
element = element || document.documentElement
var children = element? getTranslatableChildren(element) : document.childNodes;
for (var i=0, n=children.length; i < n; i++) {
this.translateNode(translations, children[i])
}
// translate element itself if necessary
this.translateNode(translations, element)
}
function asyncForEach(list, iterator, cb) {
var i = 0
, n = list.length
iterator(list[i], i, function each(err) {
if(err) consoleLog(err)
i++
if (i < n) return iterator(list[i],i, each);
cb()
})
}
function getTranslatableChildren(element) {
if(!document.querySelectorAll) {
if (!element) return []
var nodes = element.getElementsByTagName('*')
, l10nElements = []
for (var i=0, n=nodes.length; i < n; i++) {
if (nodes[i].getAttribute('data-l10n-id'))
l10nElements.push(nodes[i]);
}
return l10nElements
}
return element.querySelectorAll('*[data-l10n-id]')
}
html10n.get = function(id, args) {
var translations = html10n.translations
if(!translations) return consoleWarn('No translations available (yet)')
if(!translations[id]) return consoleWarn('Could not find string '+id)
// apply macros
var str = translations[id]
str = substMacros(id, str, args)
// apply args
str = substArguments(str, args)
return str
}
// replace {{arguments}} with their values or the
// associated translation string (based on its key)
function substArguments(str, args) {
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
, match
while (match = reArgs.exec(str)) {
if (!match || match.length < 2)
return str // argument key not found
var arg = match[1]
, sub = ''
if (arg in args) {
sub = args[arg]
} else if (arg in translations) {
sub = translations[arg]
} else {
consoleWarn('Could not find argument {{' + arg + '}}')
return str
}
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length)
}
return str
}
// replace {[macros]} with their values
function substMacros(key, str, args) {
var regex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ //.exec('{[ plural(n) other: are {{n}}, one: is ]}')
, match
while(match = regex.exec(str)) {
// a macro has been found
// Note: at the moment, only one parameter is supported
var macroName = match[1]
, paramName = match[2]
, optv = match[3]
, opts = {}
if (!(macroName in html10n.macros)) continue
if(optv) {
optv.match(/(?=\s*)([a-zA-Z]+)\: ?([ a-zA-Z{}]+)(?=,?)/g).forEach(function(arg) {
var parts = arg.split(':')
, name = parts[0]
, value = parts[1].trim()
opts[name] = value
})
}
var param
if (args && paramName in args) {
param = args[paramName]
} else if (paramName in html10n.translations) {
param = translations[paramName]
}
// there's no macro parser: it has to be defined in html10n.macros
var macro = html10n.macros[macroName]
str = str.substr(0, match.index) + macro(key, param, opts) + str.substr(match.index+match[0].length)
}
return str
}
/**
* Applies translations to a DOM node (recursive)
*/
html10n.translateNode = function(translations, node) {
var str = {}
// get id
str.id = node.getAttribute('data-l10n-id')
if (!str.id) return
if(!translations[str.id]) return consoleWarn('Couldn\'t find translation key '+str.id)
// get args
if(window.JSON) {
str.args = JSON.parse(node.getAttribute('data-l10n-args'))
}else{
try{
str.args = eval(node.getAttribute('data-l10n-args'))
}catch(e) {
consoleWarn('Couldn\'t parse args for '+str.id)
}
}
str.str = html10n.get(str.id, str.args)
// get attribute name to apply str to
var prop
, index = str.id.lastIndexOf('.')
, attrList = // allowed attributes
{ "title": 1
, "innerHTML": 1
, "alt": 1
, "textContent": 1
}
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
prop = str.id.substr(index + 1)
} else { // no attribute: assuming text content by default
prop = document.body.textContent ? 'textContent' : 'innerText'
}
// Apply translation
if (node.children.length === 0 || prop != 'textContent') {
node[prop] = str.str
} else {
var children = node.childNodes,
found = false
for (var i=0, n=children.length; i < n; i++) {
if (children[i].nodeType === 3 && /\S/.test(children[i].textContent)) {
if (!found) {
children[i].nodeValue = str.str
found = true
} else {
children[i].nodeValue = ''
}
}
}
if (!found) {
consoleWarn('Unexpected error: could not translate element content for key '+str.id, node)
}
}
}
/**
* Builds a translation object from a list of langs (loads the necessary translations)
* @param langs Array - a list of langs sorted by priority (default langs should go last)
*/
html10n.build = function(langs, cb) {
var that = this
, build = {}
asyncForEach(langs, function (lang, i, next) {
if(!lang) return next();
that.loader.load(lang, next)
}, function() {
var lang
langs.reverse()
// loop through priority array...
for (var i=0, n=langs.length; i < n; i++) {
lang = langs[i]
if(!lang || !(lang in that.loader.langs)) continue;
// ... and apply all strings of the current lang in the list
// to our build object
for (var string in that.loader.langs[lang]) {
build[string] = that.loader.langs[lang][string]
}
// the last applied lang will be exposed as the
// lang the page was translated to
that.language = lang
}
cb(null, build)
})
}
/**
* Returns the language that was last applied to the translations hash
* thus overriding most of the formerly applied langs
*/
html10n.getLanguage = function() {
return this.language;
}
/**
* Returns the direction of the language returned be html10n#getLanguage
*/
html10n.getDirection = function() {
if(!this.language) return
var langCode = this.language.indexOf('-') == -1? this.language : this.language.substr(0, this.language.indexOf('-'))
return html10n.rtl.indexOf(langCode) == -1? 'ltr' : 'rtl'
}
/**
* Index all <link>s
*/
html10n.index = function () {
// Find all <link>s
var links = document.getElementsByTagName('link')
, resources = []
for (var i=0, n=links.length; i < n; i++) {
if (links[i].type != 'application/l10n+json')
continue;
resources.push(links[i].href)
}
this.loader = new Loader(resources)
this.trigger('indexed')
}
if (document.addEventListener) // modern browsers and IE9+
document.addEventListener('DOMContentLoaded', function() {
html10n.index()
}, false)
else if (window.attachEvent)
window.attachEvent('onload', function() {
html10n.index()
}, false)
// gettext-like shortcut
if (window._ === undefined)
window._ = html10n.get;
return html10n
}
window.html10n = html10n(window, document)
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
*/ */
//the default text of a pad //the default text of a pad
"defaultPadText" : "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nGet involved with Etherpad at http:\/\/etherpad.org\n", "defaultPadText" : "${:welcome-message}",
/* Users must have a session to access pads. This effectively allows only group pads to be accessed. */ /* Users must have a session to access pads. This effectively allows only group pads to be accessed. */
"requireSession" : false, "requireSession" : false,
......
var page = require('webpage').create();
url = '${:content-url}'
page.open(url, function (status) {
var text = page.evaluate(function(){
return document.getElementById('button').textContent
});
if(text !== "" && text !== null) {
phantom.exit();
} else {
phantom.exit(1);
}
});
var page = require('webpage').create();
url = '${:content-url}/p/test'
page.open(url, function (status) {
setTimeout(function(){
var text = page.evaluate(function(){
var container = document.getElementById('editorcontainer');
var iframe = container.firstChild;
container = iframe.contentDocument.getElementById('outerdocbody');
iframe = container.firstChild;
container = iframe.contentDocument.getElementById('innerdocbody');
return container.textContent;
});
if (text === null) {
phantom.exit();
} else {
phantom.exit(1);
}
},2500);
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment