Compare commits

..

209 Commits

Author SHA1 Message Date
Badlop 2feb929c55 Fix release date of ejabberd 2.0.2 to 28 August 2008
SVN Revision: 1557
2008-08-30 11:17:03 +00:00
Badlop b193ada44d * src/ejabberd.app: Fix version number to 2.0.2
SVN Revision: 1556
2008-08-30 11:13:06 +00:00
Christophe Romain 2cdb70556b fix 2.0.2 version
SVN Revision: 1555
2008-08-27 16:35:26 +00:00
Christophe Romain adaa3ffd2b tag for ejabberd-2.0.2 release
SVN Revision: 1554
2008-08-27 16:33:06 +00:00
Christophe Romain 55b586e51c send last published events now supports PEP events from unavailable users nodes (EJAB-698)
SVN Revision: 1549
2008-08-27 09:25:24 +00:00
Badlop 0b217097dd * doc/release_notes_2.0.2.txt: Update for final release
* doc/guide.tex: Windows binary installer requires MSVC++ 5
* doc/guide.html: Likewise

SVN Revision: 1548
2008-08-26 14:26:56 +00:00
Christophe Romain d5df314295 get_items bugfix (EJAB-716)
SVN Revision: 1541
2008-08-25 22:51:17 +00:00
Christophe Romain 28c34a844a Prevent case_clause error when ejabber_odbc:sql_query returns {error, Reason}
SVN Revision: 1539
2008-08-25 13:34:53 +00:00
Christophe Romain 3c88ab49f0 Prevent case_clause error when ejabber_odbc:sql_query returns {error, Reason}
SVN Revision: 1537
2008-08-25 13:11:25 +00:00
Badlop b338dd671f * src/ejabberd_check.erl: Detect correctly MSSQL and ODBC
configuration (EJAB-710)

SVN Revision: 1536
2008-08-25 12:08:22 +00:00
Geoff Cant 2cda62dceb EJAB-624: fixes mod_muc_room:is_visitor/2 to use get_role not get_affiliation
SVN Revision: 1535
2008-08-23 23:23:51 +00:00
Badlop 5d6fe1a055 * src/ejabberd_router.erl: Fix call to mnesia match_object
SVN Revision: 1533
2008-08-22 11:35:32 +00:00
Badlop 7ecbc0cd89 * doc/guide.tex: Fix names of chatroom to room, user to occupant
* doc/guide.html: Likewise

SVN Revision: 1532
2008-08-21 15:13:25 +00:00
Badlop 2f4db862f4 * src/mod_register.erl: Change password using mod_register always
returns success regardless of real result (EJAB-723)
* src/ejabberd_auth.erl: Likewise
* src/ejabberd_auth_external.erl: Likewise
* src/ejabberd_auth_internal.erl: Likewise
* src/ejabberd_auth_odbc.erl: Likewise

SVN Revision: 1530
2008-08-18 18:21:10 +00:00
Badlop 11f68cf7fd * src/msgs/sv.msg: Fixed formatting typos
SVN Revision: 1526
2008-08-16 12:06:13 +00:00
Badlop 5a05eb8d62 * src/gen_mod.erl: Export stop_module_keep_config/2 (EJAB-706)
SVN Revision: 1525
2008-08-16 12:03:21 +00:00
Badlop 79a0a44505 * doc/guide.tex: Explain that LDAP is read-only storage (thanks to
Evgeniy Khramtsov)
* doc/guide.html: Likewise

SVN Revision: 1521
2008-08-13 11:00:21 +00:00
Badlop 54842e7585 * src/msgs/sk.msg: Updated (thanks to Marek Becka)
SVN Revision: 1519
2008-08-11 00:48:57 +00:00
Badlop 76b19660e3 * src/msgs/eo.msg: Updated (thanks to Andreas van Cranenburgh)
* src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh)
* src/msgs/sv.msg: Updated (thanks to Thore Alstromer and Heysan)

SVN Revision: 1518
2008-08-10 11:40:41 +00:00
Badlop 68ecc1f082 Retract from previous commit the code that checked the connection is attempted to a known served component (EJAB-717)
SVN Revision: 1517
2008-08-09 20:09:37 +00:00
Badlop 9147a1d2dd * src/ejabberd_service.erl: Fix XEP-0114 compliance: define xmlns
in header of error response; check the connection is attempted to
a served component; include in response the JID of served
component not server (thanks to Sergei Golovan)

SVN Revision: 1516
2008-08-09 18:08:00 +00:00
Badlop 469f1c43a6 * doc/release_notes_2.0.2.txt: Added for ejabberd 2.0.2-beta1
SVN Revision: 1503
2008-08-01 10:31:39 +00:00
Badlop 9dd66c241c * src/web/ejabberd_http.erl: Temporary solution for check of
packet size when HTTPS (EJAB-611)(EJAB-507)(EJAB-574)

SVN Revision: 1502
2008-08-01 08:50:19 +00:00
Badlop f5e489c764 * doc/guide.tex: Update Process-one name to ProcessOne (EJAB-708)
* doc/guide.html: Likewise
* doc/api/overview.edoc: Likewise
* src/*/*.erl: Likewise
* src/*/*.hrl: Likewise
* src/*/*.c: Likewise
* src/odbc/*.sql: Likewise

SVN Revision: 1499
2008-07-31 11:18:49 +00:00
Badlop 31b00c25c8 * src/mod_muc/mod_muc_room.erl: Support Reasons for all
affiliation and role changes (EJAB-306)

SVN Revision: 1498
2008-07-30 18:24:08 +00:00
Badlop 4f1fe31627 * src/gen_mod.erl: When ejabberd is kindly stopped, don't forget
modules configuration (EJAB-706)
* src/ejabberd_app.erl: Likewise

SVN Revision: 1497
2008-07-30 18:11:14 +00:00
Badlop d22154a2d4 * src/msgs/uk.msg: Fix: each string in a single line
* src/msgs/wa.msg: Likewise

* src/msgs/es.msg: Fix typo
* src/msgs/gl.msg: Likewise
* src/msgs/pt-br.msg: Likewise

* src/msgs/zh.msg: Fix some strings (thanks to Zhan Caibao)

SVN Revision: 1496
2008-07-30 14:09:36 +00:00
Badlop 751a8fbd37 * src/msgs/ca.msg: Updated (thanks to Badlop)
* src/msgs/cs.msg: Updated (thanks to Lukas Poliuvk)
* src/msgs/de.msg: Updated (thanks to Nikolaus Polak)
* src/msgs/es.msg: Updated (thanks to Badlop)
* src/msgs/fr.msg: Updated (thanks to Christophe Romain)
* src/msgs/it.msg: Updated (thanks to Luca Brivio)
* src/msgs/ja.msg: Updated (thanks to Tsukasa Hamano)
* src/msgs/no.msg: Updated (thanks to Stian B. Barmen)
* src/msgs/pl.msg: Updated (thanks to Zbyszek Zolkiewski)
* src/msgs/pt-br.msg: Updated (thanks to Otavio Fernandes)
* src/msgs/ru.msg: Updated (thanks to Evgeniy Khramtsov)
* src/msgs/tr.msg: Updated (thanks to Doruk Fisek)
* src/msgs/uk.msg: Updated (thanks to Ruslan Rakhmanin)
* src/msgs/wa.msg: Updated (thanks to Pablo Saratxaga)
* src/msgs/zh.msg: Updated (thanks to Shelley Shyan)

SVN Revision: 1495
2008-07-29 11:21:53 +00:00
Badlop 971165cb88 * doc/guide.tex: Document how to get error message when ejabberd
crash dumps at start (EJAB-660)
* doc/guide.html: Likewise

SVN Revision: 1494
2008-07-28 16:55:01 +00:00
Badlop 6ea15171f7 * src/mod_muc/mod_muc_room.erl: Add 'description' to the
mod_muc_room config record; it will be used in ejabberd 2.1.x
branch (EJAB-670)

SVN Revision: 1493
2008-07-28 16:15:51 +00:00
Christophe Romain 782ee63266 Speedup startup with many pubsub nodes (EJAB-669)
SVN Revision: 1490
2008-07-25 09:06:09 +00:00
Badlop d9f3c87899 * doc/guide.tex: Include example PAM configuration file
ejabberd.pam (thanks to Evgeniy Khramtsov)(EJAB-704)
* doc/guide.html: Likewise

SVN Revision: 1489
2008-07-24 18:21:40 +00:00
Badlop 2d5fdbab64 * src/mod_proxy65/mod_proxy65_lib.erl: Send protocol compliant
SOCKS5 reply; this breaks support of uncompliant Psi<0.10 (thanks
to Felix Geyer)(EJAB-632)
* src/mod_proxy65/mod_proxy65_stream.erl: Likewise

SVN Revision: 1488
2008-07-24 18:03:28 +00:00
Badlop f841acb21f * src/mod_register.erl: When a registration is blocked due to IP
limitation, return description in error stanza (EJAB-692)

SVN Revision: 1487
2008-07-24 17:49:37 +00:00
Christophe Romain 71e87aef6e allow owner to subscribe/get its one node (EJAB-705)
SVN Revision: 1485
2008-07-24 14:06:28 +00:00
Badlop df21b2d48c * src/Makefile.in: Support for parallel compilation with 'make -j'
in multi core CPUs: fix compilation dependencies; compile
behaviors before other source code (EJAB-697)(thanks to Jonathan
Schleifer)
* src/mod_pubsub/Makefile.in: Likewise
* src/eldap/Makefile.in: Likewise

SVN Revision: 1484
2008-07-24 11:53:00 +00:00
Badlop 35f520e3d9 * doc/guide.tex: Document room options allow_visitor_nickchange
and allow_visitor_status (EJAB-624)
* doc/guide.html: Likewise

SVN Revision: 1483
2008-07-24 11:22:43 +00:00
Geoff Cant 318823fe68 Altering XForms text for allow_visitor_status mod_muc_room option. (EJAB-624)
SVN Revision: 1481
2008-07-23 17:45:39 +00:00
Geoff Cant 102281194f Remove allow_visitor_presence, add allow_visitor_status [merge from trunk@1477-1478] (EJAB-624)
SVN Revision: 1479
2008-07-23 16:58:52 +00:00
Geoff Cant 6768a21d36 Implementing muc_room visitor presence restrictions. [merge from trunk@1475] (EJAB-624)
SVN Revision: 1476
2008-07-23 13:03:30 +00:00
Christophe Romain 895e104b6a subscribing to a node sends only last items (EJAB-700), send_last_items bugfix
SVN Revision: 1473
2008-07-23 01:13:36 +00:00
Christophe Romain c6090dd8ca pubsub improvement, fixes EJAB-684 EJAB-675 EJAB-663
SVN Revision: 1471
2008-07-22 23:41:40 +00:00
Badlop 293676d2a6 * src/ejabberd_config.erl: If syntax mistake in config file, show
specific error message (EJAB-616)

SVN Revision: 1470
2008-07-22 16:08:57 +00:00
Badlop 4ebaf3efa0 * src/mod_muc/mod_muc_room.erl: Fix to allow a server admin to add
himself as owner of a room (EJAB-687)

SVN Revision: 1460
2008-07-17 17:32:11 +00:00
Badlop 82e8b16a39 * src/Makefile.in: ejabberctl doesn't use the erl found by the
configure script (EJAB-676)
* src/ejabberdctl.template: Likewise

SVN Revision: 1459
2008-07-17 17:13:01 +00:00
Christophe Romain fc2ea76a45 use -DSSL39 if compiling with R12
SVN Revision: 1455
2008-07-16 22:23:58 +00:00
Badlop ae939c5f80 * src/ejabberd_c2s.erl: Put auth_module in Info always (EJAB-549)
SVN Revision: 1454
2008-07-16 18:05:46 +00:00
Christophe Romain 745106c83d Rolled back the previous IP getting patch, and Report connection's IP address
SVN Revision: 1452
2008-07-16 13:30:37 +00:00
Christophe Romain 546bb02153 Rolled back the previous IP getting patch, and Report connection's IP address
SVN Revision: 1451
2008-07-16 13:29:57 +00:00
Badlop 663f6f76a7 * doc/guide.tex: Improve explanation of option 'hosts' in
ejabberd_service
* doc/guide.html: Likewise

SVN Revision: 1448
2008-07-16 10:21:45 +00:00
Badlop b1ca88a5eb * src/configure.ac: Improve legibility
* src/aclocal.m4: Likewise
* src/configure: Likewise

* src/ejabberdctl.template: Remove garbage variable. Document node
option

* doc/guide.tex: Add references to sections.
* doc/guide.html: Likewise

SVN Revision: 1438
2008-07-12 21:32:45 +00:00
Badlop cdcc3a2520 * doc/guide.tex: Document how to insert a newline character in
welcome_message (EJAB-501)
* src/ejabberd.cfg.example: Likewise

SVN Revision: 1437
2008-07-11 13:47:15 +00:00
Christophe Romain 3c90d7c2b9 change needed to support previous blacklist support
SVN Revision: 1432
2008-07-11 07:13:41 +00:00
Christophe Romain bc18e89d61 Backport C2S blacklist support from trunk
SVN Revision: 1431
2008-07-11 06:59:45 +00:00
Badlop e956ca4fe3 * src/configure.ac: Don't check for erlang header file (EJAB-232)
* src/configure: Likewise

SVN Revision: 1430
2008-07-10 18:09:18 +00:00
Badlop 53c994825c * src/configure.ac: Check for erlang header files (EJAB-232)
* src/configure: Likewise

SVN Revision: 1429
2008-07-09 21:33:34 +00:00
Badlop 085d979037 * src/mod_pubsub/mod_pubsub.erl: Fix compilation warnings
* src/mod_pubsub/node_zoo.erl: Likewise
* src/mod_shared_roster.erl: Likewise

SVN Revision: 1428
2008-07-09 21:26:25 +00:00
Badlop 49b02c0a9f * src/mod_muc/mod_muc_log.erl: Fix XHTML compliance: ensure some
language is set, include ID attribute in each message, add
microseconds to ensure unique value (EJAB-497)

SVN Revision: 1426
2008-07-09 18:39:41 +00:00
Badlop d8405b694e * src/ejabberd_config.erl (load_file): error message on sasl.log
is not flattened (EJAB-616)

SVN Revision: 1424
2008-07-09 16:08:32 +00:00
Badlop 95bd9068f7 * doc/guide.tex: mod_muc_log XMPP URI supports the updated version
RFC 5122 (EJAB-631)
* doc/guide.html: Likewise

SVN Revision: 1423
2008-07-09 14:07:27 +00:00
Badlop 407d3b77b7 * tools/ejabberdctl: Work also when 'which' is unavailable
SVN Revision: 1419
2008-07-08 11:07:45 +00:00
Christophe Romain 3dfcc4c4d3 typo fix
SVN Revision: 1417
2008-07-08 10:31:29 +00:00
Christophe Romain 1de6329c41 typo on date fix
SVN Revision: 1415
2008-07-08 10:18:54 +00:00
Christophe Romain 8047ff0617 improve ip fetching patch
SVN Revision: 1414
2008-07-08 10:17:50 +00:00
Badlop 8032533f26 * src/Makefile.in: Spool, config and log dirs: writtable by owner,
readable by group, nothing by others (EJAB-686)
* doc/guide.tex: New section Securing sensible files
* doc/guide.html: Likewise

SVN Revision: 1413
2008-07-07 14:52:47 +00:00
Badlop 00c3bc2450 * doc/guide.tex: Solaris Makefile install: use ginstall (thanks to
Jonathan Auer)(EJAB-649)
* doc/guide.html: Likewise

SVN Revision: 1412
2008-07-07 08:47:47 +00:00
Jérôme Sautret c76a009238 Removed non ascii characters in changelog
SVN Revision: 1411
2008-07-04 08:35:11 +00:00
Jérôme Sautret 8012133539 * src/mod_privacy_odbc.erl: Support for privacy lists in MySQL (thanks to Igor Goryachev)(EJAB-538)(merge r1409 from trunk)
SVN Revision: 1410
2008-07-03 16:20:47 +00:00
Christophe Romain 1e56a614f9 PubSub improvements, and solves (EJAB-453) (EJAB-608)
SVN Revision: 1407
2008-07-03 09:56:21 +00:00
Badlop 971c9ce5a5 * src/ejabberd_ctl.erl: Web Admin and Ad-hoc admin: dump only
persistent tables (EJAB-678)

SVN Revision: 1387
2008-06-29 11:59:06 +00:00
Badlop 7abfd51534 * src/mod_pubsub/node_pep.erl: Complain if mod_caps disabled and
mod_pubsub has PEP plugin enabled (EJAB-677)

SVN Revision: 1386
2008-06-29 11:34:30 +00:00
Badlop 7e86698606 * src/web/ejabberd_http.erl: Support PUT and DELETE methods in
ejabberd_http (thanks to Eric Cestari)(EJAB-662)

SVN Revision: 1373
2008-06-21 00:19:57 +00:00
Badlop 45ccda9961 * doc/guide.tex: Explain that S2S outgoing first tries IPv4 and if
that fails then tries IPv6
* doc/guide.html: Likewise

SVN Revision: 1372
2008-06-21 00:12:06 +00:00
Christophe Romain 2c9d424330 allow get_default on PEP nodes (EJAB-656)
SVN Revision: 1363
2008-06-19 09:08:30 +00:00
Badlop 541f381145 * src/ejabberd.app: The ejabberd version number is defined in the
OTP application resource file, in the key 'vsn' (EJAB-657)
* src/ejabberd.hrl: The macro VERSION now consults the ejabberd
application key vsn
* src/configure.erl: Load the ejabberd application description
* doc/Makefile: Read ejabberd version from ejabberd.app vsn
* doc/api/Makefile: Likewise

SVN Revision: 1361
2008-06-18 21:33:48 +00:00
Christophe Romain a7cd412a76 temporary roster_groups_allowed fix (EJAB-655)
SVN Revision: 1360
2008-06-18 16:35:17 +00:00
Christophe Romain ab310255d7 pubsub get_default bugfix (EJAB-656)
SVN Revision: 1357
2008-06-18 16:19:15 +00:00
Badlop d9241c9e75 * src/ejabberd.cfg.example: Add registration_timeout (EJAB-653)
SVN Revision: 1355
2008-06-13 17:51:01 +00:00
Badlop bc8294990a * doc/guide.tex: Title in HTML is shorter. Update several external URIs.
SVN Revision: 1354
2008-06-13 15:25:57 +00:00
Badlop 25d8e53735 * doc/guide.tex: Document ldap_local_filter (EJAB-179)
SVN Revision: 1353
2008-06-13 10:13:44 +00:00
Badlop f59c0c9eb2 * doc/guide.tex: Table of listener modules converted to
description. Table of modules overview simplified, and module
names link to their sections.
* doc/guide.html: Regenerated with all the latest changes

SVN Revision: 1352
2008-06-12 23:52:13 +00:00
Badlop aaae1339e1 * doc/guide.tex: Fix indentation of verbatim text
SVN Revision: 1351
2008-06-12 23:01:09 +00:00
Badlop 38d218c129 * doc/guide.tex:
Changes in CSS: verbatim text is indented and has grey background;
descriptions are indented; table borders are softer.

SVN Revision: 1350
2008-06-12 22:00:51 +00:00
Badlop c67eaeb534 * doc/guide.tex: Permanent reference URL for sections (EJAB-651)
SVN Revision: 1349
2008-06-12 21:54:30 +00:00
Badlop 8a140dd509 * doc/guide.tex: Small fixes (thanks to Christoph Anton Mitterer)
* doc/introduction.tex: Likewise
* doc/guide.html: Likewise

SVN Revision: 1347
2008-06-08 16:52:25 +00:00
Badlop 6924b4c3e8 * doc/guide.tex: Document ejabberdctl status code (EJAB-633)
* doc/guide.html: Likewise

SVN Revision: 1346
2008-06-05 12:04:43 +00:00
Badlop 73f40db258 * src/msgs/pl.msg: Bugfix in arguments of translated string that
could crash the room (thanks to Anastasia Gornostaeva)

SVN Revision: 1345
2008-06-04 13:21:36 +00:00
Badlop 56740871f1 * src/web/ejabberd_web.erl (make_xhtml/2): Allow to include
elements in the HTTP header

SVN Revision: 1344
2008-05-31 18:21:43 +00:00
Badlop 6c9eb98792 * src/odbc/odbc_queries.erl (del_user_return_password): Return
password (thanks to Oleg Palij)

SVN Revision: 1343
2008-05-31 17:09:13 +00:00
Badlop 50b133f6a2 * README: R12 support: remove compilation warning (EJAB-630)
SVN Revision: 1340
2008-05-22 00:01:18 +00:00
Badlop fef60fe1d3 Retract the changes that SVN commit 1326 made in branches/ejabberd-2.0.x
SVN Revision: 1339
2008-05-20 16:23:43 +00:00
Christophe Romain 31940f16c7 add release_notes_2.0.1
SVN Revision: 1338
2008-05-19 22:35:01 +00:00
Badlop 45c1bad6d8 * doc/guide.html: Updated
* doc/dev.html: Likewise
* doc/features.html: Likewise
* doc/version.tex: Likewise

* src/ejabberd.hrl: Version is 2.0.x

SVN Revision: 1336
2008-05-19 09:46:42 +00:00
Badlop 6916d7b552 * src/configure.ac: R12 support: remove compilation
warning (EJAB-630)
* src/configure: Likewise
* doc/guide.tex: Likewise

SVN Revision: 1334
2008-05-19 09:20:35 +00:00
Badlop 39e93fcbbf * doc/guide.tex: Describe how to disable registration
limitation (EJAB-614)

SVN Revision: 1333
2008-05-19 09:13:19 +00:00
Christophe Romain 7461cb5f72 Change FSMTIMEOUT to 30s
SVN Revision: 1327
2008-05-16 15:28:23 +00:00
Christophe Romain 8e069daa61 fixing 1324 commit issue on tagged versions
SVN Revision: 1326
2008-05-16 14:23:37 +00:00
Christophe Romain 8041c033a9 Don't activate a socket untill its receiver process is controlling it
SVN Revision: 1325
2008-05-16 12:56:24 +00:00
Badlop ca8c659804 * src/mod_muc/mod_muc_room.erl: Return Forbidden error message
when user sends private message in a room that disallows
it (EJAB-595)

SVN Revision: 1323
2008-05-12 20:35:43 +00:00
Badlop a96cf33df3 * src/web/ejabberd_http.erl (parse_auth): Allow password that
include colon character (EJAB-522)

SVN Revision: 1322
2008-05-12 17:56:27 +00:00
Christophe Romain d75577fa34 change contribs to trunk
SVN Revision: 1314
2008-05-01 22:37:56 +00:00
Christophe Romain 2f62e78c06 XEP-0115 patch (EJAB-618)
SVN Revision: 1312
2008-04-30 08:49:19 +00:00
Badlop fdae05c27d * src/ejabberd_s2s_out.erl: Improve confusing log message in s2s
connection: wait_for_validation connect timeout (EJAB-617)

SVN Revision: 1311
2008-04-29 16:59:03 +00:00
Badlop 58da3e4e99 * src/ejabberd.cfg.example: Small improvements in explanations
* doc/guide.tex: Document MUC room options (EJAB-619)

SVN Revision: 1310
2008-04-29 16:44:12 +00:00
Badlop 2c795957ac Merge changeset 1305 from ejabberd trunk.
2008-04-27  Alexey Shchepin  <alexey@process-one.net>

* src/mod_muc/mod_muc_room.erl: Fixed room shaper processing

SVN Revision: 1309
2008-04-28 18:44:28 +00:00
Badlop 6e5aaadf57 Merge changesets 1299, 1300 and 1302 from ejabberd trunk.
2008-04-26  Badlop  <badlop@process-one.net>

* doc/guide.tex: Document option registration_timeout (EJAB-614)

2008-04-23  Alexey Shchepin  <alexey@process-one.net>

* src/treap.erl: Bugfix

* src/mod_register.erl: Fixed table creation, timeout isn't
activated when registration fails

* src/mod_register.erl: Restrict registration frequency per IP or
user (EJAB-614)
* src/ejabberd_c2s.erl: Pass IP to the c2s_unauthenticated_iq hook
* src/ejabberd_config.erl: Added registration_timeout option

* src/treap.erl: Treaps implementation

SVN Revision: 1308
2008-04-28 18:41:13 +00:00
Badlop 0f4244a72c * doc/guide.tex: Document the option max_s2s_connections
SVN Revision: 1307
2008-04-28 18:07:23 +00:00
Badlop e9e52374f8 * src/mod_shared_roster.erl: Fix for new registered accounts not
being immediately shown in an 'all' special shared roster
group (thanks to Alexey Shchepin) (EJAB-71)
* src/mod_register.erl: New vhost event user_registered

SVN Revision: 1304
2008-04-26 17:54:57 +00:00
Badlop 62ed66e195 * src/ejabberd_auth.erl: Improve anonymous authentication to not
remove rosters accidentally (EJAB-549). New functions in
ejabberd_auth to get/check password and know which module accepted
the authentication. New element 'auth_module' in ejabberd_c2s
record 'statedata'. Cyrsasl provides a new property in the
response: {auth_module, AuthModule}.
* src/ejabberd_auth_anonymous.erl: Likewise
* src/ejabberd_c2s.erl: Likewise
* src/cyrsasl_anonymous.erl: Likewise
* src/cyrsasl_digest.erl: Likewise
* src/cyrsasl_plain.erl: Likewise

SVN Revision: 1298
2008-04-22 18:56:29 +00:00
Badlop 2e12fd2b11 * src/ejabberd_s2s_out.erl: Fix long timeout when reconnecting s2s
after a remote server crash (EJAB-540)
* src/ejabberd_s2s_in.erl: Likewise
* src/ejabberd_s2s.erl: Likewise
* doc/guide.tex: Likewise

SVN Revision: 1296
2008-04-18 12:19:45 +00:00
Badlop 8d23ef3ed0 * doc/guide.tex: Clarification: PEP is enabled in default config
SVN Revision: 1295
2008-04-16 15:44:58 +00:00
Christophe Romain bd9d2cb97c Cache negative response (EJAB-474)
SVN Revision: 1293
2008-04-14 12:00:37 +00:00
Badlop bb5e7353a4 Merge SVN r1287 from trunk to 2.0.x branch:
* src/tls/tls_drv.c: Fixed gcc signedness warnings (EJAB-447)
* src/ejabberd_zlib/ejabberd_zlib_drv.c: Likewise

* src/expat_erl.c: Removed R9B workaround (EJAB-447)

SVN Revision: 1289
2008-04-11 09:25:54 +00:00
Christophe Romain cfeb6f9c2b pubsub identity and database update bugfix
SVN Revision: 1284
2008-04-10 14:08:35 +00:00
Mickaël Rémond 0623a04666 *src/ejabberd_c2s.erl: Uniform default value for empty privacy list. Fixes (EJAB-603).
SVN Revision: 1283
2008-04-10 09:53:07 +00:00
Badlop 397fbf5b73 * src/ejabberd_auth_ldap.erl: LDAP function to get the number of
registered users is too slow (EJAB-331): set timeout in LDAP
search queries (thanks to Evgeniy Khramtsov) and return the number
of registered users.

SVN Revision: 1280
2008-04-08 09:37:06 +00:00
Mickaël Rémond 6f205d2d2a * doc/guide.tex: Documented the IQ discipline {queue, N}.
SVN Revision: 1279
2008-04-07 13:27:03 +00:00
Badlop e8dd27d3fc * doc/guide.tex: Fix default_room_opts with default_room_options
* doc/guide.html: Likewise

SVN Revision: 1277
2008-04-05 10:53:32 +00:00
Badlop 73f061c02c * src/ejabberd_auth_ldap.erl (get_vh_registered_users_number): New
function that returns 0 registered users (EJAB-331).

SVN Revision: 1276
2008-04-04 18:57:01 +00:00
Badlop 6f19f7ebbb * src/ejabberd_c2s.erl (process_presence_probe): Don't route a
presence probe to oneself (EJAB-498)

SVN Revision: 1275
2008-04-03 22:35:26 +00:00
Christophe Romain 615dc9ff94 Do not ignore values passed from configure (EJAB-592)
SVN Revision: 1271
2008-04-02 14:24:00 +00:00
Christophe Romain cd26cb4ad6 clone iq_response table bugfix
SVN Revision: 1270
2008-04-02 12:18:22 +00:00
Christophe Romain 22b66e40e0 add condition inclusion of pep in disco identity (EJAB-564)
SVN Revision: 1269
2008-04-02 09:06:34 +00:00
Badlop 3f33ff0adf * doc/webadmmain.png: Updated to ejabberd 2.0.0
* doc/webadmmainru.png: Likewise

* doc/disco.png: Removed because not used

* doc/guide.tex: Fix Latex reference to webadmin section. Update
explanation of screenshots. Update xmpp addresses of Mickael
Remond and Sander Devrieze.
* doc/guide.html: Likewise

* doc/Makefile: Remove the Hevea deprecated option -noiso
* doc/guide.html: Likewise
* doc/dev.html: Likewise
* doc/features.html: Likewise

SVN Revision: 1262
2008-03-31 10:48:10 +00:00
Badlop fcb5788568 * doc/guide.tex: Fix epam location (thanks to Evgeniy Khramtsov)
* doc/guide.html: Likewise

SVN Revision: 1259
2008-03-27 00:28:44 +00:00
Badlop f404bac82a * src/Makefile.in: Only try to install epam if pam was enabled
in configure script (thanks to Etan Reisner)(EJAB-586)

SVN Revision: 1256
2008-03-25 18:59:45 +00:00
Badlop 7dcd189e27 * src/Makefile.in: Failure to install epam is not
critical (EJAB-573)

SVN Revision: 1255
2008-03-25 17:18:47 +00:00
Badlop 9c11783e05 * doc/guide.tex: mod_vcard_ldap replace NICK with NICKNAME (thanks
to Andreas Ntaflos)
* doc/guide.html: Likewise

SVN Revision: 1254
2008-03-24 18:57:41 +00:00
Badlop c74e7e8a17 * src/msgs/de.msg: Fix irc typo (thanks to Jonathan Schleifer)
* src/msgs/cs.msg: Likewise
* src/msgs/pl.msg: Likewise
* src/msgs/sk.msg: Likewise

SVN Revision: 1253
2008-03-24 01:28:55 +00:00
Mickaël Rémond 635565ecf3 * src/eldap/Makefile.in: Generate ELDAPv3.beam during first Makefile pass (EJAB-583).
SVN Revision: 1250
2008-03-22 16:44:23 +00:00
Badlop c25f960220 * doc/guide.tex: Document service_check_from (EJAB-576)
* doc/guide.html: Likewise

SVN Revision: 1248
2008-03-22 00:33:28 +00:00
Badlop 6aa2f740f4 * src/mod_caps.erl: Move two log calls ERROR_MSG to DEBUG
* src/shaper.erl: Move log call INFO_MSG to DEBUG

SVN Revision: 1247
2008-03-21 18:58:07 +00:00
Badlop 20ebe81384 * doc/guide.tex: Document s2s_default_policy and
s2s_host (EJAB-575)
* doc/guide.html: Likewise

SVN Revision: 1246
2008-03-21 16:17:37 +00:00
Christophe Romain 9e60b2b0a6 Pubsub subscription is now wrapped in pubsub tags (EJAB-580)
SVN Revision: 1245
2008-03-21 16:05:42 +00:00
Christophe Romain 01b4b77373 includes Makefile.in changes to EJAB-573
SVN Revision: 1242
2008-03-21 15:41:51 +00:00
Christophe Romain 6d7b71f13c Seek epam binary into priv/bin (EJAB-573)
SVN Revision: 1241
2008-03-21 15:35:40 +00:00
Christophe Romain dc37faf587 Rewrite io:format calls to loglevel macros (EJAB-555) so we do not loose debug anymore in detached nodes
SVN Revision: 1240
2008-03-21 15:00:59 +00:00
Badlop bc2f42132f * doc/guide.tex: Improve explanation of how to start ejabberd when
binary installer. Don't recommend R12 in Windows compilation.
Describe what happens if maxrate shaper is exceeded.
* doc/guide.html: Likewise

SVN Revision: 1238
2008-03-20 19:24:27 +00:00
Mickaël Rémond da5f069dd2 * src/eldap.erl: Improved logging. We now use ejabberd logging framework (EJAB-582).
* src/eldap.erl: Faster LDAP reconnection (Thanks to Christophe Romain) (EJAB-581)

SVN Revision: 1237
2008-03-20 16:38:29 +00:00
Mickaël Rémond 1a616a91ef * src/ejabberd_s2s.erl: API improvement: Added s2s_connect_hook (EJAB-566).
SVN Revision: 1233
2008-03-15 09:39:10 +00:00
Badlop c086292651 * src/odbc/ejabberd_odbc.erl: Start ODBC explicitely because
Erlang R12 doesn't start automatically like in R11 and
older (thanks to Sergei Golovan)(EJAB-541)

SVN Revision: 1231
2008-03-13 14:34:47 +00:00
Badlop c62a0562a1 * src/ejabberd.hrl: Removed unused ejabberd_debug and
PRIVACY_SUPPORT. Reordered the remaining options

SVN Revision: 1230
2008-03-13 14:13:29 +00:00
Badlop ffb1f97cf4 * doc/guide.tex: Describe option Matches in mod_vcard_ldap (thanks
to Evgeniy Khramtsov)(EJAB-530).  Fix typo in the description of
ldap_server option.
* doc/guide.html: Likewise

SVN Revision: 1229
2008-03-13 10:59:57 +00:00
Badlop 17e751521f * src/mod_echo.erl: Small change to avoid a compilation warning of
unused function

SVN Revision: 1228
2008-03-12 23:05:49 +00:00
Badlop 4be522ed0c * src/web/ejabberd_web_admin.erl (term_to_string): Show Erlang
terms in one line in Erlang R12 (EJAB-503)

SVN Revision: 1227
2008-03-12 22:29:53 +00:00
Badlop c4e89879bb * src/ejabberd_s2s_in.erl (get_cert_domains): When compiling with
Erlang R12, replace the calls to deprecated module PKIX1Explicit88
with OTP-PKIX (EJAB-556)

SVN Revision: 1226
2008-03-11 14:25:35 +00:00
Badlop 1643999c35 * src/ejabberd_update.erl: Fix crash when browsing the Update
page in Erlang R12 (EJAB-552)

SVN Revision: 1225
2008-03-10 11:59:53 +00:00
Badlop 5351f56ae1 * src/mod_proxy65/mod_proxy65_service.erl: Implement alternative
to the deprecated function inet:ip_to_bytes (thanks to Evgeniy
Khramtsov)(EJAB-542)

SVN Revision: 1222
2008-03-09 10:09:38 +00:00
Badlop c6f57c13da * doc/guide.tex: Improve documentation of host_config
add (EJAB-544)
* doc/guide.html: Likewise
* src/ejabberd.cfg.example: Likewise
* src/ejabberd_config.erl: Likewise

SVN Revision: 1219
2008-03-04 10:36:57 +00:00
Badlop a6e65dd5a9 * doc/guide.tex: mod_announce recommends, but doesn't require
mod_adhoc (thanks to Anastasia Gornostaeva)
* doc/guide.html: Likewise
* src/ejabberd.cfg.example: Likewise

SVN Revision: 1218
2008-03-04 09:07:43 +00:00
Mickaël Rémond 739a504bd5 * src/ejabberd_check.erl: Fixed missing clause (EJAB-533).
SVN Revision: 1216
2008-02-29 12:23:06 +00:00
Mickaël Rémond 45074f5349 * src/mod_roster.erl: Fixed "from" attribute in roster pushes
* src/mod_roster_odbc.erl: Likewise

SVN Revision: 1214
2008-02-29 07:54:24 +00:00
Badlop 4ee0f6a5ee * src/ejabberd_app.erl (prep_stop): Stop modules when stopping
ejabberd (EJAB-536)
* src/mod_caps.erl (stop): Probably not needed to stop supervisor
child (EJAB-536)
* src/mod_muc/mod_muc.erl (room_destroyed): Catch message
sending (EJAB-536)
* src/mod_muc/mod_muc_room.erl (init): Ensure rooms are called
when the process dies due to a linked die (EJAB-536)

SVN Revision: 1212
2008-02-28 00:30:23 +00:00
Mickaël Rémond 5171a8caec * src/ejabberd_check.erl: Separate config loading from configuration sanity checks (EJAB-533)
* src/src/ejabberd_app.erl: Likewise
* src/ejabberd_app.erl: Likewise

SVN Revision: 1211
2008-02-27 20:20:30 +00:00
Badlop 2e8e970395 * src/msgs/it.msg: Updated (thanks to Smart2128)
SVN Revision: 1209
2008-02-26 08:59:09 +00:00
Badlop 0f16fee833 * doc/release_notes_2.0.0.txt: Small fixes and update date
SVN Revision: 1207
2008-02-21 09:54:19 +00:00
Badlop 4af47f5f78 * README: Updated to match the content of the ejabberd Guide
SVN Revision: 1206
2008-02-20 19:07:19 +00:00
Badlop 01ee6284bf * doc/release_notes_2.0.0.txt: Updated version number and date
SVN Revision: 1205
2008-02-20 16:08:13 +00:00
Badlop 7006402cd7 * src/ejabberd.hrl: Updated version number
* doc/dev.html: Likewise
* doc/features.html: Likewise
* doc/guide.html: Likewise
* doc/version.tex: Likewise

* doc/guide.tex: Mentioned the problems about Windows service
* doc/guide.html: Likewise

SVN Revision: 1203
2008-02-20 16:04:36 +00:00
Badlop c496c9aae6 * src/msgs/ru.msg: Updated (thanks to Konstantin Khomoutov)
* src/msgs/zh.msg: Updated (thanks to Mike Wang and Zhan Caibao)

SVN Revision: 1202
2008-02-20 15:48:48 +00:00
Badlop 07cea7431b * src/msgs/ca.msg: Updated (thanks to Vicent Alberola Canet)
* src/msgs/cs.msg: Updated (thanks to Lukas Polivka)
* src/msgs/de.msg: Updated (thanks to Cord Beermann and Nikolaus
Polak)
* src/msgs/eo.msg: Updated (thanks to Andreas van Cranenburgh)
* src/msgs/es.msg: Updated
* src/msgs/fr.msg: Updated (thanks to Christophe Romain)
* src/msgs/gl.msg: Updated (thanks to Carlos E. Lopez)
* src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh)
* src/msgs/no.msg: Updated (thanks to Stian B. Barmen)
* src/msgs/pt-br.msg: Updated (thanks to Otavio Fernandes)
* src/msgs/uk.msg: Updated (thanks to Stoune and Ruslan Rakhmanin)

SVN Revision: 1201
2008-02-19 19:15:28 +00:00
Christophe Romain c5d3974796 add pgsql driver monitoring
SVN Revision: 1200
2008-02-19 17:06:49 +00:00
Mickaël Rémond 6737a9ff95 * src/ejabberd_config.erl: dirty_get_registered_users now correctly returns all users for all vhosts no matter which back-end is used (EJAB-527)
* src/ejabberd_auth_odbc.erl: Likewise
* src/ejabberd_auth_internal.erl: Likewise
* src/ejabberd_auth.erl: Likewise
* src/ejabberd_auth_external.erl: Likewise
* src/ejabberd_auth_ldap.erl: Likewise

SVN Revision: 1199
2008-02-19 15:19:10 +00:00
Christophe Romain 327b4406db Bug in get_conn_type since SVN r1194 crashes http-bind and http-poll (thanks to Brian Cully) (EJAB-526)
SVN Revision: 1197
2008-02-18 09:55:06 +00:00
Badlop c72082d798 * src/mod_muc/mod_muc_room.erl: Merge SVN r1164, and fix the merge
of SVN r1179 (EJAB-496)

SVN Revision: 1196
2008-02-16 09:18:19 +00:00
Badlop 9a795401ae * doc/release_notes_2.0.0.txt: Describe in the Release Notes the
upgrade instructions (EJAB-522)

SVN Revision: 1195
2008-02-15 19:18:36 +00:00
Christophe Romain fad12caa5f Retreive connection type in sm_register_connection_hook
SVN Revision: 1194
2008-02-15 16:35:32 +00:00
Jérôme Sautret 86445aff3e * odbc_queries: fix list_users queries with limit/offset.
SVN Revision: 1193
2008-02-15 15:39:30 +00:00
Christophe Romain 746c6b7d24 use ejabberd-2.0.0 tag for contribs
SVN Revision: 1192
2008-02-14 22:50:42 +00:00
Badlop 28ca665ba4 * src/mod_muc/mod_muc_room.erl: Allow unmoderated rooms (EJAB-437)
* src/msgs/*: Recover old translations to several languages from
ejabberd 1.1.4

SVN Revision: 1191
2008-02-14 11:25:39 +00:00
Badlop 206d127af7 * src/web/ejabberd_web_admin.erl: Fixed native support for all the
ACL types (EJAB-253)

SVN Revision: 1186
2008-02-12 01:16:11 +00:00
Badlop 60e1972f61 * src/acl.erl: Normalize ACL before adding to the configuration
tables (EJAB-521)

SVN Revision: 1185
2008-02-12 01:04:47 +00:00
Christophe Romain 7d73151737 use if event instead of x when xmlns is pubsub#event (EJAB-518)
SVN Revision: 1181
2008-02-11 15:21:24 +00:00
Badlop a90606b104 * src/mod_muc/mod_muc_room.erl: Include the error condition in the
presence status when kicking a participant due to an error
stanza (EJAB-496)

SVN Revision: 1179
2008-02-09 10:38:47 +00:00
Badlop 0a6a45bf09 * src/ejabberd.cfg.example: Document options to SQL keep alive
interval and pool size (EJAB-206)
* doc/guide.tex: Likewise
* doc/guide.html: Likewise

SVN Revision: 1178
2008-02-08 18:28:36 +00:00
Mickaël Rémond 1b6a2b3660 * src/mod_pubsub/node_buddy.erl: Fixed typo
* src/mod_pubsub/node_club.erl: Likewise
* src/mod_pubsub/node_dispatch.erl: Likewise
* src/mod_pubsub/node_pep.erl: Likewise
* src/mod_pubsub/node_private.erl: Likewise
* src/mod_pubsub/node_public.erl: Likewise
* src/mod_pubsub/node.template: Likewise

SVN Revision: 1176
2008-02-07 08:05:59 +00:00
Mickaël Rémond 7ca44abb22 * src/mod_pubsub/nodetree_virtual.erl: Fixed error report at startup.
SVN Revision: 1170
2008-02-02 14:27:09 +00:00
Badlop 5e88123ec9 * doc/guide.tex: Removed the option served_hosts in mod_pubsub
because it does not work correctly yet (EJAB-504)
* doc/guide.html: Likewise

SVN Revision: 1167
2008-01-30 17:51:09 +00:00
Badlop ae90a16714 * src/mod_echo.erl: Put in comments the call to the educational
function do_client_version

SVN Revision: 1166
2008-01-30 16:07:59 +00:00
Badlop b29e6ef07f * src/mod_muc/mod_muc_room.erl: MUC kicks a participant if sends a
private message with type=error (EJAB-496)

SVN Revision: 1163
2008-01-29 14:49:08 +00:00
Badlop fbe26a9186 * doc/introduction.tex: Updated list of languages
* doc/release_notes_2.0.0.txt: Likewise

SVN Revision: 1162
2008-01-25 15:28:30 +00:00
Badlop 374e7ca38b * src/msgs/eo.msg: New Esperanto translation (thanks to Andreas
van Cranenburgh)

* src/msgs/no.msg: New Norwegian translation (thanks to Stian
B. Barmen)

* doc/Makefile: Fixed small problem with contributed_modules.tex

SVN Revision: 1161
2008-01-25 11:54:17 +00:00
Christophe Romain 326fc6d331 pubsub dirty_sync typo fix on node configuration transaction
SVN Revision: 1159
2008-01-25 10:17:59 +00:00
Christophe Romain 48e15804e3 pubsub configuration patch (EJAB-508) and (EJAB-509)
SVN Revision: 1158
2008-01-25 09:24:10 +00:00
Badlop 50f0c3a14b * doc/guide.tex: Updated the names of log files.
* doc/guide.html: Likewise

* src/mod_muc/mod_muc_room.erl: Added log messages for room
destroy

* src/mod_caps.erl: Small beautify of log error messages

SVN Revision: 1156
2008-01-16 10:16:14 +00:00
Badlop 21f9c7e2d2 * doc/guide.tex: Improved the documentation of Binary
installer. Updated the requirements, specifically: Erlang R10B-9
is required as minimum, and R12 is not yet supported. Added
section Upgrading ejabberd. Improved documentation about Erlang
runtime system environment variables and command-line parameters.
* doc/guide.html: Likewise

* doc/release_notes_2.0.0.txt: Updated to RC1
* doc/version.tex: Likewise
* src/ejabberd.hrl: Likewise

* doc/introduction.tex: Updated to 22 languages

* doc/Makefile: Ensure that Bash is used

SVN Revision: 1154
2008-01-15 17:53:40 +00:00
Badlop 8e72271730 * doc/guide.tex: Updated copyright dates to 2008
* src/*: Likewise

SVN Revision: 1153
2008-01-15 17:02:57 +00:00
Badlop 561cf36c81 Merge changesets 1150 and 1151 into branch ejabberd-2.0.x:
* src/Makefile.in: Allow compilation with Erlang R12 (EJAB-446)
(thanks to Sergei Golovan and Maxim Treskin). Erlang R12 version is
not supported and not recommended for production servers.
* src/aclocal.m4: Likewise
* src/configure.ac: Likewise
* src/configure: Likewise
* src/ejabberd_s2s_in.erl: Likewise

Small fixes in trunk/ChangeLog.

SVN Revision: 1152
2008-01-15 16:09:07 +00:00
Badlop 228eb9d333 * src/ejabberdctl.template: Instead of using the Erlang kernel
variable 'inetrc', use the ERL_INETRC environment variable that is
available since Erlang/OTP R10B-5.

SVN Revision: 1149
2008-01-13 22:46:00 +00:00
Christophe Romain 73bca8fbc0 set_subscription fix (EJAB-494)
SVN Revision: 1148
2008-01-12 19:47:19 +00:00
Christophe Romain ac31008ee0 don't ask capabilities to MUC room participants
SVN Revision: 1147
2008-01-11 13:57:29 +00:00
Christophe Romain c49a6e7176 EJAB-491 fix
SVN Revision: 1146
2008-01-11 01:39:35 +00:00
Christophe Romain 09fa4a0ca7 Force PEP parent node to be []
SVN Revision: 1144
2008-01-10 17:38:24 +00:00
Christophe Romain 3225edde24 Send last published PEP event now checks the correct peer caps (EJAB-491)
SVN Revision: 1143
2008-01-10 15:02:54 +00:00
Badlop 5868a9d1a5 * src/mod_muc/mod_muc_room.erl: MUC kicks a participant if sends a
private message with type=error (EJAB-496)

SVN Revision: 1142
2008-01-09 16:01:16 +00:00
Badlop bceea5fc73 Merged changesets 1139 and 1140 from trunk:
* doc/Makefile: fix version.tex generation bug

* src/ejabberdctl.template: Removed the option ERL_FULLSWEEP_AFTER
because it is almost useless regarding ejabberd's performance.
* src/ejabberdctl.cfg.example: Likewise

SVN Revision: 1141
2008-01-08 16:21:02 +00:00
Badlop bde4d2e79b * src/web/ejabberd_web_admin.erl: Uniformize the name of
ejabberd's web admin to: 'Web Admin' (EjAB-472)
* doc/guide.tex: Likewise
* doc/introduction.tex: Likewise

* src/web/ejabberd_web_admin.erl: Uniformize ejabberd name in the
text using the Latex command

SVN Revision: 1138
2008-01-01 18:25:00 +00:00
Badlop b8993d82bd * src/mod_muc/mod_muc_room.erl: Resend 'continue' elements in muc
room invitations (EJAB-490)

SVN Revision: 1136
2008-01-01 17:09:22 +00:00
Badlop ee4f623a71 * src/ejabberdctl.template: Create logs_dir if doesn't exist. New
parameters --config, --ctl-config, --logs, --spool. Crash dump
renamed to erl_crash_DATETIME.dump.

* src/ejabberdctl.template: Backport improvements from binary
installer (EJAB-488): options are simple values; enable Kernel
Poll by default, set SMP to auto, set max ports to 32000, max
processes to 250000.
* src/ejabberdctl.cfg.example: Likewise

* src/ejabberd.inetrc: Renamed ejabberd.inetrc to inetrc
* src/inetrc: Likewise
* src/Makefile.in: Likewise
* doc/guide.tex: Likewise

SVN Revision: 1134
2008-01-01 11:03:17 +00:00
Badlop a2a1c916fa * src/msgs/ca.msg: Updated (thanks to Vicent Alberola Canet)
SVN Revision: 1132
2008-01-01 10:41:34 +00:00
Badlop e1928fc84b * src/ejabberd_s2s_out.erl: Fixed behavior when outgoing_s2s_port
option is not defined (EJAB-487)

SVN Revision: 1130
2007-12-29 15:23:53 +00:00
Badlop 98c4c8fc74 * src/mod_vcard_ldap.erl: Fix some field names (EJAB-483)
SVN Revision: 1128
2007-12-27 16:42:39 +00:00
Badlop dea1a4619d * src/web/ejabberd_web_admin.erl: Translate menu items of webadmin
hooks in each module (EJAB-485)
* src/mod_shared_roster.erl: Likewise

SVN Revision: 1126
2007-12-26 14:56:00 +00:00
Badlop 892cec5651 * src/web/ejabberd_web_admin.erl: max_user_sessions access rule
contains an integer, but webadmin always expects atoms (EJAB-482)

SVN Revision: 1124
2007-12-26 12:29:15 +00:00
Badlop 62b1811ed2 * src/mod_configure.erl: Bugfix, update to match changes in
mod_announce SVN r1099

SVN Revision: 1122
2007-12-25 00:38:04 +00:00
Mickaël Rémond d3d9d2b701 * doc/release_notes_2.0.0.txt: minor fix.
SVN Revision: 1120
2007-12-24 15:14:37 +00:00
Mickaël Rémond 1208455db5 * doc/release_notes_2.0.0.txt: Small fix.
SVN Revision: 1119
2007-12-24 15:01:00 +00:00
Mickaël Rémond 7d8de382c8 * Small fixes in release notes
SVN Revision: 1116
2007-12-24 14:11:18 +00:00
Mickaël Rémond e4e57bcf38 * Branch for 2.0.x developments
SVN Revision: 1114
2007-12-24 14:08:59 +00:00
291 changed files with 27230 additions and 90325 deletions
+6270
View File
File diff suppressed because it is too large Load Diff
+4 -12
View File
@@ -8,20 +8,14 @@ Quickstart guide
To compile ejabberd you need:
- GNU Make
- GCC
- Libexpat 1.95 or higher
- Erlang/OTP R10B-9 or higher. The recommended version is R12B-5.
Support for R13 is experimental.
- libexpat 1.95 or higher
- Erlang/OTP R10B-9 or newer
- OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL
encryption. Optional, highly recommended.
- Zlib 1.2.3 or higher, for Stream Compression support
(XEP-0138). Optional.
- Erlang mysql library. Optional. MySQL authentication/storage.
- Erlang pgsql library. Optional. PostgreSQL authentication/storage.
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
- GNU Iconv 1.8 or higher, for the IRC Transport
(mod_irc). Optional. Not needed on systems with GNU Libc.
- ImageMagicks Convert program. Optional. For CAPTCHA challenges.
- exmpp 0.9.2 or higher. Optional. For import/export XEP-0227 files.
1. Compile and install on *nix systems
@@ -36,11 +30,9 @@ To install ejabberd, run this command with system administrator rights
sudo make install
These commands will:
- Install a startup script: /sbin/ejabberdctl
- Install ejabberd in /var/lib/ejabberd/
- Install the configuration files in /etc/ejabberd/
- Install ejabberd binary, header and runtime files in /lib/ejabberd/
- Install the administration script: /sbin/ejabberdctl
- Install ejabberd documentation in /share/doc/ejabberd/
- Create a spool directory: /var/lib/ejabberd/
- Create a directory for log files: /var/log/ejabberd/
+2 -2
View File
@@ -1,5 +1,5 @@
% List of ejabberd-modules to add for ejabberd packaging (source archive and installer)
%
% HTTP-binding:
%https://svn.process-one.net/ejabberd-modules/http_bind/trunk
%https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk
https://svn.process-one.net/ejabberd-modules/http_bind/trunk
https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk
@@ -20,14 +20,9 @@
start() ->
ets:new(translations, [named_table, public]),
ets:new(translations_obsolete, [named_table, public]),
ets:new(files, [named_table, public]),
ets:new(vars, [named_table, public]),
case init:get_plain_arguments() of
["-srcmsg2po", Dir, File] ->
print_po_header(File),
Status = process(Dir, File, srcmsg2po),
halt(Status);
["-unused", Dir, File] ->
Status = process(Dir, File, unused),
halt(Status);
@@ -55,11 +50,7 @@ process(Dir, File, Used) ->
unused ->
ets:foldl(fun({Key, _}, _) ->
io:format("~p~n", [Key])
end, ok, translations);
srcmsg2po ->
ets:foldl(fun({Key, Trans}, _) ->
print_translation_obsolete(Key, Trans)
end, ok, translations_obsolete);
end, ok, translations);
_ ->
ok
end,
@@ -68,7 +59,7 @@ process(Dir, File, Used) ->
parse_file(Dir, File, Used) ->
ets:delete_all_objects(vars),
case epp:parse_file(File, [Dir, filename:dirname(File) | code:get_path()], []) of
case epp:parse_file(File, [Dir, filename:dirname(File)], []) of
{ok, Forms} ->
lists:foreach(
fun(F) ->
@@ -80,57 +71,49 @@ parse_file(Dir, File, Used) ->
parse_form(Dir, File, Form, Used) ->
case Form of
%%{undefined, Something} ->
%% io:format("Undefined: ~p~n", [Something]);
{call,
_,
{remote, _, {atom, _, translate}, {atom, _, translate}},
[_, {string, Line, Str}]
[_, {string, _, Str}]
} ->
process_string(Dir, File, Line, Str, Used);
process_string(Dir, File, Str, Used);
{call,
_,
{remote, _, {atom, _, translate}, {atom, _, translate}},
[_, {var, _, Name}]
} ->
case ets:lookup(vars, Name) of
[{_Name, Value, Line}] ->
process_string(Dir, File, Line, Value, Used);
[{_Name, Value}] ->
process_string(Dir, File, Value, Used);
_ ->
ok
end;
{match,
_,
{var, _, Name},
{string, Line, Value}
{string, _, Value}
} ->
ets:insert(vars, {Name, Value, Line});
ets:insert(vars, {Name, Value});
L when is_list(L) ->
lists:foreach(
fun(F) ->
parse_form(Dir, File, F, Used)
parse_form(Dir, File, F, Used)
end, L);
T when is_tuple(T) ->
lists:foreach(
fun(F) ->
parse_form(Dir, File, F, Used)
parse_form(Dir, File, F, Used)
end, tuple_to_list(T));
_ ->
ok
end.
process_string(_Dir, _File, _Line, "", _Used) ->
ok;
process_string(_Dir, File, Line, Str, Used) ->
process_string(_Dir, File, Str, Used) ->
case {ets:lookup(translations, Str), Used} of
{[{_Key, _Trans}], unused} ->
ets:delete(translations, Str);
{[{_Key, _Trans}], used} ->
ok;
{[{_Key, Trans}], srcmsg2po} ->
ets:delete(translations_obsolete, Str),
print_translation(File, Line, Str, Trans);
{_, used} ->
case ets:lookup(files, File) of
[{_}] ->
@@ -144,15 +127,6 @@ process_string(_Dir, File, Line, Str, Used) ->
_ -> io:format("{~p, \"\"}.~n", [Str])
end,
ets:insert(translations, {Str, ""});
{_, srcmsg2po} ->
case ets:lookup(files, File) of
[{_}] ->
ok;
_ ->
ets:insert(files, {File})
end,
ets:insert(translations, {Str, ""}),
print_translation(File, Line, Str, "");
_ ->
ok
end.
@@ -166,8 +140,7 @@ load_file(File) ->
"" ->
ok;
_ ->
ets:insert(translations, {Orig, Trans}),
ets:insert(translations_obsolete, {Orig, Trans})
ets:insert(translations, {Orig, Trans})
end
end, Terms);
Err ->
@@ -218,77 +191,3 @@ print_usage() ->
" extract_translations . ./msgs/ru.msg~n"
).
%%%
%%% Gettext
%%%
print_po_header(File) ->
MsgProps = get_msg_header_props(File),
{Language, [LastT | AddT]} = prepare_props(MsgProps),
application:load(ejabberd),
{ok, Version} = application:get_key(ejabberd, vsn),
print_po_header(Version, Language, LastT, AddT).
get_msg_header_props(File) ->
{ok, F} = file:open(File, [read]),
Lines = get_msg_header_props(F, []),
file:close(F),
Lines.
get_msg_header_props(F, Lines) ->
String = io:get_line(F, ""),
case io_lib:fread("% ", String) of
{ok, [], RemString} ->
case io_lib:fread("~s", RemString) of
{ok, [Key], Value} when Value /= "\n" ->
%% The first character in Value is a blankspace:
%% And the last characters are 'slash n'
ValueClean = string:substr(Value, 2, string:len(Value)-2),
get_msg_header_props(F, Lines ++ [{Key, ValueClean}]);
_ ->
get_msg_header_props(F, Lines)
end;
_ ->
Lines
end.
prepare_props(MsgProps) ->
Language = proplists:get_value("Language:", MsgProps),
Authors = proplists:get_all_values("Author:", MsgProps),
{Language, Authors}.
print_po_header(Version, Language, LastTranslator, AdditionalTranslatorsList) ->
AdditionalTranslatorsString = build_additional_translators(AdditionalTranslatorsList),
HeaderString =
"msgid \"\"\n"
"msgstr \"\"\n"
"\"Project-Id-Version: " ++ Version ++ "\\n\"\n"
++ "\"X-Language: " ++ Language ++ "\\n\"\n"
"\"Last-Translator: " ++ LastTranslator ++ "\\n\"\n"
++ AdditionalTranslatorsString ++
"\"MIME-Version: 1.0\\n\"\n"
"\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
"\"Content-Transfer-Encoding: 8bit\\n\"\n",
io:format("~s~n", [HeaderString]).
build_additional_translators(List) ->
lists:foldl(
fun(T, Str) ->
Str ++ "\"X-Additional-Translator: " ++ T ++ "\\n\"\n"
end,
"",
List).
print_translation(File, Line, Str, StrT) ->
{ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""),
{ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""),
io:format("#: ~s:~p~nmsgid \"~s\"~nmsgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]).
print_translation_obsolete(Str, StrT) ->
File = "unknown.erl",
Line = 1,
{ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""),
{ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""),
io:format("#: ~s:~p~n#~~ msgid \"~s\"~n#~~ msgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]).
@@ -3,24 +3,16 @@
# Frontend for ejabberd's extract_translations.erl
# by Badlop
# How to create template files for a new language:
# NEWLANG=zh
# cp msgs/ejabberd.pot msgs/$NEWLANG.po
# echo \{\"\",\"\"\}. > msgs/$NEWLANG.msg
# ../../extract_translations/prepare-translation.sh -updateall
prepare_dirs ()
{
# Where is Erlang binary
ERL=`which erl`
EJA_SRC_DIR=$EJA_DIR/src/
EJA_MSGS_DIR=$EJA_SRC_DIR/msgs/
EJA_DIR=`pwd`/../..
EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/
EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl
EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam
SRC_DIR=$RUN_DIR/src
EXTRACT_ERL=extract_translations.erl
EXTRACT_BEAM=extract_translations.beam
SRC_DIR=$EJA_DIR/src
MSGS_DIR=$SRC_DIR/msgs
if !([[ -n $EJA_DIR ]])
@@ -30,7 +22,9 @@ prepare_dirs ()
if !([[ -x $EXTRACT_BEAM ]])
then
echo -n "Compiling extract_translations.erl: "
sh -c "cd $EXTRACT_DIR; $ERL -compile $EXTRACT_ERL"
echo "ok"
fi
}
@@ -82,14 +76,14 @@ extract_lang ()
extract_lang_all ()
{
cd $MSGS_DIR
for i in $( ls *.msg ) ; do
for i in *.msg; do
extract_lang $i;
done
echo -e "File\tMissing\tLanguage\t\tLast translator"
echo -e "----\t-------\t--------\t\t---------------"
cd $MSGS_DIR
for i in $( ls *.msg ) ; do
for i in *.msg; do
MISSING=`cat $i.translate | grep "\", \"\"}." | wc -l`
LANGUAGE=`grep "Language:" $i.translate | sed 's/% Language: //g'`
LASTAUTH=`grep "Author:" $i.translate | head -n 1 | sed 's/% Author: //g'`
@@ -146,130 +140,6 @@ find_unused_full ()
cd ..
}
extract_lang_srcmsg2po ()
{
LANG=$1
LANG_CODE=$LANG.$PROJECT
MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
PO_PATH=$MSGS_DIR/$LANG_CODE.po
echo $MSGS_PATH
$ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1
sed -e 's/ \[\]$/ \"\"/g;' $PO_PATH.1 > $PO_PATH.2
msguniq --sort-by-file $PO_PATH.2 --output-file=$PO_PATH
rm $PO_PATH.*
}
extract_lang_src2pot ()
{
LANG_CODE=$PROJECT
MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
POT_PATH=$MSGS_DIR/$LANG_CODE.pot
echo -n "" >$MSGS_PATH
echo "% Language: Language Name" >>$MSGS_PATH
echo "% Author: Translator name and contact method" >>$MSGS_PATH
echo "" >>$MSGS_PATH
cd $SRC_DIR
$ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1
sed -e 's/ \[\]$/ \"\"/g;' $POT_PATH.1 > $POT_PATH.2
#msguniq --sort-by-file $POT_PATH.2 $EJA_MSGS_DIR --output-file=$POT_PATH
msguniq --sort-by-file $POT_PATH.2 --output-file=$POT_PATH
rm $POT_PATH.*
rm $MSGS_PATH
# If the project is a specific module, not the main ejabberd
if [[ $PROJECT != ejabberd ]] ; then
# Remove from project.pot the strings that are already present in the general ejabberd
EJABBERD_MSG_FILE=$EJA_MSGS_DIR/es.po # This is just some file with translated strings
POT_PATH_TEMP=$POT_PATH.temp
msgattrib --set-obsolete --only-file=$EJABBERD_MSG_FILE -o $POT_PATH_TEMP $POT_PATH
mv $POT_PATH_TEMP $POT_PATH
fi
}
extract_lang_popot2po ()
{
LANG_CODE=$1
PO_PATH=$MSGS_DIR/$LANG_CODE.po
POT_PATH=$MSGS_DIR/$PROJECT.pot
msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null
mv $PO_PATH.translate $PO_PATH
}
extract_lang_po2msg ()
{
LANG_CODE=$1
PO_PATH=$LANG_CODE.po
MS_PATH=$PO_PATH.ms
MSGID_PATH=$PO_PATH.msgid
MSGSTR_PATH=$PO_PATH.msgstr
MSGS_PATH=$LANG_CODE.msg
cd $MSGS_DIR
# Check PO has correct ~
# Let's convert to C format so we can use msgfmt
PO_TEMP=$LANG_CODE.po.temp
cat $PO_PATH | sed 's/%/perc/g' | sed 's/~/%/g' | sed 's/#:.*/#, c-format/g' >$PO_TEMP
msgfmt $PO_TEMP --check-format
result=$?
rm $PO_TEMP
if [ $result -ne 0 ] ; then
exit 1
fi
msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH
grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH
grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH
paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >$MSGS_PATH
rm $MS_PATH
rm $MSGID_PATH
rm $MSGSTR_PATH
}
extract_lang_updateall ()
{
echo "Generating POT"
extract_lang_src2pot
cd $MSGS_DIR
echo ""
echo -e "File Missing Language Last translator"
echo -e "---- ------- -------- ---------------"
for i in $( ls *.msg ) ; do
LANG_CODE=${i%.msg}
echo -n $LANG_CODE | awk '{printf "%-6s", $1 }'
# Convert old MSG file to PO
PO=$LANG_CODE.po
[ -f $PO ] || extract_lang_srcmsg2po $LANG_CODE
extract_lang_popot2po $LANG_CODE
extract_lang_po2msg $LANG_CODE
MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4 }'`
echo -n " $MISSING"
LANGUAGE=`grep "Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\\\n\"//g' | awk '{printf "%-12s", $1}'`
echo -n " $LANGUAGE"
LASTAUTH=`grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\\\n\"//g'`
echo " $LASTAUTH"
done
echo ""
rm messages.mo
cd ..
}
translation_instructions ()
{
echo ""
@@ -288,76 +158,34 @@ translation_instructions ()
echo " $MSGS_PATH"
}
EJA_DIR=`pwd`/..
RUN_DIR=`pwd`/..
PROJECT=ejabberd
while [ $# -ne 0 ] ; do
PARAM=$1
shift
case $PARAM in
--) break ;;
-project)
PROJECT=$1
shift
;;
-ejadir)
EJA_DIR=$1
shift
;;
-rundir)
RUN_DIR=$1
shift
;;
-lang)
LANGU=$1
prepare_dirs
extract_lang $LANGU
shift
;;
-langall)
prepare_dirs
extract_lang_all
;;
-srcmsg2po)
LANG_CODE=$1
prepare_dirs
extract_lang_srcmsg2po $LANG_CODE
shift
;;
-popot2po)
LANG_CODE=$1
prepare_dirs
extract_lang_popot2po $LANG_CODE
shift
;;
-src2pot)
prepare_dirs
extract_lang_src2pot
;;
-po2msg)
LANG_CODE=$1
prepare_dirs
extract_lang_po2msg $LANG_CODE
shift
;;
-updateall)
prepare_dirs
extract_lang_updateall
;;
*)
case "$1" in
-help)
echo "Options:"
echo " -langall"
echo " -lang LANGUAGE_FILE"
echo " -srcmsg2po LANGUAGE Construct .msg file using source code to PO file"
echo " -src2pot Generate template POT file from source code"
echo " -popot2po LANGUAGE Update PO file with template POT file"
echo " -po2msg LANGUAGE Export PO file to MSG file"
echo " -updateall Generate POT and update all PO"
echo ""
echo "Example:"
echo " ./prepare-translation.sh -lang es.msg"
exit 0
;;
esac
done
-lang)
LANGU=$2
prepare_dirs
extract_lang $LANGU
shift
shift
;;
-langall)
prepare_dirs
extract_lang_all
shift
;;
*)
echo "unknown option: '$1 $2'"
shift
shift
;;
esac
echo ""
echo "End."
+9 -9
View File
@@ -3,9 +3,12 @@
SHELL = /bin/bash
CONTRIBUTED_MODULES = ""
#ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex)
# CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}"
#endif
ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex)
CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}"
endif
ifeq ($(shell ls mod_http_fileserver.tex),mod_http_fileserver.tex)
CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpfileserver}{true}"
endif
all: release pdf html
@@ -13,10 +16,10 @@ all: release pdf html
release:
@echo "Notes for the releaser:"
@echo "* Do not forget to add a link to the release notes in guide.tex"
@echo "* Do not forget to update the version number in src/ejabberd.app!"
@echo "* Do not forget to update the version number in src/ejabberd.hrl!"
@echo "* Do not forget to update the features in introduction.tex (including \new{} and \improved{} tags)."
@echo "Press any key to continue"
##@read foo
@read foo
@echo "% ejabberd version (automatically generated)." > version.tex
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
@@ -29,6 +32,7 @@ pdf: guide.pdf features.pdf
clean:
rm -f *.aux
rm -f *.haux
rm -f *.html
rm -f *.htoc
rm -f *.idx
rm -f *.ilg
@@ -37,10 +41,6 @@ clean:
rm -f *.out
rm -f *.pdf
rm -f *.toc
[ ! -f contributed_modules.tex ] || rm contributed_modules.tex
distclean: clean
rm -f *.html
guide.html: guide.tex
hevea -fix -pedantic guide.tex
-1
View File
@@ -11,7 +11,6 @@ all: docs
clean:
rm -f *.html
rm edoc-info
rm erlang.png
docs:
erl -noshell -run edoc_run application \
+1 -13
View File
@@ -71,22 +71,10 @@ pre, tt, code {
}
pre {
margin:1ex 2ex;
border:1px dashed lightgrey;
background-color:#f9f9f9;
padding:0.5ex;
margin-left: 1em;
}
pre em {
font-style: normal;
font-weight: bold;
}
dt {
margin:0ex 2ex;
font-weight:bold;
}
dd {
margin:0ex 0ex 1ex 4ex;
}
+7 -7
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.2 Developers Guide
<TITLE>Ejabberd 2.0.x Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.2 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.x Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
@@ -84,7 +84,7 @@ Kevin Smith, Current maintainer of the Psi project</I></BLOCKQUOTE><!--TOC secti
</LI><LI CLASS="li-toc"><A HREF="#htoc15">8.2&#XA0;&#XA0;Services</A>
</LI></UL>
</LI></UL><P>Introduction
<A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang/OTP</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
<A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc1">1</A>&#XA0;&#XA0;Key Features</H2><!--SEC END --><P>
<A NAME="keyfeatures"></A>
</P><P><TT>ejabberd</TT> is:
@@ -98,7 +98,7 @@ Comprehensive documentation.
</LI><LI CLASS="li-itemize">Capability to send announce messages.
</LI></UL></LI><LI CLASS="li-itemize">Internationalized: <TT>ejabberd</TT> leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
<UL CLASS="itemize"><LI CLASS="li-itemize">
Translated to 25 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
Translated to 24 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
</LI></UL></LI><LI CLASS="li-itemize">Open Standards: <TT>ejabberd</TT> is the first Open Source Jabber server claiming to fully comply to the XMPP standard.
<UL CLASS="itemize"><LI CLASS="li-itemize">
Fully XMPP compliant.
@@ -146,7 +146,7 @@ Support for virtual hosting.
</LI></UL>
</LI></UL><!--TOC section How it Works-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc3">3</A>&#XA0;&#XA0;How it Works</H2><!--SEC END --><P>
<A NAME="howitworks"></A></P><P>A XMPP domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can
<A NAME="howitworks"></A></P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can
be run on different machines that are connected via a network. They all must
have the ability to connect to port 4369 of all another nodes, and must have
the same magic cookie (see Erlang/OTP documentation, in other words the file
@@ -159,7 +159,7 @@ router;
</LI><LI CLASS="li-itemize">session manager;
</LI><LI CLASS="li-itemize">S2S manager;
</LI></UL><!--TOC subsection Router-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc4">3.1</A>&#XA0;&#XA0;Router</H3><!--SEC END --><P>This module is the main router of XMPP packets on each node. It routes
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc4">3.1</A>&#XA0;&#XA0;Router</H3><!--SEC END --><P>This module is the main router of Jabber packets on each node. It routes
them based on their destinations domains. It has two tables: local and global
routes. First, domain of packet destination searched in local table, and if it
found, then the packet is routed to appropriate process. If no, then it
@@ -173,7 +173,7 @@ session manager, else it is processed depending on it&#X2019;s content.</P><!--T
packet must be sended via presence table. If this resource is connected to
this node, it is routed to C2S process, if it connected via another node, then
the packet is sent to session manager on that node.</P><!--TOC subsection S2S Manager-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc7">3.4</A>&#XA0;&#XA0;S2S Manager</H3><!--SEC END --><P>This module routes packets to other XMPP servers. First, it checks if an
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc7">3.4</A>&#XA0;&#XA0;S2S Manager</H3><!--SEC END --><P>This module routes packets to other Jabber servers. First, it checks if an
open S2S connection from the domain of the packet source to the domain of
packet destination already exists. If it is open on another node, then it
routes the packet to S2S manager on that node, if it is open on this node, then
+3 -4
View File
@@ -26,7 +26,6 @@
\newcommand{\ns}[1]{\texttt{#1}}
\newcommand{\ejabberd}{\texttt{ejabberd}}
\newcommand{\Jabber}{Jabber}
\newcommand{\XMPP}{XMPP}
%% Modules
\newcommand{\module}[1]{\texttt{#1}}
@@ -101,7 +100,7 @@
\label{howitworks}
A \XMPP{} domain is served by one or more \ejabberd{} nodes. These nodes can
A \Jabber{} domain is served by one or more \ejabberd{} nodes. These nodes can
be run on different machines that are connected via a network. They all must
have the ability to connect to port 4369 of all another nodes, and must have
the same magic cookie (see Erlang/OTP documentation, in other words the file
@@ -122,7 +121,7 @@ Each \ejabberd{} node have following modules:
\subsection{Router}
This module is the main router of \XMPP{} packets on each node. It routes
This module is the main router of \Jabber{} packets on each node. It routes
them based on their destinations domains. It has two tables: local and global
routes. First, domain of packet destination searched in local table, and if it
found, then the packet is routed to appropriate process. If no, then it
@@ -148,7 +147,7 @@ the packet is sent to session manager on that node.
\subsection{S2S Manager}
This module routes packets to other \XMPP{} servers. First, it checks if an
This module routes packets to other \Jabber{} servers. First, it checks if an
open S2S connection from the domain of the packet source to the domain of
packet destination already exists. If it is open on another node, then it
routes the packet to S2S manager on that node, if it is open on this node, then
+4 -4
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.2 Feature Sheet
<TITLE>Ejabberd 2.0.x Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.2 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.x Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
@@ -61,7 +61,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
</DIV><BLOCKQUOTE CLASS="quotation"><FONT COLOR="#921700"><I>I can thoroughly recommend ejabberd for ease of setup &#X2013;
Kevin Smith, Current maintainer of the Psi project</I></FONT></BLOCKQUOTE><P>Introduction
<A NAME="intro"></A></P><BLOCKQUOTE CLASS="quotation"><FONT COLOR="#921700"><I>I just tried out ejabberd and was impressed both by ejabberd itself and the language it is written in, Erlang. &#X2014;
Joeri</I></FONT></BLOCKQUOTE><P><TT>ejabberd</TT> is a <B><FONT SIZE=4><FONT COLOR="#001376">free and open source</FONT></FONT></B> instant messaging server written in <A HREF="http://www.erlang.org/">Erlang/OTP</A>.</P><P><TT>ejabberd</TT> is <B><FONT SIZE=4><FONT COLOR="#001376">cross-platform</FONT></FONT></B>, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a <B><FONT SIZE=4><FONT COLOR="#001376">rock-solid and feature rich</FONT></FONT></B> XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be <B><FONT SIZE=4><FONT COLOR="#001376">scalable</FONT></FONT></B> or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
Joeri</I></FONT></BLOCKQUOTE><P><TT>ejabberd</TT> is a <B><FONT SIZE=4><FONT COLOR="#001376">free and open source</FONT></FONT></B> instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is <B><FONT SIZE=4><FONT COLOR="#001376">cross-platform</FONT></FONT></B>, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a <B><FONT SIZE=4><FONT COLOR="#001376">rock-solid and feature rich</FONT></FONT></B> XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be <B><FONT SIZE=4><FONT COLOR="#001376">scalable</FONT></FONT></B> or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc1"></A>Key Features</H2><!--SEC END --><P>
<A NAME="keyfeatures"></A>
</P><BLOCKQUOTE CLASS="quotation"><FONT COLOR="#921700"><I>Erlang seems to be tailor-made for writing stable, robust servers. &#X2014;
@@ -76,7 +76,7 @@ Comprehensive documentation.
</LI><LI CLASS="li-itemize">Capability to send announce messages.
</LI></UL></LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Internationalized:</FONT></FONT></B> <TT>ejabberd</TT> leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
<UL CLASS="itemize"><LI CLASS="li-itemize">
Translated to 25 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
Translated to 24 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
</LI></UL></LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Open Standards:</FONT></FONT></B> <TT>ejabberd</TT> is the first Open Source Jabber server claiming to fully comply to the XMPP standard.
<UL CLASS="itemize"><LI CLASS="li-itemize">
Fully XMPP compliant.
+2 -2
View File
@@ -70,7 +70,7 @@
%% Fancy header
\fancyhf{}
\pagestyle{fancy}
\rhead{\textcolor{ejblue}{The Expandable Jabber/XMPP Daemon.}}
\rhead{\textcolor{ejblue}{The Expandable Jabber Daemon.}}
\renewcommand{\headrule}{{\color{ejblue}%
\hrule width\headwidth height\headrulewidth \vskip-\headrulewidth}}
\lhead{\setlength{\unitlength}{-6mm}
@@ -133,4 +133,4 @@
% "What I find interesting is that *no* XMPP servers truly provide clustering. This includes all the commercial
% servers. The one partial exception appears to be ejabberd, which can cluster certain data such as sessions,
% but not all services such as MUC."
% * try it today: links to migration tutorials
% * try it today: links to migration tutorials
+867 -1591
View File
File diff suppressed because it is too large Load Diff
+748 -1822
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -8,7 +8,7 @@ Joeri}
%ejabberd is a free and open source instant messaging server written in Erlang. ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication (Jabber/XMPP).
\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang/OTP}.
\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang}.
\ejabberd{} is \marking{cross-platform}, distributed, fault-tolerant, and based on open standards to achieve real-time communication.
@@ -68,7 +68,7 @@ Peter Saint-Andr\'e, Executive Director of the Jabber Software Foundation}
\item \marking{Internationalized:} \ejabberd{} leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
\begin{itemize}
\item Translated to 25 languages. %%\improved{}
\item Translated to 24 languages. %%\improved{}
\item Support for \footahref{http://www.ietf.org/rfc/rfc3490.txt}{IDNA}.
\end{itemize}
-35
View File
@@ -1,35 +0,0 @@
Release Notes
ejabberd 2.0.3
14 January 2009
ejabberd 2.0.3 is the third bugfix release for ejabberd 2.0.x branch.
ejabberd 2.0.3 includes several bugfixes and a few improvements.
A complete list of changes can be retrieved from:
http://redir.process-one.net/ejabberd-2.0.3
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
Recent changes include:
- Do not ask certificate for client (c2s)
- Check digest-uri in SASL digest authentication
- Use send timeout to avoid locking on gen_tcp:send
- Fix ejabberd reconnection to database
- HTTP-Bind: handle wrong order of packets
- MUC: Improve traffic regulation management
- PubSub: Several bugfixes and improvements for best coverage of XEP-0060 v1.12
- Shared Roster Groups: push immediately membership changes
- Rotate also sasl.log on "reopen-log" command
- Binary Windows installer: better detect "Error running Post Install Script"
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
END
-44
View File
@@ -1,44 +0,0 @@
Release Notes
ejabberd 2.0.4
ejabberd 2.0.4 is the fourth bugfix release for ejabberd 2.0.x branch.
ejabberd 2.0.4 includes several bugfixes.
A detailed list of changes can be retrieved from:
http://redir.process-one.net/ejabberd-2.0.4
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
- Ensure ID attribute in roster push is unique
- Authentication: Fix Anonymous auth when enabled with broken ODBC
- Authentication: Unquote correctly backslash in DIGEST-MD5 SASL responses
- Authentication: Cancel presence subscriptions on account deletion
- LDAP: Close a connection on tcp_error
- LDAP: Implemented queue for pending queries
- LDAP: On failure of LDAP connection, waiting is done on pending queue
- MUC: Owner of a password protected room must also provide the password
- MUC: Prevent XSS in MUC logs by linkifying only a few known protocols
- Privacy rules: Items are now processed in the specified order
- Privacy rules: Fix to correctly block subscription requests
- Proxy65: If ip option is not defined, take an IP address of a local hostname
- PubSub: Add roster subscription handling; send PEP events to all resources
- PubSub: Allow node creation without configure item
- PubSub: Requesting items on a node which exists, but empty returns an error
- PEP: Fix sending notifications to other domains and s2s
- S2S: Fix problem with encrypted connection to Gtalk and recent Openfire
- S2S: Workaround to get DNS SRV lookup to work on Windows machine
- Shared Roster Groups: Fix to not resend authorization request
- WebAdmin: Fix encryption problem for ejabberd_http after timeout
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
END
-33
View File
@@ -1,33 +0,0 @@
Release Notes
ejabberd 2.0.5
ejabberd 2.0.5 is the fifth bugfix release in ejabberd 2.0.x branch.
ejabberd 2.0.5 includes three bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.0.5
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
- Fix two problems introduced in ejabberd 2.0.4: subscription request
produced many authorization requests with some clients and
transports; and subscription requests were not stored for later
delivery when receiver was offline.
- Fix warning in expat_erl.c about implicit declaration of x_fix_buff
- HTTP-Bind (BOSH): Fix a missing stream:error in the returned
remote-stream-error stanza
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
END
-281
View File
@@ -1,281 +0,0 @@
Release Notes
ejabberd 2.1.0
ejabberd 2.1.0 is a major new version for ejabberd adding many
new features, performance and scalability improvements.
ejabberd 2.1.0 includes many new features, improvements and bug fixes.
A complete list of changes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.0
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
New features and improvements:
* Anti-abuse
- Captcha support (XEP-0158). The example script uses ImageMagick.
- New option: registration_timeout to limit registrations by time
- Use send timeout to avoid locking on gen_tcp:send
- mod_ip_blacklist: client blacklist support by IP
* API
- ejabberd_http provides Host, Port, Headers and Protocol in HTTP requests
- Export function to create MUC room
- New events: s2s_send_packet and s2s_receive_packet
- New event: webadmin_user_parse_query when POST in web admin user page
- Support distributed hooks over the cluster
* Authentification
- Extauth responses: log strange responses and add timeout
* Binary Installer
- Includes exmpp library to support import/export XML files
* Caps
- Remove useless caps tables entries
- mod_caps must handle correctly external contacts with several resources
- Complain if mod_caps disabled and mod_pubsub has PEP plugin enabled
* Clustering and Architecture
* Configuration
- Added option access_max_user_messages for mod_offline
- Added option backlog for ejabberd_listener to increase TCP backlog
- Added option define_macro and use_macro
- Added option include_config_file to include additional configuration files
- Added option max_fsm_queue
- Added option outgoing_s2s_options to define IP address families and timeout
- Added option registration_timeout to ejabberd.cfg.example
- Added option s2s_dns_options to define DNS timeout and retries
- Added option ERL_OPTIONS to ejabberdctl.cfg
- Added option FIREWALL_WINDOW to ejabberdctl.cfg
- Added option EJABBERD_PID_PATH to ejabberdctl.cfg
- Deleted option user_max_messages of mod_offline
- Check certfiles are readable on server start and listener start
- Config file management mix file reading and sanity check
- Include example PAM configuration file: ejabberd.pam
- New ejabberd listener: ejabberd_stun
- Support to bind the same port to multiple interfaces
- New syntax to specify the IP address and IPv6 in listeners
configuration. The old options {ip,{1,2,3,4}} and inet6 are
supported even if they aren't documented.
- New syntax to specify the network protocol: tcp or udp
- Report error at startup if a listener module isn't available
- Only listen in a port when actually ready to serve requests
- In default config, only local accounts can create rooms and PubSub nodes
* Core architecture
- More verbose error reporting for xml:element_to_string
- Deliver messages when first presence is Invisible
- Better log message when config file is not found
- Include original timestamp on delayed presences
* Crypto
- Do not ask certificate for client (c2s)
- SSL code remove from ejabberd in favor of TLS
- Support Zlib compression after STARTTLS encryption
- tls v1 client hello
* Documentation
- Document possible default MUC room options
- Document service_check_from in the Guide
- Document s2s_default_policy and s2s_host in the Guide
- new command and guide instructions to change node name in a Mnesia database
* ejabberd commands
- ejabberd commands: separate command definition and calling interface
- access_commands restricts who can execute what commands and arguments
- ejabberdctl script now displays help and categorization of commands
* HTTP Binding and HTTP Polling
- HTTP-Bind: module optimization and clean-up
- HTTP-Bind: allow configuration of max_inactivity timeout
- HTTP-Poll: turn session timeout into a config file parameter
* Jingle
- STUN server that facilitates the client-to-client negotiation process
* LDAP
- Faster reconnection to LDAP servers
- LDAP filter optimisation: Add ability to filter user in ejabberd and not LDAP
- LDAP differentiates failed auth and unavailable auth service
- Improve LDAP logging
- LDAPS support using TLS.
* Localization
- Use Gettext PO for translators, export to ejabberd MSG
- Support translation files for additional projects
- Most translations are updated to latest code
- New translation to Greek language
* Multi-User Chat (MUC)
- Allow admins to send messages to rooms
- Allow to store room description
- Captcha support in MUC: the admin of a room can configure it to
require participants to fill a captcha to join the room.
- Limit number of characters in Room ID, Name and Description
- Prevent unvoiced occupants from changing nick
- Support Result Set Management (XEP-0059) for listing rooms
- Support for decline of invitation to MUC room
- mod_muc_log options: plaintext format; filename with only room name
* Performance
- Run roster_get_jid_info only if privacy list has subscription or group item
- Significant PubSub performance improvements
* Publish-Subscribe
- Add nodetree filtering/authorization
- Add subscription option support for collection nodes
- Allow Multiple Subscriptions
- Check option of the nodetree instead of checking configuration
- Implement whitelist authorize and roster access model
- Implicit item deletion is not notified when deleting node
- Make PubSub x-data configuration form handles list value
- Make default node name convention XEP-compatible, document usage of hierarchy
- Node names are used verbatim, without separating by slash, unless a
node plugin uses its own separator
- Send authorization update event (XEP-0060, 8.6)
- Support of collection node subscription options
- Support ODBC storage. Experimental, needs more testing.
* Relational databases:
- Added MSSQL 2000 and 2005
- Privacy rules storage in MySQL
- Implement reliable ODBC transaction nesting
* Source Package
- Default installation directories changed. Please see the upgrade notes below.
- Allow more environment variable overrides in ejabberdctl
- ChangeLog is not edited manually anymore; it's generated automatically.
- Install the ejabberd Guide
- Install the ejabberd include files
- New option for the 'configure' script: --enable-user which installs
ejabberd granting permission to manage it to a regular system user;
no need to use root account to.
- Only try to install epam if pam was enabled in configure script
- Spool, config and log dirs: owner writes, group reads, others do nothing.
- Provides an example ejabberd.init file
* S2S
- Option to define s2s outgoing behaviour: IPv4, IPv6 and timeout
- DNS timeout and retries, configurable with s2s_dns_options.
* Shared rosters
- When a member is added/removed to group, send roster upgrade to group members
* Users management
- When account is deleted, cancel presence subscription for all roster items
* XEP Support
- Added XEP-0059 Result Set Management (for listing rooms)
- Added XEP-0082 Date Time
- Added XEP-0085 Chat State Notifications
- Added XEP-0157 Contact Addresses for XMPP Services
- Added XEP-0158 CAPTCHA Forms (in MUC rooms)
- Added STUN server, for XEP-0176: Jingle ICE-UDP Transport Method
- Added XEP-0199 XMPP Ping
- Added XEP-0202 Entity Time
- Added XEP-0203 Delayed Delivery
- Added XEP-0227 Portable Import/Export Format for XMPP-IM Servers
- Added XEP-0237 Roster Versioning
* Web Admin
- Display the connection method of user sessions
- Cross link of ejabberd users in the list of users and rosters
- Improved the browsing menu: don't disappear when browsing a host or node
- Include Last-Modified HTTP header in responses to allow caching
- Make some Input areas multiline: options of listening ports and modules
- Support PUT and DELETE methods in ejabberd_http
- WebAdmin serves Guide and links to related sections
* Web plugins
- mod_http_fileserver: new option directory_indices, and improve logging
Important Notes:
- ejabberd 2.1.0 requires Erlang R10B-9 or higher.
R12B-5 is the recommended version. Support for R13B is experimental.
Upgrading From ejabberd 1.x.x:
- Check the Release Notes of the intermediate versions for additional
information about database or configuration changes.
Upgrading From ejabberd 2.0.x:
- The database schemas have three changes since ejabberd 2.0.x.
Check the database creation SQL files and update your database.
1) New table roster_version to support roster versioning.
2) Six new tables for optional pubsub ODBC storage.
3) Some tables in the MySQL database have a new created_at column.
- As usual, it is recommended to backup the Mnesia spool directory and
your SQL database (if used) before upgrading ejabberd.
- Between ejabberd 2.0.0 and 2.0.5, mod_pubsub used "default" as the
default node plugin. But in 2.1.0 this is renamed to "hometree".
You have to edit your ejabberd config file and replace those names.
If you used ejabberd 2.0.5 or older, the database will be updated
automatically. But if you were using ejabberd from SVN, you must
manually run ejabberdctl with the command: rename_default_nodeplugin.
Running this command on already updated database does nothing.
- The listener options 'ip' and 'inet6' are not documented anymore
but they are supported and you can continue using them.
There is a new syntax to define IP address and IP version.
As usual, check the ejabberd Guide for more information.
- The log file sasl.log is now called erlang.log
- ejabberdctl commands now have _ characters instead of -.
For backwards compatibility, it is still supported -.
- mod_offline has a new option: access_max_user_messages.
The old option user_max_messages is no longer supported.
- If you upgrade from ejabberd trunk SVN, you must execute this:
$ ejabberdctl rename_default_nodeplugin
- Default installation directories changed a bit:
* The Mnesia spool files that were previously stored in
/var/lib/ejabberd/db/NODENAME/*
are now stored in
/var/lib/ejabberd/*
* The directories
/var/lib/ejabberd/ebin
/var/lib/ejabberd/priv
and their content is now installed as
/lib/ejabberd/ebin
/lib/ejabberd/priv
* There is a new directory with Erlang header files:
/lib/ejabberd/include
* There is a new directory for ejabberd documentation,
which includes the Admin Guide and the release notes::
/share/doc/ejabberd
- How to upgrade from previous version to ejabberd 2.1.0:
1. Stop the old instance of ejabberd.
2. Run 'make install' of new ejabberd 2.1.0 to create the new directories.
3. Copy the content of your old directory:
/var/lib/ejabberd/db/NODENAME/
to the new location:
/var/lib/ejabberd/
so you will have the files like this:
/var/lib/ejabberd/acl.DCD ...
4. You can backup the content of those directories and delete them:
/var/lib/ejabberd/ebin
/var/lib/ejabberd/priv
/var/lib/ejabberd/db
5. Now try to start your new ejabberd 2.1.0.
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-47
View File
@@ -1,47 +0,0 @@
Release Notes
ejabberd 2.1.1
ejabberd 2.1.1 is the first bugfix release in ejabberd 2.1.x branch.
ejabberd 2.1.1 includes several important bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.1
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
* Core
- Call ejabberd_router:route/3 instead of sending a message
- Can't connect if starttls_required and zlib are set
- Routes vCard request to the occupant full JID, but should to bare JID
- S2S: fix allow_host/2 on subdomains. added hook s2s_allow_host
* MUC
- Support converting one-to-one chat to MUC
- Add support for serving a Unique Room Name
* Publish Subscribe
- Receive same last published PEP items at reconnect if several resources online
- Typo in mod_pubsub_odbc breaks Service Discovery and more
* Web
- Fix memory and port leak when TLS is enabled in HTTP
- WebAdmin doesn't report correct last activity with postgresql backend
- Option to define custom HTTP headers in mod_http_fileserver
- Show informative webpage when browsing the HTTP-Poll page
* Other
- Change captcha.sh to not depend on bash
- Generate main XML file also when exporting only a vhost
- Fix last newline in ejabberdctl result
- Guide: fix -setcookie, mod_pubsub_odbc host, content_types
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-51
View File
@@ -1,51 +0,0 @@
Release Notes
ejabberd 2.1.2
ejabberd 2.1.2 is the second bugfix release in ejabberd 2.1.x branch.
ejabberd 2.1.2 includes several bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.2
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The major changes are:
* Core
- Close sessions that were half connected
- Fix SASL PLAIN authentication message for RFC4616 compliance
- Fix support for old Erlang/OTP R10 and R11
- Return proper error (not 'conflict') when register is forbidden by ACL
- When ejabberd stops, send stream close to clients
* ejabberdctl
- Check for EGID in ejabberdctl command
- Command to stop ejabberd informing users, with grace period
- If there's a problem in config file, display config lines and stop node
* MUC
- Kick occupants with reason when room is stopped due to MUC shutdown
- Write in room log when a room is created, destroyed, started, stopped
* PubSub and PEP
- Don't call gen_server on internal event (improves performance and scalability)
- Fix duplicate SHIM header in Pubsub message
- Notification messages of Pubsub node config change contained a SHIM header
- SubID SHIM header missing in Pubsub message with multiple
subscriptions on the same node
- PEP: last published item not sent from unavailable users when the
subscription is implicit (XEP-0115)
- pep_mapping not working due to Node type mismatch
* WebAdmin
- If big offline message queue, show only subset on WebAdmin
- Support in user list page of WebAdmin when mod_offline is disabled
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+1 -1
View File
@@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.2}
\newcommand{\version}{2.0.x}
+47 -180
View File
@@ -12,60 +12,43 @@ ERLANG_CFLAGS= @ERLANG_CFLAGS@
EXPAT_LIBS = @EXPAT_LIBS@
ERLANG_LIBS = @ERLANG_LIBS@
ERLC_FLAGS += @ERLANG_SSL39@
ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj
INSTALLUSER=@INSTALLUSER@
# if no user was enabled, don't set privileges or ownership
ifeq ($(INSTALLUSER),)
O_USER=
G_USER=
CHOWN_COMMAND=echo
CHOWN_OUTPUT=/dev/null
INIT_USER=root
else
O_USER=-o $(INSTALLUSER)
G_USER=-g $(INSTALLUSER)
CHOWN_COMMAND=chown
CHOWN_OUTPUT=&1
INIT_USER=$(INSTALLUSER)
endif
EFLAGS += @ERLANG_SSL39@ -pa .
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
ERLC_FLAGS+=+debug_info
endif
ifdef ejabberd_debug
EFLAGS+=-Dejabberd_debug
ERLC_FLAGS+=-Dejabberd_debug
endif
ifeq (@hipe@, true)
EFLAGS+=+native
ERLC_FLAGS+=+native
endif
ifeq (@roster_gateway_workaround@, true)
EFLAGS+=-DROSTER_GATEWAY_WORKAROUND
ERLC_FLAGS+=-DROSTER_GATEWAY_WORKAROUND
endif
ifeq (@full_xml@, true)
EFLAGS+=-DFULL_XML_SUPPORT
ERLC_FLAGS+=-DFULL_XML_SUPPORT
endif
ifeq (@transient_supervisors@, false)
EFLAGS+=-DNO_TRANSIENT_SUPERVISORS
ERLC_FLAGS+=-DNO_TRANSIENT_SUPERVISORS
endif
INSTALL_EPAM=
ifeq (@pam@, pam)
INSTALL_EPAM=install -m 750 $(O_USER) epam $(PBINDIR)
INSTALL_EPAM=install -m 750 epam $(PBINDIR)
endif
prefix = @prefix@
exec_prefix = @exec_prefix@
SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep stun @tls@ @odbc@ @ejabberd_zlib@
SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@
ERLSHLIBS = expat_erl.so
ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl
SOURCES_ALL = $(wildcard *.erl)
@@ -75,54 +58,22 @@ BEAMS = $(SOURCES:.erl=.beam)
DESTDIR =
# /etc/ejabberd/
EJABBERDDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
BEAMDIR = $(EJABBERDDIR)/ebin
SPOOLDIR = $(EJABBERDDIR)/db
PRIVDIR = $(EJABBERDDIR)/priv
SODIR = $(PRIVDIR)/lib
PBINDIR = $(PRIVDIR)/bin
MSGSDIR = $(PRIVDIR)/msgs
LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd
ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
# /sbin/
SBINDIR = $(DESTDIR)@sbindir@
# /lib/ejabberd/
EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
# /share/doc/ejabberd
PACKAGE_TARNAME = @PACKAGE_TARNAME@
datarootdir = @datarootdir@
DOCDIR = $(DESTDIR)@docdir@
# /usr/lib/ejabberd/ebin/
BEAMDIR = $(EJABBERDDIR)/ebin
# /usr/lib/ejabberd/include/
INCLUDEDIR = $(EJABBERDDIR)/include
# /usr/lib/ejabberd/priv/
PRIVDIR = $(EJABBERDDIR)/priv
# /usr/lib/ejabberd/priv/bin
PBINDIR = $(PRIVDIR)/bin
# /usr/lib/ejabberd/priv/lib
SODIR = $(PRIVDIR)/lib
# /usr/lib/ejabberd/priv/msgs
MSGSDIR = $(PRIVDIR)/msgs
# /var/lib/ejabberd/
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
# /var/lib/ejabberd/.erlang.cookie
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
# /var/log/ejabberd/
LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd
ifeq ($(shell uname),Darwin)
DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress
else
# Assume Linux-style dynamic library flags
DYNAMIC_LIB_CFLAGS = -fpic -shared
ifeq ($(shell uname),Darwin)
DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress
endif
ifeq ($(shell uname),SunOs)
DYNAMIC_LIB_CFLAGS = -KPIC -G -z text
endif
all: $(ERLSHLIBS) compile-beam all-recursive
@@ -134,7 +85,7 @@ $(BEAMS): $(ERLBEHAVBEAMS)
all-recursive: $(ERLBEHAVBEAMS)
%.beam: %.erl
@ERLC@ -W $(EFLAGS) $<
@ERLC@ -W $(ERLC_FLAGS) $<
all-recursive install-recursive uninstall-recursive \
@@ -149,135 +100,60 @@ mostlyclean-recursive maintainer-clean-recursive:
%.hrl: %.asn1
@ERLC@ $(ASN_FLAGS) $<
@ERLC@ -W $(EFLAGS) $*.erl
@ERLC@ -W $(ERLC_FLAGS) $*.erl
$(ERLSHLIBS): %.so: %.c
$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) \
$(subst ../,,$(subst .so,.c,$@)) \
$(EXPAT_LIBS) \
$(EXPAT_CFLAGS) \
$(ERLANG_LIBS) \
$(ERLANG_CFLAGS) \
-o $@ \
$(DYNAMIC_LIB_CFLAGS)
translations:
../contrib/extract_translations/prepare-translation.sh -updateall
$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) \
$(subst ../,,$(subst .so,.c,$@)) \
$(EXPAT_LIBS) $(EXPAT_CFLAGS) \
$(ERLANG_LIBS) $(ERLANG_CFLAGS) \
-o $@ $(DYNAMIC_LIB_CFLAGS)
install: all
#
# Configuration files
install -d -m 750 $(G_USER) $(ETCDIR)
[ -f $(ETCDIR)/ejabberd.cfg ] \
&& install -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \
|| install -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
sed -e "s*@rootdir@*@prefix@*" \
-e "s*@installuser@*@INSTALLUSER@*" \
-e "s*@LIBDIR@*@libdir@*" \
-e "s*@SYSCONFDIR@*@sysconfdir@*" \
-e "s*@LOCALSTATEDIR@*@localstatedir@*" \
-e "s*@DOCDIR@*@docdir@*" \
-e "s*@erl@*@ERL@*" ejabberdctl.template \
> ejabberdctl.example
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
&& install -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
|| install -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
install -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
#
# Administration script
[ -d $(SBINDIR) ] || install -d -m 755 $(SBINDIR)
install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
#
# Init script
sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
> ejabberd.init
#
# Binary Erlang files
install -d $(BEAMDIR)
install -m 644 *.app $(BEAMDIR)
install -m 644 *.beam $(BEAMDIR)
rm -f $(BEAMDIR)/configure.beam
#
# ejabberd header files
install -d $(INCLUDEDIR)
install -m 644 *.hrl $(INCLUDEDIR)
install -d $(INCLUDEDIR)/eldap/
install -m 644 eldap/*.hrl $(INCLUDEDIR)/eldap/
install -d $(INCLUDEDIR)/mod_muc/
install -m 644 mod_muc/*.hrl $(INCLUDEDIR)/mod_muc/
install -d $(INCLUDEDIR)/mod_proxy65/
install -m 644 mod_proxy65/*.hrl $(INCLUDEDIR)/mod_proxy65/
install -d $(INCLUDEDIR)/mod_pubsub/
install -m 644 mod_pubsub/*.hrl $(INCLUDEDIR)/mod_pubsub/
install -d $(INCLUDEDIR)/web/
install -m 644 web/*.hrl $(INCLUDEDIR)/web/
#
# Binary C programs
install -d $(PBINDIR)
install -m 750 $(O_USER) ../tools/captcha.sh $(PBINDIR)
$(INSTALL_EPAM)
#
# Binary system libraries
install -m 644 *.app $(BEAMDIR)
install -d -m 750 $(SPOOLDIR)
install -d $(SODIR)
install -d $(PBINDIR)
install -m 644 *.so $(SODIR)
#
# Translated strings
$(INSTALL_EPAM)
install -d $(MSGSDIR)
install -m 644 msgs/*.msg $(MSGSDIR)
#
# Spool directory
install -d -m 750 $(O_USER) $(SPOOLDIR)
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(SPOOLDIR)
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
#
# Log directory
install -d -m 750 $(O_USER) $(LOGDIR)
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(LOGDIR)
#
# Documentation
install -d $(DOCDIR)
install ../doc/guide.html $(DOCDIR)
install ../doc/*.png $(DOCDIR)
install ../doc/*.txt $(DOCDIR)
install -d -m 750 $(ETCDIR)
[ -f $(ETCDIR)/ejabberd.cfg ] && install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new || install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
sed -e "s*@rootdir@*@prefix@*" -e "s*@erl@*@ERL@*" ejabberdctl.template > ejabberdctl.example
[ -f $(ETCDIR)/ejabberdctl.cfg ] && install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new || install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
install -b -m 644 inetrc $(ETCDIR)/inetrc
install -d $(SBINDIR)
install -m 755 ejabberdctl.example $(SBINDIR)/ejabberdctl
install -d -m 750 $(LOGDIR)
uninstall: uninstall-binary
uninstall-binary:
rm -f $(SBINDIR)/ejabberdctl
rm -fr $(DOCDIR)
rm -f $(BEAMDIR)/*.beam
rm -f $(BEAMDIR)/*.app
rm -fr $(BEAMDIR)
rm -f $(INCLUDEDIR)/*.hrl
rm -fr $(INCLUDEDIR)
rm -fr $(PBINDIR)
rm -f $(SODIR)/*.so
rm -fr $(SODIR)
rm -f $(MSGSDIR)/*.msgs
rm -fr $(MSGSDIR)
rm -fr $(PRIVDIR)
rm -fr $(EJABBERDDIR)
rm -rf $(BEAMDIR)
rm -rf $(SODIR)
rm -rf $(MSGSDIR)
rm -rf $(PRIVDIR)
rm -rf $(SBINDIR)/ejabberdctl
uninstall-all: uninstall-binary
rm -rf $(ETCDIR)
rm -rf $(EJABBERDDIR)
rm -rf $(SPOOLDIR)
rm -rf $(LOGDIR)
rm -rf $(EJABBERDDIR)
clean: clean-recursive clean-local
clean-local:
rm -f *.beam $(ERLSHLIBS) epam ejabberdctl.example
rm -f *.beam $(ERLSHLIBS) epam
rm -f XmppAddr.asn1db XmppAddr.erl XmppAddr.hrl
distclean: distclean-recursive clean-local
rm -f config.status
rm -f config.log
rm -f Makefile
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
TAGS:
etags *.erl
@@ -286,12 +162,3 @@ Makefile: Makefile.in
dialyzer: $(BEAMS)
@dialyzer -c .
LASTSVNREVCHANGELOG = 2075
changelog:
svn up -r $(LASTSVNREVCHANGELOG) ../ChangeLog
mv ../ChangeLog ../ChangeLog.old
svn2cl -r BASE:$(LASTSVNREVCHANGELOG) -o ../ChangeLog --group-by-day \
--separate-daylogs --break-before-msg --reparagraph ..
cat ../ChangeLog.old >> ../ChangeLog
rm ../ChangeLog.old
+2 -8
View File
@@ -66,9 +66,6 @@ release : build release_clean
copy stringprep\*.erl $(SRC_DIR)\stringprep
copy stringprep\*.c $(SRC_DIR)\stringprep
copy stringprep\*.tcl $(SRC_DIR)\stringprep
mkdir $(SRC_DIR)\stun
copy stun\*.erl $(SRC_DIR)\stun
copy stun\*.hrl $(SRC_DIR)\stun
mkdir $(SRC_DIR)\tls
copy tls\*.erl $(SRC_DIR)\tls
copy tls\*.c $(SRC_DIR)\tls
@@ -104,8 +101,6 @@ all-recursive :
nmake -nologo -f Makefile.win32
cd ..\stringprep
nmake -nologo -f Makefile.win32
cd ..\stun
nmake -nologo -f Makefile.win32
cd ..\tls
nmake -nologo -f Makefile.win32
cd ..\ejabberd_zlib
@@ -147,8 +142,6 @@ clean-recursive :
nmake -nologo -f Makefile.win32 clean
cd ..\stringprep
nmake -nologo -f Makefile.win32 clean
cd ..\stun
nmake -nologo -f Makefile.win32 clean
cd ..\tls
nmake -nologo -f Makefile.win32 clean
cd ..\ejabberd_zlib
@@ -173,4 +166,5 @@ $(DLL) : $(OBJECT)
$(LD) $(LD_FLAGS) -out:$(DLL) $(OBJECT)
$(OBJECT) : $(SOURCE)
$(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE)
$(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE)
+3 -13
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -158,7 +158,7 @@ match_acl(ACL, JID, Host) ->
all -> true;
none -> false;
_ ->
{User, Server, Resource} = jlib:jid_tolower(JID),
{User, Server, _Resource} = jlib:jid_tolower(JID),
lists:any(fun(#acl{aclspec = Spec}) ->
case Spec of
all ->
@@ -173,24 +173,16 @@ match_acl(ACL, JID, Host) ->
(U == User) andalso (S == Server);
{server, S} ->
S == Server;
{resource, R} ->
R == Resource;
{user_regexp, UR} ->
((Host == Server) orelse
((Host == global) andalso
lists:member(Server, ?MYHOSTS)))
andalso is_regexp_match(User, UR);
{shared_group, G} ->
mod_shared_roster:is_user_in_group({User, Server}, G, Host);
{shared_group, G, H} ->
mod_shared_roster:is_user_in_group({User, Server}, G, H);
{user_regexp, UR, S} ->
(S == Server) andalso
is_regexp_match(User, UR);
{server_regexp, SR} ->
is_regexp_match(Server, SR);
{resource_regexp, RR} ->
is_regexp_match(Resource, RR);
{node_regexp, UR, SR} ->
is_regexp_match(Server, SR) andalso
is_regexp_match(User, UR);
@@ -205,8 +197,6 @@ match_acl(ACL, JID, Host) ->
is_glob_match(User, UR);
{server_glob, SR} ->
is_glob_match(Server, SR);
{resource_glob, RR} ->
is_glob_match(Resource, RR);
{node_glob, UR, SR} ->
is_glob_match(Server, SR) andalso
is_glob_match(User, UR);
+7 -10
View File
@@ -15,7 +15,7 @@ AC_DEFUN(AM_WITH_EXPAT,
[ expat_found=no ],
"$EXPAT_LIBS")
if test $expat_found = no; then
AC_MSG_ERROR([Could not find development files of Expat library])
AC_MSG_ERROR([Could not find the Expat library])
fi
expat_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
@@ -36,7 +36,6 @@ AC_DEFUN(AM_WITH_ZLIB,
[ AC_ARG_WITH(zlib,
[AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
if test x"$ejabberd_zlib" != x; then
ZLIB_CFLAGS=
ZLIB_LIBS=
if test x"$with_zlib" != x; then
@@ -50,7 +49,7 @@ if test x"$ejabberd_zlib" != x; then
[ zlib_found=no ],
"$ZLIB_LIBS")
if test $zlib_found = no; then
AC_MSG_ERROR([Could not find development files of zlib library. Install them or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
AC_MSG_ERROR([Could not find the zlib library])
fi
zlib_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $ZLIB_CFLAGS"
@@ -58,20 +57,19 @@ if test x"$ejabberd_zlib" != x; then
CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
if test $zlib_found = no; then
AC_MSG_ERROR([Could not find zlib.h. Install it or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
AC_MSG_ERROR([Could not find zlib.h])
fi
CFLAGS="$zlib_save_CFLAGS"
CPPFLAGS="$zlib_save_CPPFLAGS"
AC_SUBST(ZLIB_CFLAGS)
AC_SUBST(ZLIB_LIBS)
fi
])
AC_DEFUN(AM_WITH_PAM,
[ AC_ARG_WITH(pam,
[AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])])
if test x"$pam" != x; then
PAM_CFLAGS=
PAM_LIBS=
if test x"$with_pam" != x; then
@@ -85,7 +83,7 @@ if test x"$pam" != x; then
[ pam_found=no ],
"$PAM_LIBS")
if test $pam_found = no; then
AC_MSG_ERROR([Could not find development files of PAM library. Install them or disable `pam' with: --disable-pam])
AC_MSG_WARN([Could not find the PAM library])
fi
pam_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PAM_CFLAGS"
@@ -93,14 +91,13 @@ if test x"$pam" != x; then
CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
AC_CHECK_HEADERS(security/pam_appl.h, , pam_found=no)
if test $pam_found = no; then
AC_MSG_ERROR([Could not find security/pam_appl.h. Install it or disable `pam' with: --disable-pam])
AC_MSG_WARN([Could not find security/pam_appl.h])
fi
CFLAGS="$pam_save_CFLAGS"
CPPFLAGS="$pam_save_CPPFLAGS"
AC_SUBST(PAM_CFLAGS)
AC_SUBST(PAM_LIBS)
fi
])
AC_DEFUN(AM_WITH_ERLANG,
@@ -340,7 +337,7 @@ if test x"$tls" != x; then
fi
done
if test x${have_openssl} != xyes; then
AC_MSG_ERROR([Could not find development files of OpenSSL library. Install them or disable `tls' with: --disable-tls])
AC_MSG_ERROR([openssl library cannot be found. Install openssl or disable `tls' module (--disable-tls).])
fi
AC_SUBST(SSL_LIBS)
AC_SUBST(SSL_CFLAGS)
+6 -7
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -44,11 +44,10 @@ parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}
Action = xml:get_tag_attr_s("action", SubEl),
XData = find_xdata_el(SubEl),
{xmlelement, _, _, AllEls} = SubEl,
Others = case XData of
false ->
AllEls;
_ ->
lists:delete(XData, AllEls)
if XData ->
Others = lists:delete(XData, AllEls);
true ->
Others = AllEls
end,
#adhoc_request{lang = Lang,
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -11,7 +11,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-1533
View File
File diff suppressed because it is too large Load Diff
-1693
View File
File diff suppressed because it is too large Load Diff
+3392 -2684
View File
File diff suppressed because it is too large Load Diff
+10 -54
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.53)
AC_INIT(ejabberd.erl, version, [ejabberd@process-one.net], [ejabberd])
AC_INIT(ejabberd.erl,, ejabberd@process-one.net)
# Checks for programs.
AC_PROG_CC
@@ -18,6 +18,10 @@ AM_WITH_ERLANG
AM_ICONV
#locating libexpat
AM_WITH_EXPAT
#locating zlib
AM_WITH_ZLIB
#locating PAM
AM_WITH_PAM
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -32,22 +36,16 @@ AC_PREFIX_DEFAULT(/)
AC_FUNC_MALLOC
AC_HEADER_STDC
AC_MOD_ENABLE(mod_pubsub, yes)
AC_MOD_ENABLE(mod_irc, yes)
AC_MOD_ENABLE(mod_muc, yes)
AC_MOD_ENABLE(mod_proxy65, yes)
AC_MOD_ENABLE(mod_pubsub, yes)
AC_MOD_ENABLE(eldap, yes)
AC_MOD_ENABLE(odbc, no)
AC_MOD_ENABLE(tls, yes)
AC_MOD_ENABLE(web, yes)
AC_MOD_ENABLE(ejabberd_zlib, yes)
#locating zlib
AM_WITH_ZLIB
AC_MOD_ENABLE(pam, no)
#locating PAM
AM_WITH_PAM
AC_MOD_ENABLE(web, yes)
AC_MOD_ENABLE(tls, yes)
AC_MOD_ENABLE(odbc, no)
AC_MOD_ENABLE(ejabberd_zlib, yes)
AC_ARG_ENABLE(hipe,
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
@@ -103,7 +101,6 @@ AC_CONFIG_FILES([Makefile
$make_pam
$make_web
stringprep/Makefile
stun/Makefile
$make_tls
$make_odbc
$make_ejabberd_zlib])
@@ -125,45 +122,4 @@ else
fi
AC_CHECK_HEADER(krb5.h,,)
ENABLEUSER=""
AC_ARG_ENABLE(user,
[AS_HELP_STRING([--enable-user[[[[=USER]]]]], [allow this system user to start ejabberd (default: no)])],
[case "${enableval}" in
yes) ENABLEUSER=`whoami` ;;
no) ENABLEUSER="" ;;
*) ENABLEUSER=$enableval
esac],
[])
if test "$ENABLEUSER" != ""; then
echo "allow this system user to start ejabberd: $ENABLEUSER"
AC_SUBST([INSTALLUSER], [$ENABLEUSER])
fi
AC_CANONICAL_SYSTEM
#AC_DEFINE_UNQUOTED(CPU_VENDOR_OS, "$target")
#AC_SUBST(target_os)
case "$target_os" in
*darwin10*)
echo "Target OS is 'Darwin10'"
AC_LANG(Erlang)
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([],[dnl
halt(case erlang:system_info(wordsize) of
8 -> 0; 4 -> 1 end)])],
[AC_MSG_NOTICE(found 64-bit Erlang)
CBIT=-m64],
[AC_MSG_NOTICE(found 32-bit Erlang)
CBIT=-m32])
;;
*)
echo "Target OS is '$target_os'"
CBIT=""
;;
esac
CFLAGS="$CFLAGS $CBIT"
LD_SHARED="$LD_SHARED $CBIT"
echo "CBIT is set to '$CBIT'"
AC_OUTPUT
+8 -6
View File
@@ -1,11 +1,11 @@
%%%----------------------------------------------------------------------
%%% File : configure.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose :
%%% Purpose :
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -58,7 +58,7 @@ start() ->
end,
EVersion = "ERLANG_VERSION = " ++ erlang:system_info(version) ++ "\n",
EIDirS = "EI_DIR = " ++ code:lib_dir(erl_interface) ++ "\n",
EIDirS = "EI_DIR = " ++ code:lib_dir("erl_interface") ++ "\n",
RootDirS = "ERLANG_DIR = " ++ code:root_dir() ++ "\n",
%% Load the ejabberd application description so that ?VERSION can read the vsn key
application:load(ejabberd),
@@ -67,8 +67,8 @@ start() ->
OpenSSLDir = "OPENSSL_DIR = c:\\sdk\\OpenSSL\n",
DBType = "DBTYPE = generic\n", %% 'generic' or 'mssql'
SSLDir = "SSLDIR = " ++ code:lib_dir(ssl) ++ "\n",
StdLibDir = "STDLIBDIR = " ++ code:lib_dir(stdlib) ++ "\n",
SSLDir = "SSLDIR = " ++ code:lib_dir("ssl") ++ "\n",
StdLibDir = "STDLIBDIR = " ++ code:lib_dir("stdlib") ++ "\n",
file:write_file("Makefile.inc",
list_to_binary(EVersion ++
@@ -87,3 +87,5 @@ start() ->
ZlibDir ++
ZlibLib)),
halt().
+8 -10
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -30,19 +30,19 @@
-export([start/0,
register_mechanism/3,
listmech/1,
server_new/7,
server_new/6,
server_start/3,
server_step/2]).
-record(sasl_mechanism, {mechanism, module, require_plain_password}).
-record(sasl_state, {service, myname, realm,
get_password, check_password, check_password_digest,
get_password, check_password,
mech_mod, mech_state}).
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
[{mech_new, 4}, {mech_step, 2}];
[{mech_new, 3}, {mech_step, 2}];
behaviour_info(_Other) ->
undefined.
@@ -113,13 +113,12 @@ listmech(Host) ->
filter_anonymous(Host, Mechs).
server_new(Service, ServerFQDN, UserRealm, _SecFlags,
GetPassword, CheckPassword, CheckPasswordDigest) ->
GetPassword, CheckPassword) ->
#sasl_state{service = Service,
myname = ServerFQDN,
realm = UserRealm,
get_password = GetPassword,
check_password = CheckPassword,
check_password_digest= CheckPasswordDigest}.
check_password = CheckPassword}.
server_start(State, Mech, ClientIn) ->
case lists:member(Mech, listmech(State#sasl_state.myname)) of
@@ -129,8 +128,7 @@ server_start(State, Mech, ClientIn) ->
{ok, MechState} = Module:mech_new(
State#sasl_state.myname,
State#sasl_state.get_password,
State#sasl_state.check_password,
State#sasl_state.check_password_digest),
State#sasl_state.check_password),
server_step(State#sasl_state{mech_mod = Module,
mech_state = MechState},
ClientIn);
+4 -4
View File
@@ -6,7 +6,7 @@
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -17,7 +17,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -27,7 +27,7 @@
-module(cyrsasl_anonymous).
-export([start/1, stop/0, mech_new/4, mech_step/2]).
-export([start/1, stop/0, mech_new/3, mech_step/2]).
-behaviour(cyrsasl).
@@ -40,7 +40,7 @@ start(_Opts) ->
stop() ->
ok.
mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
mech_new(Host, _GetPassword, _CheckPassword) ->
{ok, #state{server = Host}}.
mech_step(State, _ClientIn) ->
+27 -77
View File
@@ -3,25 +3,7 @@
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : DIGEST-MD5 SASL mechanism
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%% Id : $Id$
%%%----------------------------------------------------------------------
-module(cyrsasl_digest).
@@ -29,15 +11,14 @@
-export([start/1,
stop/0,
mech_new/4,
mech_new/3,
mech_step/2]).
-include("ejabberd.hrl").
-behaviour(cyrsasl).
-record(state, {step, nonce, username, authzid, get_password, check_password, auth_module,
host}).
-record(state, {step, nonce, username, authzid, get_password, auth_module}).
start(_Opts) ->
cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, true).
@@ -45,12 +26,10 @@ start(_Opts) ->
stop() ->
ok.
mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
mech_new(_Host, GetPassword, _CheckPassword) ->
{ok, #state{step = 1,
nonce = randoms:get_string(),
host = Host,
get_password = GetPassword,
check_password = CheckPasswordDigest}}.
get_password = GetPassword}}.
mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
{continue,
@@ -62,38 +41,27 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
bad ->
{error, "bad-protocol"};
KeyVals ->
DigestURI = xml:get_attr_s("digest-uri", KeyVals),
UserName = xml:get_attr_s("username", KeyVals),
case is_digesturi_valid(DigestURI, State#state.host) of
false ->
?DEBUG("User login not authorized because digest-uri "
"seems invalid: ~p", [DigestURI]),
AuthzId = xml:get_attr_s("authzid", KeyVals),
case (State#state.get_password)(UserName) of
{false, _} ->
{error, "not-authorized", UserName};
true ->
AuthzId = xml:get_attr_s("authzid", KeyVals),
case (State#state.get_password)(UserName) of
{false, _} ->
{error, "not-authorized", UserName};
{Passwd, AuthModule} ->
case (State#state.check_password)(UserName, "",
xml:get_attr_s("response", KeyVals),
fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId,
"AUTHENTICATE") end) of
{true, _} ->
RspAuth = response(KeyVals,
UserName, Passwd,
Nonce, AuthzId, ""),
{continue,
"rspauth=" ++ RspAuth,
State#state{step = 5,
auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
false ->
{error, "not-authorized", UserName};
{false, _} ->
{error, "not-authorized", UserName}
end
{Passwd, AuthModule} ->
Response = response(KeyVals, UserName, Passwd,
Nonce, AuthzId, "AUTHENTICATE"),
case xml:get_attr_s("response", KeyVals) of
Response ->
RspAuth = response(KeyVals,
UserName, Passwd,
Nonce, AuthzId, ""),
{continue,
"rspauth=" ++ RspAuth,
State#state{step = 5,
auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
_ ->
{error, "not-authorized", UserName}
end
end
end;
@@ -107,6 +75,7 @@ mech_step(A, B) ->
?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]),
{error, "bad-protocol"}.
parse(S) ->
parse1(S, "", []).
@@ -123,17 +92,15 @@ parse1([], [], T) ->
parse1([], _S, _T) ->
bad.
parse2([$\" | Cs], Key, Val, Ts) ->
parse2([$" | Cs], Key, Val, Ts) ->
parse3(Cs, Key, Val, Ts);
parse2([C | Cs], Key, Val, Ts) ->
parse4(Cs, Key, [C | Val], Ts);
parse2([], _, _, _) ->
bad.
parse3([$\" | Cs], Key, Val, Ts) ->
parse3([$" | Cs], Key, Val, Ts) ->
parse4(Cs, Key, Val, Ts);
parse3([$\\, C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([], _, _, _) ->
@@ -149,23 +116,6 @@ parse4([], Key, Val, Ts) ->
parse1([], "", [{Key, lists:reverse(Val)} | Ts]).
%% @doc Check if the digest-uri is valid.
%% RFC-2831 allows to provide the IP address in Host,
%% however ejabberd doesn't allow that.
%% If the service (for example jabber.example.org)
%% is provided by several hosts (being one of them server3.example.org),
%% then digest-uri can be like xmpp/server3.example.org/jabber.example.org
%% In that case, ejabberd only checks the service name, not the host.
is_digesturi_valid(DigestURICase, JabberHost) ->
DigestURI = stringprep:tolower(DigestURICase),
case catch string:tokens(DigestURI, "/") of
["xmpp", Host] when Host == JabberHost ->
true;
["xmpp", _Host, ServName] when ServName == JabberHost ->
true;
_ ->
false
end.
+6 -31
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -27,7 +27,7 @@
-module(cyrsasl_plain).
-author('alexey@process-one.net').
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-export([start/1, stop/0, mech_new/3, mech_step/2, parse/1]).
-behaviour(cyrsasl).
@@ -40,11 +40,11 @@ start(_Opts) ->
stop() ->
ok.
mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
mech_new(_Host, _GetPassword, CheckPassword) ->
{ok, #state{check_password = CheckPassword}}.
mech_step(State, ClientIn) ->
case prepare(ClientIn) of
case parse(ClientIn) of
[AuthzId, User, Password] ->
case (State#state.check_password)(User, Password) of
{true, AuthModule} ->
@@ -57,24 +57,6 @@ mech_step(State, ClientIn) ->
{error, "bad-protocol"}
end.
prepare(ClientIn) ->
case parse(ClientIn) of
[[], UserMaybeDomain, Password] ->
case parse_domain(UserMaybeDomain) of
%% <NUL>login@domain<NUL>pwd
[User, _Domain] ->
[UserMaybeDomain, User, Password];
%% <NUL>login<NUL>pwd
[User] ->
["", User, Password]
end;
%% login@domain<NUL>login<NUL>pwd
[AuthzId, User, Password] ->
[AuthzId, User, Password];
_ ->
error
end.
parse(S) ->
parse1(S, "", []).
@@ -89,12 +71,5 @@ parse1([], S, T) ->
lists:reverse([lists:reverse(S) | T]).
parse_domain(S) ->
parse_domain1(S, "", []).
parse_domain1([$@ | Cs], S, T) ->
parse_domain1(Cs, "", [lists:reverse(S) | T]);
parse_domain1([C | Cs], S, T) ->
parse_domain1(Cs, [C | S], T);
parse_domain1([], S, T) ->
lists:reverse([lists:reverse(S) | T]).
-268
View File
@@ -1,268 +0,0 @@
%% Copyright (c) 2007
%% Mats Cronqvist <mats.cronqvist@ericsson.com>
%% Chris Newcombe <chris.newcombe@gmail.com>
%% Jacob Vorreuter <jacob.vorreuter@gmail.com>
%%
%% 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.
%%%-------------------------------------------------------------------
%%% File : dynamic_compile.erl
%%% Description :
%%% Authors : Mats Cronqvist <mats.cronqvist@ericsson.com>
%%% Chris Newcombe <chris.newcombe@gmail.com>
%%% Jacob Vorreuter <jacob.vorreuter@gmail.com>
%%% TODO :
%%% - add support for limit include-file depth (and prevent circular references)
%%% prevent circular macro expansion set FILE correctly when -module() is found
%%% -include_lib support $ENVVAR in include filenames
%%% substitute-stringize (??MACRO)
%%% -undef/-ifdef/-ifndef/-else/-endif
%%% -file(File, Line)
%%%-------------------------------------------------------------------
-module(dynamic_compile).
%% API
-export([from_string/1, from_string/2]).
-import(lists, [reverse/1, keyreplace/4]).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function:
%% Description:
%% Returns a binary that can be used with
%% code:load_binary(Module, ModuleFilenameForInternalRecords, Binary).
%%--------------------------------------------------------------------
from_string(CodeStr) ->
from_string(CodeStr, []).
% takes Options as for compile:forms/2
from_string(CodeStr, CompileFormsOptions) ->
%% Initialise the macro dictionary with the default predefined macros,
%% (adapted from epp.erl:predef_macros/1
Filename = "compiled_from_string",
%%Machine = list_to_atom(erlang:system_info(machine)),
Ms0 = dict:new(),
% Ms1 = dict:store('FILE', {[], "compiled_from_string"}, Ms0),
% Ms2 = dict:store('LINE', {[], 1}, Ms1), % actually we might add special code for this
% Ms3 = dict:store('MODULE', {[], undefined}, Ms2),
% Ms4 = dict:store('MODULE_STRING', {[], undefined}, Ms3),
% Ms5 = dict:store('MACHINE', {[], Machine}, Ms4),
% InitMD = dict:store(Machine, {[], true}, Ms5),
InitMD = Ms0,
%% From the docs for compile:forms:
%% When encountering an -include or -include_dir directive, the compiler searches for header files in the following directories:
%% 1. ".", the current working directory of the file server;
%% 2. the base name of the compiled file;
%% 3. the directories specified using the i option. The directory specified last is searched first.
%% In this case, #2 is meaningless.
IncludeSearchPath = ["." | reverse([Dir || {i, Dir} <- CompileFormsOptions])],
{RevForms, _OutMacroDict} = scan_and_parse(CodeStr, Filename, 1, [], InitMD, IncludeSearchPath),
Forms = reverse(RevForms),
%% note: 'binary' is forced as an implicit option, whether it is provided or not.
case compile:forms(Forms, CompileFormsOptions) of
{ok, ModuleName, CompiledCodeBinary} when is_binary(CompiledCodeBinary) ->
{ModuleName, CompiledCodeBinary};
{ok, ModuleName, CompiledCodeBinary, []} when is_binary(CompiledCodeBinary) -> % empty warnings list
{ModuleName, CompiledCodeBinary};
{ok, _ModuleName, _CompiledCodeBinary, Warnings} ->
throw({?MODULE, warnings, Warnings});
Other ->
throw({?MODULE, compile_forms, Other})
end.
%%====================================================================
%% Internal functions
%%====================================================================
%%% Code from Mats Cronqvist
%%% See http://www.erlang.org/pipermail/erlang-questions/2007-March/025507.html
%%%## 'scan_and_parse'
%%%
%%% basically we call the OTP scanner and parser (erl_scan and
%%% erl_parse) line-by-line, but check each scanned line for (or
%%% definitions of) macros before parsing.
%% returns {ReverseForms, FinalMacroDict}
scan_and_parse([], _CurrFilename, _CurrLine, RevForms, MacroDict, _IncludeSearchPath) ->
{RevForms, MacroDict};
scan_and_parse(RemainingText, CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) ->
case scanner(RemainingText, CurrLine, MacroDict) of
{tokens, NLine, NRemainingText, Toks} ->
{ok, Form} = erl_parse:parse_form(Toks),
scan_and_parse(NRemainingText, CurrFilename, NLine, [Form | RevForms], MacroDict, IncludeSearchPath);
{macro, NLine, NRemainingText, NMacroDict} ->
scan_and_parse(NRemainingText, CurrFilename, NLine, RevForms,NMacroDict, IncludeSearchPath);
{include, NLine, NRemainingText, IncludeFilename} ->
IncludeFileRemainingTextents = read_include_file(IncludeFilename, IncludeSearchPath),
%%io:format("include file ~p contents: ~n~p~nRemainingText = ~p~n", [IncludeFilename,IncludeFileRemainingTextents, RemainingText]),
%% Modify the FILE macro to reflect the filename
%%IncludeMacroDict = dict:store('FILE', {[],IncludeFilename}, MacroDict),
IncludeMacroDict = MacroDict,
%% Process the header file (inc. any nested header files)
{RevIncludeForms, IncludedMacroDict} = scan_and_parse(IncludeFileRemainingTextents, IncludeFilename, 1, [], IncludeMacroDict, IncludeSearchPath),
%io:format("include file results = ~p~n", [R]),
%% Restore the FILE macro in the NEW MacroDict (so we keep any macros defined in the header file)
%%NMacroDict = dict:store('FILE', {[],CurrFilename}, IncludedMacroDict),
NMacroDict = IncludedMacroDict,
%% Continue with the original file
scan_and_parse(NRemainingText, CurrFilename, NLine, RevIncludeForms ++ RevForms, NMacroDict, IncludeSearchPath);
done ->
scan_and_parse([], CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath)
end.
scanner(Text, Line, MacroDict) ->
case erl_scan:tokens([],Text,Line) of
{done, {ok,Toks,NLine}, LeftOverChars} ->
case pre_proc(Toks, MacroDict) of
{tokens, NToks} -> {tokens, NLine, LeftOverChars, NToks};
{macro, NMacroDict} -> {macro, NLine, LeftOverChars, NMacroDict};
{include, Filename} -> {include, NLine, LeftOverChars, Filename}
end;
{more, _Continuation} ->
%% This is supposed to mean "term is not yet complete" (i.e. a '.' has
%% not been reached yet).
%% However, for some bizarre reason we also get this if there is a comment after the final '.' in a file.
%% So we check to see if Text only consists of comments.
case is_only_comments(Text) of
true ->
done;
false ->
throw({incomplete_term, Text, Line})
end
end.
is_only_comments(Text) -> is_only_comments(Text, not_in_comment).
is_only_comments([], _) -> true;
is_only_comments([$ |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$\t |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$\n |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment
is_only_comments([$% |T], not_in_comment) -> is_only_comments(T, in_comment); % found start of a comment
is_only_comments(_, not_in_comment) -> false;
% found any significant char NOT in a comment
is_only_comments([$\n |T], in_comment) -> is_only_comments(T, not_in_comment); % found end of a comment
is_only_comments([_ |T], in_comment) -> is_only_comments(T, in_comment). % skipping over in-comment chars
%%%## 'pre-proc'
%%%
%%% have to implement a subset of the pre-processor, since epp insists
%%% on running on a file.
%%% only handles 2 cases;
%% -define(MACRO, something).
%% -define(MACRO(VAR1,VARN),{stuff,VAR1,more,stuff,VARN,extra,stuff}).
pre_proc([{'-',_},{atom,_,define},{'(',_},{_,_,Name}|DefToks],MacroDict) ->
false = dict:is_key(Name, MacroDict),
case DefToks of
[{',',_} | Macro] ->
{macro, dict:store(Name, {[], macro_body_def(Macro, [])}, MacroDict)};
[{'(',_} | Macro] ->
{macro, dict:store(Name, macro_params_body_def(Macro, []), MacroDict)}
end;
pre_proc([{'-',_}, {atom,_,include}, {'(',_}, {string,_,Filename}, {')',_}, {dot,_}], _MacroDict) ->
{include, Filename};
pre_proc(Toks,MacroDict) ->
{tokens, subst_macros(Toks, MacroDict)}.
macro_params_body_def([{')',_},{',',_} | Toks], RevParams) ->
{reverse(RevParams), macro_body_def(Toks, [])};
macro_params_body_def([{var,_,Param} | Toks], RevParams) ->
macro_params_body_def(Toks, [Param | RevParams]);
macro_params_body_def([{',',_}, {var,_,Param} | Toks], RevParams) ->
macro_params_body_def(Toks, [Param | RevParams]).
macro_body_def([{')',_}, {dot,_}], RevMacroBodyToks) ->
reverse(RevMacroBodyToks);
macro_body_def([Tok|Toks], RevMacroBodyToks) ->
macro_body_def(Toks, [Tok | RevMacroBodyToks]).
subst_macros(Toks, MacroDict) ->
reverse(subst_macros_rev(Toks, MacroDict, [])).
%% returns a reversed list of tokes
subst_macros_rev([{'?',_}, {_,LineNum,'LINE'} | Toks], MacroDict, RevOutToks) ->
%% special-case for ?LINE, to avoid creating a new MacroDict for every line in the source file
subst_macros_rev(Toks, MacroDict, [{integer,LineNum,LineNum}] ++ RevOutToks);
subst_macros_rev([{'?',_}, {_,_,Name}, {'(',_} = Paren | Toks], MacroDict, RevOutToks) ->
case dict:fetch(Name, MacroDict) of
{[], MacroValue} ->
%% This macro does not have any vars, so ignore the fact that the invocation is followed by "(...stuff"
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []),
subst_macros_rev([Paren|Toks], MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks);
ParamsAndBody ->
%% This macro does have vars.
%% Collect all of the passe arguments, in an ordered list
{NToks, Arguments} = subst_macros_get_args(Toks, []),
%% Expand the varibles
ExpandedParamsToks = subst_macros_subst_args_for_vars(ParamsAndBody, Arguments),
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(ExpandedParamsToks, MacroDict, []),
subst_macros_rev(NToks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks)
end;
subst_macros_rev([{'?',_}, {_,_,Name} | Toks], MacroDict, RevOutToks) ->
%% This macro invocation does not have arguments.
%% Therefore the definition should not have parameters
{[], MacroValue} = dict:fetch(Name, MacroDict),
%% Recursively expand any macro calls inside this macro's value
%% TODO: avoid infinite expansion due to circular references (even indirect ones)
RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []),
subst_macros_rev(Toks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks);
subst_macros_rev([Tok|Toks], MacroDict, RevOutToks) ->
subst_macros_rev(Toks, MacroDict, [Tok|RevOutToks]);
subst_macros_rev([], _MacroDict, RevOutToks) -> RevOutToks.
subst_macros_get_args([{')',_} | Toks], RevArgs) ->
{Toks, reverse(RevArgs)};
subst_macros_get_args([{',',_}, {var,_,ArgName} | Toks], RevArgs) ->
subst_macros_get_args(Toks, [ArgName| RevArgs]);
subst_macros_get_args([{var,_,ArgName} | Toks], RevArgs) ->
subst_macros_get_args(Toks, [ArgName | RevArgs]).
subst_macros_subst_args_for_vars({[], BodyToks}, []) ->
BodyToks;
subst_macros_subst_args_for_vars({[Param | Params], BodyToks}, [Arg|Args]) ->
NBodyToks = keyreplace(Param, 3, BodyToks, {var,1,Arg}),
subst_macros_subst_args_for_vars({Params, NBodyToks}, Args).
read_include_file(Filename, IncludeSearchPath) ->
case file:path_open(IncludeSearchPath, Filename, [read, raw, binary]) of
{ok, IoDevice, FullName} ->
{ok, Data} = file:read(IoDevice, filelib:file_size(FullName)),
file:close(IoDevice),
binary_to_list(Data);
{error, Reason} ->
throw({failed_to_read_include_file, Reason, Filename, IncludeSearchPath})
end.
+2 -1
View File
@@ -2,7 +2,7 @@
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "2.1.2"},
{vsn, "2.0.2"},
{modules, [acl,
adhoc,
configure,
@@ -115,6 +115,7 @@
nodetree_virtual,
p1_fsm,
p1_mnesia,
ram_file_io_server,
randoms,
sha,
shaper,
+61 -125
View File
@@ -1,11 +1,10 @@
%%%
%%% ejabberd configuration file
%%%
%%%'
%%% The parameters used in this configuration file are explained in more detail
%%% in the ejabberd Installation and Operation Guide.
%%% Please consult the Guide in case of doubts, it is included in
%%% Please consult the Guide in case of doubts, it is included in
%%% your copy of ejabberd, and is also available online at
%%% http://www.process-one.net/en/ejabberd/docs/
@@ -17,26 +16,26 @@
%%% - Each term ends in a dot, for example:
%%% override_global.
%%%
%%% - A tuple has a fixed definition, its elements are
%%% - A tuple has a fixed definition, its elements are
%%% enclosed in {}, and separated with commas:
%%% {loglevel, 4}.
%%%
%%% - A list can have as many elements as you want,
%%% - A list can have as many elements as you want,
%%% and is enclosed in [], for example:
%%% [http_poll, web_admin, tls]
%%%
%%% - A keyword of ejabberd is a word in lowercase.
%%% - A keyword of ejabberd is a word in lowercase.
%%% The strings are enclosed in "" and can have spaces, dots...
%%% {language, "en"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%%
%%% - This term includes a tuple, a keyword, a list and two strings:
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
%%%
%%%. =======================
%%%' OVERRIDE STORED OPTIONS
%%% =======================
%%% OVERRIDE STORED OPTIONS
%%
%% Override the old values stored in the database.
@@ -58,8 +57,8 @@
%%override_acls.
%%%. =========
%%%' DEBUGGING
%%% =========
%%% DEBUGGING
%%
%% loglevel: Verbosity of log files generated by ejabberd.
@@ -73,15 +72,14 @@
{loglevel, 4}.
%%
%% watchdog_admins: Only useful for developers: if an ejabberd process
%% consumes a lot of memory, send live notifications to these XMPP
%% accounts.
%% watchdog_admins: If an ejabberd process consumes too much memory,
%% send live notifications to those Jabber accounts.
%%
%%{watchdog_admins, ["bob@example.com"]}.
%%%. ================
%%%' SERVED HOSTNAMES
%%% ================
%%% SERVED HOSTNAMES
%%
%% hosts: Domains served by ejabberd.
@@ -91,15 +89,15 @@
{hosts, ["localhost"]}.
%%
%% route_subdomains: Delegate subdomains to other XMPP server.
%% route_subdomains: Delegate subdomains to other Jabber server.
%% For example, if this ejabberd serves example.org and you want
%% to allow communication with a XMPP server called im.example.org.
%% to allow communication with a Jabber server called im.example.org.
%%
%%{route_subdomains, s2s}.
%%%. ===============
%%%' LISTENING PORTS
%%% ===============
%%% LISTENING PORTS
%%
%% listen: Which ports will ejabberd listen, which service handles it
@@ -112,7 +110,7 @@
%%
%% If TLS is compiled and you installed a SSL
%% certificate, put the correct path to the
%% certificate, put the correct path to the
%% file and uncomment this line:
%%
%%{certfile, "/path/to/ssl.pem"}, starttls,
@@ -141,7 +139,7 @@
%% ejabberd_service: Interact with external components (transports...)
%%
%%{8888, ejabberd_service, [
%% {access, all},
%% {access, all},
%% {shaper_rule, fast},
%% {ip, {127, 0, 0, 1}},
%% {hosts, ["icq.example.org", "sms.example.org"],
@@ -149,19 +147,8 @@
%% }
%% ]},
%%
%% ejabberd_stun: Handles STUN Binding requests
%%
%%{{3478, udp}, ejabberd_stun, []},
{5280, ejabberd_http, [
%%{request_handlers,
%% [
%% {["pub", "archive"], mod_http_fileserver}
%% ]},
captcha,
http_bind,
http_poll,
http_poll,
web_admin
]}
@@ -198,22 +185,14 @@
%%{{s2s_host, "goodhost.org"}, allow}.
%%{{s2s_host, "badhost.org"}, deny}.
%%
%% Outgoing S2S options
%%
%% Preferred address families (which to try first) and connect timeout
%% in milliseconds.
%%
%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
%%%. ==============
%%%' AUTHENTICATION
%%% ==============
%%% AUTHENTICATION
%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal.
%% If you want to use a different method,
%% If you want to use a different method,
%% comment this line and enable the correct ones.
%%
{auth_method, internal}.
@@ -243,30 +222,19 @@
%%{auth_method, ldap}.
%%
%% List of LDAP servers:
%%{ldap_servers, ["localhost"]}.
%%
%% Encryption of connection to LDAP servers:
%%{ldap_encrypt, none}.
%%{ldap_encrypt, tls}.
%%
%% Port connect to LDAP servers:
%%{ldap_port, 389}.
%%{ldap_port, 636}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password to LDAP manager:
%%{ldap_password, "******"}.
%%
%% Search base of LDAP directory:
%%{ldap_base, "dc=example,dc=com"}.
%%{ldap_servers, ["localhost"]}.
%%
%% LDAP attribute that holds user ID:
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
%%
%% LDAP filter:
%%{ldap_filter, "(objectClass=shadowAccount)"}.
%% Search base of LDAP directory:
%%{ldap_base, "dc=example,dc=com"}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password to LDAP manager:
%%{ldap_password, "******"}.
%%
%% Anonymous login support:
@@ -283,8 +251,8 @@
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
%%%. ==============
%%%' DATABASE SETUP
%%% ==============
%%% DATABASE SETUP
%% ejabberd uses by default the internal Mnesia database,
%% so you can avoid this section.
@@ -330,8 +298,8 @@
%%{odbc_keepalive_interval, undefined}.
%%%. ===============
%%%' TRAFFIC SHAPERS
%%% ===============
%%% TRAFFIC SHAPERS
%%
%% The "normal" shaper limits traffic speed to 1.000 B/s
@@ -344,11 +312,11 @@
{shaper, fast, {maxrate, 50000}}.
%%%. ====================
%%%' ACCESS CONTROL LISTS
%%% ====================
%%% ACCESS CONTROL LISTS
%%
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
%% The 'admin' ACL grants administrative privileges to Jabber accounts.
%% You can put as many accounts as you want.
%%
%%{acl, admin, {user, "aleksey", "localhost"}}.
@@ -383,15 +351,12 @@
%%}.
%%%. ============
%%%' ACCESS RULES
%%% ============
%%% ACCESS RULES
%% Maximum number of simultaneous sessions allowed for a single user:
{access, max_user_sessions, [{10, all}]}.
%% Maximum number of offline messages that users can have:
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
%% This rule allows access only for local users:
{access, local, [{allow, local}]}.
@@ -415,20 +380,17 @@
%% Admins of this server are also admins of MUC service:
{access, muc_admin, [{allow, admin}]}.
%% Only accounts of the local ejabberd server can create rooms:
{access, muc_create, [{allow, local}]}.
%% All users are allowed to use MUC service:
{access, muc, [{allow, all}]}.
%% Only accounts in the local ejabberd server can create Pubsub nodes:
{access, pubsub_createnode, [{allow, local}]}.
%% Everybody can create pubsub nodes
{access, pubsub_createnode, [{allow, all}]}.
%% In-band registration allows registration of any possible username.
%% To disable in-band registration, replace 'allow' with 'deny'.
{access, register, [{allow, all}]}.
%% By default frequency of account registrations from the same IP
%% By default frequency of account registrations from a the same IP
%% is limited to 1 account every 10 minutes. To disable put: infinity
%%{registration_timeout, 600}.
@@ -443,8 +405,8 @@
%%}.
%%%. ================
%%%' DEFAULT LANGUAGE
%%% ================
%%% DEFAULT LANGUAGE
%%
%% language: Default language used for server messages.
@@ -459,22 +421,8 @@
%%}.
%%%. =======
%%%' CAPTCHA
%%
%% Full path to a script that generates the image.
%%
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
%%
%% Host part of the URL sent to the user.
%%
%%{captcha_host, "example.org:5280"}.
%%%. =======
%%%' MODULES
%%% =======
%%% MODULES
%%
%% Modules enabled in all ejabberd virtual hosts.
@@ -483,48 +431,39 @@
[
{mod_adhoc, []},
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
{mod_caps, []},
{mod_caps, []},
{mod_configure,[]}, % requires mod_adhoc
{mod_disco, []},
%%{mod_echo, [{host, "echo.localhost"}]},
{mod_irc, []},
{mod_http_bind, []},
%%{mod_http_fileserver, [
%% {docroot, "/var/www"},
%% {accesslog, "/var/log/ejabberd/access.log"}
%% ]},
{mod_last, []},
{mod_muc, [
%%{host, "conference.@HOST@"},
{access, muc},
{access_create, muc_create},
{access_persistent, muc_create},
{access_create, muc},
{access_persistent, muc},
{access_admin, muc_admin}
]},
%%{mod_muc_log,[]},
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
{mod_ping, []},
{mod_offline, []},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
{mod_pubsub, [
{mod_pubsub, [ % requires mod_caps
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, % reduce resource comsumption, but XEP incompliant
%%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
{last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]} % pep requires mod_caps
{plugins, ["default", "pep"]}
]},
{mod_register, [
%%
%% After successful registration, the user receives
%% After successful registration, the user receives
%% a message with this subject and body.
%%
{welcome_message, {"Welcome!",
"Hi.\nWelcome to this XMPP server."}},
{welcome_message, {"Welcome!",
"Hi\nWelcome to this Jabber server."}},
%%
%% When a user registers, send a notification to
%% these XMPP accounts.
%% When a user registers, send a notification to
%% these Jabber accounts.
%%
%%{registration_watchers, ["admin1@example.org"]},
@@ -551,12 +490,9 @@
%% ]}.
%%%.
%%%'
%%% $Id$
%%% Local Variables:
%%% mode: erlang
%%% End:
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker:
%%% vim: set filetype=erlang tabstop=8:
+3 -16
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -28,16 +28,14 @@
-author('alexey@process-one.net').
-export([start/0, stop/0,
get_pid_file/0,
get_so_path/0, get_bin_path/0]).
start() ->
%%ejabberd_cover:start(),
application:start(ejabberd).
stop() ->
application:stop(ejabberd).
%%ejabberd_cover:stop().
get_so_path() ->
case os:getenv("EJABBERD_SO_PATH") of
@@ -64,14 +62,3 @@ get_bin_path() ->
Path ->
Path
end.
%% @spec () -> false | string()
get_pid_file() ->
case os:getenv("EJABBERD_PID_PATH") of
false ->
false;
"" ->
false;
Path ->
Path
end.
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -11,7 +11,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-46
View File
@@ -1,46 +0,0 @@
#! /bin/sh
set -o errexit
set -o nounset
DIR=@ctlscriptpath@
CTL="$DIR"/ejabberdctl
USER=@installuser@
test -x "$CTL" || {
echo "ERROR: ejabberd not found: $DIR"
exit 1
}
grep ^"$USER": /etc/passwd >/dev/null || {
echo "ERROR: System user not found: $USER"
exit 2
}
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
case "$1" in
start)
test -x "$CTL" || exit 0
echo "Starting ejabberd..."
su - $USER -c "$CTL start"
su - $USER -c "$CTL started"
echo "done."
;;
stop)
test -x "$CTL" || exit 0
echo "Stopping ejabberd..."
su - $USER -c "$CTL stop"
su - $USER -c "$CTL stopped"
echo "done."
;;
force-reload|restart)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload}"
exit 1
esac
exit 0
+8 -464
View File
@@ -1,11 +1,15 @@
%%%-------------------------------------------------------------------
%%% File : ejabberd_admin.erl
%%% Author : Mickael Remond <mremond@process-one.net>
%%% Purpose : Administrative functions and commands
%%% Description : This module gathers admin functions used by different
%%% access method:
%%% - ejabberdctl command-line tool
%%% - web admin interface
%%% - adhoc mode
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +20,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -27,345 +31,9 @@
-module(ejabberd_admin).
-author('mickael.remond@process-one.net').
-export([start/0, stop/0,
%% Server
status/0, reopen_log/0,
stop_kindly/2, send_service_message_all_mucs/2,
%% Accounts
register/3, unregister/2,
registered_users/1,
%% Migration jabberd1.4
import_file/1, import_dir/1,
%% Purge DB
delete_expired_messages/0, delete_old_messages/1,
%% Mnesia
backup_mnesia/1, restore_mnesia/1,
dump_mnesia/1, dump_table/2, load_mnesia/1,
install_fallback_mnesia/1,
dump_to_textfile/1, dump_to_textfile/2,
mnesia_change_nodename/4,
restore/1 % Still used by some modules
]).
-export([restore/1]).
-include("ejabberd.hrl").
-include("ejabberd_commands.hrl").
start() ->
ejabberd_commands:register_commands(commands()).
stop() ->
ejabberd_commands:unregister_commands(commands()).
%%%
%%% ejabberd commands
%%%
commands() ->
[
%% The commands status, stop and restart are implemented also in ejabberd_ctl
%% They are defined here so that other interfaces can use them too
#ejabberd_commands{name = status, tags = [server],
desc = "Get status of the ejabberd server",
module = ?MODULE, function = status,
args = [], result = {res, restuple}},
#ejabberd_commands{name = stop, tags = [server],
desc = "Stop ejabberd gracefully",
module = init, function = stop,
args = [], result = {res, rescode}},
#ejabberd_commands{name = restart, tags = [server],
desc = "Restart ejabberd gracefully",
module = init, function = restart,
args = [], result = {res, rescode}},
#ejabberd_commands{name = reopen_log, tags = [logs, server],
desc = "Reopen the log files",
module = ?MODULE, function = reopen_log,
args = [], result = {res, rescode}},
#ejabberd_commands{name = stop_kindly, tags = [server],
desc = "Inform users and rooms, wait, and stop the server",
module = ?MODULE, function = stop_kindly,
args = [{delay, integer}, {announcement, string}],
result = {res, rescode}},
#ejabberd_commands{name = get_loglevel, tags = [logs, server],
desc = "Get the current loglevel",
module = ejabberd_loglevel, function = get,
args = [],
result = {leveltuple, {tuple, [{levelnumber, integer},
{levelatom, atom},
{leveldesc, string}
]}}},
#ejabberd_commands{name = register, tags = [accounts],
desc = "Register a user",
module = ?MODULE, function = register,
args = [{user, string}, {host, string}, {password, string}],
result = {res, restuple}},
#ejabberd_commands{name = unregister, tags = [accounts],
desc = "Unregister a user",
module = ?MODULE, function = unregister,
args = [{user, string}, {host, string}],
result = {res, restuple}},
#ejabberd_commands{name = registered_users, tags = [accounts],
desc = "List all registered users in HOST",
module = ?MODULE, function = registered_users,
args = [{host, string}],
result = {users, {list, {username, string}}}},
#ejabberd_commands{name = import_file, tags = [mnesia],
desc = "Import user data from jabberd14 spool file",
module = ?MODULE, function = import_file,
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = import_dir, tags = [mnesia],
desc = "Import users data from jabberd14 spool dir",
module = ?MODULE, function = import_dir,
args = [{file, string}],
result = {res, restuple}},
#ejabberd_commands{name = import_piefxis, tags = [mnesia],
desc = "Import users data from a PIEFXIS file (XEP-0227)",
module = ejabberd_piefxis, function = import_file,
args = [{file, string}], result = {res, rescode}},
#ejabberd_commands{name = export_piefxis, tags = [mnesia],
desc = "Export data of all users in the server to PIEFXIS files (XEP-0227)",
module = ejabberd_piefxis, function = export_server,
args = [{dir, string}], result = {res, rescode}},
#ejabberd_commands{name = export_piefxis_host, tags = [mnesia],
desc = "Export data of users in a host to PIEFXIS files (XEP-0227)",
module = ejabberd_piefxis, function = export_host,
args = [{dir, string}, {host, string}], result = {res, rescode}},
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
desc = "Delete expired offline messages from database",
module = ?MODULE, function = delete_expired_messages,
args = [], result = {res, rescode}},
#ejabberd_commands{name = delete_old_messages, tags = [purge],
desc = "Delete offline messages older than DAYS",
module = ?MODULE, function = delete_old_messages,
args = [{days, integer}], result = {res, rescode}},
#ejabberd_commands{name = rename_default_nodeplugin, tags = [mnesia],
desc = "Update PubSub table from ejabberd trunk SVN to 2.1.0",
module = mod_pubsub, function = rename_default_nodeplugin,
args = [], result = {res, rescode}},
#ejabberd_commands{name = mnesia_change_nodename, tags = [mnesia],
desc = "Change the erlang node name in a backup file",
module = ?MODULE, function = mnesia_change_nodename,
args = [{oldnodename, string}, {newnodename, string},
{oldbackup, string}, {newbackup, string}],
result = {res, restuple}},
#ejabberd_commands{name = backup, tags = [mnesia],
desc = "Store the database to backup file",
module = ?MODULE, function = backup_mnesia,
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = restore, tags = [mnesia],
desc = "Restore the database from backup file",
module = ?MODULE, function = restore_mnesia,
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = dump, tags = [mnesia],
desc = "Dump the database to text file",
module = ?MODULE, function = dump_mnesia,
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = dump_table, tags = [mnesia],
desc = "Dump a table to text file",
module = ?MODULE, function = dump_table,
args = [{file, string}, {table, string}], result = {res, restuple}},
#ejabberd_commands{name = load, tags = [mnesia],
desc = "Restore the database from text file",
module = ?MODULE, function = load_mnesia,
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = install_fallback, tags = [mnesia],
desc = "Install the database from a fallback file",
module = ?MODULE, function = install_fallback_mnesia,
args = [{file, string}], result = {res, restuple}}
].
%%%
%%% Server management
%%%
status() ->
{InternalStatus, ProvidedStatus} = init:get_status(),
String1 = io_lib:format("The node ~p is ~p. Status: ~p",
[node(), InternalStatus, ProvidedStatus]),
{Is_running, String2} =
case lists:keysearch(ejabberd, 1, application:which_applications()) of
false ->
{ejabberd_not_running, "ejabberd is not running in that node."};
{value, {_, _, Version}} ->
{ok, io_lib:format("ejabberd ~s is running in that node", [Version])}
end,
{Is_running, String1 ++ String2}.
reopen_log() ->
ejabberd_hooks:run(reopen_log_hook, []),
%% TODO: Use the Reopen log API for logger_h ?
ejabberd_logger_h:reopen_log(),
case application:get_env(sasl,sasl_error_logger) of
{ok, {file, SASLfile}} ->
error_logger:delete_report_handler(sasl_report_file_h),
ejabberd_logger_h:rotate_log(SASLfile),
error_logger:add_report_handler(sasl_report_file_h,
{SASLfile, get_sasl_error_logger_type()});
_ -> false
end,
ok.
%% Function copied from Erlang/OTP lib/sasl/src/sasl.erl which doesn't export it
get_sasl_error_logger_type () ->
case application:get_env (sasl, errlog_type) of
{ok, error} -> error;
{ok, progress} -> progress;
{ok, all} -> all;
{ok, Bad} -> exit ({bad_config, {sasl, {errlog_type, Bad}}});
_ -> all
end.
%%%
%%% Stop Kindly
%%%
stop_kindly(DelaySeconds, AnnouncementText) ->
Subject = io_lib:format("Server stop in ~p seconds!", [DelaySeconds]),
WaitingDesc = io_lib:format("Waiting ~p seconds", [DelaySeconds]),
Steps = [
{"Stopping ejabberd port listeners",
ejabberd_listener, stop_listeners, []},
{"Sending announcement to connected users",
mod_announce, send_announcement_to_all,
[?MYNAME, Subject, AnnouncementText]},
{"Sending service message to MUC rooms",
ejabberd_admin, send_service_message_all_mucs,
[Subject, AnnouncementText]},
{WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
{"Stopping ejabberd", application, stop, [ejabberd]},
{"Stopping Mnesia", mnesia, stop, []},
{"Stopping Erlang node", init, stop, []}
],
NumberLast = length(Steps),
TimestampStart = calendar:datetime_to_gregorian_seconds({date(), time()}),
lists:foldl(
fun({Desc, Mod, Func, Args}, NumberThis) ->
SecondsDiff =
calendar:datetime_to_gregorian_seconds({date(), time()})
- TimestampStart,
io:format("[~p/~p ~ps] ~s... ",
[NumberThis, NumberLast, SecondsDiff, Desc]),
Result = apply(Mod, Func, Args),
io:format("~p~n", [Result]),
NumberThis+1
end,
1,
Steps),
ok.
send_service_message_all_mucs(Subject, AnnouncementText) ->
Message = io_lib:format("~s~n~s", [Subject, AnnouncementText]),
lists:foreach(
fun(ServerHost) ->
MUCHost = gen_mod:get_module_opt_host(
ServerHost, mod_muc, "conference.@HOST@"),
mod_muc:broadcast_service_message(MUCHost, Message)
end,
?MYHOSTS).
%%%
%%% Account management
%%%
register(User, Host, Password) ->
case ejabberd_auth:try_register(User, Host, Password) of
{atomic, ok} ->
{ok, io_lib:format("User ~s@~s succesfully registered", [User, Host])};
{atomic, exists} ->
String = io_lib:format("User ~s@~s already registered at node ~p",
[User, Host, node()]),
{exists, String};
{error, Reason} ->
String = io_lib:format("Can't register user ~s@~s at node ~p: ~p",
[User, Host, node(), Reason]),
{cannot_register, String}
end.
unregister(User, Host) ->
ejabberd_auth:remove_user(User, Host),
{ok, ""}.
registered_users(Host) ->
Users = ejabberd_auth:get_vh_registered_users(Host),
SUsers = lists:sort(Users),
lists:map(fun({U, _S}) -> U end, SUsers).
%%%
%%% Migration management
%%%
import_file(Path) ->
case jd2ejd:import_file(Path) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't import jabberd14 spool file ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_import_file, String}
end.
import_dir(Path) ->
case jd2ejd:import_dir(Path) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't import jabberd14 spool dir ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_import_dir, String}
end.
%%%
%%% Purge DB
%%%
delete_expired_messages() ->
{atomic, ok} = mod_offline:remove_expired_messages(),
ok.
delete_old_messages(Days) ->
{atomic, _} = mod_offline:remove_old_messages(Days),
ok.
%%%
%%% Mnesia management
%%%
backup_mnesia(Path) ->
case mnesia:backup(Path) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't store backup in ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_backup, String}
end.
restore_mnesia(Path) ->
case ejabberd_admin:restore(Path) of
{atomic, _} ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't restore backup from ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_restore, String};
{aborted,{no_exists,Table}} ->
String = io_lib:format("Can't restore backup from ~p at node ~p: Table ~p does not exist.",
[filename:absname(Path), node(), Table]),
{table_not_exists, String};
{aborted,enoent} ->
String = io_lib:format("Can't restore backup from ~p at node ~p: File not found.",
[filename:absname(Path), node()]),
{file_not_found, String}
end.
%% Mnesia database restore
%% This function is called from ejabberd_ctl, ejabberd_web_admin and
@@ -403,127 +71,3 @@ module_tables(mod_roster) -> [roster];
module_tables(mod_shared_roster) -> [sr_group, sr_user];
module_tables(mod_vcard) -> [vcard, vcard_search];
module_tables(_Other) -> [].
get_local_tables() ->
Tabs1 = lists:delete(schema, mnesia:system_info(local_tables)),
Tabs = lists:filter(
fun(T) ->
case mnesia:table_info(T, storage_type) of
disc_copies -> true;
disc_only_copies -> true;
_ -> false
end
end, Tabs1),
Tabs.
dump_mnesia(Path) ->
Tabs = get_local_tables(),
dump_tables(Path, Tabs).
dump_table(Path, STable) ->
Table = list_to_atom(STable),
dump_tables(Path, [Table]).
dump_tables(Path, Tables) ->
case dump_to_textfile(Path, Tables) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't store dump in ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_dump, String}
end.
dump_to_textfile(File) ->
Tabs = get_local_tables(),
dump_to_textfile(File, Tabs).
dump_to_textfile(File, Tabs) ->
dump_to_textfile(mnesia:system_info(is_running), Tabs, file:open(File, [write])).
dump_to_textfile(yes, Tabs, {ok, F}) ->
Defs = lists:map(
fun(T) -> {T, [{record_name, mnesia:table_info(T, record_name)},
{attributes, mnesia:table_info(T, attributes)}]}
end,
Tabs),
io:format(F, "~p.~n", [{tables, Defs}]),
lists:foreach(fun(T) -> dump_tab(F, T) end, Tabs),
file:close(F);
dump_to_textfile(_, _, {ok, F}) ->
file:close(F),
{error, mnesia_not_running};
dump_to_textfile(_, _, {error, Reason}) ->
{error, Reason}.
dump_tab(F, T) ->
W = mnesia:table_info(T, wild_pattern),
{atomic,All} = mnesia:transaction(
fun() -> mnesia:match_object(T, W, read) end),
lists:foreach(
fun(Term) -> io:format(F,"~p.~n", [setelement(1, Term, T)]) end, All).
load_mnesia(Path) ->
case mnesia:load_textfile(Path) of
{atomic, ok} ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't load dump in ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_load, String}
end.
install_fallback_mnesia(Path) ->
case mnesia:install_fallback(Path) of
ok ->
{ok, ""};
{error, Reason} ->
String = io_lib:format("Can't install fallback from ~p at node ~p: ~p",
[filename:absname(Path), node(), Reason]),
{cannot_fallback, String}
end.
mnesia_change_nodename(FromString, ToString, Source, Target) ->
From = list_to_atom(FromString),
To = list_to_atom(ToString),
Switch =
fun
(Node) when Node == From ->
io:format(" - Replacing nodename: '~p' with: '~p'~n", [From, To]),
To;
(Node) when Node == To ->
%% throw({error, already_exists});
io:format(" - Node: '~p' will not be modified (it is already '~p')~n", [Node, To]),
Node;
(Node) ->
io:format(" - Node: '~p' will not be modified (it is not '~p')~n", [Node, From]),
Node
end,
Convert =
fun
({schema, db_nodes, Nodes}, Acc) ->
io:format(" +++ db_nodes ~p~n", [Nodes]),
{[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc};
({schema, version, Version}, Acc) ->
io:format(" +++ version: ~p~n", [Version]),
{[{schema, version, Version}], Acc};
({schema, cookie, Cookie}, Acc) ->
io:format(" +++ cookie: ~p~n", [Cookie]),
{[{schema, cookie, Cookie}], Acc};
({schema, Tab, CreateList}, Acc) ->
io:format("~n * Checking table: '~p'~n", [Tab]),
Keys = [ram_copies, disc_copies, disc_only_copies],
OptSwitch =
fun({Key, Val}) ->
case lists:member(Key, Keys) of
true ->
io:format(" + Checking key: '~p'~n", [Key]),
{Key, lists:map(Switch, Val)};
false-> {Key, Val}
end
end,
Res = {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc},
Res;
(Other, Acc) ->
{[Other], Acc}
end,
mnesia:traverse_backup(Source, Target, Convert, switched).
+22 -90
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -29,7 +29,7 @@
-behaviour(application).
-export([start_modules/0,start/2, get_log_path/0, prep_stop/1, stop/1, init/0]).
-export([start/2, prep_stop/1, stop/1, init/0]).
-include("ejabberd.hrl").
@@ -40,52 +40,42 @@
start(normal, _Args) ->
ejabberd_loglevel:set(4),
write_pid_file(),
application:start(sasl),
randoms:start(),
db_init(),
sha:start(),
catch ssl:start(),
stringprep_sup:start_link(),
start(),
translate:start(),
acl:start(),
ejabberd_ctl:init(),
ejabberd_commands:init(),
ejabberd_admin:start(),
gen_mod:start(),
ejabberd_config:start(),
ejabberd_check:config(),
start(),
connect_nodes(),
Sup = ejabberd_sup:start_link(),
ejabberd_rdbms:start(),
ejabberd_auth:start(),
cyrsasl:start(),
% Profiling
%ejabberd_debug:eprof_start(),
%ejabberd_debug:fprof_start(),
maybe_add_nameservers(),
%eprof:start(),
%eprof:profile([self()]),
%fprof:trace(start, "/tmp/fprof"),
start_modules(),
ejabberd_listener:start_listeners(),
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
Sup;
start(_, _) ->
{error, badarg}.
%% Prepare the application for termination.
%% This function is called when an application is about to be stopped,
%% This function is called when an application is about to be stopped,
%% before shutting down the processes of the application.
prep_stop(State) ->
stop_modules(),
ejabberd_admin:stop(),
broadcast_c2s_shutdown(),
timer:sleep(5000),
State.
%% All the processes were killed when this function is called
stop(_State) ->
?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]),
delete_pid_file(),
ejabberd_debug:stop(),
ok.
@@ -100,7 +90,18 @@ init() ->
register(ejabberd, self()),
%erlang:system_flag(fullsweep_after, 0),
%error_logger:logfile({open, ?LOG_PATH}),
LogPath = get_log_path(),
LogPath =
case application:get_env(log_path) of
{ok, Path} ->
Path;
undefined ->
case os:getenv("EJABBERD_LOG_PATH") of
false ->
?LOG_PATH;
Path ->
Path
end
end,
error_logger:add_report_handler(ejabberd_logger_h, LogPath),
erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
case erl_ddll:load_driver(ejabberd:get_so_path(), expat_erl) of
@@ -124,7 +125,7 @@ db_init() ->
_ ->
ok
end,
application:start(mnesia, permanent),
mnesia:start(),
mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
%% Start all the modules in all the hosts
@@ -167,72 +168,3 @@ connect_nodes() ->
end, Nodes)
end.
%% @spec () -> string()
%% @doc Returns the full path to the ejabberd log file.
%% It first checks for application configuration parameter 'log_path'.
%% If not defined it checks the environment variable EJABBERD_LOG_PATH.
%% And if that one is neither defined, returns the default value:
%% "ejabberd.log" in current directory.
get_log_path() ->
case application:get_env(log_path) of
{ok, Path} ->
Path;
undefined ->
case os:getenv("EJABBERD_LOG_PATH") of
false ->
?LOG_PATH;
Path ->
Path
end
end.
%% If ejabberd is running on some Windows machine, get nameservers and add to Erlang
maybe_add_nameservers() ->
case os:type() of
{win32, _} -> add_windows_nameservers();
_ -> ok
end.
add_windows_nameservers() ->
IPTs = win32_dns:get_nameservers(),
?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]),
lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
broadcast_c2s_shutdown() ->
Children = supervisor:which_children(ejabberd_c2s_sup),
lists:foreach(
fun({_, C2SPid, _, _}) ->
C2SPid ! system_shutdown
end, Children).
%%%
%%% PID file
%%%
write_pid_file() ->
case ejabberd:get_pid_file() of
false ->
ok;
PidFilename ->
write_pid_file(os:getpid(), PidFilename)
end.
write_pid_file(Pid, PidFilename) ->
case file:open(PidFilename, [write]) of
{ok, Fd} ->
io:format(Fd, "~s~n", [Pid]),
file:close(Fd);
{error, Reason} ->
?ERROR_MSG("Cannot write PID file ~s~nReason: ~p", [PidFilename, Reason]),
throw({cannot_write_pid_file, PidFilename, Reason})
end.
delete_pid_file() ->
case ejabberd:get_pid_file() of
false ->
ok;
PidFilename ->
file:delete(PidFilename)
end.
+54 -89
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -49,12 +49,14 @@
is_user_exists_in_other_modules/3,
remove_user/2,
remove_user/3,
plain_password_required/1
plain_password_required/1,
ctl_process_get_registered/3
]).
-export([auth_modules/1]).
-include("ejabberd.hrl").
-include("ejabberd_ctl.hrl").
%%%----------------------------------------------------------------------
%%% API
@@ -78,21 +80,20 @@ plain_password_required(Server) ->
%% @spec (User::string(), Server::string(), Password::string()) ->
%% true | false
check_password(User, Server, Password) ->
case check_password_with_authmodule(User, Server, Password) of
{true, _AuthModule} -> true;
false -> false
end.
lists:any(
fun(M) ->
M:check_password(User, Server, Password)
end, auth_modules(Server)).
%% @doc Check if the user and password can login in server.
%% @spec (User::string(), Server::string(), Password::string(),
%% Digest::string(), DigestGen::function()) ->
%% StreamID::string(), Digest::string()) ->
%% true | false
check_password(User, Server, Password, Digest, DigestGen) ->
case check_password_with_authmodule(User, Server, Password,
Digest, DigestGen) of
{true, _AuthModule} -> true;
false -> false
end.
check_password(User, Server, Password, StreamID, Digest) ->
lists:any(
fun(M) ->
M:check_password(User, Server, Password, StreamID, Digest)
end, auth_modules(Server)).
%% @doc Check if the user and password can login in server.
%% The user can login if at least an authentication method accepts the user
@@ -105,22 +106,26 @@ check_password(User, Server, Password, Digest, DigestGen) ->
%% | ejabberd_auth_internal | ejabberd_auth_ldap
%% | ejabberd_auth_odbc | ejabberd_auth_pam
check_password_with_authmodule(User, Server, Password) ->
check_password_loop(auth_modules(Server), [User, Server, Password]).
check_password_with_authmodule(User, Server, Password, Digest, DigestGen) ->
check_password_loop(auth_modules(Server), [User, Server, Password,
Digest, DigestGen]).
check_password_loop([], _Args) ->
false;
check_password_loop([AuthModule | AuthModules], Args) ->
case apply(AuthModule, check_password, Args) of
true ->
{true, AuthModule};
false ->
check_password_loop(AuthModules, Args)
Res = lists:dropwhile(
fun(M) ->
not apply(M, check_password,
[User, Server, Password])
end, auth_modules(Server)),
case Res of
[] -> false;
[AuthMod | _] -> {true, AuthMod}
end.
check_password_with_authmodule(User, Server, Password, StreamID, Digest) ->
Res = lists:dropwhile(
fun(M) ->
not apply(M, check_password,
[User, Server, Password, StreamID, Digest])
end, auth_modules(Server)),
case Res of
[] -> false;
[AuthMod | _] -> {true, AuthMod}
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, ErrorType}
@@ -136,7 +141,6 @@ set_password(User, Server, Password) ->
Res
end, {error, not_allowed}, auth_modules(Server)).
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed}
try_register(_User, _Server, "") ->
%% We do not allow empty password
{error, not_allowed};
@@ -147,19 +151,12 @@ try_register(User, Server, Password) ->
false ->
case lists:member(jlib:nameprep(Server), ?MYHOSTS) of
true ->
Res = lists:foldl(
lists:foldl(
fun(_M, {atomic, ok} = Res) ->
Res;
(M, _) ->
M:try_register(User, Server, Password)
end, {error, not_allowed}, auth_modules(Server)),
case Res of
{atomic, ok} ->
ejabberd_hooks:run(register_user, Server,
[User, Server]),
{atomic, ok};
_ -> Res
end;
end, {error, not_allowed}, auth_modules(Server));
false ->
{error, not_allowed}
end
@@ -182,13 +179,7 @@ get_vh_registered_users(Server) ->
get_vh_registered_users(Server, Opts) ->
lists:flatmap(
fun(M) ->
case erlang:function_exported(
M, get_vh_registered_users, 2) of
true ->
M:get_vh_registered_users(Server, Opts);
false ->
M:get_vh_registered_users(Server)
end
M:get_vh_registered_users(Server, Opts)
end, auth_modules(Server)).
get_vh_registered_users_number(Server) ->
@@ -256,59 +247,33 @@ is_user_exists(User, Server) ->
%% Check if the user exists in all authentications module except the module
%% passed as parameter
%% @spec (Module::atom(), User, Server) -> true | false | maybe
is_user_exists_in_other_modules(Module, User, Server) ->
is_user_exists_in_other_modules_loop(
auth_modules(Server)--[Module],
User, Server).
is_user_exists_in_other_modules_loop([], _User, _Server) ->
false;
is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) ->
case AuthModule:is_user_exists(User, Server) of
true ->
true;
false ->
is_user_exists_in_other_modules_loop(AuthModules, User, Server);
{error, Error} ->
?DEBUG("The authentication module ~p returned an error~nwhen "
"checking user ~p in server ~p~nError message: ~p",
[AuthModule, User, Server, Error]),
maybe
end.
lists:any(
fun(M) ->
M:is_user_exists(User, Server)
end, auth_modules(Server)--[Module]).
%% @spec (User, Server) -> ok | error | {error, not_allowed}
%% @doc Remove user.
%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
R = lists:foreach(
lists:foreach(
fun(M) ->
M:remove_user(User, Server)
end, auth_modules(Server)),
case R of
ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
_ -> none
end,
R.
end, auth_modules(Server)).
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
%% @doc Try to remove user if the provided password is correct.
%% The removal is attempted in each auth method provided:
%% when one returns 'ok' the loop stops;
%% if no method returns 'ok' then it returns the error message indicated by the last method attempted.
remove_user(User, Server, Password) ->
R = lists:foldl(
fun(_M, ok = Res) ->
Res;
(M, _) ->
lists:foreach(
fun(M) ->
M:remove_user(User, Server, Password)
end, error, auth_modules(Server)),
case R of
ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
_ -> none
end,
R.
end, auth_modules(Server)).
ctl_process_get_registered(_Val, Host, ["registered-users"]) ->
Users = ejabberd_auth:get_vh_registered_users(Host),
NewLine = io_lib:format("~n", []),
SUsers = lists:sort(Users),
FUsers = lists:map(fun({U, _S}) -> [U, NewLine] end, SUsers),
?PRINT("~s", [FUsers]),
{stop, ?STATUS_SUCCESS};
ctl_process_get_registered(Val, _Host, _Args) ->
Val.
%%%----------------------------------------------------------------------
%%% Internal functions
+12 -12
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -79,7 +79,7 @@ allow_anonymous(Host) ->
%% anonymous protocol can be: sasl_anon|login_anon|both
is_sasl_anonymous_enabled(Host) ->
case allow_anonymous(Host) of
false -> false;
false -> false;
true ->
case anonymous_protocol(Host) of
sasl_anon -> true;
@@ -97,7 +97,7 @@ is_login_anonymous_enabled(Host) ->
true ->
case anonymous_protocol(Host) of
login_anon -> true;
both -> true;
both -> true;
_Other -> false
end
end.
@@ -115,8 +115,10 @@ anonymous_protocol(Host) ->
%% Return true if multiple connections have been allowed in the config file
%% defaults to false
allow_multiple_connections(Host) ->
ejabberd_config:get_local_option(
{allow_multiple_connections, Host}) =:= true.
case ejabberd_config:get_local_option({allow_multiple_connections, Host}) of
true -> true;
_Other -> false
end.
%% Check if user exist in the anonymus database
anonymous_user_exist(User, Server) ->
@@ -171,15 +173,12 @@ purge_hook(true, LUser, LServer) ->
%% before allowing access
check_password(User, Server, Password) ->
check_password(User, Server, Password, undefined, undefined).
check_password(User, Server, _Password, _Digest, _DigestGen) ->
check_password(User, Server, _Password, _StreamID, _Digest) ->
%% We refuse login for registered accounts (They cannot logged but
%% they however are "reserved")
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
case ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
User, Server) of
%% If user exists in other module, reject anonnymous authentication
true -> false;
%% If we are not sure whether the user exists in other module, reject anon auth
maybe -> false;
false -> login(User, Server)
end.
@@ -224,7 +223,7 @@ get_password(User, Server) ->
get_password(User, Server, "").
get_password(User, Server, DefaultValue) ->
case anonymous_user_exist(User, Server) or login(User, Server) of
case anonymous_user_exist(User, Server) of
%% We return the default value if the user is anonymous
true ->
DefaultValue;
@@ -246,3 +245,4 @@ remove_user(_User, _Server, _Password) ->
plain_password_required() ->
false.
+5 -10
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -55,9 +55,9 @@ plain_password_required() ->
true.
check_password(User, Server, Password) ->
extauth:check_password(User, Server, Password) andalso Password /= "".
extauth:check_password(User, Server, Password).
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password, _StreamID, _Digest) ->
check_password(User, Server, Password).
set_password(User, Server, Password) ->
@@ -83,13 +83,8 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
try extauth:is_user_exists(User, Server) of
Res -> Res
catch
_:Error -> {error, Error}
end.
extauth:is_user_exists(User, Server).
remove_user(_User, _Server) ->
{error, not_allowed}.
+17 -75
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -49,7 +49,6 @@
-include("ejabberd.hrl").
-record(passwd, {us, password}).
-record(reg_users_counter, {vhost, count}).
%%%----------------------------------------------------------------------
%%% API
@@ -57,19 +56,13 @@
start(Host) ->
mnesia:create_table(passwd, [{disc_copies, [node()]},
{attributes, record_info(fields, passwd)}]),
mnesia:create_table(reg_users_counter,
[{ram_copies, [node()]},
{attributes, record_info(fields, reg_users_counter)}]),
update_table(),
update_reg_users_counter_table(Host),
ejabberd_ctl:register_commands(
Host,
[{"registered-users", "list all registered users"}],
ejabberd_auth, ctl_process_get_registered),
ok.
update_reg_users_counter_table(Server) ->
Set = get_vh_registered_users(Server),
Size = length(Set),
LServer = jlib:nameprep(Server),
set_vh_registered_users_counter(LServer, Size).
plain_password_required() ->
false.
@@ -79,12 +72,12 @@ check_password(User, Server, Password) ->
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[#passwd{password = Password}] ->
Password /= "";
true;
_ ->
false
end.
check_password(User, Server, Password, Digest, DigestGen) ->
check_password(User, Server, Password, StreamID, Digest) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
@@ -92,7 +85,7 @@ check_password(User, Server, Password, Digest, DigestGen) ->
[#passwd{password = Passwd}] ->
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
Digest == sha:sha(StreamID ++ Passwd);
true ->
false
end,
@@ -123,7 +116,7 @@ set_password(User, Server, Password) ->
ok
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {aborted, Reason}
try_register(User, Server, Password) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -137,7 +130,6 @@ try_register(User, Server, Password) ->
[] ->
mnesia:write(#passwd{us = US,
password = Password}),
inc_vh_registered_users_counter(LServer),
ok;
[_E] ->
exists
@@ -205,17 +197,8 @@ get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
get_vh_registered_users_number(Server) ->
LServer = jlib:nameprep(Server),
Query = mnesia:dirty_select(
reg_users_counter,
[{#reg_users_counter{vhost = LServer, count = '$1'},
[],
['$1']}]),
case Query of
[Count] ->
Count;
_ -> 0
end.
Set = get_vh_registered_users(Server),
length(Set).
get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) ->
Set = [{U, S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)],
@@ -224,40 +207,6 @@ get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix)
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
inc_vh_registered_users_counter(LServer) ->
F = fun() ->
case mnesia:wread({reg_users_counter, LServer}) of
[C] ->
Count = C#reg_users_counter.count + 1,
C2 = C#reg_users_counter{count = Count},
mnesia:write(C2);
_ ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = 1})
end
end,
mnesia:sync_dirty(F).
dec_vh_registered_users_counter(LServer) ->
F = fun() ->
case mnesia:wread({reg_users_counter, LServer}) of
[C] ->
Count = C#reg_users_counter.count - 1,
C2 = C#reg_users_counter{count = Count},
mnesia:write(C2);
_ ->
error
end
end,
mnesia:sync_dirty(F).
set_vh_registered_users_counter(LServer, Count) ->
F = fun() ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = Count})
end,
mnesia:sync_dirty(F).
get_password(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -280,7 +229,6 @@ get_password_s(User, Server) ->
[]
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -290,26 +238,20 @@ is_user_exists(User, Server) ->
false;
[_] ->
true;
Other ->
{error, Other}
_ ->
false
end.
%% @spec (User, Server) -> ok
%% @doc Remove user.
%% Note: it returns ok even if there was some problem removing the user.
remove_user(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
F = fun() ->
mnesia:delete({passwd, US}),
dec_vh_registered_users_counter(LServer)
mnesia:delete({passwd, US})
end,
mnesia:transaction(F),
ok.
ejabberd_hooks:run(remove_user, LServer, [User, Server]).
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request
%% @doc Remove user if the provided password is correct.
remove_user(User, Server, Password) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
@@ -318,7 +260,6 @@ remove_user(User, Server, Password) ->
case mnesia:read({passwd, US}) of
[#passwd{password = Password}] ->
mnesia:delete({passwd, US}),
dec_vh_registered_users_counter(LServer),
ok;
[_] ->
not_allowed;
@@ -328,6 +269,7 @@ remove_user(User, Server, Password) ->
end,
case mnesia:transaction(F) of
{atomic, ok} ->
ejabberd_hooks:run(remove_user, LServer, [User, Server]),
ok;
{atomic, Res} ->
Res;
+17 -21
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -66,7 +66,6 @@
servers,
backups,
port,
encrypt,
dn,
password,
base,
@@ -113,8 +112,11 @@ start_link(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:start_link({local, Proc}, ?MODULE, Host, []).
terminate(_Reason, _State) ->
ok.
terminate(_Reason, State) ->
ejabberd_ctl:unregister_commands(
State#state.host,
[{"registered-users", "list all registered users"}],
ejabberd_auth, ctl_process_get_registered).
init(Host) ->
State = parse_options(Host),
@@ -123,15 +125,17 @@ init(Host) ->
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.encrypt),
State#state.password),
eldap_pool:start_link(State#state.bind_eldap_id,
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.encrypt),
State#state.password),
ejabberd_ctl:register_commands(
Host,
[{"registered-users", "list all registered users"}],
ejabberd_auth, ctl_process_get_registered),
{ok, State}.
plain_password_required() ->
@@ -150,13 +154,12 @@ check_password(User, Server, Password) ->
end
end.
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password, _StreamID, _Digest) ->
check_password(User, Server, Password).
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec (User, Server, Password) -> {error, not_allowed}
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
@@ -182,11 +185,10 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case catch is_user_exists_ldap(User, Server) of
{'EXIT', Error} ->
{error, Error};
{'EXIT', _} ->
false;
Result ->
Result
end.
@@ -357,13 +359,8 @@ parse_options(Host) ->
undefined -> [];
Backups -> Backups
end,
LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}),
LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of
undefined -> case LDAPEncrypt of
tls -> ?LDAPS_PORT;
starttls -> ?LDAP_PORT;
_ -> ?LDAP_PORT
end;
undefined -> 389;
P -> P
end,
RootDN = case ejabberd_config:get_local_option({ldap_rootdn, Host}) of
@@ -398,7 +395,6 @@ parse_options(Host) ->
servers = LDAPServers,
backups = LDAPBackups,
port = LDAPPort,
encrypt = LDAPEncrypt,
dn = RootDN,
password = Password,
base = LDAPBase,
+24 -44
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -51,13 +51,16 @@
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(_Host) ->
start(Host) ->
ejabberd_ctl:register_commands(
Host,
[{"registered-users", "list all registered users"}],
ejabberd_auth, ctl_process_get_registered),
ok.
plain_password_required() ->
false.
%% @spec (User, Server, Password) -> true | false | {error, Error}
check_password(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
@@ -65,35 +68,26 @@ check_password(User, Server, Password) ->
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
try odbc_queries:get_password(LServer, Username) of
case catch odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{Password}]} ->
Password /= ""; %% Password is correct, and not empty
{selected, ["password"], [{_Password2}]} ->
false; %% Password is not correct
{selected, ["password"], []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
true;
_ ->
false
end
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> true | false | {error, Error}
check_password(User, Server, Password, Digest, DigestGen) ->
check_password(User, Server, Password, StreamID, Digest) ->
case jlib:nodeprep(User) of
error ->
false;
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
try odbc_queries:get_password(LServer, Username) of
%% Account exists, check if password is valid
case catch odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{Passwd}]} ->
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
Digest == sha:sha(StreamID ++ Passwd);
true ->
false
end,
@@ -102,13 +96,8 @@ check_password(User, Server, Password, Digest, DigestGen) ->
true ->
(Passwd == Password) and (Password /= "")
end;
{selected, ["password"], []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
_ ->
false
end
end.
@@ -129,7 +118,6 @@ set_password(User, Server, Password) ->
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid}
try_register(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
@@ -219,7 +207,6 @@ get_password_s(User, Server) ->
end
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case jlib:nodeprep(User) of
error ->
@@ -227,22 +214,14 @@ is_user_exists(User, Server) ->
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
try odbc_queries:get_password(LServer, Username) of
case catch odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{_Password}]} ->
true; %% Account exists
{selected, ["password"], []} ->
false; %% Account does not exist
{error, Error} ->
{error, Error} %% Typical error is that table doesn't exist
catch
_:B ->
{error, B} %% Typical error is database not accessible
true;
_ ->
false
end
end.
%% @spec (User, Server) -> ok | error
%% @doc Remove user.
%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
case jlib:nodeprep(User) of
error ->
@@ -251,11 +230,10 @@ remove_user(User, Server) ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
catch odbc_queries:del_user(LServer, Username),
ok
ejabberd_hooks:run(remove_user, jlib:nameprep(Server),
[User, Server])
end.
%% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed
%% @doc Remove user if the provided password is correct.
remove_user(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
@@ -269,6 +247,8 @@ remove_user(User, Server, Password) ->
LServer, Username, Pass),
case Result of
{selected, ["password"], [{Password}]} ->
ejabberd_hooks:run(remove_user, jlib:nameprep(Server),
[User, Server]),
ok;
{selected, ["password"], []} ->
not_exists;
+4 -6
View File
@@ -5,7 +5,7 @@
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -55,7 +55,7 @@ start(_Host) ->
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password, _StreamID, _Digest) ->
check_password(User, Server, Password).
check_password(User, Host, Password) ->
@@ -80,8 +80,6 @@ get_password(_User, _Server) ->
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
is_user_exists(User, Host) ->
Service = get_pam_service(Host),
case catch epam:acct_mgmt(Service, User) of
@@ -93,7 +91,7 @@ remove_user(_User, _Server) ->
{error, not_allowed}.
remove_user(_User, _Server, _Password) ->
not_allowed.
{error, not_allowed}.
plain_password_required() ->
true.
+217 -434
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -6,7 +6,7 @@
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -17,7 +17,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-416
View File
@@ -1,416 +0,0 @@
%%%-------------------------------------------------------------------
%%% File : ejabberd_captcha.erl
%%% Author : Evgeniy Khramtsov <xramtsov@gmail.com>
%%% Purpose : CAPTCHA processing.
%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%-------------------------------------------------------------------
-module(ejabberd_captcha).
-behaviour(gen_server).
%% API
-export([start_link/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-export([create_captcha/6, build_captcha_html/2, check_captcha/2,
process_reply/1, process/2, is_feature_available/0]).
-include("jlib.hrl").
-include("ejabberd.hrl").
-include("web/ejabberd_http.hrl").
-define(VFIELD(Type, Var, Value),
{xmlelement, "field", [{"type", Type}, {"var", Var}],
[{xmlelement, "value", [], [Value]}]}).
-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
-define(CAPTCHA_LIFETIME, 120000). % two minutes
-record(state, {}).
-record(captcha, {id, pid, key, tref, args}).
-define(T(S),
case catch mnesia:transaction(fun() -> S end) of
{atomic, Res} ->
Res;
{_, Reason} ->
?ERROR_MSG("mnesia transaction failed: ~p", [Reason]),
{error, Reason}
end).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
create_captcha(Id, SID, From, To, Lang, Args)
when is_list(Id), is_list(Lang), is_list(SID),
is_record(From, jid), is_record(To, jid) ->
case create_image() of
{ok, Type, Key, Image} ->
B64Image = jlib:encode_base64(binary_to_list(Image)),
JID = jlib:jid_to_string(From),
CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org",
Data = {xmlelement, "data",
[{"xmlns", ?NS_BOB}, {"cid", CID},
{"max-age", "0"}, {"type", Type}],
[{xmlcdata, B64Image}]},
Captcha =
{xmlelement, "captcha", [{"xmlns", ?NS_CAPTCHA}],
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}),
?VFIELD("hidden", "from", {xmlcdata, jlib:jid_to_string(To)}),
?VFIELD("hidden", "challenge", {xmlcdata, Id}),
?VFIELD("hidden", "sid", {xmlcdata, SID}),
{xmlelement, "field", [{"var", "ocr"}, {"label", ?CAPTCHA_TEXT(Lang)}],
[{xmlelement, "media", [{"xmlns", ?NS_MEDIA}],
[{xmlelement, "uri", [{"type", Type}],
[{xmlcdata, "cid:" ++ CID}]}]}]}]}]},
BodyString1 = translate:translate(Lang, "Your messages to ~s are being blocked. To unblock them, visit ~s"),
BodyString = io_lib:format(BodyString1, [JID, get_url(Id)]),
Body = {xmlelement, "body", [],
[{xmlcdata, BodyString}]},
OOB = {xmlelement, "x", [{"xmlns", ?NS_OOB}],
[{xmlelement, "url", [], [{xmlcdata, get_url(Id)}]}]},
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
case ?T(mnesia:write(#captcha{id=Id, pid=self(), key=Key,
tref=Tref, args=Args})) of
ok ->
{ok, [Body, OOB, Captcha, Data]};
_Err ->
error
end;
_Err ->
error
end.
%% @spec (Id::string(), Lang::string()) -> {FormEl, {ImgEl, TextEl, IdEl, KeyEl}} | captcha_not_found
%% where FormEl = xmlelement()
%% ImgEl = xmlelement()
%% TextEl = xmlelement()
%% IdEl = xmlelement()
%% KeyEl = xmlelement()
build_captcha_html(Id, Lang) ->
case mnesia:dirty_read(captcha, Id) of
[#captcha{}] ->
ImgEl = {xmlelement, "img", [{"src", get_url(Id ++ "/image")}], []},
TextEl = {xmlcdata, ?CAPTCHA_TEXT(Lang)},
IdEl = {xmlelement, "input", [{"type", "hidden"},
{"name", "id"},
{"value", Id}], []},
KeyEl = {xmlelement, "input", [{"type", "text"},
{"name", "key"},
{"size", "10"}], []},
FormEl = {xmlelement, "form", [{"action", get_url(Id)},
{"name", "captcha"},
{"method", "POST"}],
[ImgEl,
{xmlelement, "br", [], []},
TextEl,
{xmlelement, "br", [], []},
IdEl,
KeyEl,
{xmlelement, "br", [], []},
{xmlelement, "input", [{"type", "submit"},
{"name", "enter"},
{"value", "OK"}], []}
]},
{FormEl, {ImgEl, TextEl, IdEl, KeyEl}};
_ ->
captcha_not_found
end.
%% @spec (Id::string(), ProvidedKey::string()) -> captcha_valid | captcha_non_valid | captcha_not_found
check_captcha(Id, ProvidedKey) ->
?T(case mnesia:read(captcha, Id, write) of
[#captcha{pid=Pid, args=Args, key=StoredKey, tref=Tref}] ->
mnesia:delete({captcha, Id}),
erlang:cancel_timer(Tref),
if StoredKey == ProvidedKey ->
Pid ! {captcha_succeed, Args},
captcha_valid;
true ->
Pid ! {captcha_failed, Args},
captcha_non_valid
end;
_ ->
captcha_not_found
end).
process_reply({xmlelement, "captcha", _, _} = El) ->
case xml:get_subtag(El, "x") of
false ->
{error, malformed};
Xdata ->
Fields = jlib:parse_xdata_submit(Xdata),
case {proplists:get_value("challenge", Fields),
proplists:get_value("ocr", Fields)} of
{[Id|_], [OCR|_]} ->
?T(case mnesia:read(captcha, Id, write) of
[#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] ->
mnesia:delete({captcha, Id}),
erlang:cancel_timer(Tref),
if OCR == Key ->
Pid ! {captcha_succeed, Args},
ok;
true ->
Pid ! {captcha_failed, Args},
{error, bad_match}
end;
_ ->
{error, not_found}
end);
_ ->
{error, malformed}
end
end;
process_reply(_) ->
{error, malformed}.
process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) ->
case build_captcha_html(Id, Lang) of
{FormEl, _} when is_tuple(FormEl) ->
Form =
{xmlelement, "div", [{"align", "center"}],
[FormEl]},
ejabberd_web:make_xhtml([Form]);
captcha_not_found ->
ejabberd_web:error(not_found)
end;
process(_Handlers, #request{method='GET', path=[_, Id, "image"]}) ->
case mnesia:dirty_read(captcha, Id) of
[#captcha{key=Key}] ->
case create_image(Key) of
{ok, Type, _, Img} ->
{200,
[{"Content-Type", Type},
{"Cache-Control", "no-cache"},
{"Last-Modified", httpd_util:rfc1123_date()}],
Img};
_ ->
ejabberd_web:error(not_found)
end;
_ ->
ejabberd_web:error(not_found)
end;
process(_Handlers, #request{method='POST', q=Q, lang=Lang, path=[_, Id]}) ->
ProvidedKey = proplists:get_value("key", Q, none),
case check_captcha(Id, ProvidedKey) of
captcha_valid ->
Form =
{xmlelement, "p", [],
[{xmlcdata,
translate:translate(Lang, "The captcha is valid.")
}]},
ejabberd_web:make_xhtml([Form]);
captcha_non_valid ->
ejabberd_web:error(not_allowed);
captcha_not_found ->
ejabberd_web:error(not_found)
end;
process(_Handlers, _Request) ->
ejabberd_web:error(not_found).
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([]) ->
mnesia:create_table(captcha,
[{ram_copies, [node()]},
{attributes, record_info(fields, captcha)}]),
mnesia:add_table_copy(captcha, node(), ram_copies),
check_captcha_setup(),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
{reply, bad_request, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({remove_id, Id}, State) ->
?DEBUG("captcha ~p timed out", [Id]),
_ = ?T(case mnesia:read(captcha, Id, write) of
[#captcha{args=Args, pid=Pid}] ->
Pid ! {captcha_failed, Args},
mnesia:delete({captcha, Id});
_ ->
ok
end),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Function: create_image() -> {ok, Type, Key, Image} | {error, Reason}
%% Type = "image/png" | "image/jpeg" | "image/gif"
%% Key = string()
%% Image = binary()
%% Reason = atom()
%%--------------------------------------------------------------------
create_image() ->
%% Six numbers from 1 to 9.
Key = string:substr(randoms:get_string(), 1, 6),
create_image(Key).
create_image(Key) ->
FileName = get_prog_name(),
Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])),
case cmd(Cmd) of
{ok, <<16#89, $P, $N, $G, $\r, $\n, 16#1a, $\n, _/binary>> = Img} ->
{ok, "image/png", Key, Img};
{ok, <<16#ff, 16#d8, _/binary>> = Img} ->
{ok, "image/jpeg", Key, Img};
{ok, <<$G, $I, $F, $8, X, $a, _/binary>> = Img} when X==$7; X==$9 ->
{ok, "image/gif", Key, Img};
{error, enodata = Reason} ->
?ERROR_MSG("Failed to process output from \"~s\". "
"Maybe ImageMagick's Convert program is not installed.",
[Cmd]),
{error, Reason};
{error, Reason} ->
?ERROR_MSG("Failed to process an output from \"~s\": ~p",
[Cmd, Reason]),
{error, Reason};
_ ->
Reason = malformed_image,
?ERROR_MSG("Failed to process an output from \"~s\": ~p",
[Cmd, Reason]),
{error, Reason}
end.
get_prog_name() ->
case ejabberd_config:get_local_option(captcha_cmd) of
FileName when is_list(FileName) ->
FileName;
_ ->
?CRITICAL_MSG("The option captcha_cmd is not configured, but some "
"module wants to use the CAPTCHA feature.", []),
throw({error, option_not_configured_captcha_cmd})
end.
get_url(Str) ->
case ejabberd_config:get_local_option(captcha_host) of
Host when is_list(Host) ->
"http://" ++ Host ++ "/captcha/" ++ Str;
_ ->
"http://" ++ ?MYNAME ++ "/captcha/" ++ Str
end.
%%--------------------------------------------------------------------
%% Function: cmd(Cmd) -> Data | {error, Reason}
%% Cmd = string()
%% Data = binary()
%% Description: os:cmd/1 replacement
%%--------------------------------------------------------------------
-define(CMD_TIMEOUT, 5000).
-define(MAX_FILE_SIZE, 64*1024).
cmd(Cmd) ->
Port = open_port({spawn, Cmd}, [stream, eof, binary]),
TRef = erlang:start_timer(?CMD_TIMEOUT, self(), timeout),
recv_data(Port, TRef, <<>>).
recv_data(Port, TRef, Buf) ->
receive
{Port, {data, Bytes}} ->
NewBuf = <<Buf/binary, Bytes/binary>>,
if size(NewBuf) > ?MAX_FILE_SIZE ->
return(Port, TRef, {error, efbig});
true ->
recv_data(Port, TRef, NewBuf)
end;
{Port, {data, _}} ->
return(Port, TRef, {error, efbig});
{Port, eof} when Buf /= <<>> ->
return(Port, TRef, {ok, Buf});
{Port, eof} ->
return(Port, TRef, {error, enodata});
{timeout, TRef, _} ->
return(Port, TRef, {error, timeout})
end.
return(Port, TRef, Result) ->
case erlang:cancel_timer(TRef) of
false ->
receive
{timeout, TRef, _} ->
ok
after 0 ->
ok
end;
_ ->
ok
end,
catch port_close(Port),
Result.
is_feature_enabled() ->
try get_prog_name() of
Prog when is_list(Prog) -> true
catch
_:_ -> false
end.
is_feature_available() ->
case is_feature_enabled() of
false -> false;
true ->
case create_image() of
{ok, _, _, _} -> true;
_Error -> false
end
end.
check_captcha_setup() ->
case is_feature_enabled() andalso not is_feature_available() of
true ->
?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, "
"but it can't generate images.", []);
false ->
ok
end.
+3 -3
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -95,7 +95,7 @@ get_db_used() ->
[], Domains),
lists:usort(DBs).
%% @doc Depending in the DB definition, return which type of DB this is.
%% @doc Depending in the DB definition, return which type of DB this is
%% Note that MSSQL is detected as ODBC.
%% @spec (DB) -> mysql | pgsql | odbc
get_db_type(DB) when is_tuple(DB) ->
-429
View File
@@ -1,429 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_commands.erl
%%% Author : Badlop <badlop@process-one.net>
%%% Purpose : Management of ejabberd commands
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
%%% @headerfile "ejabberd_commands.hrl"
%%% @doc Management of ejabberd commands.
%%%
%%% An ejabberd command is an abstract function identified by a name,
%%% with a defined number and type of calling arguments and type of
%%% result, that can be defined in any Erlang module and executed
%%% using any valid frontend.
%%%
%%%
%%% == Define a new ejabberd command ==
%%%
%%% ejabberd commands can be defined and registered in
%%% any Erlang module.
%%%
%%% Some commands are procedures; and their purpose is to perform an
%%% action in the server, so the command result is only some result
%%% code or result tuple. Other commands are inspectors, and their
%%% purpose is to gather some information about the server and return
%%% a detailed response: it can be integer, string, atom, tuple, list
%%% or a mix of those ones.
%%%
%%% The arguments and result of an ejabberd command are strictly
%%% defined. The number and format of the arguments provided when
%%% calling an ejabberd command must match the definition of that
%%% command. The format of the result provided by an ejabberd command
%%% must be exactly its definition. For example, if a command is said
%%% to return an integer, it must always return an integer (except in
%%% case of a crash).
%%%
%%% If you are developing an Erlang module that will run inside
%%% ejabberd and you want to provide a new ejabberd command to
%%% administer some task related to your module, you only need to:
%%% implement a function, define the command, and register it.
%%%
%%%
%%% === Define a new ejabberd command ===
%%%
%%% An ejabberd command is defined using the Erlang record
%%% 'ejabberd_commands'. This record has several elements that you
%%% must define. Note that 'tags', 'desc' and 'longdesc' are optional.
%%%
%%% For example let's define an ejabberd command 'pow' that gets the
%%% integers 'base' and 'exponent'. Its result will be an integer
%%% 'power':
%%%
%%% <pre>#ejabberd_commands{name = pow, tags = [test],
%%% desc = "Return the power of base for exponent",
%%% longdesc = "This is an example command. The formula is:\n"
%%% " power = base ^ exponent",
%%% module = ?MODULE, function = pow,
%%% args = [{base, integer}, {exponent, integer}],
%%% result = {power, integer}}</pre>
%%%
%%%
%%% === Implement the function associated to the command ===
%%%
%%% Now implement a function in your module that matches the arguments
%%% and result of the ejabberd command.
%%%
%%% For example the function calc_power gets two integers Base and
%%% Exponent. It calculates the power and rounds to an integer:
%%%
%%% <pre>calc_power(Base, Exponent) ->
%%% PowFloat = math:pow(Base, Exponent),
%%% round(PowFloat).</pre>
%%%
%%% Since this function will be called by ejabberd_commands, it must be exported.
%%% Add to your module:
%%% <pre>-export([calc_power/2]).</pre>
%%%
%%% Only some types of result formats are allowed.
%%% If the format is defined as 'rescode', then your function must return:
%%% ok | true | atom()
%%% where the atoms ok and true as considered positive answers,
%%% and any other response atom is considered negative.
%%%
%%% If the format is defined as 'restuple', then the command must return:
%%% {rescode(), string()}
%%%
%%% If the format is defined as '{list, something()}', then the command
%%% must return a list of something().
%%%
%%%
%%% === Register the command ===
%%%
%%% Define this function and put inside the #ejabberd_command you
%%% defined in the beginning:
%%%
%%% <pre>commands() ->
%%% [
%%%
%%% ].</pre>
%%%
%%% You need to include this header file in order to use the record:
%%%
%%% <pre>-include("ejabberd_commands.hrl").</pre>
%%%
%%% When your module is initialized or started, register your commands:
%%%
%%% <pre>ejabberd_commands:register_commands(commands()),</pre>
%%%
%%% And when your module is stopped, unregister your commands:
%%%
%%% <pre>ejabberd_commands:unregister_commands(commands()),</pre>
%%%
%%% That's all! Now when your module is started, the command will be
%%% registered and any frontend can access it. For example:
%%%
%%% <pre>$ ejabberdctl help pow
%%%
%%% Command Name: pow
%%%
%%% Arguments: base::integer
%%% exponent::integer
%%%
%%% Returns: power::integer
%%%
%%% Tags: test
%%%
%%% Description: Return the power of base for exponent
%%%
%%% This is an example command. The formula is:
%%% power = base ^ exponent
%%%
%%% $ ejabberdctl pow 3 4
%%% 81
%%% </pre>
%%%
%%%
%%% == Execute an ejabberd command ==
%%%
%%% ejabberd commands are mean to be executed using any valid
%%% frontend. An ejabberd commands is implemented in a regular Erlang
%%% function, so it is also possible to execute this function in any
%%% Erlang module, without dealing with the associated ejabberd
%%% commands.
%%%
%%%
%%% == Frontend to ejabberd commands ==
%%%
%%% Currently there are two frontends to ejabberd commands: the shell
%%% script {@link ejabberd_ctl. ejabberdctl}, and the XML-RPC server
%%% ejabberd_xmlrpc.
%%%
%%%
%%% === ejabberdctl as a frontend to ejabberd commands ===
%%%
%%% It is possible to use ejabberdctl to get documentation of any
%%% command. But ejabberdctl does not support all the argument types
%%% allowed in ejabberd commands, so there are some ejabberd commands
%%% that cannot be executed using ejabberdctl.
%%%
%%% Also note that the ejabberdctl shell administration script also
%%% manages ejabberdctl commands, which are unrelated to ejabberd
%%% commands and can only be executed using ejabberdctl.
%%%
%%%
%%% === ejabberd_xmlrpc as a frontend to ejabberd commands ===
%%%
%%% ejabberd_xmlrpc provides an XML-RPC server to execute ejabberd commands.
%%% ejabberd_xmlrpc is a contributed module published in ejabberd-modules SVN.
%%%
%%% Since ejabberd_xmlrpc does not provide any method to get documentation
%%% of the ejabberd commands, please use ejabberdctl to know which
%%% commands are available, and their usage.
%%%
%%% The number and format of the arguments provided when calling an
%%% ejabberd command must match the definition of that command. Please
%%% make sure the XML-RPC call provides the required arguments, with
%%% the specified format. The order of the arguments in an XML-RPC
%%% call is not important, because all the data is tagged and will be
%%% correctly prepared by ejabberd_xmlrpc before executing the ejabberd
%%% command.
%%% TODO: consider this feature:
%%% All commands are catched. If an error happens, return the restuple:
%%% {error, flattened error string}
%%% This means that ecomm call APIs (ejabberd_ctl, ejabberd_xmlrpc) need to allows this.
%%% And ejabberd_xmlrpc must be prepared to handle such an unexpected response.
-module(ejabberd_commands).
-author('badlop@process-one.net').
-export([init/0,
list_commands/0,
get_command_format/1,
get_command_definition/1,
get_tags_commands/0,
register_commands/1,
unregister_commands/1,
execute_command/2,
execute_command/4
]).
-include("ejabberd_commands.hrl").
-include("ejabberd.hrl").
init() ->
ets:new(ejabberd_commands, [named_table, set, public,
{keypos, #ejabberd_commands.name}]).
%% @spec ([ejabberd_commands()]) -> ok
%% @doc Register ejabberd commands.
%% If a command is already registered, a warning is printed and the old command is preserved.
register_commands(Commands) ->
lists:foreach(
fun(Command) ->
case ets:insert_new(ejabberd_commands, Command) of
true ->
ok;
false ->
?DEBUG("This command is already defined:~n~p", [Command])
end
end,
Commands).
%% @spec ([ejabberd_commands()]) -> ok
%% @doc Unregister ejabberd commands.
unregister_commands(Commands) ->
lists:foreach(
fun(Command) ->
ets:delete_object(ejabberd_commands, Command)
end,
Commands).
%% @spec () -> [{Name::atom(), Args::[aterm()], Desc::string()}]
%% @doc Get a list of all the available commands, arguments and description.
list_commands() ->
Commands = ets:match(ejabberd_commands,
#ejabberd_commands{name = '$1',
args = '$2',
desc = '$3',
_ = '_'}),
[{A, B, C} || [A, B, C] <- Commands].
%% @spec (Name::atom()) -> {Args::[aterm()], Result::rterm()} | {error, command_unknown}
%% @doc Get the format of arguments and result of a command.
get_command_format(Name) ->
Matched = ets:match(ejabberd_commands,
#ejabberd_commands{name = Name,
args = '$1',
result = '$2',
_ = '_'}),
case Matched of
[] ->
{error, command_unknown};
[[Args, Result]] ->
{Args, Result}
end.
%% @spec (Name::atom()) -> ejabberd_commands() | command_not_found
%% @doc Get the definition record of a command.
get_command_definition(Name) ->
case ets:lookup(ejabberd_commands, Name) of
[E] -> E;
[] -> command_not_found
end.
%% @spec (Name::atom(), Arguments) -> ResultTerm | {error, command_unknown}
%% @doc Execute a command.
execute_command(Name, Arguments) ->
execute_command([], noauth, Name, Arguments).
%% @spec (AccessCommands, Auth, Name::atom(), Arguments) -> ResultTerm | {error, Error}
%% where
%% AccessCommands = [{Access, CommandNames, Arguments}]
%% Auth = {User::string(), Server::string(), Password::string()} | noauth
%% Method = atom()
%% Arguments = [any()]
%% Error = command_unknown | account_unprivileged | invalid_account_data | no_auth_provided
execute_command(AccessCommands, Auth, Name, Arguments) ->
case ets:lookup(ejabberd_commands, Name) of
[Command] ->
try check_access_commands(AccessCommands, Auth, Name, Command, Arguments) of
ok -> execute_command2(Command, Arguments)
catch
{error, Error} -> {error, Error}
end;
[] -> {error, command_unknown}
end.
execute_command2(Command, Arguments) ->
Module = Command#ejabberd_commands.module,
Function = Command#ejabberd_commands.function,
?DEBUG("Executing command ~p:~p with Args=~p", [Module, Function, Arguments]),
apply(Module, Function, Arguments).
%% @spec () -> [{Tag::string(), [CommandName::string()]}]
%% @doc Get all the tags and associated commands.
get_tags_commands() ->
CommandTags = ets:match(ejabberd_commands,
#ejabberd_commands{
name = '$1',
tags = '$2',
_ = '_'}),
Dict = lists:foldl(
fun([CommandNameAtom, CTags], D) ->
CommandName = atom_to_list(CommandNameAtom),
case CTags of
[] ->
orddict:append("untagged", CommandName, D);
_ ->
lists:foldl(
fun(TagAtom, DD) ->
Tag = atom_to_list(TagAtom),
orddict:append(Tag, CommandName, DD)
end,
D,
CTags)
end
end,
orddict:new(),
CommandTags),
orddict:to_list(Dict).
%% -----------------------------
%% Access verification
%% -----------------------------
%% @spec (AccessCommands, Auth, Method, Command, Arguments) -> ok
%% where
%% AccessCommands = [ {Access, CommandNames, Arguments} ]
%% Auth = {User::string(), Server::string(), Password::string()} | noauth
%% Method = atom()
%% Arguments = [any()]
%% @doc Check access is allowed to that command.
%% At least one AccessCommand must be satisfied.
%% It may throw {error, Error} where:
%% Error = account_unprivileged | invalid_account_data
check_access_commands([], _Auth, _Method, _Command, _Arguments) ->
ok;
check_access_commands(AccessCommands, Auth, Method, Command, Arguments) ->
AccessCommandsAllowed =
lists:filter(
fun({Access, Commands, ArgumentRestrictions}) ->
case check_access(Access, Auth) of
true ->
check_access_command(Commands, Command, ArgumentRestrictions,
Method, Arguments);
false ->
false
end
end,
AccessCommands),
case AccessCommandsAllowed of
[] -> throw({error, account_unprivileged});
L when is_list(L) -> ok
end.
check_auth(noauth) ->
no_auth_provided;
check_auth({User, Server, Password}) ->
%% Check the account exists and password is valid
AccountPass = ejabberd_auth:get_password_s(User, Server),
AccountPassMD5 = get_md5(AccountPass),
case Password of
AccountPass -> {ok, User, Server};
AccountPassMD5 -> {ok, User, Server};
_ -> throw({error, invalid_account_data})
end.
get_md5(AccountPass) ->
lists:flatten([io_lib:format("~.16B", [X])
|| X <- binary_to_list(crypto:md5(AccountPass))]).
check_access(all, _) ->
true;
check_access(Access, Auth) ->
{ok, User, Server} = check_auth(Auth),
%% Check this user has access permission
case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of
allow -> true;
deny -> false
end.
check_access_command(Commands, Command, ArgumentRestrictions, Method, Arguments) ->
case Commands==all orelse lists:member(Method, Commands) of
true -> check_access_arguments(Command, ArgumentRestrictions, Arguments);
false -> false
end.
check_access_arguments(Command, ArgumentRestrictions, Arguments) ->
ArgumentsTagged = tag_arguments(Command#ejabberd_commands.args, Arguments),
lists:all(
fun({ArgName, ArgAllowedValue}) ->
%% If the call uses the argument, check the value is acceptable
case lists:keysearch(ArgName, 1, ArgumentsTagged) of
{value, {ArgName, ArgValue}} -> ArgValue == ArgAllowedValue;
false -> true
end
end, ArgumentRestrictions).
tag_arguments(ArgsDefs, Args) ->
lists:zipwith(
fun({ArgName, _ArgType}, ArgValue) ->
{ArgName, ArgValue}
end,
ArgsDefs,
Args).
-52
View File
@@ -1,52 +0,0 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-record(ejabberd_commands, {name, tags = [],
desc = "", longdesc = "",
module, function,
args = [], result = rescode}).
%% @type ejabberd_commands() = #ejabberd_commands{
%% name = atom(),
%% tags = [atom()],
%% desc = string(),
%% longdesc = string(),
%% module = atom(),
%% function = atom(),
%% args = [aterm()],
%% result = rterm()
%% }.
%% desc: Description of the command
%% args: Describe the accepted arguments.
%% This way the function that calls the command can format the
%% arguments before calling.
%% @type atype() = integer | string | {tuple, [aterm()]} | {list, aterm()}.
%% Allowed types for arguments are integer, string, tuple and list.
%% @type rtype() = integer | string | atom | {tuple, [rterm()]} | {list, rterm()} | rescode | restuple.
%% A rtype is either an atom or a tuple with two elements.
%% @type aterm() = {Name::atom(), Type::atype()}.
%% An argument term is a tuple with the term name and the term type.
%% @type rterm() = {Name::atom(), Type::rtype()}.
%% A result term is a tuple with the term name and the term type.
+28 -312
View File
@@ -5,7 +5,7 @@
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -31,20 +31,9 @@
add_global_option/2, add_local_option/2,
get_global_option/1, get_local_option/1]).
-export([get_vh_by_auth_method/1]).
-export([is_file_readable/1]).
-include("ejabberd.hrl").
-include("ejabberd_config.hrl").
-include_lib("kernel/include/file.hrl").
%% @type macro() = {macro_key(), macro_value()}
%% @type macro_key() = atom().
%% The atom must have all characters in uppercase.
%% @type macro_value() = term().
start() ->
mnesia:create_table(config,
@@ -56,76 +45,36 @@ start() ->
{local_content, true},
{attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies),
Config = get_ejabberd_config_path(),
load_file(Config),
%% This start time is used by mod_last:
add_local_option(node_start, now()),
ok.
Config = case application:get_env(config) of
{ok, Path} -> Path;
undefined ->
case os:getenv("EJABBERD_CONFIG_PATH") of
false ->
?CONFIG_PATH;
Path ->
Path
end
end,
load_file(Config).
%% @doc Get the filename of the ejabberd configuration file.
%% The filename can be specified with: erl -config "/path/to/ejabberd.cfg".
%% It can also be specified with the environtment variable EJABBERD_CONFIG_PATH.
%% If not specified, the default value 'ejabberd.cfg' is assumed.
%% @spec () -> string()
get_ejabberd_config_path() ->
case application:get_env(config) of
{ok, Path} -> Path;
undefined ->
case os:getenv("EJABBERD_CONFIG_PATH") of
false ->
?CONFIG_PATH;
Path ->
Path
end
end.
%% @doc Load the ejabberd configuration file.
%% It also includes additional configuration files and replaces macros.
%% This function will crash if finds some error in the configuration file.
%% @spec (File::string()) -> ok
load_file(File) ->
Terms = get_plain_terms_file(File),
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
Terms_macros = replace_macros(Terms),
Res = lists:foldl(fun process_term/2, State, Terms_macros),
set_opts(Res).
%% @doc Read an ejabberd configuration file and return the terms.
%% Input is an absolute or relative path to an ejabberd config file.
%% Returns a list of plain terms,
%% in which the options 'include_config_file' were parsed
%% and the terms in those files were included.
%% @spec(string()) -> [term()]
get_plain_terms_file(File1) ->
File = get_absolute_path(File1),
case file:consult(File) of
{ok, Terms} ->
include_config_files(Terms);
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
ExitText = describe_config_problem(File, Reason, LineNumber),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText);
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
Res = lists:foldl(fun process_term/2, State, Terms),
set_opts(Res);
{error, {_LineNumber, erl_parse, _ParseMessage} = Reason} ->
ExitText = lists:flatten(File ++ " approximately in the line "
++ file:format_error(Reason)),
?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]),
exit(ExitText);
{error, Reason} ->
ExitText = describe_config_problem(File, Reason),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText)
ExitText = lists:flatten(File ++ ": " ++ file:format_error(Reason)),
?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]),
exit(ExitText)
end.
%% @doc Convert configuration filename to absolute path.
%% Input is an absolute or relative path to an ejabberd configuration file.
%% And returns an absolute path to the configuration file.
%% @spec (string()) -> string()
get_absolute_path(File) ->
case filename:pathtype(File) of
absolute ->
File;
relative ->
Config_path = get_ejabberd_config_path(),
Config_dir = filename:dirname(Config_path),
filename:absname_join(Config_dir, File)
end.
search_hosts(Term, State) ->
case Term of
{host, Host} ->
@@ -168,192 +117,6 @@ normalize_hosts([Host|Hosts], PrepHosts) ->
normalize_hosts(Hosts, [PrepHost|PrepHosts])
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Errors reading the config file
describe_config_problem(Filename, Reason) ->
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
Text2 = lists:flatten(" : " ++ file:format_error(Reason)),
ExitText = Text1 ++ Text2,
ExitText.
describe_config_problem(Filename, Reason, LineNumber) ->
Text1 = lists:flatten("Problem loading ejabberd config file " ++ Filename),
Text2 = lists:flatten(" approximately in the line "
++ file:format_error(Reason)),
ExitText = Text1 ++ Text2,
Lines = get_config_lines(Filename, LineNumber, 10, 3),
?ERROR_MSG("The following lines from your configuration file might be"
" relevant to the error: ~n~s", [Lines]),
ExitText.
get_config_lines(Filename, TargetNumber, PreContext, PostContext) ->
{ok, Fd} = file:open(Filename, [read]),
LNumbers = lists:seq(TargetNumber-PreContext, TargetNumber+PostContext),
NextL = file:read_line(Fd),
R = get_config_lines2(Fd, NextL, 1, LNumbers, []),
file:close(Fd),
R.
get_config_lines2(_Fd, eof, _CurrLine, _LNumbers, R) ->
lists:reverse(R);
get_config_lines2(_Fd, _NewLine, _CurrLine, [], R) ->
lists:reverse(R);
get_config_lines2(Fd, {ok, Data}, CurrLine, [NextWanted | LNumbers], R) ->
NextL = file:read_line(Fd),
if
CurrLine >= NextWanted ->
Line2 = [integer_to_list(CurrLine), ": " | Data],
get_config_lines2(Fd, NextL, CurrLine+1, LNumbers, [Line2 | R]);
true ->
get_config_lines2(Fd, NextL, CurrLine+1, [NextWanted | LNumbers], R)
end.
%% If ejabberd isn't yet running in this node, then halt the node
exit_or_halt(ExitText) ->
case [Vsn || {ejabberd, _Desc, Vsn} <- application:which_applications()] of
[] ->
timer:sleep(1000),
halt(ExitText);
[_] ->
exit(ExitText)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for 'include_config_file'
%% @doc Include additional configuration files in the list of terms.
%% @spec ([term()]) -> [term()]
include_config_files(Terms) ->
include_config_files(Terms, []).
include_config_files([], Res) ->
Res;
include_config_files([{include_config_file, Filename} | Terms], Res) ->
include_config_files([{include_config_file, Filename, []} | Terms], Res);
include_config_files([{include_config_file, Filename, Options} | Terms], Res) ->
Included_terms = get_plain_terms_file(Filename),
Disallow = proplists:get_value(disallow, Options, []),
Included_terms2 = delete_disallowed(Disallow, Included_terms),
Allow_only = proplists:get_value(allow_only, Options, all),
Included_terms3 = keep_only_allowed(Allow_only, Included_terms2),
include_config_files(Terms, Res ++ Included_terms3);
include_config_files([Term | Terms], Res) ->
include_config_files(Terms, Res ++ [Term]).
%% @doc Filter from the list of terms the disallowed.
%% Returns a sublist of Terms without the ones which first element is
%% included in Disallowed.
%% @spec (Disallowed::[atom()], Terms::[term()]) -> [term()]
delete_disallowed(Disallowed, Terms) ->
lists:foldl(
fun(Dis, Ldis) ->
delete_disallowed2(Dis, Ldis)
end,
Terms,
Disallowed).
delete_disallowed2(Disallowed, [H|T]) ->
case element(1, H) of
Disallowed ->
?WARNING_MSG("The option '~p' is disallowed, "
"and will not be accepted", [Disallowed]),
delete_disallowed2(Disallowed, T);
_ ->
[H|delete_disallowed2(Disallowed, T)]
end;
delete_disallowed2(_, []) ->
[].
%% @doc Keep from the list only the allowed terms.
%% Returns a sublist of Terms with only the ones which first element is
%% included in Allowed.
%% @spec (Allowed::[atom()], Terms::[term()]) -> [term()]
keep_only_allowed(all, Terms) ->
Terms;
keep_only_allowed(Allowed, Terms) ->
{As, NAs} = lists:partition(
fun(Term) ->
lists:member(element(1, Term), Allowed)
end,
Terms),
[?WARNING_MSG("This option is not allowed, "
"and will not be accepted:~n~p", [NA])
|| NA <- NAs],
As.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for Macro
%% @doc Replace the macros with their defined values.
%% @spec (Terms::[term()]) -> [term()]
replace_macros(Terms) ->
{TermsOthers, Macros} = split_terms_macros(Terms),
replace(TermsOthers, Macros).
%% @doc Split Terms into normal terms and macro definitions.
%% @spec (Terms) -> {Terms, Macros}
%% Terms = [term()]
%% Macros = [macro()]
split_terms_macros(Terms) ->
lists:foldl(
fun(Term, {TOs, Ms}) ->
case Term of
{define_macro, Key, Value} ->
case is_atom(Key) and is_all_uppercase(Key) of
true ->
{TOs, Ms++[{Key, Value}]};
false ->
exit({macro_not_properly_defined, Term})
end;
Term ->
{TOs ++ [Term], Ms}
end
end,
{[], []},
Terms).
%% @doc Recursively replace in Terms macro usages with the defined value.
%% @spec (Terms, Macros) -> Terms
%% Terms = [term()]
%% Macros = [macro()]
replace([], _) ->
[];
replace([Term|Terms], Macros) ->
[replace_term(Term, Macros) | replace(Terms, Macros)].
replace_term(Key, Macros) when is_atom(Key) ->
case is_all_uppercase(Key) of
true ->
case proplists:get_value(Key, Macros) of
undefined -> exit({undefined_macro, Key});
Value -> Value
end;
false ->
Key
end;
replace_term({use_macro, Key, Value}, Macros) ->
proplists:get_value(Key, Macros, Value);
replace_term(Term, Macros) when is_list(Term) ->
replace(Term, Macros);
replace_term(Term, Macros) when is_tuple(Term) ->
List = tuple_to_list(Term),
List2 = replace(List, Macros),
list_to_tuple(List2);
replace_term(Term, _) ->
Term.
is_all_uppercase(Atom) ->
String = erlang:atom_to_list(Atom),
lists:all(fun(C) when C >= $a, C =< $z -> false;
(_) -> true
end, String).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Process terms
process_term(Term, State) ->
case Term of
override_global ->
@@ -377,42 +140,18 @@ process_term(Term, State) ->
{host_config, Host, Terms} ->
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
State, Terms);
{listen, Listeners} ->
Listeners2 =
lists:map(
fun({PortIP, Module, Opts}) ->
{Port, IPT, _, _, Proto, OptsClean} =
ejabberd_listener:parse_listener_portip(PortIP, Opts),
{{Port, IPT, Proto}, Module, OptsClean}
end,
Listeners),
add_option(listen, Listeners2, State);
{listen, Val} ->
add_option(listen, Val, State);
{language, Val} ->
add_option(language, Val, State);
{outgoing_s2s_port, Port} ->
add_option(outgoing_s2s_port, Port, State);
{outgoing_s2s_options, Methods, Timeout} ->
add_option(outgoing_s2s_options, {Methods, Timeout}, State);
{s2s_dns_options, PropList} ->
add_option(s2s_dns_options, PropList, State);
{s2s_use_starttls, Port} ->
add_option(s2s_use_starttls, Port, State);
{s2s_certfile, CertFile} ->
case ejabberd_config:is_file_readable(CertFile) of
true -> add_option(s2s_certfile, CertFile, State);
false ->
ErrorText = "There is a problem in the configuration: "
"the specified file is not readable: ",
throw({error, ErrorText ++ CertFile})
end;
add_option(s2s_certfile, CertFile, State);
{domain_certfile, Domain, CertFile} ->
case ejabberd_config:is_file_readable(CertFile) of
true -> add_option({domain_certfile, Domain}, CertFile, State);
false ->
ErrorText = "There is a problem in the configuration: "
"the specified file is not readable: ",
throw({error, ErrorText ++ CertFile})
end;
add_option({domain_certfile, Domain}, CertFile, State);
{node_type, NodeType} ->
add_option(node_type, NodeType, State);
{cluster_nodes, Nodes} ->
@@ -423,21 +162,11 @@ process_term(Term, State) ->
add_option({domain_balancing_component_number, Domain}, N, State);
{watchdog_admins, Admins} ->
add_option(watchdog_admins, Admins, State);
{watchdog_large_heap, LH} ->
add_option(watchdog_large_heap, LH, State);
{registration_timeout, Timeout} ->
add_option(registration_timeout, Timeout, State);
{captcha_cmd, Cmd} ->
add_option(captcha_cmd, Cmd, State);
{captcha_host, Host} ->
add_option(captcha_host, Host, State);
{ejabberdctl_access_commands, ACs} ->
add_option(ejabberdctl_access_commands, ACs, State);
{loglevel, Loglevel} ->
ejabberd_loglevel:set(Loglevel),
State;
{max_fsm_queue, N} ->
add_option(max_fsm_queue, N, State);
{_Opt, _Val} ->
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
State, State#state.hosts)
@@ -592,16 +321,3 @@ get_vh_by_auth_method(AuthMethod) ->
mnesia:dirty_select(local_config,
[{#local_config{key = {auth_method, '$1'},
value=AuthMethod},[],['$1']}]).
%% @spec (Path::string()) -> true | false
is_file_readable(Path) ->
case file:read_file_info(Path) of
{ok, FileInfo} ->
case {FileInfo#file_info.type, FileInfo#file_info.access} of
{regular, read} -> true;
{regular, read_write} -> true;
_ -> false
end;
{error, _Reason} ->
false
end.
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -11,7 +11,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+295 -670
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -11,7 +11,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-97
View File
@@ -1,97 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_debug.erl
%%% Author : Mickael Remond
%%% Purpose : ejabberd's application callback module
%%% Created : 6 may 2009 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
-module(ejabberd_debug).
-export([eprof_start/0, fprof_start/0, stop/0]).
-export([pids/0]).
eprof_start() ->
eprof:start(),
eprof:profile(pids()).
fprof_start() ->
fprof:trace([start, {file, "/tmp/fprof"}, {procs, pids()}]).
%% Stop all profilers
stop() ->
catch eprof:stop(),
catch fprof:stop(),
ok.
pids() ->
lists:zf(
fun(Pid) ->
case process_info(Pid) of
ProcessInfo when is_list(ProcessInfo) ->
CurrentFunction = current_function(ProcessInfo),
InitialCall = initial_call(ProcessInfo),
RegisteredName = registered_name(ProcessInfo),
Ancestor = ancestor(ProcessInfo),
filter_pid(Pid, CurrentFunction, InitialCall, RegisteredName, Ancestor);
_ ->
false
end
end,
processes()).
current_function(ProcessInfo) ->
{value, {_, {CurrentFunction, _,_}}} =
lists:keysearch(current_function, 1, ProcessInfo),
atom_to_list(CurrentFunction).
initial_call(ProcessInfo) ->
{value, {_, {InitialCall, _,_}}} =
lists:keysearch(initial_call, 1, ProcessInfo),
atom_to_list(InitialCall).
registered_name(ProcessInfo) ->
case lists:keysearch(registered_name, 1, ProcessInfo) of
{value, {_, Name}} when is_atom(Name) -> atom_to_list(Name);
_ -> ""
end.
ancestor(ProcessInfo) ->
{value, {_, Dictionary}} = lists:keysearch(dictionary, 1, ProcessInfo),
case lists:keysearch('$ancestors', 1, Dictionary) of
{value, {_, [Ancestor|_T]}} when is_atom(Ancestor) ->
atom_to_list(Ancestor);
_ ->
""
end.
filter_pid(Pid, "ejabberd" ++ _, _InitialCall, _RegisteredName, _Ancestor) ->
{true, Pid};
filter_pid(Pid, _CurrentFunction, "ejabberd" ++ _, _RegisteredName, _Ancestor) ->
{true, Pid};
filter_pid(Pid, _CurrentFunction, _InitialCall, "ejabberd"++_, _Ancestor) ->
{true, Pid};
filter_pid(Pid, _CurrentFunction, _InitialCall, "stringprep"++_, _Ancestor) ->
{true, Pid};
filter_pid(Pid, _CurrentFunction, _InitialCall, _RegisteredName, "ejabberd"++_) ->
{true, Pid};
filter_pid(_Pid, _CurrentFunction, _InitialCall, _RegisteredName, _Ancestor) ->
false.
+23 -50
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -53,8 +53,6 @@
-record(state, {sockmod, socket, receiver}).
-define(HIBERNATE_TIMEOUT, 90000).
%%====================================================================
%% API
%%====================================================================
@@ -94,9 +92,8 @@ start(Module, SockMod, Socket, Opts) ->
todo
end.
starttls(FsmRef, _TLSOpts) ->
%% TODO: Frontend improvements planned by Aleksey
%%gen_server:call(FsmRef, {starttls, TLSOpts}),
starttls(FsmRef, TLSOpts) ->
gen_server:call(FsmRef, {starttls, TLSOpts}),
FsmRef.
starttls(FsmRef, TLSOpts, Data) ->
@@ -138,10 +135,8 @@ close(FsmRef) ->
sockname(FsmRef) ->
gen_server:call(FsmRef, sockname).
peername(_FsmRef) ->
%% TODO: Frontend improvements planned by Aleksey
%%gen_server:call(FsmRef, peername).
{ok, {{0, 0, 0, 0}, 0}}.
peername(FsmRef) ->
gen_server:call(FsmRef, peername).
%%====================================================================
@@ -158,12 +153,11 @@ peername(_FsmRef) ->
init([Module, SockMod, Socket, Opts, Receiver]) ->
%% TODO: monitor the receiver
Node = ejabberd_node_groups:get_closest_node(backend),
{SockMod2, Socket2} = check_starttls(SockMod, Socket, Receiver, Opts),
{ok, Pid} =
rpc:call(Node, Module, start, [{?MODULE, self()}, Opts]),
ejabberd_receiver:become_controller(Receiver, Pid),
{ok, #state{sockmod = SockMod2,
socket = Socket2,
{ok, #state{sockmod = SockMod,
socket = Socket,
receiver = Receiver}}.
%%--------------------------------------------------------------------
@@ -179,8 +173,7 @@ handle_call({starttls, TLSOpts}, _From, State) ->
{ok, TLSSocket} = tls:tcp_to_tls(State#state.socket, TLSOpts),
ejabberd_receiver:starttls(State#state.receiver, TLSSocket),
Reply = ok,
{reply, Reply, State#state{socket = TLSSocket, sockmod = tls},
?HIBERNATE_TIMEOUT};
{reply, Reply, State#state{socket = TLSSocket, sockmod = tls}};
handle_call({starttls, TLSOpts, Data}, _From, State) ->
{ok, TLSSocket} = tls:tcp_to_tls(State#state.socket, TLSOpts),
@@ -188,8 +181,7 @@ handle_call({starttls, TLSOpts, Data}, _From, State) ->
catch (State#state.sockmod):send(
State#state.socket, Data),
Reply = ok,
{reply, Reply, State#state{socket = TLSSocket, sockmod = tls},
?HIBERNATE_TIMEOUT};
{reply, Reply, State#state{socket = TLSSocket, sockmod = tls}};
handle_call(compress, _From, State) ->
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
@@ -197,8 +189,7 @@ handle_call(compress, _From, State) ->
State#state.socket),
ejabberd_receiver:compress(State#state.receiver, ZlibSocket),
Reply = ok,
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
?HIBERNATE_TIMEOUT};
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib}};
handle_call({compress, Data}, _From, State) ->
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
@@ -208,36 +199,35 @@ handle_call({compress, Data}, _From, State) ->
catch (State#state.sockmod):send(
State#state.socket, Data),
Reply = ok,
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
?HIBERNATE_TIMEOUT};
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib}};
handle_call(reset_stream, _From, State) ->
ejabberd_receiver:reset_stream(State#state.receiver),
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call({send, Data}, _From, State) ->
catch (State#state.sockmod):send(
State#state.socket, Data),
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call({change_shaper, Shaper}, _From, State) ->
ejabberd_receiver:change_shaper(State#state.receiver, Shaper),
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(get_sockmod, _From, State) ->
Reply = State#state.sockmod,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(get_peer_certificate, _From, State) ->
Reply = tls:get_peer_certificate(State#state.socket),
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(get_verify_result, _From, State) ->
Reply = tls:get_verify_result(State#state.socket),
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(close, _From, State) ->
ejabberd_receiver:close(State#state.receiver),
@@ -253,7 +243,7 @@ handle_call(sockname, _From, State) ->
_ ->
SockMod:sockname(Socket)
end,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(peername, _From, State) ->
#state{sockmod = SockMod, socket = Socket} = State,
@@ -264,11 +254,11 @@ handle_call(peername, _From, State) ->
_ ->
SockMod:peername(Socket)
end,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
{reply, Reply, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT}.
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
@@ -277,7 +267,7 @@ handle_call(_Request, _From, State) ->
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State, ?HIBERNATE_TIMEOUT}.
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
@@ -285,11 +275,8 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(timeout, State) ->
proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]),
{noreply, State, ?HIBERNATE_TIMEOUT};
handle_info(_Info, State) ->
{noreply, State, ?HIBERNATE_TIMEOUT}.
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
@@ -311,17 +298,3 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
check_starttls(SockMod, Socket, Receiver, Opts) ->
TLSEnabled = lists:member(tls, Opts),
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
end, Opts),
if
TLSEnabled ->
{ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts),
ejabberd_receiver:starttls(Receiver, TLSSocket),
{tls, TLSSocket};
true ->
{SockMod, Socket}
end.
+7 -134
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -31,18 +31,12 @@
%% External exports
-export([start_link/0,
add/3,
add/4,
add_dist/5,
delete/3,
delete/4,
delete_dist/5,
run/2,
run_fold/3,
add/5,
add_dist/6,
delete/5,
delete_dist/6,
run/3,
run_fold/4]).
@@ -56,9 +50,6 @@
-include("ejabberd.hrl").
%% Timeout of 5 seconds in calls to distributed hooks
-define(TIMEOUT_DISTRIBUTED_HOOK, 5000).
-record(state, {}).
%%%----------------------------------------------------------------------
@@ -67,55 +58,18 @@
start_link() ->
gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []).
%% @spec (Hook::atom(), Function::function(), Seq::integer()) -> ok
%% @doc See add/4.
add(Hook, Function, Seq) when is_function(Function) ->
add(Hook, global, undefined, Function, Seq).
add(Hook, Host, Function, Seq) when is_function(Function) ->
add(Hook, Host, undefined, Function, Seq);
%% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok
%% @doc Add a module and function to this hook.
%% The integer sequence is used to sort the calls: low number is called before high number.
add(Hook, Module, Function, Seq) ->
add(Hook, global, Module, Function, Seq).
add(Hook, Host, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}).
add_dist(Hook, Node, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {add, Hook, global, Node, Module, Function, Seq}).
add_dist(Hook, Host, Node, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {add, Hook, Host, Node, Module, Function, Seq}).
%% @spec (Hook::atom(), Function::function(), Seq::integer()) -> ok
%% @doc See del/4.
delete(Hook, Function, Seq) when is_function(Function) ->
delete(Hook, global, undefined, Function, Seq).
delete(Hook, Host, Function, Seq) when is_function(Function) ->
delete(Hook, Host, undefined, Function, Seq);
%% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok
%% @doc Delete a module and function from this hook.
%% It is important to indicate exactly the same information than when the call was added.
delete(Hook, Module, Function, Seq) ->
delete(Hook, global, Module, Function, Seq).
delete(Hook, Host, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}).
delete_dist(Hook, Node, Module, Function, Seq) ->
delete_dist(Hook, global, Node, Module, Function, Seq).
delete_dist(Hook, Host, Node, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {delete, Hook, Host, Node, Module, Function, Seq}).
%% @spec (Hook::atom(), Args) -> ok
%% @doc Run the calls of this hook in order, don't care about function results.
%% If a call returns stop, no more calls are performed.
run(Hook, Args) ->
run(Hook, global, Args).
@@ -127,12 +81,6 @@ run(Hook, Host, Args) ->
ok
end.
%% @spec (Hook::atom(), Val, Args) -> Val | stopped | NewVal
%% @doc Run the calls of this hook in order.
%% The arguments passed to the function are: [Val | Args].
%% The result of a call is used as Val for the next call.
%% If a call returns 'stop', no more calls are performed and 'stopped' is returned.
%% If a call returns {stopped, NewVal}, no more calls are performed and NewVal is returned.
run_fold(Hook, Val, Args) ->
run_fold(Hook, global, Val, Args).
@@ -186,24 +134,6 @@ handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) ->
ok
end,
{reply, Reply, State};
handle_call({add, Hook, Host, Node, Module, Function, Seq}, _From, State) ->
Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
El = {Seq, Node, Module, Function},
case lists:member(El, Ls) of
true ->
ok;
false ->
NewLs = lists:merge(Ls, [El]),
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok
end;
[] ->
NewLs = [{Seq, Node, Module, Function}],
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok
end,
{reply, Reply, State};
handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) ->
Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
@@ -214,16 +144,6 @@ handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) ->
ok
end,
{reply, Reply, State};
handle_call({delete, Hook, Host, Node, Module, Function, Seq}, _From, State) ->
Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
NewLs = lists:delete({Seq, Node, Module, Function}, Ls),
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok;
[] ->
ok
end,
{reply, Reply, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
@@ -264,32 +184,8 @@ code_change(_OldVsn, State, _Extra) ->
run1([], _Hook, _Args) ->
ok;
run1([{_Seq, Node, Module, Function} | Ls], Hook, Args) ->
case rpc:call(Node, Module, Function, Args, ?TIMEOUT_DISTRIBUTED_HOOK) of
timeout ->
?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p",
[Node, {Hook, Args}]),
run1(Ls, Hook, Args);
{badrpc, Reason} ->
?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p",
[Node, Reason, {Hook, Args}]),
run1(Ls, Hook, Args);
stop ->
?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n"
"Stop.", [self(), node(), Node]), % debug code
ok;
Res ->
?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n"
"The response is:~n~s", [self(), node(), Node, Res]), % debug code
run1(Ls, Hook, Args)
end;
run1([{_Seq, Module, Function} | Ls], Hook, Args) ->
Res = if is_function(Function) ->
catch apply(Function, Args);
true ->
catch apply(Module, Function, Args)
end,
case Res of
case catch apply(Module, Function, Args) of
{'EXIT', Reason} ->
?ERROR_MSG("~p~nrunning hook: ~p",
[Reason, {Hook, Args}]),
@@ -303,34 +199,8 @@ run1([{_Seq, Module, Function} | Ls], Hook, Args) ->
run_fold1([], _Hook, Val, _Args) ->
Val;
run_fold1([{_Seq, Node, Module, Function} | Ls], Hook, Val, Args) ->
case rpc:call(Node, Module, Function, [Val | Args], ?TIMEOUT_DISTRIBUTED_HOOK) of
{badrpc, Reason} ->
?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p",
[Node, Reason, {Hook, Args}]),
run_fold1(Ls, Hook, Val, Args);
timeout ->
?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p",
[Node, {Hook, Args}]),
run_fold1(Ls, Hook, Val, Args);
stop ->
stopped;
{stop, NewVal} ->
?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n"
"Stop, and the NewVal is:~n~p", [self(), node(), Node, NewVal]), % debug code
NewVal;
NewVal ->
?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n"
"The NewVal is:~n~p", [self(), node(), Node, NewVal]), % debug code
run_fold1(Ls, Hook, NewVal, Args)
end;
run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) ->
Res = if is_function(Function) ->
catch apply(Function, [Val | Args]);
true ->
catch apply(Module, Function, [Val | Args])
end,
case Res of
case catch apply(Module, Function, [Val | Args]) of
{'EXIT', Reason} ->
?ERROR_MSG("~p~nrunning hook: ~p",
[Reason, {Hook, Args}]),
@@ -342,3 +212,6 @@ run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) ->
NewVal ->
run_fold1(Ls, Hook, NewVal, Args)
end.
+108 -365
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -29,201 +29,81 @@
-export([start_link/0, init/1, start/3,
init/3,
start_listeners/0,
init_ssl/4,
start_listener/3,
stop_listeners/0,
stop_listener/2,
parse_listener_portip/2,
stop_listener/1,
add_listener/3,
delete_listener/2
delete_listener/1
]).
-include("ejabberd.hrl").
%% We do not block on send anymore.
-define(TCP_SEND_TIMEOUT, 15000).
start_link() ->
supervisor:start_link({local, ejabberd_listeners}, ?MODULE, []).
init(_) ->
{ok, {{one_for_one, 10, 1}, []}}.
start_listeners() ->
case ejabberd_config:get_local_option(listen) of
undefined ->
ignore;
Ls ->
Ls2 = lists:map(
fun({Port, Module, Opts}) ->
case start_listener(Port, Module, Opts) of
{ok, _Pid} = R -> R;
{error, Error} ->
throw(Error)
end
end, Ls),
report_duplicated_portips(Ls),
{ok, {{one_for_one, 10, 1}, Ls2}}
{ok, {{one_for_one, 10, 1},
lists:map(
fun({Port, Module, Opts}) ->
{Port,
{?MODULE, start, [Port, Module, Opts]},
transient,
brutal_kill,
worker,
[?MODULE]}
end, Ls)}}
end.
report_duplicated_portips(L) ->
LKeys = [Port || {Port, _, _} <- L],
LNoDupsKeys = proplists:get_keys(L),
case LKeys -- LNoDupsKeys of
[] -> ok;
Dups ->
?CRITICAL_MSG("In the ejabberd configuration there are duplicated "
"Port number + IP address:~n ~p",
[Dups])
end.
start(Port, Module, Opts) ->
%% Check if the module is an ejabberd listener or an independent listener
ModuleRaw = strip_frontend(Module),
case ModuleRaw:socket_type() of
independent -> ModuleRaw:start_listener(Port, Opts);
_ -> start_dependent(Port, Module, Opts)
SSLError = "There is a problem with your ejabberd configuration file: the option 'ssl' for listening sockets is no longer available. To get SSL encryption use the option 'tls'.",
case lists:keysearch(ssl, 1, Opts) of
{value, {ssl, _SSLOpts}} ->
%%{ok, proc_lib:spawn_link(?MODULE, init_ssl,
%% [Port, Module, Opts, SSLOpts])};
?ERROR_MSG(SSLError, []),
{error, SSLError};
_ ->
case lists:member(ssl, Opts) of
true ->
%%{ok, proc_lib:spawn_link(?MODULE, init_ssl,
%% [Port, Module, Opts, []])};
?ERROR_MSG(SSLError, []),
{error, SSLError};
false ->
{ok, proc_lib:spawn_link(?MODULE, init,
[Port, Module, Opts])}
end
end.
%% @spec(Port, Module, Opts) -> {ok, Pid} | {error, ErrorMessage}
start_dependent(Port, Module, Opts) ->
try check_listener_options(Opts) of
ok ->
proc_lib:start_link(?MODULE, init, [Port, Module, Opts])
catch
throw:{error, Error} ->
?ERROR_MSG(Error, []),
{error, Error}
end.
init(PortIP, Module, RawOpts) ->
{Port, IPT, IPS, IPV, Proto, OptsClean} = parse_listener_portip(PortIP, RawOpts),
%% The first inet|inet6 and the last {ip, _} work,
%% so overriding those in Opts
Opts = [IPV | OptsClean] ++ [{ip, IPT}],
init(Port, Module, Opts) ->
SockOpts = lists:filter(fun({ip, _}) -> true;
(inet6) -> true;
(inet) -> true;
({backlog, _}) -> true;
(_) -> false
end, Opts),
if Proto == udp ->
init_udp(PortIP, Module, Opts, SockOpts, Port, IPS);
true ->
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS)
end.
init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
case gen_udp:open(Port, [binary,
{active, false},
{reuseaddr, true} |
SockOpts]) of
{ok, Socket} ->
%% Inform my parent that this port was opened succesfully
proc_lib:init_ack({ok, self()}),
udp_recv(Socket, Module, Opts);
{error, Reason} ->
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
end.
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
SockOpts2 = try erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true} | SockOpts];
false -> SockOpts
catch
_:_ -> []
end,
Res = gen_tcp:listen(Port, [binary,
{packet, 0},
{packet, 0},
{active, false},
{reuseaddr, true},
{nodelay, true},
{send_timeout, ?TCP_SEND_TIMEOUT},
{keepalive, true} |
SockOpts2]),
SockOpts]),
case Res of
{ok, ListenSocket} ->
%% Inform my parent that this port was opened succesfully
proc_lib:init_ack({ok, self()}),
%% And now start accepting connection attempts
accept(ListenSocket, Module, Opts);
{error, Reason} ->
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS)
?ERROR_MSG("Failed to open socket for ~p: ~p",
[{Port, Module, Opts}, Reason]),
error
end.
%% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean}
%% where
%% PortIP = Port | {Port, IPT | IPS}
%% Port = integer()
%% IPT = tuple()
%% IPS = string()
%% IPV = inet | inet6
%% Opts = [IPV | {ip, IPT} | atom() | tuple()]
%% OptsClean = [atom() | tuple()]
%% @doc Parse any kind of ejabberd listener specification.
%% The parsed options are returned in several formats.
%% OptsClean does not include inet/inet6 or ip options.
%% Opts can include the options inet6 and {ip, Tuple},
%% but they are only used when no IP address was specified in the PortIP.
%% The IP version (either IPv4 or IPv6) is inferred from the IP address type,
%% so the option inet/inet6 is only used when no IP is specified at all.
parse_listener_portip(PortIP, Opts) ->
{IPOpt, Opts2} = strip_ip_option(Opts),
{IPVOpt, OptsClean} = case lists:member(inet6, Opts2) of
true -> {inet6, Opts2 -- [inet6]};
false -> {inet, Opts2}
end,
{Port, IPT, IPS, Proto} =
case add_proto(PortIP, Opts) of
{P, Prot} ->
T = get_ip_tuple(IPOpt, IPVOpt),
S = inet_parse:ntoa(T),
{P, T, S, Prot};
{P, T, Prot} when is_integer(P) and is_tuple(T) ->
S = inet_parse:ntoa(T),
{P, T, S, Prot};
{P, S, Prot} when is_integer(P) and is_list(S) ->
[S | _] = string:tokens(S, "/"),
{ok, T} = inet_parse:address(S),
{P, T, S, Prot}
end,
IPV = case size(IPT) of
4 -> inet;
8 -> inet6
end,
{Port, IPT, IPS, IPV, Proto, OptsClean}.
add_proto(Port, Opts) when is_integer(Port) ->
{Port, get_proto(Opts)};
add_proto({Port, Proto}, _Opts) when is_atom(Proto) ->
{Port, normalize_proto(Proto)};
add_proto({Port, Addr}, Opts) ->
{Port, Addr, get_proto(Opts)};
add_proto({Port, Addr, Proto}, _Opts) ->
{Port, Addr, normalize_proto(Proto)}.
strip_ip_option(Opts) ->
{IPL, OptsNoIP} = lists:partition(
fun({ip, _}) -> true;
(_) -> false
end,
Opts),
case IPL of
%% Only the first ip option is considered
[{ip, T1} | _] when is_tuple(T1) ->
{T1, OptsNoIP};
[] ->
{no_ip_option, OptsNoIP}
end.
get_ip_tuple(no_ip_option, inet) ->
{0, 0, 0, 0};
get_ip_tuple(no_ip_option, inet6) ->
{0, 0, 0, 0, 0, 0, 0, 0};
get_ip_tuple(IPOpt, _IPVOpt) ->
IPOpt.
accept(ListenSocket, Module, Opts) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
@@ -234,11 +114,12 @@ accept(ListenSocket, Module, Opts) ->
_ ->
ok
end,
CallMod = case is_frontend(Module) of
true -> ejabberd_frontend_socket;
false -> ejabberd_socket
end,
CallMod:start(strip_frontend(Module), gen_tcp, Socket, Opts),
case Module of
{frontend, Mod} ->
ejabberd_frontend_socket:start(Mod, gen_tcp, Socket, Opts);
_ ->
ejabberd_socket:start(Module, gen_tcp, Socket, Opts)
end,
accept(ListenSocket, Module, Opts);
{error, Reason} ->
?INFO_MSG("(~w) Failed TCP accept: ~w",
@@ -246,59 +127,58 @@ accept(ListenSocket, Module, Opts) ->
accept(ListenSocket, Module, Opts)
end.
udp_recv(Socket, Module, Opts) ->
case gen_udp:recv(Socket, 0) of
{ok, {Addr, Port, Packet}} ->
case catch Module:udp_recv(Socket, Addr, Port, Packet, Opts) of
{'EXIT', Reason} ->
?ERROR_MSG("failed to process UDP packet:~n"
"** Source: {~p, ~p}~n"
"** Reason: ~p~n** Packet: ~p",
[Addr, Port, Reason, Packet]);
init_ssl(Port, Module, Opts, SSLOpts) ->
SockOpts = lists:filter(fun({ip, _}) -> true;
(inet6) -> true;
(inet) -> true;
({verify, _}) -> true;
({depth, _}) -> true;
({certfile, _}) -> true;
({keyfile, _}) -> true;
({password, _}) -> true;
({cacertfile, _}) -> true;
({ciphers, _}) -> true;
(_) -> false
end, Opts),
Res = ssl:listen(Port, [binary,
{packet, 0},
{active, false},
{nodelay, true} |
SockOpts ++ SSLOpts]),
case Res of
{ok, ListenSocket} ->
accept_ssl(ListenSocket, Module, Opts);
{error, Reason} ->
?ERROR_MSG("Failed to open socket for ~p: ~p",
[{Port, Module, Opts}, Reason]),
error
end.
accept_ssl(ListenSocket, Module, Opts) ->
case ssl:accept(ListenSocket, 200) of
{ok, Socket} ->
case {ssl:sockname(Socket), ssl:peername(Socket)} of
{{ok, Addr}, {ok, PAddr}} ->
?INFO_MSG("(~w) Accepted SSL connection ~w -> ~w",
[Socket, PAddr, Addr]);
_ ->
ok
end,
udp_recv(Socket, Module, Opts);
{ok, Pid} = Module:start({ssl, Socket}, Opts),
catch ssl:controlling_process(Socket, Pid),
Module:become_controller(Pid),
accept_ssl(ListenSocket, Module, Opts);
{error, timeout} ->
accept_ssl(ListenSocket, Module, Opts);
{error, Reason} ->
?ERROR_MSG("unexpected UDP error: ~s", [format_error(Reason)]),
throw({error, Reason})
?INFO_MSG("(~w) Failed SSL handshake: ~w",
[ListenSocket, Reason]),
accept_ssl(ListenSocket, Module, Opts)
end.
%% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error}
start_listener(Port, Module, Opts) ->
case start_listener2(Port, Module, Opts) of
{ok, _Pid} = R -> R;
{error, {{'EXIT', {undef, [{M, _F, _A}|_]}}, _} = Error} ->
?ERROR_MSG("Error starting the ejabberd listener: ~p.~n"
"It could not be loaded or is not an ejabberd listener.~n"
"Error: ~p~n", [Module, Error]),
{error, {module_not_available, M}};
{error, {already_started, Pid}} ->
{ok, Pid};
{error, Error} ->
{error, Error}
end.
%% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error}
start_listener2(Port, Module, Opts) ->
%% It is only required to start the supervisor in some cases.
%% But it doesn't hurt to attempt to start it for any listener.
%% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}}
start_module_sup(Port, Module),
start_listener_sup(Port, Module, Opts).
start_module_sup(_Port, Module) ->
Proc1 = gen_mod:get_module_proc("sup", Module),
ChildSpec1 =
{Proc1,
{ejabberd_tmp_sup, start_link, [Proc1, strip_frontend(Module)]},
permanent,
infinity,
supervisor,
[ejabberd_tmp_sup]},
supervisor:start_child(ejabberd_sup, ChildSpec1).
start_listener_sup(Port, Module, Opts) ->
ChildSpec = {Port,
{?MODULE, start, [Port, Module, Opts]},
transient,
@@ -307,167 +187,30 @@ start_listener_sup(Port, Module, Opts) ->
[?MODULE]},
supervisor:start_child(ejabberd_listeners, ChildSpec).
stop_listeners() ->
Ports = ejabberd_config:get_local_option(listen),
lists:foreach(
fun({PortIpNetp, Module, _Opts}) ->
delete_listener(PortIpNetp, Module)
end,
Ports).
stop_listener(Port) ->
supervisor:terminate_child(ejabberd_listeners, Port),
supervisor:delete_child(ejabberd_listeners, Port).
%% @spec (PortIP, Module) -> ok
%% where
%% PortIP = {Port, IPT | IPS}
%% Port = integer()
%% IPT = tuple()
%% IPS = string()
%% Module = atom()
stop_listener(PortIP, _Module) ->
supervisor:terminate_child(ejabberd_listeners, PortIP),
supervisor:delete_child(ejabberd_listeners, PortIP).
%% @spec (PortIP, Module, Opts) -> {ok, Pid} | {error, Error}
%% where
%% PortIP = {Port, IPT | IPS}
%% Port = integer()
%% IPT = tuple()
%% IPS = string()
%% IPV = inet | inet6
%% Module = atom()
%% Opts = [IPV | {ip, IPT} | atom() | tuple()]
%% @doc Add a listener and store in config if success
add_listener(PortIP, Module, Opts) ->
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
PortIP1 = {Port, IPT, Proto},
case start_listener(PortIP1, Module, Opts) of
{ok, _Pid} ->
Ports = case ejabberd_config:get_local_option(listen) of
undefined ->
[];
Ls ->
Ls
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
Ports2 = [{PortIP1, Module, Opts} | Ports1],
ejabberd_config:add_local_option(listen, Ports2),
ok;
{error, {already_started, _Pid}} ->
{error, {already_started, PortIP}};
{error, Error} ->
{error, Error}
end.
delete_listener(PortIP, Module) ->
delete_listener(PortIP, Module, []).
%% @spec (PortIP, Module, Opts) -> ok
%% where
%% PortIP = {Port, IPT | IPS}
%% Port = integer()
%% IPT = tuple()
%% IPS = string()
%% Module = atom()
%% Opts = [term()]
delete_listener(PortIP, Module, Opts) ->
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
PortIP1 = {Port, IPT, Proto},
add_listener(Port, Module, Opts) ->
Ports = case ejabberd_config:get_local_option(listen) of
undefined ->
[];
Ls ->
Ls
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
Ports1 = lists:keydelete(Port, 1, Ports),
Ports2 = [{Port, Module, Opts} | Ports1],
ejabberd_config:add_local_option(listen, Ports2),
start_listener(Port, Module, Opts).
delete_listener(Port) ->
Ports = case ejabberd_config:get_local_option(listen) of
undefined ->
[];
Ls ->
Ls
end,
Ports1 = lists:keydelete(Port, 1, Ports),
ejabberd_config:add_local_option(listen, Ports1),
stop_listener(PortIP1, Module).
stop_listener(Port).
is_frontend({frontend, _Module}) -> true;
is_frontend(_) -> false.
%% @doc(FrontMod) -> atom()
%% where FrontMod = atom() | {frontend, atom()}
strip_frontend({frontend, Module}) -> Module;
strip_frontend(Module) when is_atom(Module) -> Module.
%%%
%%% Check options
%%%
check_listener_options(Opts) ->
case includes_deprecated_ssl_option(Opts) of
false -> ok;
true ->
Error = "There is a problem with your ejabberd configuration file: "
"the option 'ssl' for listening sockets is no longer available."
" To get SSL encryption use the option 'tls'.",
throw({error, Error})
end,
case certfile_readable(Opts) of
true -> ok;
{false, Path} ->
ErrorText = "There is a problem in the configuration: "
"the specified file is not readable: ",
throw({error, ErrorText ++ Path})
end,
ok.
%% Parse the options of the socket,
%% and return if the deprecated option 'ssl' is included
%% @spec (Opts) -> true | false
includes_deprecated_ssl_option(Opts) ->
case lists:keysearch(ssl, 1, Opts) of
{value, {ssl, _SSLOpts}} ->
true;
_ ->
lists:member(ssl, Opts)
end.
%% @spec (Opts) -> true | {false, Path::string()}
certfile_readable(Opts) ->
case proplists:lookup(certfile, Opts) of
none -> true;
{certfile, Path} ->
case ejabberd_config:is_file_readable(Path) of
true -> true;
false -> {false, Path}
end
end.
get_proto(Opts) ->
case proplists:get_value(proto, Opts) of
undefined ->
tcp;
Proto ->
normalize_proto(Proto)
end.
normalize_proto(tcp) -> tcp;
normalize_proto(udp) -> udp;
normalize_proto(UnknownProto) ->
?WARNING_MSG("There is a problem in the configuration: "
"~p is an unknown IP protocol. Using tcp as fallback",
[UnknownProto]),
tcp.
socket_error(Reason, PortIP, Module, SockOpts, Port, IPS) ->
ReasonT = case Reason of
eaddrnotavail ->
"IP address not available: " ++ IPS;
eaddrinuse ->
"IP address and port number already used: "
++IPS++" "++integer_to_list(Port);
_ ->
format_error(Reason)
end,
?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s",
[{Port, Module, SockOpts}, ReasonT]),
throw({Reason, PortIP}).
format_error(Reason) ->
case inet:format_error(Reason) of
"unknown POSIX error" ->
atom_to_list(Reason);
ReasonStr ->
ReasonStr
end.
+35 -91
View File
@@ -5,7 +5,7 @@
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -33,8 +33,6 @@
-export([start_link/0]).
-export([route/3,
route_iq/4,
process_iq_reply/3,
register_iq_handler/4,
register_iq_handler/5,
register_iq_response_handler/4,
@@ -53,13 +51,10 @@
-record(state, {}).
-record(iq_response, {id, module, function, timer}).
-record(iq_response, {id, module, function}).
-define(IQTABLE, local_iqtable).
%% This value is used in SIP and Megaco for a transaction lifetime.
-define(IQ_TIMEOUT, 32000).
%%====================================================================
%% API
%%====================================================================
@@ -94,24 +89,36 @@ process_iq(From, To, Packet) ->
ejabberd_router:route(To, From, Err)
end;
reply ->
IQReply = jlib:iq_query_or_response_info(Packet),
process_iq_reply(From, To, IQReply);
process_iq_reply(From, To, Packet);
_ ->
Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST),
ejabberd_router:route(To, From, Err),
ok
end.
process_iq_reply(From, To, #iq{id = ID} = IQ) ->
case get_iq_callback(ID) of
{ok, undefined, Function} ->
Function(IQ),
ok;
{ok, Module, Function} ->
Module:Function(From, To, IQ),
process_iq_reply(From, To, Packet) ->
IQ = jlib:iq_query_or_response_info(Packet),
#iq{id = ID} = IQ,
case catch mnesia:dirty_read(iq_response, ID) of
[] ->
ok;
_ ->
nothing
F = fun() ->
case mnesia:read({iq_response, ID}) of
[] ->
nothing;
[#iq_response{module = Module,
function = Function}] ->
mnesia:delete({iq_response, ID}),
{Module, Function}
end
end,
case mnesia:transaction(F) of
{atomic, {Module, Function}} ->
Module:Function(From, To, IQ);
_ ->
ok
end
end.
route(From, To, Packet) ->
@@ -123,23 +130,8 @@ route(From, To, Packet) ->
ok
end.
route_iq(From, To, #iq{type = Type} = IQ, F) when is_function(F) ->
Packet = if Type == set; Type == get ->
ID = randoms:get_string(),
Host = From#jid.lserver,
register_iq_response_handler(Host, ID, undefined, F),
jlib:iq_to_xml(IQ#iq{id = ID});
true ->
jlib:iq_to_xml(IQ)
end,
ejabberd_router:route(From, To, Packet).
register_iq_response_handler(_Host, ID, Module, Function) ->
TRef = erlang:start_timer(?IQ_TIMEOUT, ejabberd_local, ID),
mnesia:dirty_write(#iq_response{id = ID,
module = Module,
function = Function,
timer = TRef}).
register_iq_response_handler(Host, ID, Module, Fun) ->
ejabberd_local ! {register_iq_response_handler, Host, ID, Module, Fun}.
register_iq_handler(Host, XMLNS, Module, Fun) ->
ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}.
@@ -147,9 +139,8 @@ register_iq_handler(Host, XMLNS, Module, Fun) ->
register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
unregister_iq_response_handler(_Host, ID) ->
catch get_iq_callback(ID),
ok.
unregister_iq_response_handler(Host, ID) ->
ejabberd_local ! {unregister_iq_response_handler, Host, ID}.
unregister_iq_handler(Host, XMLNS) ->
ejabberd_local ! {unregister_iq_handler, Host, XMLNS}.
@@ -181,7 +172,6 @@ init([]) ->
?MODULE, bounce_resource_packet, 100)
end, ?MYHOSTS),
catch ets:new(?IQTABLE, [named_table, public]),
update_table(),
mnesia:create_table(iq_response,
[{ram_copies, [node()]},
{attributes, record_info(fields, iq_response)}]),
@@ -225,6 +215,12 @@ handle_info({route, From, To, Packet}, State) ->
ok
end,
{noreply, State};
handle_info({register_iq_response_handler, _Host, ID, Module, Function}, State) ->
mnesia:dirty_write(#iq_response{id = ID, module = Module, function = Function}),
{noreply, State};
handle_info({unregister_iq_response_handler, _Host, ID}, State) ->
mnesia:dirty_delete({iq_response, ID}),
{noreply, State};
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
catch mod_disco:register_feature(Host, XMLNS),
@@ -256,9 +252,6 @@ handle_info(refresh_iq_handlers, State) ->
end
end, ets:tab2list(?IQTABLE)),
{noreply, State};
handle_info({timeout, _TRef, ID}, State) ->
process_iq_timeout(ID),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
@@ -312,52 +305,3 @@ do_route(From, To, Packet) ->
end
end.
update_table() ->
case catch mnesia:table_info(iq_response, attributes) of
[id, module, function] ->
mnesia:delete_table(iq_response);
[id, module, function, timer] ->
ok;
{'EXIT', _} ->
ok
end.
get_iq_callback(ID) ->
case mnesia:dirty_read(iq_response, ID) of
[#iq_response{module = Module, timer = TRef,
function = Function}] ->
cancel_timer(TRef),
mnesia:dirty_delete(iq_response, ID),
{ok, Module, Function};
_ ->
error
end.
process_iq_timeout(ID) ->
spawn(fun process_iq_timeout/0) ! ID.
process_iq_timeout() ->
receive
ID ->
case get_iq_callback(ID) of
{ok, undefined, Function} ->
Function(timeout);
_ ->
ok
end
after 5000 ->
ok
end.
cancel_timer(TRef) ->
case erlang:cancel_timer(TRef) of
false ->
receive
{timeout, TRef, _} ->
ok
after 0 ->
ok
end;
_ ->
ok
end.
+12 -13
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -31,7 +31,7 @@
%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2,
code_change/3, reopen_log/0, rotate_log/1]).
code_change/3, reopen_log/0]).
-record(state, {fd, file}).
@@ -117,7 +117,7 @@ reopen_log() ->
write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->
T = write_time(Time),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
S when list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
@@ -126,7 +126,7 @@ write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) ->
write_event(Fd, {Time, {emulator, _GL, Chars}}) ->
T = write_time(Time),
case catch io_lib:format(Chars, []) of
S when is_list(S) ->
S when list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
file:write(Fd, io_lib:format(T ++ "ERROR: ~p ~n", [Chars]))
@@ -145,7 +145,7 @@ write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
T = write_time(Time, "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
S when list(S) ->
file:write(Fd, io_lib:format(T ++ S, []));
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
@@ -154,7 +154,7 @@ write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
write_event(_, _) ->
ok.
format_report(Rep) when is_list(Rep) ->
format_report(Rep) when list(Rep) ->
case string_p(Rep) of
true ->
io_lib:format("~s~n",[Rep]);
@@ -171,7 +171,7 @@ format_rep([Other|Rep]) ->
format_rep(_) ->
[].
add_node(X, Pid) when is_atom(X) ->
add_node(X, Pid) when atom(X) ->
add_node(atom_to_list(X), Pid);
add_node(X, Pid) when node(Pid) /= node() ->
lists:concat([X,"** at node ",node(Pid)," **~n"]);
@@ -183,7 +183,7 @@ string_p([]) ->
string_p(Term) ->
string_p1(Term).
string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 ->
string_p1([H|T]) when integer(H), H >= $\s, H < 255 ->
string_p1(T);
string_p1([$\n|T]) -> string_p1(T);
string_p1([$\r|T]) -> string_p1(T);
@@ -192,7 +192,7 @@ string_p1([$\v|T]) -> string_p1(T);
string_p1([$\b|T]) -> string_p1(T);
string_p1([$\f|T]) -> string_p1(T);
string_p1([$\e|T]) -> string_p1(T);
string_p1([H|T]) when is_list(H) ->
string_p1([H|T]) when list(H) ->
case string_p1(H) of
true -> string_p1(T);
_ -> false
@@ -206,11 +206,10 @@ write_time({{Y,Mo,D},{H,Mi,S}}, Type) ->
io_lib:format("~n=~s==== ~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w ===~n",
[Type, Y, Mo, D, H, Mi, S]).
%% @doc Rename the log file if exists, to "*-old.log".
%% Rename the log file if it the filename exists
%% This is needed in systems when the file must be closed before rotation (Windows).
%% On most Unix-like system, the file can be renamed from the command line and
%% the log can directly be reopened.
%% @spec (Filename::string()) -> ok
%%the log can directly be reopened.
rotate_log(Filename) ->
case file:read_file_info(Filename) of
{ok, _FileInfo} ->
+46 -36
View File
@@ -9,7 +9,7 @@
%%% Created : 29 Nov 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -20,7 +20,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -31,51 +31,64 @@
-module(ejabberd_loglevel).
-author('mickael.remond@process-one.net').
-export([set/1, get/0]).
-export([set/1]).
-include("ejabberd.hrl").
-define(LOGMODULE, "error_logger").
%% Error levels:
-define(LOG_LEVELS,[ {0, no_log, "No log"}
,{1, critical, "Critical"}
,{2, error, "Error"}
,{3, warning, "Warning"}
,{4, info, "Info"}
,{5, debug, "Debug"}
]).
get() ->
Level = ejabberd_logger:get(),
case lists:keysearch(Level, 1, ?LOG_LEVELS) of
{value, Result} -> Result;
_ -> erlang:error({no_such_loglevel, Level})
end.
set(LogLevel) when is_atom(LogLevel) ->
set(level_to_integer(LogLevel));
%% 0 -> No log
%% 1 -> Critical
%% 2 -> Error
%% 3 -> Warning
%% 4 -> Info
%% 5 -> Debug
set(Loglevel) when is_integer(Loglevel) ->
try
{Mod,Code} = dynamic_compile:from_string(ejabberd_logger_src(Loglevel)),
code:load_binary(Mod, ?LOGMODULE ++ ".erl", Code)
catch
Type:Error -> ?CRITICAL_MSG("Error compiling logger (~p): ~p~n", [Type, Error])
end;
Forms = compile_string(?LOGMODULE, ejabberd_logger_src(Loglevel)),
load_logger(Forms, ?LOGMODULE, Loglevel);
set(_) ->
exit("Loglevel must be an integer").
%% --------------------------------------------------------------
%% Compile a string into a module and returns the binary
compile_string(Mod, Str) ->
Fname = Mod ++ ".erl",
{ok, Fd} = open_ram_file(Fname),
file:write(Fd, Str),
file:position(Fd, 0),
case epp_dodger:parse(Fd) of
{ok, Tree} ->
Forms = revert_tree(Tree),
close_ram_file(Fd),
Forms;
Error ->
close_ram_file(Fd),
Error
end.
open_ram_file(Fname) ->
ram_file_io_server:start(self(), Fname, [read,write]).
level_to_integer(Level) ->
case lists:keysearch(Level, 2, ?LOG_LEVELS) of
{value, {Int, Level, _Desc}} -> Int;
_ -> erlang:error({no_such_loglevel, Level})
close_ram_file(Fd) ->
file:close(Fd).
revert_tree(Tree) ->
[erl_syntax:revert(T) || T <- Tree].
load_logger(Forms, Mod, Loglevel) ->
Fname = Mod ++ ".erl",
case compile:forms(Forms, [binary, {d,'LOGLEVEL',Loglevel}]) of
{ok, M, Bin} ->
code:load_binary(M, Fname, Bin);
Error ->
?CRITICAL_MSG("Error ~p~n", [Error])
end.
%% --------------------------------------------------------------
%% Code of the ejabberd logger, dynamically compiled and loaded
%% This allows to dynamically change log level while keeping a
%% very efficient code.
%% very efficient code.
ejabberd_logger_src(Loglevel) ->
L = integer_to_list(Loglevel),
"-module(ejabberd_logger).
@@ -85,10 +98,7 @@ ejabberd_logger_src(Loglevel) ->
info_msg/4,
warning_msg/4,
error_msg/4,
critical_msg/4,
get/0]).
get() -> "++ L ++".
critical_msg/4]).
%% Helper functions
debug_msg(Module, Line, Format, Args) when " ++ L ++ " >= 5 ->
+2 -2
View File
@@ -5,7 +5,7 @@
%%% Created : 1 Nov 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-688
View File
@@ -1,688 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_piefxis.erl
%%% Author : Pablo Polvorin, Vidal Santiago Martinez
%%% Purpose : XEP-0227: Portable Import/Export Format for XMPP-IM Servers
%%% Created : 17 Jul 2008 by Pablo Polvorin <pablo.polvorin@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%%----------------------------------------------------------------------
%%% Not implemented:
%%% - write mod_piefxis with ejabberdctl commands
%%% - Export from mod_offline_odbc.erl
%%% - Export from mod_private_odbc.erl
%%% - XEP-227: 6. Security Considerations
%%% - Other schemas of XInclude are not tested, and may not be imported correctly.
%%% - If a host has many users, split that host in XML files with 50 users each.
%%%% Headers
-module(ejabberd_piefxis).
-export([import_file/1, export_server/1, export_host/2]).
-record(parsing_state, {parser, host, dir}).
-include("ejabberd.hrl").
%%-include_lib("exmpp/include/exmpp.hrl").
%%-include_lib("exmpp/include/exmpp_client.hrl").
%% Copied from exmpp header files:
-define(NS_ROSTER, "jabber:iq:roster").
-define(NS_VCARD, "vcard-temp").
-record(xmlcdata, {
cdata = <<>>
}).
-record(xmlattr, {
ns = undefined,
name,
value
}).
-record(xmlel, {
ns = undefined,
declared_ns = [],
name,
attrs = [],
children = []
}).
-record(iq, {
kind,
type,
id,
ns,
payload,
error,
lang,
iq_ns
}).
-record(xmlendtag, {
ns = undefined,
name
}).
%% Copied from mod_private.erl
-record(private_storage, {usns, xml}).
%%-define(ERROR_MSG(M,Args),io:format(M,Args)).
%%-define(INFO_MSG(M,Args),ok).
-define(CHUNK_SIZE,1024*20). %20k
-define(BTL, binary_to_list).
-define(LTB, list_to_binary).
-define(NS_XINCLUDE, 'http://www.w3.org/2001/XInclude').
%%%==================================
%%%% Import file
import_file(FileName) ->
_ = #xmlattr{}, %% this stupid line is only to prevent compilation warning about "recod xmlattr is unused"
import_file(FileName, 2).
import_file(FileName, RootDepth) ->
try_start_exmpp(),
Dir = filename:dirname(FileName),
{ok, IO} = try_open_file(FileName),
Parser = exmpp_xml:start_parser([{max_size,infinity},
{root_depth, RootDepth},
{emit_endtag,true}]),
read_chunks(IO, #parsing_state{parser=Parser, dir=Dir}),
file:close(IO),
exmpp_xml:stop_parser(Parser).
try_start_exmpp() ->
try exmpp:start()
catch
error:{already_started, exmpp} -> ok;
error:undef -> throw({error, exmpp_not_installed})
end.
try_open_file(FileName) ->
case file:open(FileName,[read,binary]) of
{ok, IO} -> {ok, IO};
{error, enoent} -> throw({error, {file_not_found, FileName}})
end.
%%File could be large.. we read it in chunks
read_chunks(IO,State) ->
case file:read(IO,?CHUNK_SIZE) of
{ok,Chunk} ->
NewState = process_chunk(Chunk,State),
read_chunks(IO,NewState);
eof ->
ok
end.
process_chunk(Chunk,S =#parsing_state{parser=Parser}) ->
case exmpp_xml:parse(Parser,Chunk) of
continue ->
S;
XMLElements ->
process_elements(XMLElements,S)
end.
%%%==================================
%%%% Process Elements
process_elements(Elements,State) ->
lists:foldl(fun process_element/2,State,Elements).
%%%==================================
%%%% Process Element
process_element(El=#xmlel{name=user, ns=_XMLNS},
State=#parsing_state{host=Host}) ->
case add_user(El,Host) of
{error, _Other} -> error;
_ -> ok
end,
State;
process_element(H=#xmlel{name=host},State) ->
State#parsing_state{host=?BTL(exmpp_xml:get_attribute(H,"jid",none))};
process_element(#xmlel{name='server-data'},State) ->
State;
process_element(El=#xmlel{name=include, ns=?NS_XINCLUDE}, State=#parsing_state{dir=Dir}) ->
case exmpp_xml:get_attribute(El, href, none) of
none ->
ok;
HrefB ->
Href = binary_to_list(HrefB),
%%?INFO_MSG("Parse also this file: ~n~p", [Href]),
FileName = filename:join([Dir, Href]),
import_file(FileName, 1),
Href
end,
State;
process_element(#xmlcdata{cdata = _CData},State) ->
State;
process_element(#xmlendtag{ns = _NS, name='server-data'},State) ->
State;
process_element(#xmlendtag{ns = _NS, name=_Name},State) ->
State;
process_element(El,State) ->
io:format("Warning!: unknown element found: ~p ~n",[El]),
State.
%%%==================================
%%%% Add user
add_user(El, Domain) ->
User = exmpp_xml:get_attribute(El,name,none),
Password = exmpp_xml:get_attribute(El,password,none),
add_user(El, Domain, ?BTL(User), ?BTL(Password)).
%% @spec (El::xmlel(), Domain::string(), User::string(), Password::string())
%% -> ok | {atomic, exists} | {error, not_allowed}
%% @doc Add a new user to the database.
%% If user already exists, it will be only updated.
add_user(El, Domain, User, Password) ->
case create_user(User,Password,Domain) of
ok ->
ok = exmpp_xml:foreach(
fun(_,Child) ->
populate_user(User,Domain,Child)
end,
El),
ok;
{atomic, exists} ->
io:format("Account ~s@~s already exists, updating it...~n",
[User, Domain]),
io:format(""),
ok = exmpp_xml:foreach(
fun(_,Child) ->
populate_user(User,Domain,Child)
end,
El);
{error, Other} ->
?ERROR_MSG("Error adding user ~s@~s: ~p~n", [User, Domain, Other])
end.
%% @spec (User::string(), Password::string(), Domain::string())
%% -> ok | {atomic, exists} | {error, not_allowed}
%% @doc Create a new user
create_user(User,Password,Domain) ->
case ejabberd_auth:try_register(User,Domain,Password) of
{atomic,ok} -> ok;
{atomic, exists} -> {atomic, exists};
{error, not_allowed} -> {error, not_allowed};
Other -> {error, Other}
end.
%%%==================================
%%%% Populate user
%% @spec (User::string(), Domain::string(), El::xml())
%% -> ok | {error, not_found}
%%
%% @doc Add a new user from a XML file with a roster list.
%%
%% Example of a file:
%% ```
%% <?xml version='1.0' encoding='UTF-8'?>
%% <server-data xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'>
%% <host jid='localhost'>
%% <user name='juliet' password='s3crEt'>
%% <query xmlns='jabber:iq:roster'>
%% <item jid='romeo@montague.net'
%% name='Romeo'
%% subscription='both'>
%% <group>Friends</group>
%% </item>
%% </query>
%% </user>
%% </host>
%% </server-data>
%% '''
populate_user(User,Domain,El=#xmlel{name='query', ns='jabber:iq:roster'}) ->
io:format("Trying to add/update roster list...",[]),
case loaded_module(Domain,[mod_roster_odbc,mod_roster]) of
{ok, M} ->
case M:set_items(User, Domain, exmpp_xml:xmlel_to_xmlelement(El)) of
{atomic, ok} ->
io:format(" DONE.~n",[]),
ok;
_ ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("Error trying to add a new user: ~s ~n",
[exmpp_xml:document_to_list(El)]),
{error, not_found}
end;
E -> io:format(" ERROR: ~p~n",[E]),
?ERROR_MSG("No modules loaded [mod_roster, mod_roster_odbc] ~s ~n",
[exmpp_xml:document_to_list(El)]),
{error, not_found}
end;
%% @spec User = String with the user name
%% Domain = String with a domain name
%% El = Sub XML element with vCard tags values
%% @ret ok | {error, not_found}
%% @doc Read vcards from the XML and send it to the server
%%
%% Example:
%% ```
%% <?xml version='1.0' encoding='UTF-8'?>
%% <server-data xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'>
%% <host jid='localhost'>
%% <user name='admin' password='s3crEt'>
%% <vCard xmlns='vcard-temp'>
%% <FN>Admin</FN>
%% </vCard>
%% </user>
%% </host>
%% </server-data>
%% '''
populate_user(User,Domain,El=#xmlel{name='vCard', ns='vcard-temp'}) ->
io:format("Trying to add/update vCards...",[]),
case loaded_module(Domain,[mod_vcard,mod_vcard_odbc]) of
{ok, M} -> FullUser = jid_to_old_jid(exmpp_jid:make(User, Domain)),
IQ = iq_to_old_iq(#iq{type = set, payload = El}),
case M:process_sm_iq(FullUser, FullUser , IQ) of
{error,_Err} ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("Error processing vcard ~s : ~p ~n",
[exmpp_xml:document_to_list(El), _Err]);
_ ->
io:format(" DONE.~n",[]), ok
end;
_ ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("No modules loaded [mod_vcard, mod_vcard_odbc] ~s ~n",
[exmpp_xml:document_to_list(El)]),
{error, not_found}
end;
%% @spec User = String with the user name
%% Domain = String with a domain name
%% El = Sub XML element with offline messages values
%% @ret ok | {error, not_found}
%% @doc Read off-line message from the XML and send it to the server
populate_user(User,Domain,El=#xmlel{name='offline-messages'}) ->
io:format("Trying to add/update offline-messages...",[]),
case loaded_module(Domain, [mod_offline, mod_offline_odbc]) of
{ok, M} ->
ok = exmpp_xml:foreach(
fun (_Element, {xmlcdata, _}) ->
ok;
(_Element, Child) ->
From = exmpp_xml:get_attribute(Child,from,none),
FullFrom = jid_to_old_jid(exmpp_jid:parse(From)),
FullUser = jid_to_old_jid(exmpp_jid:make(User,
Domain)),
OldChild = exmpp_xml:xmlel_to_xmlelement(Child),
_R = M:store_packet(FullFrom, FullUser, OldChild)
end, El), io:format(" DONE.~n",[]);
_ ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("No modules loaded [mod_offline, mod_offline_odbc] ~s ~n",
[exmpp_xml:document_to_list(El)]),
{error, not_found}
end;
%% @spec User = String with the user name
%% Domain = String with a domain name
%% El = Sub XML element with private storage values
%% @ret ok | {error, not_found}
%% @doc Private storage parsing
populate_user(User,Domain,El=#xmlel{name='query', ns='jabber:iq:private'}) ->
io:format("Trying to add/update private storage...",[]),
case loaded_module(Domain,[mod_private_odbc,mod_private]) of
{ok, M} ->
FullUser = jid_to_old_jid(exmpp_jid:make(User, Domain)),
IQ = iq_to_old_iq(#iq{type = set,
ns = 'jabber:iq:private',
kind = request,
iq_ns = 'jabberd:client',
payload = El}),
case M:process_sm_iq(FullUser, FullUser, IQ ) of
{error, _Err} ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("Error processing private storage ~s : ~p ~n",
[exmpp_xml:document_to_list(El), _Err]);
_ -> io:format(" DONE.~n",[]), ok
end;
_ ->
io:format(" ERROR.~n",[]),
?ERROR_MSG("No modules loaded [mod_private, mod_private_odbc] ~s ~n",
[exmpp_xml:document_to_list(El)]),
{error, not_found}
end;
populate_user(_User, _Domain, #xmlcdata{cdata = _CData}) ->
ok;
populate_user(_User, _Domain, _El) ->
ok.
%%%==================================
%%%% Utilities
loaded_module(Domain,Options) ->
LoadedModules = gen_mod:loaded_modules(Domain),
case lists:filter(fun(Module) ->
lists:member(Module, LoadedModules)
end, Options) of
[M|_] -> {ok, M};
[] -> {error,not_found}
end.
jid_to_old_jid(Jid) ->
{jid, to_list(exmpp_jid:node_as_list(Jid)),
to_list(exmpp_jid:domain_as_list(Jid)),
to_list(exmpp_jid:resource_as_list(Jid)),
to_list(exmpp_jid:prep_node_as_list(Jid)),
to_list(exmpp_jid:prep_domain_as_list(Jid)),
to_list(exmpp_jid:prep_resource_as_list(Jid))}.
iq_to_old_iq(#iq{id = ID, type = Type, lang = Lang, ns= NS, payload = El }) ->
{iq, to_list(ID), Type, to_list(NS), to_list(Lang),
exmpp_xml:xmlel_to_xmlelement(El)}.
to_list(L) when is_list(L) -> L;
to_list(B) when is_binary(B) -> binary_to_list(B);
to_list(undefined) -> "";
to_list(B) when is_atom(B) -> atom_to_list(B).
%%%==================================
%%%% Export hosts
%% @spec (Dir::string(), Hosts::[string()]) -> ok
export_hosts(Dir, Hosts) ->
try_start_exmpp(),
FnT = make_filename_template(),
DFn = make_main_basefilename(Dir, FnT),
{ok, Fd} = file_open(DFn),
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_server_head()),
FilesAndHosts = [{make_host_filename(FnT, Host), Host} || Host <- Hosts],
[print(Fd, make_xinclude(FnH)) || {FnH, _Host} <- FilesAndHosts],
print(Fd, make_piefxis_server_tail()),
print(Fd, make_piefxis_xml_tail()),
file_close(Fd),
[export_host(Dir, FnH, Host) || {FnH, Host} <- FilesAndHosts],
ok.
%%%==================================
%%%% Export server
%% @spec (Dir::string()) -> ok
export_server(Dir) ->
Hosts = ?MYHOSTS,
export_hosts(Dir, Hosts).
%%%==================================
%%%% Export host
%% @spec (Dir::string(), Host::string()) -> ok
export_host(Dir, Host) ->
Hosts = [Host],
export_hosts(Dir, Hosts).
%% @spec (Dir::string(), Fn::string(), Host::string()) -> ok
export_host(Dir, FnH, Host) ->
DFn = make_host_basefilename(Dir, FnH),
{ok, Fd} = file_open(DFn),
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_host_head(Host)),
Users = ejabberd_auth:get_vh_registered_users(Host),
[export_user(Fd, Username, Host) || {Username, _Host} <- Users],
print(Fd, make_piefxis_host_tail()),
print(Fd, make_piefxis_xml_tail()),
file_close(Fd).
%%%==================================
%%%% PIEFXIS formatting
%% @spec () -> string()
make_piefxis_xml_head() ->
"<?xml version='1.0' encoding='UTF-8'?>".
%% @spec () -> string()
make_piefxis_xml_tail() ->
"".
%% @spec () -> string()
make_piefxis_server_head() ->
"<server-data"
" xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'"
" xmlns:xi='http://www.w3.org/2001/XInclude'>".
%% @spec () -> string()
make_piefxis_server_tail() ->
"</server-data>".
%% @spec (Host::string()) -> string()
make_piefxis_host_head(Host) ->
NSString =
" xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'"
" xmlns:xi='http://www.w3.org/2001/XInclude'",
io_lib:format("<host~s jid='~s'>", [NSString, Host]).
%% @spec () -> string()
make_piefxis_host_tail() ->
"</host>".
%% @spec (Fn::string()) -> string()
make_xinclude(Fn) ->
Base = filename:basename(Fn),
io_lib:format("<xi:include href='~s'/>", [Base]).
%%%==================================
%%%% Export user
%% @spec (Fd, Username::string(), Host::string()) -> ok
%% @doc Extract user information and print it.
export_user(Fd, Username, Host) ->
UserString = extract_user(Username, Host),
print(Fd, UserString).
%% @spec (Username::string(), Host::string()) -> string()
extract_user(Username, Host) ->
Password = ejabberd_auth:get_password_s(Username, Host),
UserInfo = [extract_user_info(InfoName, Username, Host) || InfoName <- [roster, offline, private, vcard]],
UserInfoString = lists:flatten(UserInfo),
io_lib:format("<user name='~s' password='~s'>~s</user>", [Username, Password, UserInfoString]).
%% @spec (InfoName::atom(), Username::string(), Host::string()) -> string()
extract_user_info(roster, Username, Host) ->
case loaded_module(Host,[mod_roster_odbc,mod_roster]) of
{ok, M} ->
From = To = jlib:make_jid(Username, Host, ""),
SubelGet = {xmlelement, "query", [{"xmlns",?NS_ROSTER}], []},
%%IQGet = #iq{type=get, xmlns=?NS_ROSTER, payload=SubelGet}, % this is for 3.0.0 version
IQGet = {iq, "", get, ?NS_ROSTER, "" , SubelGet},
Res = M:process_local_iq(From, To, IQGet),
%%[El] = Res#iq.payload, % this is for 3.0.0 version
{iq, _, result, _, _, Els} = Res,
case Els of
[El] -> exmpp_xml:document_to_list(El);
[] -> ""
end;
_E ->
""
end;
extract_user_info(offline, Username, Host) ->
case loaded_module(Host,[mod_offline,mod_offline_odbc]) of
{ok, mod_offline} ->
Els = mnesia_pop_offline_messages([], Username, Host),
case Els of
[] -> "";
Els ->
OfEl = {xmlelement, "offline-messages", [], Els},
exmpp_xml:document_to_list(OfEl)
end;
{ok, mod_offline_odbc} ->
"";
_E ->
""
end;
extract_user_info(private, Username, Host) ->
case loaded_module(Host,[mod_private,mod_private_odbc]) of
{ok, mod_private} ->
get_user_private_mnesia(Username, Host);
{ok, mod_private_odbc} ->
"";
_E ->
""
end;
extract_user_info(vcard, Username, Host) ->
case loaded_module(Host,[mod_vcard, mod_vcard_odbc, mod_vcard_odbc]) of
{ok, M} ->
From = To = jlib:make_jid(Username, Host, ""),
SubelGet = {xmlelement, "vCard", [{"xmlns",?NS_VCARD}], []},
%%IQGet = #iq{type=get, xmlns=?NS_VCARD, payload=SubelGet}, % this is for 3.0.0 version
IQGet = {iq, "", get, ?NS_VCARD, "" , SubelGet},
Res = M:process_sm_iq(From, To, IQGet),
%%[El] = Res#iq.payload, % this is for 3.0.0 version
{iq, _, result, _, _, Els} = Res,
case Els of
[El] -> exmpp_xml:document_to_list(El);
[] -> ""
end;
_E ->
""
end.
%%%==================================
%%%% Interface with ejabberd offline storage
%% Copied from mod_offline.erl and customized
-record(offline_msg, {us, timestamp, expire, from, to, packet}).
mnesia_pop_offline_messages(Ls, User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
F = fun() ->
Rs = mnesia:wread({offline_msg, US}),
%%mnesia:delete({offline_msg, US}),
Rs
end,
case mnesia:transaction(F) of
{atomic, Rs} ->
TS = now(),
Ls ++ lists:map(
fun(R) ->
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
FromString = jlib:jid_to_string(R#offline_msg.from),
Attrs2 = lists:keystore("from", 1, Attrs, {"from", FromString}),
Attrs3 = lists:keystore("xmlns", 1, Attrs2, {"xmlns", "jabber:client"}),
{xmlelement, Name, Attrs3,
Els ++
[jlib:timestamp_to_xml(
calendar:now_to_universal_time(
R#offline_msg.timestamp))]}
end,
lists:filter(
fun(R) ->
case R#offline_msg.expire of
never ->
true;
TimeStamp ->
TS < TimeStamp
end
end,
lists:keysort(#offline_msg.timestamp, Rs)));
_ ->
Ls
end.
%%%==================================
%%%% Interface with ejabberd private storage
get_user_private_mnesia(Username, Host) ->
ListNsEl = mnesia:dirty_select(private_storage,
[{#private_storage{usns={Username, Host, '$1'}, xml = '$2'},
[], ['$$']}]),
Els = [exmpp_xml:document_to_list(El) || [_Ns, El] <- ListNsEl],
case lists:flatten(Els) of
"" -> "";
ElsString ->
io_lib:format("<query xmlns='jabber:iq:private'>~s</query>", [ElsString])
end.
%%%==================================
%%%% Disk file access
%% @spec () -> string()
make_filename_template() ->
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(),
lists:flatten(
io_lib:format("~4..0w~2..0w~2..0w-~2..0w~2..0w~2..0w",
[Year, Month, Day, Hour, Minute, Second])).
%% @spec (Dir::string(), FnT::string()) -> string()
make_main_basefilename(Dir, FnT) ->
Filename2 = filename:flatten([FnT, ".xml"]),
filename:join([Dir, Filename2]).
%% @spec (FnT::string(), Host::string()) -> FnH::string()
%% @doc Make the filename for the host.
%% Example: ``("20080804-231550", "jabber.example.org") -> "20080804-231550_jabber_example_org.xml"''
make_host_filename(FnT, Host) ->
Host2 = string:join(string:tokens(Host, "."), "_"),
filename:flatten([FnT, "_", Host2, ".xml"]).
make_host_basefilename(Dir, FnT) ->
filename:join([Dir, FnT]).
%% @spec (Fn::string()) -> {ok, Fd}
file_open(Fn) ->
file:open(Fn, [write]).
%% @spec (Fd) -> ok
file_close(Fd) ->
file:close(Fd).
%% @spec (Fd, String::string()) -> ok
print(Fd, String) ->
io:format(Fd, String, []).
%%%==================================
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%%,%%%= foldmethod=marker:
+5 -12
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -52,21 +52,14 @@ start_hosts() ->
%% Start the ODBC module on the given host
start_odbc(Host) ->
Supervisor_name = gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
ChildSpec =
{Supervisor_name,
{gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
{ejabberd_odbc_sup, start_link, [Host]},
transient,
temporary,
infinity,
supervisor,
[ejabberd_odbc_sup]},
case supervisor:start_child(ejabberd_sup, ChildSpec) of
{ok, _PID} ->
ok;
_Error ->
?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", [Supervisor_name, _Error]),
start_odbc(Host)
end.
supervisor:start_child(ejabberd_sup, ChildSpec).
%% Returns true if we have configured odbc_server for the given host
needs_odbc(Host) ->
+25 -61
View File
@@ -5,7 +5,7 @@
%%% Created : 10 Nov 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -54,8 +54,6 @@
xml_stream_state,
timeout}).
-define(HIBERNATE_TIMEOUT, 90000).
%%====================================================================
%% API
%%====================================================================
@@ -136,14 +134,19 @@ handle_call({starttls, TLSSocket}, _From,
#state{xml_stream_state = XMLStreamState,
c2s_pid = C2SPid,
max_stanza_size = MaxStanzaSize} = State) ->
close_stream(XMLStreamState),
if
XMLStreamState /= undefined ->
xml_stream:close(XMLStreamState);
true ->
ok
end,
NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
NewState = State#state{socket = TLSSocket,
sock_mod = tls,
xml_stream_state = NewXMLStreamState},
case tls:recv_data(TLSSocket, "") of
{ok, TLSData} ->
{reply, ok, process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT};
{reply, ok, process_data(TLSData, NewState)};
{error, _Reason} ->
{stop, normal, ok, NewState}
end;
@@ -151,14 +154,14 @@ handle_call({compress, ZlibSocket}, _From,
#state{xml_stream_state = XMLStreamState,
c2s_pid = C2SPid,
max_stanza_size = MaxStanzaSize} = State) ->
close_stream(XMLStreamState),
xml_stream:close(XMLStreamState),
NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
NewState = State#state{socket = ZlibSocket,
sock_mod = ejabberd_zlib,
xml_stream_state = NewXMLStreamState},
case ejabberd_zlib:recv_data(ZlibSocket, "") of
{ok, ZlibData} ->
{reply, ok, process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT};
{reply, ok, process_data(ZlibData, NewState)};
{error, _Reason} ->
{stop, normal, ok, NewState}
end;
@@ -166,21 +169,20 @@ handle_call(reset_stream, _From,
#state{xml_stream_state = XMLStreamState,
c2s_pid = C2SPid,
max_stanza_size = MaxStanzaSize} = State) ->
close_stream(XMLStreamState),
xml_stream:close(XMLStreamState),
NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize),
Reply = ok,
{reply, Reply, State#state{xml_stream_state = NewXMLStreamState},
?HIBERNATE_TIMEOUT};
{reply, Reply, State#state{xml_stream_state = NewXMLStreamState}};
handle_call({become_controller, C2SPid}, _From, State) ->
XMLStreamState = xml_stream:new(C2SPid, State#state.max_stanza_size),
NewState = State#state{c2s_pid = C2SPid,
xml_stream_state = XMLStreamState},
activate_socket(NewState),
Reply = ok,
{reply, Reply, NewState, ?HIBERNATE_TIMEOUT};
{reply, Reply, NewState};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT}.
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
@@ -190,11 +192,11 @@ handle_call(_Request, _From, State) ->
%%--------------------------------------------------------------------
handle_cast({change_shaper, Shaper}, State) ->
NewShaperState = shaper:new(Shaper),
{noreply, State#state{shaper_state = NewShaperState}, ?HIBERNATE_TIMEOUT};
{noreply, State#state{shaper_state = NewShaperState}};
handle_cast(close, State) ->
{stop, normal, State};
handle_cast(_Msg, State) ->
{noreply, State, ?HIBERNATE_TIMEOUT}.
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
@@ -205,26 +207,24 @@ handle_cast(_Msg, State) ->
handle_info({Tag, _TCPSocket, Data},
#state{socket = Socket,
sock_mod = SockMod} = State)
when (Tag == tcp) or (Tag == ssl) or (Tag == ejabberd_xml) ->
when (Tag == tcp) or (Tag == ssl) ->
case SockMod of
tls ->
case tls:recv_data(Socket, Data) of
{ok, TLSData} ->
{noreply, process_data(TLSData, State),
?HIBERNATE_TIMEOUT};
{noreply, process_data(TLSData, State)};
{error, _Reason} ->
{stop, normal, State}
end;
ejabberd_zlib ->
case ejabberd_zlib:recv_data(Socket, Data) of
{ok, ZlibData} ->
{noreply, process_data(ZlibData, State),
?HIBERNATE_TIMEOUT};
{noreply, process_data(ZlibData, State)};
{error, _Reason} ->
{stop, normal, State}
end;
_ ->
{noreply, process_data(Data, State), ?HIBERNATE_TIMEOUT}
{noreply, process_data(Data, State)}
end;
handle_info({Tag, _TCPSocket}, State)
when (Tag == tcp_closed) or (Tag == ssl_closed) ->
@@ -233,18 +233,15 @@ handle_info({Tag, _TCPSocket, Reason}, State)
when (Tag == tcp_error) or (Tag == ssl_error) ->
case Reason of
timeout ->
{noreply, State, ?HIBERNATE_TIMEOUT};
{noreply, State};
_ ->
{stop, normal, State}
end;
handle_info({timeout, _Ref, activate}, State) ->
activate_socket(State),
{noreply, State, ?HIBERNATE_TIMEOUT};
handle_info(timeout, State) ->
proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]),
{noreply, State, ?HIBERNATE_TIMEOUT};
{noreply, State};
handle_info(_Info, State) ->
{noreply, State, ?HIBERNATE_TIMEOUT}.
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
@@ -255,7 +252,7 @@ handle_info(_Info, State) ->
%%--------------------------------------------------------------------
terminate(_Reason, #state{xml_stream_state = XMLStreamState,
c2s_pid = C2SPid} = State) ->
close_stream(XMLStreamState),
xml_stream:close(XMLStreamState),
if
C2SPid /= undefined ->
gen_fsm:send_event(C2SPid, closed);
@@ -294,25 +291,6 @@ activate_socket(#state{socket = Socket,
ok
end.
%% Data processing for connectors directly generating xmlelement in
%% Erlang data structure.
%% WARNING: Shaper does not work with Erlang data structure.
process_data([], State) ->
activate_socket(State),
State;
process_data([Element|Els], #state{c2s_pid = C2SPid} = State)
when element(1, Element) == xmlelement;
element(1, Element) == xmlstreamstart;
element(1, Element) == xmlstreamelement;
element(1, Element) == xmlstreamend ->
if
C2SPid == undefined ->
State;
true ->
catch gen_fsm:send_event(C2SPid, element_wrapper(Element)),
process_data(Els, State)
end;
%% Data processing for connectors receivind data as string.
process_data(Data,
#state{xml_stream_state = XMLStreamState,
shaper_state = ShaperState,
@@ -331,17 +309,3 @@ process_data(Data,
State#state{xml_stream_state = XMLStreamState1,
shaper_state = NewShaperState}.
%% Element coming from XML parser are wrapped inside xmlstreamelement
%% When we receive directly xmlelement tuple (from a socket module
%% speaking directly Erlang XML), we wrap it inside the same
%% xmlstreamelement coming from the XML parser.
element_wrapper(XMLElement)
when element(1, XMLElement) == xmlelement ->
{xmlstreamelement, XMLElement};
element_wrapper(Element) ->
Element.
close_stream(undefined) ->
ok;
close_stream(XMLStreamState) ->
xml_stream:close(XMLStreamState).
+2 -2
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+28 -98
View File
@@ -5,7 +5,7 @@
%%% Created : 7 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -39,19 +39,16 @@
remove_connection/3,
dirty_get_connections/0,
allow_host/2,
incoming_s2s_number/0,
outgoing_s2s_number/0
ctl_process/2
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% ejabberd API
-export([get_info_s2s_connections/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd_ctl.hrl").
-define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER, 1).
-define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE, 1).
@@ -167,7 +164,10 @@ init([]) ->
{attributes, record_info(fields, s2s)}]),
mnesia:add_table_copy(s2s, node(), ram_copies),
mnesia:subscribe(system),
ejabberd_commands:register_commands(commands()),
ejabberd_ctl:register_commands(
[{"incoming-s2s-number", "print number of incoming s2s connections on the node"},
{"outgoing-s2s-number", "print number of outgoing s2s connections on the node"}],
?MODULE, ctl_process),
{ok, #state{}}.
%%--------------------------------------------------------------------
@@ -221,7 +221,6 @@ handle_info(_Info, State) ->
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ejabberd_commands:unregister_commands(commands()),
ok.
%%--------------------------------------------------------------------
@@ -251,17 +250,12 @@ do_route(From, To, Packet) ->
?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n",
[From, To, Packet, 8]),
case find_connection(From, To) of
{atomic, Pid} when is_pid(Pid) ->
{atomic, Pid} when pid(Pid) ->
?DEBUG("sending to process ~p~n", [Pid]),
{xmlelement, Name, Attrs, Els} = Packet,
NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
#jid{lserver = MyServer} = From,
ejabberd_hooks:run(
s2s_send_packet,
MyServer,
[From, To, Packet]),
send_element(Pid, {xmlelement, Name, NewAttrs, Els}),
ok;
{aborted, _Reason} ->
@@ -428,35 +422,16 @@ is_subdomain(Domain1, Domain2) ->
send_element(Pid, El) ->
Pid ! {send_element, El}.
%%%----------------------------------------------------------------------
%%% ejabberd commands
commands() ->
[
#ejabberd_commands{name = incoming_s2s_number,
tags = [stats, s2s],
desc = "Number of incoming s2s connections on the node",
module = ?MODULE, function = incoming_s2s_number,
args = [],
result = {s2s_incoming, integer}},
#ejabberd_commands{name = outgoing_s2s_number,
tags = [stats, s2s],
desc = "Number of outgoing s2s connections on the node",
module = ?MODULE, function = outgoing_s2s_number,
args = [],
result = {s2s_outgoing, integer}}
].
incoming_s2s_number() ->
length(supervisor:which_children(ejabberd_s2s_in_sup)).
outgoing_s2s_number() ->
length(supervisor:which_children(ejabberd_s2s_out_sup)).
%%%----------------------------------------------------------------------
%%% Update Mnesia tables
ctl_process(_Val, ["incoming-s2s-number"]) ->
N = length(supervisor:which_children(ejabberd_s2s_in_sup)),
?PRINT("~p~n", [N]),
{stop, ?STATUS_SUCCESS};
ctl_process(_Val, ["outgoing-s2s-number"]) ->
N = length(supervisor:which_children(ejabberd_s2s_out_sup)),
?PRINT("~p~n", [N]),
{stop, ?STATUS_SUCCESS};
ctl_process(Val, _Args) ->
Val.
update_tables() ->
case catch mnesia:table_info(s2s, type) of
@@ -486,58 +461,13 @@ update_tables() ->
%% Check if host is in blacklist or white list
allow_host(MyServer, S2SHost) ->
case lists:filter(
fun(Host) ->
is_subdomain(MyServer, Host)
end, ?MYHOSTS) of
[MyHost|_] ->
allow_host1(MyHost, S2SHost);
[] ->
allow_host1(MyServer, S2SHost)
case ejabberd_config:get_local_option({{s2s_host, S2SHost},MyServer}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyServer}) of
deny -> false;
allow -> true;
_ -> true %% The default s2s policy is allow
end
end.
allow_host1(MyHost, S2SHost) ->
case ejabberd_config:get_local_option({{s2s_host, S2SHost}, MyHost}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyHost}) of
deny -> false;
_ ->
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
allow, [MyHost, S2SHost]) of
deny -> false;
allow -> true;
_ -> true
end
end
end.
%% Get information about S2S connections of the specified type.
%% @spec (Type) -> [Info]
%% where Type = in | out
%% Info = [{InfoName::atom(), InfoValue::any()}]
get_info_s2s_connections(Type) ->
ChildType = case Type of
in -> ejabberd_s2s_in_sup;
out -> ejabberd_s2s_out_sup
end,
Connections = supervisor:which_children(ChildType),
get_s2s_info(Connections,Type).
get_s2s_info(Connections,Type)->
complete_s2s_info(Connections,Type,[]).
complete_s2s_info([],_,Result)->
Result;
complete_s2s_info([Connection|T],Type,Result)->
{_,PID,_,_}=Connection,
State = get_s2s_state(PID),
complete_s2s_info(T,Type,[State|Result]).
get_s2s_state(S2sPid)->
Infos = case gen_fsm:sync_send_all_state_event(S2sPid,get_state_infos) of
{state_infos, Is} -> [{status, open} | Is];
{noproc,_} -> [{status, closed}]; %% Connection closed
{badrpc,_} -> [{status, error}]
end,
[{s2s_pid, S2sPid} | Infos].
+2 -48
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -412,10 +412,6 @@ stream_established({xmlstreamelement, El}, StateData) ->
if ((Name == "iq") or
(Name == "message") or
(Name == "presence")) ->
ejabberd_hooks:run(
s2s_receive_packet,
LTo,
[From, To, NewEl]),
ejabberd_router:route(
From, To, NewEl);
true ->
@@ -431,10 +427,6 @@ stream_established({xmlstreamelement, El}, StateData) ->
if ((Name == "iq") or
(Name == "message") or
(Name == "presence")) ->
ejabberd_hooks:run(
s2s_receive_packet,
LTo,
[From, To, NewEl]),
ejabberd_router:route(
From, To, NewEl);
true ->
@@ -518,44 +510,6 @@ stream_established(closed, StateData) ->
%%----------------------------------------------------------------------
handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData}.
%%----------------------------------------------------------------------
%% Func: handle_sync_event/4
%% Returns: The associated StateData for this connection
%% {reply, Reply, NextStateName, NextStateData}
%% Reply = {state_infos, [{InfoName::atom(), InfoValue::any()]
%%----------------------------------------------------------------------
handle_sync_event(get_state_infos, _From, StateName, StateData) ->
SockMod = StateData#state.sockmod,
{Addr,Port} = try SockMod:peername(StateData#state.socket) of
{ok, {A,P}} -> {A,P};
{error, _} -> {unknown,unknown}
catch
_:_ -> {unknown,unknown}
end,
Domains = case StateData#state.authenticated of
true ->
[StateData#state.auth_domain];
false ->
Connections = StateData#state.connections,
[D || {{D, _}, established} <-
dict:to_list(Connections)]
end,
Infos = [
{direction, in},
{statename, StateName},
{addr, Addr},
{port, Port},
{streamid, StateData#state.streamid},
{tls, StateData#state.tls},
{tls_enabled, StateData#state.tls_enabled},
{tls_options, StateData#state.tls_options},
{authenticated, StateData#state.authenticated},
{shaper, StateData#state.shaper},
{sockmod, SockMod},
{domains, Domains}
],
Reply = {state_infos, Infos},
{reply,Reply,StateName,StateData};
%%----------------------------------------------------------------------
%% Func: handle_sync_event/4
+46 -186
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -52,8 +52,7 @@
handle_info/3,
terminate/3,
code_change/4,
test_get_addr_port/1,
get_addr_port/1]).
test_get_addr_port/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -84,17 +83,17 @@
%% Module start with or without supervisor:
-ifdef(NO_TRANSIENT_SUPERVISORS).
-define(SUPERVISOR_START, p1_fsm:start(ejabberd_s2s_out, [From, Host, Type],
fsm_limit_opts() ++ ?FSMOPTS)).
?FSMLIMITS ++ ?FSMOPTS)).
-else.
-define(SUPERVISOR_START, supervisor:start_child(ejabberd_s2s_out_sup,
[From, Host, Type])).
-endif.
%% Only change this value if you now what your are doing:
-define(FSMLIMITS,[]).
%% -define(FSMLIMITS, [{max_queue, 2000}]).
-define(FSMTIMEOUT, 30000).
%% We do not block on send anymore.
-define(TCP_SEND_TIMEOUT, 15000).
%% Maximum delay to wait before retrying to connect after a failed attempt.
%% Specified in miliseconds. Default value is 5 minutes.
-define(MAX_RETRY_DELAY, 300000).
@@ -119,8 +118,6 @@
-define(INVALID_XML_ERR,
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
-define(SOCKET_DEFAULT_RESULT, {error, badarg}).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
@@ -129,7 +126,7 @@ start(From, Host, Type) ->
start_link(From, Host, Type) ->
p1_fsm:start_link(ejabberd_s2s_out, [From, Host, Type],
fsm_limit_opts() ++ ?FSMOPTS).
?FSMLIMITS ++ ?FSMOPTS).
start_connection(Pid) ->
p1_fsm:send_event(Pid, init).
@@ -208,7 +205,7 @@ open_socket(init, StateData) ->
_ ->
open_socket1(Addr, Port)
end
end, ?SOCKET_DEFAULT_RESULT, AddrList) of
end, {error, badarg}, AddrList) of
{ok, Socket} ->
Version = if
StateData#state.use_v10 ->
@@ -241,47 +238,34 @@ open_socket(_, StateData) ->
{next_state, open_socket, StateData}.
%%----------------------------------------------------------------------
%% IPv4
open_socket1({_,_,_,_} = Addr, Port) ->
open_socket2(inet, Addr, Port);
%% IPv6
open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) ->
open_socket2(inet6, Addr, Port);
%% Hostname
open_socket1(Host, Port) ->
lists:foldl(fun(_Family, {ok, _Socket} = R) ->
R;
(Family, _) ->
Addrs = get_addrs(Host, Family),
lists:foldl(fun(_Addr, {ok, _Socket} = R) ->
R;
(Addr, _) ->
open_socket1(Addr, Port)
end, ?SOCKET_DEFAULT_RESULT, Addrs)
end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()).
open_socket2(Type, Addr, Port) ->
?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
Timeout = outgoing_s2s_timeout(),
SockOpts = try erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true}];
false -> []
catch
_:_ -> []
end,
case (catch ejabberd_socket:connect(Addr, Port,
[binary, {packet, 0},
{send_timeout, ?TCP_SEND_TIMEOUT},
{active, false}, Type | SockOpts],
Timeout)) of
{ok, _Socket} = R -> R;
{error, Reason} = R ->
?DEBUG("s2s_out: connect return ~p~n", [Reason]),
R;
open_socket1(Addr, Port) ->
?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]),
Res = case catch ejabberd_socket:connect(
Addr, Port,
[binary, {packet, 0},
{active, false}]) of
{ok, _Socket} = R -> R;
{error, Reason1} ->
?DEBUG("s2s_out: connect return ~p~n", [Reason1]),
catch ejabberd_socket:connect(
Addr, Port,
[binary, {packet, 0},
{active, false}, inet6]);
{'EXIT', Reason1} ->
?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]),
catch ejabberd_socket:connect(
Addr, Port,
[binary, {packet, 0},
{active, false}, inet6])
end,
case Res of
{ok, Socket} ->
{ok, Socket};
{error, Reason} ->
?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
{error, Reason};
{'EXIT', Reason} ->
?DEBUG("s2s_out: connect crashed ~p~n", [Reason]),
?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]),
{error, Reason}
end.
@@ -299,12 +283,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
{next_state, wait_for_features, StateData, ?FSMTIMEOUT};
{"jabber:server", "", true} when StateData#state.use_v10 ->
{next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT};
{NSProvided, DB, _} ->
_ ->
send_text(StateData, ?INVALID_NAMESPACE_ERR),
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace).~n"
"Namespace provided: ~p~nNamespace expected: \"jabber:server\"~n"
"xmlns:db provided: ~p~nAll attributes: ~p",
[StateData#state.myname, StateData#state.server, NSProvided, DB, Attrs]),
?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)",
[StateData#state.myname, StateData#state.server]),
{stop, normal, StateData}
end;
@@ -315,11 +297,6 @@ wait_for_stream({xmlstreamerror, _}, StateData) ->
[StateData#state.myname, StateData#state.server]),
{stop, normal, StateData};
wait_for_stream({xmlstreamend,_Name}, StateData) ->
?INFO_MSG("Closing s2s connection: ~s -> ~s (xmlstreamend)",
[StateData#state.myname, StateData#state.server]),
{stop, normal, StateData};
wait_for_stream(timeout, StateData) ->
?INFO_MSG("Closing s2s connection: ~s -> ~s (timeout in wait_for_stream)",
[StateData#state.myname, StateData#state.server]),
@@ -703,7 +680,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
{next_state, stream_established, StateData};
stream_established({xmlstreamend, _Name}, StateData) ->
?INFO_MSG("Connection closed in stream established: ~s -> ~s (xmlstreamend)",
?INFO_MSG("stream established: ~s -> ~s (xmlstreamend)",
[StateData#state.myname, StateData#state.server]),
{stop, normal, StateData};
@@ -748,42 +725,6 @@ stream_established(closed, StateData) ->
handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData, get_timeout_interval(StateName)}.
%%----------------------------------------------------------------------
%% Func: handle_sync_event/4
%% Returns: The associated StateData for this connection
%% {reply, Reply, NextStateName, NextStateData}
%% Reply = {state_infos, [{InfoName::atom(), InfoValue::any()]
%%----------------------------------------------------------------------
handle_sync_event(get_state_infos, _From, StateName, StateData) ->
{Addr,Port} = try ejabberd_socket:peername(StateData#state.socket) of
{ok, {A,P}} -> {A,P};
{error, _} -> {unknown,unknown}
catch
_:_ ->
{unknown,unknown}
end,
Infos = [
{direction, out},
{statename, StateName},
{addr, Addr},
{port, Port},
{streamid, StateData#state.streamid},
{use_v10, StateData#state.use_v10},
{tls, StateData#state.tls},
{tls_required, StateData#state.tls_required},
{tls_enabled, StateData#state.tls_enabled},
{tls_options, StateData#state.tls_options},
{authenticated, StateData#state.authenticated},
{db_enabled, StateData#state.db_enabled},
{try_auth, StateData#state.try_auth},
{myname, StateData#state.myname},
{server, StateData#state.server},
{delay_to_retry, StateData#state.delay_to_retry},
{verify, StateData#state.verify}
],
Reply = {state_infos, Infos},
{reply,Reply,StateName,StateData};
%%----------------------------------------------------------------------
%% Func: handle_sync_event/4
%% Returns: {next_state, NextStateName, NextStateData} |
@@ -1000,7 +941,11 @@ is_verify_res(_) ->
-include_lib("kernel/include/inet.hrl").
get_addr_port(Server) ->
Res = srv_lookup(Server),
Res = case inet_res:getbyname("_xmpp-server._tcp." ++ Server, srv) of
{error, _Reason} ->
inet_res:getbyname("_jabber._tcp." ++ Server, srv);
{ok, _HEnt} = R -> R
end,
case Res of
{error, Reason} ->
?DEBUG("srv lookup of '~s' failed: ~p~n", [Server, Reason]),
@@ -1024,7 +969,7 @@ get_addr_port(Server) ->
end,
{Priority * 65536 - N, Host, Port}
end, AddrList)) of
{'EXIT', _Reason} ->
{'EXIT', _Reasn} ->
[{Server, outgoing_s2s_port()}];
SortedList ->
List = lists:map(
@@ -1037,36 +982,6 @@ get_addr_port(Server) ->
end
end.
srv_lookup(Server) ->
Options = case ejabberd_config:get_local_option(s2s_dns_options) of
L when is_list(L) -> L;
_ -> []
end,
TimeoutMs = timer:seconds(proplists:get_value(timeout, Options, 10)),
Retries = proplists:get_value(retries, Options, 2),
srv_lookup(Server, TimeoutMs, Retries).
%% XXX - this behaviour is suboptimal in the case that the domain
%% has a "_xmpp-server._tcp." but not a "_jabber._tcp." record and
%% we don't get a DNS reply for the "_xmpp-server._tcp." lookup. In this
%% case we'll give up when we get the "_jabber._tcp." nxdomain reply.
srv_lookup(_Server, _Timeout, Retries) when Retries < 1 ->
{error, timeout};
srv_lookup(Server, Timeout, Retries) ->
case inet_res:getbyname("_xmpp-server._tcp." ++ Server, srv, Timeout) of
{error, _Reason} ->
case inet_res:getbyname("_jabber._tcp." ++ Server, srv, Timeout) of
{error, timeout} ->
?ERROR_MSG("The DNS servers~n ~p~ntimed out on request"
" for ~p IN SRV."
" You should check your DNS configuration.",
[inet_db:res_option(nameserver), Server]),
srv_lookup(Server, Timeout, Retries - 1);
R -> R
end;
{ok, _HEnt} = R -> R
end.
test_get_addr_port(Server) ->
lists:foldl(
fun(_, Acc) ->
@@ -1079,23 +994,6 @@ test_get_addr_port(Server) ->
end
end, [], lists:seq(1, 100000)).
get_addrs(Host, Family) ->
Type = case Family of
inet4 -> inet;
ipv4 -> inet;
inet6 -> inet6;
ipv6 -> inet6
end,
case inet:gethostbyname(Host, Type) of
{ok, #hostent{h_addr_list = Addrs}} ->
?DEBUG("~s of ~s resolved to: ~p~n", [Type, Host, Addrs]),
Addrs;
{error, Reason} ->
?DEBUG("~s lookup of '~s' failed: ~p~n", [Type, Host, Reason]),
[]
end.
outgoing_s2s_port() ->
case ejabberd_config:get_local_option(outgoing_s2s_port) of
Port when is_integer(Port) ->
@@ -1104,36 +1002,6 @@ outgoing_s2s_port() ->
5269
end.
outgoing_s2s_families() ->
case ejabberd_config:get_local_option(outgoing_s2s_options) of
{Families, _} when is_list(Families) ->
Families;
undefined ->
%% DISCUSSION: Why prefer IPv4 first?
%%
%% IPv4 connectivity will be available for everyone for
%% many years to come. So, there's absolutely no benefit
%% in preferring IPv6 connections which are flaky at best
%% nowadays.
%%
%% On the other hand content providers hesitate putting up
%% AAAA records for their sites due to the mentioned
%% quality of current IPv6 connectivity. Making IPv6 the a
%% `fallback' may avoid these problems elegantly.
[ipv4, ipv6]
end.
outgoing_s2s_timeout() ->
case ejabberd_config:get_local_option(outgoing_s2s_options) of
{_, Timeout} when is_integer(Timeout) ->
Timeout;
{_, infinity} ->
infinity;
undefined ->
%% 10 seconds
10000
end.
%% Human readable S2S logging: Log only new outgoing connections as INFO
%% Do not log dialback
log_s2s_out(false, _, _) -> ok;
@@ -1199,11 +1067,3 @@ terminate_if_waiting_delay(From, To) ->
Pid ! terminate_if_waiting_before_retry
end,
Pids).
fsm_limit_opts() ->
case ejabberd_config:get_local_option(max_fsm_queue) of
N when is_integer(N) ->
[{max_queue, N}];
_ ->
[]
end.
+5 -25
View File
@@ -5,7 +5,7 @@
%%% Created : 6 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -27,9 +27,7 @@
-module(ejabberd_service).
-author('alexey@process-one.net').
-define(GEN_FSM, p1_fsm).
-behaviour(?GEN_FSM).
-behaviour(gen_fsm).
%% External exports
-export([start/2,
@@ -82,11 +80,7 @@
).
-define(INVALID_HANDSHAKE_ERR,
"<stream:error>"
"<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
"<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='en'>"
"Invalid Handshake</text>"
"</stream:error>"
"<stream:error>Invalid Handshake</stream:error>"
"</stream:stream>"
).
@@ -102,8 +96,7 @@ start(SockData, Opts) ->
supervisor:start_child(ejabberd_service_sup, [SockData, Opts]).
start_link(SockData, Opts) ->
?GEN_FSM:start_link(ejabberd_service, [SockData, Opts],
fsm_limit_opts(Opts) ++ ?FSMOPTS).
gen_fsm:start_link(ejabberd_service, [SockData, Opts], ?FSMOPTS).
socket_type() ->
xml_stream.
@@ -386,16 +379,3 @@ send_element(StateData, El) ->
new_id() ->
randoms:get_string().
fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) ->
[{max_queue, N}];
_ ->
case ejabberd_config:get_local_option(max_fsm_queue) of
N when is_integer(N) ->
[{max_queue, N}];
_ ->
[]
end
end.
+32 -129
View File
@@ -5,7 +5,7 @@
%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -43,13 +43,10 @@
dirty_get_sessions_list/0,
dirty_get_my_sessions_list/0,
get_vh_session_list/1,
get_vh_session_number/1,
register_iq_handler/4,
register_iq_handler/5,
unregister_iq_handler/2,
connected_users/0,
connected_users_number/0,
user_resources/2,
ctl_process/2,
get_session_pid/3,
get_user_info/3,
get_user_ip/3
@@ -61,11 +58,9 @@
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("ejabberd_commands.hrl").
-include("mod_privacy.hrl").
-include("ejabberd_ctl.hrl").
-record(session, {sid, usr, us, priority, info}).
-record(session_counter, {vhost, count}).
-record(state, {}).
%% default value for the maximum number of user connections
@@ -92,7 +87,6 @@ route(From, To, Packet) ->
open_session(SID, User, Server, Resource, Info) ->
set_session(SID, User, Server, Resource, undefined, Info),
inc_session_counter(jlib:nameprep(Server)),
check_for_sessions_to_replace(User, Server, Resource),
JID = jlib:make_jid(User, Server, Resource),
ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver,
@@ -104,8 +98,7 @@ close_session(SID, User, Server, Resource) ->
[#session{info=I}] -> I
end,
F = fun() ->
mnesia:delete({session, SID}),
dec_session_counter(jlib:nameprep(Server))
mnesia:delete({session, SID})
end,
mnesia:sync_dirty(F),
JID = jlib:make_jid(User, Server, Resource),
@@ -218,19 +211,6 @@ get_vh_session_list(Server) ->
[{'==', {element, 2, '$1'}, LServer}],
['$1']}]).
get_vh_session_number(Server) ->
LServer = jlib:nameprep(Server),
Query = mnesia:dirty_select(
session_counter,
[{#session_counter{vhost = LServer, count = '$1'},
[],
['$1']}]),
case Query of
[Count] ->
Count;
_ -> 0
end.
register_iq_handler(Host, XMLNS, Module, Fun) ->
ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}.
@@ -257,9 +237,6 @@ init([]) ->
mnesia:create_table(session,
[{ram_copies, [node()]},
{attributes, record_info(fields, session)}]),
mnesia:create_table(session_counter,
[{ram_copies, [node()]},
{attributes, record_info(fields, session_counter)}]),
mnesia:add_table_index(session, usr),
mnesia:add_table_index(session, us),
mnesia:add_table_copy(session, node(), ram_copies),
@@ -274,7 +251,11 @@ init([]) ->
ejabberd_hooks:add(remove_user, Host,
ejabberd_sm, disconnect_removed_user, 100)
end, ?MYHOSTS),
ejabberd_commands:register_commands(commands()),
ejabberd_ctl:register_commands(
[{"connected-users", "list all established sessions"},
{"connected-users-number", "print a number of established sessions"},
{"user-resources user server", "print user's connected resources"}],
?MODULE, ctl_process),
{ok, #state{}}.
@@ -344,7 +325,6 @@ handle_info(_Info, State) ->
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ejabberd_commands:unregister_commands(commands()),
ok.
%%--------------------------------------------------------------------
@@ -381,8 +361,6 @@ clean_table_from_bad_node(Node) ->
[{'==', {node, '$1'}, Node}],
['$_']}]),
lists:foreach(fun(E) ->
{_, LServer} = E#session.us,
dec_session_counter(LServer),
mnesia:delete({session, E#session.sid})
end, Es)
end,
@@ -406,32 +384,28 @@ do_route(From, To, Packet) ->
Reason = xml:get_path_s(
Packet,
[{elem, "status"}, cdata]),
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
{ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, subscribe, Reason]),
true};
"subscribed" ->
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
{ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, subscribed, ""]),
true};
"unsubscribe" ->
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
{ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
[User, Server, From, unsubscribe, ""]),
true};
"unsubscribed" ->
{is_privacy_allow(From, To, Packet) andalso
ejabberd_hooks:run_fold(
{ejabberd_hooks:run_fold(
roster_in_subscription,
LServer,
false,
@@ -481,7 +455,7 @@ do_route(From, To, Packet) ->
_ ->
Err =
jlib:make_error_reply(
Packet, ?ERR_SERVICE_UNAVAILABLE),
Packet, ?ERR_RECIPIENT_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end;
_ ->
@@ -495,31 +469,6 @@ do_route(From, To, Packet) ->
end
end.
%% The default list applies to the user as a whole,
%% and is processed if there is no active list set
%% for the target session/resource to which a stanza is addressed,
%% or if there are no current sessions for the user.
is_privacy_allow(From, To, Packet) ->
User = To#jid.user,
Server = To#jid.server,
PrivacyList = ejabberd_hooks:run_fold(privacy_get_user_list, Server,
#userlist{}, [User, Server]),
is_privacy_allow(From, To, Packet, PrivacyList).
%% Check if privacy rules allow this delivery
%% Function copied from ejabberd_c2s.erl
is_privacy_allow(From, To, Packet, PrivacyList) ->
User = To#jid.user,
Server = To#jid.server,
allow == ejabberd_hooks:run_fold(
privacy_check_packet, Server,
allow,
[User,
Server,
PrivacyList,
{From, To, Packet},
in]).
route_message(From, To, Packet) ->
LUser = To#jid.luser,
LServer = To#jid.lserver,
@@ -663,33 +612,6 @@ get_max_user_sessions(LUser, Host) ->
_ -> ?MAX_USER_SESSIONS
end.
inc_session_counter(LServer) ->
F = fun() ->
case mnesia:wread({session_counter, LServer}) of
[C] ->
Count = C#session_counter.count + 1,
C2 = C#session_counter{count = Count},
mnesia:write(C2);
_ ->
mnesia:write(#session_counter{vhost = LServer,
count = 1})
end
end,
mnesia:sync_dirty(F).
dec_session_counter(LServer) ->
F = fun() ->
case mnesia:wread({session_counter, LServer}) of
[C] ->
Count = C#session_counter.count - 1,
C2 = C#session_counter{count = Count},
mnesia:write(C2);
_ ->
error
end
end,
mnesia:sync_dirty(F).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -725,47 +647,28 @@ process_iq(From, To, Packet) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% ejabberd commands
commands() ->
[
#ejabberd_commands{name = connected_users,
tags = [session],
desc = "List all established sessions",
module = ?MODULE, function = connected_users,
args = [],
result = {connected_users, {list, {sessions, string}}}},
#ejabberd_commands{name = connected_users_number,
tags = [session, stats],
desc = "Get the number of established sessions",
module = ?MODULE, function = connected_users_number,
args = [],
result = {num_sessions, integer}},
#ejabberd_commands{name = user_resources,
tags = [session],
desc = "List user's connected resources",
module = ?MODULE, function = user_resources,
args = [{user, string}, {host, string}],
result = {resources, {list, {resource, string}}}}
].
connected_users() ->
ctl_process(_Val, ["connected-users"]) ->
USRs = dirty_get_sessions_list(),
NewLine = io_lib:format("~n", []),
SUSRs = lists:sort(USRs),
lists:map(fun({U, S, R}) -> [U, $@, S, $/, R] end, SUSRs).
connected_users_number() ->
length(dirty_get_sessions_list()).
user_resources(User, Server) ->
FUSRs = lists:map(fun({U, S, R}) -> [U, $@, S, $/, R, NewLine] end, SUSRs),
?PRINT("~s", [FUSRs]),
{stop, ?STATUS_SUCCESS};
ctl_process(_Val, ["connected-users-number"]) ->
N = length(dirty_get_sessions_list()),
?PRINT("~p~n", [N]),
{stop, ?STATUS_SUCCESS};
ctl_process(_Val, ["user-resources", User, Server]) ->
Resources = get_user_resources(User, Server),
lists:sort(Resources).
NewLine = io_lib:format("~n", []),
SResources = lists:sort(Resources),
FResources = lists:map(fun(R) -> [R, NewLine] end, SResources),
?PRINT("~s", [FResources]),
{stop, ?STATUS_SUCCESS};
ctl_process(Val, _Args) ->
Val.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Update Mnesia tables
update_tables() ->
case catch mnesia:table_info(session, attributes) of
[ur, user, node] ->
+14 -58
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -30,14 +30,12 @@
%% API
-export([start/4,
connect/3,
connect/4,
starttls/2,
starttls/3,
compress/1,
compress/2,
reset_stream/1,
send/2,
send_xml/2,
change_shaper/2,
monitor/1,
get_sockmod/1,
@@ -46,15 +44,13 @@
close/1,
sockname/1, peername/1]).
-include("ejabberd.hrl").
-record(socket_state, {sockmod, socket, receiver}).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function:
%% Function:
%% Description:
%%--------------------------------------------------------------------
start(Module, SockMod, Socket, Opts) ->
@@ -65,18 +61,10 @@ start(Module, SockMod, Socket, Opts) ->
{value, {_, Size}} -> Size;
_ -> infinity
end,
{ReceiverMod, Receiver, RecRef} =
case catch SockMod:custom_receiver(Socket) of
{receiver, RecMod, RecPid} ->
{RecMod, RecPid, RecMod};
_ ->
RecPid = ejabberd_receiver:start(
Socket, SockMod, none, MaxStanzaSize),
{ejabberd_receiver, RecPid, RecPid}
end,
Receiver = ejabberd_receiver:start(Socket, SockMod, none, MaxStanzaSize),
SocketData = #socket_state{sockmod = SockMod,
socket = Socket,
receiver = RecRef},
receiver = Receiver},
case Module:start({?MODULE, SocketData}, Opts) of
{ok, Pid} ->
case SockMod:controlling_process(Socket, Receiver) of
@@ -85,12 +73,10 @@ start(Module, SockMod, Socket, Opts) ->
{error, _Reason} ->
SockMod:close(Socket)
end,
ReceiverMod:become_controller(Receiver, Pid);
ejabberd_receiver:become_controller(Receiver, Pid);
{error, _Reason} ->
SockMod:close(Socket)
end;
independent ->
ok;
raw ->
case Module:start({SockMod, Socket}, Opts) of
{ok, Pid} ->
@@ -106,10 +92,7 @@ start(Module, SockMod, Socket, Opts) ->
end.
connect(Addr, Port, Opts) ->
connect(Addr, Port, Opts, infinity).
connect(Addr, Port, Opts, Timeout) ->
case gen_tcp:connect(Addr, Port, Opts, Timeout) of
case gen_tcp:connect(Addr, Port, Opts) of
{ok, Socket} ->
Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
SocketData = #socket_state{sockmod = gen_tcp,
@@ -154,45 +137,18 @@ compress(SocketData, Data) ->
send(SocketData, Data),
SocketData#socket_state{socket = ZlibSocket, sockmod = ejabberd_zlib}.
reset_stream(SocketData) when is_pid(SocketData#socket_state.receiver) ->
ejabberd_receiver:reset_stream(SocketData#socket_state.receiver);
reset_stream(SocketData) when is_atom(SocketData#socket_state.receiver) ->
(SocketData#socket_state.receiver):reset_stream(
SocketData#socket_state.socket).
reset_stream(SocketData) ->
ejabberd_receiver:reset_stream(SocketData#socket_state.receiver).
%% sockmod=gen_tcp|tls|ejabberd_zlib
send(SocketData, Data) ->
case catch (SocketData#socket_state.sockmod):send(
SocketData#socket_state.socket, Data) of
ok -> ok;
{error, timeout} ->
?INFO_MSG("Timeout on ~p:send",[SocketData#socket_state.sockmod]),
exit(normal);
Error ->
?DEBUG("Error in ~p:send: ~p",[SocketData#socket_state.sockmod, Error]),
exit(normal)
end.
%% Can only be called when in c2s StateData#state.xml_socket is true
%% This function is used for HTTP bind
%% sockmod=ejabberd_http_poll|ejabberd_http_bind or any custom module
send_xml(SocketData, Data) ->
catch (SocketData#socket_state.sockmod):send_xml(
catch (SocketData#socket_state.sockmod):send(
SocketData#socket_state.socket, Data).
change_shaper(SocketData, Shaper)
when is_pid(SocketData#socket_state.receiver) ->
ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper);
change_shaper(SocketData, Shaper)
when is_atom(SocketData#socket_state.receiver) ->
(SocketData#socket_state.receiver):change_shaper(
SocketData#socket_state.socket, Shaper).
change_shaper(SocketData, Shaper) ->
ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper).
monitor(SocketData) when is_pid(SocketData#socket_state.receiver) ->
erlang:monitor(process, SocketData#socket_state.receiver);
monitor(SocketData) when is_atom(SocketData#socket_state.receiver) ->
(SocketData#socket_state.receiver):monitor(
SocketData#socket_state.socket).
monitor(SocketData) ->
erlang:monitor(process, SocketData#socket_state.receiver).
get_sockmod(SocketData) ->
SocketData#socket_state.sockmod.
+2 -19
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -84,13 +84,6 @@ init([]) ->
brutal_kill,
worker,
[ejabberd_local]},
Captcha =
{ejabberd_captcha,
{ejabberd_captcha, start_link, []},
permanent,
brutal_kill,
worker,
[ejabberd_captcha]},
Listener =
{ejabberd_listener,
{ejabberd_listener, start_link, []},
@@ -169,14 +162,6 @@ init([]) ->
infinity,
supervisor,
[ejabberd_tmp_sup]},
STUNSupervisor =
{ejabberd_stun_sup,
{ejabberd_tmp_sup, start_link,
[ejabberd_stun_sup, ejabberd_stun]},
permanent,
infinity,
supervisor,
[ejabberd_tmp_sup]},
{ok, {{one_for_one, 10, 1},
[Hooks,
NodeGroups,
@@ -185,7 +170,6 @@ init([]) ->
SM,
S2S,
Local,
Captcha,
ReceiverSupervisor,
C2SSupervisor,
S2SInSupervisor,
@@ -194,7 +178,6 @@ init([]) ->
HTTPSupervisor,
HTTPPollSupervisor,
IQSupervisor,
STUNSupervisor,
FrontendSocketSupervisor,
Listener]}}.
+7 -44
View File
@@ -5,7 +5,7 @@
%%% Created : 21 Mar 2007 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -51,12 +51,7 @@
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
LH = case ejabberd_config:get_local_option(watchdog_large_heap) of
I when is_integer(I) -> I;
_ -> 1000000
end,
Opts = [{large_heap, LH}],
gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []).
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
process_command(From, To, Packet) ->
case To of
@@ -95,10 +90,9 @@ process_command(From, To, Packet) ->
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init(Opts) ->
LH = proplists:get_value(large_heap, Opts),
init([]) ->
process_flag(priority, high),
erlang:system_monitor(self(), [{large_heap, LH}]),
erlang:system_monitor(self(), [{large_heap, 1000000}]),
lists:foreach(
fun(Host) ->
ejabberd_hooks:add(local_send_to_resource_hook, Host,
@@ -115,24 +109,10 @@ init(Opts) ->
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({get, large_heap}, _From, State) ->
{reply, get_large_heap(), State};
handle_call({set, large_heap, NewValue}, _From, State) ->
MonSettings = erlang:system_monitor(self(), [{large_heap, NewValue}]),
OldLH = get_large_heap(MonSettings),
NewLH = get_large_heap(),
{reply, {lh_changed, OldLH, NewLH}, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
get_large_heap() ->
MonSettings = erlang:system_monitor(),
get_large_heap(MonSettings).
get_large_heap(MonSettings) ->
{_MonitorPid, Options} = MonSettings,
proplists:get_value(large_heap, Options).
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
@@ -185,7 +165,7 @@ process_large_heap(Pid, Info) ->
JIDs /= [] ->
DetailedInfo = detailed_info(Pid),
Body = io_lib:format(
"(~w) The process ~w is consuming too much memory:~n~p~n"
"(~w) The process ~w is consuming too much memory: ~w.~n"
"~s",
[node(), Pid, Info, DetailedInfo]),
From = jlib:make_jid("", Host, "watchdog"),
@@ -323,25 +303,14 @@ process_command1(From, To, Body) ->
process_command2(["kill", SNode, SPid], From, To) ->
Node = list_to_atom(SNode),
remote_command(Node, [kill, SPid], From, To);
process_command2(["showlh", SNode], From, To) ->
Node = list_to_atom(SNode),
remote_command(Node, [showlh], From, To);
process_command2(["setlh", SNode, NewValueString], From, To) ->
Node = list_to_atom(SNode),
NewValue = list_to_integer(NewValueString),
remote_command(Node, [setlh, NewValue], From, To);
process_command2(["help"], From, To) ->
send_message(To, From, help());
process_command2(_, From, To) ->
send_message(To, From, help()).
help() ->
"Commands:\n"
" kill <node> <pid>\n"
" showlh <node>\n"
" setlh <node> <integer>".
" kill <node> <pid>".
remote_command(Node, Args, From, To) ->
Message =
@@ -356,12 +325,6 @@ remote_command(Node, Args, From, To) ->
process_remote_command([kill, SPid]) ->
exit(list_to_pid(SPid), kill),
"ok";
process_remote_command([showlh]) ->
Res = gen_server:call(ejabberd_system_monitor, {get, large_heap}),
io_lib:format("Current large heap: ~p", [Res]);
process_remote_command([setlh, NewValue]) ->
{lh_changed, OldLH, NewLH} = gen_server:call(ejabberd_system_monitor, {set, large_heap, NewValue}),
io_lib:format("Result of set large heap: ~p --> ~p", [OldLH, NewLH]);
process_remote_command(_) ->
throw(unknown_command).
+2 -2
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jul 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+33 -78
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -28,15 +28,13 @@
-author('alexey@process-one.net').
%% API
-export([update/0, update/1, update_info/0]).
-export([update/0, update_info/0]).
-include("ejabberd.hrl").
%%====================================================================
%% API
%%====================================================================
%% Update all the modified modules
update() ->
case update_info() of
{ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} ->
@@ -50,91 +48,48 @@ update() ->
{error, Reason}
end.
%% Update only the specified modules
update(ModulesToUpdate) ->
case update_info() of
{ok, Dir, UpdatedBeamsAll, _Script, _LowLevelScript, _Check} ->
UpdatedBeamsNow =
[A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B],
{_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow),
Eval =
release_handler_1:eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("eval: ~p~n", [Eval]),
Eval;
{error, Reason} ->
{error, Reason}
end.
%% Get information about the modified modules
update_info() ->
Dir = filename:dirname(code:which(ejabberd)),
case file:list_dir(Dir) of
{ok, Files} ->
update_info(Dir, Files);
Beams = [list_to_atom(filename:rootname(FN)) ||
FN <- Files, lists:suffix(".beam", FN)],
UpdatedBeams =
lists:filter(
fun(Module) ->
{ok, {Module, NewVsn}} =
beam_lib:version(code:which(Module)),
case code:is_loaded(Module) of
{file, _} ->
Attrs = Module:module_info(attributes),
{value, {vsn, CurVsn}} =
lists:keysearch(vsn, 1, Attrs),
NewVsn /= CurVsn;
false ->
false
end
end, Beams),
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
Script = make_script(UpdatedBeams),
?INFO_MSG("script: ~p~n", [Script]),
LowLevelScript = make_low_level_script(UpdatedBeams, Script),
?INFO_MSG("low level script: ~p~n", [LowLevelScript]),
Check =
release_handler_1:check_script(
LowLevelScript,
[{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("check: ~p~n", [Check]),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check};
{error, Reason} ->
{error, Reason}
end.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
update_info(Dir, Files) ->
Beams = lists:sort(get_beams(Files)),
UpdatedBeams = get_updated_beams(Beams),
?INFO_MSG("beam files: ~p~n", [UpdatedBeams]),
{Script, LowLevelScript, Check} = build_script(Dir, UpdatedBeams),
{ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}.
get_beams(Files) ->
[list_to_atom(filename:rootname(FN))
|| FN <- Files, lists:suffix(".beam", FN)].
%% Return only the beams that have different version
get_updated_beams(Beams) ->
lists:filter(
fun(Module) ->
NewVsn = get_new_version(Module),
case code:is_loaded(Module) of
{file, _} ->
CurVsn = get_current_version(Module),
(NewVsn /= CurVsn
andalso NewVsn /= unknown_version);
false ->
false
end
end, Beams).
get_new_version(Module) ->
Path = code:which(Module),
VersionRes = beam_lib:version(Path),
case VersionRes of
{ok, {Module, NewVsn}} -> NewVsn;
%% If a m1.erl has -module("m2"):
_ -> unknown_version
end.
get_current_version(Module) ->
Attrs = Module:module_info(attributes),
{value, {vsn, CurVsn}} = lists:keysearch(vsn, 1, Attrs),
CurVsn.
%% @spec(Dir::string(), UpdatedBeams::[atom()]) -> {Script,LowLevelScript,Check}
build_script(Dir, UpdatedBeams) ->
Script = make_script(UpdatedBeams),
?INFO_MSG("script: ~p~n", [Script]),
LowLevelScript = make_low_level_script(UpdatedBeams, Script),
?INFO_MSG("low level script: ~p~n", [LowLevelScript]),
Check =
release_handler_1:check_script(
LowLevelScript,
[{ejabberd, "", filename:join(Dir, "..")}]),
?INFO_MSG("check: ~p~n", [Check]),
{Script, LowLevelScript, Check}.
%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl
%% From systools.hrl
-record(application,
{name, %% Name of the application, atom().
type = permanent, %% Application start type, atom().
+11 -19
View File
@@ -12,21 +12,17 @@ ZLIB_LIBS = @ZLIB_LIBS@
ERLANG_CFLAGS = @ERLANG_CFLAGS@
ERLANG_LIBS = @ERLANG_LIBS@
# Assume Linux-style dynamic library flags
DYNAMIC_LIB_CFLAGS = -fpic -shared
ifeq ($(shell uname),Darwin)
DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress
endif
ifeq ($(shell uname),SunOs)
DYNAMIC_LIB_CFLAGS = -KPIC -G -z text
DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress
else
# Assume Linux-style dynamic library flags
DYNAMIC_LIB_CFLAGS = -fpic -shared
endif
EFLAGS += -I ..
EFLAGS += -pz ..
EFLAGS = -I .. -pz ..
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
ERLSHLIBS = ../ejabberd_zlib_drv.so
@@ -43,15 +39,11 @@ $(OUTDIR)/%.beam: %.erl
# erl -s make all report "{outdir, \"..\"}" -noinput -s erlang halt
$(ERLSHLIBS): ../%.so: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) \
$(subst ../,,$(subst .so,.c,$@)) \
$(LIBS) \
$(ZLIB_LIBS) \
$(ZLIB_CFLAGS) \
$(ERLANG_LIBS) \
$(ERLANG_CFLAGS) \
-o $@ \
$(DYNAMIC_LIB_CFLAGS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) \
$(subst ../,,$(subst .so,.c,$@)) $(LIBS) \
$(ZLIB_LIBS) $(ZLIB_CFLAGS) \
$(ERLANG_LIBS) $(ERLANG_CFLAGS) \
-o $@ $(DYNAMIC_LIB_CFLAGS)
clean:
rm -f $(BEAMS) $(ERLSHLIBS)
+2 -1
View File
@@ -4,7 +4,8 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
BEAMS = ..\ejabberd_zlib.beam
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
SOURCE = ejabberd_zlib_drv.c
OBJECT = ejabberd_zlib_drv.o
+4 -29
View File
@@ -5,7 +5,7 @@
%%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -35,7 +35,6 @@
recv/2, recv/3, recv_data/2,
setopts/2,
sockname/1, peername/1,
get_sockmod/1,
controlling_process/2,
close/1]).
@@ -101,7 +100,7 @@ enable_zlib(SockMod, Socket) ->
end,
Port = open_port({spawn, ejabberd_zlib_drv}, [binary]),
{ok, #zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}}.
disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
port_close(Port),
{SockMod, Socket}.
@@ -117,28 +116,7 @@ recv(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock,
Error
end.
recv_data(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock, Packet) ->
case SockMod of
gen_tcp ->
recv_data2(ZlibSock, Packet);
_ ->
case SockMod:recv_data(Socket, Packet) of
{ok, Packet2} ->
recv_data2(ZlibSock, Packet2);
Error ->
Error
end
end.
recv_data2(ZlibSock, Packet) ->
case catch recv_data1(ZlibSock, Packet) of
{'EXIT', Reason} ->
{error, Reason};
Res ->
Res
end.
recv_data1(#zlibsock{zlibport = Port} = _ZlibSock, Packet) ->
recv_data(#zlibsock{zlibport = Port} = _ZlibSock, Packet) ->
case port_control(Port, ?INFLATE, Packet) of
<<0, In/binary>> ->
{ok, In};
@@ -172,9 +150,6 @@ sockname(#zlibsock{sockmod = SockMod, socket = Socket}) ->
SockMod:sockname(Socket)
end.
get_sockmod(#zlibsock{sockmod = SockMod}) ->
SockMod.
peername(#zlibsock{sockmod = SockMod, socket = Socket}) ->
case SockMod of
gen_tcp ->
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* ejabberd, Copyright (C) 2002-2010 ProcessOne
* ejabberd, Copyright (C) 2002-2008 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -10,7 +10,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+11 -61
View File
@@ -1,22 +1,21 @@
#
# In this file you can configure options that are passed by ejabberdctl
# In this file you can configure options that are passed by ejabberdctl
# to the erlang runtime system when starting ejabberd
#
#' POLL: Kernel polling ([true|false])
# POLL: Kernel polling ([true|false])
#
# The kernel polling option requires support in the kernel.
# Additionally, you need to enable this feature while compiling Erlang.
# Additionaly, you need to enable this feature while compiling Erlang.
#
# Default: true
#
#POLL=true
#.
#' SMP: SMP support ([enable|auto|disable])
# SMP: SMP support ([enable|auto|disable])
#
# Explanation in Erlang/OTP documentation:
# enable: starts the Erlang runtime system with SMP support enabled.
# enable: starts the Erlang runtime system with SMP support enabled.
# This may fail if no runtime system with SMP support is available.
# auto: starts the Erlang runtime system with SMP support enabled if it
# is available and more than one logical processor are detected.
@@ -26,10 +25,9 @@
#
#SMP=auto
#.
#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
# ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
#
# ejabberd consumes two or three ports for every connection, either
# ejabberd consumes two or three ports for every connection, either
# from a client or from another Jabber server. So take this into
# account when setting this limit.
#
@@ -38,23 +36,10 @@
#
#ERL_MAX_PORTS=32000
#.
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
#
# If Ejabberd is configured to run in cluster, and a firewall is blocking ports,
# it's possible to make Erlang use a defined range of port (instead of dynamic
# ports) for node communication.
#
# Default: not defined
# Example: 4200-4210
#
#FIREWALL_WINDOW=
#.
#' PROCESSES: Maximum number of Erlang processes
# PROCESSES: Maximum number of Erlang processes
#
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
# on ejabberd so that the maximum number of processes is reached, people will
# on ejabberd so that the maximum number of proccesses is reached, people will
# experiment greater latency times. As these processes are implemented in
# Erlang, and therefore not related to the operating system processes, you do
# not have to worry about allowing a huge number of them.
@@ -64,8 +49,7 @@
#
#PROCESSES=250000
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
# ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
#
# The number of concurrent ETS and Mnesia tables is limited. When the limit is
# reached, errors will appear in the logs:
@@ -77,24 +61,6 @@
#
#ERL_MAX_ETS_TABLES=1400
#.
#' ERL_OPTIONS: Additional Erlang options
#
# The next variable allows to specify additional options passed to erlang while
# starting ejabberd. Some useful options are -noshell, -detached, -heart. When
# ejabberd is started from an init.d script options -noshell and -detached are
# added implicitly. See erl(1) for more info.
#
# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you
# want to add local modules in this path.
#
# Default: ""
#
#ERL_OPTIONS=""
#.
#' ERLANG_NODE: Erlang node name
#
# The next variable allows to explicitly specify erlang node for ejabberd
# It can be given in different formats:
# ERLANG_NODE=ejabberd
@@ -103,25 +69,9 @@
# Erlang uses node name as is (so make sure that hostname is a real
# machine hostname or you'll not be able to control ejabberd)
# ERLANG_NODE=ejabberd@hostname.domainname
# The same as previous, but erlang will use long hostname
# The same as previous, but erlang will use long hostname
# (see erl (1) manual for details)
#
# Default: ejabberd
#
#ERLANG_NODE=ejabberd
#.
#' EJABBERD_PID_PATH: ejabberd PID file
#
# Indicate the full path to the ejabberd Process identifier (PID) file.
# If this variable is defined, ejabberd writes the PID file when starts,
# and deletes it when stops.
# Remember to create the directory and grant write permission to ejabberd.
#
# Default: don't write PID file
#
#EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid
#.
#'
# vim: foldmarker=#',#. foldmethod=marker:
+53 -165
View File
@@ -12,7 +12,14 @@ NODE=ejabberd
HOST=localhost
ERLANG_NODE=$NODE@$HOST
ERL=@erl@
INSTALLUSER=@installuser@
ROOTDIR=@rootdir@
EJABBERD_CONFIG_PATH=$ROOTDIR/etc/ejabberd/ejabberd.cfg
LOGS_DIR=$ROOTDIR/var/log/ejabberd/
EJABBERD_DB=$ROOTDIR/var/lib/ejabberd/db/$NODE
# read custom configuration
CONFIG=$ROOTDIR/etc/ejabberd/ejabberdctl.cfg
[ -f "$CONFIG" ] && . "$CONFIG"
# parse command line parameters
ARGS=
@@ -21,98 +28,31 @@ while [ $# -ne 0 ] ; do
shift
case $PARAM in
--) break ;;
--node) ERLANG_NODE_ARG=$1; shift ;;
--config-dir) ETCDIR=$1 ; shift ;;
--node) ERLANG_NODE=$1; shift ;;
--config) EJABBERD_CONFIG_PATH=$1 ; shift ;;
--ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;;
--ctl-config) CONFIG=$1 ; shift ;;
--logs) LOGS_DIR=$1 ; shift ;;
--spool) SPOOLDIR=$1 ; shift ;;
--spool) EJABBERD_DB=$1 ; shift ;;
*) ARGS="$ARGS $PARAM" ;;
esac
done
# Define ejabberd variable if they have not been defined from the command line
if [ "$ETCDIR" = "" ] ; then
ETCDIR=@SYSCONFDIR@/ejabberd
fi
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
fi
if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then
EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg
fi
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
if [ "$LOGS_DIR" = "" ] ; then
LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd
fi
if [ "$SPOOLDIR" = "" ] ; then
SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd
fi
if [ "$EJABBERD_DOC_PATH" = "" ] ; then
EJABBERD_DOC_PATH=@DOCDIR@
fi
if [ "$ERLANG_NODE_ARG" != "" ] ; then
ERLANG_NODE=$ERLANG_NODE_ARG
fi
# check the proper system user is used
ID=`id -g`
GIDS=`id -G`
EJID=`id -g $INSTALLUSER`
EXEC_CMD="false"
for GID in $GIDS; do
if [ $GID -eq 0 ] ; then
EXEC_CMD="su ${INSTALLUSER} -p -c"
fi
done
if [ "$ID" -eq "$EJID" ] ; then
EXEC_CMD="sh -c"
fi
if [ "$EXEC_CMD" = "false" ] ; then
echo "This command can only be run by root or the user $INSTALLUSER" >&2
exit 1
fi
NAME=-name
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname
if [ "$FIREWALL_WINDOW" = "" ] ; then
KERNEL_OPTS=""
else
KERNEL_OPTS="-kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
fi
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS $KERNEL_OPTS"
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES"
# define additional environment variables
if [ "$EJABBERDDIR" = "" ]; then
EJABBERDDIR=@LIBDIR@/ejabberd
fi
if [ "$EJABBERD_EBIN_PATH" = "" ]; then
EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin
fi
if [ "$EJABBERD_PRIV_PATH" = "" ]; then
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
fi
if [ "$EJABBRD_BIN_PATH" = "" ]; then
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
fi
if [ "$EJABBERD_SO_PATH" = "" ]; then
EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib
fi
if [ "$EJABBERD_MSGS_PATH" = "" ]; then
EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs
fi
EJABBERD_EBIN=$ROOTDIR/var/lib/ejabberd/ebin
EJABBERD_MSGS_PATH=$ROOTDIR/var/lib/ejabberd/priv/msgs
EJABBERD_SO_PATH=$ROOTDIR/var/lib/ejabberd/priv/lib
EJABBERD_BIN_PATH=$ROOTDIR/var/lib/ejabberd/priv/bin
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
SASL_LOG_PATH=$LOGS_DIR/erlang.log
SASL_LOG_PATH=$LOGS_DIR/sasl.log
DATETIME=`date "+%Y%m%d-%H%M%S"`
ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump
ERL_INETRC=$ETCDIR/inetrc
HOME=$SPOOLDIR
# create the home dir with the proper user if doesn't exist, because it stores cookie file
[ -d $HOME ] || $EXEC_CMD "mkdir -p $HOME"
ERL_INETRC=$ROOTDIR/etc/ejabberd/inetrc
HOME=$ROOTDIR/var/lib/ejabberd
# export global variables
export EJABBERD_CONFIG_PATH
@@ -120,15 +60,14 @@ export EJABBERD_MSGS_PATH
export EJABBERD_LOG_PATH
export EJABBERD_SO_PATH
export EJABBERD_BIN_PATH
export EJABBERD_DOC_PATH
export EJABBERD_PID_PATH
export ERL_CRASH_DUMP
export ERL_INETRC
export ERL_MAX_PORTS
export ERL_MAX_ETS_TABLES
export HOME
export EXEC_CMD
[ -d $EJABBERD_DB ] || mkdir -p $EJABBERD_DB
[ -d $LOGS_DIR ] || mkdir -p $LOGS_DIR
# Compatibility in ZSH
#setopt shwordsplit 2>/dev/null
@@ -136,14 +75,14 @@ export EXEC_CMD
# start server
start ()
{
$EXEC_CMD "$ERL \
$ERL \
$NAME $ERLANG_NODE \
-noinput -detached \
-pa $EJABBERD_EBIN_PATH \
-mnesia dir \"\\\"$SPOOLDIR\\\"\" \
-pa $EJABBERD_EBIN \
-mnesia dir "\"$EJABBERD_DB\"" \
-s ejabberd \
-sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \
$ERLANG_OPTS $ARGS \"$@\""
-sasl sasl_error_logger \{file,\"$SASL_LOG_PATH\"\} \
$ERLANG_OPTS $ARGS "$@"
}
# attach to server
@@ -162,18 +101,13 @@ debug ()
echo " control+c, control+c"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
read foo
echo ""
$EXEC_CMD "$ERL \
$NAME debug-${ERLANG_NODE} \
$ERL \
$NAME ${NODE}debug \
-remsh $ERLANG_NODE \
-hidden \
$ERLANG_OPTS $ARGS \"$@\""
$ERLANG_OPTS $ARGS "$@"
}
# start interactive server
@@ -191,55 +125,42 @@ live ()
echo " q(). and press the Enter key"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
read foo
echo ""
$EXEC_CMD "$ERL \
$ERL \
$NAME $ERLANG_NODE \
-pa $EJABBERD_EBIN_PATH \
-mnesia dir \"\\\"$SPOOLDIR\\\"\" \
-pa $EJABBERD_EBIN \
-mnesia dir "\"$EJABBERD_DB\"" \
-s ejabberd \
$ERLANG_OPTS $ARGS \"$@\""
}
help ()
{
echo ""
echo "Commands to start an ejabberd node:"
echo " start Start an ejabberd node in server mode"
echo " debug Attach an interactive Erlang shell to a running ejabberd node"
echo " live Start an ejabberd node in live (interactive) mode"
echo ""
echo "Optional parameters when starting an ejabberd node:"
echo " --config-dir dir Config ejabberd: $ETCDIR"
echo " --config file Config ejabberd: $EJABBERD_CONFIG_PATH"
echo " --ctl-config file Config ejabberdctl: $EJABBERDCTL_CONFIG_PATH"
echo " --logs dir Directory for logs: $LOGS_DIR"
echo " --spool dir Database spool dir: $SPOOLDIR"
echo " --node nodename ejabberd node name: $ERLANG_NODE"
echo ""
$ERLANG_OPTS $ARGS "$@"
}
# common control function
ctl ()
{
COMMAND=$@
$EXEC_CMD "$ERL \
$NAME ctl-${ERLANG_NODE} \
$ERL \
$NAME ejabberdctl \
-noinput \
-hidden \
-pa $EJABBERD_EBIN_PATH \
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
-pa $EJABBERD_EBIN \
-s ejabberd_ctl -extra $ERLANG_NODE $@
result=$?
case $result in
0) :;;
1) :;;
2) help;;
3) help;;
*)
echo ""
echo "Commands to start an ejabberd node:"
echo " start Start an ejabberd node in server mode"
echo " debug Attach an interactive Erlang shell to a running ejabberd node"
echo " live Start an ejabberd node in live (interactive) mode"
echo ""
echo "Optional parameters when starting an ejabberd node:"
echo " --config file Config file of ejabberd: $EJABBERD_CONFIG_PATH"
echo " --ctl-config file Config file of ejabberdctl: $CONFIG"
echo " --logs dir Directory for logs: $LOGS_DIR"
echo " --spool dir Database spool dir: $EJABBERD_DB"
echo " --node nodename ejabberd node name: $ERLANG_NODE"
echo "";;
esac
return $result
}
@@ -251,42 +172,9 @@ usage ()
exit
}
# stop epmd if there is no other running node
stop_epmd()
{
epmd -names | grep -q name || epmd -kill
}
# allow sync calls
wait_for_status()
{
# args: status try delay
# return: 0 OK, 1 KO
timeout=$2
status=4
while [ $status -ne $1 ]; do
sleep $3
let timeout=timeout-1
[ $timeout -eq 0 ] && {
status=$1
} || {
ctl status > /dev/null
status=$?
}
done
[ $timeout -eq 0 ] && {
status=1
} || {
status=0
}
return $status
}
case $ARGS in
' start') start;;
' debug') debug;;
' live') live;;
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
' stopped') wait_for_status 3 15 2; stop_epmd;; # wait 15x2s before timeout
*) ctl $ARGS;;
esac
+3 -10
View File
@@ -5,7 +5,7 @@
%%% Created : 22 Aug 2005 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -131,14 +131,7 @@ export_offline(Server, Output) ->
NewPacket = {xmlelement, Name, Attrs2,
Els ++
[jlib:timestamp_to_xml(
calendar:now_to_universal_time(TimeStamp),
utc,
jlib:make_jid("", Server, ""),
"Offline Storage"),
%% TODO: Delete the next three lines once XEP-0091 is Obsolete
jlib:timestamp_to_xml(
calendar:now_to_universal_time(
TimeStamp))]},
calendar:now_to_universal_time(TimeStamp))]},
XML =
ejabberd_odbc:escape(
lists:flatten(
+3 -7
View File
@@ -6,17 +6,13 @@ CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
ASN_FLAGS = -bber_bin +optimize +driver
ERLANG_CFLAGS = @ERLANG_CFLAGS@
ERLANG_LIBS = @ERLANG_LIBS@
EFLAGS += -I ..
EFLAGS += -pz ..
EFLAGS = -I .. -pz ..
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
EFLAGS+=+debug_info
endif
OUTDIR = ..
@@ -29,7 +25,7 @@ all: $(BEAMS) ELDAPv3.beam
ELDAPv3.beam: ELDAPv3.erl
ELDAPv3.erl: ELDAPv3.asn
@ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
@ERLC@ -bber_bin -W $(EFLAGS) $<
$(OUTDIR)/%.beam: %.erl ELDAPv3.erl
@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
+3 -4
View File
@@ -4,9 +4,8 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
ASN_FLAGS = -bber_bin +optimize +driver
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
ALL : $(BEAMS)
@@ -18,7 +17,7 @@ Clean :
-@erase $(BEAMS)
ELDAPv3.erl : ELDAPv3.asn
erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
erlc -bber_bin -W $(EFLAGS) ELDAPv3.asn
$(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
+156 -238
View File
@@ -42,12 +42,6 @@
%%% Modified by Mickael Remond <mremond@process-one.net>
%%% Now use ejabberd log mechanism
%%% Modified by:
%%% Thomas Baden <roo@ham9.net> 2008 April 6th
%%% Andy Harb <Ahmad.N.Abou-Harb@jpl.nasa.gov> 2008 April 28th
%%% Anton Podavalov <a.podavalov@gmail.com> 2009 February 22th
%%% Added LDAPS support, modeled off jungerl eldap.erl version.
%%% NOTICE: STARTTLS is not supported.
%%% --------------------------------------------------------------------
-vc('$Id$ ').
@@ -67,7 +61,7 @@
-include("ejabberd.hrl").
%% External exports
-export([start_link/1, start_link/6]).
-export([start_link/1, start_link/5]).
-export([baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
@@ -91,33 +85,20 @@
-define(RETRY_TIMEOUT, 500).
-define(BIND_TIMEOUT, 10000).
-define(CMD_TIMEOUT, 100000).
%% Used in gen_fsm sync calls.
-define(CALL_TIMEOUT, ?CMD_TIMEOUT + ?BIND_TIMEOUT + ?RETRY_TIMEOUT).
%% Used as a timeout for gen_tcp:send/2
-define(SEND_TIMEOUT, 30000).
-define(MAX_TRANSACTION_ID, 65535).
-define(MIN_TRANSACTION_ID, 0).
%% Grace period after "soft" LDAP bind errors:
-define(GRACEFUL_RETRY_TIMEOUT, 5000).
-define(SUPPORTEDEXTENSION, "1.3.6.1.4.1.1466.101.120.7").
-define(SUPPORTEDEXTENSIONSYNTAX, "1.3.6.1.4.1.1466.115.121.1.38").
-define(STARTTLS, "1.3.6.1.4.1.1466.20037").
-record(eldap, {version = ?LDAP_VERSION,
hosts, % Possible hosts running LDAP servers
host = null, % Connected Host LDAP server
port = 389, % The LDAP server port
sockmod, % SockMod (gen_tcp|tls)
tls = none, % LDAP/LDAPS (none|starttls|tls)
tls_options = [],
fd = null, % Socket filedescriptor.
rootdn = "", % Name of the entry to bind as
passwd, % Password for (above) entry
id = 0, % LDAP Request ID
bind_timer, % Ref to bind timeout
dict, % dict holding operation params and results
req_q % Queue for requests
bind_q % Queue for bind() requests
}).
%%%----------------------------------------------------------------------
@@ -127,9 +108,9 @@ start_link(Name) ->
Reg_name = list_to_atom("eldap_" ++ Name),
gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []).
start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) ->
start_link(Name, Hosts, Port, Rootdn, Passwd) ->
Reg_name = list_to_atom("eldap_" ++ Name),
gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []).
gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd}, []).
%%% --------------------------------------------------------------------
%%% Get status of connection.
@@ -158,14 +139,13 @@ close(Handle) ->
%%% {"telephoneNumber", ["545 555 00"]}]
%%% )
%%% --------------------------------------------------------------------
add(Handle, Entry, Attributes) when is_list(Entry), is_list(Attributes) ->
add(Handle, Entry, Attributes) when list(Entry),list(Attributes) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)},
?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)}).
%%% Do sanity check !
add_attrs(Attrs) ->
F = fun({Type,Vals}) when is_list(Type), is_list(Vals) ->
F = fun({Type,Vals}) when list(Type),list(Vals) ->
%% Confused ? Me too... :-/
{'AddRequest_attributes',Type, Vals}
end,
@@ -184,9 +164,9 @@ add_attrs(Attrs) ->
%%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com"
%%% )
%%% --------------------------------------------------------------------
delete(Handle, Entry) when is_list(Entry) ->
delete(Handle, Entry) when list(Entry) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {delete, Entry}, ?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {delete, Entry}).
%%% --------------------------------------------------------------------
%%% Modify an entry. Given an entry a number of modification
@@ -199,18 +179,18 @@ delete(Handle, Entry) when is_list(Entry) ->
%%% add("description", ["LDAP hacker"])]
%%% )
%%% --------------------------------------------------------------------
modify(Handle, Object, Mods) when is_list(Object), is_list(Mods) ->
modify(Handle, Object, Mods) when list(Object), list(Mods) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}, ?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}).
%%%
%%% Modification operations.
%%% Example:
%%% replace("telephoneNumber", ["555 555 00"])
%%%
mod_add(Type, Values) when is_list(Type), is_list(Values) -> m(add, Type, Values).
mod_delete(Type, Values) when is_list(Type), is_list(Values) -> m(delete, Type, Values).
mod_replace(Type, Values) when is_list(Type), is_list(Values) -> m(replace, Type, Values).
mod_add(Type, Values) when list(Type), list(Values) -> m(add, Type, Values).
mod_delete(Type, Values) when list(Type), list(Values) -> m(delete, Type, Values).
mod_replace(Type, Values) when list(Type), list(Values) -> m(replace, Type, Values).
m(Operation, Type, Values) ->
#'ModifyRequest_modification_SEQOF'{
@@ -232,12 +212,9 @@ m(Operation, Type, Values) ->
%%% )
%%% --------------------------------------------------------------------
modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
when is_list(Entry), is_list(NewRDN), is_atom(DelOldRDN), is_list(NewSup) ->
when list(Entry),list(NewRDN),atom(DelOldRDN),list(NewSup) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(
Handle1,
{modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)},
?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)}).
%%% --------------------------------------------------------------------
@@ -249,9 +226,9 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup)
%%% "secret")
%%% --------------------------------------------------------------------
bind(Handle, RootDN, Passwd)
when is_list(RootDN), is_list(Passwd) ->
when list(RootDN),list(Passwd) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, ?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, infinity).
%%% Sanity checks !
@@ -285,18 +262,18 @@ optional(Value) -> Value.
%%% []}}
%%%
%%% --------------------------------------------------------------------
search(Handle, A) when is_record(A, eldap_search) ->
search(Handle, A) when record(A, eldap_search) ->
call_search(Handle, A);
search(Handle, L) when is_list(L) ->
search(Handle, L) when list(L) ->
case catch parse_search_args(L) of
{error, Emsg} -> {error, Emsg};
{'EXIT', Emsg} -> {error, Emsg};
A when is_record(A, eldap_search) -> call_search(Handle, A)
A when record(A, eldap_search) -> call_search(Handle, A)
end.
call_search(Handle, A) ->
Handle1 = get_handle(Handle),
gen_fsm:sync_send_event(Handle1, {search, A}, ?CALL_TIMEOUT).
gen_fsm:sync_send_event(Handle1, {search, A}, infinity).
parse_search_args(Args) ->
parse_search_args(Args, #eldap_search{scope = wholeSubtree}).
@@ -311,7 +288,7 @@ parse_search_args([{attributes, Attrs}|T],A) ->
parse_search_args(T,A#eldap_search{attributes = Attrs});
parse_search_args([{types_only, TypesOnly}|T],A) ->
parse_search_args(T,A#eldap_search{types_only = TypesOnly});
parse_search_args([{timeout, Timeout}|T],A) when is_integer(Timeout) ->
parse_search_args([{timeout, Timeout}|T],A) when integer(Timeout) ->
parse_search_args(T,A#eldap_search{timeout = Timeout});
parse_search_args([{limit, Limit}|T],A) when is_integer(Limit) ->
parse_search_args(T,A#eldap_search{limit = Limit});
@@ -330,9 +307,9 @@ wholeSubtree() -> wholeSubtree.
%%%
%%% Boolean filter operations
%%%
'and'(ListOfFilters) when is_list(ListOfFilters) -> {'and',ListOfFilters}.
'or'(ListOfFilters) when is_list(ListOfFilters) -> {'or', ListOfFilters}.
'not'(Filter) when is_tuple(Filter) -> {'not',Filter}.
'and'(ListOfFilters) when list(ListOfFilters) -> {'and',ListOfFilters}.
'or'(ListOfFilters) when list(ListOfFilters) -> {'or', ListOfFilters}.
'not'(Filter) when tuple(Filter) -> {'not',Filter}.
%%%
%%% The following Filter parameters consist of an attribute
@@ -350,7 +327,7 @@ av_assert(Desc, Value) ->
%%%
%%% Filter to check for the presence of an attribute
%%%
present(Attribute) when is_list(Attribute) ->
present(Attribute) when list(Attribute) ->
{present, Attribute}.
@@ -369,15 +346,15 @@ present(Attribute) when is_list(Attribute) ->
%%% Example: substrings("sn",[{initial,"To"},{any,"kv"},{final,"st"}])
%%% will match entries containing: 'sn: Tornkvist'
%%%
substrings(Type, SubStr) when is_list(Type), is_list(SubStr) ->
substrings(Type, SubStr) when list(Type), list(SubStr) ->
Ss = {'SubstringFilter_substrings',v_substr(SubStr)},
{substrings,#'SubstringFilter'{type = Type,
substrings = Ss}}.
get_handle(Pid) when is_pid(Pid) -> Pid;
get_handle(Atom) when is_atom(Atom) -> Atom;
get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
get_handle(Pid) when pid(Pid) -> Pid;
get_handle(Atom) when atom(Atom) -> Atom;
get_handle(Name) when list(Name) -> list_to_atom("eldap_" ++ Name).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
@@ -393,37 +370,19 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name).
%%----------------------------------------------------------------------
init([]) ->
case get_config() of
{ok, Hosts, Rootdn, Passwd, Encrypt} ->
init({Hosts, Rootdn, Passwd, Encrypt});
{ok, Hosts, Rootdn, Passwd} ->
init({Hosts, Rootdn, Passwd});
{error, Reason} ->
{stop, Reason}
end;
init({Hosts, Port, Rootdn, Passwd, Encrypt}) ->
catch ssl:start(),
{X1,X2,X3} = erlang:now(),
ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)),
PortTemp = case Port of
undefined ->
case Encrypt of
tls ->
?LDAPS_PORT;
starttls ->
?LDAP_PORT;
_ ->
?LDAP_PORT
end;
PT -> PT
end,
TLSOpts = [verify_none],
init({Hosts, Port, Rootdn, Passwd}) ->
{ok, connecting, #eldap{hosts = Hosts,
port = PortTemp,
port = Port,
rootdn = Rootdn,
passwd = Passwd,
tls = Encrypt,
tls_options = TLSOpts,
id = 0,
dict = dict:new(),
req_q = queue:new()}, 0}.
bind_q = queue:new()}, 0}.
%%----------------------------------------------------------------------
%% Func: StateName/2
@@ -446,20 +405,38 @@ connecting(timeout, S) ->
%% {stop, Reason, NewStateData} |
%% {stop, Reason, Reply, NewStateData}
%%----------------------------------------------------------------------
connecting(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, connecting, S#eldap{req_q=Q}}.
connecting(_Event, _From, S) ->
Reply = {error, connecting},
{reply, Reply, connecting, S}.
wait_bind_response(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, wait_bind_response, S#eldap{req_q=Q}}.
active_bind(Event, From, S) ->
Q = queue:in({Event, From}, S#eldap.req_q),
{next_state, active_bind, S#eldap{req_q=Q}}.
wait_bind_response(_Event, _From, S) ->
Reply = {error, wait_bind_response},
{reply, Reply, wait_bind_response, S}.
active(Event, From, S) ->
process_command(S, Event, From).
case catch send_command(Event, From, S) of
{ok, NewS} ->
case Event of
{bind, _, _} ->
{next_state, active_bind, NewS};
_ ->
{next_state, active, NewS}
end;
{error, Reason} ->
{reply, {error, Reason}, active, S};
{'EXIT', Reason} ->
{reply, {error, Reason}, active, S}
end.
active_bind({bind, RootDN, Passwd}, From, #eldap{bind_q=Q} = S) ->
NewQ = queue:in({{bind, RootDN, Passwd}, From}, Q),
{next_state, active_bind, S#eldap{bind_q=NewQ}};
active_bind(Event, From, S) ->
case catch send_command(Event, From, S) of
{ok, NewS} -> {next_state, active_bind, NewS};
{error, Reason} -> {reply, {error, Reason}, active_bind, S};
{'EXIT', Reason} -> {reply, {error, Reason}, active_bind, S}
end.
%%----------------------------------------------------------------------
%% Func: handle_event/3
@@ -469,8 +446,21 @@ active(Event, From, S) ->
%% {stop, Reason, NewStateData}
%%----------------------------------------------------------------------
handle_event(close, _StateName, S) ->
catch (S#eldap.sockmod):close(S#eldap.fd),
{stop, normal, S};
gen_tcp:close(S#eldap.fd),
{stop, closed, S};
handle_event(process_bind_q, active_bind, #eldap{bind_q=Q} = S) ->
case queue:out(Q) of
{{value, {BindEvent, To}}, NewQ} ->
NewStateData = case catch send_command(BindEvent, To, S) of
{ok, NewS} -> NewS;
{error, Reason} -> gen_fsm:reply(To, {error, Reason}), S;
{'EXIT', Reason} -> gen_fsm:reply(To, {error, Reason}), S
end,
{next_state, active_bind, NewStateData#eldap{bind_q=NewQ}};
{empty, Q} ->
{next_state, active, S}
end;
handle_event(_Event, StateName, S) ->
{next_state, StateName, S}.
@@ -498,70 +488,60 @@ handle_sync_event(_Event, _From, StateName, S) ->
%%
%% Packets arriving in various states
%%
handle_info({Tag, _Socket, Data}, connecting, S)
when Tag == tcp; Tag == ssl ->
?DEBUG("tcp packet received when disconnected!~n~p", [Data]),
handle_info({tcp, _Socket, Data}, connecting, S) ->
?DEBUG("eldap. tcp packet received when disconnected!~n~p", [Data]),
{next_state, connecting, S};
handle_info({Tag, _Socket, Data}, wait_bind_response, S)
when Tag == tcp; Tag == ssl ->
handle_info({tcp, _Socket, Data}, wait_bind_response, S) ->
cancel_timer(S#eldap.bind_timer),
case catch recvd_wait_bind_response(Data, S) of
bound ->
dequeue_commands(S);
{fail_bind, Reason} ->
report_bind_failure(S#eldap.host, S#eldap.port, Reason),
{next_state, connecting, close_and_retry(S, ?GRACEFUL_RETRY_TIMEOUT)};
{'EXIT', Reason} ->
report_bind_failure(S#eldap.host, S#eldap.port, Reason),
{next_state, connecting, close_and_retry(S)};
{error, Reason} ->
report_bind_failure(S#eldap.host, S#eldap.port, Reason),
{next_state, connecting, close_and_retry(S)}
bound -> {next_state, active, S};
{fail_bind, _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
{'EXIT', _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
{error, _Reason} -> close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}}
end;
handle_info({Tag, _Socket, Data}, StateName, S)
when (StateName == active orelse StateName == active_bind) andalso
(Tag == tcp orelse Tag == ssl) ->
handle_info({tcp, _Socket, Data}, StateName, S)
when StateName==active; StateName==active_bind ->
case catch recvd_packet(Data, S) of
{response, Response, RequestType} ->
NewS = case Response of
{reply, Reply, To, S1} ->
gen_fsm:reply(To, Reply),
S1;
{ok, S1} ->
S1
end,
if (StateName == active_bind andalso
RequestType == bindRequest) orelse
(StateName == active) ->
dequeue_commands(NewS);
true ->
{next_state, StateName, NewS}
end;
_ ->
{next_state, StateName, S}
{reply, Reply, To, NewS} -> gen_fsm:reply(To, Reply),
{next_state, StateName, NewS};
{ok, NewS} -> {next_state, StateName, NewS};
{'EXIT', _Reason} -> {next_state, StateName, S};
{error, _Reason} -> {next_state, StateName, S}
end;
handle_info({Tag, _Socket}, Fsm_state, S)
when Tag == tcp_closed; Tag == ssl_closed ->
handle_info({tcp_closed, _Socket}, Fsm_state, S) ->
?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn State: ~p",
[S#eldap.host, S#eldap.port ,Fsm_state]),
{next_state, connecting, close_and_retry(S)};
F = fun(_Id, [{Timer, From, _Name}|_]) ->
gen_fsm:reply(From, {error, tcp_closed}),
cancel_timer(Timer)
end,
dict:map(F, S#eldap.dict),
{ok, NextState, NewS} = connect_bind(S#eldap{fd = null,
dict = dict:new(),
bind_q=queue:new()}),
{next_state, NextState, NewS};
handle_info({Tag, _Socket, Reason}, Fsm_state, S)
when Tag == tcp_error; Tag == ssl_error ->
handle_info({tcp_error, _Socket, Reason}, Fsm_state, S) ->
?DEBUG("eldap received tcp_error: ~p~nIn State: ~p", [Reason, Fsm_state]),
{next_state, connecting, close_and_retry(S)};
%% XXX wouldn't it be safer to try reconnect ?
%% if we were waiting a result, we may mait forever
%% cause request is probably lost....
{next_state, Fsm_state, S};
%%
%% Timers
%%
handle_info({timeout, Timer, {cmd_timeout, Id}}, StateName, S) ->
handle_info({timeout, Timer, {cmd_timeout, Id}}, active, S) ->
case cmd_timeout(Timer, Id, S) of
{reply, To, Reason, NewS} -> gen_fsm:reply(To, Reason),
{next_state, StateName, NewS};
{error, _Reason} -> {next_state, StateName, S}
{next_state, active, NewS};
{error, _Reason} -> {next_state, active, S}
end;
handle_info({timeout, retry_connect}, connecting, S) ->
@@ -569,7 +549,8 @@ handle_info({timeout, retry_connect}, connecting, S) ->
{next_state, NextState, NewS};
handle_info({timeout, _Timer, bind_timeout}, wait_bind_response, S) ->
{next_state, connecting, close_and_retry(S)};
close_and_retry(S),
{next_state, connecting, S#eldap{fd = null}};
%%
%% Make sure we don't fill the message queue with rubbish
@@ -598,34 +579,6 @@ code_change(_OldVsn, StateName, S, _Extra) ->
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
dequeue_commands(S) ->
case queue:out(S#eldap.req_q) of
{{value, {Event, From}}, Q} ->
case process_command(S#eldap{req_q=Q}, Event, From) of
{_, active, NewS} ->
dequeue_commands(NewS);
Res ->
Res
end;
{empty, _} ->
{next_state, active, S}
end.
process_command(S, Event, From) ->
case send_command(Event, From, S) of
{ok, NewS} ->
case Event of
{bind, _, _} ->
{next_state, active_bind, NewS};
_ ->
{next_state, active, NewS}
end;
{error, _Reason} ->
Q = queue:in_r({Event, From}, S#eldap.req_q),
NewS = close_and_retry(S#eldap{req_q=Q}),
{next_state, connecting, NewS}
end.
send_command(Command, From, S) ->
Id = bump_id(S),
{Name, Request} = gen_req(Command),
@@ -633,10 +586,10 @@ send_command(Command, From, S) ->
protocolOp = {Name, Request}},
?DEBUG("~p~n",[{Name, Request}]),
{ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage', Message),
case (S#eldap.sockmod):send(S#eldap.fd, Bytes) of
case gen_tcp:send(S#eldap.fd, Bytes) of
ok ->
Timer = erlang:start_timer(?CMD_TIMEOUT, self(), {cmd_timeout, Id}),
New_dict = dict:store(Id, [{Timer, Command, From, Name}], S#eldap.dict),
New_dict = dict:store(Id, [{Timer, From, Name}], S#eldap.dict),
{ok, S#eldap{id = Id, dict = New_dict}};
Error ->
Error
@@ -696,10 +649,9 @@ recvd_packet(Pkt, S) ->
Dict = S#eldap.dict,
Id = Msg#'LDAPMessage'.messageID,
{Timer, From, Name, Result_so_far} = get_op_rec(Id, Dict),
Answer =
case {Name, Op} of
{searchRequest, {searchResEntry, R}} when
is_record(R,'SearchResultEntry') ->
record(R,'SearchResultEntry') ->
New_dict = dict:append(Id, R, Dict),
{ok, S#eldap{dict = New_dict}};
{searchRequest, {searchResDone, Result}} ->
@@ -744,14 +696,14 @@ recvd_packet(Pkt, S) ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
Reply = check_bind_reply(Result, From),
gen_fsm:send_all_state_event(self(), process_bind_q),
{reply, Reply, From, S#eldap{dict = New_dict}};
{OtherName, OtherResult} ->
New_dict = dict:erase(Id, Dict),
cancel_timer(Timer),
{reply, {error, {invalid_result, OtherName, OtherResult}},
From, S#eldap{dict = New_dict}}
end,
{response, Answer, Name};
end;
Error -> Error
end.
@@ -771,7 +723,7 @@ check_bind_reply(Other, _From) ->
get_op_rec(Id, Dict) ->
case dict:find(Id, Dict) of
{ok, [{Timer, _Command, From, Name}|Res]} ->
{ok, [{Timer, From, Name}|Res]} ->
{Timer, From, Name, Res};
error ->
throw({error, unkown_id})
@@ -831,24 +783,14 @@ check_tag(Data) ->
_ -> throw({error,decoded_tag})
end.
close_and_retry(S, Timeout) ->
catch (S#eldap.sockmod):close(S#eldap.fd),
Queue = dict:fold(
fun(_Id, [{Timer, Command, From, _Name}|_], Q) ->
cancel_timer(Timer),
queue:in_r({Command, From}, Q);
(_, _, Q) ->
Q
end, S#eldap.req_q, S#eldap.dict),
erlang:send_after(Timeout, self(), {timeout, retry_connect}),
S#eldap{fd=null, req_q=Queue, dict=dict:new()}.
close_and_retry(S) ->
close_and_retry(S, ?RETRY_TIMEOUT).
gen_tcp:close(S#eldap.fd),
retry_connect().
retry_connect() ->
erlang:send_after(?RETRY_TIMEOUT, self(),
{timeout, retry_connect}).
report_bind_failure(Host, Port, Reason) ->
?WARNING_MSG("LDAP bind failed on ~s:~p~nReason: ~p",
[Host, Port, Reason]).
%%-----------------------------------------------------------------------
%% Sort out timed out commands
@@ -856,7 +798,7 @@ report_bind_failure(Host, Port, Reason) ->
cmd_timeout(Timer, Id, S) ->
Dict = S#eldap.dict,
case dict:find(Id, Dict) of
{ok, [{Timer, _Command, From, Name}|Res]} ->
{ok, [{Timer, From, Name}|Res]} ->
case Name of
searchRequest ->
{Res1, Ref1} = polish(Res),
@@ -883,7 +825,7 @@ cmd_timeout(Timer, Id, S) ->
polish(Entries) ->
polish(Entries, [], []).
polish([H|T], Res, Ref) when is_record(H, 'SearchResultEntry') ->
polish([H|T], Res, Ref) when record(H, 'SearchResultEntry') ->
ObjectName = H#'SearchResultEntry'.objectName,
F = fun({_,A,V}) -> {A,V} end,
Attrs = lists:map(F, H#'SearchResultEntry'.attributes),
@@ -899,40 +841,27 @@ polish([], Res, Ref) ->
%%-----------------------------------------------------------------------
connect_bind(S) ->
Host = next_host(S#eldap.host, S#eldap.hosts),
TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, binary],
?INFO_MSG("LDAP connection on ~s:~p", [Host, S#eldap.port]),
SocketData = case S#eldap.tls of
tls ->
SockMod = ssl,
SslOpts = [{packet, asn1}, {active, true}, {keepalive, true},
binary],
ssl:connect(Host, S#eldap.port, SslOpts);
%% starttls -> %% TODO: Implement STARTTLS;
_ ->
SockMod = gen_tcp,
TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true},
{send_timeout, ?SEND_TIMEOUT}, binary],
gen_tcp:connect(Host, S#eldap.port, TcpOpts)
end,
case SocketData of
case gen_tcp:connect(Host, S#eldap.port, TcpOpts) of
{ok, Socket} ->
case bind_request(Socket, S#eldap{sockmod = SockMod}) of
case bind_request(Socket, S) of
{ok, NewS} ->
Timer = erlang:start_timer(?BIND_TIMEOUT, self(),
{timeout, bind_timeout}),
{ok, wait_bind_response, NewS#eldap{fd = Socket,
sockmod = SockMod,
host = Host,
bind_timer = Timer}};
{error, Reason} ->
report_bind_failure(Host, S#eldap.port, Reason),
NewS = close_and_retry(S),
{ok, connecting, NewS#eldap{host = Host}}
?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]),
gen_tcp:close(Socket),
retry_connect(),
{ok, connecting, S#eldap{host = Host}}
end;
{error, Reason} ->
?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p",
[Host, S#eldap.port, Reason]),
NewS = close_and_retry(S),
{ok, connecting, NewS#eldap{host = Host}}
?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]),
retry_connect(),
{ok, connecting, S#eldap{host = Host}}
end.
bind_request(Socket, S) ->
@@ -944,7 +873,7 @@ bind_request(Socket, S) ->
protocolOp = {bindRequest, Req}},
?DEBUG("Bind Request Message:~p~n",[Message]),
{ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage', Message),
case (S#eldap.sockmod):send(Socket, Bytes) of
case gen_tcp:send(Socket, Bytes) of
ok -> {ok, S#eldap{id = Id}};
Error -> Error
end.
@@ -972,7 +901,7 @@ v_filter({greaterOrEqual,AV}) -> {greaterOrEqual,AV};
v_filter({lessOrEqual,AV}) -> {lessOrEqual,AV};
v_filter({approxMatch,AV}) -> {approxMatch,AV};
v_filter({present,A}) -> {present,A};
v_filter({substrings,S}) when is_record(S,'SubstringFilter') -> {substrings,S};
v_filter({substrings,S}) when record(S,'SubstringFilter') -> {substrings,S};
v_filter(_Filter) -> throw({error,concat(["unknown filter: ",_Filter])}).
v_modifications(Mods) ->
@@ -984,7 +913,7 @@ v_modifications(Mods) ->
end,
lists:foreach(F, Mods).
v_substr([{Key,Str}|T]) when is_list(Str),Key==initial;Key==any;Key==final ->
v_substr([{Key,Str}|T]) when list(Str),Key==initial;Key==any;Key==final ->
[{Key,Str}|v_substr(T)];
v_substr([H|_]) ->
throw({error,{substring_arg,H}});
@@ -999,11 +928,11 @@ v_bool(true) -> true;
v_bool(false) -> false;
v_bool(_Bool) -> throw({error,concat(["not Boolean: ",_Bool])}).
v_timeout(I) when is_integer(I), I>=0 -> I;
v_timeout(I) when integer(I), I>=0 -> I;
v_timeout(_I) -> throw({error,concat(["timeout not positive integer: ",_I])}).
v_attributes(Attrs) ->
F = fun(A) when is_list(A) -> A;
F = fun(A) when list(A) -> A;
(A) -> throw({error,concat(["attribute not String: ",A])})
end,
lists:map(F,Attrs).
@@ -1018,8 +947,8 @@ get_config() ->
case file:consult(File) of
{ok, Entries} ->
case catch parse(Entries) of
{ok, Hosts, Port, Rootdn, Passwd, Encrypt} ->
{ok, Hosts, Port, Rootdn, Passwd, Encrypt};
{ok, Hosts, Port, Rootdn, Passwd} ->
{ok, Hosts, Port, Rootdn, Passwd};
{error, Reason} ->
{error, Reason};
{'EXIT', Reason} ->
@@ -1034,12 +963,11 @@ parse(Entries) ->
get_hosts(host, Entries),
get_integer(port, Entries),
get_list(rootdn, Entries),
get_list(passwd, Entries),
get_atom(encrypt, Entries)}.
get_list(passwd, Entries)}.
get_integer(Key, List) ->
case lists:keysearch(Key, 1, List) of
{value, {Key, Value}} when is_integer(Value) ->
{value, {Key, Value}} when integer(Value) ->
Value;
{value, {Key, _Value}} ->
throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
@@ -1049,17 +977,7 @@ get_integer(Key, List) ->
get_list(Key, List) ->
case lists:keysearch(Key, 1, List) of
{value, {Key, Value}} when is_list(Value) ->
Value;
{value, {Key, _Value}} ->
throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
false ->
throw({error, "No Entry in Config for " ++ atom_to_list(Key)})
end.
get_atom(Key, List) ->
case lists:keysearch(Key, 1, List) of
{value, {Key, Value}} when is_atom(Value) ->
{value, {Key, Value}} when list(Value) ->
Value;
{value, {Key, _Value}} ->
throw({error, "Bad Value in Config for " ++ atom_to_list(Key)});
@@ -1068,13 +986,13 @@ get_atom(Key, List) ->
end.
get_hosts(Key, List) ->
lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A),
is_integer(B),
is_integer(C),
is_integer(D),
lists:map(fun({Key1, {A,B,C,D}}) when integer(A),
integer(B),
integer(C),
integer(D),
Key == Key1->
{A,B,C,D};
({Key1, Value}) when is_list(Value),
({Key1, Value}) when list(Value),
Key == Key1->
Value;
({_Else, _Value}) ->
+2 -5
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -11,7 +11,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -19,9 +19,6 @@
%%%
%%%----------------------------------------------------------------------
-define(LDAP_PORT, 389).
-define(LDAPS_PORT, 636).
-record(eldap_search, {scope = wholeSubtree,
base = [],
filter,
+2 -2
View File
@@ -6,7 +6,7 @@
%%% Author: Evgeniy Khramtsov <xramtsov@gmail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -17,7 +17,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+5 -9
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Nov 2006 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -29,13 +29,11 @@
%% API
-export([
start_link/7,
start_link/6,
bind/3,
search/2
]).
-include("ejabberd.hrl").
%%====================================================================
%% API
%%====================================================================
@@ -45,12 +43,12 @@ bind(PoolName, DN, Passwd) ->
search(PoolName, Opts) ->
do_request(PoolName, {search, [Opts]}).
start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Encrypt) ->
start_link(Name, Hosts, Backups, Port, Rootdn, Passwd) ->
PoolName = make_id(Name),
pg2:create(PoolName),
lists:foreach(fun(Host) ->
ID = erlang:ref_to_list(make_ref()),
case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of
case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd) of
{ok, Pid} ->
pg2:join(PoolName, Pid);
_ ->
@@ -66,8 +64,6 @@ do_request(Name, {F, Args}) ->
Pid when is_pid(Pid) ->
case catch apply(eldap, F, [Pid | Args]) of
{'EXIT', Reason} ->
?ERROR_MSG("LDAP request failed: eldap:~p(~p)~nReason: ~p",
[F, Args, Reason]),
{error, Reason};
Reply ->
Reply
+2 -2
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+100 -25
View File
@@ -1,23 +1,4 @@
/*
* ejabberd, Copyright (C) 2002-2010 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*
*/
/* $Id$ */
#include <stdio.h>
#include <string.h>
@@ -25,6 +6,100 @@
#include <ei.h>
#include <expat.h>
#define EI_ENCODE_STRING_BUG
#ifdef EI_ENCODE_STRING_BUG
/*
* Workaround for EI encode_string bug
*/
#define put8(s,n) do { \
(s)[0] = (char)((n) & 0xff); \
(s) += 1; \
} while (0)
#define put16be(s,n) do { \
(s)[0] = ((n) >> 8) & 0xff; \
(s)[1] = (n) & 0xff; \
(s) += 2; \
} while (0)
#define put32be(s,n) do { \
(s)[0] = ((n) >> 24) & 0xff; \
(s)[1] = ((n) >> 16) & 0xff; \
(s)[2] = ((n) >> 8) & 0xff; \
(s)[3] = (n) & 0xff; \
(s) += 4; \
} while (0)
int ei_encode_string_len_fixed(char *buf, int *index, const char *p, int len)
{
char *s = buf + *index;
char *s0 = s;
int i;
if (len <= 0xffff) {
if (!buf) s += 3;
else {
put8(s,ERL_STRING_EXT);
put16be(s,len);
memmove(s,p,len); /* unterminated string */
}
s += len;
}
else {
if (!buf) s += 6 + (2*len);
else {
/* strings longer than 65535 are encoded as lists */
put8(s,ERL_LIST_EXT);
put32be(s,len);
for (i=0; i<len; i++) {
put8(s,ERL_SMALL_INTEGER_EXT);
put8(s,p[i]);
}
put8(s,ERL_NIL_EXT);
}
}
*index += s-s0;
return 0;
}
int ei_encode_string_fixed(char *buf, int *index, const char *p)
{
return ei_encode_string_len_fixed(buf, index, p, strlen(p));
}
int ei_x_encode_string_len_fixed(ei_x_buff* x, const char* s, int len)
{
int i = x->index;
ei_encode_string_len_fixed(NULL, &i, s, len);
if (!x_fix_buff(x, i))
return -1;
return ei_encode_string_len_fixed(x->buff, &x->index, s, len);
}
int ei_x_encode_string_fixed(ei_x_buff* x, const char* s)
{
return ei_x_encode_string_len_fixed(x, s, strlen(s));
}
#else
#define ei_encode_string_len_fixed(buf, index, p, len) \
ei_encode_string_len(buf, index, p, len)
#define ei_encode_string_fixed(buf, index, p) \
ei_encode_string(buf, index, p)
#define ei_x_encode_string_len_fixed(x, s, len) \
ei_x_encode_string_len(x, s, len)
#define ei_x_encode_string_fixed(x, s) \
ei_x_encode_string(x, s)
#endif
#define XML_START 0
#define XML_END 1
@@ -51,7 +126,7 @@ void *erlXML_StartElementHandler(expat_data *d,
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_START);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_string(&event_buf, name);
ei_x_encode_string_fixed(&event_buf, name);
for (i = 0; atts[i]; i += 2) {}
@@ -62,8 +137,8 @@ void *erlXML_StartElementHandler(expat_data *d,
for (i = 0; atts[i]; i += 2)
{
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_string(&event_buf, atts[i]);
ei_x_encode_string(&event_buf, atts[i+1]);
ei_x_encode_string_fixed(&event_buf, atts[i]);
ei_x_encode_string_fixed(&event_buf, atts[i+1]);
}
}
@@ -78,7 +153,7 @@ void *erlXML_EndElementHandler(expat_data *d,
ei_x_encode_list_header(&event_buf, 1);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, XML_END);
ei_x_encode_string(&event_buf, name);
ei_x_encode_string_fixed(&event_buf, name);
return NULL;
}
@@ -148,7 +223,7 @@ static int expat_erl_control(ErlDrvData drv_data,
ei_x_encode_long(&event_buf, XML_ERROR);
ei_x_encode_tuple_header(&event_buf, 2);
ei_x_encode_long(&event_buf, errcode);
ei_x_encode_string(&event_buf, errstring);
ei_x_encode_string_fixed(&event_buf, errstring);
}
ei_x_encode_empty_list(&event_buf);
+6 -17
View File
@@ -5,7 +5,7 @@
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -16,7 +16,7 @@
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%%
%%% You should have received a copy of the GNU General Public License
%%% along with this program; if not, write to the Free Software
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
@@ -32,9 +32,6 @@
-include("ejabberd.hrl").
-define(INIT_TIMEOUT, 60000). % Timeout is in milliseconds: 60 seconds == 60000
-define(CALL_TIMEOUT, 10000). % Timeout is in milliseconds: 10 seconds == 10000
start(Host, ExtPrg) ->
spawn(?MODULE, init, [Host, ExtPrg]).
@@ -42,7 +39,7 @@ init(Host, ExtPrg) ->
register(gen_mod:get_module_proc(Host, eauth), self()),
process_flag(trap_exit,true),
Port = open_port({spawn, ExtPrg}, [{packet,2}]),
loop(Port, ?INIT_TIMEOUT).
loop(Port).
stop(Host) ->
gen_mod:get_module_proc(Host, eauth) ! stop.
@@ -64,23 +61,15 @@ call_port(Server, Msg) ->
Result
end.
loop(Port, Timeout) ->
loop(Port) ->
receive
{call, Caller, Msg} ->
Port ! {self(), {command, encode(Msg)}},
receive
{Port, {data, Data}} ->
?DEBUG("extauth call '~p' received data response:~n~p", [Msg, Data]),
Caller ! {eauth, decode(Data)};
{Port, Other} ->
?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other]),
Caller ! {eauth, false}
after
Timeout ->
?ERROR_MSG("extauth call '~p' didn't receive response", [Msg]),
Caller ! {eauth, false}
Caller ! {eauth, decode(Data)}
end,
loop(Port, ?CALL_TIMEOUT);
loop(Port);
stop ->
Port ! {self(), close},
receive

Some files were not shown because too many files have changed in this diff Show More