Compare commits

..

771 Commits

Author SHA1 Message Date
Badlop 453e249de3 Update ejabberd version number to 2.1.11 2012-04-26 16:04:16 +02:00
Badlop 8688030d7a Add ejabberd 2.1.11 release notes 2012-04-26 15:57:37 +02:00
Badlop 6e2003c2e2 Recompile translation files 2012-04-26 15:54:54 +02:00
Badlop 5ed8959eba Update Italian translation (thanks to Luca Brivio) 2012-04-25 00:00:52 +02:00
Maxim Ignatenko 7623ebd327 mod_irc: Make use of MUC password 2012-04-24 15:21:46 +02:00
Badlop 522eb0fe9d Update PO files manually according to the English fix 2012-04-24 13:52:59 +02:00
Badlop 7dd171322d Fix English strings (thanks to Andreas van Cranenburgh) 2012-04-24 13:51:54 +02:00
Badlop 752652e56c Update German translation again (thanks to Nikolaus Polak) 2012-04-24 13:51:04 +02:00
Badlop 2582a478ab Update Portuguese-Brazil translation (thanks to Otávio Fernandes) 2012-04-23 09:58:03 +02:00
Badlop 52ff5de564 Update Polish translation (thanks to Zbyszek Żółkiewski) 2012-04-23 09:58:01 +02:00
Badlop ba793af8b7 Update Norwegian translation (thanks to Stian B. Barmen) 2012-04-23 09:57:59 +02:00
Badlop 3304ecd1f0 Update Catalan translation (thanks to Jan Kusanagi) 2012-04-23 09:57:56 +02:00
Badlop 4e0394cab3 Update Japanese translation (thanks to Mako N) 2012-04-20 15:42:41 +02:00
Badlop eaa963a840 Update Greek translation (thanks to James Iakovos Mandelis) 2012-04-20 15:42:38 +02:00
Evgeniy Khramtsov 31c13cc1c8 Remove useless mnesia call 2012-04-20 16:52:33 +10:00
Badlop 310aa7a00d Update Czech translation (thanks to Jan Pinkas) 2012-04-18 11:13:36 +02:00
Badlop fafd605d4d Update Chinese translation (thanks to Shelley Shyan) 2012-04-18 10:13:34 +02:00
Badlop 078f3583f0 Update Turkish translation (thanks to Doruk Fisek) 2012-04-18 10:13:15 +02:00
Badlop 0b337329ba Update Russian translation (thanks to Evgeniy Khramtsov) 2012-04-18 10:12:47 +02:00
Badlop f5df63554f Update Dutch translation (thanks to Andreas van Cranenburgh) 2012-04-18 10:12:22 +02:00
Badlop 46c4f46451 Update Esperanto translation (thanks to Andreas van Cranenburgh) 2012-04-18 10:12:09 +02:00
Badlop e034864c12 Update German translation (thanks to Nikolaus Polak) 2012-04-18 10:11:36 +02:00
Badlop 91f38cc849 Extract new strings 2012-04-18 10:08:30 +02:00
Evgeniy Khramtsov e616d2686f Perform user part substitution in ldap_rfilter (EJAB-1555) 2012-04-17 17:19:53 +10:00
Badlop 5a09d671ab Photos from LDAP not displayed in some clients, lacking TYPE (thanks to Alex Crycheck)(EJAB-1554) 2012-04-16 12:25:14 +02:00
Badlop 58d49d2867 Update Spanish translation 2012-04-15 00:21:22 +02:00
Badlop 8bb58ba3c3 Extract new strings 2012-04-15 00:21:15 +02:00
Badlop 017ce4e092 Fix translation script to use ejabberd_regexp (EJAB-921) 2012-04-15 00:21:10 +02:00
Badlop 49859683b0 Document how to provide a long announcement (EJAB-1553) 2012-04-14 23:29:55 +02:00
Badlop 169b83b36d Handle the scenario of disabled mod_muc (EJAB-1553) 2012-04-14 23:29:30 +02:00
Evgeniy Khramtsov 86435ba9aa ODBC support for mod_blocking 2012-04-12 14:22:56 +10:00
Paweł Chmielowski e2d6bc95a4 Parse and encode https header names like native http parser does
This code adds case normalization step to https headers parsing, making
it correctly use atoms for some special header no matter how upper/lower
case letters are used in input string
2012-04-11 17:28:18 +02:00
Christophe Romain 06f570f4ff return user affiliation for a specified node (thanks to Karim Gemayel) (EJAB-1294) 2012-04-11 16:50:36 +02:00
Badlop 730dfe8fc7 Add comments about Dialyzer warnings 2012-04-11 16:34:03 +02:00
Evgeniy Khramtsov 5619d39bd3 Add odbc modules to Makefile.win32 2012-04-09 14:53:15 +10:00
Evgeniy Khramtsov 959e0ff1c9 Remove obsoleted function call 2012-04-09 10:43:49 +10:00
Paweł Chmielowski 2c228e6414 Don't use binary:match to extract lines from binaries
This was added in R13B3, lets roll our own implementation to make sure it
works on older erlang versions.
2012-04-06 18:55:27 +02:00
Paweł Chmielowski 82468bff00 Fix makefile rules for building dll-s in Makefile.win32 files 2012-04-06 16:31:17 +02:00
Paweł Chmielowski 5f82846732 Parse correctly https request split into multiple packets
This fixes case when SockMod:recv() calls returns only part of first line
of http request (GET/POST/OPTION/HEAD line). Before that change request
like that (and if keep-alive was active, all further request) were dropped.

This fixes EJAB-1537.
2012-04-06 16:22:08 +02:00
Paweł Chmielowski 09c75af15c Make sure that res is initialized in all cases 2012-04-06 12:00:43 +02:00
Alexey Shchepin 91964b1aba Added missed tls:recv_data/2 2012-04-06 11:53:53 +02:00
Paweł Chmielowski af2e9169e6 Don't ignore Length parameter in tls:recv 2012-04-06 11:53:21 +02:00
Alexey Shchepin 4637e2c66b Avoid quadratic behavior in reading SSL data 2012-04-06 11:47:53 +02:00
Paweł Chmielowski 1f1a98d7ae Properly handle HEAD request in mod_http_bind (this fixes EJAB-1538) 2012-04-06 11:47:38 +02:00
Evgeniy Khramtsov cea23b055b Get rid of duplicated code 2012-04-06 12:31:29 +10:00
Evgeniy Khramtsov 41a0eae0bd ODBC support for mod_shared_roster 2012-04-04 20:37:43 +10:00
Evgeniy Khramtsov 5fab00011e ODBC support for mod_irc 2012-04-03 20:23:41 +10:00
Evgeniy Khramtsov ca5f028016 ODBC support for mod_vcard_xupdate 2012-04-02 15:21:54 +10:00
Evgeniy Khramtsov b43444f674 ODBC support for mod_announce 2012-04-02 14:49:13 +10:00
Evgeniy Khramtsov 866085c918 Add ODBC exporting function for privacy table 2012-04-02 12:39:23 +10:00
Evgeniy Khramtsov 585c5afd1a Add notes about mod_muc_odbc 2012-04-02 10:57:10 +10:00
Evgeniy Khramtsov 6ec5c7c4d8 Use proper module name 2012-03-31 22:56:51 +10:00
Evgeniy Khramtsov 6b3875814c ODBC support for mod_muc 2012-03-31 21:41:54 +10:00
Evgeniy Khramtsov 3a51c801e1 Change log level from informational to error 2012-03-19 18:52:20 +10:00
Badlop 983da9c887 Relax digest-uri handling (thanks to Daniel Willmann)(EJAB-1529)
This patch introduces a new config option - fqdn - to set the fully
qualified domain name of the host:
  {fqdn, "foo.example.com"}.
This fixes a problem with Pidgin not being able to log in on a server
that used SRV records.
2012-03-16 14:16:17 +01:00
Evgeniy Khramtsov f7b6446c74 Assume we have only one CPU when an auto-detection fails (EJAB-1516) 2012-02-29 00:45:45 +10:00
Evgeniy Khramtsov deb87f2dfa Cache caps timestamp before the IQ-request is done 2012-02-28 16:38:24 +10:00
Alexey Shchepin b1e2538488 Update copyright dates 2012-02-23 17:52:34 +02:00
Badlop 7b9e59d15d Recommend Erlang/OTP R13B04 and R14B04 2012-02-22 15:42:13 +01:00
Badlop 794d0bbe69 Fix Enlish in the Guide (thanks to Ludovic Bocquet) 2012-02-22 15:40:31 +01:00
Christophe Romain f7ffdfa15d Fix typo in xep number, bosh is xep0206 (thanks to Ludovic Bocquet) 2012-02-20 14:15:08 +01:00
Badlop 4900ac31a7 Add thanks to Ludovic Bocquet for past Guide contributions 2012-02-15 18:30:16 +01:00
Badlop 112a18f966 Work also with some unicode strings in PgSQL (EJAB-1490) 2012-02-14 13:18:18 +01:00
Badlop 7d623d5eb4 Option default_host for handling HTTP requests with ambiguous Host (EJAB-1261) 2012-02-14 11:35:52 +01:00
Evgeniy Khramtsov 4819738e8f Receiver should not generate an exception 2012-02-14 17:03:08 +10:00
Badlop 948318ca19 Fix the documentation about default value of captcha_cmd option 2012-02-01 00:09:51 +01:00
Evgeniy Khramtsov 89aa7baa5b Replace a single quote with double quotes in
an ODBC escape (thanks to Vladislav Chugunov)
2012-01-31 11:18:37 +10:00
Badlop 95928a7cd4 http_bind webserver TLS fail on Chrome (thanks to Adam Langley)(EJAB-1530) 2012-01-19 13:21:25 +01:00
Alexey Shchepin 1ecc9ac48c Fixed ejabberd_http:get_line 2012-01-19 12:20:48 +02:00
Badlop 288196c7e8 Foreign shared rosters items not pushed (thanks to Nathan Bruning)(EJAB-1509) 2012-01-04 19:21:31 +01:00
Badlop 0283c6cdfe Revert "Update ejabberd version number to 2.1.10"
This reverts commit bcdae19141.
2011-12-31 20:40:04 +01:00
Alexey Shchepin d4e7b0cda0 mod_private.erl: misc errors cases fixes (thanks to Karim Gemayel) 2011-12-30 16:08:24 +02:00
Badlop bcdae19141 Update ejabberd version number to 2.1.10 2011-12-23 12:27:30 +01:00
Badlop 6edbbded40 New release notes for 2.1.10 2011-12-23 12:25:50 +01:00
Badlop 684cac274d Support undefinition of ssl:seed in R15B 2011-12-23 12:19:38 +01:00
Badlop ce7b008b8f Use the regexp frontend module (EJAB-921) 2011-12-23 11:33:33 +01:00
Alexey Shchepin a3c58f2896 Always allow packets from user's server and bare jid in mod_privacy* 2011-12-22 16:37:47 +02:00
Alexey Shchepin 3839f1055a Fixed the previous mod_blocking patch 2011-12-21 18:28:04 +02:00
Alexey Shchepin 94350ddb3a Corrected mod_blocking hooks return value, activate "Blocked Contacts" privacy list after it is changed 2011-12-21 16:25:01 +02:00
Badlop 919cdc27db Fix update with stripped beams (thanks to Jose M Herrero)(EJAB-1520) 2011-12-21 12:58:58 +01:00
Badlop 2029e39299 Support Erlang/OTP R15B driver (EJAB-1521) 2011-12-21 12:15:21 +01:00
Evgeniy Khramtsov 707bb0a321 Replace regexp with ejabberd_regexp 2011-12-19 16:10:48 +10:00
Evgeniy Khramtsov 298a4a3acf Get rid of +driver option because it is incompatible with R15B 2011-12-19 16:01:04 +10:00
Badlop 262157c88d Preliminary support for groupname@vhost in Displayed Groups (EJAB-506) 2011-12-15 17:27:28 +01:00
Badlop 37107af7b4 Fix command "update" to return response in the expected format 2011-12-08 19:39:36 +01:00
Badlop 13a9ca65a4 Don't reveal invitee's resource when room informs invitor 2011-12-08 16:35:31 +01:00
Badlop d3369c83e7 Add callback function print_state/1 for behavior p1_fsm 2011-12-08 12:50:40 +01:00
Badlop 48308042b6 Use the regexp frontend module (EJAB-921) 2011-12-08 12:40:04 +01:00
Badlop d30ad8ba28 Frontend module to Re and Regexp (EJAB-921) 2011-12-08 12:39:58 +01:00
Pablo Polvorin cf973f27bb Prevent overload of incomming s2s connections
Three changes were introduced:

1) ejabberd_s2s_in now uses p1_fsm instead of gen_fsm.  And uses
   the {max_queue, N} option to kill the process if its input
   queue grows too much.
2) If a ejabberd_s2s_in process is overload and killed, the server
   that originated that connection is not allowed to connect back
   to us for X seconds (set to 60seconds on the source)
3) The list of blocked (both statically and dynamically by the above
   method) host is now also checked for hosts authenticating by
   starttls+sasl. Previusly it was only used during dialback.
2011-12-02 15:30:20 -03:00
Pablo Polvorin 87df27109a Fix bug on s2s shaper when TLS is used
The shaper was not enabled if the remote server authenticates
using a certificate instead of dialback.
2011-12-01 13:16:21 -03:00
Christophe Romain 89e4e822bf add hooks for node creation/deletion (EJAB-1470) 2011-11-29 14:13:13 +01:00
Badlop b89d4c7476 Use httpc instead of the deprecated http 2011-11-26 17:20:06 +01:00
Badlop ee968b5573 Fix error in mod_vcard when lowercasing some vjud search result fields (EJAB-1490) 2011-11-26 17:08:17 +01:00
Badlop 1f97740cfa Avoid a possible race condition 2011-11-26 17:03:24 +01:00
Badlop 07cfc000ea Comment section 6.3.1 because it has no content at all 2011-11-15 16:46:00 +01:00
Evgeniy Khramtsov 944791e888 Fix presence problem after first unavailable (thanks to Christopher Faulet) (EJAB-1466) 2011-11-09 15:09:02 +10:00
Badlop 0656377165 Support to update modules in R14B04 and higher 2011-11-03 19:47:11 +01:00
Badlop 1a419972d2 Fix previous commit about language name 2011-10-20 16:28:53 +02:00
Badlop 98b150e1a4 Fix extraction of language name from PO files 2011-10-20 15:45:17 +02:00
Evgeniy Khramtsov 96800e9b75 Get rid of useless mnesia transaction (EJAB-1502) 2011-10-14 16:57:51 +10:00
Badlop c1d479f863 Set ejabberd version to 2.1.x 2011-10-13 17:56:19 +02:00
Badlop 4be7984a0e Update ejabberd version number to 2.1.9 2011-09-26 18:11:18 +02:00
Badlop 3b0b318730 New release notes for 2.1.9 2011-09-26 18:09:01 +02:00
Evgeniy Khramtsov 39bc499b10 Fix instruction and error text 2011-09-26 20:00:43 +10:00
Evgeniy Khramtsov de4d4a4bbb Change "muc#role" field type to "hidden" 2011-09-26 19:54:55 +10:00
Evgeniy Khramtsov 8631dd14e9 Correct lists:keysearch output processing and fix dialyzer warning 2011-09-26 19:06:34 +10:00
Evgeniy Khramtsov e7d12f4b9e Code cleanup 2011-09-26 18:44:41 +10:00
Maxim Ignatenko f17a531e15 Use treap correctly 2011-09-26 11:16:30 +03:00
Maxim Ignatenko ff57c8a58c Apply patch from Evgeniy Khramtsov 2011-09-26 11:16:30 +03:00
Maxim Ignatenko 499b884c67 Use treap for keeping last voice request timestamps 2011-09-26 11:16:29 +03:00
Maxim Ignatenko 0c261fb903 Fix voice request/approvement detection and extract_jid_from_voice_approvement/1 2011-09-26 11:16:29 +03:00
Maxim Ignatenko 322263fd5c Fix typo 2011-09-26 11:16:29 +03:00
Maxim Ignatenko 845f5cabec Fix patterns in check_voice_request_fields/2 and check_voice_approvement_fields/2 2011-09-26 11:16:29 +03:00
Maxim Ignatenko f919349173 Use more pattern-matching 2011-09-26 11:16:29 +03:00
Maxim Ignatenko a91ae03dc6 Remove try/catch 2011-09-26 11:16:29 +03:00
Maxim Ignatenko faed7698c2 Use pattern matching in check_voice_request_fields/2 and check_voice_approvement_fields/2 2011-09-26 11:16:29 +03:00
Maxim Ignatenko eb8347f92b Reverse arguments order for timer:now_diff/2 2011-09-26 11:16:29 +03:00
Maxim Ignatenko c53ffe6dc5 Fix return value inconsistency in last_voice_request_time/2 2011-09-26 11:16:29 +03:00
Maxim Ignatenko 7c8eab4f43 Use jlib:parse_xdata_submit/1 in is_voice_request/1 and is_voice_approvement/1 2011-09-26 11:16:29 +03:00
Maxim Ignatenko b1d8168dd3 Use bare JID as key in state.last_voice_request_time 2011-09-26 11:16:28 +03:00
Maxim Ignatenko c196c1f5e5 Use lists:foreach instead of lists:map in send_voice_request/2 2011-09-26 11:16:28 +03:00
Maxim Ignatenko 604563af76 Remove needless time conversions 2011-09-26 11:16:28 +03:00
Maxim Ignatenko 6848d3affe Ignore any extra elements in voice approvement form submission 2011-09-26 11:16:28 +03:00
Maxim Ignatenko 6708914e99 Add 2 room config options
- Allow voice requests?
 - Minimum interval between voice requests
2011-09-26 11:16:28 +03:00
Maxim Ignatenko 5921f9c506 Simple rate control
Visitor allowed to send new voice request only after specified amount of
time (or after rejoining).
2011-09-26 11:16:28 +03:00
Maxim Ignatenko 6193ed63b1 Voice approvement support 2011-09-26 11:16:28 +03:00
Maxim Ignatenko 18dd0d08cb Implement basic voice request processing logic.
No rate control or configuration for now
2011-09-26 11:16:28 +03:00
Maxim Ignatenko 8dd6f128bf Implement voice approvement detection and remove some debug code 2011-09-26 11:16:28 +03:00
Maxim Ignatenko 04267930de Fix form instructions 2011-09-26 11:16:27 +03:00
Maxim Ignatenko d83716dece Use ejabberd_router:route/3 directly, instead of send_packet_to/3 2011-09-26 11:16:27 +03:00
Maxim Ignatenko c77358bdc1 Use exception handling in is_invitation/1 2011-09-26 11:16:27 +03:00
Maxim Ignatenko 44987479a5 Fix exception handling in is_voice_request/1 2011-09-26 11:16:27 +03:00
Maxim Ignatenko 30d89abf66 Implemented sending voice request and fixed some bugs 2011-09-26 11:16:27 +03:00
Maxim Ignatenko f175be6b78 Add function for detecting voice requests 2011-09-26 11:16:27 +03:00
Maxim Ignatenko 2a41ca0628 More correct dispatching of normal messages to conference room
is_invitation/1 function returns true if <x> element of message is
an invitation
2011-09-26 11:16:27 +03:00
Janusz Dziemidowicz c4f9a050c9 Decrease CPU usage caused by tls:send with large data.
Sending one large chunk of data with tls:send eats lots of
CPU power and blocks whole Erlang emulator. This is caused by the
fact that encrypted output is read from memory BIO in 1k chunks.
Memory BIO, after reading data, shifts the remaining part.
If large chunks of data (few MB) is sent and then read in 1k
chunks, then a _lot_ of shifting is performed eating CPU.

The solution is to simply allocate binary of the needed size
(amount of data in memory BIO can be retrieved with
BIO_ctrl_pending) and then issue only one read that reads the
whole data.
2011-09-25 00:23:31 +02:00
Badlop 32ff6b56eb Fix mod_muc_log crash when first log entry is room being destroyed (EJAB-1499) 2011-09-23 17:00:50 +02:00
Christophe Romain 33c0ebb100 fix broken PEP after EJAB-1498 (thanks to Karim Gemayel) 2011-09-22 20:51:59 +02:00
Badlop cb9aecf35e ejabberdctl doesn't support parameters with blankspaces (EJAB-1458)
Revert "Escape output from ctlexec() to erl script (thanks to Dan Scott)(EJAB-1399)"

This reverts commit 6dea2d2307.
2011-09-22 16:18:04 +02:00
Christophe Romain d5b4d67858 Fix Denial of Service when user sends malformed publish stanza (thanks to Oleg Smirnov) (EJAB-1498) 2011-09-21 14:39:50 +02:00
Badlop 9f4ae07100 added svg mimetype to default content types (thanks to Markus Kohlhase) 2011-09-20 16:50:22 +02:00
Badlop 32fc36b17d Add support for @online@ to add_user_to_group 2011-09-20 16:44:51 +02:00
Evgeniy Khramtsov 33766a124d New option support: ldap_deref_aliases (EJAB-639) 2011-09-19 16:58:55 +10:00
Evgeniy Khramtsov ede8d57373 Fix dialyzer warnings 2011-09-17 10:48:52 +10:00
Evgeniy Khramtsov 2494e39c9e Fix dialyzer warnings 2011-09-15 16:59:45 +10:00
Badlop 07fdd089a0 No need to explicitly skip old useless tables, simply fix keep_tables 2011-09-14 12:15:53 +02:00
Evgeniy Khramtsov 228a587fc5 Fix previous commit 2011-09-09 12:40:07 +10:00
Evgeniy Khramtsov e432ff58f9 Avoid crash when performing admin action 2011-09-09 12:34:06 +10:00
Badlop b8969f68e0 Fixed support for multi-resource occupants (EJAB-305) 2011-09-08 16:10:38 +02:00
Badlop dbb2d1c229 Fix room config change logging, due to allow_private_messages_from_visitors 2011-09-08 12:34:25 +02:00
Badlop 609b7ed5c5 Support to import XML files without password-format attribute 2011-09-08 11:41:45 +02:00
Badlop 3eca0259f7 Clarification about system user of ejabberd.init 2011-09-06 13:39:43 +02:00
Badlop 20f3fc96c3 Fix SCRAM to support attributes which value has only one character 2011-09-05 23:21:38 +02:00
Badlop 76a174a007 Fix typo in the Guide about user_regexp 2011-09-05 19:24:05 +02:00
Evgeniy Khramtsov 0fde148a9f Fix dialyzer warnings 2011-09-05 22:00:50 +10:00
Evgeniy Khramtsov 6b0eb1f09d Reorganize the code to shut up the dialyzer 2011-09-05 21:27:31 +10:00
Evgeniy Khramtsov f3c90ee266 Get rid of useless check 2011-09-05 21:06:18 +10:00
Evgeniy Khramtsov 2482c9c5ed Merge set_affiliation/3 and set_affiliation_and_reason/4 into set_affiliation/4 2011-09-05 20:53:01 +10:00
Badlop da555fb908 Fix SCRAM auth of uppercase passwords (EJAB-1196) 2011-09-05 12:50:24 +02:00
Evgeniy Khramtsov 7ae7d6315f Remove useless clauses 2011-09-05 18:07:50 +10:00
Evgeniy Khramtsov eccb499346 Add some magic in order to shut up the dialyzer (because I do not want to replace the macro with a function) 2011-09-05 17:33:51 +10:00
Evgeniy Khramtsov 0c1796ea40 Fix potential case-clause crash 2011-09-05 17:27:15 +10:00
Evgeniy Khramtsov 826fab9999 Remove useless case clause 2011-09-05 17:12:45 +10:00
Evgeniy Khramtsov 3b95108a3a Replace VVALUEL macro with function in order to shut up the dialyzer 2011-09-05 17:09:36 +10:00
Evgeniy Khramtsov ab2a298ebf Merge branch '2.1.x' of git+ssh://gitorious.process-one.net/ejabberd/mainline into 2.1.x 2011-09-05 16:53:10 +10:00
Evgeniy Khramtsov 8b5fa88b6f Export do_client_version/3 in order to shut up the dialyzer 2011-09-05 16:52:36 +10:00
Evgeniy Khramtsov de712e5ccb Remove useless case clauses 2011-09-05 16:48:04 +10:00
Evgeniy Khramtsov ffdf5cb206 Remove useless case clause 2011-09-05 16:47:18 +10:00
Evgeniy Khramtsov f1a91108ef Correct some function clauses and value types 2011-09-05 16:31:58 +10:00
Evgeniy Khramtsov ffe063a0e9 Get rid of useless code 2011-09-05 15:59:30 +10:00
Evgeniy Khramtsov d74f02e367 ejabberd_auth:remove_user/2 always returns ok 2011-09-05 15:39:55 +10:00
Evgeniy Khramtsov 0da2107974 Fix some case clauses 2011-09-05 15:35:46 +10:00
Evgeniy Khramtsov 1994c8a174 Change argument of open_port/2 to string in order to shut up the dialyzer 2011-09-05 15:28:14 +10:00
Evgeniy Khramtsov 2434be4803 Get rid of useless function clause 2011-09-05 15:13:54 +10:00
Badlop d6fcee4faa Replace calls of OTP's Binary, since they would require R14 2011-09-04 14:56:56 +02:00
Badlop 41d028d101 First check occupant existence, later check the message 2011-09-04 13:28:32 +02:00
Christophe Romain 75fc431fb8 enable pubsub#deliver_notification checking (thanks to Karim Gemayel)(EJAB-1453) 2011-08-31 16:11:01 +02:00
Badlop 917d1be994 Explicitly skip useless ejabberd 2.0* mnesia tables when restoring backup
Reference:
http://www.ejabberd.im/node/4867
2011-08-29 12:36:49 +02:00
Christophe Romain 900b013658 typo fix (thanks to Artem Sh)(EJAB-1424) 2011-08-25 17:22:48 +02:00
Badlop 84486dcb2c Support multiple sessions per nick in muc_online_users, relevant for max_user_conferences (EJAB-305) 2011-08-23 21:53:41 +02:00
Badlop 9a190f3bc4 Send private messages to all the sessions with same nick (EJAB-305) 2011-08-23 21:53:30 +02:00
Badlop c76bbdf16f Don't send unavailable presence when leaving occupant has other nicks in the room (EJAB-305) 2011-08-23 21:53:19 +02:00
Badlop 24c5063b99 Allow multiple entry with same nick to MUC rooms (thanks to Magnus Henoch)(EJAB-305) 2011-08-23 21:52:20 +02:00
Badlop a0f8a2c3a4 New option resource_conflict defines server action (thanks to Lee Boynton)(EJAB-650) 2011-08-17 19:44:39 +02:00
Badlop 3edea6c806 Fix bug in scram is_alpha 2011-08-17 19:33:58 +02:00
Badlop abebabc487 Fix ODBC account counting (thanks to Artem Sh)(EJAB-1491) 2011-08-16 19:33:22 +02:00
Badlop 1ee6eae684 Fix and improve support for SCRAM auth method (EJAB-1196) 2011-08-16 00:26:49 +02:00
Badlop 24852b9be8 Indicate license and copyright (thanks to Stephen Röttger)(EJAB-1196) 2011-08-16 00:25:40 +02:00
Badlop e80b92b481 Preliminary patch for SASL SCRAM-SHA-1 (thanks to Stephen Röttger)(EJAB-1196) 2011-08-16 00:25:03 +02:00
Pablo Polvorin 573a84b2ec handle case when roster version on DB is enabled but version is not found.
Thanks Evgeniy.
2011-08-05 12:21:24 -03:00
Badlop 75f8e174dc Add comment about ping requests sent even to non-supporting clients 2011-08-04 18:29:13 +02:00
Badlop e690afc33b Verify username provided in registration web form 2011-07-27 12:25:51 +02:00
Badlop 493b664f19 Handle case when ejabberd_auth_* says the account exists 2011-07-27 11:44:35 +02:00
Badlop 83014fb77b Include status 110 in presence to new occupant (EJAB-740) 2011-07-16 19:35:59 +02:00
Badlop 1a4722e909 Fix typo in modules overview 2011-07-15 02:53:32 +02:00
Badlop 369fefd5a8 Use #roster record instead of direct tuple 2011-07-13 17:06:17 +02:00
Evgeniy Khramtsov cc0aa707c4 Document ldap_tls_cacertfile and ldap_tls_depth options (EJAB-1299) 2011-07-13 15:57:01 +10:00
Evgeniy Khramtsov 7e14b2d46a Add ldap_tls_cacertfile and ldap_tls_depth options (EJAB-1299) 2011-07-13 15:40:27 +10:00
Badlop 1e88c3f180 Room option to ignore private messages from visitors (thanks to Maxim Ignatenko) 2011-07-11 17:34:07 +02:00
Maxim Ignatenko 49ee637a5c One more fix 2011-07-11 12:55:38 +02:00
Maxim Ignatenko 71f085fec0 Improve spelling and fix some typos 2011-07-11 12:55:35 +02:00
Badlop caa84e2731 Fix reference to 'admin' ACL name (thanks to Samuel Wejeus)(EJAB-1476) 2011-07-05 16:33:06 +02:00
Alexey Shchepin 2787df035c Merge branch '2.1.x' of git+ssh://git@gitorious.process-one.net/ejabberd/mainline.git into 2.1.x 2011-07-03 18:58:45 +03:00
Alexey Shchepin 32da749041 Minor mod_version bugfix 2011-07-03 18:58:07 +03:00
Juan Pablo Carlino 0cbd702419 is_user_in_group/3 must check if user belongs to given Group from Host specified on third argument.
* is_user_in_group/3 was checking if given user (passed on first parameter as
a bare jid) belonged to group of the server derived from this jid.
2011-07-01 12:51:52 -03:00
Alexey Shchepin 15f664af26 Optimized mod_roster_odbc:get_roster 2011-06-29 11:56:23 +03:00
Badlop d673ff5fad Support servers that reply error on any command before registration (thanks to Gelraen)
This makes mod_irc actually work with servers that reply with error
on any command before the registration procedure is completed.
Such servers, after NICK/USER they send PING and wait for client response.
In such situation they reply with message 451 to CODEPAGE command,
and mod_irc thinks that connection failed.

Example IRC server that works thanks to the patch: irc.mibbit.com
2011-06-28 23:04:12 +02:00
Badlop f112df2cfc Comment in the cfg file the correct node name used in ejabberdctl.template 2011-06-28 00:31:13 +02:00
Evgeniy Khramtsov 35644cf73c Match ldap_uidattr_format case-insensitively (EJAB-1449) 2011-06-23 15:14:15 +10:00
Evgeniy Khramtsov 6cc6c04c4a Log an error when an LDAP filter is incorrect (EJAB-1395) 2011-06-15 20:06:32 +10:00
Badlop b9e1bc34da Clarify in mod_register_web example what host to put in the URL 2011-06-11 16:15:37 +02:00
Evgeniy Khramtsov f4d0b201ad Escape iolist correctly when NIFs are disabled (EJAB-1462) 2011-06-11 23:28:10 +10:00
Badlop aff99097e7 Fix compilation in Windows (thanks to flyingwow99)
See http://www.ejabberd.im/node/4549
2011-06-07 13:27:00 +02:00
Jerome Sautret 18f6b02065 Added 2.1.8 release notes. 2011-06-06 11:18:10 +02:00
Badlop 33544569fb Fix crash when user publishes an item (EJAB-1457) 2011-06-01 23:22:25 +02:00
Badlop 529ab22a79 Recompile the Guide 2011-05-31 22:31:24 +02:00
Badlop 9f6afab09c Update ejabberd version number to 2.1.7 2011-05-31 22:31:22 +02:00
Badlop 2137c03da1 Recompile translations 2011-05-31 22:31:20 +02:00
Badlop 58fe9d3345 Add release_notes_2.1.7.txt 2011-05-31 22:30:57 +02:00
Badlop deb5e45bff Fix some typos in the Guide 2011-05-31 21:12:31 +02:00
Badlop bd1df027c6 Disable all entity expansions (thanks to Alexey Shchepin)(EJAB-1451) 2011-05-31 21:12:29 +02:00
Badlop 20290cab01 Update the 'configure' script with: aclocal; autoconf 2011-05-31 21:03:45 +02:00
Christophe Romain adcf2d5c4e Pubsub node maxitem forced to 0 if non persistent node (thanks to Karim Gemayel)(EJAB-1434) 2011-05-31 15:51:30 +02:00
Christophe Romain 8faafc5b0d apply filtered notification to PEP last items (thanks to karim Gemayel)(EJAB-1456) 2011-05-31 15:40:07 +02:00
Badlop 370093afde Fix minor English error 2011-05-31 12:27:45 +02:00
Badlop 32d3d1626b New ERL_EPMD_ADDRESS that works since Erlang/OTP R14B03 2011-05-31 12:26:44 +02:00
Badlop d4d28e038b Cut the string when calling halt/1 2011-05-30 17:11:32 +02:00
Evgeniy Khramtsov d6a076dae8 Under some circumstances the "uri" variable in StartNamespaceDeclHandler could be NULL. We check this now. 2011-05-30 22:39:56 +10:00
Badlop 2cacf21d51 Fix a recent commit about "Set script as executable" 2011-05-30 11:46:13 +02:00
Badlop 0874b93e7c Support anonymous accounts in Shared Roster @all@ directive (EJAB-1264)
With this change, logged anonymous accounts are considered to be registered.
2011-05-30 11:00:21 +02:00
Badlop ba9094a089 Add link in the Backup page to the Guide 2011-05-29 20:51:33 +02:00
Badlop bfebcebeb7 Support XEP-0191 Simple Communications Blocking (thanks to Stephan Maka)(EJAB-695) 2011-05-27 11:47:22 +02:00
Badlop 1c0b99e162 A user can query his own Last activity, even if not subscribed to oneself 2011-05-26 12:50:40 +02:00
Badlop f850bcbbc9 Several fixes and improvements in ejabberd.init.template
Changes:
* Set script as executable
* Add LSB tags and overrides, copied from Debian's ejabberd package
* Add chkconfig support (thanks to Ivan Martinez)(EJAB-1450)
* Don't use nounset, as that breaks when no argument is provided
* Add status command
2011-05-24 23:46:44 +02:00
Evgeniy Khramtsov 7bc879c6f4 When checking captcha setup, try to generate image only when captcha is enabled in order to avoid logging of confusing error 2011-05-18 12:48:02 +10:00
Badlop f7d532f2f7 When module start fails during server start, stop erlang (EJAB-1446) 2011-05-16 22:33:59 +02:00
Evgeniy Khramtsov dfbf32ecba Note that ejabberd works with CGP LDAP server 2011-05-07 10:32:52 +10:00
Christophe Romain 17abbf3d82 Owner can delete any items from its own node (EJAB-1445) 2011-05-06 13:58:49 +02:00
Evgeniy Khramtsov dfbfd90f8c Take into consideration internal queue length when sorting processes queues 2011-05-05 16:08:28 +10:00
Evgeniy Khramtsov 84c1cf8033 Do not accept XML with undefined prefixes (EJAB-680) 2011-05-03 20:26:07 +10:00
Badlop 5a0cfe7e2b Reorganize the push_item function, and handle version not_found (EJAB-1420) 2011-04-29 20:34:08 +02:00
Badlop 714dce84db No need to inform that XEP-0237 is optional; clarified in XEP version 1.2 2011-04-29 20:34:06 +02:00
Badlop b807b21a59 Show configuration for HTTPS http_bind 2011-04-28 13:24:18 +02:00
Badlop 4f4c8eb61e mod_register Access now also controls account unregistrations 2011-04-26 22:55:04 +02:00
Badlop 3952888f94 Escape user input in mod_privacy_odbc (EJAB-1442) 2011-04-26 20:57:48 +02:00
Badlop 9b145385af Throw error when captcha fails at server start, not later at runtime 2011-04-26 13:59:08 +02:00
jabber 897b46c31d Do not decrease MUC admin's role/affiliation 2011-04-18 21:06:05 +10:00
Evgeniy Khramtsov 72299ab078 Add captcha_limit option to the example config 2011-04-18 16:16:10 +10:00
Evgeniy Khramtsov e7ab83b612 Remove forgotten -compile(export_all). 2011-04-18 16:09:05 +10:00
Evgeniy Khramtsov 07cf6f09b8 Implement CAPTCHA limit 2011-04-18 16:06:36 +10:00
Evgeniy Khramtsov 252ee6228b Fix syntax error 2011-04-18 15:50:24 +10:00
Evgeniy Khramtsov cf6264f507 CAPTCHA whitelist support 2011-04-18 15:47:06 +10:00
Badlop 4f1ececbd1 Try to improve support for roster_version in MSSQL (EJAB-1437) 2011-04-14 23:11:37 +02:00
Badlop 70bf5b4eda The responses to HEAD must have empty Body 2011-04-12 23:31:08 +02:00
Badlop f59a979f7c Support as read-only HTTP method not only GET, also HEAD 2011-04-12 23:13:46 +02:00
Badlop 05e3893f60 If extauth script crashes, ejabberd should restart it (EJAB-1428) 2011-04-11 21:27:19 +02:00
Badlop 7d7621c67c Support more captcha_host value formats (EJAB-1418) 2011-04-11 19:59:26 +02:00
Badlop 449e56ed52 Send jid attribute when occupant is banned (EJAB-1432) 2011-04-07 12:54:39 +02:00
Badlop aded966370 mod_ping uses iqdisc no_queue by default (thanks to Chris Moos)(EJAB-1435) 2011-04-07 12:08:31 +02:00
Badlop dac1f328d7 Clarify {iqdisc, no_queue} 2011-04-07 12:06:31 +02:00
Badlop 90ea752046 Updated Japanese translation (thanks to Mako N) 2011-03-30 19:18:26 +02:00
Badlop e4b3bd5005 Fix typo (thanks to Krzee) 2011-03-17 12:15:31 +01:00
Badlop abcbcd1f2c Update the changed string in the PO translation files 2011-03-13 18:34:55 +01:00
Badlop 18fd67b311 Change string in WebAdmin to reuse an existing one 2011-03-13 18:34:50 +01:00
Badlop b116957982 Fix bashism and make some lines similar to master branch (EJAB-1404) 2011-03-09 16:25:05 +01:00
Badlop a1f20a5bc0 If the port number isn't listener, then specify the protocol (EJAB-1418) 2011-03-03 11:38:00 +01:00
Badlop e0d14c3b8d captcha_host must have the port number to get protocol (EJAB-1418) 2011-03-03 00:02:43 +01:00
Badlop 1548a18b5e mod_irc must send presence unavailable to the departing occupant (EJAB-1417) 2011-03-01 22:33:11 +01:00
Badlop 339fa6e41b ejabberdctl needs space between INET_DIST_INTERFACE (thanks to Dale Chase)(EJAB-1416) 2011-02-28 18:40:45 +01:00
Badlop db0962804d Tweak pg2_backport.erl to work with Erlang older than R13A (EJAB-1349) 2011-02-22 23:44:45 +01:00
Badlop 677d8b1a29 Add support for '@online@' Shared Roster Group (thanks to Martin Langhoff)(EJAB-1391)
New version of the @online@ patch originally by Collabora.
Notes:
- the presence push is mediated via the group rather than
  per user - this may reduce memory footprint... _if_ ejabberd
  has some smart optimisation in that codepath
- it assumes that any group with membership @online@ _displays_
  online as well -- this is a simplification and breaks the
  decoupling that ejabberd has in this regard.
2011-02-21 22:34:15 +01:00
Badlop 850218c2df Forward old messages to newly spawned extauth process (thanks to Mika Seppänen)(EJAB-1385) 2011-02-21 16:13:41 +01:00
Badlop 1c89914382 New route_iq/5 accepting Timeout (thanks to Edwin Fine)(EJAB-1398)
Also new register_iq_response_handler/5
2011-02-21 13:44:39 +01:00
Badlop fe40a9c5f6 New DIST_USE_INTERFACE to restrict IP where erlang connections are listened (EJAB-1404) 2011-02-16 23:53:29 +01:00
Badlop bc0ae5a017 New Indonesian translation (thanks to Irfan Mahfudz Guntur)(EJAB-1407) 2011-02-16 13:46:20 +01:00
Christophe Romain 91ab7e029b fix empty pubsub payload check on odbc version 2011-02-14 16:45:49 +01:00
Christophe Romain c3a88c713b fix empty pubsub payload check 2011-02-14 16:41:32 +01:00
Christophe Romain fd52f2cb7d update copyright up to 2011 2011-02-14 13:50:55 +01:00
Badlop f91eb52890 Provide HTTPS URL in CAPTCHA form when listener has 'tls' option (EJAB-1406) 2011-02-14 13:11:21 +01:00
Badlop ca59a7f027 Fix typo in French translation 2011-02-11 20:19:59 +01:00
Badlop 6dea2d2307 Escape output from ctlexec() to erl script (thanks to Dan Scott)(EJAB-1399) 2011-02-09 16:38:54 +01:00
Badlop 650b2802b5 Remove erroneous comment (EJAB-645) 2011-02-03 17:23:09 +01:00
Badlop 6ddc66db9f Handle Tigase's unexpected version=1.0 when ejabberd doesn't announce it (EJAB-1379) 2011-01-31 19:43:28 +01:00
Badlop 792512459d mod_pres_counter prevents subscription flood (thanks to Ahmed Omar and Alexey Shchepin)(EJAB-1388) 2011-01-31 18:52:07 +01:00
Badlop 0359e345b0 Add to example config file access_from comment 2011-01-28 17:13:44 +01:00
Badlop a09c319357 Update exmpp version to 0.9.6 2011-01-28 12:46:09 +01:00
Badlop 36166aa40e Comment unused code 2011-01-28 12:11:34 +01:00
Badlop a25c9c5df3 Don't let presence-in privacy rule block a presence subscription using ODBC (EJAB-255) 2011-01-19 20:58:57 +01:00
Badlop 6e3a9ac4fd Fix delayed response of a timeout call was reused for next login (EJAB-1385) 2011-01-19 19:06:46 +01:00
Badlop f4c74c147b Clarify more the expected content of welcome_message mod_register option 2011-01-17 23:46:08 +01:00
Badlop 0edda6150b Clarify error message when BOSH query is sent to non-running module 2011-01-12 21:22:43 +01:00
Mickaël Rémond bd43505db9 Use route instead of send_element to go through standard workflow Offline messages should thus be tracked for ack if needed (TEXTO-226).
Signed-off-by: Evgeniy Khramtsov <ekhramtsov@process-one.net>
2011-01-04 15:21:10 +01:00
Badlop a2e1d2030a Keep the order of stanzas when BOSH sends several (EJAB-1374) 2010-12-30 13:42:53 +01:00
Evgeniy Khramtsov 4c8b034874 Change c2s state before offline messages resending 2010-12-28 21:09:15 +09:00
Alexey Shchepin b47c50145d Make jlib:ip_to_list safe to use 2010-12-20 19:29:05 +02:00
Badlop b9f4daca46 Revert branch name back to 2.1.x 2010-12-20 13:10:33 +01:00
Evgeniy Khramtsov 606c207e21 Make sure 'closed' event is correctly processed on every state 2010-12-17 17:26:20 +09:00
W. Andrew Loe III d9c01e8ed9 Ignore OS X libraries. 2010-12-15 17:01:14 +01:00
Badlop 3e9c9fc750 Remove Type and Spec, backport list comprehensions, so R12B-5 can compile 2010-12-13 12:17:28 +01:00
Badlop fbcb9bb154 Recompile the Guide 2010-12-13 11:15:19 +01:00
Badlop 6242fd2bb8 Update ejabberd version number to 2.1.6 2010-12-13 11:15:18 +01:00
Badlop 1c566057f8 Recompile translations 2010-12-13 11:15:16 +01:00
Badlop aa59d8f1f0 Add release notes for ejabberd 2.1.6 2010-12-13 11:15:14 +01:00
Badlop 6dd35923b0 Fix warning about unused variables 2010-12-13 11:14:39 +01:00
Badlop b9bbe19d4c Option to reject S2S connection if untrusted certificate (EJAB-464) 2010-12-11 02:29:53 +01:00
Badlop 44b2002504 Include From attribute in the stream header of outgoing S2S connections 2010-12-11 02:29:52 +01:00
Badlop faf422202f When TLS is required in s2s, add subelement to stream:features starttls 2010-12-11 02:29:50 +01:00
Badlop eb884c80d0 Add option to require encryption in S2S connections (EJAB-495) 2010-12-11 02:29:48 +01:00
Badlop b83dd9f954 Support for X-Forwarded-For HTTP header (EJAB-1356) 2010-12-07 16:47:55 +01:00
Christophe Romain fd828c3e9b update pubsub_odbc patch 2010-12-07 14:00:40 +01:00
Christophe Romain 79648ce853 add node attribute to pubsub subscribe event (EJAB-1361) 2010-12-07 13:51:10 +01:00
Badlop ddc94a8c96 Update Czech Translation (thanks to Lukáš Polívka) 2010-12-06 12:04:12 +01:00
Badlop aa413d63da Fix detection of mod_last at server start (EJAB-641) 2010-12-03 17:26:12 +01:00
Badlop 548be4cf3d Update example extauth script with tryregister, removeuser and removeuser3 (EJAB-641) 2010-12-03 17:26:10 +01:00
Pablo Polvorin 0e5b0b43fa Revert "Fix cyrsasl_digest RFC-2831 2.1.2.1 (EJAB-476)"
This reverts commit c890b17834.
This change made ejabberd more strict in protocol compliance, which breaks Psi 0.14 and other clients.
We must grant a grace period to client developers to fix their clients. So this isn't going to be included
in 2.1.x.
2010-12-03 11:12:43 -03:00
Badlop 8258f5940b Support PostgreSQL 9.0 (EJAB-1359)(thanks to Stephen Gibberd and Konstantin Nikiforov) 2010-12-03 12:43:05 +01:00
Pablo Polvorin c890b17834 Fix cyrsasl_digest RFC-2831 2.1.2.1 (EJAB-476)
Fix sasl digest bug when username|password|resource strings had
all characters <= U+00FF and at least one character >= U+0080.

Warnning:
Note that by fixing the bug, we may be broking compatibility with clients
that "implements" it.
See comments on https://support.process-one.net/browse/EJAB-476
2010-12-02 12:55:06 -03:00
Christophe Romain f0a848ef45 fix pubsub cross domain eventing (EJAB-1340) 2010-12-02 13:56:45 +01:00
Badlop 20d66e6736 Update Greek translation (thanks to James Iakovos Mandelis) 2010-12-01 13:28:20 +01:00
Evgeniy Khramtsov 731c9b86e0 Increase maximum restart strategy of the ODBC supervisor. Do not brutally kill ODBC processes on supervisor shutdown to avoid polution of the mnesia table 2010-12-01 14:24:51 +09:00
Badlop 955343f6aa When the Password attribute is missing in PIEFXIS file, don't check account auth. 2010-12-01 00:55:09 +01:00
Otavio Fernandes 1b73ac5118 Corrections on pt_BR translations. 2010-11-30 22:43:04 +01:00
Badlop 9ee8191939 Update Ukrainian translation (thanks to Ruslan Rakhmanin) 2010-11-30 22:43:02 +01:00
Christopher tofu Zorn f2231a2282 expose find_connection for routing in other modules (if needed) 2010-11-29 20:05:39 +01:00
Christopher tofu Zorn 3e24408710 add the ability to send raw xml packets over http bind 2010-11-29 20:05:37 +01:00
Badlop 3e67200d64 Update mod_register_web string in PO files 2010-11-29 19:35:18 +01:00
Badlop 6374b5b1e7 Fix characters not allowed in username. Don't include that in translatable string.
List mentioned in:
http://xmpp.org/rfcs/rfc3920.html#nodeprep-prohibited
2010-11-29 19:34:26 +01:00
Badlop 26ac75bdc9 Support negative part-hour TZ values (thanks to Alexander Zhukov)(EJAB-1301) 2010-11-29 14:36:09 +01:00
Alexey Shchepin 1d1496a667 Don't loop when there is nothing after a stream start 2010-11-26 17:08:00 +01:00
Andreas Köhler e34eebb5ad Correct domain_certfile tlsopts modifications for s2s connections (EJAB-1086)
* In ejabberd_s2s_out:wait_for_feature_request/2, the domain to use for
  looking up domain_certfile options is #state.myname and not
  #state.server

* If s2s_certfile is not specified, connect should still be part of the
  tls options used by ejabberd_s2s_out

* Add #state.server to ejabberd_s2s_in processes and store the to
  attribute in :wait_for_stream/2. Then use that server in
  :wait_for_feature_request/2 to change the tls options like in
  ejabberd_s2s_out.

Fixes EJAB-1086.
2010-11-26 00:14:46 +01:00
Badlop 776930fa06 Update French translation (thanks to Nicolas Vérité) 2010-11-25 21:31:21 +01:00
Badlop 38af7c85a6 Update German translation (thanks to Nikolaus Polak) 2010-11-25 21:31:19 +01:00
Badlop 99b7a285d7 Update Japanese translation (thanks to Tsukasa Hamano) 2010-11-24 17:10:54 +01:00
Badlop 19e20f75d7 Update Chinese translation (thanks to Shelley Shyan) 2010-11-24 13:42:19 +01:00
Evgeniy Khramtsov b8d6aee1ce Merge branch 'caps' into 2.1.x
Conflicts:
	src/ejabberd_c2s.erl
2010-11-24 16:45:05 +09:00
Otavio Fernandes 48b768b5b0 Updating Brazilian Portuguese (pt_BR) translations for v2.1.6 2010-11-23 17:54:37 +01:00
Badlop bd604945c9 Update Polish translation (thanks to Zbyszek Żółkiewski) 2010-11-23 13:07:14 +01:00
Badlop 0a59ebe405 Use pg2 from R14B in systems with older versions (EJAB-1349)
pg2_backport.erl is a copy of pg2.erl from Erlang/OTP R14B.
That module is used in ejabberd installations where an OTP
previous to R14 is installed.
2010-11-22 16:04:07 +01:00
Christophe Romain 32eaa01929 Revert "populate pubsub#roster_groups_allowed in node configuration options (EJAB-1344)"
This reverts commit dfaeb3bc88.
2010-11-22 11:15:04 +01:00
Badlop baf9363bdf Disapprove the use of R14A and R14B due to the rwlock bug. 2010-11-19 15:33:48 +01:00
Badlop 12aaa0125b Update Russian translation (thanks to Evgeniy Khramtsov) 2010-11-19 15:15:47 +01:00
Badlop cb7cd9abb8 Update translate files 2010-11-19 13:47:24 +01:00
Badlop ca701e1675 Update the Spanish translation 2010-11-19 13:45:32 +01:00
Badlop 9b88fd6646 Fix some English strings 2010-11-19 13:44:30 +01:00
Badlop 76ca7ae7f0 Translate mod_register_web to Ukrainian (thanks to Rain) 2010-11-19 00:23:40 +01:00
Evgeniy Khramtsov 1ab223568d Document mod_shared_roster_ldap (thanks to Marcin Owsiany) 2010-11-18 16:59:35 +09:00
Badlop 043effc3ce Translate mod_register_web to Spanish 2010-11-17 23:16:46 +01:00
Badlop 4fd1a8ba63 Translate mod_register_web to Russian (thanks to Rain) 2010-11-17 22:42:43 +01:00
Badlop 36303fb4be Update strings to translate 2010-11-17 22:36:56 +01:00
Badlop 62357b9589 Add extract_translations.beam to gitignore 2010-11-17 22:35:33 +01:00
Badlop 808029b868 Fix http-bind supervisor to support multiple vhosts (EJAB-1321) 2010-11-17 20:31:28 +01:00
Andreas Köhler cfd377b98e Fix R12B5 compatibility in ejabberd_http_bind.erl (EJAB-1343)
erlang:max/2 and :min/2 are new functions
2010-11-17 13:01:17 +01:00
Andreas Köhler 6eeb355a22 Use LFrom and LTo consistently in ejabberd_s2s_in:stream_established/2 (EJAB-1342) 2010-11-17 12:57:05 +01:00
Evgeniy Khramtsov a0e2e943b4 Do not start mod_proxy65 if it is unable to bind an address (EJAB-1336) 2010-11-17 18:13:19 +09:00
Evgeniy Khramtsov 78931d8efa Use MEDIUMTEXT type for vcard avatars in MySQL schema (EJAB-1252) 2010-11-17 17:36:51 +09:00
Evgeniy Khramtsov 0d2a8cd04f Do not print full error message when LDAP timeout occurs (EJAB-1324) 2010-11-17 17:14:47 +09:00
Evgeniy Khramtsov 97087eb3b9 Set SSL_MODE_RELEASE_BUFFERS mode when available (EJAB-1351) 2010-11-17 13:54:27 +09:00
Badlop 6eeef62ce4 Provide new, not old, affiliation in kick/ban presence with codes 321 and 301 2010-11-16 00:03:09 +01:00
Evgeniy Khramtsov 0ccff15599 Strip status when needed in presence-unavailable as well 2010-11-15 13:47:31 +09:00
Badlop 325fb8caef Fix typos in the example configuration file 2010-11-12 21:24:01 +01:00
Andreas Köhler 18ef908759 Before binding tcp ports, checks the socket type and listener options
If the callback module has a socket type of independent and needs to
create the listener itself, do not pre-bind the port. The same holds if
there are errors in the listener configuration.
2010-11-10 23:46:18 +01:00
Andreas Köhler 1f1d2bd5f5 Bind listener ports early and start accepting connections later
It may happen that auth or rdbms client tcp connections bind a local
socket to a port number required by a configered listener. The ejabberd
applications fails to start up and needs to be restarted.

In plain C you would bind(2) the listener port and listen(2) later on.
gen_tcp:listen/2 does not allow to separate these two steps though, so
another way is not to accept connections while start up. OTOH, the
kernel will syn/ack incoming connections and receive data, leaving them
in a buffer for the ejabberd to read from. If this is unwanted, a load
balancer would need to receive data from the ejabberd server before
adding the node to its pool.

This patch binds tcp ports while initializing the ejabberd_listener
process, storing ListenSockets in an ets table. start_listeners/0 will
reuse these ports later on.
2010-11-10 23:46:16 +01:00
Andreas Köhler 0c484369c9 In mod_last*:get_last_iq/4, check for user resources first to return 0 seconds if there is one
Fixes problem 2 of EJAB-1158.
2010-11-10 15:40:04 +01:00
Andreas Köhler 100f2e9a13 Refactor mod_last to use the same core get_last/2 functionality, but keep api stable
The local function get_last/4 has been renamed to get_last_iq/4, since
it converts the result of get_last/2 (typically {ok, TimeStamp, Status})
to an iq packet.
2010-11-10 15:40:03 +01:00
Andreas Köhler 510fd8cf73 Before forwarding last activity requests to a user, check that the user's presence is visible for From
According to XEP-0012, 4. Online User Query, "if the requesting entity
is not authorized to view the user's presence information (normally via
a presence subscription as defined in XMPP IM), the user's server MUST
NOT deliver the IQ-get to an available resource but instead MUST return
a <forbidden/> error in response to the last activity request."

So check for a subscription of from of the jid and bare jid and whether
outgoing presences to From are allowed.

Fixes problem 3 of EJAB-1158.
2010-11-10 15:40:01 +01:00
Andreas Köhler 080922a3de Remove dead code for NS_VCARD iq packets from ejabberd_c2s
For EJAB-1045, the special NS_VCARD block for handling incoming vcard
iqs on behalf of clients has already been restricted to cases where the
user or resource part of the recipient is empty. But then the packets
should not have been routed to the c2s process anyway. This patch
completely removes it.
2010-11-10 15:40:00 +01:00
Andreas Köhler cb7d8c8ead Use ejabberd_c2s:privacy_check_packet/5 for all those hook folded runs in the c2s module 2010-11-10 15:39:59 +01:00
Andreas Köhler c47252aea1 Use c2s state data as user and server in ejabberd_c2s:is_privacy_allow
is_privacy_allow is only used in ejabberd_c2s:handle_info/3 to determine
for a few presence types whether the packet is allowed to be forwarded
to the user's client. This only makes sense if To#jid.user and
To#jid.server match StateData#state.user and StateData#state.server.

Also, add the atom in as parameter to a new argument Dir of
is_privacy_allow and extract from that function
privacy_check_packet(StateData, From, To, Packet, Dir) which runs the
privavcy check without converting allow/deny to true/false.
2010-11-10 15:39:57 +01:00
Andreas Köhler f96074057c Correct error responses of forbidden offline last activity queries
According to XEP-0012 Last Activity, the server must return iq errors
with forbidden instead of not-allowed.

Fixes problem 1 of EJAB-1158.
2010-11-10 15:39:55 +01:00
Christophe Romain dfaeb3bc88 populate pubsub#roster_groups_allowed in node configuration options (thanks to Karim Gemayel)(EJAB-1344) 2010-11-10 15:15:03 +01:00
Christophe Romain c31f59e326 fix bad plugin order issue injected in previous patch (EJAB-1286) 2010-11-09 14:32:40 +01:00
Andreas Köhler 7c2b9eaf97 Correct privacy check direction in mod_last (EJAB-1339)
The change for EJAB-1271 to change the direction of the privacy check
from out to in violates the idea that the check should imitate a
subscription state check of from. Rather correct the order of the From
and To parameters.
2010-11-09 13:57:57 +01:00
Andreas Köhler 79f5251d69 Change max restart strategy of ejabberd_odbc_sup to handle some SQL timeouts. 2010-11-08 18:41:03 +01:00
Christophe Romain 917e8640c2 avoid node_call to break transaction (thanks to Karim Gemayel)(EJAB-1286) 2010-11-08 11:16:51 +01:00
Andreas Köhler c4bc0e7252 Re-raise exceptions caught in gen_mod:start_module/3 (EJAB-1335)
Modules configured by the administrator normally should not be treated
as optional, so a exception (error, exit, throw) to start them should not
be caught and logged only.

This patch re-raises a caught exception instead of ignoring the
exception and inserting the module's opts on success. That way
gen_mod:get_module_opt/4 should work while calling Module:start/2.
2010-11-07 00:49:52 +01:00
Evgeniy Khramtsov 1f16e4783c Take care of xml:lang attribute in unauthenticated stanzas as well 2010-11-06 13:58:52 +09:00
Badlop 7f3a5066c6 New ip_access option restricts which IPs can register (thanks to Alexey Shchepin)(EJAB-915) 2010-11-05 19:33:52 +01:00
Badlop 6f3713a67d Disable mod_register_web in default config because by default captcha is disabled 2010-11-05 19:33:50 +01:00
Badlop abfb4a2841 Recompile the Guide 2010-11-05 18:21:20 +01:00
Badlop f672fd0824 Added mod_register_web: web page for account registration (EJAB-471) 2010-11-05 18:19:52 +01:00
Evgeniy Khramtsov 60b36beda8 Disable LRU caching algorithm for LDAP shared rosters 2010-11-05 17:01:18 +09:00
Evgeniy Khramtsov c4289095e0 Do not store long language tag to avoid possible DoS/flood attacks 2010-11-05 05:10:18 +09:00
Evgeniy Khramtsov 31757116fc LDAP shared roster support (thanks to Realloc and Marcin Owsiany) 2010-11-05 02:34:45 +09:00
Jonas Ådahl 2f68733708 Fixes a leak of ejabberd_receiver processes.
When a (non-frontend) socket module without any custom receiver fails to
start, the newly created ejabberd_receiver process needs to be properly
closed.
2010-11-03 17:10:52 +01:00
Badlop dccaff0544 Correct in the Guide the default mod_irc encoding
The default option value was last changed in  EJAB-302,
but the Guide was not properly updated yet.
2010-11-02 22:47:28 +01:00
Badlop 184ec38510 Implement the mod_irc option default_encoding, it was already documented
Related:
http://www.ejabberd.im/node/4270#comment-56609
http://www.ejabberd.im/node/4270#comment-56780
2010-11-02 22:40:08 +01:00
Badlop 2d59efb515 Fix crash in ejabberd_c2s when blacklist hook returned true (thanks to Jonas Ådahl)
Cause of the crash jlib:ip_to_list/1 only supports IP tuples using the
form {N1,N2,N3,N4} which is not the case when IPv6 is enabled.
2010-11-02 13:51:36 +01:00
Evgeniy Khramtsov 195d22d906 Merge branch '2.1.x' of git+ssh://gitorious.process-one.net/ejabberd/mainline into 2.1.x 2010-11-01 22:23:01 +09:00
Evgeniy Khramtsov ab80513755 Do not run set_last request inside a transaction 2010-11-01 22:22:41 +09:00
Badlop 8a116411bb Fix errors in EDoc comments 2010-10-28 18:48:27 +02:00
Badlop bd3889b6ec Include a Required xml element in the captcha field 2010-10-27 00:50:17 +02:00
Andreas Köhler 400fb69f15 Ignore Length argument to tls:recv/[23] (EJAB-1327)
The Length argument cannot be used for gen_tcp:recv/3, because the
compressed size does not equal the desired uncompressed one.
2010-10-26 19:32:15 +02:00
Andreas Köhler 9da45d40c7 Re-use the TLSSock argument in tls:send/2 (EJAB-1327) 2010-10-26 19:30:32 +02:00
Evgeniy Khramtsov 23db206ea1 * Add top-level instructions for x:data incompatible clients
* Remove trailing dot
2010-10-26 03:47:14 +10:00
Badlop 964b7b6b67 Changes in registration form to workaround client problems (EJAB-1262)
Changes included:
* Remove var in fixed field because Gajim and Tkabber display it to user
* Add workaround for Psi's overlap fields
* Add var=url attribute, required by Psi to display the field
* Provide the image URL as a copy-able form field
2010-10-25 19:00:52 +02:00
Badlop 9c5f34794a Workaround for Psi's wrong Type in form submission 2010-10-25 18:58:31 +02:00
Badlop eca7588abf Recompile the guide.html 2010-10-25 18:57:54 +02:00
Badlop a15d583d4d Add CAPTCHA example configurations to cfg (EJAB-1262)(EJAB-1326) 2010-10-25 18:57:39 +02:00
Evgeniy Khramtsov e03c453c78 Provide image url in registration form when captcha is enabled 2010-10-25 23:36:31 +10:00
Evgeniy Khramtsov 641dc7d695 Add password entropy check (EJAB-1326) 2010-10-24 17:17:30 +10:00
Evgeniy Khramtsov 0a1b0498a6 * Rename option captcha to captcha_protected for consistency.
* Document captcha_protected option
2010-10-24 15:45:42 +10:00
Evgeniy Khramtsov a6858a6ce4 Merge branch '2.1.x' of git+ssh://gitorious.process-one.net/ejabberd/mainline into 2.1.x 2010-10-24 15:30:37 +10:00
Evgeniy Khramtsov f4beeb1706 CAPTCHA IBR support (EJAB-1262) 2010-10-24 15:30:16 +10:00
Badlop 75298b4c27 Improve example of outoging_s2s_options 2010-10-22 23:14:24 +02:00
Christophe Romain 011464e6ac improve documentation (thanks to Karim Gemayel) 2010-10-21 11:14:24 +02:00
Peter Lemenkov c53e8012b2 Change directory before any operation to one readable by INSTALLUSER (EJAB-1322)
This is required in order to suppress error messages like
"File operation error: eacces" when ejabberd was started from directory,
which is not readable by INSTALLUSER (/root, for example). See rhbz #564686:

https://bugzilla.redhat.com/564686

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2010-10-19 01:05:31 +02:00
Badlop fe04d57284 Fix bug in mod_pubsub in_subscription return value 2010-10-19 00:26:36 +02:00
Christophe Romain 0f3bd782c4 documentation update (thanks to Karim Gemayel) 2010-10-18 16:53:21 +02:00
Badlop 91cf9194d8 When privacy list denies local user's outgoing stanza, try to return error (EJAB-1320)
See:
http://xmpp.org/extensions/xep-0016.html#example-51
Example 51. Error: contact is blocked
2010-10-16 22:53:12 +02:00
Badlop e2dbad6242 Check privacy of outgoing IQ stanzas (EJAB-1320) 2010-10-16 22:53:10 +02:00
Badlop 84d4a1619b Check privacy of incoming IQ stanzas (EJAB-1320) 2010-10-16 22:53:08 +02:00
Badlop 16fae4d117 Add support to ejabberd_ctl to handle anonymous command arguments 2010-10-15 21:53:03 +02:00
Badlop 76f7548935 Rename aclocal.m4 to acinclude.m4 (thanks to Andreas Köhler)
Also fixed minor typos, added the compiled aclocal.m4 to gitignore.
As the 2.1.x branch includes the 'configure' script, it isn't needed
to document here how to build it, only in the master branch.

Related documentation:
http://www.gnu.org/software/hello/manual/automake/Local-Macros.html#Local-Macros
http://www.gnu.org/software/hello/manual/automake/Invoking-aclocal.html#Invoking-aclocal
2010-10-15 16:29:47 +02:00
Badlop 2d08dcf11a Fix errors detected by Dialyzer 2010-10-15 13:17:32 +02:00
Badlop 7af47b9dbe Document ejabberd_loglevel using EDoc (EJAB-225) 2010-10-15 13:17:19 +02:00
Andreas Köhler 437da38342 Fix unused variable warning in ejabberd_loglevel 2010-10-15 13:15:52 +02:00
Andreas Köhler 801ee586b7 Add set_custom/2, clear_custom/0 and clear_custom/1 to ejabberd_loglevel 2010-10-15 13:15:50 +02:00
Andreas Köhler 6ff3fda14b Document new loglevel configuration form. 2010-10-15 13:15:49 +02:00
Andreas Köhler cfca2b502a Add support for changing the loglevels for given modules (EJAB-225)
ejabberd_loglevel:set/1 now understands more input formats:

set(Param) -> {module, ejabberd_logger}
    Param = Level | {Level, CustomLevels}
    CustomLevels = [CustomLevel]
    CustomLevel = {Module, Level}
    Module = atom()
    Level = integer() | atom()

set(Level) is equivalent to set({Level, []}), so it clears all module
level customizations. log_src/2 adds additional function heads for those
_msg function and module combinations that need non-default behavior,
i.e. add or filter logging.

ejabberd_loglevel:get/0 only returns the default log level. To retrieve
the complete setting use ejabberd_logger:get/0 instead.
2010-10-15 13:15:48 +02:00
Andreas Köhler e1a4ae8264 Use warning_msg event type for warning log level. 2010-10-15 13:15:46 +02:00
Andreas Köhler 19826858a4 Add warning message and report handlers to ejabberd_logger_h.erl. 2010-10-15 13:15:45 +02:00
Andreas Köhler 0c2677bc50 Improve ejabberd_logger code generation
Split the monolithic function ejabberd_loglevel:ejabberd_logger_src/1
into separate functions returning deep lists.

log_src/2 now returns the code for any of *_msg/4. Its parameters are
the current loglevel (integer()) and a loglevel specification
(#loglevel{}), with added information in #loglevel:

- function: The api function enabled by this level, may be no_log
- event_type: The type of the event sent to the error_logger
- msg_prefix: One character used in the message (one of "DIWEC")

If the current loglevel is too low for logging, the api function is
optimized at compile time.
2010-10-15 13:15:44 +02:00
Andreas Köhler d1c1902687 Use records for encoding static loglevel information. 2010-10-15 13:15:42 +02:00
Badlop a5230c46c2 Speed up ejabberd_s2s:is_service/2, allow_host/2 (thanks to Andreas Köhler)(EJAB-1319)
Iterating through the list of possible parent domains of a given domain
and comparing with the list of hosts or routes is almost always faster
than doing it the other way around. It naturally returns the shortest or
longest parent domain satisfying a predicate, whereas the possibly long
list compared with would need to be sorted by length first.
2010-10-14 21:15:40 +02:00
Badlop 95ce77f80d Include a gitignore file in the ejabberd git repository (EJAB-1312) 2010-10-14 19:53:31 +02:00
Christophe Romain a93f4f7750 make http-bind restartable (thanks to Andreas Köhler)(EJAB-1318) 2010-10-13 10:54:12 +02:00
Evgeniy Khramtsov ac87749d55 add find_s2s_bridge hook 2010-10-11 18:40:57 +10:00
Evgeniy Khramtsov 50b747041f use one_queue IQ discipline by default 2010-10-05 21:28:45 +10:00
Evgeniy Khramtsov 36df8c9035 implement lifetime for broken hashes 2010-10-05 21:27:28 +10:00
Evgeniy Khramtsov 58a5ed9cdc change caps hook name 2010-10-03 16:04:29 +10:00
Evgeniy Khramtsov 5ea909885e call caps hook when caps is changed 2010-10-03 16:02:50 +10:00
Evgeniy Khramtsov 1f2c9b7971 fixes typo in stop_connection/1 2010-09-28 14:20:02 +10:00
Evgeniy Khramtsov c13940e1de new CAPS processing 2010-09-28 14:18:57 +10:00
Evgeniy Khramtsov 8e5297f4c3 fixes default value for cache_life_time 2010-09-21 04:31:18 +10:00
Andreas Köhler 3278f019cb Add missing needdb check in mod_privacy, to enable blocking by group and subscription again. 2010-09-17 18:48:45 +02:00
Andreas Köhler e2c3925b7d Discard unmatched INFO messages in ejabberd services.
This patch will stop services terminating with function clause messages,
but doesn't affect the message queue at all.
2010-09-17 18:48:43 +02:00
Badlop 8a0ccfc401 Support timezone West of UTC (thanks to Edwin Fine)(EJAB-1301) 2010-09-13 12:06:13 +02:00
Evgeniy Khramtsov c29b2fda99 cache lifetime should be converted in microseconds 2010-09-08 02:33:49 +10:00
Evgeniy Khramtsov c75b7b2b12 Implemented dirty (non-atomic) functions; added copyright notice 2010-08-31 18:06:02 +10:00
Badlop c754c91ad1 Add IPv6 support to mod_irc (thanks to Matthias Schiffer)(EJAB-1298) 2010-08-30 23:25:02 +02:00
Evgeniy Khramtsov 6952324509 implemented backend-independed key-value cacheing table; applied to mod_caps.erl first 2010-08-30 14:02:47 +10:00
Badlop 4b5ef8f2ce Add mod_pubsub_odbc to list of ODBC modules (EJAB-1293) 2010-08-21 18:56:01 +02:00
Badlop d87fff1a4c Bugfix http-poll for correctly parsing binary (thanks to Peter Lemenkov) 2010-08-19 17:38:38 +02:00
Evgeniy Khramtsov 3024bb0cbf fixes ampersand escaping (EJAB-1258) 2010-08-19 16:28:31 +10:00
Evgeniy Khramtsov f8dd973373 fixes typo for table copy 2010-08-10 19:42:22 +10:00
Badlop 972440c2ca When user joins non-anonymous room, warn also in presence stanza (EJAB-310) 2010-08-07 20:48:36 +02:00
Badlop b14899d41a Update the 'configure' script 2010-08-07 19:42:56 +02:00
Evgeniy Khramtsov d2d8a09b4a Make MD2 autodetected (EJAB-1285) 2010-08-07 22:04:57 +10:00
Evgeniy Khramtsov 1ea09b09a2 Make xml.c correctly compiles on R14A (EJAB-1288) 2010-08-07 21:06:50 +10:00
Badlop 071c0a1afe Go back to the 2.1.x branch name 2010-08-05 20:39:55 +02:00
Badlop 4ed00c3d1f Fix detection of Erlang R11 and older (thanks to Mathias Ertl)(EJAB-1287) 2010-08-05 20:27:12 +02:00
Evgeniy Khramtsov c9ff370278 Loading ASN.1 driver explicitly to avoid races in LDAP (EJAB-1284) 2010-08-04 19:23:52 +10:00
Badlop 8ab8da82c4 Update ejabberd version number to 2.1.5 2010-08-02 17:38:36 +02:00
Badlop 4b6a42f539 New 2.1.5 release notes 2010-08-02 17:33:16 +02:00
Christophe Romain 8a251ccafe enforce disco features results (thanks to Karim)(EJAB-1033, EJAB-1228, EJAB-1238) 2010-08-02 17:07:23 +02:00
Badlop 550363cd52 Support parallel extauth script (thanks to Jesse Thompson)(EJAB-1280) 2010-07-30 20:33:03 +02:00
Badlop 367353100b Don't say v1.2, because that number is never increased and is confusing 2010-07-28 19:59:39 +02:00
Badlop 5113d28bb4 Return Registered element when account exists (thanks to PioneerMike) 2010-07-28 19:32:42 +02:00
Badlop c8df607173 Fix typo (thanks to Evgeniy Khramtsov) 2010-07-23 00:38:15 +02:00
Badlop c8033833f9 When logging s2s out connection attempt or success, log if TLS is used 2010-07-23 00:25:43 +02:00
Badlop cf4f0dbe6d The command Update now returns meaningful message and exit-status (EJAB-1237) 2010-07-22 16:32:55 +02:00
Evgeniy Khramtsov 8c4884d665 Use driver allocators in iconv_erl.c for reflecting memory in erlang:memory(system) 2010-07-20 15:28:22 +10:00
Evgeniy Khramtsov 26f6eebaa9 Use driver allocators in ejabberd_zlib_drv.c for reflecting memory in erlang:memory(system) 2010-07-20 14:57:23 +10:00
Badlop ac84267b22 Describe what a user gets when he hits the registration_timeout limit 2010-07-19 12:08:02 +02:00
Evgeniy Khramtsov 5030f35558 correct handling of SQL boolean types (EJAB-1275) 2010-07-14 21:23:21 +10:00
Evgeniy Khramtsov d7930d7f82 Use driver allocators in expat for reflecting memory in erlang:memory(system) 2010-07-14 14:19:16 +10:00
Badlop 42ddc297fe Fix my flock change from last friday 2010-07-12 18:53:16 +02:00
Badlop e82db8cc7f Remove ejabberd_debug because p1_prof provides similar and better features 2010-07-12 16:02:52 +02:00
Badlop 10d43c7cc6 Only compile and install p1_prof when: make debugtools=true 2010-07-12 16:02:41 +02:00
Badlop d539fd28c1 Recompile the 'configure' script 2010-07-12 15:18:15 +02:00
Badlop 12e00c57f9 When using OTP R14, use public_key library instead of old ssl (EJAB-953) 2010-07-12 13:57:07 +02:00
Badlop 0c95cf7e61 Mention missing modules in the overview table 2010-07-11 12:14:23 +02:00
Badlop d106f741d9 Some systems delete the lock dir; in such case don't use flock at all 2010-07-09 22:39:13 +02:00
Evgeniy Khramtsov 6c96157d1b Added functions to collect statistics about queues, memory, reductions etc. Several cleanups 2010-07-10 01:36:12 +10:00
Evgeniy Khramtsov a42a012f94 Added new ejabberd profiler 2010-07-05 13:43:44 +10:00
Badlop 7e90d6cf92 Fix print of command result that contains ~ (thanks to Tsukasa Hamano) 2010-07-03 00:42:54 +02:00
Badlop e19ac27803 Show some more room options in the log file 2010-07-02 15:19:54 +02:00
Badlop c100cbedd1 Document the mod_muc option captcha_protected 2010-07-02 13:08:33 +02:00
Evgeniy Khramtsov 4c2e7e38a1 Use ets insead of asking supervisor in ejabberd_odbc_sup:get_pids/1 (Thanks to Alexey Shchepin) 2010-07-02 20:31:42 +10:00
Badlop fa22b23435 Recompile the Guide and Configure 2010-07-01 17:03:36 +02:00
Badlop c3c23a04f6 Requirement of OpenSSL increased from 0.9.6 to 0.9.8 2010-07-01 17:01:13 +02:00
Badlop ae6545989e Fix typo in --enable-transient_supervisors 2010-07-01 16:59:26 +02:00
Badlop baeb3d076e Document the optional --enable-nif 2010-07-01 16:57:47 +02:00
Badlop 0ac5684bf0 Clarify that to use the optional --enable-nif, R13B04 is needed. 2010-07-01 16:51:26 +02:00
Evgeniy Khramtsov 715cc5ea3b New configure option: --enable-nif 2010-07-01 20:54:01 +10:00
Badlop d9e2931ed9 Fix privacy check when serving local Last (thanks to Brian Acton)(EJAB-1271) 2010-06-29 11:58:05 +02:00
Badlop 1531541331 Fix problem when FIREWALL_WINDOW options for erl kernel were used
http://www.ejabberd.im/node/4120
2010-06-28 13:17:55 +02:00
Badlop b7e02cc42e Inform client that SSL session caching is disabled (thanks to Pawel Chmielowski) 2010-06-25 18:33:49 +02:00
Badlop 3ab90c9d3a Don't ask for client certificate when using tls (EJAB-1267) 2010-06-25 18:33:46 +02:00
Badlop 1b7948f50a OpenSSL is required, not optional 2010-06-25 16:56:44 +02:00
Badlop fe23dbd76e When account is deleted, delete also member of stored shared rosters. 2010-06-24 00:02:16 +02:00
Evgeniy Khramtsov 21d2f4efab now admins are able to see private rooms in disco (EJAB-1269) 2010-06-23 17:44:35 +10:00
Evgeniy Khramtsov f66f049ef3 Added support for all hash functions required by XEP-0115 2010-06-22 03:10:41 +10:00
Evgeniy Khramtsov 49dd83e731 Added md2/1 support 2010-06-22 02:56:34 +10:00
Evgeniy Khramtsov 9cd2d5e0cf New OpenSSL functions wrapper: sha224/1, sha256/1, sha384/1, sha512/1 2010-06-22 02:30:16 +10:00
Badlop fab705dc13 Rebuilt the configure script with: autoconf 2010-06-16 16:05:45 +02:00
Peter Lemenkov a84f8bc9ef Pass correct version to autoreconf
It seems that AC_INIT macro is wrongly initialized. See this link
for explanation of a particular AC_INIT variables:

http://www.gnu.org/software/autoconf/manual/html_node/Initializing-configure.html

Briefly, AC_INIT macro should be populated with the following data:

AC_INIT (package, version, [bug-report], [tarname], [url])

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2010-06-16 16:05:07 +02:00
Peter Lemenkov 2477b735bf Install COPYING file along with other docs
It's a generally good idea to provide file with licensing terms.

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2010-06-16 16:05:07 +02:00
Peter Lemenkov 8db328af60 Install dev.html, and guide.pdf if it exists
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2010-06-16 16:05:07 +02:00
Christophe Romain bc2280be70 remove outdated and useless file, use ejabberdctl.template instead 2010-06-16 12:20:08 +02:00
Badlop a28aaa1fdd Log error when HTTP request has ambiguous Host header (EJAB-1261) 2010-06-16 11:33:17 +02:00
Badlop afa0f4d403 Fix for Erlang R12, that doesn't support: true andalso ok 2010-06-15 22:59:53 +02:00
Jerome Sautret 0e5b930b22 Discard queued requests that are too old (the caller has already got a timeout). 2010-06-11 16:35:45 +02:00
Badlop 7d8f8a7e99 Explain that 2 LDAP connections are established per vhost 2010-06-10 13:58:55 +02:00
Badlop a7924adee9 Fix typo in update_list command (EJAB-1237) 2010-06-07 15:58:16 +02:00
Badlop d4ec7a2f01 New optional BOSH connection attribute process-delay (EJAB-1257) 2010-06-07 13:44:55 +02:00
Badlop e0fab19345 Revert version number from 2.1.4 tag to 2.1.x branch 2010-06-04 11:26:42 +02:00
Evgeniy Khramtsov 4646a5dbb8 fixes wrong SQL escaping when --enable-full-xml is set 2010-06-04 13:31:34 +10:00
Badlop 1567592ac7 Update ejabberd version number to 2.1.4 2010-06-02 18:48:55 +02:00
Badlop 3b735c269c Remove duplicate item in release notes 2010-06-02 18:23:19 +02:00
Badlop 5bdef05f12 Add release notes for ejabberd 2.1.4 2010-06-02 17:33:35 +02:00
Badlop 077626c40a Clarify in the Guide that mssql configuration is similar to odbc 2010-06-02 17:10:48 +02:00
Christophe Romain c544384c83 sync last changes in pubsub_odbc patch 2010-06-02 16:46:02 +02:00
Christophe Romain d56522c8a0 final fix on created node notification (EJAB-1225) 2010-06-02 14:37:18 +02:00
Badlop b83e77ca21 Update the Norwegian translation (thanks to Stian B. Barmen) 2010-06-01 19:44:27 +02:00
Badlop 361400691d Recommend Erlang/OTP R12B-5 and R13B04 2010-06-01 15:45:00 +02:00
Badlop ba9247c530 Update the Slovak translation (thanks to Marek Bečka) 2010-05-31 00:27:58 +02:00
Badlop 91d22109c8 Update the Czech translation (thanks to Lukáš Polívka) 2010-05-28 18:46:08 +02:00
Badlop cb702a770d Update the Russian translation (thanks to Evgeniy Khramtsov) 2010-05-28 18:46:06 +02:00
Christophe Romain db059bdfaf fix error code when unsubscribing from a non-existent ODBC node (EJAB-1227) 2010-05-28 13:42:35 +02:00
Christophe Romain 2291a6afea fix error code when unsubscribing from a non-existent node (thanks to Karim Gemayel)(EJAB-1227) 2010-05-28 13:37:20 +02:00
Christophe Romain af7fe0c21e send created node notifications (EJAB-1225) 2010-05-28 13:34:05 +02:00
Christophe Romain 7ce3291603 fix jlib calls from previous patch 2010-05-28 12:33:11 +02:00
Christophe Romain 07e870271e make last_item_cache feature cluster aware (EJAB-1234) 2010-05-28 11:56:09 +02:00
Badlop a5f8aeb6da Handle error response from auth modules (thanks to Eric Liang) 2010-05-28 01:36:19 +02:00
Badlop 1777ecd15a Makefile with optional ejabberd_debug.erl compilation (EJAB-1242)
Only compile and install ejabberd_debug.erl when running:
 make ejabberd_debug=true
2010-05-28 00:51:25 +02:00
Christopher tofu Zorn d4d45f3a50 remove the silly loop that isnt needed, this speeds up all requests by 100 milliseconds. Clean up prepare response function and add two new functions to handle out going payloads based of whether its a new session or not. 2010-05-27 21:21:17 +02:00
Badlop 9900be3d68 Update the Portuguese Brazil translation (thanks to Otávio Fernandes) 2010-05-26 19:53:32 +02:00
Badlop b88372c313 Update the Ukrainian translation (thanks to Konstantin Khomoutov) 2010-05-26 19:53:29 +02:00
Badlop e4aab7f749 Add created_at column also to PostgreSQL schema (thanks to Mathias Ertl)(EJAB-1240) 2010-05-26 16:13:45 +02:00
Badlop 42cbd0c1c4 Update the Catalan translation (thanks to Jan Kusanagi) 2010-05-25 20:11:16 +02:00
Badlop 9318678e08 Mix the commands update_all/0 and update_module/1 into update/1 (EJAB-1237) 2010-05-25 20:01:04 +02:00
Badlop bd992bcb87 Update the Italian translation (thanks to Luca Brivio) 2010-05-25 12:18:16 +02:00
Badlop 01d2bcfd92 Update the Greek translation (thanks to James Iakovos Mandelis) 2010-05-24 20:44:23 +02:00
Badlop 0bfda4e628 New ejabberd commands to update modified modules (EJAB-1237) 2010-05-24 13:58:11 +02:00
Badlop a2f659a2c6 Only log when script errors are found 2010-05-24 13:58:10 +02:00
Badlop 9a04a60c7d Update the Polish translation (thanks to Zbyszek Żółkiewski) 2010-05-24 13:34:54 +02:00
Badlop 7238ab6f05 Update the Dutch translation (thanks to Andreas van Cranenburgh) 2010-05-24 11:10:41 +02:00
Badlop dd954ef1c2 Update the Esperanto translation (thanks to Andreas van Cranenburgh) 2010-05-24 11:10:30 +02:00
Badlop f1b8853339 Update the German translation (thanks to Nikolaus Polak) 2010-05-23 16:21:44 +02:00
Badlop 479a2adaae Recompile Japanese translation 2010-05-23 02:30:30 +02:00
Tsukasa Hamano dd3c939025 update ja.po 2010-05-23 02:30:21 +02:00
Badlop 767e7d65ef Update the French translation (thanks to Nicolas Vérité) 2010-05-23 02:29:44 +02:00
Badlop 5feb20afd0 Update the Chinese translation (thanks to Shelley Shyan) 2010-05-23 02:28:57 +02:00
Badlop 9038bbd3e7 Update the Spanish translation 2010-05-23 02:28:26 +02:00
Badlop 506fbbe7f7 Update translations 2010-05-20 21:12:36 +02:00
Christopher tofu Zorn 08f1f55e0c typo on exported function 2010-05-20 20:45:37 +02:00
Christopher tofu Zorn 5ea9a0ddb7 expose more functions so developers can implement prebinding methods 2010-05-20 20:32:07 +02:00
Christophe Romain d4e0fab06b fix EJAB-1233 on pubsub_odbc patch 2010-05-19 11:05:02 +02:00
Christophe Romain 217aaf78f9 prevent orphaned pubsub node (EJAB-1233) 2010-05-19 10:47:47 +02:00
Badlop 2ee788e0bf Fix English typos 2010-05-17 11:54:22 +02:00
Christophe Romain f0f4b2719c sync pubsub_odbc with latest code 2010-05-12 13:54:44 +02:00
Christophe Romain 406a31c8be Enforce pubsub#show_values subscription option (EJAB-1096)(thanks to Karim Gemayel) 2010-05-12 13:45:56 +02:00
Badlop c32332898b Show HTTP auth username and IP address in logs, not the password (EJAB-1231) 2010-05-12 10:27:47 +02:00
Badlop 4bbf6684b4 Don't show HTTP request in logs, because reveals password (EJAB-1231) 2010-05-10 23:23:31 +02:00
Badlop 9476d8a2c3 Optionally cache extauth users in mnesia (EJAB-641) 2010-05-10 16:42:54 +02:00
Badlop 6ac46c6171 Fix EDoc comment 2010-05-10 16:12:48 +02:00
Badlop 6ae8b9c4d6 Use a standard method to get a random seed (EJAB-1229) 2010-05-10 15:38:38 +02:00
Badlop 39119192a1 New option pam_userinfotype to provide username or JID (EJAB-652) 2010-05-10 15:14:49 +02:00
Badlop 25e4038623 Recompile the guide 2010-05-10 15:11:40 +02:00
Evgeniy Khramtsov f58d03c12e new option ldap_tls_verify is added (EJAB-1229) 2010-05-10 19:37:37 +10:00
Evgeniy Khramtsov 58590cf08d full support for XEP-0115 v1.5 (EJAB-1223) (EJAB-1189) 2010-05-08 02:32:57 +10:00
Christopher tofu Zorn cce57310b0 Change max inactivity from 30 to 120 seconds 2010-05-06 20:52:40 +02:00
Christopher tofu Zorn 516d369174 Use dirty_delete when removing the session.
There is no need for a transaction and has less overhead
2010-05-06 20:52:36 +02:00
Christophe Romain 7fc1207661 enforce pubsub#presence_based_delivery (EJAB-1221) (thanks to Karim Gemayel) 2010-05-05 15:42:49 +02:00
Badlop 951808658d Indicate explicitly what nodes are handled by mod_configure 2010-05-04 11:37:44 +02:00
Badlop cd9e1621f9 Add xml default content type (thanks to Aaron Winborn)(EJAB-1214) 2010-04-28 20:06:27 +02:00
Badlop 650966ce2c Minor fixes in listeners options list 2010-04-28 20:06:27 +02:00
Badlop 2a99af8cce Rename some JEP references to XEP 2010-04-28 20:06:27 +02:00
Badlop 3ba0061ada Reduce verbosity of log when captcha_cmd is checked but not configured. 2010-04-28 20:06:27 +02:00
Badlop 705c5b4c1c New Access rule webadmin_view for read-only (thanks to Oleg Palij)(EJAB-213) 2010-04-27 23:27:44 +02:00
Badlop 6ae1f62469 Don't store blocked messages in offline queue (thanks to Brian Acton)(EJAB-1224) 2010-04-27 13:30:00 +02:00
Badlop 1c00a9713d Automatic vcard avatar addition in presence (thanks to Igor Goryachev)(EJAB-208) 2010-04-27 12:33:56 +02:00
Badlop 5e7d8868c0 No need to handle IQ requests other than Get and Set 2010-04-22 20:19:42 +02:00
Emilio Bustos 55dbdf5dba Fixed Bugs handling Service Discovery to contacts.
Resolves [#EJAB-1207]
2010-04-22 10:29:20 -03:00
Badlop 2ff291899d Don't send error stanza as reply to error stanza (EJAB-930) 2010-04-20 20:31:42 +02:00
Badlop 2d375e0429 Recompile the Guide 2010-04-19 15:22:10 +02:00
Evgeniy Khramtsov 4669ae0a81 added notes about LDAP password change 2010-04-19 23:05:48 +10:00
Evgeniy Khramtsov c2362db03d allow inband password change (EJAB-199) 2010-04-19 20:57:24 +10:00
Evgeniy Khramtsov 1405e9d375 LDAP extensible match support (EJAB-722) 2010-04-19 14:08:00 +10:00
Pablo Polvorin 84c4d75735 Remove warning for undefined print_state/1 function for p1_fsm processes (thanks Badlop).
Include a identity function as implementation of print_state/1.
2010-04-09 14:25:00 -03:00
Pablo Polvorin 41aa693896 Allow customizing the StateData in p1_fsm before error reporting.
A new callback is introduced on the p1_fsm behaviour:

print_error/1

If the module implements this function, it will be invoked
in case of process crash with the current state data *before*
printing the error in the log. The function must return the
desired State to print.

It is used in ejabberd_c2s to prune the presence sets that
can be large. Instead, the state is changed to include only
the # of elements on each set.

Change inspired in comming changes to gen_server on OTP, and
http://github.com/erlyvideo/erlyvideo/commit/b01d15abc3189226dbf824db19db22da35fa33a0#diff-0
2010-03-30 16:39:34 -03:00
Badlop 44b282474a Fix indentation (EJAB-1038) 2010-03-29 20:51:24 +02:00
Badlop 70cfcb1008 Fix crash in number of occupants; other minor changes (EJAB-1038) 2010-03-29 20:51:04 +02:00
Badlop fa28c8baf6 Refactor code to reduce calls to get_affiliation and get_role (thanks to Steam)(EJAB-1038) 2010-03-29 20:49:52 +02:00
Evgeniy Khramtsov 584fa98564 - pass jid into feature_check_packet hook;
- bounce messages when closing c2s session;
- implemented treap:to_list/1 and treap:from_list/1
2010-03-17 23:40:48 +09:00
Mickael Remond 214c62bf9c Move HTTP session timeout log from warning level to info. Timeout can be generated when user close the browser for example. 2010-03-15 11:42:11 +01:00
Badlop 962b66b099 Update ejabberd version number to 2.1.3 2010-03-12 10:21:32 +01:00
Badlop 417cf11bdd Add 2.1.3 release notes 2010-03-11 20:50:26 +01:00
Christophe Romain b3da1c7d86 improve remove_user (EJAB-1172) 2010-03-11 16:00:42 +01:00
Evgeniy Khramtsov 839b406903 don't route PEP error messsages to a client 2010-03-09 14:03:27 +09:00
Peter Lemenkov 95e085beb7 More compliance with LSB
The init-script shall return 4 in case then user doesn't have sufficient privileges for action.
See http://refspecs.freestandards.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2010-03-08 21:16:18 +01:00
Christophe Romain df63fcd353 typo fix on previous pubsub patch 2010-03-08 15:40:08 +01:00
Christophe Romain 77e549e504 allow sending PEP to bare jid on s2s 2010-03-08 15:16:58 +01:00
Badlop 20c2bc54cd Document mod_sic (EJAB-1205) 2010-03-08 13:58:22 +01:00
Badlop 63ccbe90d3 Implement XEP-0279: Server IP Check (thanks to Karim Gemayel)(EJAB-1205) 2010-03-08 13:58:06 +01:00
Badlop 1f02b5db0f Fix warnings about unused variable. 2010-03-08 12:43:38 +01:00
Badlop 6bde01cd45 Replace concat_binary supported until R14 with list_to_binary supported since R9 2010-03-08 12:41:11 +01:00
Badlop f36ac2b809 Catch errors when exporting to PIEFXIS file (EJAB-1178) 2010-03-08 11:13:56 +01:00
Badlop e4f19df428 Recompile the Guide 2010-03-08 11:07:28 +01:00
Evgeniy Khramtsov 606860e1cc ldap_dn_filter option is documented; now fetching only needed attributes in LDAP search requests (EJAB-1204) 2010-03-08 16:44:14 +09:00
Evgeniy Khramtsov 22d490486a now using "%u" pattern as default for ldap_uids (EJAB-1203) 2010-03-08 14:04:56 +09:00
Christophe Romain d2d06403ac fix mistake in previous broadcast_stanza change 2010-03-05 18:20:22 +01:00
Christophe Romain 6ee8ec49a5 add extended stanza addressing 'replyto' on PEP (EJAB-1198) (thanks karim) 2010-03-05 17:52:41 +01:00
Denis Kurochkin 6e878d17e6 MSSQL support was broken (EJAB-1201) 2010-03-05 14:40:33 +01:00
Christophe Romain 4984320f17 fix compilations issues 2010-03-05 11:53:26 +01:00
Christophe Romain 09250c0b65 minor intentation fix, and sync _odbc code 2010-03-05 11:35:20 +01:00
Christophe Romain 6e8f5a9cd3 add pubsub#purge_offline (EJAB-1186) (thanks karim) 2010-03-05 11:11:44 +01:00
Christophe Romain c3edcd0575 fix pubsub#title option (EJAB-1190) (thanks karim) 2010-03-05 10:40:34 +01:00
Christophe Romain 6fb99fbb48 mod_caps optimizations (thanks evgeniy) 2010-03-05 10:34:15 +01:00
Evgeniy Khramtsov 31c3a78453 improved s2s connections clean up (EJAB-1202) 2010-03-04 12:36:57 +09:00
Pablo Polvorin a3f2588df6 Remove print debug (thanks evgeniy) 2010-03-02 12:45:59 -03:00
Badlop 41c455fabb Add quotes in documentation of some erl arguments (thanks to Vincent Courcelle)(EJAB-1191) 2010-02-25 00:04:48 +01:00
Badlop 8045fec882 Fix German translation (thanks to Florian Zumbiehl)(EJAB-1195) 2010-02-24 23:06:09 +01:00
Badlop 414004eae4 Fix resending authorization problem 2010-02-24 13:14:45 +01:00
Badlop 8e8a1a3bf5 Run user_receive_packet also when sending offline messages to client (thanks to Brian Acton)(EJAB-1193) 2010-02-22 22:57:08 +01:00
Badlop fbd8547d94 Fix typos in example config comments (thanks to Florian Zumbiehl)(EJAB-1192) 2010-02-22 13:40:42 +01:00
Badlop 6df9a6ab33 Use alternative of file:read_line/1 to not require R13B02 2010-02-20 19:31:36 +01:00
Evgeniy Khramtsov 2907446e87 fixes typo in Russian translation 2010-02-20 20:41:39 +09:00
Evgeniy Khramtsov f60804b060 get rid of queue:filter/2 to keep compatibility with older Erlang versions 2010-02-20 20:05:48 +09:00
Evgeniy Khramtsov e569087d83 now using mnesia:async_dirty when cleaning table from failed node 2010-02-19 16:38:18 +09:00
Badlop 4a7a33168a Reduce verbosity of HTTP Binding log messages (thanks to Alexey Shchepin) 2010-02-19 00:01:26 +01:00
Badlop d7fbad6fa1 Recompile guide.html 2010-02-18 22:13:28 +01:00
ekhramtsov e6c23e0413 improved explanation of "max_fsm_queue" option; included this option in ejabberd.cfg.example (EJAB-1185) 2010-02-18 15:48:11 +09:00
ekhramtsov 35e00ebcf6 option "access_from" is now documented (EJAB-1187) 2010-02-18 14:57:08 +09:00
ekhramtsov 1a96944929 new option "hostname" is added (thanks to Stefan Hepp) (EJAB-838) 2010-02-17 23:17:33 +09:00
Badlop bc69b96e4c Close also legacy sessions that were half connected (thanks to Evgeniy Khramtsov)(EJAB-1165) 2010-02-16 12:46:20 +01:00
Badlop 35c9c95e4b Remove references to the old SVN repository. 2010-02-16 11:55:01 +01:00
Badlop 47ee65d101 Rewrite mnesia counter functions to use dirty_update_counter (EJAB-1177)
(thanks to Juan Pablo Carlino and Alexey Shchepin)
2010-02-15 23:38:17 +01:00
Badlop 8a856df2f0 New command to set master Mnesia node 2010-02-15 23:24:48 +01:00
Badlop 6795675108 Shared roster gets contact nickname from vcard, when available (EJAB-114) 2010-02-15 22:47:28 +01:00
Badlop 6867ca43e4 Cross-domain HTTP-Bind support (thanks to Jack Moffitt)(EJAB-1168) 2010-02-15 22:42:59 +01:00
Badlop ab0905ce56 Fix cluster race condition in route read (thanks to Alexey Shchepin) 2010-02-15 18:29:17 +01:00
Badlop a71b47ea27 Improve TTY code to work on more operating systems (thanks to Jan Koum) 2010-02-12 22:11:15 +01:00
Badlop 2cca00acc0 Added support for Jot in ctl and TTY in debug (thanks to Jan Koum) 2010-02-12 20:50:56 +01:00
Badlop 7c36e304f0 Minor fixes in the new ejabberdctl flock code 2010-02-12 20:25:31 +01:00
Martin Langhoff 10c16b1cdf ejabberdctl: support concurrent connections with bound conn names
If flock is available, ejabberdctl will use it to grab one
of a bound number of connection names. This allows concurrent
connections while using a bound number of atoms.

Using PID, timestamps or random strings for transient connection IDs
(which would avoid the need for flock) uses an unbound number of atoms.
This can effectively DoS servers, as these connection names are
not garbage collected.
2010-02-12 20:23:33 +01:00
Badlop 8bd37462cb Remove unnecessary section about Snow Leopard with Erlang R13B 2010-02-11 13:20:06 +01:00
Badlop 78f1fe9ba5 Replace mention of ejabberd SVN with Git. 2010-02-11 13:14:55 +01:00
Badlop b17c7848fd Fix bashism in 'ejabberdctl started' 2010-02-11 11:02:57 +01:00
Badlop 071aa123e8 Allow a request_handler to serve a file in root of HTTP 2010-02-10 20:17:09 +01:00
Badlop abdb7f2742 Fix character in README file
SVN Revision: 2963
2010-02-05 13:30:27 +01:00
Pablo Polvorin bc70e90853 Add new debuging hook to the http receiving process.
The new hook is called http_request_debug, and receive the  LocalPath and Request as parameter.

SVN Revision: 2961
2010-02-05 13:30:27 +01:00
Pablo Polvorin 787e078f6a Hibernate http-bind process after handling a request.
When using BOSH, this reduces memory consuption of the http-bind process, with negligible CPU impact.

SVN Revision: 2960
2010-02-05 13:30:27 +01:00
Pablo Polvorin 17607ecaa4 Bug Fix: The value of max # of erlang process specified in ejabberdctl.cfg was not used.
It was called PROCESSES in the .cfg file,  and ERL_PROCESSES in the script.  The latter is the correct,  to be coherent with ERL_MAX_PORTS and ERL_MAX_ETS_TABLES.

SVN Revision: 2959
2010-02-05 13:30:26 +01:00
Evgeniy Khramtsov 9d84caebdb avoid resending <stream:error> stanzas on terminate (EJAB-1180)
SVN Revision: 2955
2010-02-03 11:25:03 +00:00
Evgeniy Khramtsov 35bcadde7a avoid 'invalid' value in #iq{} record
SVN Revision: 2954
2010-02-02 13:41:34 +00:00
Evgeniy Khramtsov d9e345a4d8 iq_query_info/1 now returns 'invalid' if XMLNS is invalid
SVN Revision: 2953
2010-02-02 12:20:19 +00:00
Evgeniy Khramtsov 46c667c567 changed Reason to shutdown when stopping destroyed MUC room
SVN Revision: 2952
2010-02-02 11:49:49 +00:00
Badlop db3f8487fc Fix bug handling Reason in gen_fsm:terminate
SVN Revision: 2950
2010-02-02 11:14:48 +00:00
Evgeniy Khramtsov 34234b4a46 Added new acl for mod_register: access_from. This acl is applied if existing account tries to register a new account (either via s2s or c2s). The default value is to deny such operations.
SVN Revision: 2949
2010-01-31 13:55:10 +00:00
Evgeniy Khramtsov 03454c7f1d improved SQL reconnect behaviour
SVN Revision: 2947
2010-01-31 11:41:28 +00:00
Evgeniy Khramtsov 1cced15c0d regenerated guide.html
SVN Revision: 2945
2010-01-28 15:37:42 +00:00
Evgeniy Khramtsov 4c8beae585 ejabberd_c2s option "max_fsm_queue" is now documented
SVN Revision: 2941
2010-01-28 13:56:38 +00:00
Evgeniy Khramtsov 0a3cfeeed9 new ejabberd_c2s option support: max_fsm_queue
SVN Revision: 2939
2010-01-28 13:44:49 +00:00
Evgeniy Khramtsov 933d4a69b8 fixes regression with configure script
SVN Revision: 2938
2010-01-28 13:34:17 +00:00
Evgeniy Khramtsov 352afa7902 now using p1_fsm behaviour in c2s FSM (EJAB-1173)
SVN Revision: 2936
2010-01-28 13:00:04 +00:00
Mickaël Rémond ce18cfb41b Fix typo in doc
SVN Revision: 2928
2010-01-26 13:16:51 +00:00
Badlop 4fe8d76b83 Fix documentation installation, no need for executable permission (thanks to Peter)(EJAB-1170)
SVN Revision: 2926
2010-01-25 18:40:17 +00:00
Badlop d804698541 Fix typo in EJABBERD_BIN_PATH (thanks to Martin Langhoff)(EJAB-891)
SVN Revision: 2925
2010-01-25 18:37:58 +00:00
Badlop 1b1a0d7ed3 Support in ejabberdctl help command names with old - characters.
SVN Revision: 2924
2010-01-25 18:32:45 +00:00
Badlop a0de5bc317 Revert version number from 2.1.2 tag to 2.1.x branch
SVN Revision: 2916
2010-01-18 14:37:36 +00:00
Badlop a77b6946cf Update version number to 2.1.2
SVN Revision: 2914
2010-01-18 12:11:16 +00:00
Badlop cbbb7256ae Add ejabberd 2.1.2 release notes
SVN Revision: 2913
2010-01-18 12:11:09 +00:00
Badlop 16bd626fc9 Close sessions that were half connected (thanks to Alexey Shchepin)(EJAB-1165)
SVN Revision: 2911
2010-01-17 19:28:35 +00:00
Badlop 8068fdf4e3 Fix some moved URLs in the Guide
SVN Revision: 2908
2010-01-16 14:34:35 +00:00
Badlop b6aa6d6f09 Document the option route_subdomains in the Guide (EJAB-1164)
SVN Revision: 2907
2010-01-16 14:34:31 +00:00
Badlop 86794b1d23 Fix OTP version detection to work with old supported R10 and R11
SVN Revision: 2906
2010-01-16 12:24:11 +00:00
Badlop 3e4858f348 Improve functions calls when closing client connection.
SVN Revision: 2904
2010-01-15 12:01:12 +00:00
Christophe Romain 7aff5defac improve delete_subscriptions code
SVN Revision: 2902
2010-01-14 12:51:22 +00:00
Christophe Romain 6ad93eb609 add send_loop robustness
SVN Revision: 2899
2010-01-13 10:22:55 +00:00
Badlop 9f5246cacc If big offline message queue, show only subset on WebAdmin (EJAB-1095)
SVN Revision: 2896
2010-01-12 23:58:22 +00:00
Badlop 855d427182 Fix explanation of access_max_user_messages.
SVN Revision: 2895
2010-01-12 23:57:44 +00:00
Badlop 4d85297c85 Check for Effective GID EGID in ejabberdctl (thanks to Rustam Aliyev)(EJAB-1160)
SVN Revision: 2893
2010-01-12 17:50:21 +00:00
Badlop 7b76fdcde7 Update year of ProcessOne copyright from 2009 to 2010 (EJAB-1159)
SVN Revision: 2891
2010-01-12 16:11:32 +00:00
Badlop 6179daaf99 For XEP-0227 support, get exmpp 0.9.2; maybe 0.9.1 works too.
SVN Revision: 2889
2010-01-12 15:52:46 +00:00
Christophe Romain 0cc58d7a71 remove useless comment
SVN Revision: 2888
2010-01-12 15:25:59 +00:00
Christophe Romain e5373de2b9 avoid calling gen_server on internal events (EJAB-1156)
SVN Revision: 2886
2010-01-12 15:14:47 +00:00
Christophe Romain 6ddff15b39 allow unsubscribe with 'all' SubId, as mod_pubsub already does
SVN Revision: 2884
2010-01-12 14:39:52 +00:00
Christophe Romain 392ea78acf fix NodeName issue from r2880 (thanks to Karim Gemayel)
SVN Revision: 2882
2010-01-12 13:27:04 +00:00
Christophe Romain 024b688c1d fix r2876 compilation warning
SVN Revision: 2880
2010-01-12 12:31:08 +00:00
Christophe Romain 276f890c50 apply r2876 on pubsub_odbc
SVN Revision: 2879
2010-01-12 12:12:28 +00:00
Badlop ee77257d41 Support in user list page of WebAdmin when mod_offline is disabled (EJAB-377)
SVN Revision: 2877
2010-01-12 12:02:50 +00:00
Christophe Romain e7a8bf6154 fix headers (EJAB-1091), (EJAB-1092), (EJAB-1093) (thanks to Karim Gemayel)
SVN Revision: 2876
2010-01-12 10:33:39 +00:00
Badlop 4f643ce9b8 Show and throw error when captcha_cmd is required but not configured.
SVN Revision: 2874
2010-01-11 22:21:23 +00:00
Badlop 8447dfa4b1 Minor case code simplification.
SVN Revision: 2873
2010-01-09 18:39:17 +00:00
Mickaël Rémond 7b05ba0e1e Match Erlang typing documentation, to remove dialyzer warning. Code was working fine however.
SVN Revision: 2870
2010-01-09 16:31:45 +00:00
Mickaël Rémond c8fd680d92 Attempt to fix dialyzer warning: adhoc.erl:51: Guard test XData::'false' | #xmlel{ns::'jabber:x:data',declared_ns::[{_,_}],attrs::[{_,_,_,_}],children::'undefined' | [{_,_} | {_,_,_,_,_,_}]} =:= 'true' can never succeed
SVN Revision: 2869
2010-01-09 16:18:59 +00:00
Mickaël Rémond 24aefc429c Small refactoring
SVN Revision: 2867
2010-01-09 15:15:46 +00:00
Badlop 0bf9832187 An AccessCommand with Access 'all', don't require auth to execute it.
SVN Revision: 2865
2010-01-09 00:39:33 +00:00
Badlop 761ed1b192 Fix so script runs correctly when invoked by root (EJAB-1152)
SVN Revision: 2862
2010-01-05 19:43:03 +00:00
Badlop 05ee83bddc Improve parsing of ejabberd_sm:get_user_info result.
SVN Revision: 2857
2010-01-04 18:59:01 +00:00
Christophe Romain f30783a2d2 add explicit comment on last published items configuration (EJAB-1130)
SVN Revision: 2855
2010-01-04 11:49:00 +00:00
Badlop ee41e1eb70 Show the last activity time in the user page.
SVN Revision: 2854
2010-01-03 00:40:37 +00:00
Badlop 8d218dd2b9 Command to stop ejabberd informing users, with grace period, and kindly (EJAB-1112)
SVN Revision: 2853
2010-01-03 00:38:00 +00:00
Badlop 7cbda8badb When ejabberd stops, send stream close to clients (thanks to Alexey Shchepin)(EJAB-1112)
SVN Revision: 2852
2010-01-03 00:35:51 +00:00
Badlop 15a27c0566 Improve log message when showing lines of config file.
SVN Revision: 2850
2009-12-30 01:36:07 +00:00
Badlop d9a1eecdca Kick occupants with reason when room is stopped due to MUC shutdown (EJAB-1149)
SVN Revision: 2848
2009-12-30 01:25:35 +00:00
Badlop 5d749de74d Fix warning about unused variable
SVN Revision: 2846
2009-12-29 23:12:52 +00:00
Badlop dbad3df333 If problem in config file starting ejabberd: display config lines and stop node (EJAB-1148)
SVN Revision: 2844
2009-12-29 22:48:25 +00:00
Badlop 50137aa98d Add +export_all to EFLAGS if: make debug=true (thanks to Marcin Owsiany)(EJAB-1134)
SVN Revision: 2842
2009-12-29 19:10:52 +00:00
Badlop f0863e1dfe Support also SASL PLAIN auth messages described in RFC4616 (EJAB-1132)
SVN Revision: 2839
2009-12-29 18:44:17 +00:00
Badlop 1713bf635d Disable code of recent commit because some clients can't handle it (EJAB-1058)
SVN Revision: 2838
2009-12-29 18:44:02 +00:00
Badlop 9bee86178f Write in room log when a room is created, destroyed, started, stopped (EJAB-1144)
SVN Revision: 2836
2009-12-29 14:43:24 +00:00
Badlop 455d85a278 Send features after negotiating binding and session (EJAB-1058)
SVN Revision: 2834
2009-12-28 20:09:46 +00:00
Badlop d812975565 Provide more detailed log message when s2s stream start fails.
SVN Revision: 2831
2009-12-28 15:29:42 +00:00
Badlop 9aa9c34a57 Better use install_fallback when importing a Mnesia backup file.
SVN Revision: 2829
2009-12-28 12:43:44 +00:00
Badlop 34d5d08501 Support for arguments in ejabberdctl that are empty strings.
SVN Revision: 2827
2009-12-28 11:45:46 +00:00
Badlop 71142e336d Add explanation about global Access precendence over vhost Access (EJAB-803)
SVN Revision: 2824
2009-12-23 16:08:34 +00:00
Badlop c7f4f39c03 Fix error message when register is forbidden by ACL (EJAB-803)
SVN Revision: 2823
2009-12-23 16:08:20 +00:00
Badlop b2d6a25240 Improved Polish translation (thanks to Janusz B. Wiśniewski and Zbigniew Żółkiewski)(EJAB-1138)
SVN Revision: 2822
2009-12-23 14:23:45 +00:00
Badlop 4a57f5db74 Recompile all translation files
SVN Revision: 2821
2009-12-23 14:23:30 +00:00
Badlop 4cdf7fba4f Clarify that 'tls' option is still useful in ejabberd_http for HTTPS.
SVN Revision: 2819
2009-12-23 09:04:39 +00:00
Badlop 341e47c2a4 Remove the old note about LDAP lack of encryption.
SVN Revision: 2817
2009-12-21 16:10:51 +00:00
Badlop 675c24f5eb pep_mapping not working due to Node type mismatch (EJAB-1135)
SVN Revision: 2815
2009-12-21 15:13:44 +00:00
Badlop 15abddb7a8 Fix EDoc comment
SVN Revision: 2814
2009-12-21 14:35:09 +00:00
Badlop 3df45683ff Fix get_group_opt to return Default value in case of Mnesia error.
SVN Revision: 2811
2009-12-19 00:16:32 +00:00
Badlop ef49822a47 Update branch version name back to 2.1.x
SVN Revision: 2810
2009-12-17 18:08:07 +00:00
Badlop 402a8c0d35 Prepare 2.1.1 release
SVN Revision: 2808
2009-12-14 14:15:45 +00:00
Badlop d24449488c Print command's reply and newline only when there's something to print.
SVN Revision: 2806
2009-12-11 20:04:36 +00:00
Badlop b9e57a341d Added to ejabberdctl an experimental variable EJABBERD_BYPASS_WARNINGS
SVN Revision: 2804
2009-12-11 19:42:59 +00:00
Badlop 79be929d96 Add support for serving a Unique Room Name (thanks to Pablo Polvorin)(EJAB-1121)
SVN Revision: 2802
2009-12-11 12:30:41 +00:00
Badlop 65aed47873 Show Last Activity menu item in Webadmin only if vhost has mod_last (EJAB-1031)
SVN Revision: 2799
2009-12-09 17:47:02 +00:00
Badlop 8ac16a0ec1 Call in WebAdmin the proper mod_last backend module (EJAB-1031)
SVN Revision: 2798
2009-12-09 17:46:51 +00:00
Badlop 3250c24ff1 This is ejabberd 2.1.x branch, not 2.1.0 tag.
SVN Revision: 2796
2009-12-09 10:09:35 +00:00
Badlop 88b6849e69 Fix erl -setcookie argument in cluster setup (thanks to Jan Koum)
SVN Revision: 2795
2009-12-09 10:09:19 +00:00
Badlop e3b4c99b00 Apply a forgotten part of the original patch (EJAB-1119)
SVN Revision: 2792
2009-12-08 17:32:46 +00:00
Badlop 1f5bf8fbc0 Fix memory and port leak when TLS is enabled in HTTP (thanks to Brian Cully)(EJAB-1119)
SVN Revision: 2790
2009-12-07 17:33:02 +00:00
Badlop f044d6ed28 Fix bug that couldn't connect if starttls_required and zlib were set (EJAB-1118)
SVN Revision: 2789
2009-12-07 15:54:25 +00:00
Christophe Romain 3aa242e2c7 prevent sending duplicated last items if several resources online (EJAB-1116)
SVN Revision: 2786
2009-12-06 23:18:17 +00:00
Badlop 8983cba129 Typo in mod_pubsub_odbc breaks Service Discovery and more (EJAB-1115)
SVN Revision: 2784
2009-12-04 18:35:14 +00:00
Badlop bd97c40f92 Call ejabberd_router:route/3 instead of sending a message (EJAB-1114)
SVN Revision: 2782
2009-12-04 16:31:25 +00:00
Badlop 5a006b977d Small relax the limitation in the mod_pubsub_odbc host option.
SVN Revision: 2781
2009-12-04 16:08:31 +00:00
Badlop 3658da3ae8 Explain limitation in the mod_pubsub_odbc host option.
SVN Revision: 2777
2009-12-03 22:53:56 +00:00
Badlop 2265f52c34 Fix warning of unused variable
SVN Revision: 2776
2009-12-03 22:53:39 +00:00
Badlop 7b244652f1 Use os:getenv to get HOME; if variable is undefined use default values.
SVN Revision: 2773
2009-12-03 15:59:01 +00:00
Badlop 325e67f4cb Use old regexp instead re in 2.x for pre-R12B-4 compatibility.
SVN Revision: 2771
2009-12-02 23:26:28 +00:00
Badlop 6ce660b9c2 IQ sent to resource not connected, return service-unavailable instead of recipient-unavailable (EJAB-1045)
SVN Revision: 2768
2009-12-01 20:00:33 +00:00
Badlop 575e07a986 Forward IQ vCard queries of room occupants to bare JID, not full (EJAB-1045)
SVN Revision: 2767
2009-12-01 20:00:15 +00:00
Badlop 20d1011194 Don't handle internally an IQ vCard if destination is full JID (EJAB-1045)
SVN Revision: 2766
2009-12-01 19:59:59 +00:00
Badlop 3df5277728 Move get_group_name outside the loop (thanks to mikekaganski)
SVN Revision: 2762
2009-11-26 14:46:24 +00:00
Badlop ea4f379bd5 Fix explanation of option content_types. Reorder options.
SVN Revision: 2755
2009-11-23 19:11:37 +00:00
Badlop 51594b6011 Generate main XML file also when exporting only a vhost (EJAB-1098)
SVN Revision: 2753
2009-11-23 18:34:36 +00:00
Badlop 58425ba45d Show informative webpage when browsing the HTTP-Poll page (EJAB-1106)
SVN Revision: 2751
2009-11-23 15:21:05 +00:00
Badlop 7fd3d67ff3 Change captcha.sh to not depend on bash (thanks to Konstantin Khomoutov)(EJAB-1105)
SVN Revision: 2749
2009-11-23 12:43:15 +00:00
Badlop 1716b090f9 Option to define custom HTTP headers in mod_http_fileserver (EJAB-612)
SVN Revision: 2747
2009-11-23 12:00:46 +00:00
Badlop e5e777694d Explain that the example captcha.sh requires Bash because uses RANDOM feature.
SVN Revision: 2745
2009-11-17 15:49:05 +00:00
Badlop 6cf3ae8050 Include IP address, time and module in IBR admin message (thanks to Tsukasa Hamano)
SVN Revision: 2744
2009-11-17 11:14:31 +00:00
Badlop 26c572b7e7 The default value of option ldap_filter is: undefined.
SVN Revision: 2741
2009-11-13 20:16:41 +00:00
Evgeniy Khramtsov 311bf4dbb1 fixes allow_host/2 on subdomains. added hook s2s_allow_host: the hook should return deny or allow
SVN Revision: 2738
2009-11-13 16:19:46 +00:00
Badlop 1511a5dc82 Fix EDoc errors
SVN Revision: 2735
2009-11-06 18:26:06 +00:00
Badlop 041d947e83 Fix bug that forgot listener options when using R12 or older.
SVN Revision: 2734
2009-11-06 18:24:54 +00:00
Christophe Romain 2007b3d496 typo fix that breaks pep
SVN Revision: 2731
2009-11-06 11:01:40 +00:00
Christophe Romain 09e847b97d fix root node deletion match
SVN Revision: 2729
2009-11-05 17:36:15 +00:00
Badlop b9f911554c Fix ProcessOne name in comments.
SVN Revision: 2724
2009-11-04 20:14:22 +00:00
Badlop 24323e8b3b Extend explanation of ldap_encrypt tls (thanks to Konstantin Khomoutov)
SVN Revision: 2723
2009-11-04 20:12:54 +00:00
Badlop 1a5eb4f73d Fix disco on root node, add commands to disco (thanks to Brian Cully)(EJAB-1094)
SVN Revision: 2722
2009-11-04 19:54:15 +00:00
Badlop 3930715712 Send authorization messages outside of get-pending transaction (thanks to Brian Cully)(EJAB-1090)
SVN Revision: 2721
2009-11-04 19:52:33 +00:00
Badlop 64bc97d471 Send authorization messages outside of get-pending transaction (thanks to Brian Cully)(EJAB-1090)
SVN Revision: 2719
2009-11-04 17:38:51 +00:00
Badlop 4aec8dda48 Extend explanation of mod_pubsub "default" rename to "hometree".
SVN Revision: 2718
2009-11-04 09:42:54 +00:00
Badlop 9192c75e1a Fix stringprep Bidi checking (thanks to Alexey Shchepin)(EJAB-1087)
SVN Revision: 2717
2009-11-01 12:15:34 +00:00
Christophe Romain 512d701ef8 minor bugfix, thanks to brian Cully (EJAB-1089)
SVN Revision: 2713
2009-10-27 14:26:22 +00:00
Christophe Romain ef3dd090c7 backport previous patch to pubsub odbc
SVN Revision: 2711
2009-10-27 14:13:18 +00:00
Christophe Romain 3d5fe6a337 fix disco bugs, thanks to Brian Cully (EJAB-1088)
SVN Revision: 2710
2009-10-27 14:07:35 +00:00
Badlop 0906a68c27 Mention in Release Notes the three changes in SQL databases (EJAB-1078)
SVN Revision: 2707
2009-10-23 17:32:12 +00:00
Badlop 798853abb6 Fix mistake that disallowed s2s_out connections when using Erlang R12 or older.
SVN Revision: 2694
2009-10-21 21:11:09 +00:00
Badlop 5e3fdbeeed Mention the change in nodename slash separation in release notes.
SVN Revision: 2689
2009-10-20 15:39:57 +00:00
Badlop 04545f2668 Create branch for ejabberd 2.1.x release line.
SVN Revision: 2688
2009-10-20 15:28:48 +00:00
Christophe Romain f383511e0d add release_notes_2.0.1
SVN Revision: 1338
2008-05-19 22:35:01 +00:00
Jérôme Sautret 2f65188edb Created ejabberd 2.1.X branch.
SVN Revision: 1274
2008-04-03 13:38:34 +00:00
343 changed files with 77150 additions and 49459 deletions
+1 -1
View File
@@ -2,6 +2,7 @@
# You can add personal rules in your file .git/info/exclude
*.swp
*~
/contrib/extract_translations/extract_translations.beam
/doc/*.aux
/doc/*.haux
/doc/*.html
@@ -28,7 +29,6 @@
/src/autom4te.cache
/src/config.log
/src/config.status
/src/configure
/src/ejabberd.init
/src/ejabberdctl.example
/src/eldap/ELDAPv3.asn1db
+5 -9
View File
@@ -8,17 +8,19 @@ Quickstart guide
To compile ejabberd you need:
- GNU Make
- GCC
- Erlang/OTP R12B-5 or higher. Recommended: R12B-5, R13B04 and R14B01.
- Libexpat 1.95 or higher
- Erlang/OTP R10B-9 or higher. Recommended: R13B04 and R14B04.
Avoid R14A and R14B.
- exmpp 0.9.6 or higher
- OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
- 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).
- ESASL library. Optional. For SASL GSSAPI authentication.
- GNU Iconv 1.8 or higher, for the IRC Transport
(mod_irc). Optional. Not needed on systems with GNU Libc.
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
- exmpp 0.9.6 or higher. Optional. For import/export XEP-0227 files.
1. Compile and install on *nix systems
@@ -27,12 +29,6 @@ To compile ejabberd, go to the directory src/ and execute the commands:
./configure
make
If you get an error like:
./configure: No such file or directory
the solution is to first execute:
aclocal
autoconf
To install ejabberd, run this command with system administrator rights
(root user):
@@ -281,14 +281,14 @@ build_additional_translators(List) ->
List).
print_translation(File, Line, Str, StrT) ->
StrQ = re:replace(Str, "\\\"", "\\\\\\\"", [global, {return, list}]),
StrTQ = re:replace(StrT, "\\\"", "\\\\\\\"", [global, {return, list}]),
StrQ = ejabberd_regexp:greplace(Str, "\\\"", "\\\\\""),
StrTQ = ejabberd_regexp:greplace(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,
StrQ = re:replace(Str, "\\\"", "\\\\\\\"", [global, {return, list}]),
StrTQ = re:replace(StrT, "\\\"", "\\\\\\\"", [global, {return, list}]),
StrQ = ejabberd_regexp:greplace(Str, "\\\"", "\\\\\""),
StrTQ = ejabberd_regexp:greplace(StrT, "\\\"", "\\\\\""),
io:format("#: ~s:~p~n#~~ msgid \"~s\"~n#~~ msgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]).
@@ -16,7 +16,7 @@ prepare_dirs ()
EJA_SRC_DIR=$EJA_DIR/src/
EJA_MSGS_DIR=$EJA_SRC_DIR/msgs/
EXTRACT_DIR=$EJA_DIR/tools/extract_translations/
EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/
EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl
EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam
@@ -91,7 +91,7 @@ extract_lang_all ()
cd $MSGS_DIR
for i in $( ls *.msg ) ; do
MISSING=`cat $i.translate | grep "\", \"\"}." | wc -l`
LANGUAGE=`grep "Language:" $i.translate | sed 's/% Language: //g'`
LANGUAGE=`grep "X-Language:" $i.translate | sed 's/% Language: //g'`
LASTAUTH=`grep "Author:" $i.translate | head -n 1 | sed 's/% Author: //g'`
echo -e "$i\t$MISSING\t$LANGUAGE\t$LASTAUTH"
done
@@ -258,7 +258,7 @@ extract_lang_updateall ()
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}'`
LANGUAGE=`grep "X-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'`
+2 -1
View File
@@ -1,3 +1,5 @@
# $Id$
SHELL = /bin/bash
CONTRIBUTED_MODULES = ""
@@ -35,7 +37,6 @@ clean:
rm -f *.out
rm -f *.pdf
rm -f *.toc
rm -f version.tex
[ ! -f contributed_modules.tex ] || rm contributed_modules.tex
distclean: clean
+1 -1
View File
@@ -15,4 +15,4 @@ clean:
docs:
erl -noshell -run edoc_run application \
"'$(APPNAME)'" '"$(SRCDIR)"' '[{dir,"$(DOCDIR)"},{packages, false},{todo,false},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"$(DOCDIR)/overview.edoc"}]' -s init stop
"'$(APPNAME)'" '"$(SRCDIR)"' '[{dir,"$(DOCDIR)"},{packages, false},{todo,true},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"$(DOCDIR)/overview.edoc"}]' -s init stop
+10
View File
@@ -0,0 +1,10 @@
@author Mickael Remond <mickael.remond@process-one.net>
[http://www.process-one.net/]
@copyright 2012 ProcessOne
@version {@vsn}, {@date} {@time}
@title ejabberd Development API Documentation
@doc
== Introduction ==
TODO: Insert content from Jerome documentation.
@@ -1,25 +1,3 @@
div.navbar table tr td a[target="_parent"] {
background: transparent url("ejabberd-devdoc.png") no-repeat;
display: block;
font-size: 0%;
top: 0;
left: 0;
padding: 0;
margin: 0;
width: 192px;
height: 42px;
}
div.navbar table tr td a img {
border: 0;
padding: 0 0 0 10;
float: right;
}
p i {
display: none;
}
html, body {
font-family: Verdana, sans-serif;
color: #000;
@@ -27,20 +5,19 @@ html, body {
}
h1 {
font-size: 20px;
color: #4a5389;
border-bottom: solid 1px #000;
}
h2 {
font-size: 18px;
font-size: 24px;
text-align: right;
color: #4a5389;
border-bottom: 1px solid #000;
}
h3 {
font-size: 16px;
font-size: 18px;
color: #900;
}
+413
View File
@@ -0,0 +1,413 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.11 Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<META name="GENERATOR" content="hevea 1.10">
<STYLE type="text/css">
.li-itemize{margin:1ex 0ex;}
.li-enumerate{margin:1ex 0ex;}
.dd-description{margin:0ex 0ex 1ex 4ex;}
.dt-description{margin:0ex;}
.toc{list-style:none;}
.thefootnotes{text-align:left;margin:0ex;}
.dt-thefootnotes{margin:0em;}
.dd-thefootnotes{margin:0em 0em 0em 2em;}
.footnoterule{margin:1em auto 1em 0px;width:50%;}
.caption{padding-left:2ex; padding-right:2ex; margin-left:auto; margin-right:auto}
.title{margin:2ex auto;text-align:center}
.center{text-align:center;margin-left:auto;margin-right:auto;}
.flushleft{text-align:left;margin-left:0ex;margin-right:auto;}
.flushright{text-align:right;margin-left:auto;margin-right:0ex;}
DIV TABLE{margin-left:inherit;margin-right:inherit;}
PRE{text-align:left;margin-left:0ex;margin-right:auto;}
BLOCKQUOTE{margin-left:4ex;margin-right:4ex;text-align:left;}
TD P{margin:0px;}
.boxed{border:1px solid black}
.textboxed{border:1px solid black}
.vbar{border:none;width:2px;background-color:black;}
.hbar{border:none;height:2px;width:100%;background-color:black;}
.hfill{border:none;height:1px;width:200%;background-color:black;}
.vdisplay{border-collapse:separate;border-spacing:2px;width:auto; empty-cells:show; border:2px solid red;}
.vdcell{white-space:nowrap;padding:0px;width:auto; border:2px solid green;}
.display{border-collapse:separate;border-spacing:2px;width:auto; border:none;}
.dcell{white-space:nowrap;padding:0px;width:auto; border:none;}
.dcenter{margin:0ex auto;}
.vdcenter{border:solid #FF8000 2px; margin:0ex auto;}
.minipage{text-align:left; margin-left:0em; margin-right:auto;}
.marginpar{border:solid thin black; width:20%; text-align:left;}
.marginparleft{float:left; margin-left:0ex; margin-right:1ex;}
.marginparright{float:right; margin-left:1ex; margin-right:0ex;}
.theorem{text-align:left;margin:1ex auto 1ex 0ex;}
.part{margin:2ex auto;text-align:center}
</STYLE>
</HEAD>
<BODY >
<!--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.11 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">
<IMG SRC="logo.png" ALT="logo.png">
</DIV><BLOCKQUOTE CLASS="quotation"><I>I can thoroughly recommend ejabberd for ease of setup &#X2013;
Kevin Smith, Current maintainer of the Psi project</I></BLOCKQUOTE><!--TOC section Contents-->
<H2 CLASS="section"><!--SEC ANCHOR -->Contents</H2><!--SEC END --><UL CLASS="toc"><LI CLASS="li-toc">
<A HREF="#htoc1">1&#XA0;&#XA0;Key Features</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc2">2&#XA0;&#XA0;Additional Features</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc3">3&#XA0;&#XA0;How it Works</A>
<UL CLASS="toc"><LI CLASS="li-toc">
<A HREF="#htoc4">3.1&#XA0;&#XA0;Router</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc5">3.2&#XA0;&#XA0;Local Router</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc6">3.3&#XA0;&#XA0;Session Manager</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc7">3.4&#XA0;&#XA0;S2S Manager</A>
</LI></UL>
</LI><LI CLASS="li-toc"><A HREF="#htoc8">4&#XA0;&#XA0;Authentication</A>
<UL CLASS="toc">
<UL CLASS="toc"><LI CLASS="li-toc">
<A HREF="#htoc9">4.0.1&#XA0;&#XA0;External</A>
</LI></UL>
</UL>
</LI><LI CLASS="li-toc"><A HREF="#htoc10">5&#XA0;&#XA0;XML Representation</A>
</LI><LI CLASS="li-toc"><A HREF="#htoc11">6&#XA0;&#XA0;Module <TT>xml</TT></A>
</LI><LI CLASS="li-toc"><A HREF="#htoc12">7&#XA0;&#XA0;Module <TT>xml_stream</TT></A>
</LI><LI CLASS="li-toc"><A HREF="#htoc13">8&#XA0;&#XA0;Modules</A>
<UL CLASS="toc"><LI CLASS="li-toc">
<A HREF="#htoc14">8.1&#XA0;&#XA0;Module gen_iq_handler</A>
</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-->
<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:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
Cross-platform: <TT>ejabberd</TT> runs under Microsoft Windows and Unix derived systems such as Linux, FreeBSD and NetBSD.</LI><LI CLASS="li-itemize">Distributed: You can run <TT>ejabberd</TT> on a cluster of machines and all of them will serve the same Jabber domain(s). When you need more capacity you can simply add a new cheap node to your cluster. Accordingly, you do not need to buy an expensive high-end machine to support tens of thousands concurrent users.</LI><LI CLASS="li-itemize">Fault-tolerant: You can deploy an <TT>ejabberd</TT> cluster so that all the information required for a properly working service will be replicated permanently on all nodes. This means that if one of the nodes crashes, the others will continue working without disruption. In addition, nodes also can be added or replaced &#X2018;on the fly&#X2019;.</LI><LI CLASS="li-itemize">Administrator Friendly: <TT>ejabberd</TT> is built on top of the Open Source Erlang. As a result you do not need to install an external database, an external web server, amongst others because everything is already included, and ready to run out of the box. Other administrator benefits include:
<UL CLASS="itemize"><LI CLASS="li-itemize">
Comprehensive documentation.
</LI><LI CLASS="li-itemize">Straightforward installers for Linux, Mac OS X, and Windows. </LI><LI CLASS="li-itemize">Web Administration.
</LI><LI CLASS="li-itemize">Shared Roster Groups.
</LI><LI CLASS="li-itemize">Command line administration tool. </LI><LI CLASS="li-itemize">Can integrate with existing authentication mechanisms.
</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>.
</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.
</LI><LI CLASS="li-itemize">XML-based protocol.
</LI><LI CLASS="li-itemize"><A HREF="http://www.ejabberd.im/protocols">Many protocols supported</A>.
</LI></UL></LI></UL><!--TOC section Additional Features-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc2">2</A>&#XA0;&#XA0;Additional Features</H2><!--SEC END --><P>
<A NAME="addfeatures"></A>
</P><P>Moreover, <TT>ejabberd</TT> comes with a wide range of other state-of-the-art features:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
Modular
<UL CLASS="itemize"><LI CLASS="li-itemize">
Load only the modules you want.
</LI><LI CLASS="li-itemize">Extend <TT>ejabberd</TT> with your own custom modules.
</LI></UL>
</LI><LI CLASS="li-itemize">Security
<UL CLASS="itemize"><LI CLASS="li-itemize">
SASL and STARTTLS for c2s and s2s connections.
</LI><LI CLASS="li-itemize">STARTTLS and Dialback s2s connections.
</LI><LI CLASS="li-itemize">Web Admin accessible via HTTPS secure access.
</LI></UL>
</LI><LI CLASS="li-itemize">Databases
<UL CLASS="itemize"><LI CLASS="li-itemize">
Internal database for fast deployment (Mnesia).
</LI><LI CLASS="li-itemize">Native MySQL support.
</LI><LI CLASS="li-itemize">Native PostgreSQL support.
</LI><LI CLASS="li-itemize">ODBC data storage support.
</LI><LI CLASS="li-itemize">Microsoft SQL Server support. </LI></UL>
</LI><LI CLASS="li-itemize">Authentication
<UL CLASS="itemize"><LI CLASS="li-itemize">
Internal Authentication.
</LI><LI CLASS="li-itemize">PAM, LDAP and ODBC. </LI><LI CLASS="li-itemize">External Authentication script.
</LI></UL>
</LI><LI CLASS="li-itemize">Others
<UL CLASS="itemize"><LI CLASS="li-itemize">
Support for virtual hosting.
</LI><LI CLASS="li-itemize">Compressing XML streams with Stream Compression (<A HREF="http://www.xmpp.org/extensions/xep-0138.html">XEP-0138</A>).
</LI><LI CLASS="li-itemize">Statistics via Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>).
</LI><LI CLASS="li-itemize">IPv6 support both for c2s and s2s connections.
</LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0045.html">Multi-User Chat</A> module with support for clustering and HTML logging. </LI><LI CLASS="li-itemize">Users Directory based on users vCards.
</LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0060.html">Publish-Subscribe</A> component with support for <A HREF="http://www.xmpp.org/extensions/xep-0163.html">Personal Eventing via Pubsub</A>.
</LI><LI CLASS="li-itemize">Support for web clients: <A HREF="http://www.xmpp.org/extensions/xep-0025.html">HTTP Polling</A> and <A HREF="http://www.xmpp.org/extensions/xep-0206.html">HTTP Binding (BOSH)</A> services.
</LI><LI CLASS="li-itemize">IRC transport.
</LI><LI CLASS="li-itemize">Component support: interface with networks such as AIM, ICQ and MSN installing special tranports.
</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
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
<TT>~ejabberd/.erlang.cookie</TT> must be the same on all nodes). This is
needed because all nodes exchange information about connected users, S2S
connections, registered services, etc&#X2026;</P><P>Each <TT>ejabberd</TT> node have following modules:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
router;
</LI><LI CLASS="li-itemize">local 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
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
searches in global table, and is routed to the appropriate <TT>ejabberd</TT> node or
process. If it does not exists in either tables, then it sent to the S2S
manager.</P><!--TOC subsection Local Router-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc5">3.2</A>&#XA0;&#XA0;Local Router</H3><!--SEC END --><P>This module routes packets which have a destination domain equal to this server
name. If destination JID has a non-empty user part, then it routed to the
session manager, else it is processed depending on it&#X2019;s content.</P><!--TOC subsection Session Manager-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc6">3.3</A>&#XA0;&#XA0;Session Manager</H3><!--SEC END --><P>This module routes packets to local users. It searches for what user resource
packet must be sent 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
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
it is routed to the process that serves this connection, and if a connection
does not exist, then it is opened and registered.</P><!--TOC section Authentication-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc8">4</A>&#XA0;&#XA0;Authentication</H2><!--SEC END --><!--TOC subsubsection External-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A NAME="htoc9">4.0.1</A>&#XA0;&#XA0;External</H4><!--SEC END --><P>
<A NAME="externalauth"></A>
</P><P>The external authentication script follows
<A HREF="http://www.erlang.org/doc/tutorial/c_portdriver.html">the erlang port driver API</A>.</P><P>That script is supposed to do theses actions, in an infinite loop:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
read from stdin: AABBBBBBBBB.....
<UL CLASS="itemize"><LI CLASS="li-itemize">
A: 2 bytes of length data (a short in network byte order)
</LI><LI CLASS="li-itemize">B: a string of length found in A that contains operation in plain text
operation are as follows:
<UL CLASS="itemize"><LI CLASS="li-itemize">
auth:User:Server:Password (check if a username/password pair is correct)
</LI><LI CLASS="li-itemize">isuser:User:Server (check if it&#X2019;s a valid user)
</LI><LI CLASS="li-itemize">setpass:User:Server:Password (set user&#X2019;s password)
</LI><LI CLASS="li-itemize">tryregister:User:Server:Password (try to register an account)
</LI><LI CLASS="li-itemize">removeuser:User:Server (remove this account)
</LI><LI CLASS="li-itemize">removeuser3:User:Server:Password (remove this account if the password is correct)
</LI></UL>
</LI></UL>
</LI><LI CLASS="li-itemize">write to stdout: AABB
<UL CLASS="itemize"><LI CLASS="li-itemize">
A: the number 2 (coded as a short, which is bytes length of following result)
</LI><LI CLASS="li-itemize">B: the result code (coded as a short), should be 1 for success/valid, or 0 for failure/invalid
</LI></UL>
</LI></UL><P>Example python script
</P><PRE CLASS="verbatim">#!/usr/bin/python
import sys
from struct import *
def from_ejabberd():
input_length = sys.stdin.read(2)
(size,) = unpack('&gt;h', input_length)
return sys.stdin.read(size).split(':')
def to_ejabberd(bool):
answer = 0
if bool:
answer = 1
token = pack('&gt;hh', 2, answer)
sys.stdout.write(token)
sys.stdout.flush()
def auth(username, server, password):
return True
def isuser(username, server):
return True
def setpass(username, server, password):
return True
while True:
data = from_ejabberd()
success = False
if data[0] == "auth":
success = auth(data[1], data[2], data[3])
elif data[0] == "isuser":
success = isuser(data[1], data[2])
elif data[0] == "setpass":
success = setpass(data[1], data[2], data[3])
to_ejabberd(success)
</PRE><!--TOC section XML Representation-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc10">5</A>&#XA0;&#XA0;XML Representation</H2><!--SEC END --><P>
<A NAME="xmlrepr"></A></P><P>Each XML stanza is represented as the following tuple:
</P><PRE CLASS="verbatim">XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
Name = string()
Attrs = [Attr]
Attr = {Key, Val}
Key = string()
Val = string()
ElementOrCDATA = XMLElement | CDATA
CDATA = {xmlcdata, string()}
</PRE><P>E.&#XA0;g. this stanza:
</P><PRE CLASS="verbatim">&lt;message to='test@conference.example.org' type='groupchat'&gt;
&lt;body&gt;test&lt;/body&gt;
&lt;/message&gt;
</PRE><P>is represented as the following structure:
</P><PRE CLASS="verbatim">{xmlelement, "message",
[{"to", "test@conference.example.org"},
{"type", "groupchat"}],
[{xmlelement, "body",
[],
[{xmlcdata, "test"}]}]}}
</PRE><!--TOC section Module <TT>xml</TT>-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc11">6</A>&#XA0;&#XA0;Module <TT>xml</TT></H2><!--SEC END --><P>
<A NAME="xmlmod"></A></P><DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>element_to_string(El) -&gt; string()</CODE>
<PRE CLASS="verbatim">El = XMLElement
</PRE>Returns string representation of XML stanza <TT>El</TT>.</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>crypt(S) -&gt; string()</CODE>
<PRE CLASS="verbatim">S = string()
</PRE>Returns string which correspond to <TT>S</TT> with encoded XML special
characters.</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>remove_cdata(ECList) -&gt; EList</CODE>
<PRE CLASS="verbatim">ECList = [ElementOrCDATA]
EList = [XMLElement]
</PRE><TT>EList</TT> is a list of all non-CDATA elements of ECList.</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>get_path_s(El, Path) -&gt; Res</CODE>
<PRE CLASS="verbatim">El = XMLElement
Path = [PathItem]
PathItem = PathElem | PathAttr | PathCDATA
PathElem = {elem, Name}
PathAttr = {attr, Name}
PathCDATA = cdata
Name = string()
Res = string() | XMLElement
</PRE>If <TT>Path</TT> is empty, then returns <TT>El</TT>. Else sequentially
consider elements of <TT>Path</TT>. Each element is one of:
<DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>{elem, Name}</CODE> <TT>Name</TT> is name of subelement of
<TT>El</TT>, if such element exists, then this element considered in
following steps, else returns empty string.
</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>{attr, Name}</CODE> If <TT>El</TT> have attribute <TT>Name</TT>, then
returns value of this attribute, else returns empty string.
</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>cdata</CODE> Returns CDATA of <TT>El</TT>.
</DD></DL></DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description">TODO:
<PRE CLASS="verbatim"> get_cdata/1, get_tag_cdata/1
get_attr/2, get_attr_s/2
get_tag_attr/2, get_tag_attr_s/2
get_subtag/2
</PRE></DD></DL><!--TOC section Module <TT>xml_stream</TT>-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc12">7</A>&#XA0;&#XA0;Module <TT>xml_stream</TT></H2><!--SEC END --><P>
<A NAME="xmlstreammod"></A></P><DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>parse_element(Str) -&gt; XMLElement | {error, Err}</CODE>
<PRE CLASS="verbatim">Str = string()
Err = term()
</PRE>Parses <TT>Str</TT> using XML parser, returns either parsed element or error
tuple.
</DD></DL><!--TOC section Modules-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc13">8</A>&#XA0;&#XA0;Modules</H2><!--SEC END --><P>
<A NAME="emods"></A></P><!--TOC subsection Module gen_iq_handler-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc14">8.1</A>&#XA0;&#XA0;Module gen_iq_handler</H3><!--SEC END --><P>
<A NAME="geniqhandl"></A></P><P>The module <CODE>gen_iq_handler</CODE> allows to easily write handlers for IQ packets
of particular XML namespaces that addressed to server or to users bare JIDs.</P><P>In this module the following functions are defined:
</P><DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>add_iq_handler(Component, Host, NS, Module, Function, Type)</CODE>
<PRE CLASS="verbatim">Component = Module = Function = atom()
Host = NS = string()
Type = no_queue | one_queue | parallel
</PRE>Registers function <CODE>Module:Function</CODE> as handler for IQ packets on
virtual host <CODE>Host</CODE> that contain child of namespace <CODE>NS</CODE> in
<CODE>Component</CODE>. Queueing discipline is <CODE>Type</CODE>. There are at least
two components defined:
<DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>ejabberd_local</CODE> Handles packets that addressed to server JID;
</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>ejabberd_sm</CODE> Handles packets that addressed to users bare JIDs.
</DD></DL>
</DD><DT CLASS="dt-description"></DT><DD CLASS="dd-description"><CODE>remove_iq_handler(Component, Host, NS)</CODE>
<PRE CLASS="verbatim">Component = atom()
Host = NS = string()
</PRE>Removes IQ handler on virtual host <CODE>Host</CODE> for namespace <CODE>NS</CODE> from
<CODE>Component</CODE>.
</DD></DL><P>Handler function must have the following type:
</P><DL CLASS="description"><DT CLASS="dt-description">
</DT><DD CLASS="dd-description"><CODE>Module:Function(From, To, IQ)</CODE>
<PRE CLASS="verbatim">From = To = jid()
</PRE></DD></DL><PRE CLASS="verbatim">-module(mod_cputime).
-behaviour(gen_mod).
-export([start/2,
stop/1,
process_local_iq/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-define(NS_CPUTIME, "ejabberd:cputime").
start(Host, Opts) -&gt;
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_CPUTIME,
?MODULE, process_local_iq, IQDisc).
stop(Host) -&gt;
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_CPUTIME).
process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -&gt;
case Type of
set -&gt;
{iq, ID, error, XMLNS,
[SubEl, ?ERR_NOT_ALLOWED]};
get -&gt;
CPUTime = element(1, erlang:statistics(runtime))/1000,
SCPUTime = lists:flatten(io_lib:format("~.3f", CPUTime)),
{iq, ID, result, XMLNS,
[{xmlelement, "query",
[{"xmlns", ?NS_CPUTIME}],
[{xmlelement, "cputime", [], [{xmlcdata, SCPUTime}]}]}]}
end.
</PRE><!--TOC subsection Services-->
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc15">8.2</A>&#XA0;&#XA0;Services</H3><!--SEC END --><P>
<A NAME="services"></A></P><PRE CLASS="verbatim">-module(mod_echo).
-behaviour(gen_mod).
-export([start/2, init/1, stop/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
start(Host, Opts) -&gt;
MyHost = gen_mod:get_opt(host, Opts, "echo." ++ Host),
register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, [MyHost])).
init(Host) -&gt;
ejabberd_router:register_local_route(Host),
loop(Host).
loop(Host) -&gt;
receive
{route, From, To, Packet} -&gt;
ejabberd_router:route(To, From, Packet),
loop(Host);
stop -&gt;
ejabberd_router:unregister_route(Host),
ok;
_ -&gt;
loop(Host)
end.
stop(Host) -&gt;
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
Proc ! stop,
{wait, Proc}.
</PRE><!--CUT END -->
<!--HTMLFOOT-->
<!--ENDHTML-->
<!--FOOTER-->
<HR SIZE=2><BLOCKQUOTE CLASS="quote"><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
</EM><A HREF="http://hevea.inria.fr/index.html"><EM>H</EM><EM><FONT SIZE=2><sup>E</sup></FONT></EM><EM>V</EM><EM><FONT SIZE=2><sup>E</sup></FONT></EM><EM>A</EM></A><EM>.</EM></BLOCKQUOTE></BODY>
</HTML>
+4
View File
@@ -37,20 +37,24 @@
\newcommand{\modecho}{\module{mod\_echo}}
\newcommand{\modirc}{\module{mod\_irc}}
\newcommand{\modlast}{\module{mod\_last}}
\newcommand{\modlastodbc}{\module{mod\_last\_odbc}}
\newcommand{\modmuc}{\module{mod\_muc}}
\newcommand{\modmuclog}{\module{mod\_muc\_log}}
\newcommand{\modoffline}{\module{mod\_offline}}
\newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}}
\newcommand{\modprivacy}{\module{mod\_privacy}}
\newcommand{\modprivate}{\module{mod\_private}}
\newcommand{\modpubsub}{\module{mod\_pubsub}}
\newcommand{\modregister}{\module{mod\_register}}
\newcommand{\modroster}{\module{mod\_roster}}
\newcommand{\modrosterodbc}{\module{mod\_roster\_odbc}}
\newcommand{\modservicelog}{\module{mod\_service\_log}}
\newcommand{\modsharedroster}{\module{mod\_shared\_roster}}
\newcommand{\modstats}{\module{mod\_stats}}
\newcommand{\modtime}{\module{mod\_time}}
\newcommand{\modvcard}{\module{mod\_vcard}}
\newcommand{\modvcardldap}{\module{mod\_vcard\_ldap}}
\newcommand{\modvcardodbc}{\module{mod\_vcard\_odbc}}
\newcommand{\modversion}{\module{mod\_version}}
%% Title page
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

-19
View File
@@ -1,19 +0,0 @@
.comment {color: brown}
.export {color: darkorchid}
.import {color: darkorchid}
.string {color: maroon}
.builtin {color: dodgerblue}
.guard {color: mediumturquoise}
.function {color: blue}
.variable {color: green}
.macro {color: mediumpurple}
.record {color: orangered}
.call {color: purple}
.attribute {color: firebrick}
.error{color: red}
.l {
font-style: normal;
font-weight: normal;
text-decoration: none;
color: gray;
}
-356
View File
@@ -1,356 +0,0 @@
%%%-------------------------------------------------------------------
%%% File : escobar_hiliter.erl
%%% Author : Mats Cronqvist <mats.cronqvist@gmail.com>
%%% Description :
%%%
%%% Created : 6 Jun 2005 by Mats Cronqvist <mats.cronqvist@gmail.com>
%%%
%%%
%%% Escobar, Copyright (c) 2005-2009 Mats Cronqvist
%%%
%%% MIT License:
%%%
%%% 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.
%%%
%%%-------------------------------------------------------------------
-module(escobar_hilite).
-export([file/1,tree/1,string/1,out/2]).
-define(LOG(T),escobar:log(process_info(self()),T)).
-import(erl_syntax,
[get_ann/1,add_ann/2,subtrees/1,update_tree/2,type/1,get_pos/1,
application/2,application_arguments/1,application_operator/1,
arity_qualifier_argument/1,arity_qualifier_body/1,
atom_name/1,atom_value/1,
attribute/2,attribute_name/1,attribute_arguments/1,
clause/3,clause_patterns/1,clause_guard/1,clause_body/1,
comment/2,comment_text/1,comment_padding/1,
function/2,function_name/1,function_clauses/1,function_arity/1,
integer_literal/1,
list/1,list_elements/1,
macro/2,macro_name/1,macro_arguments/1,
module_qualifier_body/1, module_qualifier_argument/1,
string_value/1,string_literal/1,
variable_literal/1,variable_name/1,
record_access/3, record_access_argument/1,
record_access_field/1,record_access_type/1,
record_expr/3, record_expr_argument/1,
record_expr_fields/1, record_expr_type/1,
record_index_expr/2, record_index_expr_field/1,
record_index_expr_type/1,
form_list/1,
get_precomments/1,get_postcomments/1,has_comments/1,
copy_comments/2,remove_comments/1]).
-import(prettypr,
[above/2,follow/2,beside/2,empty/0,
null_text/1,break/1,floating/3,text/1,floating/1]).
-import(lists,[flatten/1,duplicate/2,keysearch/3,member/2,usort/1,reverse/1]).
-import(filename,[join/1,basename/1]).
out(File,HtmlString) ->
{ok,FD}=file:open(File,[write]),
try
io:fwrite(FD,"<html>",[]),
io:fwrite(FD,"<link rel=\"stylesheet\" type=\"text/css\"",[]),
io:fwrite(FD,"href=\"escobar.css\"></link><body><pre>",[]),
io:fwrite(FD,"~s",[HtmlString]),
io:fwrite(FD,"</pre></body></html>",[])
after
file:close(FD)
end.
string(Str) ->
tree(form_list(scan_and_parse(Str,1,[]))).
scan_and_parse([],_Line,Forms) -> reverse(Forms);
scan_and_parse(Text,Line,Forms) ->
{done,{ok,Toks,NLine},Cont} = erl_scan:tokens([],Text,Line),
{ok,Form} = erl_parse:parse_form(Toks),
scan_and_parse(Cont,NLine,[Form|Forms]).
file(FileName) ->
case filelib:is_regular(FileName) of
true ->
case filename:extension(FileName) of
".beam"-> tree(get_tree_beam(FileName));
".erl" -> tree(get_comm_tree_erl(FileName));
".hrl" -> tree(get_comm_tree_erl(FileName));
X -> erlang:error({unknown_extension,X})
end;
false->
erlang:error({no_file,FileName})
end.
get_comm_tree_erl(Filename) ->
Comms = erl_comment_scan:file(Filename),
Forms = get_forms_erl(Filename),
erl_recomment:recomment_forms(Forms,Comms).
get_tree_beam(Filename) ->
case beam_lib:chunks(Filename,["Abst"]) of
{ok,{_,[{"Abst",AChunk}]}} ->
{_,Forms} = binary_to_term(AChunk),
form_list(Forms);
_ ->
erlang:error({no_debuginfo,Filename})
end.
get_forms_erl(Filename) ->
{ok,Fs} = epp_dodger:parse_file(Filename,[{no_fail, true}]),
Fs.
%%% # tree
%%% turn a syntax tree into html by annotating and pretty-printing
%%% with a hook function
tree(Tree) ->
pout(ann(type(Tree),Tree)).
%%lists:foldl(fun(Form,Acc) -> [pout(ann(Form))|Acc] end, [], Tree).
pout(Form) ->
erl_prettypr:format(Form,[{hook,fun tag/3},{paper,90},{ribbon,650}]).
%%% ## formatting
%%% ### 'tag' - the format hook function
tag(Node,Ctxt,Cont) ->
Tags = get_ann(Node),
case member(has_comment,Tags) of
true ->
PreC = get_precomments(Node),
PostC = get_postcomments(Node),
Nod = remove_comments(Node),
Doc0 = tagit(Tags--[has_comment],Cont(Nod,Ctxt)),
postcomment(precomment(Doc0,PreC),PostC);
false ->
Doc0 = Cont(Node,Ctxt),
tagit(Tags,Doc0)
end.
tagit([],Doc0) ->
Doc0;
tagit(["binary"],{beside,_,{beside,Doc,_}}) ->
beside(floating(text("&lt;&lt;")),beside(Doc,floating(text("&gt;&gt;"))));
tagit([Tag],Doc0) ->
beside(null_text(Tag),beside(Doc0,null_text(etag(Tag)))).
etag("<"++Tag) -> "</"++hd(string:tokens(Tag," "))++">".
%%%### comment stuff
precomment(Doc,PreC) ->
above(floating(break(stack(PreC)), -1, -1), Doc).
postcomment(Doc,PostC) ->
beside(Doc, floating(break(stack(PostC)), 1, 0)).
stack([]) -> empty();
stack([Comm|Comms]) ->
Doc = maybe_pad(stack_comment_lines(comment_text(Comm)),Comm),
case Comms of
[] -> Doc;
_ -> above(Doc, stack(Comms))
end.
maybe_pad(Doc,Comm) ->
case comment_padding(Comm) of
I when is_integer(I), 0 < I -> beside(text(duplicate(I,$ )), Doc);
_ -> Doc
end.
%%% stolen with pride from erl_prettypr
%%% Stack lines of text above each other and prefix each string in
%%% the list with a single `%' character.
stack_comment_lines([S | Ss]) ->
D = tagit([dehtml('span', [{class,comment}])],text("%"++debracket(S))),
case Ss of
[] -> D;
_ -> above(D, stack_comment_lines(Ss))
end;
stack_comment_lines([]) ->
empty().
%%% annotate nodes that should be hilited
%%% the annotation is put on the subtree that should be marked up
%%% the annotation is;
%%% has_comments|Markup
%%% if a node already has an annotation the new one is dropped, except
%%% if either the new or the old one is has_comments
ann(binary,Tree) ->
new_tree(Tree,add_anno("binary",Tree));
ann(application,Tree) ->
Op = application_operator(Tree),
Args = application_arguments(Tree),
new_tree(Tree,application(add_anno(mu(application,Tree),Op),Args));
ann(attribute,Tree) ->
Name = attribute_name(Tree),
case atom_value(Name) of
export ->
AQs = list_elements(hd(attribute_arguments(Tree))),
Args = [list([add_anno(mu(export,Tree),AQ) || AQ <- AQs])];
import ->
[ImportMod,ImportFAs] = attribute_arguments(Tree),
AQs = list_elements(ImportFAs),
Args = [ImportMod,list([add_anno(mu(import,Tree),AQ) || AQ <- AQs])];
define ->
[Macro|Rest] = attribute_arguments(Tree),
case type(Macro) of
application ->
Op = application_operator(Macro),
As = application_arguments(Macro),
Args = [application(add_anno(mu(macro,Tree),Op),As)|Rest];
_ ->
Args = [add_anno(mu(macro,Tree),Macro)|Rest]
end;
record ->
[Rec|Rest] = attribute_arguments(Tree),
Args = [add_anno(mu(record,Tree),Rec)|Rest];
_ ->
Args = attribute_arguments(Tree)
end,
new_tree(Tree,attribute(add_anno(mu(attribute,Tree),Name),Args));
ann(record_access,Tree) ->
Arg = record_access_argument(Tree),
Type = record_access_type(Tree),
Field = record_access_field(Tree),
new_tree(Tree,record_access(Arg,add_anno(mu(record,Tree),Type),Field));
ann(record_expr,Tree) ->
Arg = record_expr_argument(Tree),
Type = record_expr_type(Tree),
Fields = record_expr_fields(Tree),
new_tree(Tree,record_expr(Arg,add_anno(mu(record,Tree),Type),Fields));
ann(record_index_expr,Tree) ->
Type = record_index_expr_type(Tree),
Field = record_index_expr_field(Tree),
new_tree(Tree,record_index_expr(add_anno(mu(record,Tree),Type),Field));
ann(function,Tree) ->
Name = function_name(Tree),
Clauses = function_clauses(Tree),
new_tree(Tree,function(add_anno(mu(function,Tree),Name),Clauses));
ann(macro,Tree) ->
Name = macro_name(Tree),
Args = macro_arguments(Tree),
new_tree(Tree,macro(add_anno(mu(macro,Tree),Name), Args));
ann(string,OTree) ->
Tree = erl_syntax:string(debracket(string_value(OTree))),
new_tree(OTree,add_anno(mu(string,OTree),Tree));
ann(variable,Tree) ->
new_tree(Tree,add_anno(mu(variable,Tree),Tree));
ann(text,Tree) ->
new_tree(Tree,add_anno(mu(error,Tree),Tree));
ann(comment,OTree) ->
Pad = comment_padding(OTree),
Text = [debracket(S) || S <- comment_text(OTree)],
Tree = comment(Pad,Text),
new_tree(OTree,add_anno(mu(comment,OTree),Tree));
ann(_Typ,Tree) ->
new_tree(Tree,Tree).
new_tree(OTree,NTree) ->
Tree =
case has_comments(OTree) of
true -> add_ann(has_comment,copy_comments(OTree,NTree));
false -> NTree
end,
SubTrees = subtrees(Tree),
case [[ann(type(SubT),SubT) || SubT<-Group] || Group<-SubTrees] of
[] -> Tree;
NSubtrees -> update_tree(Tree,NSubtrees)
end.
debracket([]) -> [];
debracket([$>|Str]) -> "&gt;"++debracket(Str);
debracket([$<|Str]) -> "&lt;"++debracket(Str);
debracket([C|Str]) -> [C|debracket(Str)].
add_anno(nil,Tree) -> Tree;
add_anno(Ann,Tree) ->
case get_ann(Tree) of
[] -> add_ann(Ann,Tree);
[has_comment] -> add_ann(Ann,Tree);
_OAnn -> Tree
end.
%%%### the markups
mu(application,Node) ->
Op = application_operator(Node),
Ar = length(application_arguments(Node)),
case type(Op) of
%% variable ->
%% dehtml('span', [{class,variable}]);
atom ->
case is_guard_or_builtin(atom_value(Op),Ar) of
guard -> dehtml('span', [{class,guard}]);
builtin->dehtml('span', [{class,builtin}]);
neither->dehtml('span', [{class,call}])
end;
module_qualifier ->
Mod = module_qualifier_argument(Op),
Fun = module_qualifier_body(Op),
case {type(Mod),type(Fun)} of
{atom,atom} ->
case atom_value(Mod) of
erlang -> dehtml('span', [{class,builtin}]);
_ -> dehtml('span', [{class,call}])
end;
_ ->
nil
end;
_ ->
nil
end;
mu(function = Class, {tree, function, _, {function, _, [{tree, clause, _, {clause, Vars, _, _}} | _]}}) ->
dehtml('span', [{class,Class}, {arity,length(Vars)}]);
mu(Class,_Node) ->
dehtml('span', [{class,Class}]).
dehtml(Tag,Atts) ->
flatten([$<,str(Tag),$ ,[[str(A),"=\"",str(V),"\" "]||{A,V}<-Atts],$>]).
str(I) when is_integer(I) -> integer_to_list(I);
str(A) when is_atom(A) -> atom_to_list(A);
str(L) when is_list(L) -> L.
is_guard_or_builtin(atom,1) ->guard;
is_guard_or_builtin(binary,1) ->guard;
is_guard_or_builtin(constant,1) ->guard;
is_guard_or_builtin(float,1) ->guard;
is_guard_or_builtin(function,1) ->guard;
is_guard_or_builtin(function,2) ->guard;
is_guard_or_builtin(integer,1) ->guard;
is_guard_or_builtin(list,1) ->guard;
is_guard_or_builtin(number,1) ->guard;
is_guard_or_builtin(pid,1) ->guard;
is_guard_or_builtin(port,1) ->guard;
is_guard_or_builtin(reference,1) ->guard;
is_guard_or_builtin(tuple,1) ->guard;
is_guard_or_builtin(record,2) ->guard;
is_guard_or_builtin(record,3) ->guard;
is_guard_or_builtin(F,A) ->
case erlang:function_exported(erlang,F,A) orelse
erlang:is_builtin(erlang,F,A) of
true -> builtin;
false-> neither
end.
-54
View File
@@ -1,54 +0,0 @@
%%%-------------------------------------------------------------------
%%% File : escobar_run.erl
%%% Author : Badlop <badlop@process-one.net>
%%% Purpose : Frontend to run Escobar
%%% Created : 16 Apr 2008 by Badlop <badlop@process-one.net>
%%%-------------------------------------------------------------------
-module(escobar_run).
%%% Download ejabberd_hilite.erl from http://code.google.com/p/erl-escobar/
%%% Example calls:
%%% escobar_run:file("escobar_run.erl", "../ejascobar/").
%%% escobar_run:dir(".", "../ejascobar/").
%%% escobar_run:dir(".", "../doc/api/").
%%% find ./ -type f -name '*.html' -exec sed -i 's/class="function" >\([a-z0-9]*\)</class="function" id="\1">\1</;' {} \;
-export([file/2, file/1, dir/1]).
file([F, OutDir]) ->
file(F, OutDir).
file(F, OutDir) ->
String = escobar_hilite:file(F),
FB = filename:basename(F),
FilenameHTML = filename:join(OutDir, FB ++ ".html"),
escobar_hilite:out(FilenameHTML, String).
dir([SrcDir, OutDir]) ->
SrcDirAbs = filename:absname(SrcDir),
OutDirAbs = filename:absname(OutDir),
Files = get_files([SrcDirAbs]),
lists:foreach(
fun(F) ->
case filename:extension(F) of
".erl" ->
file(F, OutDirAbs);
".hrl" ->
file(F, OutDirAbs);
_ ->
ok
end
end,
Files).
get_files([]) ->
[];
get_files([FHead | FTail]) ->
case catch file:list_dir(FHead) of
{ok, Files} ->
FilesHead = [filename:join(FHead, FilesN) || FilesN <- Files],
get_files(FilesHead ++ FTail);
{error, enotdir} ->
[FHead] ++ get_files(FTail)
end.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

-522
View File
@@ -1,522 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : funrelg.erl
%%% Author : Badlop <badlop@process-one.net>
%%% Purpose : Function Relation Graph
%%% Created : 3 Apr 2007 by Badlop <badlop@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2009 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(funrelg).
-author('badlop@process-one.net').
-export([dir/1, file/1, g/0, g/1, gc/0, gc/1, d/0]).
-record(mfa, {mod, func, arity}).
-record(arcs, {id, from, to, occ}).
%% The functions that are not in export and don't call anybody are not drawn
%% The calls to this module that use Mod:Func are drawn as external calls
%%-----------------------------
%% Module handlers
%%-----------------------------
dir([SrcDir, OutDir]) ->
SrcDirAbs = filename:absname(SrcDir),
OutDirAbs = filename:absname(OutDir),
Files = get_files([SrcDirAbs]),
lists:foreach(
fun(F) ->
file(F, OutDirAbs)
end,
Files).
file([SrcDir, OutDir]) ->
SrcFilAbs = filename:absname(SrcDir),
OutDirAbs = filename:absname(OutDir),
file(SrcFilAbs, OutDirAbs).
file(SrcFile, OutDir) ->
case {filename:extension(SrcFile), filename:basename(SrcFile)} of
%% The file must by *.erl, and the first character must be a-z
{".erl", [FirstChar | _]} when (FirstChar >= 97) and (FirstChar =< 122) ->
make_file(SrcFile, OutDir),
d();
_ ->
ok
end.
get_files([]) ->
[];
get_files([FHead | FTail]) ->
case catch file:list_dir(FHead) of
{ok, Files} ->
FilesHead = [filename:join(FHead, FilesN) || FilesN <- Files],
get_files(FilesHead ++ FTail);
{error, enotdir} ->
[FHead] ++ get_files(FTail)
end.
make_file(File, OutDir) ->
FB = filename:basename(File),
FileDot = filename:join(OutDir, FB ++ ".dot"),
Text = gc(File),
{ok,FO}=file:open(FileDot,[write]),
try
io:fwrite(FO,"~s",[Text])
after
file:close(FO)
end,
FileSvg = filename:join(OutDir, filename:basename(File, ".erl") ++ ".svg"),
case os:cmd("dot -Tsvg " ++ FileDot ++ " -o " ++ FileSvg) of
"" -> ok;
ShellResult ->
io:format("Trying to run 'dot', we got this result:~n ~s~n"
"Remember that you need to have Graphviz 'dot' installed.~n", [ShellResult])
end,
ok.
%%====================================================================
%% Internal functions
%%====================================================================
g() ->
g("a.erl").
g(Filename) ->
gc(Filename),
halt().
gc() ->
gc("a.erl").
gc(Filename) ->
{ok, File} = epp_dodger:parse_file(Filename),
ets:new(arcs, [set, public, named_table, {keypos, 2}]),
ets:new(mfa_conversion, [set, public, named_table, {keypos, 1}]),
ets:new(counters, [set, public, named_table]),
ets:insert(counters, {arcs_id, 0}),
ModuleName = get_module_name(File),
Exports = lists:usort(get_exports(File)),
Functions = get_functions(File),
FunctionsParsed = lists:usort(parse_functions(Functions)), % side effects: stores on ets
Privates = FunctionsParsed -- Exports,
%%Externals = get_externals(),
MFAs = get_func_calls(),
AppModules1 = os:cmd("ls -1 ../doc/devdoc/*.html | tr \".\" \" \" | tr \"/\" \" \" | awk '{print $3}'"),
AppModules = [list_to_atom(Str) || Str <- string:tokens(AppModules1, [10])],
ExternalTypes1 = [mfa_to_externaltype(MFA, ModuleName, AppModules, FunctionsParsed) || MFA <- MFAs],
ExternalTypes = lists:usort(ExternalTypes1),
AppExternals = [Function || {Type, Function} <- ExternalTypes, Type == app],
ExmppExternals = [Function || {Type, Function} <- ExternalTypes, Type == exmpp],
OTPExternals = [Function || {Type, Function} <- ExternalTypes, Type == other],
textize(ModuleName, Exports, Privates, AppExternals, ExmppExternals, OTPExternals).
get_arcs_id() ->
ets:update_counter(counters, arcs_id, 1).
insert_arc_normal(FromFunc, FromArity, ToFunc, ToArity) ->
From = #mfa{mod = -1, func = FromFunc, arity = FromArity},
To = #mfa{mod = -1, func = ToFunc, arity = ToArity},
insert_arc(From, To).
insert_arc_external(FromFunc, FromArity, ToMod, ToFunc, ToArity) ->
From = #mfa{mod = -1, func = FromFunc, arity = FromArity},
To = #mfa{mod = ToMod, func = ToFunc, arity = ToArity},
insert_arc(From, To).
insert_arc(From, To) ->
Match = #arcs{
from = From,
to = To,
id='$1',
_='_'},
Select = [{Match, [], ['$1']}],
Ids = ets:select(arcs, Select),
case Ids of
[] ->
ets:insert(arcs,
#arcs{
id = get_arcs_id(),
from = From,
to = To,
occ = 1
}
);
[Id] ->
[Arc] = ets:lookup(arcs, Id),
Arc2 = Arc#arcs{occ = Arc#arcs.occ+1},
ets:insert(arcs, Arc2)
end.
read_arc(Id) ->
ets:lookup(arcs, Id).
d() ->
ets:delete(arcs),
ets:delete(mfa_conversion),
ets:delete(counters).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Get
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
get_module_name(File) ->
Attributes = get_elements(attribute, File),
get_attribute(module, Attributes).
get_exports(File) ->
Attributes = get_elements(attribute, File),
Exports = get_attribute(export, Attributes),
parse_export(Exports).
get_functions(File) ->
get_elements(function, File).
get_elements(Type, L) -> get_elements(Type, L, []).
get_elements(_, [], Res) -> Res;
get_elements(Type, [{tree, Type, _, A} | L], Res) ->
get_elements(Type, L, Res++[A]);
get_elements(Type, [_ | L], Res) ->
get_elements(Type, L, Res).
get_attribute(_, []) -> [];
get_attribute(Name, [{attribute, {tree, atom, _, Name}, [Al]} | As]) ->
case Name of
module ->
{tree, atom, _, Mn} = Al,
Mn;
export ->
{tree, list, _, {list, Exports, _}} = Al,
Exports++get_attribute(Name, As);
_ -> ok
end;
get_attribute(Name, [_ | As]) ->
get_attribute(Name, As).
parse_export(Ex) ->
lists:foldl(
fun(Aq, Res) ->
{tree, arity_qualifier, _, {arity_qualifier, Atom, Inte}} = Aq,
{tree, atom, _, An} = Atom,
{tree, integer, _, In} = Inte,
Res++[{An, In}]
end,
[],
Ex).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Parse
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parse_functions(Functions) ->
lists:map(
fun(E) ->
{function, {_, _, _, Fn}, Clauses} = E,
Arity = get_function_arity(Clauses),
parse_clauses(Fn, Clauses),
{Fn, Arity}
end,
Functions).
parse_clauses(Fn, Clauses) ->
lists:foreach(
fun(E) ->
{tree, clause, L, C} = E,
{attr, _Ln, _, _} = L,
{clause, Parameters, _, Contents} = C,
Fa = length(Parameters),
parse_contents({Fn, Fa}, Contents)
end,
Clauses).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OLD
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parse_contents(F, Contents) ->
{_, Res} = lists:foldl(
fun(C, {Fu, R}) ->
{Fu, R++parse_content(F, C)}
end,
{F, []},
Contents),
Res.
parse_content(F, {tree, application, L, A}) ->
{attr, _Ln, _, _} = L,
parse_application(F, A);
parse_content(F, {tree, list, _, {list, [L], Ls}}) ->
RL = parse_content(F, L),
RL++parse_content(F, Ls);
parse_content(F, {tree, tuple, _, T}) ->
parse_contents(F, T);
parse_content(F, {tree, match_expr, _, M}) ->
{match_expr, _, Value} = M,
parse_content(F, Value);
parse_content(F, {tree, try_expr, _, T}) ->
{try_expr, As, Bs, Cs, Ds} = T,
RAs = parse_contents(F, As),
RBs = parse_contents(F, Bs),
RDs = parse_contents(F, Ds),
RAs++RBs++RDs++parse_contents(F, Cs);
parse_content(F, {tree, block_expr, _, Ts}) ->
parse_contents(F, Ts);
parse_content(F, {tree, catch_expr, _, C}) ->
parse_content(F, C);
parse_content(F, {tree, case_expr, _, C}) ->
{case_expr, Case, Cases} = C,
R2 = parse_content(F, Case),
R2++parse_contents(F, Cases);
parse_content(F, {tree, if_expr, _, Cases}) ->
parse_contents(F, Cases);
parse_content(F, {tree, disjunction, _, Cases}) ->
parse_contents(F, Cases);
parse_content(F, {tree, conjunction, _, Cases}) ->
parse_contents(F, Cases);
parse_content(F, {tree, list_comp, _, L}) ->
{list_comp, A, Bs} = L,
RA = parse_content(F, A),
RA++parse_contents(F, Bs);
parse_content(F, {tree, generator, _, G}) ->
{generator, _, Gen} = G,
parse_content(F, Gen);
parse_content(F, {tree, clause, _, C}) ->
{clause, Clause, When, Second} = C,
R2 = parse_contents(F, Clause),
R3 = parse_content(F, When),
R2++R3++parse_contents(F, Second);
parse_content(F, {tree, fun_expr, _, E}) ->
parse_contents(F, E);
parse_content(F, {tree, record_expr, _, E}) ->
{record_expr, _, _, Records} = E,
parse_contents(F, Records);
parse_content(F, {tree, record_field, _, R}) ->
{record_field, F1, F2} = R,
R2 = parse_content(F, F1),
R2++parse_content(F, F2);
parse_content(F, {tree, receive_expr, _, E}) ->
{receive_expr, E1, _, _} = E,
parse_contents(F, E1);
parse_content(F, {tree, infix_expr, _, I}) ->
{infix_expr, _Operator, T1, T2} = I,
R = parse_content(F, T1),
R++parse_content(F, T2);
parse_content(_F, {tree, prefix_expr, _, _P}) ->
[];
parse_content(_F, {tree, class_qualifier, _, _}) -> [];
parse_content(_F, {tree, implicit_fun, _, _}) -> [];
parse_content(_F, {tree, record_access, _, _}) -> [];
parse_content(_F, {tree, record_index_expr, _, _}) -> [];
parse_content(_F, {tree, macro, _, _}) -> [];
parse_content(_F, {tree, binary, _, _}) -> [];
parse_content(_F, {tree, binary_generator, _, _}) -> [];
parse_content(_F, {tree, binary_comp, _, _}) -> [];
parse_content(_F, {integer, _, _I}) -> [];
parse_content(_F, {float, _, _I}) -> [];
parse_content(_F, {string, _, _S}) -> [];
parse_content(_F, {char, _, _S}) -> [];
parse_content(_F, {atom, _, _A}) -> [];
parse_content(_F, {var, _, _V}) -> [];
parse_content(_F, {nil, _}) -> [];
parse_content(_F, none) -> [];
parse_content(_F, C) -> io:format("Unknown content: ~p~n", [C]), [].
parse_application({Fn, Fa}, {application, {atom, _, Name}, Valores}) ->
Arity = length(Valores),
insert_arc_normal(Fn, Fa, Name, Arity),
Ra = [{arc_normal, Fn, Name}],
Ra++parse_contents({Fn, Fa}, Valores);
parse_application({Fn, Fa}, {application, {tree, module_qualifier, _, M}, Tree2}) ->
case M of
{module_qualifier, {_, _, Tf1}, {_, _, Tf2}} ->
ToArity = length(Tree2),
insert_arc_external(Fn, Fa, Tf1, Tf2, ToArity),
parse_contents({Fn, Fa}, Tree2);
_Other ->
%%io:format("Unknown application module_qualifier: ~p~n", [M]),
parse_contents({Fn, Fa}, Tree2)
end;
parse_application({Fn, Fa}, {application, {tree, record_access, _, _}, Tree2}) ->
parse_contents({Fn, Fa}, Tree2);
parse_application({Fn, Fa}, {application, {var, _, _}, Tree2}) ->
parse_contents({Fn, Fa}, Tree2);
parse_application({Fn, Fa}, {application, Other, Tree2}) ->
io:format("Unknown application tree: ~p~n", [Other]),
parse_contents({Fn, Fa}, Tree2).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Textize
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
textize(ModuleName, Exports, Privates, AppExternals, ExmppExternals, OTPExternals) ->
ExportsS = textize_exports(Exports),
PrivatesS = textize_exports(Privates),
AppExternalsS = textize_externals(AppExternals),
ExmppExternalsS = textize_externals(ExmppExternals),
OTPExternalsS = textize_externals(OTPExternals),
Arcs = textize_arcs(),
io_lib:format(
"digraph ~p {~n"++
" label = \"Module ~p\";~n"++
" labelloc = \"t\";~n"++
" fontname = Helvetica;~n"++
" rankdir = LR;~n"++
" ratio = fill;~n"++
%%" node [shape = box, style = filled, color = olivedrab1, fontsize=40];~s~n"++
%%" node [shape = parallelogram, style = filled, color = rosybrown1, fontsize=40];~s~n"++
%%" node [shape = ellipse, style = filled, color = slategray1, peripheries=3, fontsize=40];~n"++
" node [shape = box, color=darkgreen, fillcolor=Honeydew, style=filled, href=\"PRI~p.html#\\N\"];~s~n"++
" node [shape = box, color=darkgreen, fillcolor=PaleGreen, style=filled, href=\"EXP~p.html#\\N\"];~s~n"++
" node [shape = box, color=darkgreen, fillcolor=Aquamarine, style=filled, href=\"APP\\N\"];~s~n"++
" node [shape = box, color=darkblue, fillcolor=LightSkyBlue,style=filled, href=\"EXM\\N\"];~s~n"++
" node [shape = box, color=darkred, fillcolor=PeachPuff, style=filled, href=\"OTP\\N\"];~s~n"++
" node [shape = box];~n"++
"~s"++
"}~n",
[ModuleName, ModuleName,
ModuleName, PrivatesS,
ModuleName, ExportsS,
AppExternalsS,
ExmppExternalsS,
OTPExternalsS,
Arcs]).
textize_exports(Exports) ->
lists:foldl(
fun({Func, Arity}, R) ->
string:concat(R, io_lib:format(" \"~p/~p\";", [Func, Arity]))
end,
"",
Exports).
textize_externals(Externals) ->
lists:foldl(
fun({Mod, Func, Arity}, R) ->
string:concat(R, io_lib:format(" \"~p:~p/~p\";", [Mod, Func, Arity]));
({Func, Arity}, R) ->
string:concat(R, io_lib:format(" \"~p/~p\";", [Func, Arity]))
end,
"",
Externals).
textize_arcs() ->
Id = ets:first(arcs),
textize_arcs(Id, []).
textize_arcs('$end_of_table', Res) -> Res;
textize_arcs(Id, Res) ->
[Arc] = read_arc(Id),
From = mfa_prepare(Arc#arcs.from),
To = mfa_prepare(Arc#arcs.to),
Edge_attrs = check_loop(From, To)++check_occu(Arc#arcs.occ)++check_external(Arc#arcs.to),
Res2 = io_lib:format(" ~s -> ~s~s;~n", [From, To, Edge_attrs]),
Id_next = ets:next(arcs, Id),
textize_arcs(Id_next, string:concat(Res2, Res)).
get_func_calls() ->
Id = ets:first(arcs),
get_func_calls(Id, []).
get_func_calls('$end_of_table', Res) -> Res;
get_func_calls(Id, Res) ->
[Arc] = read_arc(Id),
MFA = Arc#arcs.to,
Call = MFA,
Id_next = ets:next(arcs, Id),
get_func_calls(Id_next, [Call | Res]).
mfa_prepare(MFAinitial) ->
MFA = try_mfa_conversion(MFAinitial),
Mod = case MFA#mfa.mod of
-1 -> "\"";
M -> io_lib:format("\"~p:", [M])
end,
Func = io_lib:format("~p", [MFA#mfa.func]),
Arity = case MFA#mfa.arity of
-1 -> "\"";
A -> io_lib:format("/~p\"", [A])
end,
string:concat(Mod, string:concat(Func, Arity)).
%% noexternal | app | exmpp | other
mfa_to_externaltype(MFA, ModuleName, AppModules, Functions) ->
case MFA of
{mfa, -1, Fu, Ar} ->
case {is_internal, lists:member({Fu, Ar}, Functions)} of
{is_internal, true} ->
{noexternal, {Fu, Ar}};
{is_internal, false} ->
store_mfa_conversion(MFA, {mfa, -1, Fu, Ar}),
{other, {Fu, Ar}}
end;
{mfa, Mo, Fu, Ar} when Mo == ModuleName ->
store_mfa_conversion(MFA, {mfa, -1, Fu, Ar}),
{noexternal, {Fu, Ar}};
{mfa, Mo, Fu, Ar} ->
Type = case {is_app, lists:member(Mo, AppModules)} of
{is_app, true} -> app;
{is_app, false} ->
case string:str(atom_to_list(Mo), "exmpp") of
0 -> other;
N when is_integer(N) -> exmpp
end
end,
{Type, {Mo, Fu, Ar}}
end.
get_function_arity([{tree, clause, _, {clause, Vars, _, _}} | _]) ->
length(Vars);
get_function_arity(E) ->
io:format("Unknown function arity: ~p~n", [E]).
store_mfa_conversion(MFA1, MFA2) ->
ets:insert(mfa_conversion, {MFA1, MFA2}).
try_mfa_conversion(MFA) ->
case ets:lookup(mfa_conversion, MFA) of
[{MFA,MFA2}] ->
MFA2;
[] ->
MFA
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Utils
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%check_loop(I, I) -> " [color = sandybrown]";
check_loop(I, I) -> "";
check_loop(_, _) -> "".
check_occu(1) -> "";
check_occu(Occ) -> io_lib:format(" [label=\"~p\"]", [Occ]).
check_external(To) ->
case To#mfa.mod of
-1 -> " [style = bold]";
_ -> ""
end.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 B

+132
View File
@@ -0,0 +1,132 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.11 Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<META name="GENERATOR" content="hevea 1.10">
<STYLE type="text/css">
.li-itemize{margin:1ex 0ex;}
.li-enumerate{margin:1ex 0ex;}
.dd-description{margin:0ex 0ex 1ex 4ex;}
.dt-description{margin:0ex;}
.toc{list-style:none;}
.thefootnotes{text-align:left;margin:0ex;}
.dt-thefootnotes{margin:0em;}
.dd-thefootnotes{margin:0em 0em 0em 2em;}
.footnoterule{margin:1em auto 1em 0px;width:50%;}
.caption{padding-left:2ex; padding-right:2ex; margin-left:auto; margin-right:auto}
.title{margin:2ex auto;text-align:center}
.center{text-align:center;margin-left:auto;margin-right:auto;}
.flushleft{text-align:left;margin-left:0ex;margin-right:auto;}
.flushright{text-align:right;margin-left:auto;margin-right:0ex;}
DIV TABLE{margin-left:inherit;margin-right:inherit;}
PRE{text-align:left;margin-left:0ex;margin-right:auto;}
BLOCKQUOTE{margin-left:4ex;margin-right:4ex;text-align:left;}
TD P{margin:0px;}
.boxed{border:1px solid black}
.textboxed{border:1px solid black}
.vbar{border:none;width:2px;background-color:black;}
.hbar{border:none;height:2px;width:100%;background-color:black;}
.hfill{border:none;height:1px;width:200%;background-color:black;}
.vdisplay{border-collapse:separate;border-spacing:2px;width:auto; empty-cells:show; border:2px solid red;}
.vdcell{white-space:nowrap;padding:0px;width:auto; border:2px solid green;}
.display{border-collapse:separate;border-spacing:2px;width:auto; border:none;}
.dcell{white-space:nowrap;padding:0px;width:auto; border:none;}
.dcenter{margin:0ex auto;}
.vdcenter{border:solid #FF8000 2px; margin:0ex auto;}
.minipage{text-align:left; margin-left:0em; margin-right:auto;}
.marginpar{border:solid thin black; width:20%; text-align:left;}
.marginparleft{float:left; margin-left:0ex; margin-right:1ex;}
.marginparright{float:right; margin-left:1ex; margin-right:0ex;}
.theorem{text-align:left;margin:1ex auto 1ex 0ex;}
.part{margin:2ex auto;text-align:center}
SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
</STYLE>
</HEAD>
<BODY >
<!--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.11 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">
<IMG SRC="logo.png" ALT="logo.png">
</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-->
<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;
Peter Saint-Andr&#XE9;, Executive Director of the Jabber Software Foundation</I></FONT></BLOCKQUOTE><P><TT>ejabberd</TT> is:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
<B><FONT SIZE=4><FONT COLOR="#001376">Cross-platform:</FONT></FONT></B> <TT>ejabberd</TT> runs under Microsoft Windows and Unix derived systems such as Linux, FreeBSD and NetBSD.</LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Distributed:</FONT></FONT></B> You can run <TT>ejabberd</TT> on a cluster of machines and all of them will serve the same Jabber domain(s). When you need more capacity you can simply add a new cheap node to your cluster. Accordingly, you do not need to buy an expensive high-end machine to support tens of thousands concurrent users.</LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Fault-tolerant:</FONT></FONT></B> You can deploy an <TT>ejabberd</TT> cluster so that all the information required for a properly working service will be replicated permanently on all nodes. This means that if one of the nodes crashes, the others will continue working without disruption. In addition, nodes also can be added or replaced &#X2018;on the fly&#X2019;.</LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Administrator Friendly:</FONT></FONT></B> <TT>ejabberd</TT> is built on top of the Open Source Erlang. As a result you do not need to install an external database, an external web server, amongst others because everything is already included, and ready to run out of the box. Other administrator benefits include:
<UL CLASS="itemize"><LI CLASS="li-itemize">
Comprehensive documentation.
</LI><LI CLASS="li-itemize">Straightforward installers for Linux, Mac OS X, and Windows. </LI><LI CLASS="li-itemize">Web Administration.
</LI><LI CLASS="li-itemize">Shared Roster Groups.
</LI><LI CLASS="li-itemize">Command line administration tool. </LI><LI CLASS="li-itemize">Can integrate with existing authentication mechanisms.
</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>.
</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.
</LI><LI CLASS="li-itemize">XML-based protocol.
</LI><LI CLASS="li-itemize"><A HREF="http://www.ejabberd.im/protocols">Many protocols supported</A>.
</LI></UL></LI></UL><!--TOC section Additional Features-->
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc2"></A>Additional Features</H2><!--SEC END --><P>
<A NAME="addfeatures"></A>
</P><BLOCKQUOTE CLASS="quotation"><FONT COLOR="#921700"><I>ejabberd is making inroads to solving the "buggy incomplete server" problem &#X2014;
Justin Karneges, Founder of the Psi and the Delta projects</I></FONT></BLOCKQUOTE><P>Moreover, <TT>ejabberd</TT> comes with a wide range of other state-of-the-art features:
</P><UL CLASS="itemize"><LI CLASS="li-itemize">
Modular
<UL CLASS="itemize"><LI CLASS="li-itemize">
Load only the modules you want.
</LI><LI CLASS="li-itemize">Extend <TT>ejabberd</TT> with your own custom modules.
</LI></UL>
</LI><LI CLASS="li-itemize">Security
<UL CLASS="itemize"><LI CLASS="li-itemize">
SASL and STARTTLS for c2s and s2s connections.
</LI><LI CLASS="li-itemize">STARTTLS and Dialback s2s connections.
</LI><LI CLASS="li-itemize">Web Admin accessible via HTTPS secure access.
</LI></UL>
</LI><LI CLASS="li-itemize">Databases
<UL CLASS="itemize"><LI CLASS="li-itemize">
Internal database for fast deployment (Mnesia).
</LI><LI CLASS="li-itemize">Native MySQL support.
</LI><LI CLASS="li-itemize">Native PostgreSQL support.
</LI><LI CLASS="li-itemize">ODBC data storage support.
</LI><LI CLASS="li-itemize">Microsoft SQL Server support. </LI></UL>
</LI><LI CLASS="li-itemize">Authentication
<UL CLASS="itemize"><LI CLASS="li-itemize">
Internal Authentication.
</LI><LI CLASS="li-itemize">PAM, LDAP and ODBC. </LI><LI CLASS="li-itemize">External Authentication script.
</LI></UL>
</LI><LI CLASS="li-itemize">Others
<UL CLASS="itemize"><LI CLASS="li-itemize">
Support for virtual hosting.
</LI><LI CLASS="li-itemize">Compressing XML streams with Stream Compression (<A HREF="http://www.xmpp.org/extensions/xep-0138.html">XEP-0138</A>).
</LI><LI CLASS="li-itemize">Statistics via Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>).
</LI><LI CLASS="li-itemize">IPv6 support both for c2s and s2s connections.
</LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0045.html">Multi-User Chat</A> module with support for clustering and HTML logging. </LI><LI CLASS="li-itemize">Users Directory based on users vCards.
</LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0060.html">Publish-Subscribe</A> component with support for <A HREF="http://www.xmpp.org/extensions/xep-0163.html">Personal Eventing via Pubsub</A>.
</LI><LI CLASS="li-itemize">Support for web clients: <A HREF="http://www.xmpp.org/extensions/xep-0025.html">HTTP Polling</A> and <A HREF="http://www.xmpp.org/extensions/xep-0206.html">HTTP Binding (BOSH)</A> services.
</LI><LI CLASS="li-itemize">IRC transport.
</LI><LI CLASS="li-itemize">Component support: interface with networks such as AIM, ICQ and MSN installing special tranports.
</LI></UL>
</LI></UL><!--CUT END -->
<!--HTMLFOOT-->
<!--ENDHTML-->
<!--FOOTER-->
<HR SIZE=2><BLOCKQUOTE CLASS="quote"><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
</EM><A HREF="http://hevea.inria.fr/index.html"><EM>H</EM><EM><FONT SIZE=2><sup>E</sup></FONT></EM><EM>V</EM><EM><FONT SIZE=2><sup>E</sup></FONT></EM><EM>A</EM></A><EM>.</EM></BLOCKQUOTE></BODY>
</HTML>
+4516
View File
File diff suppressed because it is too large Load Diff
+380 -343
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -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 24 languages. %%\improved{}
\item Translated to 25 languages. %%\improved{}
\item Support for \footahref{http://www.ietf.org/rfc/rfc3490.txt}{IDNA}.
\end{itemize}
@@ -127,6 +127,7 @@ Moreover, \ejabberd{} comes with a wide range of other state-of-the-art features
\item Users Directory based on users vCards.
\item \txepref{0060}{Publish-Subscribe} component with support for \txepref{0163}{Personal Eventing via Pubsub}.
\item Support for web clients: \txepref{0025}{HTTP Polling} and \txepref{0206}{HTTP Binding (BOSH)} services.
\item IRC transport.
\item Component support: interface with networks such as AIM, ICQ and MSN installing special tranports.
\end{itemize}
\end{itemize}
+39
View File
@@ -0,0 +1,39 @@
Release Notes
ejabberd 2.1.10
ejabberd 2.1.10 includes a few bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.10
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The major changes are:
* Erlang/OTP compatibility
- Support Erlang/OTP R15B regexp and drivers (EJAB-1521)
- Fix modules update in R14B04 and higher
- Fix modules update of stripped beams (EJAB-1520)
* XMPP Core
- Fix presence problem in C2S after first unavailable (EJAB-1466)
- Fix bug on S2S shaper when TLS is used
- Prevent overload of incoming S2S connections
* XEPs
- BOSH: Get rid of useless mnesia transaction (EJAB-1502)
- MUC: Don't reveal invitee resource when room informs invitor
- Privacy: Activate "Blocked Contacts" to current c2s connection (EJAB-1519)
- Privacy: Always allow packets from user's server and bare jid (EJAB-1441)
- Pubsub: Add hooks for node creation/deletion (EJAB-1470)
- Shared Rosters: support groupname@vhost in Displayed Groups (EJAB-506)
- Vcard: Fix error when lowercasing some search results (EJAB-1490)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+58
View File
@@ -0,0 +1,58 @@
Release Notes
ejabberd 2.1.11
ejabberd 2.1.11 includes a few bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.11
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The major changes are:
* HTTP service
- Fix ejabberd_http:get_line
- Don't use binary:match to extract lines from binaries
- Parse and encode https header names like native http parser does
- Parse correctly https request split into multiple packets
- Properly handle HEAD request in mod_http_bind (EJAB-1538)
- New option default_host for handling requests with ambiguous Host (EJAB-1261)
* ODBC
- New ODBC support for mod_announce
- New ODBC support for mod_blocking
- New ODBC support for mod_irc
- New ODBC support for mod_muc
- New ODBC support for mod_shared_roster
- New ODBC support for mod_vcard_xupdate
- Add ODBC exporting function for privacy table
- Work also with some unicode strings in PgSQL (EJAB-1490)
- Replace a single quote with double quotes in an ODBC escape
* SSL
- Make sure that res is initialized in all cases
- Parse correctly https request split into multiple packets (EJAB-1537)
- Added missed tls:recv_data/2
- Don't ignore Length parameter in tls:recv
- Avoid quadratic behavior in reading SSL data
- Dix http_bind webserver TLS fail on Chrome (EJAB-1530)
* Miscelanea
- Assume we have only one CPU when an auto-detection fails (EJAB-1516)
- Auth: Relax digest-uri handling (EJAB-1529)
- Caps: Cache caps timestamp before the IQ-request is done
- IRC: Use of MUC password
- Private: misc errors cases fixes
- Pubsub: return user affiliation for a specified node (EJAB-1294)
- Shared Roster: Foreign items were not pushed (EJAB-1509)
- Shared Roster LDAP: user substitution in ldap_rfilter (EJAB-1555)
- Windows: Fix makefile rules for building DLLs
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+1 -1
View File
@@ -6,7 +6,7 @@
and includes several minor bugfixes and a few improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.5
http://redir.process-one.net/ejabberd-2.1.4
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
+97
View File
@@ -0,0 +1,97 @@
Release Notes
ejabberd 2.1.7
ejabberd 2.1.7 is the eighth release in ejabberd 2.1.x branch,
and includes a lot of bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.7
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The changes are:
* BOSH and Web
- Clarify error message when BOSH query is sent to non-running module
- Keep the order of stanzas when BOSH sends several (EJAB-1374)
- Show configuration for HTTPS http_bind
- Support as read-only HTTP method not only GET, also HEAD
- The responses to HEAD must have empty Body
* CAPTCHA
- If the port number isn't listener, then specify the protocol (EJAB-1418)
- New CAPTCHA limit
- New CAPTCHA whitelist support
- Only check system at startup if option is enabled
- Provide HTTPS URL in CAPTCHA form when listener has 'tls' option (EJAB-1406)
- Show captcha_limit option in the example config
- Support more captcha_host value formats (EJAB-1418)
- Throw error when captcha fails at server start, not later at runtime
- captcha_host must have the port number to get protocol (EJAB-1418)
* Core ejabberd
- Disable all entity expansions (EJAB-1451)
- Do not accept XML with undefined prefixes (EJAB-680)
- Make jlib:ip_to_list safe to use
- Make sure 'closed' event is correctly processed on every state
- New route_iq/5 accepting Timeout (EJAB-1398)
- Take into consideration internal queue length when sorting processes queues
- Use route instead of send_element to go through standard workflow
* Erlang/OTP compatibility
- Remove Type and Spec, backport list comprehensions, so R12B-5 can compile
- Tweak pg2_backport.erl to work with Erlang older than R13A (EJAB-1349)
* ODBC
- Don't let presence-in privacy rule block a presence subscription (EJAB-255)
- Escape user input in mod_privacy_odbc (EJAB-1442)
- Try to improve support for roster_version in MSSQL (EJAB-1437)
* Pubsub/PEP/Caps
- Apply filtered notification to PEP last items (EJAB-1456)
- Fix empty pubsub payload check
- Owner can delete any items from its own node (EJAB-1445)
- Pubsub node maxitem forced to 0 if non persistent node (EJAB-1434)
- Reorganize the push_item function, and handle version not_found (EJAB-1420)
* Scripts
- ejabberd.init: Several fixes and improvements
- ejabberdctl: Escape output from ctlexec() to erl script (EJAB-1399)
- ejabberdctl: Fix bashism and mimic master branch (EJAB-1404)
- ejabberdctl: Fix space between INET_DIST_INTERFACE (EJAB-1416)
- ejabberdctl: New DIST_USE_INTERFACE restricts IP of erlang listen (EJAB-1404)
- ejabberdctl: New ERL_EPMD_ADDRESS that works since Erlang/OTP R14B03
- extauth: Fix delayed response of timeout was reused for next login (EJAB-1385)
- extauth: Forward old messages to newly spawned extauth process (EJAB-1385)
- extauth: If script crashes, ejabberd should restart it (EJAB-1428)
* XEP support
- mod_blocking: New XEP-0191 Simple Communications Blocking (EJAB-695)
- No need to inform that XEP-0237 is optional; clarified in XEP version 1.2
* Miscellanea:
- If a module start fails during server start, stop erlang (EJAB-1446)
- New Indonesian translation (EJAB-1407)
- LDAP: Note that ejabberd works with CGP LDAP server
- S2S: Handle Tigase's unexpected version=1.0 (EJAB-1379)
- mod_irc: Send presence unavailable to the departing occupant (EJAB-1417)
- mod_last: Allow user to query his own Last activity
- mod_muc: Do not decrease MUC admin's role/affiliation
- mod_muc: Send jid attribute when occupant is banned (EJAB-1432)
- mod_offline: Change c2s state before offline messages resending
- mod_ping: Use iqdisc no_queue by default (EJAB-1435)
- mod_pres_counter: Prevent subscription flood (EJAB-1388)
- mod_register Access now also controls account unregistrations
- mod_register: Clarify more the expected content of welcome_message option
- mod_shared_roster: Fix support for anonymous accounts in @all@ (EJAB-1264)
- mod_shared_roster: New @online@ directive (EJAB-1391)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+21
View File
@@ -0,0 +1,21 @@
Release Notes
ejabberd 2.1.8
ejabberd 2.1.8 is the ninth release in ejabberd 2.1.x branch,
and includes a PubSub regression bugfix.
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The change is:
- Fix issue on PubSub preventing publication of items (EJAB-1457)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+56
View File
@@ -0,0 +1,56 @@
Release Notes
ejabberd 2.1.9
ejabberd 2.1.9 is the eighth release in ejabberd 2.1.x branch,
and includes a lot of bugfixes and improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-2.1.9
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
The changes are:
* Core ejabberd
- Decrease CPU usage caused by tls:send with large data
- Escape iolist correctly when NIFs are disabled (EJAB-1462)
- Fix code to satisfy Dialyzer warnings
- Fix compilation in Windows
- Replace calls of OTP's Binary, since they would require R14
* LDAP
- Document ldap_tls_cacertfile and ldap_tls_depth options (EJAB-1299)
- Log an error when an LDAP filter is incorrect (EJAB-1395)
- New options: ldap_tls_cacertfile and ldap_tls_depth (EJAB-1299)
- New option: ldap_deref_aliases (EJAB-639)
- Match ldap_uidattr_format case-insensitively (EJAB-1449)
* MUC
- Support for multiple entry with same nick to MUC rooms (EJAB-305)
- Support voice request and approvement
- New room option: allow_private_messages_from_visitors
- New room options: allow_voice_requests and voice_request_min_interval
- Include status 110 in presence to new occupant (EJAB-740)
- Fix mod_muc_log crash when first log entry is room destroy (EJAB-1499)
- Many fixes and improvements in mod_muc
* Pubsub
- Enable pubsub#deliver_notification checking (EJAB-1453)
- Fix Denial of Service when user sends malformed publish stanza (EJAB-1498)
* ODBC
- Fix ODBC account counting (EJAB-1491)
- Optimized mod_roster_odbc:get_roster
* Miscellanea:
- New SASL SCRAM-SHA-1 authentication mechanism (EJAB-1196)
- New option: resource_conflict (EJAB-650)
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
-104
View File
@@ -1,104 +0,0 @@
******************************************************************************
* These are the preliminary release notes of ejabberd 3.0.0.
*
* The download page for preliminary releases is:
* http://download.process-one.net/ejabberd/
*
* WARNING!!! PRELIMINARY DATABASE SCHEMA !!!
* The database schema may change before ejabberd 3.0.0 is released,
* and no migration code will be developed for this preliminary schema.
* The only supported migrations are
* from any ejabberd 0.9.0 ... 2.1.x to the final 3.0.0.
* Don't use this preliminary ejabberd release for a production server.
* You can test this release with a blank database or with a copy of your
* production database, but don't let your users connect to this copy
* because their changes may get lost when you upgrade to the final 3.0.0.
******************************************************************************
Release Notes
ejabberd 3.0.0
ejabberd 3.0.0 is the first release in the brand new 3.x.x branch,
and includes several minor bugfixes and a few improvements.
Read more details about the changes in:
http://redir.process-one.net/ejabberd-3.0.0
Download the source code and installers from:
http://www.process-one.net/en/ejabberd/
ejabberd 3.0.0 includes three major changes:
* exmpp is now extensively used in ejabberd for parsing stanzas, and many more.
* gen_storage (abbreviated GS) provides a database abstraction layer,
which supports storage in Mnesia and in ODBC databases.
Several ejabberd modules use GS, like mod_roster and ejabberd_auth_storage.
The schema of the tables stored by those modules have changed.
ejabberd automatically creates mnesia and ODBC tables,
and migrates them from a previous ejabberd version.
* Massive Hosting (abbreviated MH) is preliminary implemented in ejabberd,
but it is still incomplete, untested and undocumented.
This is a more detailed list of changes since ejabberd 2.1.x releases:
* Requirements
- Erlang/OTP R12B-5 or higher is required
- exmpp 0.9.6 or higher is required, not optional
- ESASL library is optional, for SASL GSSAPI authentication
- Libexpat not required by ejabberd, it uses exmpp now (EJAB-1111)
- GNU Iconv not required, because mod_irc isn't included anymore (EJAB-954)
- Only database migration from ejabberd 0.9.0 up to 2.1.x is supported
- ejabberd modules developed for previous releases need to be upgraded to exmpp
* Configuration
- New option clusterid
- New option that can't be used yet: static_modules
- ejabberd_auth_storage: new option auth_storage
- mod_muc_log: option spam_prevention is now link_nofollow (EJAB-1141)
- mod_roster: new access option (EJAB-72)
- S2S: allow definition of local address for outgoing connections (EJAB-418)
* Database
- New gen_storage that provides a database storage abstraction layer (EJAB-1102)
- mod_*_odbc are obsolete, use the normal ones with the option {backend, odbc}
- New ejabberd_auth_storage that supports internal and odbc databases
* XEP support
- Removed support for the deprecated XEP-0018 Invisible Presence (EJAB-810)
- mod_multicast: service for XEP-0033: Extended Stanza Addressing (EJAB-265)
- New ejabberd router for multicast packets (XEP-0033) (EJAB-329)
- ejabberd_c2s uses XEP-0033 if mod_multicast is enabled (EJAB-267)
- mod_muc uses XEP-0033 if mod_multicast is enabled (EJAB-266)
* Pubsub/PEP/Caps
- Allow distinguish between leafs and items (EJAB-1027)
- Enforce disco features results (EJAB-1033, EJAB-1228, EJAB-1238)
- Enforce pubsub#presence_based_delivery (EJAB-1221)
- Improve get_caps while still waiting for initial presence (EJAB-934)
- Make nodetree_tree implicitly create parent node if required (EJAB-944)
- Only use binary() instead of string() in Host and ServerHost (EJAB-1244)
- Rename NodeId (pubsub_node.id) bindings to Nidx (EJAB-1000)
- node_flat becomes default; it has the code instead of hometree (EJAB-1077)
- pubsub#notify_sub node option (EJAB-1230)
- pubsub#type node config and payload namespace (EJAB-1083)
* Miscellanea
- Bugfix handling Service Discovery to contacts (EJAB-1207)
- Bugfix: external contacts were offline after unavailable presence (EJAB-943)
- Don't offer SASL auth before doing TLS if TLS is required
- Experimental support for GSSAPI auth, requires esasl library (EJAB-831)
- Use binaries instead of lists where possible (EJAB-17)
- Windows ejabberdctl.cmd only handles up to 4 arguments (EJAB-1216)
- ejabberdctl: when starting, check it isn't already running
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+2
View File
@@ -0,0 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.11}
+75
View File
@@ -0,0 +1,75 @@
#!/bin/sh
#
# PROVIDE: ejabberd
# REQUIRE: DAEMON
# KEYWORD: shutdown
#
HOME=/usr/pkg/jabber D=/usr/pkg/jabber/ejabberd export HOME
name="ejabberd"
rcvar=$name
if [ -r /etc/rc.conf ]
then
. /etc/rc.conf
else
eval ${rcvar}=YES
fi
# $flags from environment overrides ${rcvar}_flags
if [ -n "${flags}" ]
then
eval ${rcvar}_flags="${flags}"
fi
checkyesno()
{
eval _value=\$${1}
case $_value in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0 ;;
[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1 ;;
*)
echo "\$${1} is not set properly."
return 1
;;
esac
}
cmd=${1:-start}
case ${cmd} in
force*)
cmd=${cmd#force}
eval ${rcvar}=YES
;;
esac
if checkyesno ${rcvar}
then
else
exit 0
fi
case ${cmd} in
start)
if [ -x $D/src ]; then
echo "Starting ${name}."
cd $D/src
ERL_MAX_PORTS=32000 export ERL_MAX_PORTS
ulimit -n $ERL_MAX_PORTS
su jabber -c "/usr/pkg/bin/erl -sname ejabberd -s ejabberd -heart -detached -sasl sasl_error_logger '{file, \"ejabberd-sasl.log\"}' &" \
1>/dev/null 2>&1
fi
;;
stop)
echo "rpc:call('ejabberd@`hostname -s`', init, stop, [])." | \
su jabber -c "/usr/pkg/bin/erl -sname ejabberdstop"
;;
restart)
echo "rpc:call('ejabberd@`hostname -s`', init, restart, [])." | \
su jabber -c "/usr/pkg/bin/erl -sname ejabberdrestart"
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
+81
View File
@@ -0,0 +1,81 @@
#!/bin/sh
echo '1. fetch, compile, and install erlang'
if [ ! pkg_info erlang 1>/dev/null 2>&1 ]; then
cd /usr/pkgsrc/lang/erlang
make fetch-list|sh
make
make install
fi
if pkg_info erlang | grep -q erlang-9.1nb1; then
else
echo "erlang-9.1nb1 not installed" 1>&2
exit 1
fi
echo '2. install crypt_drv.so'
if [ ! -d /usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib ] ; then
mkdir -p /usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib
fi
if [ ! -f /usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib/crypto_drv.so ]; then
cp work/otp*/lib/crypto/priv/*/*/crypto_drv.so \
/usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib
fi
echo '3. compile and install elibcrypto.so'
if [ ! -f /usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib/elibcrypto.so ]; then
cd /usr/pkgsrc/lang/erlang/work/otp_src_R9B-1/lib/crypto/c_src
ld -r -u CRYPTO_set_mem_functions -u MD5 -u MD5_Init -u MD5_Update \
-u MD5_Final -u SHA1 -u SHA1_Init -u SHA1_Update -u SHA1_Final \
-u des_set_key -u des_ncbc_encrypt -u des_ede3_cbc_encrypt \
-L/usr/lib -lcrypto -o ../priv/obj/i386--netbsdelf/elibcrypto.o
cc -shared \
-L/usr/pkgsrc/lang/erlang/work/otp_src_R9B-1/lib/erl_interface/obj/i386--netbsdelf \
-o ../priv/obj/i386--netbsdelf/elibcrypto.so \
../priv/obj/i386--netbsdelf/elibcrypto.o -L/usr/lib -lcrypto
cp ../priv/obj/i386--netbsdelf/elibcrypto.so \
/usr/pkg/lib/erlang/lib/crypto-1.1.2.1/priv/lib
fi
echo '4. compile and install ssl_esock'
if [ ! -f /usr/pkg/lib/erlang/lib/ssl-2.3.5/priv/bin/ssl_esock ]; then
cd /usr/pkg/lib/erlang/lib/ssl-2.3.5/priv/obj/
make
fi
echo '5. initial ejabberd configuration'
cd /usr/pkg/jabber/ejabberd/src
./configure
echo '6. edit ejabberd Makefiles'
for M in Makefile mod_*/Makefile; do
if [ ! -f $M.orig ]; then
mv $M $M.orig
sed -e s%/usr/local%/usr/pkg%g < $M.orig > $M
fi
done
echo '7. compile ejabberd'
gmake
for A in mod_irc mod_muc mod_pubsub; do
(cd $A; gmake)
done
echo ''
echo 'now edit ejabberd.cfg'
echo ''
echo 'to start ejabberd: erl -sname ejabberd -s ejabberd'
+66
View File
@@ -0,0 +1,66 @@
% jabber.dbc.mtview.ca.us
override_acls.
{acl, admin, {user, "mrose", "jabber.dbc.mtview.ca.us"}}.
{access, announce, [{allow, admin},
{deny, all}]}.
{access, c2s, [{deny, blocked},
{allow, all}]}.
{access, c2s_shaper, [{none, admin},
{normal, all}]}.
{access, configure, [{allow, admin},
{deny, all}]}.
{access, disco_admin, [{allow, admin},
{deny, all}]}.
{access, muc_admin, [{allow, admin},
{deny, all}]}.
{access, register, [{deny, all}]}.
{access, s2s_shaper, [{fast, all}]}.
{auth_method, internal}.
{host, "jabber.dbc.mtview.ca.us"}.
{outgoing_s2s_port, 5269}.
{shaper, normal, {maxrate, 1000}}.
{shaper, fast, {maxrate, 50000}}.
{welcome_message, none}.
{listen, [{5222, ejabberd_c2s,
[{access, c2s},
{shaper, c2s_shaper}]},
{5223, ejabberd_c2s,
[{access, c2s},
{shaper, c2s_shaper},
{ssl, [{certfile, "/etc/openssl/certs/ejabberd.pem"}]}]},
{5269, ejabberd_s2s_in,
[{shaper, s2s_shaper}]}]}.
{modules, [
{mod_register, []},
{mod_roster, []},
{mod_privacy, []},
{mod_configure, []},
{mod_disco, []},
{mod_stats, []},
{mod_vcard, []},
{mod_offline, []},
{mod_echo, [{host, "echo.jabber.dbc.mtview.ca.us"}]},
{mod_private, []},
% {mod_irc, []},
{mod_muc, []},
{mod_pubsub, []},
{mod_time, []},
{mod_last, []},
{mod_version, []}
]}.
% Local Variables:
% mode: erlang
% End:
@@ -0,0 +1,77 @@
<!-- aim-transport.xml -->
<jabber>
<!--
You need to add elogger and rlogger entries when using ejabberd.
In this case the transport will do the logging.
-->
<log id='elogger'>
<host/>
<logtype/>
<format>%d: [%t] (%h): %s</format>
<file>/var/log/jabber/aim-transport-error.log</file>
</log>
<log id='rlogger'>
<host/>
<logtype>record</logtype>
<format>%d %h %s</format>
<file>/var/log/jabber/aim-transport-record.log</file>
</log>
<!--
ejabberd do not provide XDB services.
xdb_file.so is loaded in to handle all XDB requests.
-->
<xdb id="xdb">
<host/>
<load>
<xdb_file>/usr/local/lib/jabber/libjabberdxdbfile.so</xdb_file> <!-- This file is part of jabberd-1.4.x. -->
</load>
<xdb_file xmlns="jabber:config:xdb_file">
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool>
</xdb_file>
</xdb>
<!--
Make sure that all host names here are resolveable via DNS if you
want the transport to be available to the public.
-->
<service id='aim.SERVER.COM'>
<!-- aim-transport configuration. -->
<aimtrans xmlns='jabber:config:aimtrans'>
<vCard>
<FN>AIM/ICQ Transport</FN>
<DESC>This is the AIM/ICQ Transport.</DESC>
<MAIL>EMAIL@ADDRESS.COM</MAIL>
<URL>http://aim-transport.jabberstudio.org/</URL>
</vCard>
<charset>cp1252</charset>
</aimtrans>
<!-- aim-transport module. -->
<load>
<aim_transport>/usr/local/lib/jabber/aim-transport.so</aim_transport>
</load>
</service>
<!--
The settings below have to match the settings you made
in your ejabberd.cfg configuration file.
-->
<service id="icq-linker">
<uplink/>
<connect>
<ip>127.0.0.1</ip>
<port>5233</port>
<secret>SECRET</secret>
</connect>
</service>
<pidfile>/var/run/jabber/aim-transport.pid</pidfile>
</jabber>
+136
View File
@@ -0,0 +1,136 @@
<!-- ile.xml -->
<config>
<jabber>
<server>127.0.0.1</server>
<port>5238</port>
<secret>SECRET</secret>
<service>ile.SERVER.COM</service>
<connectsleep>7</connectsleep> <!-- seconds to wait if we get disconnected -->
<language>en</language>
<vCard>
<FN>I Love Email</FN>
<DESC>With this service you can receive email notifications.
Security warning: Be careful when using this. Your password will travel in clear from your client to your jabber server if you don't use SSL and it will probably travel in clear from the jabber server to your email server. Use with care. This shouldn't be an issue in your Intranet, but it is if you use an ILE installed in a foreign jabber server.</DESC>
<MAIL>EMAIL@ADDRESS.COM</MAIL>
<URL>http://ile.jabberstudio.org/</URL>
</vCard>
</jabber>
<debug>
<file>/var/log/jabber/ile.log</file>
<level>1</level> <!-- man Net::Jabber::Debug -->
</debug>
<mail>
<checkinterval>10</checkinterval> <!-- in minutes -->
<timeout>20</timeout> <!-- timeout for IMAP/POP connection, in seconds -->
</mail>
<files>
<users>/var/spool/jabber/ile.SERVER.COM/users.db</users>
<passwords>/var/spool/jabber/ile.SERVER.COM/passwords.db</passwords>
<hosts>/var/spool/jabber/ile.SERVER.COM/hosts.db</hosts>
<types>/var/spool/jabber/ile.SERVER.COM/types.db</types>
<notifyxa>/var/spool/jabber/ile.SERVER.COM/notifyxa.db</notifyxa>
<notifydnd>/var/spool/jabber/ile.SERVER.COM/notifydnd.db</notifydnd>
<urls>/var/spool/jabber/ile.SERVER.COM/urls.db</urls>
</files>
<form>
<en>
<instructions>Please fill in the fields,according to your email account settings and notification preferences</instructions>
<title>ILE: Email notification service</title>
<email_options>Email account settings</email_options>
<user>Username</user>
<pass>Password</pass>
<host>Hostname</host>
<type>Type</type>
<newmail>You have received NUM email messages since last time I checked, which was CHECKINTERVAL minutes ago.</newmail>
<errorcheck>There was an error while trying to check mail for ACCOUNT.</errorcheck>
<notify_options>Notification Options</notify_options>
<notifyxa>Notify even when Xtended Away (XA)</notifyxa>
<notifydnd>Notify even when Do Not Disturb (DND)</notifydnd>
<webmail_url>Webmail URL</webmail_url>
<webmail_login>Login to ACCOUNT</webmail_login>
<iledesc>ILE: an email notifier component: http://ile.jabberstudio.org</iledesc>
</en>
<es>
<instructions>Por favor, rellene los campos del formulario.</instructions>
<title>ILE: Servicio de notificación de correo</title>
<email_options>Configuración de la cuenta de correo</email_options>
<user>Usuario</user>
<pass>Clave</pass>
<host>Host</host>
<type>Tipo</type>
<newmail>Ha recibido NUM email(s) desde la última comprobación que fue hace CHECKINTERVAL minutos</newmail>
<errorcheck>Ha habido un error en la comprobación del correo para la cuenta ACCOUNT.</errorcheck>
<notify_options>Opciones de notificación</notify_options>
<notifyxa>Notificar incluso si muy ausente (XA)</notifyxa>
<notifydnd>Notificar incluso si no molestar (DND)</notifydnd>
<webmail_url>Webmail URL</webmail_url>
<webmail_login>Leer correo de ACCOUNT</webmail_login>
<iledesc>ILE: un notificador de nuevo email - http://ile.jabberstudio.org</iledesc>
</es>
<ca>
<instructions>Ompli els camps del formulari.</instructions>
<title>ILE: Servei de notificació de nou email</title>
<email_options>Dades del compte de mail</email_options>
<user>Usuari</user>
<pass>Clau</pass>
<host>Host</host>
<type>Tipus</type>
<newmail>Ha rebut NUM email(s) des de la última comprobació que va ser fa CHECKINTERVAL minuts.</newmail>
<errorcheck>S'ha produit un error en la comprobació del correu per al compte ACCOUNT.</errorcheck>
<notify_options>Opcions de notificació</notify_options>
<notifyxa>Notificar si molt absent (XA)</notifyxa>
<notifydnd>Notificar si no molestar (DND)</notifydnd>
<webmail_url>Webmail URL</webmail_url>
<webmail_login>Llegir correu de ACCOUNT</webmail_login>
<iledesc>ILE: un notificador de nou email - http://ile.jabberstudio.org</iledesc>
</ca>
<ro>
<!-- Contributed by Adrian Rappa -->
<instructions>Va rog completati urmatoarele campuri</instructions>
<title>I Love Email: new email notification service</title>
<email_options>Email account settings</email_options>
<user>Nume utilizator</user>
<pass>Parola</pass>
<host>Nume gazda</host>
<type>Tip</type>
<newmail>Ati primit NUM mesaj(e) de la ultima verificare, care a fost acum CHECKINTERVAL minute.</newmail>
<errorcheck>A fost eroare in timp ce incercam sa verific posta pentru ACCOUNT.</errorcheck>
<notify_options>Notification Options</notify_options>
<notifyxa>Notify even when Xtended Away (XA)</notifyxa>
<notifydnd>Notify even when Do Not Disturb (DND)</notifydnd>
<webmail_url>Webmail URL</webmail_url>
<webmail_login>Login to ACCOUNT</webmail_login>
<iledesc>ILE: an email notifier component: http://ile.jabberstudio.org</iledesc>
</ro>
<nl>
<!-- Contributed by Sander Devrieze -->
<instructions>Vul volgende velden in.</instructions>
<title>ILE: Dienst voor e-mailnotificaties</title>
<email_options>Instellingen van e-mailaccount</email_options>
<user>Gebruikersnaam</user>
<pass>Wachtwoord</pass>
<host>Inkomende mailserver</host>
<type>Type verbinding</type>
<newmail>U hebt NUM berichten ontvangen sinds CHECKINTERVAL minuten geleden.</newmail>
<errorcheck>Fout tijdens controle op nieuwe e-mails bij ACCOUNT. ILE zal deze account niet meer opnieuw controleren tot u uw registratiegegevens wijzigt of opnieuw aanmeldt.</errorcheck>
<notify_options>Notificatie-instellingen</notify_options>
<notifyxa>Notificeer ook in de status Niet Beschikbaar (XA)</notifyxa>
<notifydnd>Notificeer ook in de status Niet Storen (DND)</notifydnd>
<webmail_url>URL van webmail</webmail_url>
<webmail_login>Aanmelden op ACCOUNT</webmail_login>
<iledesc>ILE: een dienst om e-mailnotificaties te ontvangen: http://ile.jabberstudio.org</iledesc>
</nl>
</form>
</config>
@@ -0,0 +1,149 @@
<jggtrans>
<service jid="gg.SERVER.COM"/>
<!-- This connects the jabber-gg-transport process to ejabberd. -->
<connect id="gglinker">
<ip>127.0.0.1</ip>
<port>5237</port>
<secret>SECRET</secret>
</connect>
<register>
<!-- This tag contains the message displayed to users at registration time.
You can use <p/> and/or <br/> to break lines. Multiple spaces and newlines
are converted to just one, so formatting of config file doesn't really matter. -->
<instructions>
Fill in your GG number (after "username")
and password to register on the transport.
<p/>To change your information in the GaduGadu directory you need to fill in the other fields.
<p/>To remove registration you need to leave the form blank.
</instructions>
</register>
<search>
<!-- This tag contains the message displayed to users at search time. -->
<instructions>
To search people:<br/>
First fill in surname or family name, nickname, city, birthyear or range of birthyears (eg. 1950-1960)
and gender (you may fill in more fields at once).<br/>
or<br/>
Fill in phone number<br/>
or<br/>
Fill in the GG number of the person you are searching.
</instructions>
</search>
<gateway>
<!-- This is message, that may be displayed to user when adding gg contact. -->
<desc>Please fill in the GaduGadu number of the person you want to add.</desc>
<!-- And this is the prompt for GG number. -->
<prompt>GG Nummer</prompt>
</gateway>
<vCard>
<FN>Gadu-Gadu Transport</FN>
<DESC>This is the Gadu-Gadu Transport.</DESC>
<EMAIL>EMAIL@ADDRESS.COM</EMAIL>
<URL>http://www.jabberstudio.org/projects/jabber-gg-transport/</URL>
</vCard>
<!-- Default user locale (language).
Empty means system locale setting,
no (or commented-out) <default_locale> tag means no translations. -->
<!-- <default_locale>pl_PL</default_locale> -->
<!-- Logger configuration.
You may configure one logger of type "syslog" and/or one of type "file".
You may also not configure logging at all. -->
<log type="syslog" facility="local0"/>
<log type="file">/var/log/jabber/jabber-gg-transport.log</log>
<!-- Uncomment this, if you want proxy to be used for Gadu-Gadu connection. -->
<!--
<proxy>
<ip>127.0.0.1</ip>
<port>8080</port>
</proxy>
-->
<!-- You can change these values according to your needs. -->
<conn_timeout>60</conn_timeout>
<ping_interval>10</ping_interval>
<!-- Gadu-Gadu server doesn't seem to answer pings anymore :-(
So let's give it 10 year :-) -->
<pong_timeout>315360000</pong_timeout>
<!-- This time after disconnection from Gadu-Gadu server the transport
will try to connect again. -->
<reconnect>300</reconnect>
<!-- How long to wait before restart, after jabber server connection is broken
negative value means, that jggtrans should terminate. -->
<restart_timeout>60</restart_timeout>
<!-- Delay between the unavailable presence is received from user and loggin out
from Gadu-Gadu - for nice <presence type="invisible"/> support. -->
<disconnect_delay>5</disconnect_delay>
<!-- list of Gadu-Gadu servers to use.
<hub/> means "use GG hub to find server"
<server/> tag should contain server address and may contain "port"
attribute with port number. When TLS is available (supported by libgadu)
it will be used unless "tls" attribute is set to "no". Please notice,
that not all servers will accept TLS connections.
Servers (including hub) are tried in order as they appear in <servers/>
element.
A reasonable default server list is hardcoded in jggtrans.
-->
<!--
<servers>
<hub/>
<server port="443">217.17.41.90</server>
<server tls="no">217.17.41.85</server>
<server tls="no">217.17.41.88</server>
</servers>
-->
<!-- Spool directory. This is the place, where user info will be stored. -->
<!-- Be careful about permissions - users' Gadu-Gadu passwords are stored there. -->
<spool>/var/spool/jabber/gg.SERVER.COM/</spool>
<!-- Where to store pid file. This tag is optional. -->
<pidfile>/var/run/jabber/jabber-gg-transport.pid</pidfile>
<!-- jid allowed to do some administrative task (eg. discovering online users).
May be used multiple times. -->
<admin>GG_TRANSPORT_ADMIN@SERVER.COM</admin>
<!-- ACL gives detailed access control to the transport. -->
<acl>
<!-- Example entries: -->
<allow who="admin@SERVER.COM" what="iq/query?xmlns=http://jabber.org/protocol/stats"/>
<!-- will allow statistics gathering to admin@SERVER.COM -->
<deny who="*" what="iq/query?xmlns=http://jabber.org/protocol/stats"/>
<!-- will deny statistics gathering for anybody else -->
<!-- <allow who="*@SERVER.COM"/> -->
<!-- will allow anything else to users from "SERVER.COM" -->
<!-- <deny what="iq/query?xmlns=jabber:x:register"/> -->
<!-- will deny registration for all other users -->
<!-- <allow what="presence"/> -->
<!-- allow presence from anybody -->
<!-- <allow what="iq"/> -->
<!-- allow iq from anybody -->
<!-- <allow what="message"/> -->
<!-- allow message from anybody -->
<!-- <deny/> -->
<!-- will deny anything else -->
</acl>
</jggtrans>
+128
View File
@@ -0,0 +1,128 @@
<!-- jit.xml -->
<jabber>
<!--
You need to add elogger and rlogger entries here when using ejabberd.
In this case the transport will do the logging.
-->
<log id='elogger'>
<host/>
<logtype/>
<file>/var/log/jabber/jit-error</file> <!-- WPJabber logs with date. -->
</log>
<log id='rlogger'>
<host/>
<logtype>record</logtype>
<file>/var/log/jabber/jit-record</file> <!-- WPJabber logs with date. -->
</log>
<!--
ejabberd do not provide XDB services.
xdb_file-jit.so (the renamed xdb_file.so from WPJabber) is
loaded in to handle all XDB requests.
Read also the documentation in xdb_file/README from the JIT package.
-->
<xdb id="xdb">
<host/>
<load>
<xdb_file>/usr/local/lib/jabber/xdb_file.so</xdb_file> <!-- The xdb_file.so from WPJabber/JIT. -->
</load>
<xdb_file xmlns="jabber:config:xdb_file">
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool>
</xdb_file>
</xdb>
<!--
Make sure that all host names here are resolveable via DNS if you
want the transport to be available to the public.
-->
<service id="icq.SERVER.COM">
<!--
Replace SERVER.COM with the same as above to enable sms.
-->
<host>sms.icq.SERVER.COM</host>
<!-- JIT configuration. -->
<icqtrans xmlns="jabber:config:icqtrans">
<sms>
<host>sms.icq.SERVER.COM</host>
<!-- Status of virtual "sms-contacts". -->
<show>away</show>
<status/>
</sms>
<instructions>Fill in your UIN and password.</instructions>
<search>Search ICQ users.</search>
<vCard>
<FN>ICQ Transport (JIT)</FN>
<DESC>This is the Jabber ICQ Transport.</DESC>
<MAIL>EMAIL@ADDRESS.COM</MAIL>
<URL>http://jit.jabberstudio.org/</URL>
</vCard>
<!-- Hashtable for users. -->
<prime>3907</prime>
<!-- Send messages from ICQ as chat to Jabber clients. -->
<chat/>
<!-- Enable this for ICQ web presence. -->
<web/>
<!--
If you don't want jabber:x:data forms
in reg and search uncomment this tag
(Not recomended).
-->
<no_xdata/>
<!--
This tag is necessary when using ejabberd.
In this way JIT will have its own contact list.
-->
<own_roster/>
<!--
When present, this tag will tell JIT not to try to
get the user's roster (which will take a bit of time
to fail in scenarios described above).
-->
<no_jabber_roster/>
<!-- File with stats. -->
<user_count_file>/var/spool/jabber/jit-count</user_count_file>
<!--
Interval beetween checking sessions: ping, messages, acks.
-->
<session_check>5</session_check>
<!-- Reconnect retries. -->
<reconnects>5</reconnects>
<!--
Time in sec when session can be inactive, 0=disabled.
-->
<session_timeout>18000</session_timeout>
<charset>windows-1252</charset>
<server>
<host port="5190">login.icq.com</host>
</server>
</icqtrans>
<!-- JIT module. -->
<load>
<icqtrans>/usr/local/lib/jabber/jit.so</icqtrans>
</load>
</service>
<!--
The settings below have to match the settings you made
in your ejabberd.cfg configuration file.
-->
<service id="icq-linker">
<host>SERVER.COM</host>
<uplink/>
<connect>
<ip>127.0.0.1</ip>
<port>5234</port>
<secret>SECRET</secret>
</connect>
</service>
<pidfile>/var/run/jabber/jit.pid</pidfile>
</jabber>
@@ -0,0 +1,118 @@
<!-- msn-transport.xml -->
<jabber>
<!--
You need to add elogger and rlogger entries here when using ejabberd.
In this case the transport will do the logging.
-->
<log id='elogger'>
<host/>
<logtype/>
<format>%d: [%t] (%h): %s</format>
<file>/var/log/jabber/msn-transport-error.log</file>
</log>
<log id='rlogger'>
<host/>
<logtype>record</logtype>
<format>%d %h %s</format>
<file>/var/log/jabber/msn-transport-record.log</file>
</log>
<!--
ejabberd do not provide XDB services.
xdb_file.so is loaded in to handle all XDB requests.
-->
<xdb id="xdb">
<host/>
<load>
<xdb_file>/usr/local/lib/jabber/libjabberdxdbfile.so</xdb_file>
</load>
<xdb_file xmlns="jabber:config:xdb_file">
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool>
</xdb_file>
</xdb>
<!--
Make sure that all host names here are resolveable via DNS if you
want the transport to be available to the public.
-->
<service id="msn.SERVER.COM">
<!-- msn-transport configuration. -->
<msntrans xmlns="jabber:config:msntrans">
<instructions>Fill in your MSN account and password (eg: user1@hotmail.com). A nickname is optional.</instructions>
<vCard>
<FN>MSN Transport</FN>
<DESC>This is the MSN Transport.</DESC>
<EMAIL>EMAIL@ADDRESS.COM</EMAIL>
<URL>http://msn-transport.jabberstudio.org/</URL>
</vCard>
<!--
Conference support allows you to create groupchat rooms on the
msn-transport and invite MSN users to join.
-->
<conference id="conference.msn.SERVER.COM">
<!--
This will make MSN transport invite you to a special groupchat
room when more then one user joins a normal one-on-one session.
Joining this room will make MSN transport "switch" the session
into groupchat mode. If you ignore it, MSN transport will
continue to send the messages as one-on-one chats.
-->
<invite>More than one user entered this chat session. Enter this room to switch to groupchat modus.</invite>
<notice>
<join> is available</join>
<leave> has leaved the room</leave>
</notice>
</conference>
<!-- Enable Hotmail inbox notification. -->
<headlines/>
<!--
Enable fancy friendly names
If the user enters a nickname upon registration, and the user has
a status message, their MSN friendly name will be "nickname - status message".
If the user does not enter a nickname on registration, but they do have
a status message, their friendly name will just be their status message.
If the user did enter a nickname on registration, but they have a blank status message,
then their friendly name will just be the registered nickname.
If the user did not enter a nickname on registration, and they have a blank status message,
their nickname will just be the username portion of their JID.
If the above chosen friendly name is too long, then it will be truncated and "..." placed
at the end. MSN only supports friendly names of 128 characters, so this is unavoidable.
If this is disabled, then the registered nick is always sent as the MSN friendly name,
or if that is blank, the username portion of their JID is sent instead.
-->
<fancy_friendly/>
</msntrans>
<!-- msn-transport module. -->
<load>
<msntrans>/usr/local/lib/jabber/msn-transport.so</msntrans>
</load>
</service>
<!--
The settings below have to match the settings you made
in your ejabberd.cfg configuration file.
-->
<service id="msn-linker">
<uplink/>
<connect>
<ip>127.0.0.1</ip>
<port>5235</port>
<secret>SECRET</secret>
</connect>
</service>
<pidfile>/var/run/jabber/msn-transport.pid</pidfile>
</jabber>
@@ -0,0 +1,86 @@
<!-- yahoo-transport-2.xml -->
<jabber>
<!--
You need to add the elogger entry here when using ejabberd.
In this case the transport will do the logging.
-->
<log id='elogger'>
<host/>
<logtype/>
<format>%d: [%t] (%h): %s</format>
<file>/var/log/jabber/yahoo-transport-2-error.log</file>
<stderr/>
</log>
<!--
ejabberd do not provide XDB services.
xdb_file.so is loaded in to handle all XDB requests.
-->
<xdb id="xdb">
<host/>
<load>
<xdb_file>/usr/local/lib/jabber/libjabberdxdbfile.so</xdb_file>
</load>
<xdb_file xmlns="jabber:config:xdb_file">
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool>
</xdb_file>
</xdb>
<!--
Make sure that all host names here are resolveable via DNS if you
want the transport to be available to the public.
-->
<service id="yahoo.SERVER.COM">
<!-- yahoo-transport-2 configuration. -->
<config xmlns="jabber:config:yahoo">
<vCard>
<NAME>Yahoo! Transport</NAME>
<FN>vCard not implemented in current version</FN>
<DESC>This is the Yahoo! transport.</DESC>
<MAIL>EMAIL@ADDRESS.COM</MAIL>
<URL>http://yahoo-transport-2.jabberstudio.org/</URL>
</vCard>
<instructions>Fill in your YAHOO! Messenger username and password to register on this transport.</instructions>
<server>scs.msg.yahoo.com</server>
<port>5050</port>
<!--
The character map. This provides character set translation from UTF-8
to the indicated character map. See the man page for 'iconv' for available
character maps on your platform. CP1252 is the standard Windows character
set.
-->
<charmap>CP1252</charmap>
<!--
When this element exists, the transport will send new mail notifications as
well as a count of unread messages when the user initially logs in.
-->
<newmail/>
</config>
<!-- yahoo-transport-2 module. -->
<load>
<yahoo_transport>/usr/local/lib/jabber/yahoo-transport-2.so</yahoo_transport>
</load>
</service>
<!--
The settings below have to match the settings you made
in your ejabberd.cfg configuration file.
-->
<service id="yahoo-linker">
<uplink/>
<connect>
<ip>127.0.0.1</ip>
<port>5236</port>
<secret>SECRET</secret>
</connect>
</service>
<pidfile>/var/run/jabber/yahoo-transport-2.pid</pidfile>
</jabber>
+45
View File
@@ -0,0 +1,45 @@
#!/bin/sh
#########################################################
#
# aim-transport -- script to start aim-transport.
#
#########################################################
DAEMON=/usr/local/sbin/jabberd-aim-transport
CONF=/etc/jabber/aim-transport.xml
NAME=jabberd-aim-transport
HOME=/etc/jabber/
USER=ejabberd
#########################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
debug)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in debugging mode."
$DAEMON -D -H $HOME -c $CONF &
;;
start)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME."
$DAEMON -H $HOME -c $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|restart}"
exit 1
esac
+43
View File
@@ -0,0 +1,43 @@
#!/bin/sh
#########################################################
#
# ile -- script to start ILE.
#
#########################################################
DAEMON=/usr/local/sbin/ile.pl
NAME=ile.pl
CONF=/etc/jabber/ile.xml
USER=ejabberd
#########################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
debug)
echo "Not implemented yet. Starting in normal mode"
$0 start
;;
start)
test -f $DAEMON || exit 0
echo "Starting $NAME."
$DAEMON $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|status|restart}"
exit 1
esac
@@ -0,0 +1,47 @@
#!/bin/sh
#########################################################
#
# jabber-gg-transport -- script to start jabber-gg-transport.
#
#########################################################
DAEMON=/usr/local/sbin/jggtrans
CONF=/etc/jabber/jabber-gg-transport.xml
NAME=jggtrans
HOME=/etc/jabber/
USER=ejabberd
#########################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
debug)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in debugging mode."
$DAEMON -D -H $HOME -c $CONF &
;;
start)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME."
$DAEMON $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
rm /var/run/jabber/jabber-gg-transport.pid
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|restart}"
exit 1
esac
+45
View File
@@ -0,0 +1,45 @@
#!/bin/sh
#########################################################
#
# jit -- script to start JIT.
#
#########################################################
DAEMON=/usr/local/sbin/wpjabber-jit
CONF=/etc/jabber/jit.xml
NAME=wpjabber-jit
HOME=/etc/jabber/
USER=ejabberd
#########################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
debug)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in debugging mode."
$DAEMON -D -H $HOME -c $CONF &
;;
start)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME."
$DAEMON -H $HOME -c $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|restart}"
exit 1
esac
+50
View File
@@ -0,0 +1,50 @@
#!/bin/sh
#########################################################
#
# msn-transport -- script to start MSN Transport.
#
#########################################################
DAEMON=/usr/local/sbin/jabberd-msn-transport
CONF=/etc/jabber/msn-transport.xml
NAME=jabberd-msn-transport
HOME=/etc/jabber/
USER=ejabberd
#########################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
strace)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in strace mode."
strace -o /opt/ejabberd/var/log/jabber/strace.log $DAEMON -H $HOME -c $CONF &
;;
debug)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in debugging mode."
$DAEMON -D -H $HOME -c $CONF &
;;
start)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME."
$DAEMON -H $HOME -c $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|restart}"
exit 1
esac
+45
View File
@@ -0,0 +1,45 @@
#!/bin/sh
##############################################################
#
# yahoo-transport-2 -- script to start Yahoo-transport-2.
#
#############################################################
DAEMON=/usr/local/sbin/jabberd-yahoo-transport-2
CONF=/etc/jabber/yahoo-transport-2.xml
NAME=jabberd-yahoo-transport-2
HOME=/etc/jabber/
USER=ejabberd
#############################################################
if [ "`/usr/bin/whoami`" != "$USER" ]; then
echo "You need to be" $USER "user to run this script."
exit 1
fi
case "$1" in
debug)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME in debugging mode."
$DAEMON -D -H $HOME -c $CONF &
;;
start)
test -f $DAEMON -a -f $CONF || exit 0
echo "Starting $NAME."
$DAEMON -H $HOME -c $CONF &
;;
stop)
echo "Stopping $NAME."
killall $NAME &
;;
restart|reload)
$0 stop
sleep 3
$0 start
;;
*)
echo "Usage: $0 {debug|start|stop|restart}"
exit 1
esac
+22 -98
View File
@@ -1,11 +1,15 @@
# $Id$
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
EXPAT_CFLAGS = @EXPAT_CFLAGS@
ERLANG_CFLAGS= @ERLANG_CFLAGS@
EXPAT_LIBS = @EXPAT_LIBS@
ERLANG_LIBS = @ERLANG_LIBS@
ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj
@@ -27,13 +31,14 @@ else
endif
EFLAGS += @ERLANG_SSLVER@ -pa .
ERLANG_CFLAGS += @ERLANG_SSLVER@
# make debug=true to compile Erlang module with debug informations.
ifdef debug
EFLAGS+=+debug_info +export_all
endif
DEBUGTOOLS = p1_prof.erl etop_tr.erl
DEBUGTOOLS = p1_prof.erl
ifdef debugtools
SOURCES+=$(DEBUGTOOLS)
endif
@@ -50,6 +55,11 @@ ifeq (@full_xml@, true)
EFLAGS+=-DFULL_XML_SUPPORT
endif
ifeq (@nif@, true)
EFLAGS+=-DNIF
ERLSHLIBS=xml.so
endif
ifeq (@transient_supervisors@, false)
EFLAGS+=-DNO_TRANSIENT_SUPERVISORS
endif
@@ -67,8 +77,8 @@ endif
prefix = @prefix@
exec_prefix = @exec_prefix@
SUBDIRS = stun @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ @tls@ @odbc@ @ejabberd_zlib@
ERLSHLIBS =
SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep stun @tls@ @odbc@ @ejabberd_zlib@
ERLSHLIBS += expat_erl.so
ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl
SOURCES_ALL = $(wildcard *.erl)
SOURCES_MISC = $(ERLBEHAVS) $(DEBUGTOOLS)
@@ -144,7 +154,7 @@ all-recursive: $(ERLBEHAVBEAMS)
all-recursive install-recursive uninstall-recursive \
clean-recursive distclean-recursive devdoc-recursive \
clean-recursive distclean-recursive \
mostlyclean-recursive maintainer-clean-recursive:
@subdirs="$(SUBDIRS)"; for subdir in $$subdirs; do \
target=`echo $@|sed 's,-recursive,,'`; \
@@ -160,13 +170,15 @@ mostlyclean-recursive maintainer-clean-recursive:
$(ERLSHLIBS): %.so: %.c
$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) \
$(subst ../,,$(subst .so,.c,$@)) \
$(EXPAT_LIBS) \
$(EXPAT_CFLAGS) \
$(ERLANG_LIBS) \
$(ERLANG_CFLAGS) \
-o $@ \
$(DYNAMIC_LIB_CFLAGS)
translations:
../tools/extract_translations/prepare-translation.sh -updateall
../contrib/extract_translations/prepare-translation.sh -updateall
install: all
#
@@ -249,11 +261,9 @@ install: all
#
# Documentation
install -d $(DOCDIR)
[ -f ../doc/guide.html ] \
&& install -m 644 ../doc/dev.html $(DOCDIR) \
&& install -m 644 ../doc/guide.html $(DOCDIR) \
&& install -m 644 ../doc/*.png $(DOCDIR) \
|| echo "No ../doc/guide.html was built"
install -m 644 ../doc/dev.html $(DOCDIR)
install -m 644 ../doc/guide.html $(DOCDIR)
install -m 644 ../doc/*.png $(DOCDIR)
install -m 644 ../doc/*.txt $(DOCDIR)
[ -f ../doc/guide.pdf ] \
&& install -m 644 ../doc/guide.pdf $(DOCDIR) \
@@ -285,7 +295,7 @@ uninstall-all: uninstall-binary
rm -rf $(CTLLOCKDIR)
rm -rf $(LOGDIR)
clean: clean-recursive clean-local clean-devdoc
clean: clean-recursive clean-local
clean-local:
rm -f *.beam $(ERLSHLIBS) epam ejabberdctl.example
@@ -295,6 +305,7 @@ distclean: distclean-recursive clean-local
rm -f config.status
rm -f config.log
rm -f Makefile
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
TAGS:
etags *.erl
@@ -303,90 +314,3 @@ Makefile: Makefile.in
dialyzer: $(BEAMS)
@dialyzer -c .
## Devdoc definitions
SRCDIR=.
DDTDIR=.
DEVDOCDIR=../doc/devdoc
DEVDOC_ERLS = $(wildcard ../doc/devdoc/*.erl)
DEVDOC_BEAMS = $(DEVDOC_ERLS:.erl=.beam)
APPNAME = ejabberd
VSN = $(shell sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ./ejabberd.app)
.PHONY = all
HTMLS = $(SOURCES:%.erl=../doc/devdoc/%.html)
ERLHTMLS = $(SOURCES:%.erl=../doc/devdoc/%.erl.html)
SVGS = $(SOURCES:%.erl=../doc/devdoc/%.svg)
EDOCINDEX = $(DEVDOCDIR)/index.html
## Devdoc rules
devdoc: compile-devdoc devdoc-root devdoc-recursive
$(devdoc-customize)
$(devdoc-move)
devdoc-root: $(EDOCINDEX) $(HTMLS) $(ERLHTMLS) $(SVGS)
define devdoc-customize
find $(DDTDIR) -type f -name '*.erl.html' -exec sed -i 's/<span class="attribute" >module<\/span>(\([A-Za-z0-9_]*\))/<span class="attribute" >module<\/span>(<a href="\1.html">\1<\/a>)/g;' {} \;
find $(DDTDIR) -type f -name '*.erl.html' -exec sed -i 's/arity="\([0-9]*\)" >\([A-Za-z0-9_]*\)</><a class="function" id="\2-\1" href="EDOCFILENAME#\2-\1">\2<\/a></g;' {} \;
find $(DDTDIR) -type f -name '*.erl.html' -exec sed -i 's/class="export" >\([A-Za-z0-9_]*\)\/\([0-9]*\)</class="export" ><a href="#\1-\2">\1\/\2<\/a></g;' {} \;
for fn in *.erl.html; do \
sed -i 's/EDOCFILENAME/'$${fn%.erl.html}.html'/g;' $${fn} ; \
sed = $${fn} | sed 'N;s/\n/ /;s/^\([0-9_]*\)/<a href="#\1" name="\1" class="l">\1<\/a>/' >$${fn}.tmp ; \
mv $${fn}.tmp $${fn} ; \
sed -i 's/<a href="#1" name="1" class="l">1<\/a> <html><link rel="stylesheet" type="text\/css"href="escobar.css"><\/link><body><pre><span class="comment" >/<html><link rel="stylesheet" type="text\/css" href="escobar.css"><\/link><body><pre><span class="comment" ><a href="#1" name="1" class="l">1<\/a> /g;' $${fn} ; \
done
-mv *.erl.html $(DEVDOCDIR)
find $(DDTDIR) -type f -name '*.html' -exec sed -i 's/<a href="overview-summary.html" target="overviewFrame">/<a href="index.html" target="_parent">/g;' {} \;
find $(DDTDIR) -type f -name '*.html' -exec sed -i 's/align=\"right\" border=\"0\" alt=\"erlang logo\"/alt=\"erlang logo\"><\/a><a href=\"http:\/\/www.ejabberd.im\/\"><img src=\"ejabberd-im.png\" alt=\"ejabberd Community\"><\/a><a href=\"http:\/\/www.process-one.net\/en\/ejabberd\/\"><img src=\"ejabberd-p1.png\" alt=\"ejabberd home\"><\/a><a href=\"http:\/\/www.process-one.net\/\"><img src=\"process-one.png\" alt=\"ProcessOne\"/g;' {} \;
find $(DDTDIR) -type f -name '*.html' -exec sed -i 's/^<h1>Module \([A-Za-z0-9_]*\)<\/h1>/<h1>Module \1 [<a href="\1.erl.html">erl<\/a> <a href="\1.svg">svg<\/a>]<\/h1>/g;' {} \;
find $(DDTDIR) -type f -name '*.html' -exec sed -i 's/class="function"><a name="\([A-Za-z0-9_]*\)-\([0-9_]*\)">/class="function"><a name="\1-\2" href="ESCOFILENAME#\1-\2">/g;' {} \;
-for fn in *.html; do sed -i 's/ESCOFILENAME/'$${fn%.html}.erl.html'/g;' $${fn} ; done
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="EXP\([A-Za-z0-9_]*\).html#\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="\1.html#\2-\3"/g;' {} \;
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="PRI\([A-Za-z0-9_]*\).html#\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="\1.html#\2-\3"/g;' {} \;
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="APP\([A-Za-z0-9_]*\):\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="\1.html#\2-\3"/g;' {} \;
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="EXM\([A-Za-z0-9_]*\):\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="http:\/\/www.process-one.net\/docs\/exmpp\/devdoc\/trunk\/\1.html#\2-\3"/g;' {} \;
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="OTP\([A-Za-z0-9_]*\):\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="http:\/\/www.erlang.org\/doc\/man\/\1.html#\2-\3"/g;' {} \;
find $(DDTDIR) -type f -name '*.svg' -exec sed -i 's/xlink:href="OTP\([A-Za-z0-9_]*\)\/\([0-9_]*\)"/xlink:href="http:\/\/www.erlang.org\/doc\/man\/erlang.html#\1-\2"/g;' {} \;
endef
define devdoc-move
-rm *.dot
-mv *.html $(DEVDOCDIR)
-mv *.svg $(DEVDOCDIR)
endef
compile-devdoc: $(DEVDOC_BEAMS)
[ ! -f funrelg.beam ] || mv funrelg.beam $(DEVDOCDIR)
[ ! -f escobar_hilite.beam ] || mv escobar_hilite.beam $(DEVDOCDIR)
[ ! -f escobar_run.beam ] || mv escobar_run.beam $(DEVDOCDIR)
$(EDOCINDEX):
@ERL@ -noshell -run edoc_run application "'$(APPNAME)'" '"$(SRCDIR)"' \
'[{dir,"$(DDTDIR)"},{packages,false},{todo,true},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"overview.edoc"}]' -s init stop
sed -i 's/<title>The ejabberd application<\/title>/<title>ejabberd devdoc<\/title><link rel="shortcut icon" href="favicon.ico" type="image\/x-icon"\/>/g;' $(DDTDIR)/index.html
mv edoc-info $(DEVDOCDIR)
mv *.png $(DEVDOCDIR)
cp *.html $(DEVDOCDIR)
@ERL@ -noshell -pa $(DEVDOCDIR) -run escobar_run dir $(SRCDIR) $(SRCDIR) -s init stop
@ERL@ -noshell -pa $(DEVDOCDIR) -run funrelg dir $(SRCDIR) $(SRCDIR) -s init stop
$(devdoc-customize)
$(devdoc-move)
$(DEVDOCDIR)/%.erl.html: %.erl
@ERL@ -noshell -pa $(DEVDOCDIR) -run escobar_run file $< $(SRCDIR) -s init stop
$(DEVDOCDIR)/%.html: %.erl
@ERL@ -noshell -run edoc_run file $< \
'[{dir,"$(DDTDIR)"},{packages,false},{todo,true},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"overview.edoc"}]' -s init stop
$(DEVDOCDIR)/%.svg: %.erl
@ERL@ -noshell -pa $(DEVDOCDIR) -run funrelg file $< $(SRCDIR) -s init stop
clean-devdoc:
rm -f $(DEVDOCDIR)/edoc-info
rm -f $(DEVDOCDIR)/erlang.png
rm -f $(DEVDOCDIR)/*.beam
rm -f $(DEVDOCDIR)/*.dot
rm -f $(DEVDOCDIR)/*.html
rm -f $(DEVDOCDIR)/*.svg
+16 -7
View File
@@ -52,6 +52,9 @@ release : build release_clean
mkdir $(SRC_DIR)\eldap
copy eldap\eldap.* $(SRC_DIR)\eldap
copy eldap\ELDAPv3.asn $(SRC_DIR)\eldap
mkdir $(SRC_DIR)\mod_irc
copy mod_irc\*.erl $(SRC_DIR)\mod_irc
copy mod_irc\*.c $(SRC_DIR)\mod_irc
mkdir $(SRC_DIR)\mod_muc
copy mod_muc\*.erl $(SRC_DIR)\mod_muc
mkdir $(SRC_DIR)\mod_pubsub
@@ -82,15 +85,17 @@ release : build release_clean
copy ..\doc\*.html $(DOC_DIR)
copy ..\doc\*.png $(DOC_DIR)
SOURCE =
OBJECT =
DLL =
SOURCE = expat_erl.c
OBJECT = expat_erl.o
DLL = expat_erl.dll
build : $(DLL) compile-beam all-recursive
all-recursive :
cd eldap
nmake -nologo -f Makefile.win32
cd ..\mod_irc
nmake -nologo -f Makefile.win32
cd ..\mod_muc
nmake -nologo -f Makefile.win32
cd ..\mod_pubsub
@@ -122,6 +127,8 @@ CLEAN : clean-recursive clean-local
clean-local :
-@erase $(OBJECT)
-@erase $(DLL)
-@erase expat_erl.exp
-@erase expat_erl.lib
-@erase *.beam
-@erase XmppAddr.asn1db
-@erase XmppAddr.erl
@@ -130,6 +137,8 @@ clean-local :
clean-recursive :
cd eldap
nmake -nologo -f Makefile.win32 clean
cd ..\mod_irc
nmake -nologo -f Makefile.win32 clean
cd ..\mod_muc
nmake -nologo -f Makefile.win32 clean
cd ..\mod_pubsub
@@ -155,13 +164,13 @@ distclean : release_clean clean
-@erase Makefile.inc
CC=cl.exe
CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include"
CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT $(EXPAT_FLAG) -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include" -I"$(EXPAT_DIR)\source\lib"
LD=link.exe
LD_FLAGS=-release -nologo -incremental:no -dll "$(EI_DIR)\lib\ei_md.lib" "$(EI_DIR)\lib\erl_interface_md.lib" MSVCRT.LIB kernel32.lib advapi32.lib gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib
LD_FLAGS=-release -nologo -incremental:no -dll "$(EI_DIR)\lib\ei_md.lib" "$(EI_DIR)\lib\erl_interface_md.lib" "$(EXPAT_LIB)" MSVCRT.LIB kernel32.lib advapi32.lib gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib
$(DLL) : $(OBJECT)
$(LD) $(LD_FLAGS) -out:$(DLL) $(OBJECT)
$(LD) $(LD_FLAGS) -out:$@ $<
$(OBJECT) : $(SOURCE)
$(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE)
$(CC) $(CC_FLAGS) -c -Fo$@ $<
+125 -10
View File
@@ -1,3 +1,37 @@
AC_DEFUN([AM_WITH_EXPAT],
[ AC_ARG_WITH(expat,
[AC_HELP_STRING([--with-expat=PREFIX], [prefix where EXPAT is installed])])
EXPAT_CFLAGS=
EXPAT_LIBS=
if test x"$with_expat" != x; then
EXPAT_CFLAGS="-I$with_expat/include"
EXPAT_LIBS="-L$with_expat/lib"
fi
AC_CHECK_LIB(expat, XML_ParserCreate,
[ EXPAT_LIBS="$EXPAT_LIBS -lexpat"
expat_found=yes ],
[ expat_found=no ],
"$EXPAT_LIBS")
if test $expat_found = no; then
AC_MSG_ERROR([Could not find development files of Expat library])
fi
expat_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $EXPAT_CFLAGS"
expat_save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $EXPAT_CFLAGS"
AC_CHECK_HEADERS(expat.h, , expat_found=no)
if test $expat_found = no; then
AC_MSG_ERROR([Could not find expat.h])
fi
CFLAGS="$expat_save_CFLAGS"
CPPFLAGS="$expat_save_CPPFLAGS"
AC_SUBST(EXPAT_CFLAGS)
AC_SUBST(EXPAT_LIBS)
])
AC_DEFUN([AM_WITH_ZLIB],
[ AC_ARG_WITH(zlib,
[AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
@@ -91,14 +125,8 @@ AC_DEFUN([AM_WITH_ERLANG],
start() ->
EIDirS = code:lib_dir("erl_interface") ++ "\n",
EILibS = libpath("erl_interface") ++ "\n",
EXMPPDir = code:lib_dir("exmpp"),
case EXMPPDir of
{error, bad_name} -> exit("exmpp not found");
_ -> ok
end,
EXMPPDirS = EXMPPDir ++ "\n",
RootDirS = code:root_dir() ++ "\n",
file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ EXMPPDirS ++ RootDirS)),
file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ RootDirS)),
halt().
ssldef() ->
@@ -158,8 +186,6 @@ _EOF
ERLANG_EI_LIB=`cat conftest.out | head -n 2 | tail -n 1`
# Third line
ERLANG_SSLVER=`cat conftest.out | head -n 3 | tail -n 1`
# Fourth line
ERLANG_EXMPP=`cat conftest.out | head -n 4 | tail -n 1`
# End line
ERLANG_DIR=`cat conftest.out | tail -n 1`
@@ -169,7 +195,6 @@ _EOF
AC_SUBST(ERLANG_CFLAGS)
AC_SUBST(ERLANG_LIBS)
AC_SUBST(ERLANG_SSLVER)
AC_SUBST(ERLANG_EXMPP)
AC_SUBST(ERLC)
AC_SUBST(ERL)
])
@@ -193,6 +218,96 @@ AC_SUBST(make_$1)
])
dnl From Bruno Haible.
AC_DEFUN([AM_ICONV],
[
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
dnl those with the standalone portable GNU libiconv installed).
AC_ARG_WITH([libiconv-prefix],
[AC_HELP_STRING([--with-libiconv-prefix=PREFIX], [prefix where libiconv is installed])], [
for dir in `echo "$withval" | tr : ' '`; do
if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
if test -d $dir/include; then CFLAGS="$CFLAGS -I$dir/include"; fi
if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
done
])
AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
am_cv_func_iconv="no, consider installing GNU libiconv"
am_cv_lib_iconv=no
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_func_iconv=yes)
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
LIBS="$LIBS -liconv"
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_lib_iconv=yes
am_cv_func_iconv=yes)
LIBS="$am_save_LIBS"
fi
dnl trying /usr/local
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
am_save_CFLAGS="$CFLAGS"
am_save_LDFLAGS="$LDFLAGS"
LIBS="$LIBS -liconv"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
CFLAGS="$CFLAGS -I/usr/local/include"
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_lib_iconv=yes
am_cv_func_iconv=yes
CPPFLAGS="$CPPFLAGS -I/usr/local/include",
LDFLAGS="$am_save_LDFLAGS"
CFLAGS="$am_save_CFLAGS")
LIBS="$am_save_LIBS"
fi
])
if test "$am_cv_func_iconv" = yes; then
AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL(am_cv_proto_iconv, [
AC_TRY_COMPILE([
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([$]{ac_t:-
}[$]am_cv_proto_iconv)
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
[Define as const if the declaration of iconv() needs const.])
fi
LIBICONV=
if test "$am_cv_lib_iconv" = yes; then
LIBICONV="-liconv"
fi
AC_SUBST(LIBICONV)
])
dnl <openssl>
AC_DEFUN([AM_WITH_OPENSSL],
[ AC_ARG_WITH(openssl,
+30 -120
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -32,45 +32,13 @@
add/3,
add_list/3,
match_rule/3,
for_host/1,
% for debugging only
match_acl/3]).
-include("ejabberd.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
%% @type aclspec() = all | JID_Exact | JID_Regexp | JID_Glob | Shared_Group
%% JID_Exact = {user, U} | {user, U, S} | {server, S} | {resource, R}
%% U = string()
%% S = string()
%% R = string()
%% JID_Regexp = {user_regexp, UR} | {user_regexp, UR, S} | {server_regexp, SR} | {resource_regexp, RR} | {node_regexp, UR, SR}
%% UR = string()
%% SR = string()
%% RR = string()
%% JID_Glob = {user_glob, UG} | {user_glob, UG, S} | {server_glob, SG} | {resource_glob, RG} | {node_glob, UG, SG}
%% UG = string()
%% SG = string()
%% RG = string()
%% Shared_Group = {shared_group, G} | {shared_group, G, H}
%% G = string()
%% H = string().
%% @type acl() = {acl, ACLName, ACLSpec}
%% ACLName = atom()
%% ACLSpec = aclspec().
%% Record in its Ejabberd-configuration-file variant.
%% @type storedacl() = {acl, {ACLName, Host}, ACLSpec}
%% ACLName = atom()
%% Host = global | string()
%% ACLSpec = aclspec().
%% Record in its Mnesia-table-record variant.
-record(acl, {aclname, aclspec}).
%% @spec () -> ok
start() ->
mnesia:create_table(acl,
[{disc_copies, [node()]},
@@ -79,20 +47,9 @@ start() ->
mnesia:add_table_copy(acl, node(), ram_copies),
ok.
%% @spec (Host, ACLName, ACLSpec) -> storedacl()
%% Host = global | string()
%% ACLName = atom()
%% ACLSpec = aclspec()
to_record(Host, ACLName, ACLSpec) ->
#acl{aclname = {ACLName, Host}, aclspec = normalize_spec(ACLSpec)}.
%% @spec (Host, ACLName, ACLSpec) -> {atomic, ok} | {aborted, Reason}
%% Host = global | string()
%% ACLName = atom()
%% ACLSpec = all | none | aclspec()
%% Reason = term()
add(Host, ACLName, ACLSpec) ->
F = fun() ->
mnesia:write(#acl{aclname = {ACLName, Host},
@@ -100,11 +57,6 @@ add(Host, ACLName, ACLSpec) ->
end,
mnesia:transaction(F).
%% @spec (Host, ACLs, Clear) -> ok | false
%% Host = global | string()
%% ACLs = [acl()]
%% Clear = bool()
add_list(Host, ACLs, Clear) ->
F = fun() ->
if
@@ -134,17 +86,8 @@ add_list(Host, ACLs, Clear) ->
false
end.
%% @spec (String) -> Prepd_String
%% String = string()
%% Prepd_String = string()
normalize(String) ->
exmpp_stringprep:nodeprep(String).
%% @spec (ACLSpec) -> Normalized_ACLSpec
%% ACLSpec = all | none | aclspec()
%% Normalized_ACLSpec = aclspec()
normalize(A) ->
jlib:nodeprep(A).
normalize_spec({A, B}) ->
{A, normalize(B)};
normalize_spec({A, B, C}) ->
@@ -156,12 +99,6 @@ normalize_spec(none) ->
%% @spec (Host, Rule, JID) -> Access
%% Host = global | string()
%% Rule = all | none | atom()
%% JID = exmpp_jid:jid()
%% Access = allow | deny | atom()
match_rule(global, Rule, JID) ->
case Rule of
all -> allow;
@@ -206,37 +143,23 @@ match_rule(Host, Rule, JID) ->
end
end.
%% @spec (ACLs, JID, Host) -> Access
%% ACLs = [{Access, ACLName}]
%% Access = deny | atom()
%% ACLName = atom()
%% JID = exmpp_jid:jid()
%% Host = string()
match_acls([], _, _Host) ->
deny;
match_acls([{Access, ACLName} | ACLs], JID, Host) ->
case match_acl(ACLName, JID, Host) of
match_acls([{Access, ACL} | ACLs], JID, Host) ->
case match_acl(ACL, JID, Host) of
true ->
Access;
_ ->
match_acls(ACLs, JID, Host)
end.
%% @spec (ACLName, JID, Host) -> bool()
%% ACLName = all | none | atom()
%% JID = exmpp_jid:jid()
%% Host = string()
match_acl(ACLName, JID, Host) ->
case ACLName of
match_acl(ACL, JID, Host) ->
case ACL of
all -> true;
none -> false;
_ ->
User = exmpp_jid:prep_node_as_list(JID),
Server = exmpp_jid:prep_domain_as_list(JID),
Resource = exmpp_jid:prep_resource_as_list(JID),
lists:any(fun(#acl{aclname=Name, aclspec = Spec}) ->
{User, Server, Resource} = jlib:jid_tolower(JID),
lists:any(fun(#acl{aclspec = Spec}) ->
case Spec of
all ->
true;
@@ -245,26 +168,24 @@ match_acl(ACLName, JID, Host) ->
andalso
((Host == Server) orelse
((Host == global) andalso
?IS_MY_HOST(Server)));
lists:member(Server, ?MYHOSTS)));
{user, U, S} ->
(U == User) andalso (S == Server);
{server, S} ->
S == Server;
{resource, R} ->
R == Resource;
{user_regexp, UR} when is_tuple(Name),
element(2, Name) =:= global ->
?IS_MY_HOST(Server)
andalso is_regexp_match(User, UR);
{user_regexp, UR} ->
((Host == Server) orelse
((Host == global) andalso
?IS_MY_HOST(Server)))
lists:member(Server, ?MYHOSTS)))
andalso is_regexp_match(User, UR);
{shared_group, G} ->
mod_shared_roster:is_user_in_group({User, Server}, G, Host);
Mod = loaded_shared_roster_module(Host),
Mod:is_user_in_group({User, Server}, G, Host);
{shared_group, G, H} ->
mod_shared_roster:is_user_in_group({User, Server}, G, H);
Mod = loaded_shared_roster_module(H),
Mod:is_user_in_group({User, Server}, G, H);
{user_regexp, UR, S} ->
(S == Server) andalso
is_regexp_match(User, UR);
@@ -278,7 +199,7 @@ match_acl(ACLName, JID, Host) ->
{user_glob, UR} ->
((Host == Server) orelse
((Host == global) andalso
?IS_MY_HOST(Server)))
lists:member(Server, ?MYHOSTS)))
andalso
is_glob_match(User, UR);
{user_glob, UR, S} ->
@@ -299,41 +220,30 @@ match_acl(ACLName, JID, Host) ->
false
end
end,
ets:lookup(acl, {ACLName, global}) ++
ets:lookup(acl, {ACLName, Host}))
ets:lookup(acl, {ACL, global}) ++
ets:lookup(acl, {ACL, Host}))
end.
%% @spec (String, RegExp) -> bool()
%% String = string() | undefined
%% RegExp = string()
is_regexp_match(undefined, _RegExp) ->
false;
is_regexp_match(String, RegExp) ->
try re:run(String, RegExp, [{capture, none}]) of
case ejabberd_regexp:run(String, RegExp) of
nomatch ->
false;
match ->
true
catch
_:ErrDesc ->
true;
{error, ErrDesc} ->
?ERROR_MSG(
"Wrong regexp ~p in ACL:~n~p",
"Wrong regexp ~p in ACL: ~p",
[RegExp, ErrDesc]),
false
end.
%% @spec (String, Glob) -> bool()
%% String = string() | undefined
%% Glob = string()
is_glob_match(String, Glob) ->
is_regexp_match(String, xmerl_regexp:sh_to_awk(Glob)).
is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)).
for_host(Host) ->
mnesia:select(acl,
ets:fun2ms(fun (#acl{aclname = {_ACLName, H}})
when H =:= Host ->
object()
end)).
loaded_shared_roster_module(Host) ->
case {gen_mod:is_loaded(Host, mod_shared_roster_odbc),
gen_mod:is_loaded(Host, mod_shared_roster_ldap)} of
{true, _} -> mod_shared_roster_odbc;
{_, true} -> mod_shared_roster_ldap;
_ -> mod_shared_roster
end.
+43 -46
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -31,52 +31,48 @@
produce_response/2,
produce_response/1]).
-include_lib("exmpp/include/exmpp.hrl").
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("adhoc.hrl").
%% Parse an ad-hoc request. Return either an adhoc_request record or
%% an {error, ErrorType} tuple.
parse_request(#iq{type = Type, ns = NS, payload = SubEl, lang = Lang}) ->
try
case {Type, NS} of
{set, ?NS_ADHOC} ->
?DEBUG("entering parse_request...", []),
Node = exmpp_xml:get_attribute_as_list(SubEl, <<"node">>, ""),
SessionID = exmpp_xml:get_attribute_as_list(SubEl, <<"sessionid">>, ""),
Action = exmpp_xml:get_attribute_as_list(SubEl, <<"action">>, ""),
XData = find_xdata_el(SubEl),
AllEls = exmpp_xml:get_child_elements(SubEl),
Others = case XData of
false ->
AllEls;
_ ->
lists:delete(XData, AllEls)
end,
#adhoc_request{lang = Lang,
node = Node,
sessionid = SessionID,
action = Action,
xdata = XData,
others = Others};
_ ->
{error, 'bad-request'}
end
catch
parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) ->
?DEBUG("entering parse_request...", []),
Node = xml:get_tag_attr_s("node", SubEl),
SessionID = xml:get_tag_attr_s("sessionid", SubEl),
Action = xml:get_tag_attr_s("action", SubEl),
XData = find_xdata_el(SubEl),
{xmlelement, _, _, AllEls} = SubEl,
Others = case XData of
false ->
AllEls;
_ ->
{error, 'bad-request'}
end.
lists:delete(XData, AllEls)
end,
#adhoc_request{lang = Lang,
node = Node,
sessionid = SessionID,
action = Action,
xdata = XData,
others = Others};
parse_request(_) ->
{error, ?ERR_BAD_REQUEST}.
%% Borrowed from mod_vcard.erl
find_xdata_el(#xmlel{children = SubEls}) ->
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
find_xdata_el1(SubEls).
find_xdata_el1([]) ->
false;
find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) ->
El;
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_XDATA ->
{xmlelement, Name, Attrs, SubEls};
_ ->
find_xdata_el1(Els)
end;
find_xdata_el1([_ | Els]) ->
find_xdata_el1(Els).
@@ -114,19 +110,20 @@ produce_response(#adhoc_response{lang = _Lang,
"" ->
ActionsElAttrs = [];
_ ->
ActionsElAttrs = [?XMLATTR(<<"execute">>, DefaultAction)]
ActionsElAttrs = [{"execute", DefaultAction}]
end,
ActionsEls = [#xmlel{ns = ?NS_ADHOC, name = 'actions', attrs =
ActionsElAttrs, children =
[#xmlel{ns = ?NS_ADHOC, name = Action} || Action <- Actions]}]
ActionsEls = [{xmlelement, "actions",
ActionsElAttrs,
[{xmlelement, Action, [], []} || Action <- Actions]}]
end,
NotesEls = lists:map(fun({Type, Text}) ->
#xmlel{ns = ?NS_ADHOC, name = 'note', attrs =
[?XMLATTR(<<"type">>, Type)],
children = [#xmlcdata{cdata = list_to_binary(Text)}]}
{xmlelement, "note",
[{"type", Type}],
[{xmlcdata, Text}]}
end, Notes),
#xmlel{ns = ?NS_ADHOC, name = 'command', attrs =
[?XMLATTR(<<"sessionid">>, SessionID),
?XMLATTR(<<"node">>, Node),
?XMLATTR(<<"status">>, Status)], children =
{xmlelement, "command",
[{"xmlns", ?NS_COMMANDS},
{"sessionid", SessionID},
{"node", Node},
{"status", atom_to_list(Status)}],
ActionsEls ++ NotesEls ++ Elements}.
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+9 -4
View File
@@ -6,7 +6,7 @@
%%% Created : 29 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -70,8 +70,8 @@
%% API
%%====================================================================
start_link(Proc, Tab, Opts, Owner) ->
?GEN_SERVER:start_link({local, Proc}, ?MODULE,
[Tab, Opts, get_proc_num(), Owner], []).
?GEN_SERVER:start_link(
{local, Proc}, ?MODULE, [Tab, Opts, get_proc_num(), Owner], []).
new(Tab, Opts) ->
Res = lists:flatmap(
@@ -380,7 +380,12 @@ do_setopts(#state{procs_num = N} = State, Opts) ->
shrink_size = ShrinkSize}.
get_proc_num() ->
erlang:system_info(logical_processors).
case erlang:system_info(logical_processors) of
unknown ->
1;
Num ->
Num
end.
get_proc_by_hash(Tab, Term) ->
N = erlang:phash2(Term, get_proc_num()) + 1,
+1 -1
View File
@@ -6,7 +6,7 @@
%%% Created : 30 Aug 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
Vendored Executable
+6317
View File
File diff suppressed because it is too large Load Diff
+16 -9
View File
@@ -14,6 +14,10 @@ fi
#locating erlang
AM_WITH_ERLANG
#locating iconv
AM_ICONV
#locating libexpat
AM_WITH_EXPAT
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -28,6 +32,7 @@ AC_PREFIX_DEFAULT(/)
AC_FUNC_MALLOC
AC_HEADER_STDC
AC_MOD_ENABLE(mod_irc, yes)
AC_MOD_ENABLE(mod_muc, yes)
AC_MOD_ENABLE(mod_proxy65, yes)
AC_MOD_ENABLE(mod_pubsub, yes)
@@ -89,13 +94,24 @@ AC_ARG_ENABLE(full_xml,
esac],[full_xml=false])
AC_SUBST(full_xml)
AC_ARG_ENABLE(nif,
[AC_HELP_STRING([--enable-nif], [replace some functions with C equivalents. Requires Erlang R13B04 or higher (default: no)])],
[case "${enableval}" in
yes) nif=true ;;
no) nif=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-nif) ;;
esac],[nif=false])
AC_SUBST(nif)
AC_CONFIG_FILES([Makefile
$make_mod_irc
$make_mod_muc
$make_mod_pubsub
$make_mod_proxy65
$make_eldap
$make_pam
$make_web
stringprep/Makefile
stun/Makefile
$make_tls
$make_odbc
@@ -163,12 +179,3 @@ LD_SHARED="$LD_SHARED $CBIT"
echo "CBIT is set to '$CBIT'"
AC_OUTPUT
echo
echo "********************** WARNING ! ************************"
echo "* ejabberd master is NOT ready for real usage yet, *"
echo "* because it is still in heavy development. *"
echo "* Don't use ejabberd master, it is still alpha code! *"
echo "* Please use ejabberd 2.1.x branch instead. *"
echo "*********************************************************"
echo
+15 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -42,9 +42,17 @@ start() ->
end,
case Static of
true ->
ExpatLib = "EXPAT_LIB = $(EXPAT_DIR)\\StaticLibs\\libexpatMT.lib\n",
ExpatFlag = "EXPAT_FLAG = -DXML_STATIC\n",
IconvDir = "ICONV_DIR = c:\\sdk\\GnuWin32\n",
IconvLib = "ICONV_LIB = $(ICONV_DIR)\\lib\\libiconv.lib\n",
ZlibDir = "ZLIB_DIR = c:\\sdk\\GnuWin32\n",
ZlibLib = "ZLIB_LIB = $(ZLIB_DIR)\\lib\\zlib.lib\n";
false ->
ExpatLib = "EXPAT_LIB = $(EXPAT_DIR)\\Libs\\libexpat.lib\n",
ExpatFlag = "",
IconvDir = "ICONV_DIR = c:\\sdk\\GnuWin32\n",
IconvLib = "ICONV_LIB = $(ICONV_DIR)\\lib\\libiconv.lib\n",
ZlibDir = "ZLIB_DIR = c:\\sdk\\GnuWin32\n",
ZlibLib = "ZLIB_LIB = $(ZLIB_DIR)\\lib\\zlib.lib\n"
end,
@@ -55,6 +63,7 @@ start() ->
%% Load the ejabberd application description so that ?VERSION can read the vsn key
application:load(ejabberd),
Version = "EJABBERD_VERSION = " ++ ?VERSION ++ "\n",
ExpatDir = "EXPAT_DIR = c:\\sdk\\Expat-2.0.0\n",
OpenSSLDir = "OPENSSL_DIR = c:\\sdk\\OpenSSL\n",
DBType = "DBTYPE = generic\n", %% 'generic' or 'mssql'
@@ -70,6 +79,11 @@ start() ->
StdLibDir ++
OpenSSLDir ++
DBType ++
ExpatDir ++
ExpatLib ++
ExpatFlag ++
IconvDir ++
IconvLib ++
ZlibDir ++
ZlibLib)),
halt().
+75 -169
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,217 +30,123 @@
-export([start/0,
register_mechanism/3,
listmech/1,
server_new/8,
server_new/7,
server_start/3,
server_step/2]).
-include("cyrsasl.hrl").
-include("ejabberd.hrl").
%% @type saslmechanism() = {sasl_mechanism, Mechanism, Module, Require_Plain}
%% Mechanism = string()
%% Module = atom()
%% Require_Plain = bool().
%% Registry entry of a supported SASL mechanism.
-record(sasl_mechanism, {mechanism, module, require_plain_password}).
%% @type saslstate() = {sasl_state, Service, Myname, Realm, GetPassword, CheckPassword, CheckPasswordDigest, Mech_Mod, Mech_State}
%% Service = string()
%% Myname = string()
%% Realm = string()
%% GetPassword = function()
%% CheckPassword = function()
%% CheckPasswordDigest = any()
%% Mech_Mod = atom()
%% Mech_State = term().
%% State of this process.
-record(sasl_state, {service, myname,
mech_mod, mech_state, params}).
-record(sasl_mechanism, {mechanism, module, password_type}).
-record(sasl_state, {service, myname, realm,
get_password, check_password, check_password_digest,
mech_mod, mech_state}).
-export([behaviour_info/1]).
%% @hidden
behaviour_info(callbacks) ->
[{mech_new, 1}, {mech_step, 2}];
[{mech_new, 4}, {mech_step, 2}];
behaviour_info(_Other) ->
undefined.
%% @spec () -> ok
start() ->
ets:new(sasl_mechanism, [named_table,
public,
{keypos, #sasl_mechanism.mechanism}]),
cyrsasl_plain:start([]),
cyrsasl_digest:start([]),
cyrsasl_scram:start([]),
cyrsasl_anonymous:start([]),
maybe_try_start_gssapi(),
ok.
maybe_try_start_gssapi() ->
case os:getenv("KRB5_KTNAME") of
false ->
ok;
_String ->
try_start_gssapi()
end.
try_start_gssapi() ->
case code:load_file(esasl) of
{module, _Module} ->
cyrsasl_gssapi:start([]);
{error, What} ->
?ERROR_MSG("Support for GSSAPI not started because esasl.beam was not found: ~p", [What])
end.
%% @spec (Mechanism, Module, Require_Plain) -> true
%% Mechanism = string()
%% Module = atom()
%% Require_Plain = bool()
register_mechanism(Mechanism, Module, RequirePlainPassword) ->
register_mechanism(Mechanism, Module, PasswordType) ->
ets:insert(sasl_mechanism,
#sasl_mechanism{mechanism = Mechanism,
module = Module,
require_plain_password = RequirePlainPassword}).
password_type = PasswordType}).
% TODO use callbacks
%-include("ejabberd.hrl").
%-include("jlib.hrl").
%check_authzid(_State, Props) ->
% AuthzId = xml:get_attr_s(authzid, Props),
% case jlib:string_to_jid(AuthzId) of
% error ->
% {error, "invalid-authzid"};
% JID ->
% LUser = jlib:nodeprep(xml:get_attr_s(username, Props)),
% {U, S, R} = jlib:short_prepd_jid(JID),
% case R of
% "" ->
% {error, "invalid-authzid"};
% _ ->
% case {LUser, ?MYNAME} of
% {U, S} ->
% ok;
% _ ->
% {error, "invalid-authzid"}
% end
% end
% end.
%% @spec (State, Props) -> ok | {error, 'not-authorized'}
%% State = saslstate()
%% Props = [{Key, Value}]
%% Key = atom()
%% Value = string()
%%% TODO: use callbacks
%%-include("ejabberd.hrl").
%%-include("jlib.hrl").
%%check_authzid(_State, Props) ->
%% AuthzId = xml:get_attr_s(authzid, Props),
%% case jlib:string_to_jid(AuthzId) of
%% error ->
%% {error, "invalid-authzid"};
%% JID ->
%% LUser = jlib:nodeprep(xml:get_attr_s(username, Props)),
%% {U, S, R} = jlib:jid_tolower(JID),
%% case R of
%% "" ->
%% {error, "invalid-authzid"};
%% _ ->
%% case {LUser, ?MYNAME} of
%% {U, S} ->
%% ok;
%% _ ->
%% {error, "invalid-authzid"}
%% end
%% end
%% end.
check_credentials(_State, Props) ->
case proplists:get_value(username, Props) of
undefined ->
{error, 'not-authorized'};
User ->
case exmpp_stringprep:is_node(User) of
false -> {error, 'not-authorized'};
true -> ok
end
User = xml:get_attr_s(username, Props),
case jlib:nodeprep(User) of
error ->
{error, "not-authorized"};
"" ->
{error, "not-authorized"};
_LUser ->
ok
end.
%% @spec (Host) -> [Mechanism]
%% Host = string()
%% Mechanism = string()
listmech(Host) ->
RequirePlainPassword = ejabberd_auth:plain_password_required(Host),
Mechs = ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1',
require_plain_password = '$2',
password_type = '$2',
_ = '_'},
if
RequirePlainPassword ->
[{'==', '$2', false}];
true ->
[]
case catch ejabberd_auth:store_type(Host) of
external ->
[{'==', '$2', plain}];
scram ->
[{'/=', '$2', digest}];
{'EXIT',{undef,[{Module,store_type,[]} | _]}} ->
?WARNING_MSG("~p doesn't implement the function store_type/0", [Module]),
[];
_Else ->
[]
end,
['$1']}]),
filter_anonymous(Host, Mechs).
%% @spec (Service, ServerFQDN, UserRealm, SecFlags, GetPassword, CheckPassword, CheckPasswordDigest, Socket) -> saslstate()
%% Service = string()
%% ServerFQDN = string()
%% UserRealm = string()
%% SecFlags = [term()]
%% GetPassword = function()
%% CheckPassword = function()
server_new(Service, ServerFQDN, UserRealm, _SecFlags,
GetPassword, CheckPassword, CheckPasswordDigest, Socket) ->
Params = #sasl_params{
host = ServerFQDN,
realm = UserRealm,
get_password = GetPassword,
check_password = CheckPassword,
check_password_digest= CheckPasswordDigest,
socket = Socket
},
GetPassword, CheckPassword, CheckPasswordDigest) ->
#sasl_state{service = Service,
myname = ServerFQDN,
params = Params}.
%% @spec (State, Mech, ClientIn) -> Ok | Continue | Error
%% State = saslstate()
%% Mech = string()
%% ClientIn = string()
%% Ok = {ok, Props}
%% Props = [Prop]
%% Prop = [{Key, Value}]
%% Key = atom()
%% Value = string()
%% Continue = {continue, ServerOut, New_State}
%% ServerOut = string()
%% New_State = saslstate()
%% Error = {error, Reason} | {error, Reason, Username}
%% Reason = term()
%% Username = string()
realm = UserRealm,
get_password = GetPassword,
check_password = CheckPassword,
check_password_digest= CheckPasswordDigest}.
server_start(State, Mech, ClientIn) ->
case lists:member(Mech, listmech(State#sasl_state.myname)) of
true ->
case ets:lookup(sasl_mechanism, Mech) of
[#sasl_mechanism{module = Module}] ->
{ok, MechState} =
Module:mech_new(State#sasl_state.params),
{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),
server_step(State#sasl_state{mech_mod = Module,
mech_state = MechState},
ClientIn);
_ ->
{error, 'invalid-mechanism'}
{error, "no-mechanism"}
end;
false ->
{error, 'invalid-mechanism'}
{error, "no-mechanism"}
end.
%% @spec (State, ClientIn) -> Ok | Continue | Error
%% State = saslstate()
%% ClientIn = string()
%% Ok = {ok, Props}
%% Props = [Prop]
%% Prop = [{Key, Value}]
%% Key = atom()
%% Value = string()
%% Continue = {continue, ServerOut, New_State}
%% ServerOut = string()
%% New_State = saslstate()
%% Error = {error, Reason} | {error, Reason, Text, Username}
%% Reason = term()
%% Text = string()
%% Username = string()
server_step(State, ClientIn) ->
Module = State#sasl_state.mech_mod,
MechState = State#sasl_state.mech_state,
@@ -252,24 +158,24 @@ server_step(State, ClientIn) ->
{error, Error} ->
{error, Error}
end;
{ok, Props, ServerOut} ->
case check_credentials(State, Props) of
ok ->
{ok, Props, ServerOut};
{error, Error} ->
{error, Error}
end;
{continue, ServerOut, NewMechState} ->
{continue, ServerOut,
State#sasl_state{mech_state = NewMechState}};
{error, Error, Text, Username} ->
{error, Error, Text, Username};
{error, Error, Username} ->
{error, Error, Username};
{error, Error} ->
{error, Error}
end.
%% @spec (Host, Mechs) -> [Filtered_Mechs]
%% Host = string()
%% Mechs = [Mech]
%% Mech = string()
%% Filtered_Mechs = [Mech]
%%
%% @doc Remove the anonymous mechanism from the list if not enabled for
%% the given host.
%% Remove the anonymous mechanism from the list if not enabled for the given
%% host
filter_anonymous(Host, Mechs) ->
case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(Host) of
true -> Mechs;
-15
View File
@@ -1,15 +0,0 @@
%% @type saslparams() = {sasl_params, Host, Realm, GetPassword, CheckPassword, CheckPasswordDigest}
%% Host = string()
%% Realm = string()
%% GetPassword = function()
%% CheckPassword = function()
%% CheckPasswordDigest = any().
%% Parameters for SASL.
-record(sasl_params, {
host,
realm,
get_password,
check_password,
check_password_digest,
socket}).
+5 -25
View File
@@ -6,7 +6,7 @@
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,42 +27,22 @@
-module(cyrsasl_anonymous).
-export([start/1, stop/0, mech_new/1, mech_step/2]).
-include("cyrsasl.hrl").
-export([start/1, stop/0, mech_new/4, mech_step/2]).
-behaviour(cyrsasl).
%% @type mechstate() = {state, Server}
%% Server = string().
-record(state, {server}).
%% @spec (Opts) -> true
%% Opts = term()
start(_Opts) ->
cyrsasl:register_mechanism("ANONYMOUS", ?MODULE, false),
cyrsasl:register_mechanism("ANONYMOUS", ?MODULE, plain),
ok.
%% @spec () -> ok
stop() ->
ok.
mech_new(#sasl_params{host=Host}) ->
mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
{ok, #state{server = Host}}.
%% @spec (State, ClientIn) -> Ok | Error
%% State = mechstate()
%% ClientIn = string()
%% Ok = {ok, Props}
%% Props = [Prop]
%% Prop = {username, Username} | {auth_module, AuthModule}
%% Username = string()
%% AuthModule = ejabberd_auth_anonymous
%% Error = {error, 'not-authorized'}
mech_step(State, _ClientIn) ->
%% We generate a random username:
User = lists:concat([randoms:get_string() | tuple_to_list(now())]),
@@ -70,7 +50,7 @@ mech_step(State, _ClientIn) ->
%% Checks that the username is available
case ejabberd_auth:is_user_exists(User, Server) of
true -> {error, 'not-authorized'};
true -> {error, "not-authorized"};
false -> {ok, [{username, User},
{auth_module, ejabberd_auth_anonymous}]}
end.
+50 -177
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -29,60 +29,32 @@
-export([start/1,
stop/0,
mech_new/1,
mech_new/4,
mech_step/2]).
-include("ejabberd.hrl").
-include("cyrsasl.hrl").
-behaviour(cyrsasl).
%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, CheckPassword, AuthModule, Host}
%% Step = 1 | 3 | 5
%% Nonce = string()
%% Username = string()
%% AuthzId = string()
%% GetPassword = function()
%% AuthModule = atom()
%% Host = string().
-record(state, {step, nonce, username, authzid, get_password, check_password, auth_module,
host}).
%% @spec (Opts) -> true
%% Opts = term()
host, hostfqdn}).
start(_Opts) ->
cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, true).
%% @spec () -> ok
Fqdn = get_local_fqdn(),
?INFO_MSG("FQDN used to check DIGEST-MD5 SASL authentication: ~p", [Fqdn]),
cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, digest).
stop() ->
ok.
mech_new(#sasl_params{host=Host, get_password=GetPassword,
check_password_digest=CheckPasswordDigest}) ->
mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
{ok, #state{step = 1,
nonce = randoms:get_string(),
host = Host,
hostfqdn = get_local_fqdn(),
get_password = GetPassword,
check_password = CheckPasswordDigest}}.
%% @spec (State, ClientIn) -> Ok | Continue | Error
%% State = mechstate()
%% ClientIn = string()
%% Ok = {ok, Props}
%% Props = [Prop]
%% Prop = {username, Username} | {authzid, AuthzId} | {auth_module, AuthModule}
%% Username = string()
%% AuthzId = string()
%% AuthModule = atom()
%% Continue = {continue, ServerOut, New_State}
%% ServerOut = string()
%% New_State = mechstate()
%% Error = {error, Reason} | {error, Reason, Text, Username}
%% Reason = term()
mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
{continue,
"nonce=\"" ++ Nonce ++
@@ -91,23 +63,24 @@ mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
case parse(ClientIn) of
bad ->
{error, 'bad-protocol'};
{error, "bad-protocol"};
KeyVals ->
DigestURI = proplists:get_value("digest-uri", KeyVals, ""),
UserName = proplists:get_value("username", KeyVals, ""),
case is_digesturi_valid(DigestURI, State#state.host) of
DigestURI = xml:get_attr_s("digest-uri", KeyVals),
UserName = xml:get_attr_s("username", KeyVals),
case is_digesturi_valid(DigestURI, State#state.host, State#state.hostfqdn) of
false ->
?DEBUG("User login not authorized because digest-uri "
"seems invalid: ~p", [DigestURI]),
{error, 'not-authorized', "", UserName};
"seems invalid: ~p (checking for Host ~p, FQDN ~p)", [DigestURI,
State#state.host, State#state.hostfqdn]),
{error, "not-authorized", UserName};
true ->
AuthzId = proplists:get_value("authzid", KeyVals, ""),
AuthzId = xml:get_attr_s("authzid", KeyVals),
case (State#state.get_password)(UserName) of
{false, _} ->
{error, 'not-authorized', "", UserName};
{error, "not-authorized", UserName};
{Passwd, AuthModule} ->
case (State#state.check_password)(UserName, "",
proplists:get_value("response", KeyVals, ""),
xml:get_attr_s("response", KeyVals),
fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId,
"AUTHENTICATE") end) of
{true, _} ->
@@ -121,9 +94,9 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
username = UserName,
authzid = AuthzId}};
false ->
{error, 'not-authorized', "", UserName};
{error, "not-authorized", UserName};
{false, _} ->
{error, 'not-authorized', "", UserName}
{error, "not-authorized", UserName}
end
end
end
@@ -136,18 +109,11 @@ mech_step(#state{step = 5,
{auth_module, AuthModule}]};
mech_step(A, B) ->
?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]),
{error, 'bad-protocol'}.
%% @spec (S) -> [{Key, Value}] | bad
%% S = string()
%% Key = string()
%% Value = string()
{error, "bad-protocol"}.
parse(S) ->
parse1(S, "", []).
%% @hidden
parse1([$= | Cs], S, Ts) ->
parse2(Cs, lists:reverse(S), "", Ts);
parse1([$, | Cs], [], Ts) ->
@@ -161,8 +127,6 @@ parse1([], [], T) ->
parse1([], _S, _T) ->
bad.
%% @hidden
parse2([$\" | Cs], Key, Val, Ts) ->
parse3(Cs, Key, Val, Ts);
parse2([C | Cs], Key, Val, Ts) ->
@@ -170,8 +134,6 @@ parse2([C | Cs], Key, Val, Ts) ->
parse2([], _, _, _) ->
bad.
%% @hidden
parse3([$\" | Cs], Key, Val, Ts) ->
parse4(Cs, Key, Val, Ts);
parse3([$\\, C | Cs], Key, Val, Ts) ->
@@ -181,8 +143,6 @@ parse3([C | Cs], Key, Val, Ts) ->
parse3([], _, _, _) ->
bad.
%% @hidden
parse4([$, | Cs], Key, Val, Ts) ->
parse1(Cs, "", [{Key, lists:reverse(Val)} | Ts]);
parse4([$\s | Cs], Key, Val, Ts) ->
@@ -193,46 +153,49 @@ parse4([], Key, Val, Ts) ->
parse1([], "", [{Key, lists:reverse(Val)} | Ts]).
%% @spec (DigestURICase, JabberHost) -> bool()
%% DigestURICase = string()
%% JabberHost = string()
%%
%% @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 = exmpp_stringprep:to_lower(DigestURICase),
%% then acceptable digest-uris would be:
%% xmpp/server3.example.org/jabber.example.org, xmpp/server3.example.org and
%% xmpp/jabber.example.org
%% The last version is not actually allowed by the RFC, but implemented by popular clients
is_digesturi_valid(DigestURICase, JabberDomain, JabberFQDN) ->
DigestURI = stringprep:tolower(DigestURICase),
case catch string:tokens(DigestURI, "/") of
["xmpp", Host] when Host == JabberHost ->
["xmpp", Host] when (Host == JabberDomain) or (Host == JabberFQDN) ->
true;
["xmpp", _Host, ServName] when ServName == JabberHost ->
["xmpp", Host, ServName] when (ServName == JabberDomain) and (Host == JabberFQDN) ->
true;
_ ->
false
end.
%% @hidden
get_local_fqdn() ->
case (catch get_local_fqdn2()) of
Str when is_list(Str) -> Str;
_ -> "unknown-fqdn, please configure fqdn option in ejabberd.cfg!"
end.
get_local_fqdn2() ->
case ejabberd_config:get_local_option(fqdn) of
ConfiguredFqdn when is_list(ConfiguredFqdn) ->
ConfiguredFqdn;
_undefined ->
{ok, Hostname} = inet:gethostname(),
{ok, {hostent, Fqdn, _, _, _, _}} = inet:gethostbyname(Hostname),
Fqdn
end.
digit_to_xchar(D) when (D >= 0) and (D < 10) ->
D + 48;
digit_to_xchar(D) ->
D + 87.
%% @hidden
hex(S) ->
hex(S, []).
%% @hidden
hex([], Res) ->
lists:reverse(Res);
hex([N | Ns], Res) ->
@@ -240,35 +203,20 @@ hex([N | Ns], Res) ->
digit_to_xchar(N div 16) | Res]).
%% @spec (KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) -> string()
%% KeyVals = [{Key, Value}]
%% Key = string()
%% Value = string()
%% User = string()
%% Passwd = string()
%% Nonce = string()
%% AuthzId = nil() | string()
%% A2Prefix = string()
response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) ->
Realm = proplists:get_value("realm", KeyVals, ""),
CNonce = proplists:get_value("cnonce", KeyVals, ""),
DigestURI = proplists:get_value("digest-uri", KeyVals, ""),
NC = proplists:get_value("nc", KeyVals, ""),
QOP = proplists:get_value("qop", KeyVals, ""),
%% handle non-fully latin-1 strings as specified
%% on RFC 2831 Section 2.1.2.1 (EJAB-476)
SUser = sanitize(User),
SPasswd = sanitize(Passwd),
SRealm = sanitize(Realm),
Realm = xml:get_attr_s("realm", KeyVals),
CNonce = xml:get_attr_s("cnonce", KeyVals),
DigestURI = xml:get_attr_s("digest-uri", KeyVals),
NC = xml:get_attr_s("nc", KeyVals),
QOP = xml:get_attr_s("qop", KeyVals),
A1 = case AuthzId of
"" ->
binary_to_list(
crypto:md5(SUser ++ ":" ++ SRealm ++ ":" ++ SPasswd)) ++
crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
":" ++ Nonce ++ ":" ++ CNonce;
_ ->
binary_to_list(
crypto:md5(SUser ++ ":" ++ SRealm ++ ":" ++ SPasswd)) ++
crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
":" ++ Nonce ++ ":" ++ CNonce ++ ":" ++ AuthzId
end,
A2 = case QOP of
@@ -284,79 +232,4 @@ response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) ->
hex(binary_to_list(crypto:md5(T))).
sanitize(V) ->
L = from_utf8(V),
case lists:all(fun is_latin1/1, L) of
true -> L;
false -> V
end.
%%%% copied from xmerl_ucs:from_utf8/1 and xmerl_ucs:is_latin1/1 , to not
%%%% require xmerl as a dependency only for this.
from_utf8(Bin) when is_binary(Bin) -> from_utf8(binary_to_list(Bin));
from_utf8(List) ->
case expand_utf8(List) of
{Result,0} -> Result;
{_Res,_NumBadChar} ->
exit({ucs,{bad_utf8_character_code}})
end.
%% expand_utf8([Byte]) -> {[UnicodeChar],NumberOfBadBytes}
%% Expand UTF8 byte sequences to ISO 10646/Unicode
%% charactes. Any illegal bytes are removed and the number of
%% bad bytes are returned.
%%
%% Reference:
%% RFC 3629: "UTF-8, a transformation format of ISO 10646".
expand_utf8(Str) ->
expand_utf8_1(Str, [], 0).
expand_utf8_1([C|Cs], Acc, Bad) when C < 16#80 ->
%% Plain Ascii character.
expand_utf8_1(Cs, [C|Acc], Bad);
expand_utf8_1([C1,C2|Cs], Acc, Bad) when C1 band 16#E0 =:= 16#C0,
C2 band 16#C0 =:= 16#80 ->
case ((C1 band 16#1F) bsl 6) bor (C2 band 16#3F) of
C when 16#80 =< C ->
expand_utf8_1(Cs, [C|Acc], Bad);
_ ->
%% Bad range.
expand_utf8_1(Cs, Acc, Bad+1)
end;
expand_utf8_1([C1,C2,C3|Cs], Acc, Bad) when C1 band 16#F0 =:= 16#E0,
C2 band 16#C0 =:= 16#80,
C3 band 16#C0 =:= 16#80 ->
case ((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor
(C3 band 16#3F) of
C when 16#800 =< C ->
expand_utf8_1(Cs, [C|Acc], Bad);
_ ->
%% Bad range.
expand_utf8_1(Cs, Acc, Bad+1)
end;
expand_utf8_1([C1,C2,C3,C4|Cs], Acc, Bad) when C1 band 16#F8 =:= 16#F0,
C2 band 16#C0 =:= 16#80,
C3 band 16#C0 =:= 16#80,
C4 band 16#C0 =:= 16#80 ->
case ((((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor
(C3 band 16#3F)) bsl 6) bor (C4 band 16#3F) of
C when 16#10000 =< C ->
expand_utf8_1(Cs, [C|Acc], Bad);
_ ->
%% Bad range.
expand_utf8_1(Cs, Acc, Bad+1)
end;
expand_utf8_1([_|Cs], Acc, Bad) ->
%% Ignore bad character.
expand_utf8_1(Cs, Acc, Bad+1);
expand_utf8_1([], Acc, Bad) -> {lists:reverse(Acc),Bad}.
%%% Test for legitimate Latin-1 code
is_latin1(Ch) when is_integer(Ch), Ch >= 0, Ch =< 255 -> true;
is_latin1(_) -> false.
-164
View File
@@ -1,164 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_gssapi.erl
%%% Author : Mikael Magnusson <mikma@users.sourceforge.net>
%%% Purpose : GSSAPI SASL mechanism
%%% Created : 1 June 2007 by Mikael Magnusson <mikma@users.sourceforge.net>
%%%----------------------------------------------------------------------
%%%
%%% Copyright (C) 2007-2009 Mikael Magnusson <mikma@users.sourceforge.net>
%%%
%%% 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.
%%%
%%%
%%% configuration options:
%%% {sasl_realm, "<Kerberos realm>"}.
%%%
%%% environment variables:
%%% KRB5_KTNAME
%%%
-module(cyrsasl_gssapi).
-author('mikma@users.sourceforge.net').
-export([start/1,
stop/0,
mech_new/1,
mech_step/2]).
-include("ejabberd.hrl").
-include("cyrsasl.hrl").
-behaviour(cyrsasl).
-define(SERVER, ?MODULE).
-define(SERVICE, "xmpp").
-record(state, {sasl,
needsmore=true,
step=0,
host,
realm,
authid,
authzid,
authrealm,
error}).
start(_Opts) ->
ChildSpec =
{?SERVER,
{esasl, start_link, [{local, ?SERVER}]},
transient,
1000,
worker,
[esasl]},
case supervisor:start_child(ejabberd_sup, ChildSpec) of
{ok, _Pid} ->
cyrsasl:register_mechanism("GSSAPI", ?MODULE, false);
{error, Error} = E ->
?ERROR_MSG("esasl failed: ~p", [Error]),
E
end.
stop() ->
catch esasl:stop(?SERVER),
supervisor:terminate_child(ejabberd_sup, ?SERVER),
supervisor:delete_child(ejabberd_sup, ?SERVER).
mech_new(#sasl_params{host=Host, realm=Realm, socket=Socket}) ->
case ejabberd_socket:gethostname(Socket) of
{ok, FQDN} ->
?DEBUG("mech_new ~p ~p ~p~n", [Host, Realm, FQDN]),
case esasl:server_start(?SERVER, "GSSAPI", ?SERVICE, FQDN) of
{ok, Sasl} ->
{ok, #state{sasl=Sasl,host=Host,realm=Realm}};
{error, {gsasl_error, Error}} ->
{ok, Str} = esasl:str_error(?SERVER, Error),
?DEBUG("esasl error: ~p", [Str]),
{ok, #state{needsmore=error,error="internal-server-error"}};
{error, Error} ->
?DEBUG("esasl error: ~p", [Error]),
{ok, #state{needsmore=error,error="internal-server-error"}}
end;
{error, Error} ->
?DEBUG("gethostname error: ~p", [Error]),
{ok, #state{needsmore=error,error="internal-server-error"}}
end.
mech_step(State, ClientIn) when is_list(ClientIn) ->
catch do_step(State, ClientIn).
do_step(#state{needsmore=error,error=Error}=_State, _) ->
{error, Error};
do_step(#state{needsmore=false}=State, _) ->
check_user(State);
do_step(#state{needsmore=true,sasl=Sasl,step=Step}=State, ClientIn) ->
?DEBUG("mech_step~n", []),
case esasl:step(Sasl, list_to_binary(ClientIn)) of
{ok, RspAuth} ->
?DEBUG("ok~n", []),
{ok, Display_name} = esasl:property_get(Sasl, gssapi_display_name),
{ok, Authzid} = esasl:property_get(Sasl, authzid),
{Authid, [$@ | Auth_realm]} =
lists:splitwith(fun(E)->E =/= $@ end, Display_name),
State1 = State#state{authid=Authid,
authzid=Authzid,
authrealm=Auth_realm},
handle_step_ok(State1, binary_to_list(RspAuth));
{needsmore, RspAuth} ->
?DEBUG("needsmore~n", []),
if (Step > 0) and (ClientIn =:= []) and (RspAuth =:= <<>>) ->
{error, 'not-authorized'};
true ->
{continue, binary_to_list(RspAuth),
State#state{step=Step+1}}
end;
{error, _} ->
{error, 'not-authorized'}
end.
handle_step_ok(State, []) ->
check_user(State);
handle_step_ok(#state{step=Step}=State, RspAuth) ->
?DEBUG("continue~n", []),
{continue, RspAuth, State#state{needsmore=false,step=Step+1}}.
check_user(#state{authid=Authid,authzid=Authzid,
authrealm=Auth_realm,host=Host,realm=Realm}) ->
if Realm =/= Auth_realm ->
?DEBUG("bad realm ~p (expected ~p)~n",[Auth_realm, Realm]),
throw({error, 'not-authorized'});
true ->
ok
end,
case ejabberd_auth:is_user_exists(Authid, Host) of
false ->
?DEBUG("bad user ~p~n",[Authid]),
throw({error, 'not-authorized'});
true ->
ok
end,
?DEBUG("GSSAPI authenticated ~p ~p~n", [Authid, Authzid]),
{ok, [{username, Authid}, {authzid, Authzid}]}.
+6 -33
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,43 +27,22 @@
-module(cyrsasl_plain).
-author('alexey@process-one.net').
-export([start/1, stop/0, mech_new/1, mech_step/2, parse/1]).
-include("cyrsasl.hrl").
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-behaviour(cyrsasl).
%% @type mechstate() = {state, CheckPassword}
%% CheckPassword = function().
-record(state, {check_password}).
%% @spec (Opts) -> true
%% Opts = term()
start(_Opts) ->
cyrsasl:register_mechanism("PLAIN", ?MODULE, false),
cyrsasl:register_mechanism("PLAIN", ?MODULE, plain),
ok.
%% @spec () -> ok
stop() ->
ok.
mech_new(#sasl_params{check_password = CheckPassword}) ->
mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
{ok, #state{check_password = CheckPassword}}.
%% @spec (State, ClientIn) -> Ok | Error
%% State = mechstate()
%% ClientIn = string()
%% Ok = {ok, Props}
%% Props = [Prop]
%% Prop = {username, Username} | {authzid, AuthzId} | {auth_module, AuthModule}
%% Username = string()
%% AuthzId = string()
%% AuthModule = atom()
%% Error = {error, Reason} | {error, Reason, Text, Username}
mech_step(State, ClientIn) ->
case prepare(ClientIn) of
[AuthzId, User, Password] ->
@@ -71,13 +50,11 @@ mech_step(State, ClientIn) ->
{true, AuthModule} ->
{ok, [{username, User}, {authzid, AuthzId},
{auth_module, AuthModule}]};
{false, ReasonAuthFail} when is_list(ReasonAuthFail) ->
{error, 'not-authorized', ReasonAuthFail, User};
_ ->
{error, 'not-authorized', "", User}
{error, "not-authorized", User}
end;
_ ->
{error, 'bad-protocol'}
{error, "bad-protocol"}
end.
prepare(ClientIn) ->
@@ -99,13 +76,9 @@ prepare(ClientIn) ->
end.
%% @hidden
parse(S) ->
parse1(S, "", []).
%% @hidden
parse1([0 | Cs], S, T) ->
parse1(Cs, "", [lists:reverse(S) | T]);
parse1([C | Cs], S, T) ->
+190
View File
@@ -0,0 +1,190 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_scram.erl
%%% Author : Stephen Röttger <stephen.roettger@googlemail.com>
%%% Purpose : SASL SCRAM authentication
%%% Created : 7 Aug 2011 by Stephen Röttger <stephen.roettger@googlemail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2012 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(cyrsasl_scram).
-author('stephen.roettger@googlemail.com').
-export([start/1,
stop/0,
mech_new/4,
mech_step/2]).
-include("ejabberd.hrl").
-behaviour(cyrsasl).
-record(state, {step, stored_key, server_key, username, get_password, check_password,
auth_message, client_nonce, server_nonce}).
-define(SALT_LENGTH, 16).
-define(NONCE_LENGTH, 16).
start(_Opts) ->
cyrsasl:register_mechanism("SCRAM-SHA-1", ?MODULE, scram).
stop() ->
ok.
mech_new(_Host, GetPassword, _CheckPassword, _CheckPasswordDigest) ->
{ok, #state{step = 2, get_password = GetPassword}}.
mech_step(#state{step = 2} = State, ClientIn) ->
case string:tokens(ClientIn, ",") of
[CBind, UserNameAttribute, ClientNonceAttribute] when (CBind == "y") or (CBind == "n") ->
case parse_attribute(UserNameAttribute) of
{error, Reason} ->
{error, Reason};
{_, EscapedUserName} ->
case unescape_username(EscapedUserName) of
error ->
{error, "protocol-error-bad-username"};
UserName ->
case parse_attribute(ClientNonceAttribute) of
{$r, ClientNonce} ->
case (State#state.get_password)(UserName) of
{false, _} ->
{error, "not-authorized", UserName};
{Ret, _AuthModule} ->
{StoredKey, ServerKey, Salt, IterationCount} = if
is_tuple(Ret) ->
Ret;
true ->
TempSalt = crypto:rand_bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Ret, TempSalt, ?SCRAM_DEFAULT_ITERATION_COUNT),
{scram:stored_key(scram:client_key(SaltedPassword)),
scram:server_key(SaltedPassword), TempSalt, ?SCRAM_DEFAULT_ITERATION_COUNT}
end,
ClientFirstMessageBare = string:substr(ClientIn, string:str(ClientIn, "n=")),
ServerNonce = base64:encode_to_string(crypto:rand_bytes(?NONCE_LENGTH)),
ServerFirstMessage = "r=" ++ ClientNonce ++ ServerNonce ++ "," ++
"s=" ++ base64:encode_to_string(Salt) ++ "," ++
"i=" ++ integer_to_list(IterationCount),
{continue,
ServerFirstMessage,
State#state{step = 4, stored_key = StoredKey, server_key = ServerKey,
auth_message = ClientFirstMessageBare ++ "," ++ ServerFirstMessage,
client_nonce = ClientNonce, server_nonce = ServerNonce, username = UserName}}
end;
_Else ->
{error, "not-supported"}
end
end
end;
_Else ->
{error, "bad-protocol"}
end;
mech_step(#state{step = 4} = State, ClientIn) ->
case string:tokens(ClientIn, ",") of
[GS2ChannelBindingAttribute, NonceAttribute, ClientProofAttribute] ->
case parse_attribute(GS2ChannelBindingAttribute) of
{$c, CVal} when (CVal == "biws") or (CVal == "eSws") ->
%% biws is base64 for n,, => channelbinding not supported
%% eSws is base64 for y,, => channelbinding supported by client only
Nonce = State#state.client_nonce ++ State#state.server_nonce,
case parse_attribute(NonceAttribute) of
{$r, CompareNonce} when CompareNonce == Nonce ->
case parse_attribute(ClientProofAttribute) of
{$p, ClientProofB64} ->
ClientProof = base64:decode(ClientProofB64),
AuthMessage = State#state.auth_message ++ "," ++ string:substr(ClientIn, 1, string:str(ClientIn, ",p=")-1),
ClientSignature = scram:client_signature(State#state.stored_key, AuthMessage),
ClientKey = scram:client_key(ClientProof, ClientSignature),
CompareStoredKey = scram:stored_key(ClientKey),
if CompareStoredKey == State#state.stored_key ->
ServerSignature = scram:server_signature(State#state.server_key, AuthMessage),
{ok, [{username, State#state.username}], "v=" ++ base64:encode_to_string(ServerSignature)};
true ->
{error, "bad-auth"}
end;
_Else ->
{error, "bad-protocol"}
end;
{$r, _} ->
{error, "bad-nonce"};
_Else ->
{error, "bad-protocol"}
end;
_Else ->
{error, "bad-protocol"}
end;
_Else ->
{error, "bad-protocol"}
end.
parse_attribute(Attribute) ->
AttributeLen = string:len(Attribute),
if
AttributeLen >= 3 ->
SecondChar = lists:nth(2, Attribute),
case is_alpha(lists:nth(1, Attribute)) of
true ->
if
SecondChar == $= ->
String = string:substr(Attribute, 3),
{lists:nth(1, Attribute), String};
true ->
{error, "bad-format second char not equal sign"}
end;
_Else ->
{error, "bad-format first char not a letter"}
end;
true ->
{error, "bad-format attribute too short"}
end.
unescape_username("") ->
"";
unescape_username(EscapedUsername) ->
Pos = string:str(EscapedUsername, "="),
if
Pos == 0 ->
EscapedUsername;
true ->
Start = string:substr(EscapedUsername, 1, Pos-1),
End = string:substr(EscapedUsername, Pos),
EndLen = string:len(End),
if
EndLen < 3 ->
error;
true ->
case string:substr(End, 1, 3) of
"=2C" ->
Start ++ "," ++ unescape_username(string:substr(End, 4));
"=3D" ->
Start ++ "=" ++ unescape_username(string:substr(End, 4));
_Else ->
error
end
end
end.
is_alpha(Char) when Char >= $a, Char =< $z ->
true;
is_alpha(Char) when Char >= $A, Char =< $Z ->
true;
is_alpha(_) ->
false.
+17 -4
View File
@@ -1,6 +1,8 @@
%% $Id$
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "3.0.0-alpha-x"},
{vsn, "2.1.11"},
{modules, [acl,
adhoc,
configure,
@@ -8,14 +10,16 @@
cyrsasl,
cyrsasl_digest,
cyrsasl_plain,
cyrsasl_scram,
ejabberd_admin,
ejabberd_app,
ejabberd_auth_anonymous,
ejabberd_auth,
ejabberd_auth_external,
ejabberd_auth_internal,
ejabberd_auth_ldap,
ejabberd_auth_odbc,
ejabberd_auth_pam,
ejabberd_auth_storage,
ejabberd,
ejabberd_c2s,
ejabberd_c2s_config,
@@ -34,7 +38,6 @@
ejabberd_rdbms,
ejabberd_receiver,
ejabberd_router,
ejabberd_router_multicast,
ejabberd_s2s,
ejabberd_s2s_in,
ejabberd_s2s_out,
@@ -59,6 +62,7 @@
gen_mod,
gen_pubsub_node,
gen_pubsub_nodetree,
iconv,
idna,
jd2ejd,
jlib,
@@ -71,13 +75,19 @@
mod_echo,
mod_http_bind,
mod_http_fileserver,
mod_irc,
mod_irc_connection,
mod_last,
mod_last_odbc,
mod_muc,
mod_muc_log,
mod_muc_room,
mod_offline,
mod_offline_odbc,
mod_privacy,
mod_privacy_odbc,
mod_private,
mod_private_odbc,
mod_proxy65,
mod_proxy65_lib,
mod_proxy65_service,
@@ -86,12 +96,14 @@
mod_pubsub,
mod_register,
mod_roster,
mod_roster_odbc,
mod_service_log,
mod_shared_roster,
mod_stats,
mod_time,
mod_vcard,
mod_vcard_ldap,
mod_vcard_odbc,
mod_version,
node_buddy,
node_club,
@@ -113,13 +125,13 @@
tls,
translate,
xml,
xml_stream,
'XmppAddr'
]},
{registered, [ejabberd,
ejabberd_sup,
ejabberd_auth,
ejabberd_router,
ejabberd_router_multicast,
ejabberd_sm,
ejabberd_s2s,
ejabberd_local,
@@ -132,6 +144,7 @@
ejabberd_mod_roster,
ejabberd_mod_echo,
ejabberd_mod_pubsub,
ejabberd_mod_irc,
ejabberd_mod_muc,
ejabberd_offline,
random_generator
+58 -86
View File
@@ -80,24 +80,14 @@
%%{watchdog_admins, ["bob@example.com"]}.
%%%. =====================
%%%' CLUSTER CONFIGURATION
%% clusterid: the integer id of the cluster of nodes this node will
%% belong to.
{clusterid, 1}.
%%%. ================
%%%' SERVED HOSTNAMES
%%
%% hosts: Domains served by ejabberd.
%% You can define one or several, for example:
%% {hosts, ["localhost", "example.net", "example.com", "example.org"]}.
%% {hosts, ["example.net", "example.com", "example.org"]}.
%%
%% Additional hosts will be discovered from the 'hosts' database table
%% configured for the first host.
{hosts, ["localhost"]}.
%%
@@ -223,19 +213,18 @@
%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal Mnesia database storage.
%% The default method is the internal.
%% If you want to use a different method,
%% comment those lines and enable the desired lines later.
%% comment this line and enable the correct ones.
%%
{auth_method, storage}.
{auth_storage, mnesia}.
{auth_method, internal}.
%%
%% Authentication using ODBC
%% Remember to setup a database in the next section.
%% Store the plain passwords or hashed for SCRAM:
%%{auth_password_format, plain}.
%%{auth_password_format, scram}.
%%
%%{auth_method, storage}.
%%{auth_storage, odbc}.
%% Define the FQDN if ejabberd doesn't detect it:
%%{fqdn, "server3.example.com"}.
%%
%% Authentication using external script
@@ -244,6 +233,12 @@
%%{auth_method, external}.
%%{extauth_program, "/path/to/authentication/script"}.
%%
%% Authentication using ODBC
%% Remember to setup a database in the next section.
%%
%%{auth_method, odbc}.
%%
%% Authentication using PAM
%%
@@ -305,32 +300,22 @@
%% you want to use other database backends.
%% Please consult the ejabberd Guide for details on database creation.
%% Template host ODBC configuration.
%% The host specified here will be used by default for all discovered vhosts.
%% The actual ODBC server configuration must be provided in a host_config directive.
{odbc_server, {host, "localhost"}}.
{host_config, "localhost",
[
%%
%% MySQL server:
%%
%%{odbc_server, {mysql, "server", "database", "username", "password"}}
%%{odbc_server, {mysql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}.
%%
%% PostgreSQL server:
%%
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}.
%%
]
}.
%% If you use PostgreSQL, have a large database, and need a
%% faster but inexact replacement for "select count(*) from users"
%%
@@ -472,19 +457,6 @@
%%}.
%%%. =======
%%%' CAPTCHA
%%
%% Full path to a script that generates the image.
%%
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
%% Host for the URL and port where ejabberd listens for CAPTCHA requests.
%%
%%{captcha_host, "example.org:5280"}.
%%%. ================
%%%' DEFAULT LANGUAGE
@@ -501,51 +473,67 @@
%%}.
%%%. ================
%%%' INSTANCE MODULES
%%%. =======
%%%' CAPTCHA
%%
%% Modules to start for every virtual host.
%% Full path to a script that generates the image.
%%
%% Note: One copy of each module will be started for each host.
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
%%
%% Host for the URL and port where ejabberd listens for CAPTCHA requests.
%%
%%{captcha_host, "example.org:5280"}.
%%
%% Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
%%
%%{captcha_limit, 5}.
%%%. =======
%%%' MODULES
%%
%% Modules enabled in all ejabberd virtual hosts.
%%
{modules,
[
{mod_adhoc, []},
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
{mod_blocking,[]}, % requires mod_privacy
{mod_caps, []}, % 1 proc/host
{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, [ % 1 proc/host
{host, "conference.@HOST@"},
{access, muc},
{access_create, muc_create},
{access_persistent, muc_create},
{access_admin, muc_admin}
]},
{mod_muc, [
%%{host, "conference.@HOST@"},
{access, muc},
{access_create, muc_create},
{access_persistent, muc_create},
{access_admin, muc_admin}
]},
%%{mod_muc_log,[]},
%%{mod_multicast,[]},
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
{mod_ping, []},
%%{mod_pres_counter,[{count, 5}, {interval, 60}]},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
%%{mod_pubsub, [ % 1 proc/host
%% {access_createnode, pubsub_createnode},
%% {ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
%% %%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
%% {last_item_cache, false},
%% {plugins, ["flat", "pep"]} % pep requires mod_caps
%% ]},
{mod_pubsub, [
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, % reduces 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
]},
{mod_register, [
%%
%% Protect In-Band account registrations with CAPTCHA.
@@ -595,28 +583,10 @@
{mod_shared_roster,[]},
{mod_stats, []},
{mod_time, []},
{mod_vcard, []}, % 1 proc/host
{mod_vcard, []},
{mod_version, []}
]}.
%%%.
%%%' STATIC MODULES
%%
%% Modules to start for the global virtual host ("localhost").
%%
%% The functionality of these modules will be enabled in all ejabberd
%% virtual hosts without consuming more resources.
%%
{static_modules,
[
]}.
%%%.
%%%' HOST SPECIFIC MODULES
%%
%% Enable modules with custom options in a specific virtual host
%%
@@ -632,6 +602,8 @@
%%%.
%%%'
%%% $Id$
%%% Local Variables:
%%% mode: erlang
%%% End:
+3 -36
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -28,14 +28,8 @@
-author('alexey@process-one.net').
-export([start/0, stop/0,
get_so_path/0,
get_bin_path/0,
get_pid_file/0,
is_my_host/1,
normalize_host/1
]).
-include("ejabberd.hrl").
get_pid_file/0,
get_so_path/0, get_bin_path/0]).
start() ->
%%ejabberd_cover:start(),
@@ -71,33 +65,6 @@ get_bin_path() ->
Path
end.
is_my_host([$* | _]) ->
false;
is_my_host(Host) ->
case ejabberd_config:get_local_option({Host, host}) of
undefined ->
WCHost = re:replace(Host, "^[^.]*\.", "*.", [{return, list}]),
case ejabberd_config:get_local_option({WCHost, host}) of
undefined ->
false;
_ ->
true
end;
_ ->
true
end.
normalize_host(global) ->
global;
normalize_host(Host) ->
WCHost = re:replace(Host, "^[^.]*\.", "*.", [{return, list}]),
case ejabberd_config:get_local_option({WCHost, host}) of
undefined ->
Host;
_ ->
WCHost
end.
%% @spec () -> false | string()
get_pid_file() ->
case os:getenv("EJABBERD_PID_PATH") of
+6 -5
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -23,8 +23,7 @@
%% If the ejabberd application description isn't loaded, returns atom: undefined
-define(VERSION, element(2, application:get_key(ejabberd,vsn))).
-define(IS_MY_HOST(Host), ejabberd:is_my_host(Host)).
-define(MYHOSTS, ejabberd_config:get_global_option(hosts)). %% Deprecated
-define(MYHOSTS, ejabberd_config:get_global_option(hosts)).
-define(MYNAME, hd(ejabberd_config:get_global_option(hosts))).
-define(MYLANG, ejabberd_config:get_global_option(language)).
@@ -36,10 +35,11 @@
-define(S2STIMEOUT, 600000).
-define(PRIVACY_SUPPORT, true).
%%-define(DBGFSM, true).
-record(scram, {storedkey, serverkey, salt, iterationcount}).
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
%% ---------------------------------
%% Logging mechanism
@@ -61,3 +61,4 @@
-define(CRITICAL_MSG(Format, Args),
ejabberd_logger:critical_msg(?MODULE,?LINE,Format, Args)).
+20 -34
View File
@@ -5,7 +5,7 @@
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -36,9 +36,6 @@
%% Accounts
register/3, unregister/2,
registered_users/1,
%% For debugging gen_storage
get_last_info/0,
get_last_info/2,
%% Migration jabberd1.4
import_file/1, import_dir/1,
%% Purge DB
@@ -88,6 +85,10 @@ commands() ->
args = [], result = {res, rescode}},
#ejabberd_commands{name = stop_kindly, tags = [server],
desc = "Inform users and rooms, wait, and stop the server",
longdesc = "Provide the delay in seconds, and the "
"announcement quoted, for example: \n"
"ejabberdctl stop_kindly 60 "
"\\\"The server will stop in one minute.\\\"",
module = ?MODULE, function = stop_kindly,
args = [{delay, integer}, {announcement, string}],
result = {res, rescode}},
@@ -127,21 +128,6 @@ commands() ->
args = [{host, string}],
result = {users, {list, {username, string}}}},
#ejabberd_commands{name = gli, tags = [accounts],
desc = "Get information about last access of an account",
module = ?MODULE, function = get_last_info,
args = [],
result = {lastinfo, {tuple, [{timestamp, integer},
{status, string}
]}}},
#ejabberd_commands{name = get_last_info, tags = [accounts],
desc = "Get information about last access of an account",
module = ?MODULE, function = get_last_info,
args = [{user, string}, {host, string}],
result = {lastinfo, {tuple, [{timestamp, integer},
{status, string}
]}}},
#ejabberd_commands{name = import_file, tags = [mnesia],
desc = "Import user data from jabberd14 spool file",
module = ?MODULE, function = import_file,
@@ -173,6 +159,11 @@ commands() ->
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 old ejabberd trunk SVN to 2.1.0",
module = mod_pubsub, function = rename_default_nodeplugin,
args = [], result = {res, rescode}},
#ejabberd_commands{name = set_master, tags = [mnesia],
desc = "Set master node of the clustered Mnesia tables",
@@ -261,7 +252,8 @@ get_sasl_error_logger_type () ->
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",
Steps = [
{"Stopping ejabberd port listeners",
ejabberd_listener, stop_listeners, []},
{"Sending announcement to connected users",
mod_announce, send_announcement_to_all,
@@ -283,7 +275,7 @@ stop_kindly(DelaySeconds, AnnouncementText) ->
- TimestampStart,
io:format("[~p/~p ~ps] ~s... ",
[NumberThis, NumberLast, SecondsDiff, Desc]),
Result = apply(Mod, Func, Args),
Result = (catch apply(Mod, Func, Args)),
io:format("~p~n", [Result]),
NumberThis+1
end,
@@ -297,8 +289,7 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
fun(ServerHost) ->
MUCHost = gen_mod:get_module_opt_host(
ServerHost, mod_muc, "conference.@HOST@"),
MUCHostB = list_to_binary(MUCHost),
mod_muc:broadcast_service_message(MUCHostB, Message)
mod_muc:broadcast_service_message(MUCHost, Message)
end,
?MYHOSTS).
@@ -312,14 +303,15 @@ update_list() ->
[atom_to_list(Beam) || Beam <- UpdatedBeams].
update("all") ->
[update_module(ModStr) || ModStr <- update_list()];
[update_module(ModStr) || ModStr <- update_list()],
{ok, []};
update(ModStr) ->
update_module(ModStr).
update_module(ModuleNameString) ->
ModuleName = list_to_atom(ModuleNameString),
case ejabberd_update:update([ModuleName]) of
{ok, Res} -> {ok, io_lib:format("Updated: ~p", [Res])};
{ok, _Res} -> {ok, []};
{error, Reason} -> {error, Reason}
end.
@@ -350,12 +342,6 @@ registered_users(Host) ->
SUsers = lists:sort(Users),
lists:map(fun({U, _S}) -> U end, SUsers).
get_last_info() -> get_last_info("badlop", "localhost").
get_last_info(User, Server) ->
case mod_last:get_last_info(User, Server) of
{ok, TimeStamp, Status} -> {TimeStamp, Status};
not_found -> {"never", ""}
end.
%%%
%%% Migration management
@@ -387,11 +373,11 @@ import_dir(Path) ->
%%%
delete_expired_messages() ->
mod_offline:remove_expired_messages(),
{atomic, ok} = mod_offline:remove_expired_messages(),
ok.
delete_old_messages(Days) ->
mod_offline:remove_old_messages(Days),
{atomic, _} = mod_offline:remove_old_messages(Days),
ok.
@@ -453,7 +439,7 @@ restore(Path) ->
%% Obsolete tables or tables created by module who are no longer used are not
%% restored and are ignored.
keep_tables() ->
lists:flatten([acl, passwd, config, local_config, disco_publish,
lists:flatten([acl, passwd, config, local_config,
keep_modules_tables()]).
%% Returns the list of modules tables in use, according to the list of actually
+16 -23
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -42,10 +42,11 @@ start(normal, _Args) ->
ejabberd_loglevel:set(4),
write_pid_file(),
application:start(sasl),
application:start(exmpp),
randoms:start(),
db_init(),
sha:start(),
stringprep_sup:start_link(),
xml:start(),
start(),
translate:start(),
acl:start(),
@@ -66,10 +67,7 @@ start(normal, _Args) ->
%ejabberd_debug:eprof_start(),
%ejabberd_debug:fprof_start(),
maybe_add_nameservers(),
print_start_debug_info(),
start_modules(),
ejabberd_cluster:announce(),
ejabberd_node_groups:start(),
ejabberd_listener:start_listeners(),
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
Sup;
@@ -108,7 +106,19 @@ init() ->
LogPath = get_log_path(),
error_logger:add_report_handler(ejabberd_logger_h, LogPath),
erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
ok.
case erl_ddll:load_driver(ejabberd:get_so_path(), expat_erl) of
ok -> ok;
{error, already_loaded} -> ok
end,
Port = open_port({spawn, "expat_erl"}, [binary]),
loop(Port).
loop(Port) ->
receive
_ ->
loop(Port)
end.
db_init() ->
case mnesia:system_info(extra_db_nodes) of
@@ -122,15 +132,6 @@ db_init() ->
%% Start all the modules in all the hosts
start_modules() ->
case ejabberd_config:get_local_option({static_modules, global}) of
undefined ->
ok;
StaticModules ->
lists:foreach(
fun({Module, Args}) ->
gen_mod:start_module(global, Module, Args)
end, StaticModules)
end,
lists:foreach(
fun(Host) ->
case ejabberd_config:get_local_option({modules, Host}) of
@@ -238,11 +239,3 @@ delete_pid_file() ->
PidFilename ->
file:delete(PidFilename)
end.
print_start_debug_info() ->
?DEBUG("Inet DB RC:~n~p", [inet_db:get_rc()]),
?DEBUG("Mnesia database:~n~p", [mnesia:system_info(all)]),
?DEBUG("Mnesia tables:~n~p",
[ [{Table, mnesia:table_info(Table, all)} ||
Table <- lists:sort(mnesia:system_info(tables))] ]),
ok.
+111 -233
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -50,149 +50,103 @@
remove_user/2,
remove_user/3,
plain_password_required/1,
store_type/1,
entropy/1
]).
-export([start/1
,start_module/2
,stop_module/2
,start_modules/2
,start_method/2
,stop_method/2
,start_methods/2
]).
-export([auth_modules/1]).
-include("ejabberd.hrl").
%% @type authmodule() = ejabberd_auth_anonymous | ejabberd_auth_external |
%% ejabberd_auth_ldap | ejabberd_auth_pam |
%% ejabberd_auth_storage | atom().
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
%% @spec () -> term()
start() ->
?DEBUG("About to start auth modules. Hosts: ~p", [?MYHOSTS]),
lists:foreach(fun start/1, ?MYHOSTS).
lists:foreach(
fun(Host) ->
lists:foreach(
fun(M) ->
M:start(Host)
end, auth_modules(Host))
end, ?MYHOSTS).
start(Host) ->
start_modules(Host, auth_modules(Host)).
start_modules(Host, Modules) when is_list(Modules) ->
lists:foreach(fun (M) -> start_module(Host, M) end, Modules).
start_module(Host, Module) when is_atom(Module) ->
Module:start(Host).
stop_module(Host, Module) when is_atom(Module) ->
Module:stop(Host).
start_methods(Host, Methods) when is_list(Methods) ->
lists:foreach(fun (M) -> start_method(Host, M) end, Methods).
start_method(Host, Method) when is_atom(Method) ->
start_module(Host, module_name(Method)).
stop_method(Host, Method) when is_atom(Method) ->
stop_module(Host, module_name(Method)).
%% @spec (Server) -> bool()
%% Server = string()
plain_password_required(Server) when is_list(Server) ->
%% This is only executed by ejabberd_c2s for non-SASL auth client
plain_password_required(Server) ->
lists:any(
fun(M) ->
M:plain_password_required()
end, auth_modules(Server)).
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% @doc Check if the user and password can login in server.
store_type(Server) ->
lists:foldl(
fun(_, external) ->
external;
(M, scram) ->
case M:store_type() of
external ->
external;
_Else ->
scram
end;
(M, plain) ->
M:store_type()
end, plain, auth_modules(Server)).
check_password(User, Server, Password)
when is_list(User), is_list(Server), is_list(Password) ->
%% @doc Check if the user and password can login in 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, _Reason} -> false
false -> false
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% Digest = string()
%% DigestGen = function()
%% @doc Check if the user and password can login in server.
check_password(User, Server, Password, Digest, DigestGen)
when is_list(User), is_list(Server), is_list(Password),
is_list(Digest), is_function(DigestGen) ->
%% @spec (User::string(), Server::string(), Password::string(),
%% Digest::string(), DigestGen::function()) ->
%% true | false
check_password(User, Server, Password, Digest, DigestGen) ->
case check_password_with_authmodule(User, Server, Password,
Digest, DigestGen) of
{true, _AuthModule} -> true;
{false, _Reason} -> false
false -> false
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% {true, AuthModule} | {false, Reason::string()}
%% where
%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external
%% | ejabberd_auth_internal | ejabberd_auth_ldap
%% | ejabberd_auth_odbc | ejabberd_auth_pam
%% @doc Check if the user and password can login in server.
%% The user can login if at least an authentication method accepts the user
%% and the password.
%% The first authentication method that accepts the credentials is returned.
check_password_with_authmodule(User, Server, Password)
when is_list(User), is_list(Server), is_list(Password) ->
check_password_loop(auth_modules(Server), [User, Server, Password], "").
%% @spec (User::string(), Server::string(), Password::string()) ->
%% {true, AuthModule} | false
%% where
%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external
%% | 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]).
%% @spec (User, Server, Password, Digest, DigestGen) -> {true, AuthModule} | false
%% User = string()
%% Server = string()
%% Password = string() | undefined
%% Digest = string() | undefined
%% DigestGen = function()
%% AuthModule = authmodule()
%% @doc Check the password is valid and also return the authentication module that accepts it.
%% The password is 'undefined' if the client
%% authenticates using the digest method as defined in
%% XEP-0078: Non-SASL Authentication
check_password_with_authmodule(User, Server, Password, Digest, DigestGen)
when is_list(User), is_list(Server), (is_list(Password) orelse Password == 'undefined'),
is_function(DigestGen), (is_list(Digest) orelse Digest == 'undefined')->
check_password_with_authmodule(User, Server, Password, Digest, DigestGen) ->
check_password_loop(auth_modules(Server), [User, Server, Password,
Digest, DigestGen], "").
Digest, DigestGen]).
check_password_loop([], _Args, LastReason) ->
{false, LastReason};
check_password_loop([AuthModule | AuthModules], Args, PreviousReason) ->
check_password_loop([], _Args) ->
false;
check_password_loop([AuthModule | AuthModules], Args) ->
case apply(AuthModule, check_password, Args) of
true ->
{true, AuthModule};
{false, Reason} when Reason /= "" ->
check_password_loop(AuthModules, Args, Reason);
{false, ""} ->
check_password_loop(AuthModules, Args, PreviousReason);
false ->
check_password_loop(AuthModules, Args, PreviousReason)
check_password_loop(AuthModules, Args)
end.
%% @spec (User, Server, Password) -> ok | {error, ErrorType}
%% User = string()
%% Server = string()
%% Password = string()
%% ErrorType = empty_password | not_allowed | invalid_jid
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, ErrorType}
%% where ErrorType = empty_password | not_allowed | invalid_jid
set_password(_User, _Server, "") ->
%% We do not allow empty password
{error, empty_password};
set_password(User, Server, Password)
when is_list(User), is_list(Server), is_list(Password) ->
set_password(User, Server, Password) ->
lists:foldl(
fun(M, {error, _}) ->
M:set_password(User, Server, Password);
@@ -201,71 +155,49 @@ set_password(User, Server, Password)
end, {error, not_allowed}, auth_modules(Server)).
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string() | nil()
try_register(_User, _Server, "") ->
%% We do not allow empty password
{error, not_allowed};
try_register(User, Server, Password)
when is_list(User), is_list(Server), is_list(Password) ->
case is_user_exists(User, Server) of
{error, not_allowed};
try_register(User, Server, Password) ->
case is_user_exists(User,Server) of
true ->
{atomic, exists};
false ->
case ?IS_MY_HOST(exmpp_stringprep:nameprep(Server)) of
case lists:member(jlib:nameprep(Server), ?MYHOSTS) of
true ->
Res = lists:foldl(
fun (_M, {atomic, ok} = Res) ->
Res;
(M, _) ->
M:try_register(User, Server, Password)
end, {error, not_allowed}, auth_modules(Server)),
trigger_register_hooks(Res, User, Server);
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;
false ->
{error, not_allowed}
end
end.
trigger_register_hooks({atomic, ok} = Res, User, Server) ->
ejabberd_hooks:run(register_user, list_to_binary(Server),
[User, Server]),
Res;
trigger_register_hooks(Res, _User, _Server) ->
Res.
%% @spec () -> [{LUser, LServer}]
%% LUser = string()
%% LServer = string()
%% @doc Registered users list do not include anonymous users logged.
%% Registered users list do not include anonymous users logged
dirty_get_registered_users() ->
lists:flatmap(
fun(M) ->
M:dirty_get_registered_users()
end, auth_modules()).
%% @spec (Server) -> [{LUser, LServer}]
%% Server = string()
%% LUser = string()
%% LServer = string()
%% @doc Registered users list do not include anonymous users logged.
get_vh_registered_users(Server) when is_list(Server) ->
%% Registered users list do not include anonymous users logged
get_vh_registered_users(Server) ->
lists:flatmap(
fun(M) ->
M:get_vh_registered_users(Server)
end, auth_modules(Server)).
%% @spec (Server, Opts) -> [{LUser, LServer}]
%% Server = string()
%% Opts = [{Opt, Val}]
%% Opt = atom()
%% Val = term()
%% LUser = string()
%% LServer = string()
get_vh_registered_users(Server, Opts) when is_list(Server) ->
get_vh_registered_users(Server, Opts) ->
lists:flatmap(
fun(M) ->
case erlang:function_exported(
@@ -277,11 +209,7 @@ get_vh_registered_users(Server, Opts) when is_list(Server) ->
end
end, auth_modules(Server)).
%% @spec (Server) -> Users_Number
%% Server = string()
%% Users_Number = integer()
get_vh_registered_users_number(Server) when is_list(Server) ->
get_vh_registered_users_number(Server) ->
lists:sum(
lists:map(
fun(M) ->
@@ -294,14 +222,7 @@ get_vh_registered_users_number(Server) when is_list(Server) ->
end
end, auth_modules(Server))).
%% @spec (Server, Opts) -> Users_Number
%% Server = string()
%% Opts = [{Opt, Val}]
%% Opt = atom()
%% Val = term()
%% Users_Number = integer()
get_vh_registered_users_number(Server, Opts) when is_list(Server) ->
get_vh_registered_users_number(Server, Opts) ->
lists:sum(
lists:map(
fun(M) ->
@@ -314,13 +235,9 @@ get_vh_registered_users_number(Server, Opts) when is_list(Server) ->
end
end, auth_modules(Server))).
%% @spec (User, Server) -> Password | false
%% User = string()
%% Server = string()
%% Password = string()
%% @doc Get the password of the user.
get_password(User, Server) when is_list(User), is_list(Server) ->
%% @spec (User::string(), Server::string()) -> Password::string()
get_password(User, Server) ->
lists:foldl(
fun(M, false) ->
M:get_password(User, Server);
@@ -328,29 +245,20 @@ get_password(User, Server) when is_list(User), is_list(Server) ->
Password
end, false, auth_modules(Server)).
%% @spec (User, Server) -> Password | nil()
%% User = string()
%% Server = string()
%% Password = string()
%% @doc Get the password of the user.
get_password_s(User, Server) when is_list(User), is_list(Server) ->
get_password_s(User, Server) ->
case get_password(User, Server) of
false ->
"";
Password ->
Password
Password when is_list(Password) ->
Password;
_ ->
""
end.
%% @spec (User, Server) -> {Password, AuthModule} | {false, none}
%% User = string()
%% Server = string()
%% Password = string()
%% AuthModule = authmodule()
%% @doc Get the password of the user and the auth module.
get_password_with_authmodule(User, Server)
when is_list(User), is_list(Server) ->
%% @spec (User::string(), Server::string()) ->
%% {Password::string(), AuthModule::atom()} | {false, none}
get_password_with_authmodule(User, Server) ->
lists:foldl(
fun(M, {false, _}) ->
{M:get_password(User, Server), M};
@@ -358,13 +266,9 @@ get_password_with_authmodule(User, Server)
{Password, AuthModule}
end, {false, none}, auth_modules(Server)).
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
%% @doc Returns true if the user exists in the DB or if an anonymous
%% user is logged under the given name.
is_user_exists(User, Server) when is_list(User), is_list(Server) ->
%% Returns true if the user exists in the DB or if an anonymous user is logged
%% under the given name
is_user_exists(User, Server) ->
lists:any(
fun(M) ->
case M:is_user_exists(User, Server) of
@@ -379,15 +283,10 @@ is_user_exists(User, Server) when is_list(User), is_list(Server) ->
end
end, auth_modules(Server)).
%% @spec (Module, User, Server) -> true | false | maybe
%% Module = authmodule()
%% User = string()
%% Server = string()
%% @doc Check if the user exists in all authentications module except
%% the module passed as parameter.
is_user_exists_in_other_modules(Module, User, Server)
when is_list(User), is_list(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).
@@ -407,34 +306,23 @@ is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) ->
end.
%% @spec (User, Server) -> ok | error | {error, not_allowed}
%% User = string()
%% Server = string()
%% @spec (User, Server) -> ok
%% @doc Remove user.
%% TODO: Fix me: It always return ok even if there was some problem removing the user.
%% dialyzer warning
%% ejabberd_auth.erl:388: The variable _ can never match since previous clauses completely covered the type 'ok'
remove_user(User, Server) when is_list(User), is_list(Server) ->
R = lists:foreach(
fun(M) ->
M:remove_user(User, Server)
end, auth_modules(Server)),
ejabberd_hooks:run(remove_user, list_to_binary(exmpp_stringprep:nameprep(Server)),
[list_to_binary(User), list_to_binary(Server)]),
R.
%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
lists:foreach(
fun(M) ->
M:remove_user(User, Server)
end, auth_modules(Server)),
ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]),
ok.
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
%% User = string()
%% Server = string()
%% Password = string()
%% @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)
when is_list(User), is_list(Server), is_list(Password) ->
remove_user(User, Server, Password) ->
R = lists:foldl(
fun(_M, ok = Res) ->
Res;
@@ -442,8 +330,7 @@ remove_user(User, Server, Password)
M:remove_user(User, Server, Password)
end, error, auth_modules(Server)),
case R of
ok -> ejabberd_hooks:run(remove_user, list_to_binary(exmpp_stringprep:nameprep(Server)),
[list_to_binary(User), list_to_binary(Server)]);
ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]);
_ -> none
end,
R.
@@ -475,11 +362,8 @@ entropy(IOList) ->
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
%% @spec () -> [authmodule()]
%% @doc Return the lists of all the auth modules actually used in the
%% configuration.
%% Return the lists of all the auth modules actually used in the
%% configuration
auth_modules() ->
lists:usort(
lists:flatmap(
@@ -487,19 +371,13 @@ auth_modules() ->
auth_modules(Server)
end, ?MYHOSTS)).
%% @spec (Server) -> [authmodule()]
%% Server = string()
%% @doc Return the list of authenticated modules for a given host.
auth_modules(Server) when is_list(Server) ->
LServer = exmpp_stringprep:nameprep(Server),
Method = ejabberd_config:get_local_option({auth_method, ejabberd:normalize_host(LServer)}),
%% Return the list of authenticated modules for a given host
auth_modules(Server) ->
LServer = jlib:nameprep(Server),
Method = ejabberd_config:get_local_option({auth_method, LServer}),
Methods = if
Method == undefined -> [];
is_list(Method) -> Method;
is_atom(Method) -> [Method]
end,
[module_name(M) || M <- Methods].
module_name(Method) when is_atom(Method) ->
list_to_atom("ejabberd_auth_" ++ atom_to_list(Method)).
[list_to_atom("ejabberd_auth_" ++ atom_to_list(M)) || M <- Methods].
+54 -170
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -28,7 +28,6 @@
-author('mickael.remond@process-one.net').
-export([start/1,
stop/1,
allow_anonymous/1,
is_sasl_anonymous_enabled/1,
is_login_anonymous_enabled/1,
@@ -52,56 +51,34 @@
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0]).
-include_lib("exmpp/include/exmpp.hrl").
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(anonymous, {us, sid}).
%% @spec (Host) -> ok
%% Host = string()
%% @doc Create the anonymous table if at least one virtual host has
%% anonymous features enabled.
%% Register to login / logout events.
start(Host) when is_list(Host) ->
HostB = list_to_binary(Host),
%% Create the anonymous table if at least one virtual host has anonymous features enabled
%% Register to login / logout events
start(Host) ->
%% TODO: Check cluster mode
update_tables(),
mnesia:create_table(anonymous, [{ram_copies, [node()]},
{type, bag}, {local_content, true},
{attributes, record_info(fields, anonymous)}]),
mnesia:add_table_copy(anonymous, node(), ram_copies),
{type, bag},
{attributes, record_info(fields, anonymous)}]),
%% The hooks are needed to add / remove users from the anonymous tables
ejabberd_hooks:add(sm_register_connection_hook, HostB,
ejabberd_hooks:add(sm_register_connection_hook, Host,
?MODULE, register_connection, 100),
ejabberd_hooks:add(sm_remove_connection_hook, HostB,
ejabberd_hooks:add(sm_remove_connection_hook, Host,
?MODULE, unregister_connection, 100),
ok.
stop(Host) when is_list(Host) ->
HostB = list_to_binary(Host),
ejabberd_hooks:delete(sm_register_connection_hook, HostB,
?MODULE, register_connection, 100),
ejabberd_hooks:delete(sm_remove_connection_hook, HostB,
?MODULE, unregister_connection, 100),
ok.
%% @spec (Host) -> bool()
%% Host = string()
%% @doc Return true if anonymous is allowed for host or false otherwise.
allow_anonymous(Host) when is_list(Host) ->
%% Return true if anonymous is allowed for host or false otherwise
allow_anonymous(Host) ->
lists:member(?MODULE, ejabberd_auth:auth_modules(Host)).
%% @spec (Host) -> bool()
%% Host = string()
%% @doc Return true if anonymous mode is enabled and if anonymous
%% protocol is SASL anonymous.
%% protocol can be: sasl_anon|login_anon|both
is_sasl_anonymous_enabled(Host) when is_list(Host) ->
%% Return true if anonymous mode is enabled and if anonymous protocol is SASL
%% anonymous protocol can be: sasl_anon|login_anon|both
is_sasl_anonymous_enabled(Host) ->
case allow_anonymous(Host) of
false -> false;
true ->
@@ -112,13 +89,10 @@ is_sasl_anonymous_enabled(Host) when is_list(Host) ->
end
end.
%% @spec (Host) -> bool()
%% Host = string()
%% @doc Return true if anonymous login is enabled on the server.
%% Return true if anonymous login is enabled on the server
%% anonymous login can be use using standard authentication method (i.e. with
%% clients that do not support anonymous login)
is_login_anonymous_enabled(Host) when is_list(Host) ->
is_login_anonymous_enabled(Host) ->
case allow_anonymous(Host) of
false -> false;
true ->
@@ -129,12 +103,9 @@ is_login_anonymous_enabled(Host) when is_list(Host) ->
end
end.
%% @spec (Host) -> sasl_anon | login_anon | both
%% Host = string()
%% @doc Return the anonymous protocol to use: sasl_anon|login_anon|both.
%% Return the anonymous protocol to use: sasl_anon|login_anon|both
%% defaults to login_anon
anonymous_protocol(Host) when is_list(Host) ->
anonymous_protocol(Host) ->
case ejabberd_config:get_local_option({anonymous_protocol, Host}) of
sasl_anon -> sasl_anon;
login_anon -> login_anon;
@@ -142,26 +113,16 @@ anonymous_protocol(Host) when is_list(Host) ->
_Other -> sasl_anon
end.
%% @spec (Host) -> bool()
%% Host = string()
%% @doc Return true if multiple connections have been allowed in the
%% config file.
%% 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.
allow_multiple_connections(Host) when is_list(Host) ->
ejabberd_config:get_local_option({allow_multiple_connections, Host})
=:= true.
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
%% @doc Check if user exist in the anonymous database.
anonymous_user_exist(User, Server) when is_list(User), is_list(Server) ->
anonymous_user_exist(list_to_binary(User), list_to_binary(Server));
anonymous_user_exist(User, Server) when is_binary(User), is_binary(Server) ->
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
%% Check if user exist in the anonymus database
anonymous_user_exist(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({anonymous, US}) of
[] ->
@@ -170,75 +131,46 @@ anonymous_user_exist(User, Server) when is_binary(User), is_binary(Server) ->
true
end.
%% @spec (SID, LUser, LServer) -> term()
%% SID = term()
%% LUser = string()
%% LServer = string()
%% @doc Remove connection from Mnesia tables.
remove_connection(SID, LUser, LServer) when is_binary(LUser), is_binary(LServer) ->
%% Remove connection from Mnesia tables
remove_connection(SID, LUser, LServer) ->
US = {LUser, LServer},
F = fun() ->
mnesia:delete_object({anonymous, US, SID})
end,
mnesia:async_dirty(F).
mnesia:transaction(F).
%% @spec (SID, JID, Info) -> term()
%% SID = term()
%% JID = exmpp_jid:jid()
%% Info = [term()]
%% @doc Register connection.
register_connection(SID, JID, Info) when ?IS_JID(JID) ->
LUser = exmpp_jid:prep_node(JID),
LServer = exmpp_jid:prep_domain(JID),
case proplists:get_value(auth_module, Info) of
undefined ->
ok;
?MODULE ->
%% Register connection
register_connection(SID, #jid{luser = LUser, lserver = LServer}, Info) ->
AuthModule = xml:get_attr_s(auth_module, Info),
case AuthModule == ?MODULE of
true ->
ejabberd_hooks:run(register_user, LServer, [LUser, LServer]),
US = {LUser, LServer},
mnesia:async_dirty(
mnesia:sync_dirty(
fun() -> mnesia:write(#anonymous{us = US, sid=SID})
end);
_ ->
ok
false ->
ok
end.
%% @spec (SID, JID, Ignored) -> term()
%% SID = term()
%% JID = exmpp_jid:jid()
%% Ignored = term()
%% @doc Remove an anonymous user from the anonymous users table.
unregister_connection(SID, JID, _) when ?IS_JID(JID) ->
LUser = exmpp_jid:prep_node(JID),
LServer = exmpp_jid:prep_domain(JID),
%% Remove an anonymous user from the anonymous users table
unregister_connection(SID, #jid{luser = LUser, lserver = LServer}, _) ->
purge_hook(anonymous_user_exist(LUser, LServer),
LUser, LServer),
remove_connection(SID, LUser, LServer).
%% @spec (bool(), LUser, LServer) -> term()
%% LUser = string()
%% LServer = string()
%% @doc Launch the hook to purge user data only for anonymous users.
%% Launch the hook to purge user data only for anonymous users
purge_hook(false, _LUser, _LServer) ->
ok;
purge_hook(true, LUser, LServer) when is_binary(LUser), is_binary(LServer) ->
purge_hook(true, LUser, LServer) ->
ejabberd_hooks:run(anonymous_purge_hook, LServer, [LUser, LServer]).
%% ---------------------------------
%% Specific anonymous auth functions
%% ---------------------------------
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% @doc When anonymous login is enabled, check the password for
%% permenant users before allowing access.
%% When anonymous login is enabled, check the password for permenant users
%% before allowing access
check_password(User, Server, Password) ->
check_password(User, Server, Password, undefined, undefined).
check_password(User, Server, _Password, _Digest, _DigestGen) ->
@@ -253,10 +185,6 @@ check_password(User, Server, _Password, _Digest, _DigestGen) ->
false -> login(User, Server)
end.
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
login(User, Server) ->
case is_login_anonymous_enabled(Server) of
false -> false;
@@ -271,13 +199,8 @@ login(User, Server) ->
end
end.
%% @spec (User, Server, Password) -> ok | {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
%% @doc When anonymous login is enabled, check that the user is
%% permanent before changing its password.
%% When anonymous login is enabled, check that the user is permanent before
%% changing its password
set_password(User, Server, _Password) ->
case anonymous_user_exist(User, Server) of
true ->
@@ -286,41 +209,22 @@ set_password(User, Server, _Password) ->
{error, not_allowed}
end.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
%% @doc When anonymous login is enabled, check if permanent users are
%% allowed on the server:
%% When anonymous login is enabled, check if permanent users are allowed on
%% the server:
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec () -> nil()
dirty_get_registered_users() ->
[].
%% @spec (Server) -> nil()
%% Server = string()
get_vh_registered_users(Server) ->
[{U, S} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(list_to_binary(Server))].
[{U, S} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(Server)].
%% @spec (User, Server) -> Password | false
%% User = string()
%% Server = string()
%% Password = nil()
%% @doc Return password of permanent user or false for anonymous users.
%% Return password of permanent user or false for anonymous users
get_password(User, Server) ->
get_password(User, Server, "").
%% @spec (User, Server, DefaultValue) -> DefaultValue | false
%% User = string()
%% Server = string()
%% DefaultValue = string()
get_password(User, Server, DefaultValue) ->
case anonymous_user_exist(User, Server) or login(User, Server) of
%% We return the default value if the user is anonymous
@@ -331,39 +235,19 @@ get_password(User, Server, DefaultValue) ->
false
end.
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
%% @doc Returns true if the user exists in the DB or if an anonymous
%% user is logged under the given name.
%% Returns true if the user exists in the DB or if an anonymous user is logged
%% under the given name
is_user_exists(User, Server) ->
anonymous_user_exist(User, Server).
%% @spec (User, Server) -> {error, not_allowed}
%% User = string()
%% Server = string()
remove_user(_User, _Server) ->
{error, not_allowed}.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
remove_user(_User, _Server, _Password) ->
not_allowed.
%% @spec () -> bool()
plain_password_required() ->
false.
update_tables() ->
case catch mnesia:table_info(anonymous, local_content) of
false ->
mnesia:delete_table(anonymous);
_ ->
ok
end.
store_type() ->
plain.
+45 -105
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -29,7 +29,6 @@
%% External exports
-export([start/1,
stop/1,
set_password/3,
check_password/3,
check_password/5,
@@ -44,6 +43,7 @@
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0
]).
@@ -52,25 +52,12 @@
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
%% @spec (Host) -> ok
%% Host = string()
start(Host) ->
extauth:start(
Host, ejabberd_config:get_local_option({extauth_program, Host})),
case check_cache_last_options(Host) of
cache ->
ok = ejabberd_auth_storage:start(Host);
no_cache ->
ok
end.
stop(Host) ->
extauth:stop(Host),
case check_cache_last_options(Host) of
cache ->
ok = ejabberd_auth_storage:stop(Host);
ok = ejabberd_auth_internal:start(Host);
no_cache ->
ok
end.
@@ -89,15 +76,11 @@ check_cache_last_options(Server) ->
end
end.
%% @spec () -> bool()
plain_password_required() ->
true.
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
store_type() ->
external.
check_password(User, Server, Password) ->
case get_cache_option(Server) of
@@ -105,77 +88,44 @@ check_password(User, Server, Password) ->
{true, CacheTime} -> check_password_cache(User, Server, Password, CacheTime)
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% Digest = string()
%% DigestGen = function()
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password).
%% @spec (User, Server, Password) -> ok | {error, unknown_problem}
%% User = string()
%% Server = string()
%% Password = string()
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
true -> set_password_storage(User, Server, Password),
true -> set_password_internal(User, Server, Password),
ok;
_ -> {error, unknown_problem}
end.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
try_register(User, Server, Password) ->
case get_cache_option(Server) of
false -> try_register_extauth(User, Server, Password);
{true, _CacheTime} -> try_register_external_cache(User, Server, Password)
end.
%% @spec () -> nil()
%% @todo Write it.
%% @doc Return the list of all users handled by external.
dirty_get_registered_users() ->
ejabberd_auth_storage:dirty_get_registered_users().
ejabberd_auth_internal:dirty_get_registered_users().
get_vh_registered_users(Server) ->
ejabberd_auth_storage:get_vh_registered_users(Server).
ejabberd_auth_internal:get_vh_registered_users(Server).
get_vh_registered_users(Server, Data) ->
ejabberd_auth_storage:get_vh_registered_users(Server, Data).
%% @spec (Server) -> nil()
%% Server = string()
ejabberd_auth_internal:get_vh_registered_users(Server, Data).
get_vh_registered_users_number(Server) ->
ejabberd_auth_storage:get_vh_registered_users_number(Server).
ejabberd_auth_internal:get_vh_registered_users_number(Server).
get_vh_registered_users_number(Server, Data) ->
ejabberd_auth_storage:get_vh_registered_users_number(Server, Data).
ejabberd_auth_internal:get_vh_registered_users_number(Server, Data).
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
%% @doc Get the user cached password, if possible.
%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
get_password(User, Server) ->
case get_cache_option(Server) of
false -> false;
{true, CacheTime} -> get_password_cache(User, Server, CacheTime)
end.
%% @spec (User, Server) -> nil()
%% User = string()
%% Server = string()
get_password_s(User, Server) ->
case get_password(User, Server) of
false -> [];
@@ -183,9 +133,6 @@ get_password_s(User, Server) ->
end.
%% @spec (User, Server) -> true | false | {error, Error}
%% User = string()
%% Server = string()
is_user_exists(User, Server) ->
try extauth:is_user_exists(User, Server) of
Res -> Res
@@ -193,10 +140,6 @@ is_user_exists(User, Server) ->
_:Error -> {error, Error}
end.
%% @spec (User, Server) -> {error, not_allowed}
%% User = string()
%% Server = string()
remove_user(User, Server) ->
case extauth:remove_user(User, Server) of
false -> false;
@@ -204,15 +147,10 @@ remove_user(User, Server) ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_storage:remove_user(User, Server)
ejabberd_auth_internal:remove_user(User, Server)
end
end.
%% @spec (User, Server, Password) -> not_allowed
%% User = string()
%% Server = string()
%% Password = string()
remove_user(User, Server, Password) ->
case extauth:remove_user(User, Server, Password) of
false -> false;
@@ -220,7 +158,7 @@ remove_user(User, Server, Password) ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_storage:remove_user(User, Server, Password)
ejabberd_auth_internal:remove_user(User, Server, Password)
end
end.
@@ -246,7 +184,7 @@ try_register_extauth(User, Server, Password) ->
check_password_cache(User, Server, Password, CacheTime) ->
case get_last_access(User, Server) of
online ->
check_password_storage(User, Server, Password);
check_password_internal(User, Server, Password);
never ->
check_password_external_cache(User, Server, Password);
mod_last_required ->
@@ -257,7 +195,7 @@ check_password_cache(User, Server, Password, CacheTime) ->
case is_fresh_enough(TimeStamp, CacheTime) of
%% If no need to refresh, check password against Mnesia
true ->
case check_password_storage(User, Server, Password) of
case check_password_internal(User, Server, Password) of
%% If password valid in Mnesia, accept it
true ->
true;
@@ -271,14 +209,14 @@ check_password_cache(User, Server, Password, CacheTime) ->
end
end.
get_password_storage(User, Server) ->
ejabberd_auth_storage:get_password(User, Server).
get_password_internal(User, Server) ->
ejabberd_auth_internal:get_password(User, Server).
%% @spec (User, Server, CacheTime) -> Password::string() | false
%% @spec (User, Server, CacheTime) -> false | Password::string()
get_password_cache(User, Server, CacheTime) ->
case get_last_access(User, Server) of
online ->
get_password_storage(User, Server);
get_password_internal(User, Server);
never ->
false;
mod_last_required ->
@@ -287,7 +225,7 @@ get_password_cache(User, Server, CacheTime) ->
TimeStamp ->
case is_fresh_enough(TimeStamp, CacheTime) of
true ->
get_password_storage(User, Server);
get_password_internal(User, Server);
false ->
false
end
@@ -298,7 +236,7 @@ get_password_cache(User, Server, CacheTime) ->
check_password_external_cache(User, Server, Password) ->
case check_password_extauth(User, Server, Password) of
true ->
set_password_storage(User, Server, Password), true;
set_password_internal(User, Server, Password), true;
false ->
false
end.
@@ -307,18 +245,18 @@ check_password_external_cache(User, Server, Password) ->
try_register_external_cache(User, Server, Password) ->
case try_register_extauth(User, Server, Password) of
{atomic, ok} = R ->
set_password_storage(User, Server, Password),
set_password_internal(User, Server, Password),
R;
_ -> {error, not_allowed}
end.
%% @spec (User, Server, Password) -> true | false
check_password_storage(User, Server, Password) ->
ejabberd_auth_storage:check_password(User, Server, Password).
check_password_internal(User, Server, Password) ->
ejabberd_auth_internal:check_password(User, Server, Password).
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
set_password_storage(User, Server, Password) ->
ejabberd_auth_storage:set_password(User, Server, Password).
set_password_internal(User, Server, Password) ->
ejabberd_auth_internal:set_password(User, Server, Password).
%% @spec (TimeLast, CacheTime) -> true | false
%% TimeLast = online | never | integer()
@@ -332,13 +270,11 @@ is_fresh_enough(TimeStampLast, CacheTime) ->
Now = MegaSecs * 1000000 + Secs,
(TimeStampLast + CacheTime > Now).
%% @spec (User, Server) -> TimeStamp::integer() | online | never | mod_last_required
get_last_access(UserS, ServerS) ->
%% Code copied from mod_configure.erl
%% Code copied from web/ejabberd_web_admin.erl
%% TODO: Update time format to XEP-0202: Entity Time
User = list_to_binary(UserS),
Server = list_to_binary(ServerS),
%% @spec (User, Server) -> online | never | mod_last_required | TimeStamp::integer()
%% Code copied from mod_configure.erl
%% Code copied from web/ejabberd_web_admin.erl
%% TODO: Update time format to XEP-0202: Entity Time
get_last_access(User, Server) ->
case ejabberd_sm:get_user_resources(User, Server) of
[] ->
_US = {User, Server},
@@ -357,23 +293,27 @@ get_last_access(UserS, ServerS) ->
get_last_info(User, Server) ->
case get_mod_last_enabled(Server) of
mod_last -> mod_last:get_last_info(User, Server);
mod_last_odbc -> mod_last_odbc:get_last_info(User, Server);
no_mod_last -> mod_last_required
end.
%% @spec (Server) -> mod_last | no_mod_last
get_mod_last_enabled(ServerB) when is_binary(ServerB)->
Server = binary_to_list(ServerB),
get_mod_last_enabled(Server);
%% @spec (Server) -> mod_last | mod_last_odbc | no_mod_last
get_mod_last_enabled(Server) ->
case gen_mod:is_loaded(Server, mod_last) of
true -> mod_last;
false -> no_mod_last
ML = gen_mod:is_loaded(Server, mod_last),
MLO = gen_mod:is_loaded(Server, mod_last_odbc),
case {ML, MLO} of
{true, _} -> mod_last;
{false, true} -> mod_last_odbc;
{false, false} -> no_mod_last
end.
get_mod_last_configured(Server) ->
case is_configured(Server, mod_last) of
true -> mod_last;
false -> no_mod_last
ML = is_configured(Server, mod_last),
MLO = is_configured(Server, mod_last_odbc),
case {ML, MLO} of
{true, _} -> mod_last;
{false, true} -> mod_last_odbc;
{false, false} -> no_mod_last
end.
is_configured(Host, Module) ->
+470
View File
@@ -0,0 +1,470 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_auth_internal.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Authentification via mnesia
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2012 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_auth_internal).
-author('alexey@process-one.net').
%% External exports
-export([start/1,
set_password/3,
check_password/3,
check_password/5,
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2,
get_password/2,
get_password_s/2,
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0
]).
-include("ejabberd.hrl").
-record(passwd, {us, password}).
-record(reg_users_counter, {vhost, count}).
-define(SALT_LENGTH, 16).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
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),
maybe_alert_password_scrammed_without_option(),
ok.
update_reg_users_counter_table(Server) ->
Set = get_vh_registered_users(Server),
Size = length(Set),
LServer = jlib:nameprep(Server),
F = fun() ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = Size})
end,
mnesia:sync_dirty(F).
plain_password_required() ->
case is_scrammed() of
false -> false;
true -> true
end.
store_type() ->
case is_scrammed() of
false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
true -> scram %% allows: PLAIN SCRAM
end.
check_password(User, Server, Password) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[#passwd{password = Password}] when is_list(Password) ->
Password /= "";
[#passwd{password = Scram}] when is_record(Scram, scram) ->
is_password_scram_valid(Password, Scram);
_ ->
false
end.
check_password(User, Server, Password, Digest, DigestGen) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[#passwd{password = Passwd}] when is_list(Passwd) ->
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
true ->
false
end,
if DigRes ->
true;
true ->
(Passwd == Password) and (Password /= "")
end;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
Passwd = base64:decode(Scram#scram.storedkey),
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
true ->
false
end,
if DigRes ->
true;
true ->
(Passwd == Password) and (Password /= "")
end;
_ ->
false
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
if
(LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
F = fun() ->
Password2 = case is_scrammed() and is_list(Password) of
true -> password_to_scram(Password);
false -> Password
end,
mnesia:write(#passwd{us = US,
password = Password2})
end,
{atomic, ok} = mnesia:transaction(F),
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),
US = {LUser, LServer},
if
(LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
F = fun() ->
case mnesia:read({passwd, US}) of
[] ->
Password2 = case is_scrammed() and is_list(Password) of
true -> password_to_scram(Password);
false -> Password
end,
mnesia:write(#passwd{us = US,
password = Password2}),
mnesia:dirty_update_counter(
reg_users_counter,
LServer, 1),
ok;
[_E] ->
exists
end
end,
mnesia:transaction(F)
end.
%% Get all registered users in Mnesia
dirty_get_registered_users() ->
mnesia:dirty_all_keys(passwd).
get_vh_registered_users(Server) ->
LServer = jlib:nameprep(Server),
mnesia:dirty_select(
passwd,
[{#passwd{us = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, LServer}],
['$1']}]).
get_vh_registered_users(Server, [{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
get_vh_registered_users(Server, [{limit, End-Start+1}, {offset, Start}]);
get_vh_registered_users(Server, [{limit, Limit}, {offset, Offset}])
when is_integer(Limit) and is_integer(Offset) ->
case get_vh_registered_users(Server) of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_vh_registered_users(Server, [{prefix, Prefix}])
when is_list(Prefix) ->
Set = [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)],
lists:keysort(1, Set);
get_vh_registered_users(Server, [{prefix, Prefix}, {from, Start}, {to, End}])
when is_list(Prefix) and is_integer(Start) and is_integer(End) ->
get_vh_registered_users(Server, [{prefix, Prefix}, {limit, End-Start+1}, {offset, Start}]);
get_vh_registered_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_list(Prefix) and is_integer(Limit) and is_integer(Offset) ->
case [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)] of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
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.
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)],
length(Set);
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
get_password(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read(passwd, US) of
[#passwd{password = Password}] when is_list(Password) ->
Password;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
{base64:decode(Scram#scram.storedkey),
base64:decode(Scram#scram.serverkey),
base64:decode(Scram#scram.salt),
Scram#scram.iterationcount};
_ ->
false
end.
get_password_s(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read(passwd, US) of
[#passwd{password = Password}] when is_list(Password) ->
Password;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
[];
_ ->
[]
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[] ->
false;
[_] ->
true;
Other ->
{error, Other}
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}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1)
end,
mnesia:transaction(F),
ok.
%% @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),
US = {LUser, LServer},
F = fun() ->
case mnesia:read({passwd, US}) of
[#passwd{password = Password}] when is_list(Password) ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1),
ok;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
case is_password_scram_valid(Password, Scram) of
true ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1),
ok;
false ->
not_allowed
end;
_ ->
not_exists
end
end,
case mnesia:transaction(F) of
{atomic, ok} ->
ok;
{atomic, Res} ->
Res;
_ ->
bad_request
end.
update_table() ->
Fields = record_info(fields, passwd),
case mnesia:table_info(passwd, attributes) of
Fields ->
maybe_scram_passwords(),
ok;
[user, password] ->
?INFO_MSG("Converting passwd table from "
"{user, password} format", []),
Host = ?MYNAME,
{atomic, ok} = mnesia:create_table(
ejabberd_auth_internal_tmp_table,
[{disc_only_copies, [node()]},
{type, bag},
{local_content, true},
{record_name, passwd},
{attributes, record_info(fields, passwd)}]),
mnesia:transform_table(passwd, ignore, Fields),
F1 = fun() ->
mnesia:write_lock_table(ejabberd_auth_internal_tmp_table),
mnesia:foldl(
fun(#passwd{us = U} = R, _) ->
mnesia:dirty_write(
ejabberd_auth_internal_tmp_table,
R#passwd{us = {U, Host}})
end, ok, passwd)
end,
mnesia:transaction(F1),
mnesia:clear_table(passwd),
F2 = fun() ->
mnesia:write_lock_table(passwd),
mnesia:foldl(
fun(R, _) ->
mnesia:dirty_write(R)
end, ok, ejabberd_auth_internal_tmp_table)
end,
mnesia:transaction(F2),
mnesia:delete_table(ejabberd_auth_internal_tmp_table);
_ ->
?INFO_MSG("Recreating passwd table", []),
mnesia:transform_table(passwd, ignore, Fields)
end.
%%%
%%% SCRAM
%%%
%% The passwords are stored scrammed in the table either if the option says so,
%% or if at least the first password is scrammed.
is_scrammed() ->
OptionScram = is_option_scram(),
FirstElement = mnesia:dirty_read(passwd, mnesia:dirty_first(passwd)),
case {OptionScram, FirstElement} of
{true, _} ->
true;
{false, [#passwd{password = Scram}]} when is_record(Scram, scram) ->
true;
_ ->
false
end.
is_option_scram() ->
scram == ejabberd_config:get_local_option({auth_password_format, ?MYNAME}).
maybe_alert_password_scrammed_without_option() ->
case is_scrammed() andalso not is_option_scram() of
true ->
?ERROR_MSG("Some passwords were stored in the database as SCRAM, "
"but 'auth_password_format' is not configured 'scram'. "
"The option will now be considered to be 'scram'.", []);
false ->
ok
end.
maybe_scram_passwords() ->
case is_scrammed() of
true -> scram_passwords();
false -> ok
end.
scram_passwords() ->
?INFO_MSG("Converting the stored passwords into SCRAM bits", []),
Fun = fun(#passwd{password = Password} = P) ->
Scram = password_to_scram(Password),
P#passwd{password = Scram}
end,
Fields = record_info(fields, passwd),
mnesia:transform_table(passwd, Fun, Fields).
password_to_scram(Password) ->
password_to_scram(Password, ?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(Password, IterationCount) ->
Salt = crypto:rand_bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
#scram{storedkey = base64:encode(StoredKey),
serverkey = base64:encode(ServerKey),
salt = base64:encode(Salt),
iterationcount = IterationCount}.
is_password_scram_valid(Password, Scram) ->
IterationCount = Scram#scram.iterationcount,
Salt = base64:decode(Scram#scram.salt),
SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
(base64:decode(Scram#scram.storedkey) == StoredKey).
+82 -194
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -54,6 +54,7 @@
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0
]).
@@ -72,7 +73,9 @@
base,
uids,
ufilter,
sfilter,
lfilter, %% Local filter (performed by ejabberd, not LDAP)
deref_aliases,
dn_filter,
dn_filter_attrs
}).
@@ -94,89 +97,50 @@ handle_info(_Info, State) ->
%%% API
%%%----------------------------------------------------------------------
%% @spec (Host) -> term()
%% Host = string()
start(Host) ->
?DEBUG("Starting ~p for ~p.", [?MODULE, Host]),
case ejabberd_config:get_host_option(Host, ldap_servers) of
undefined -> check_bad_config(Host);
{host, _Host} -> ok;
_ ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
ChildSpec = {
Proc, {?MODULE, start_link, [Host]},
transient, 1000, worker, [?MODULE]
},
supervisor:start_child(ejabberd_sup, ChildSpec)
end.
check_bad_config(Host) ->
case ejabberd_config:get_local_option({ldap_servers, Host}) of
undefined ->
?ERROR_MSG("Can't start ~p for host ~p: missing ldap_servers configuration",
[?MODULE, Host]),
{error, bad_config};
_ -> ok
end.
%% @spec (Host) -> term()
%% Host = string()
Proc = gen_mod:get_module_proc(Host, ?MODULE),
ChildSpec = {
Proc, {?MODULE, start_link, [Host]},
transient, 1000, worker, [?MODULE]
},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
case ejabberd_config:get_host_option(Host, ldap_servers) of
undefined -> ok;
{host, _Host} -> ok;
_ ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc)
end.
%% @spec (Host) -> term()
%% Host = string()
Proc = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
start_link(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:start_link({local, Proc}, ?MODULE, Host, []).
%% @hidden
terminate(_Reason, _State) ->
ok.
%% @spec (Host) -> {ok, State}
%% Host = string()
%% State = term()
init(Host) ->
State = parse_options(Host),
eldap_pool:start_link(State#state.eldap_id,
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.tls_options),
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.tls_options),
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.tls_options),
State#state.servers,
State#state.backups,
State#state.port,
State#state.dn,
State#state.password,
State#state.tls_options),
{ok, State}.
%% @spec () -> true
plain_password_required() ->
true.
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
store_type() ->
external.
check_password(User, Server, Password) ->
%% In LDAP spec: empty password means anonymous authentication.
@@ -191,25 +155,12 @@ check_password(User, Server, Password) ->
end
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% Digest = string()
%% DigestGen = function()
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password).
%% @spec (User, Server, Password) -> {error, Reason} | ok
%% User = string()
%% Server = string()
%% Password = string()
%% Reason = term()
set_password(User, Server, Password) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, Server, State) of
case find_user_dn(User, State) of
false ->
{error, user_not_found};
DN ->
@@ -217,17 +168,9 @@ set_password(User, Server, Password) ->
end.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec () -> [{LUser, LServer}]
%% LUser = string()
%% LServer = string()
dirty_get_registered_users() ->
Servers = ejabberd_config:get_vh_by_auth_method(ldap),
lists:flatmap(
@@ -235,42 +178,22 @@ dirty_get_registered_users() ->
get_vh_registered_users(Server)
end, Servers).
%% @spec (Server) -> [{LUser, LServer}]
%% Server = string()
%% LUser = string()
%% LServer = string()
get_vh_registered_users(Server) ->
case catch get_vh_registered_users_ldap(Server) of
{'EXIT', _} -> [];
Result -> Result
end.
%% @spec (Server) -> Users_Number
%% Server = string()
%% Users_Number = integer()
get_vh_registered_users_number(Server) ->
length(get_vh_registered_users(Server)).
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
get_password(_User, _Server) ->
false.
%% @spec (User, Server) -> nil()
%% User = string()
%% Server = string()
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
%% User = string()
%% Server = string()
is_user_exists(User, Server) ->
case catch is_user_exists_ldap(User, Server) of
{'EXIT', Error} ->
@@ -279,33 +202,18 @@ is_user_exists(User, Server) ->
Result
end.
%% @spec (User, Server) -> {error, not_allowed}
%% User = string()
%% Server = string()
remove_user(_User, _Server) ->
{error, not_allowed}.
%% @spec (User, Server, Password) -> not_allowed
%% User = string()
%% Server = string()
%% Password = string()
remove_user(_User, _Server, _Password) ->
not_allowed.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
check_password_ldap(User, Server, Password) ->
{ok, State} = get_state(Server),
case find_user_dn(User, Server, State) of
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of
false ->
false;
DN ->
@@ -313,44 +221,27 @@ check_password_ldap(User, Server, Password) ->
ok -> true;
_ -> false
end
end.
%% We need an ?MODULE server state to use for queries. This will
%% either be Server if this is a statically configured host or the
%% Server for a different host if this is a dynamically configured
%% vhost.
%% The {ldap_vhost, Server} -> Host. ejabberd config option specifies
%% which actual ?MODULE server to use for a particular Host. The value
%% of the option if it is defined or Server by default.
get_state(Server) ->
Host = case ejabberd_config:get_local_option({ldap_servers, Server}) of
{host, H} -> H;
_ -> Server
end,
eldap_utils:get_state(Host, ?MODULE).
%% @spec (Server) -> [{LUser, LServer}]
%% Server = string()
%% LUser = string()
%% LServer = string()
end.
get_vh_registered_users_ldap(Server) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
UIDs = eldap_utils:uids_domain_subst(Server, State#state.uids),
UIDs = State#state.uids,
Eldap_ID = State#state.eldap_id,
SearchFilter = build_sfilter(State, UIDs),
Server = State#state.host,
ResAttrs = result_attrs(State),
case eldap_filter:parse(SearchFilter) of
case eldap_filter:parse(State#state.sfilter) of
{ok, EldapFilter} ->
case eldap_pool:search(Eldap_ID, [{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{attributes, ResAttrs}]) of
case eldap_pool:search(Eldap_ID,
[{base, State#state.base},
{filter, EldapFilter},
{timeout, ?LDAP_SEARCH_TIMEOUT},
{deref_aliases, State#state.deref_aliases},
{attributes, ResAttrs}]) of
#eldap_search_result{entries = Entries} ->
lists:flatmap(
fun(#eldap_entry{attributes = Attrs,
object_name = DN}) ->
case is_valid_dn(DN, Server, Attrs, State) of
case is_valid_dn(DN, Attrs, State) of
false -> [];
_ ->
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
@@ -358,11 +249,9 @@ get_vh_registered_users_ldap(Server) ->
{User, UIDFormat} ->
case eldap_utils:get_user_part(User, UIDFormat) of
{ok, U} ->
try
[{exmpp_stringprep:nodeprep(U), exmpp_stringprep:nameprep(Server)}]
catch
_ ->
[]
case jlib:nodeprep(U) of
error -> [];
LU -> [{LU, jlib:nameprep(Server)}]
end;
_ -> []
end
@@ -376,13 +265,9 @@ get_vh_registered_users_ldap(Server) ->
[]
end.
%% @spec (User, Server) -> bool()
%% User = string()
%% Server = string()
is_user_exists_ldap(User, Server) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, Server, State) of
case find_user_dn(User, State) of
false -> false;
_DN -> true
end.
@@ -396,17 +281,18 @@ handle_call(stop, _From, State) ->
handle_call(_Request, _From, State) ->
{reply, bad_request, State}.
find_user_dn(User, Server, State) ->
find_user_dn(User, State) ->
ResAttrs = result_attrs(State),
UserFilter = build_ufilter(State, Server),
case eldap_filter:parse(UserFilter, [{"%u", User}]) of
case eldap_filter:parse(State#state.ufilter, [{"%u", User}]) of
{ok, Filter} ->
case eldap_pool:search(State#state.eldap_id, [{base, State#state.base},
{filter, Filter},
{attributes, ResAttrs}]) of
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, Filter},
{deref_aliases, State#state.deref_aliases},
{attributes, ResAttrs}]) of
#eldap_search_result{entries = [#eldap_entry{attributes = Attrs,
object_name = DN} | _]} ->
dn_filter(DN, Server, Attrs, State);
dn_filter(DN, Attrs, State);
_ ->
false
end;
@@ -415,20 +301,20 @@ find_user_dn(User, Server, State) ->
end.
%% apply the dn filter and the local filter:
dn_filter(DN, Server, Attrs, State) ->
dn_filter(DN, Attrs, State) ->
%% Check if user is denied access by attribute value (local check)
case check_local_filter(Attrs, State) of
false -> false;
true -> is_valid_dn(DN, Server, Attrs, State)
true -> is_valid_dn(DN, Attrs, State)
end.
%% Check that the DN is valid, based on the dn filter
is_valid_dn(DN, _, _, #state{dn_filter = undefined}) ->
is_valid_dn(DN, _, #state{dn_filter = undefined}) ->
DN;
is_valid_dn(DN, Server, Attrs, State) ->
is_valid_dn(DN, Attrs, State) ->
DNAttrs = State#state.dn_filter_attrs,
UIDs = eldap_utils:uids_domain_subst(Server, State#state.uids),
UIDs = State#state.uids,
Values = [{"%s", eldap_utils:get_ldap_attr(Attr, Attrs), 1} || Attr <- DNAttrs],
SubstValues = case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
"" -> Values;
@@ -443,6 +329,7 @@ is_valid_dn(DN, Server, Attrs, State) ->
case eldap_pool:search(State#state.eldap_id,
[{base, State#state.base},
{filter, EldapFilter},
{deref_aliases, State#state.deref_aliases},
{attributes, ["dn"]}]) of
#eldap_search_result{entries = [_|_]} ->
DN;
@@ -483,22 +370,6 @@ result_attrs(#state{uids = UIDs, dn_filter_attrs = DNFilterAttrs}) ->
[UID | Acc]
end, DNFilterAttrs, UIDs).
build_ufilter(State, VHost) ->
UIDs = eldap_utils:uids_domain_subst(VHost, State#state.uids),
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
case State#state.ufilter of
"" -> SubFilter;
F -> "(&" ++ SubFilter ++ F ++ ")"
end.
build_sfilter(State, FormattedUIDs) ->
SubFilter = lists:flatten(eldap_utils:generate_subfilter(FormattedUIDs)),
UserFilter = case State#state.ufilter of
"" -> SubFilter;
F -> "(&" ++ SubFilter ++ F ++ ")"
end,
eldap_filter:do_sub(UserFilter, [{"%u", "*"}]).
%%%----------------------------------------------------------------------
%%% Auxiliary functions
%%%----------------------------------------------------------------------
@@ -512,6 +383,8 @@ parse_options(Host) ->
end,
LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}),
LDAPTLSVerify = ejabberd_config:get_local_option({ldap_tls_verify, Host}),
LDAPTLSCAFile = ejabberd_config:get_local_option({ldap_tls_cacertfile, Host}),
LDAPTLSDepth = ejabberd_config:get_local_option({ldap_tls_depth, Host}),
LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of
undefined -> case LDAPEncrypt of
tls -> ?LDAPS_PORT;
@@ -530,12 +403,17 @@ parse_options(Host) ->
end,
UIDs = case ejabberd_config:get_local_option({ldap_uids, Host}) of
undefined -> [{"uid", "%u"}];
UI -> UI
UI -> eldap_utils:uids_domain_subst(Host, UI)
end,
SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
UserFilter = case ejabberd_config:get_local_option({ldap_filter, Host}) of
undefined -> "";
F -> F
undefined -> SubFilter;
"" -> SubFilter;
F ->
eldap_utils:check_filter(F),
"(&" ++ SubFilter ++ F ++ ")"
end,
SearchFilter = eldap_filter:do_sub(UserFilter, [{"%u", "*"}]),
LDAPBase = ejabberd_config:get_local_option({ldap_base, Host}),
{DNFilter, DNFilterAttrs} =
case ejabberd_config:get_local_option({ldap_dn_filter, Host}) of
@@ -546,7 +424,13 @@ parse_options(Host) ->
{DNF, DNFA} ->
{DNF, DNFA}
end,
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
eldap_utils:check_filter(DNFilter),
LocalFilter = ejabberd_config:get_local_option({ldap_local_filter, Host}),
DerefAliases = case ejabberd_config:get_local_option(
{ldap_deref_aliases, Host}) of
undefined -> never;
Val -> Val
end,
#state{host = Host,
eldap_id = Eldap_ID,
bind_eldap_id = Bind_Eldap_ID,
@@ -554,13 +438,17 @@ parse_options(Host) ->
backups = LDAPBackups,
port = LDAPPort,
tls_options = [{encrypt, LDAPEncrypt},
{tls_verify, LDAPTLSVerify}],
{tls_verify, LDAPTLSVerify},
{tls_cacertfile, LDAPTLSCAFile},
{tls_depth, LDAPTLSDepth}],
dn = RootDN,
password = Password,
base = LDAPBase,
uids = UIDs,
ufilter = UserFilter,
sfilter = SearchFilter,
lfilter = LocalFilter,
deref_aliases = DerefAliases,
dn_filter = DNFilter,
dn_filter_attrs = DNFilterAttrs
}.
+285
View File
@@ -0,0 +1,285 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_auth_odbc.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Authentification via ODBC
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2012 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_auth_odbc).
-author('alexey@process-one.net').
%% External exports
-export([start/1,
set_password/3,
check_password/3,
check_password/5,
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2,
get_password/2,
get_password_s/2,
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0
]).
-include("ejabberd.hrl").
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(_Host) ->
ok.
plain_password_required() ->
false.
store_type() ->
plain.
%% @spec (User, Server, Password) -> true | false | {error, Error}
check_password(User, Server, Password) ->
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
{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
end
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> true | false | {error, Error}
check_password(User, Server, Password, Digest, DigestGen) ->
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
{selected, ["password"], [{Passwd}]} ->
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
true ->
false
end,
if DigRes ->
true;
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
end
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
{error, invalid_jid};
LUser ->
Username = ejabberd_odbc:escape(LUser),
Pass = ejabberd_odbc:escape(Password),
LServer = jlib:nameprep(Server),
case catch odbc_queries:set_password_t(LServer, Username, Pass) of
{atomic, ok} -> ok;
Other -> {error, Other}
end
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid}
try_register(User, Server, Password) ->
case jlib:nodeprep(User) of
error ->
{error, invalid_jid};
LUser ->
Username = ejabberd_odbc:escape(LUser),
Pass = ejabberd_odbc:escape(Password),
LServer = jlib:nameprep(Server),
case catch odbc_queries:add_user(LServer, Username, Pass) of
{updated, 1} ->
{atomic, ok};
_ ->
{atomic, exists}
end
end.
dirty_get_registered_users() ->
Servers = ejabberd_config:get_vh_by_auth_method(odbc),
lists:flatmap(
fun(Server) ->
get_vh_registered_users(Server)
end, Servers).
get_vh_registered_users(Server) ->
LServer = jlib:nameprep(Server),
case catch odbc_queries:list_users(LServer) of
{selected, ["username"], Res} ->
[{U, LServer} || {U} <- Res];
_ ->
[]
end.
get_vh_registered_users(Server, Opts) ->
LServer = jlib:nameprep(Server),
case catch odbc_queries:list_users(LServer, Opts) of
{selected, ["username"], Res} ->
[{U, LServer} || {U} <- Res];
_ ->
[]
end.
get_vh_registered_users_number(Server) ->
LServer = jlib:nameprep(Server),
case catch odbc_queries:users_number(LServer) of
{selected, [_], [{Res}]} ->
list_to_integer(Res);
_ ->
0
end.
get_vh_registered_users_number(Server, Opts) ->
LServer = jlib:nameprep(Server),
case catch odbc_queries:users_number(LServer, Opts) of
{selected, [_], [{Res}]} ->
list_to_integer(Res);
_Other ->
0
end.
get_password(User, Server) ->
case jlib:nodeprep(User) of
error ->
false;
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
case catch odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{Password}]} ->
Password;
_ ->
false
end
end.
get_password_s(User, Server) ->
case jlib:nodeprep(User) of
error ->
"";
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
case catch odbc_queries:get_password(LServer, Username) of
{selected, ["password"], [{Password}]} ->
Password;
_ ->
""
end
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
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
{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
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 ->
error;
LUser ->
Username = ejabberd_odbc:escape(LUser),
LServer = jlib:nameprep(Server),
catch odbc_queries:del_user(LServer, Username),
ok
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 ->
error;
LUser ->
Username = ejabberd_odbc:escape(LUser),
Pass = ejabberd_odbc:escape(Password),
LServer = jlib:nameprep(Server),
F = fun() ->
Result = odbc_queries:del_user_return_password(
LServer, Username, Pass),
case Result of
{selected, ["password"], [{Password}]} ->
ok;
{selected, ["password"], []} ->
not_exists;
_ ->
not_allowed
end
end,
{atomic, Result} = odbc_queries:sql_transaction(LServer, F),
Result
end.
+18 -83
View File
@@ -5,7 +5,7 @@
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -28,7 +28,6 @@
%% External exports
-export([start/1,
stop/1,
set_password/3,
check_password/3,
check_password/5,
@@ -40,16 +39,13 @@
is_user_exists/2,
remove_user/2,
remove_user/3,
store_type/0,
plain_password_required/0
]).
%%====================================================================
%% API
%%====================================================================
%% @spec (Host) -> ok | term()
%% Host = string()
start(_Host) ->
case epam:start() of
{ok, _} -> ok;
@@ -57,129 +53,68 @@ start(_Host) ->
Err -> Err
end.
%% TODO: Stop epam if no other auth_pam are running.
stop(_Host) ->
ok.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec (User, Server, Password, Digest, DigestGen) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% Digest = string()
%% DigestGen = function()
check_password(User, Server, Password, _StreamID, _Digest) ->
check_password(User, Server, Password, _Digest, _DigestGen) ->
check_password(User, Server, Password).
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
check_password(User, Server, Password) ->
Service = get_pam_service(Server),
UserInfo = case get_pam_userinfotype(Server) of
check_password(User, Host, Password) ->
Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of
username -> User;
jid -> User++"@"++Server
jid -> User++"@"++Host
end,
case catch epam:authenticate(Service, UserInfo, Password) of
true -> true;
_ -> false
end.
%% @spec (User, Server, Password) -> {error, not_allowed}
%% User = string()
%% Server = string()
%% Password = string()
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
%% @spec () -> [{LUser, LServer}]
%% LUser = string()
%% LServer = string()
dirty_get_registered_users() ->
[].
%% @spec (Server) -> [{LUser, LServer}]
%% Server = string()
%% LUser = string()
%% LServer = string()
get_vh_registered_users(_Server) ->
get_vh_registered_users(_Host) ->
[].
%% @spec (User, Server) -> Password | false
%% User = string()
%% Server = string()
%% Password = string()
get_password(_User, _Server) ->
false.
%% @spec (User, Server) -> Password | nil()
%% User = string()
%% Server = string()
%% Password = string()
get_password_s(_User, _Server) ->
"".
%% @spec (User, Server) -> true | false | {error, Error}
%% User = string()
%% Server = string()
%% TODO: Improve this function to return an error instead of 'false' when
%% connection to PAM failed
is_user_exists(User, Server) ->
Service = get_pam_service(Server),
UserInfo = case get_pam_userinfotype(Server) of
%% 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),
UserInfo = case get_pam_userinfotype(Host) of
username -> User;
jid -> User++"@"++Server
jid -> User++"@"++Host
end,
case catch epam:acct_mgmt(Service, UserInfo) of
true -> true;
_ -> false
end.
%% @spec (User, Server) -> {error, not_allowed}
%% User = string()
%% Server = string()
remove_user(_User, _Server) ->
{error, not_allowed}.
%% @spec (User, Server, Password) -> not_allowed
%% User = string()
%% Server = string()
%% Password = string()
remove_user(_User, _Server, _Password) ->
not_allowed.
%% @spec () -> bool()
plain_password_required() ->
true.
store_type() ->
external.
%%====================================================================
%% Internal functions
%%====================================================================
%% @spec (Server) -> string()
%% Server = string()
get_pam_service(Server) ->
case ejabberd_config:get_local_option({pam_service, Server}) of
get_pam_service(Host) ->
case ejabberd_config:get_local_option({pam_service, Host}) of
undefined -> "ejabberd";
Service -> Service
end.
-477
View File
@@ -1,477 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_auth_storage.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>, Stephan Maka
%%% Purpose : Authentification via gen_storage
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 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
%%%
%%%----------------------------------------------------------------------
%%% Database schema (version / storage / table)
%%%
%%% 2.1.x / mnesia / passwd
%%% us = {Username::string(), Host::string()}
%%% password = string()
%%%
%%% 2.1.x / odbc / users
%%% username = varchar250
%%% password = text
%%%
%%% 3.0.0-prealpha / mnesia / passwd
%%% Same as 2.1.x
%%%
%%% 3.0.0-prealpha / odbc / users
%%% Same as 2.1.x
%%%
%%% 3.0.0-alpha / mnesia / passwd
%%% user_host = {Username::string(), Host::string()}
%%% password = string()
%%%
%%% 3.0.0-alpha / odbc / passwd
%%% user = varchar150
%%% host = varchar150
%%% password = text
-module(ejabberd_auth_storage).
-author('alexey@process-one.net').
%% External exports
-export([start/1,
stop/1,
set_password/3,
check_password/3,
check_password/5,
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2,
get_password/2,
get_password_s/2,
is_user_exists/2,
remove_user/2,
remove_user/3,
plain_password_required/0
]).
-include("ejabberd.hrl").
-record(passwd, {user_host, password}).
-record(reg_users_counter, {vhost, count}).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
%% @spec (Host) -> ok
%% Host = string()
start(Host) ->
Backend =
case ejabberd_config:get_local_option({auth_storage, Host}) of
undefined -> mnesia;
B -> B
end,
HostB = list_to_binary(Host),
gen_storage:create_table(Backend, HostB, passwd,
[{odbc_host, Host},
{disc_copies, [node()]},
{attributes, record_info(fields, passwd)},
{types, [{user_host, {text, text}}]}
]),
update_table(Host, Backend),
mnesia:create_table(reg_users_counter,
[{ram_copies, [node()]},
{attributes, record_info(fields, reg_users_counter)}]),
update_reg_users_counter_table(Host),
ok.
stop(_Host) ->
ok.
update_reg_users_counter_table(Server) ->
Set = get_vh_registered_users(Server),
Size = length(Set),
LServer = exmpp_jid:prep_domain(exmpp_jid:parse(Server)),
F = fun() ->
mnesia:write(#reg_users_counter{vhost = LServer,
count = Size})
end,
mnesia:sync_dirty(F).
%% @spec () -> bool()
plain_password_required() ->
false.
%% @spec (User, Server, Password) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
check_password(User, Server, Password) ->
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
case catch gen_storage:dirty_read(LServer, {passwd, US}) of
[#passwd{password = Password}] ->
Password /= "";
_ ->
false
end.
%% @spec (User, Server, Password, Digest, DigestGen) -> bool()
%% User = string()
%% Server = string()
%% Password = string()
%% Digest = string()
%% DigestGen = function()
check_password(User, Server, Password, Digest, DigestGen) ->
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
case catch gen_storage:dirty_read(LServer, {passwd, US}) of
[#passwd{password = Passwd}] ->
DigRes = if
Digest /= "" ->
Digest == DigestGen(Passwd);
true ->
false
end,
if DigRes ->
true;
true ->
(Passwd == Password) and (Password /= "")
end;
_ ->
false
end.
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
%% User = string()
%% Server = string()
%% Password = string()
set_password(User, Server, Password) ->
LUser = (catch exmpp_stringprep:nodeprep(User)),
LServer = (catch exmpp_stringprep:nameprep(Server)),
case {LUser, LServer} of
{{stringprep, _, invalid_string, _}, _} ->
{error, invalid_jid};
{_, {stringprep, _, invalid_string, _}} ->
{error, invalid_jid};
US ->
%% TODO: why is this a transaction?
F = fun() ->
gen_storage:write(LServer,
#passwd{user_host = US,
password = Password})
end,
{atomic, ok} = gen_storage:transaction(LServer, passwd, F),
ok
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {aborted, Reason}
%% User = string()
%% Server = string()
%% Password = string()
try_register(User, Server, Password) ->
LUser = (catch exmpp_stringprep:nodeprep(User)),
LServer = (catch exmpp_stringprep:nameprep(Server)),
case {LUser, LServer} of
{{stringprep, _, invalid_string, _}, _} ->
{error, invalid_jid};
{_, {stringprep, _, invalid_string, _}} ->
{error, invalid_jid};
US ->
F = fun() ->
case gen_storage:read(LServer, {passwd, US}) of
[] ->
gen_storage:write(LServer,
#passwd{user_host = US,
password = Password}),
mnesia:dirty_update_counter(
reg_users_counter,
exmpp_jid:prep_domain(exmpp_jid:parse(Server)), 1),
ok;
[_E] ->
exists
end
end,
%% TODO: transaction return value?
gen_storage:transaction(LServer, passwd, F)
end.
%% @spec () -> [{LUser, LServer}]
%% LUser = string()
%% LServer = string()
%% @doc Get all registered users in Mnesia.
dirty_get_registered_users() ->
%% TODO:
exit(not_implemented).
%% @spec (Server) -> [{LUser, LServer}]
%% Server = string()
%% LUser = string()
%% LServer = string()
get_vh_registered_users(Server) ->
LServer = exmpp_stringprep:nameprep(Server),
lists:map(fun(#passwd{user_host = US}) ->
US
end,
gen_storage:dirty_select(LServer, passwd,
[{'=', user_host, {'_', LServer}}])).
%% @spec (Server, Opts) -> [{LUser, LServer}]
%% Server = string()
%% Opts = [{Opt, Val}]
%% Opt = atom()
%% Val = term()
%% LUser = string()
%% LServer = string()
%% @doc Return the registered users for the specified host.
%%
%% `Opts' can be one of the following:
%% <ul>
%% <li>`[{from, integer()}, {to, integer()}]'</li>
%% <li>`[{limit, integer()}, {offset, integer()}]'</li>
%% <li>`[{prefix, string()}]'</li>
%% <li>`[{prefix, string()}, {from, integer()}, {to, integer()}]'</li>
%% <li>`[{prefix, string()}, {limit, integer()}, {offset, integer()}]'</li>
%% </ul>
get_vh_registered_users(Server, [{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
get_vh_registered_users(Server, [{limit, End-Start+1}, {offset, Start}]);
get_vh_registered_users(Server, [{limit, Limit}, {offset, Offset}])
when is_integer(Limit) and is_integer(Offset) ->
case get_vh_registered_users(Server) of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_vh_registered_users(Server, [{prefix, Prefix}])
when is_list(Prefix) ->
Set = [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)],
lists:keysort(1, Set);
get_vh_registered_users(Server, [{prefix, Prefix}, {from, Start}, {to, End}])
when is_list(Prefix) and is_integer(Start) and is_integer(End) ->
get_vh_registered_users(Server, [{prefix, Prefix}, {limit, End-Start+1}, {offset, Start}]);
get_vh_registered_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_list(Prefix) and is_integer(Limit) and is_integer(Offset) ->
case [{U,S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)] of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
%% @spec (Server) -> Users_Number
%% Server = string()
%% Users_Number = integer()
get_vh_registered_users_number(Server) ->
LServer = exmpp_jid:prep_domain(exmpp_jid:parse(Server)),
Query = mnesia:dirty_select(
reg_users_counter,
[{#reg_users_counter{vhost = LServer, count = '$1'},
[],
['$1']}]),
case Query of
[Count] ->
Count;
_ -> 0
end.
%% @spec (Server, [{prefix, Prefix}]) -> Users_Number
%% Server = string()
%% Prefix = string()
%% Users_Number = integer()
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)],
length(Set);
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
%% @spec (User, Server) -> Password | false
%% User = string()
%% Server = string()
%% Password = string()
get_password(User, Server) ->
try
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
case catch gen_storage:dirty_read(LServer, passwd, US) of
[#passwd{password = Password}] ->
Password;
_ ->
false
end
catch
_ ->
false
end.
%% @spec (User, Server) -> Password | nil()
%% User = string()
%% Server = string()
%% Password = string()
get_password_s(User, Server) ->
try
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
case catch gen_storage:dirty_read(LServer, passwd, US) of
[#passwd{password = Password}] ->
Password;
_ ->
[]
end
catch
_ ->
[]
end.
%% @spec (User, Server) -> true | false | {error, Error}
%% User = string()
%% Server = string()
is_user_exists(User, Server) ->
try
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
case catch gen_storage:dirty_read(LServer, {passwd, US}) of
[] ->
false;
[_] ->
true;
Other ->
{error, Other}
end
catch
_ ->
false
end.
%% @spec (User, Server) -> ok
%% User = string()
%% Server = string()
%% @doc Remove user.
%% Note: it returns ok even if there was some problem removing the user.
remove_user(User, Server) ->
try
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
F = fun() ->
gen_storage:delete(LServer, {passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
exmpp_jid:prep_domain(exmpp_jid:parse(Server)), -1)
end,
gen_storage:transaction(LServer, passwd, F),
ok
catch
_ ->
ok
end.
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request
%% User = string()
%% Server = string()
%% Password = string()
%% @doc Remove user if the provided password is correct.
remove_user(User, Server, Password) ->
try
LUser = exmpp_stringprep:nodeprep(User),
LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
F = fun() ->
case gen_storage:read(LServer, {passwd, US}) of
[#passwd{password = Password}] ->
gen_storage:delete(LServer, {passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
exmpp_jid:prep_domain(exmpp_jid:parse(Server)), -1),
ok;
[_] ->
not_allowed;
_ ->
not_exists
end
end,
case gen_storage:transaction(LServer, passwd, F) of
{atomic, ok} ->
ok;
{atomic, Res} ->
Res
end
catch
_ ->
bad_request
end.
update_table(Host, mnesia) ->
gen_storage_migration:migrate_mnesia(
Host, passwd,
[{passwd, [us, password],
fun({passwd, {User, _Host}, Password}) ->
#passwd{user_host = {User, Host},
password = Password}
end}]);
update_table(Host, odbc) ->
gen_storage_migration:migrate_odbc(
Host, [passwd],
[{"users", ["username", "password"],
fun(_, User, Password) ->
#passwd{user_host = {User, Host},
password = Password}
end}]).
+981 -959
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@
%%% Created : 2 Nov 2007 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+276 -482
View File
@@ -5,7 +5,7 @@
%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -24,22 +24,6 @@
%%%
%%%-------------------------------------------------------------------
%%% Database schema (version / storage / table)
%%%
%%% 2.1.x / mnesia / captcha
%%% id = string()
%%% pid = pid()
%%% key = string()
%%% tref = any()
%%% args = any()
%%%
%%% 3.0.0-alpha / ets / captcha
%%% id = string()
%%% pid = pid()
%%% key = string()
%%% tref = any()
%%% args = any()
-module(ejabberd_captcha).
-behaviour(gen_server).
@@ -51,39 +35,34 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-export([create_captcha/5, build_captcha_html/2, check_captcha/2,
-export([create_captcha/6, build_captcha_html/2, check_captcha/2,
process_reply/1, process/2, is_feature_available/0,
create_captcha_x/4, create_captcha_x/5]).
-include_lib("exmpp/include/exmpp.hrl").
create_captcha_x/5, create_captcha_x/6]).
-include("jlib.hrl").
-include("ejabberd.hrl").
-include("web/ejabberd_http.hrl").
-define(VFIELD(Type, Var, Value),
#xmlel{name = 'field',
attrs = [
#xmlattr{name = <<"type">>,
value = Type
},
#xmlattr{name = <<"var">>,
value = Var
}
],
children = [
#xmlel{name = 'value',
children = [Value]
}
]}).
{xmlelement, "field", [{"type", Type}, {"var", Var}],
[{xmlelement, "value", [], [Value]}]}).
-define(CAPTCHA_TEXT(Lang), list_to_binary(translate:translate(Lang, "Enter the text you see"))).
-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
-define(CAPTCHA_LIFETIME, 120000). % two minutes
-define(RPC_TIMEOUT, 5000).
-define(LIMIT_PERIOD, 60*1000*1000). % one minute
-record(state, {}).
-record(state, {limits = treap:empty()}).
-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
%%====================================================================
@@ -94,226 +73,96 @@
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
create_captcha(SID, From, To, Lang, Args)
when is_binary(Lang), is_binary(SID) ->
case create_image() of
create_captcha(SID, From, To, Lang, Limiter, Args)
when is_list(Lang), is_list(SID),
is_record(From, jid), is_record(To, jid) ->
case create_image(Limiter) of
{ok, Type, Key, Image} ->
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
B64Image = list_to_binary(jlib:encode_base64(binary_to_list(Image))),
JID = exmpp_jid:to_list(From),
CID = list_to_binary(["sha1+", sha:sha(Image), "@bob.xmpp.org"]),
% Data = {xmlelement, "data",
% [{"xmlns", ?NS_BOB}, {"cid", CID},
% {"max-age", "0"}, {"type", Type}],
% [{xmlcdata, B64Image}]},
Data =
#xmlel{
name = 'data',
ns = ?NS_BOB,
attrs = [
#xmlattr{name = <<"cid">>,
value = CID
},
#xmlattr{name = <<"max-age">>,
value = <<"0">>
},
#xmlattr{name = <<"type">>,
value = Type
}
],
children = [#xmlcdata{cdata = B64Image}]},
% {xmlelement, "captcha", [{"xmlns", ?NS_CAPTCHA}],
% %% ?NS_DATA_FORMS is 'jabber:x:data'
% [{xmlelement, "x", [{"xmlns", "jabber:x:data"}, {"type", "form"}],
% [?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}),
% ?VFIELD("hidden", "from", {xmlcdata, exmpp_jid:to_list(To)}),
% ?VFIELD("hidden", "challenge", {xmlcdata, Id}),
% ?VFIELD("hidden", "sid", {xmlcdata, SID}),
% {xmlelement, "field", [{"var", "ocr"}, {"label", ?CAPTCHA_TEXT(Lang)}],
% [{xmlelement, "media", [{"xmlns", ?NS_DATA_FORMS_MEDIA_s}],
% [{xmlelement, "uri", [{"type", Type}],
% [{xmlcdata, "cid:" ++ CID}]}]}]}]}]},
%% TODO : kael : write exmpp_captcha.erl
Id = randoms:get_string(),
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 =
#xmlel{
name = 'captcha',
ns = ?NS_CAPTCHA,
children = [
#xmlel{name = 'x',
ns = ?NS_DATA_FORMS_s,
attrs = [
#xmlattr{name = <<"type">>,
value = <<"form">>
}
],
children = [
?VFIELD(<<"hidden">>, <<"FORM_TYPE">>, #xmlcdata{cdata = ?NS_CAPTCHA_b}),
?VFIELD(<<"hidden">>, <<"from">>, #xmlcdata{cdata = exmpp_jid:to_binary(To)}),
?VFIELD(<<"hidden">>, <<"challenge">>, #xmlcdata{cdata = list_to_binary(Id)}),
?VFIELD(<<"hidden">>, <<"sid">>, #xmlcdata{cdata = SID}),
#xmlel{name = 'field',
attrs = [
#xmlattr{name = <<"var">>,
value = <<"ocr">>
},
#xmlattr{name = <<"label">>,
value = ?CAPTCHA_TEXT(Lang)
}
],
children = [
#xmlel{ns = ?NS_DATA_FORMS, name = 'required'},
#xmlel{name = 'media',
ns = ?NS_DATA_FORMS_MEDIA_s,
children = [
#xmlel{name = 'uri',
attrs = [
#xmlattr{name = <<"type">>,
value = Type
}
],
children = [
#xmlcdata{cdata = list_to_binary(["cid:", CID])}
]
}
]
}
]
}
]
}
]
},
{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, "required", [], []},
{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 =
#xmlel{name = 'body',
children = [
#xmlcdata{cdata = list_to_binary(BodyString)
}
]
},
OOB =
#xmlel{name = 'x',
ns = ?NS_OOBD_X_s,
children = [
#xmlel{name = 'url',
children = [
#xmlcdata{cdata = list_to_binary(get_url(Id))}
]
}
]
},
%Body = {xmlelement, "body", [],
% [{xmlcdata, BodyString}]},
%OOB = {xmlelement, "x", [{"xmlns", ?NS_OOBD_X_s}],
% [{xmlelement, "url", [], [{xmlcdata, 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}),
ets:insert(captcha, #captcha{id=Id, pid=self(), key=Key,
tref=Tref, args=Args}),
{ok, Id, [Body, OOB, Captcha, Data]};
_Err ->
error
case ?T(mnesia:write(#captcha{id=Id, pid=self(), key=Key,
tref=Tref, args=Args})) of
ok ->
{ok, Id, [Body, OOB, Captcha, Data]};
Err ->
{error, Err}
end;
Err ->
Err
end.
create_captcha_x(SID, To, Lang, HeadEls) ->
create_captcha_x(SID, To, Lang, HeadEls, []).
create_captcha_x(SID, To, Lang, Limiter, HeadEls) ->
create_captcha_x(SID, To, Lang, Limiter, HeadEls, []).
create_captcha_x(SID, To, Lang, HeadEls, TailEls) ->
case create_image() of
create_captcha_x(SID, To, Lang, Limiter, HeadEls, TailEls) ->
case create_image(Limiter) of
{ok, Type, Key, Image} ->
Id = randoms:get_string() ++ "-" ++ ejabberd_cluster:node_id(),
B64Image = list_to_binary(jlib:encode_base64(binary_to_list(Image))),
CID = list_to_binary(["sha1+", sha:sha(Image), "@bob.xmpp.org"]),
Data =
#xmlel{
name = 'data',
ns = ?NS_BOB,
attrs = [
#xmlattr{name = <<"cid">>,
value = CID
},
#xmlattr{name = <<"max-age">>,
value = <<"0">>
},
#xmlattr{name = <<"type">>,
value = Type
}
],
children = [#xmlcdata{cdata = B64Image}]},
Id = randoms:get_string(),
B64Image = jlib:encode_base64(binary_to_list(Image)),
CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org",
Data = {xmlelement, "data",
[{"xmlns", ?NS_BOB}, {"cid", CID},
{"max-age", "0"}, {"type", Type}],
[{xmlcdata, B64Image}]},
HelpTxt = translate:translate(
Lang,
"If you don't see the CAPTCHA image here, "
"visit the web page."),
Imageurl = list_to_binary(get_url(Id ++ "/image")),
Imageurl = get_url(Id ++ "/image"),
Captcha =
#xmlel{name = 'x',
ns = ?NS_DATA_FORMS_s,
attrs = [
#xmlattr{name = <<"type">>,
value = <<"form">>
}
],
children = [
?VFIELD(<<"hidden">>, <<"FORM_TYPE">>, #xmlcdata{cdata = ?NS_CAPTCHA_b}) | HeadEls] ++ [
#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
[?XMLATTR(<<"type">>, <<"fixed">>), ?XMLATTR(<<"label">>, HelpTxt)]},
?VFIELD(<<"hidden">>, <<"captchahidden">>, #xmlcdata{cdata = <<"workaround-for-psi">>}),
#xmlel{name = 'field',
attrs = [
#xmlattr{name = <<"type">>,
value = <<"text-single">>
},
#xmlattr{name = <<"label">>,
value = list_to_binary(translate:translate(Lang, "CAPTCHA web page"))
},
#xmlattr{name = <<"var">>,
value = <<"url">>
}
],
children = [
#xmlel{name = 'value',
children = [#xmlcdata{cdata = Imageurl}]
}
]},
?VFIELD(<<"hidden">>, <<"from">>, #xmlcdata{cdata = exmpp_jid:to_binary(To)}),
?VFIELD(<<"hidden">>, <<"challenge">>, #xmlcdata{cdata = list_to_binary(Id)}),
?VFIELD(<<"hidden">>, <<"sid">>, #xmlcdata{cdata = SID}),
#xmlel{name = 'field',
attrs = [
#xmlattr{name = <<"var">>,
value = <<"ocr">>
},
#xmlattr{name = <<"label">>,
value = ?CAPTCHA_TEXT(Lang)
}
],
children = [
#xmlel{ns = ?NS_DATA_FORMS, name = 'required'},
#xmlel{name = 'media',
ns = ?NS_DATA_FORMS_MEDIA_s,
children = [
#xmlel{name = 'uri',
attrs = [
#xmlattr{name = <<"type">>,
value = Type
}
],
children = [
#xmlcdata{cdata = list_to_binary(["cid:", CID])}
]
}
]
}
]
}
] ++ TailEls
},
{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}) | HeadEls] ++
[{xmlelement, "field", [{"type", "fixed"}],
[{xmlelement, "value", [], [{xmlcdata, HelpTxt}]}]},
{xmlelement, "field", [{"type", "hidden"}, {"var", "captchahidden"}],
[{xmlelement, "value", [], [{xmlcdata, "workaround-for-psi"}]}]},
{xmlelement, "field",
[{"type", "text-single"},
{"label", translate:translate(Lang, "CAPTCHA web page")},
{"var", "url"}],
[{xmlelement, "value", [], [{xmlcdata, Imageurl}]}]},
?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, "required", [], []},
{xmlelement, "media", [{"xmlns", ?NS_MEDIA}],
[{xmlelement, "uri", [{"type", Type}],
[{xmlcdata, "cid:" ++ CID}]}]}]}] ++ TailEls},
Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
ets:insert(captcha, #captcha{id=Id, key=Key, tref=Tref}),
{ok, [Captcha, Data]};
_ ->
error
case ?T(mnesia:write(#captcha{id=Id, key=Key, tref=Tref})) of
ok ->
{ok, [Captcha, Data]};
Err ->
{error, Err}
end;
Err ->
Err
end.
%% @spec (Id::string(), Lang::string()) -> {FormEl, {ImgEl, TextEl, IdEl, KeyEl}} | captcha_not_found
@@ -323,106 +172,30 @@ create_captcha_x(SID, To, Lang, HeadEls, TailEls) ->
%% IdEl = xmlelement()
%% KeyEl = xmlelement()
build_captcha_html(Id, Lang) ->
case lookup_captcha(Id) of
{ok, _} ->
%ImgEl = {xmlelement, "img", [{"src", get_url(Id ++ "/image")}], []},
ImgEl =
#xmlel{name = 'img',
attrs = [
#xmlattr{name = <<"src">>,
value = list_to_binary(get_url(Id ++ "/image"))
}
]
},
%TextEl = {xmlcdata, ?CAPTCHA_TEXT(Lang)},
TextEl = #xmlcdata{cdata = ?CAPTCHA_TEXT(Lang)},
%IdEl = {xmlelement, "input", [{"type", "hidden"},
% {"name", "id"},
% {"value", Id}], []},
IdEl =
#xmlel{name = 'input',
attrs = [
#xmlattr{name = <<"type">>,
value = <<"hidden">>
},
#xmlattr{name = <<"name">>,
value = <<"id">>
},
#xmlattr{name = <<"value">>,
value = list_to_binary(Id)
}
]
},
%KeyEl = {xmlelement, "input", [{"type", "text"},
% {"name", "key"},
% {"size", "10"}], []},
KeyEl =
#xmlel{name = 'input',
attrs = [
#xmlattr{name = <<"type">>,
value = <<"text">>
},
#xmlattr{name = <<"name">>,
value = <<"key">>
},
#xmlattr{name = <<"size">>,
value = <<"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 =
#xmlel{name = 'form',
attrs = [
#xmlattr{name = <<"action">>,
value = list_to_binary(get_url(Id))
},
#xmlattr{name = <<"name">>,
value = <<"captcha">>
},
#xmlattr{name = <<"method">>,
value = <<"POST">>
}
],
children = [
ImgEl,
#xmlel{name = 'br'
},
TextEl,
#xmlel{name = 'br'
},
IdEl,
KeyEl,
#xmlel{name = 'br'
},
#xmlel{name = 'input',
attrs = [
#xmlattr{name = <<"type">>,
value = <<"submit">>
},
#xmlattr{name = <<"name">>,
value = <<"enter">>
},
#xmlattr{name = <<"value">>,
value = <<"OK">>
}
]
}
]
},
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
@@ -430,78 +203,93 @@ build_captcha_html(Id, Lang) ->
%% @spec (Id::string(), ProvidedKey::string()) -> captcha_valid | captcha_non_valid | captcha_not_found
check_captcha(Id, ProvidedKey) ->
case string:tokens(Id, "-") of
[_, NodeID] ->
case ejabberd_cluster:get_node_by_id(NodeID) of
Node when Node == node() ->
do_check_captcha(Id, ProvidedKey);
Node ->
case catch rpc:call(Node, ?MODULE, check_captcha,
[Id, ProvidedKey], ?RPC_TIMEOUT) of
{'EXIT', _} ->
captcha_not_found;
{badrpc, _} ->
captcha_not_found;
Res ->
Res
end
end;
_ ->
captcha_not_found
end.
?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 ->
if is_pid(Pid) ->
Pid ! {captcha_succeed, Args};
true ->
ok
end,
captcha_valid;
true ->
if is_pid(Pid) ->
Pid ! {captcha_failed, Args};
true ->
ok
end,
captcha_non_valid
end;
_ ->
captcha_not_found
end).
process_reply(El) ->
case exmpp_xml:get_element(El, x) of
undefined ->
process_reply({xmlelement, _, _, _} = El) ->
case xml:get_subtag(El, "x") of
false ->
{error, malformed};
Xdata ->
Fields = jlib:parse_xdata_submit(Xdata),
case catch {proplists:get_value("challenge", Fields),
proplists:get_value("ocr", Fields)} of
{[Id|_], [OCR|_]} ->
case check_captcha(Id, OCR) of
captcha_valid ->
ok;
captcha_non_valid ->
{error, bad_match};
captcha_not_found ->
{error, not_found}
end;
?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 ->
if is_pid(Pid) ->
Pid ! {captcha_succeed, Args};
true ->
ok
end,
ok;
true ->
if is_pid(Pid) ->
Pid ! {captcha_failed, Args};
true ->
ok
end,
{error, bad_match}
end;
_ ->
{error, not_found}
end);
_ ->
{error, malformed}
end
end.
end;
process_reply(_) ->
{error, malformed}.
process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) ->
case build_captcha_html(Id, Lang) of
{FormEl, CaptchaTuple} when is_tuple(CaptchaTuple) ->
{FormEl, _} when is_tuple(FormEl) ->
Form =
%{xmlelement, "div", [{"align", "center"}],
%[FormEl]},
#xmlel{name = 'div',
attrs = [
#xmlattr{name = <<"align">>,
value = <<"center">>
}
],
children = [FormEl]
},
{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 lookup_captcha(Id) of
{ok, #captcha{key=Key}} ->
case create_image(Key) of
process(_Handlers, #request{method='GET', path=[_, Id, "image"], ip = IP}) ->
{Addr, _Port} = IP,
case mnesia:dirty_read(captcha, Id) of
[#captcha{key=Key}] ->
case create_image(Addr, Key) of
{ok, Type, _, Img} ->
{200,
[{"Content-Type", Type},
{"Cache-Control", "no-cache"},
{"Last-Modified", httpd_util:rfc1123_date()}],
Img};
{error, limit} ->
ejabberd_web:error(not_allowed);
_ ->
ejabberd_web:error(not_found)
end;
@@ -514,15 +302,10 @@ process(_Handlers, #request{method='POST', q=Q, lang=Lang, path=[_, Id]}) ->
case check_captcha(Id, ProvidedKey) of
captcha_valid ->
Form =
%{xmlelement, "p", [],
% [{xmlcdata,
% translate:translate(Lang, "The captcha is valid.")
% }]},
#xmlel{name = 'p',
children = [
#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "The captcha is valid."))}
]
},
{xmlelement, "p", [],
[{xmlcdata,
translate:translate(Lang, "The CAPTCHA is valid.")
}]},
ejabberd_web:make_xhtml([Form]);
captcha_non_valid ->
ejabberd_web:error(not_allowed);
@@ -533,15 +316,32 @@ process(_Handlers, #request{method='POST', q=Q, lang=Lang, path=[_, Id]}) ->
process(_Handlers, _Request) ->
ejabberd_web:error(not_found).
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([]) ->
mnesia:delete_table(captcha),
ets:new(captcha, [named_table, public, {keypos, #captcha.id}]),
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({is_limited, Limiter, RateLimit}, _From, State) ->
NowPriority = now_priority(),
CleanPriority = NowPriority + ?LIMIT_PERIOD,
Limits = clean_treap(State#state.limits, CleanPriority),
case treap:lookup(Limiter, Limits) of
{ok, _, Rate} when Rate >= RateLimit ->
{reply, true, State#state{limits = Limits}};
{ok, Priority, Rate} ->
NewLimits = treap:insert(Limiter, Priority, Rate+1, Limits),
{reply, false, State#state{limits = NewLimits}};
_ ->
NewLimits = treap:insert(Limiter, NowPriority, 1, Limits),
{reply, false, State#state{limits = NewLimits}}
end;
handle_call(_Request, _From, State) ->
{reply, bad_request, State}.
@@ -550,17 +350,17 @@ handle_cast(_Msg, State) ->
handle_info({remove_id, Id}, State) ->
?DEBUG("captcha ~p timed out", [Id]),
case ets:lookup(captcha, Id) of
[#captcha{args=Args, pid=Pid}] ->
if is_pid(Pid) ->
Pid ! {captcha_failed, Args};
true ->
ok
end,
ets:delete(captcha, Id);
_ ->
ok
end,
_ = ?T(case mnesia:read(captcha, Id, write) of
[#captcha{args=Args, pid=Pid}] ->
if is_pid(Pid) ->
Pid ! {captcha_failed, Args};
true ->
ok
end,
mnesia:delete({captcha, Id});
_ ->
ok
end),
{noreply, State};
handle_info(_Info, State) ->
@@ -578,25 +378,36 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
%% Function: create_image() -> {ok, Type, Key, Image} | {error, Reason}
%% Type = "image/png" | "image/jpeg" | "image/gif"
%% Key = binary()
%% Key = string()
%% Image = binary()
%% Reason = atom()
%%--------------------------------------------------------------------
create_image() ->
create_image(undefined).
create_image(Limiter) ->
%% Six numbers from 1 to 9.
Key = string:substr(randoms:get_string(), 1, 6),
create_image(Key).
create_image(Limiter, Key).
create_image(Key) ->
create_image(Limiter, Key) ->
case is_limited(Limiter) of
true ->
{error, limit};
false ->
do_create_image(Key)
end.
do_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, "image/png", Key, Img};
{ok, <<16#ff, 16#d8, _/binary>> = Img} ->
{ok, <<"image/jpeg">>, Key, 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};
{ok, "image/gif", Key, Img};
{error, enodata = Reason} ->
?ERROR_MSG("Failed to process output from \"~s\". "
"Maybe ImageMagick's Convert program is not installed.",
@@ -617,13 +428,12 @@ get_prog_name() ->
case ejabberd_config:get_local_option(captcha_cmd) of
FileName when is_list(FileName) ->
FileName;
_ ->
Value when (Value == undefined) or (Value == "") ->
?DEBUG("The option captcha_cmd is not configured, but some "
"module wants to use the CAPTCHA feature.", []),
throw({error, option_not_configured_captcha_cmd})
false
end.
%% @doc (Str::string()) -> string()
get_url(Str) ->
CaptchaHost = ejabberd_config:get_local_option(captcha_host),
case string:tokens(CaptchaHost, ":") of
@@ -675,6 +485,25 @@ get_captcha_transfer_protocol([{{_Port, _Ip, tcp}, ejabberd_http, Opts}
get_captcha_transfer_protocol([_ | Listeners]) ->
get_captcha_transfer_protocol(Listeners).
is_limited(undefined) ->
false;
is_limited(Limiter) ->
case ejabberd_config:get_local_option(captcha_limit) of
Int when is_integer(Int), Int > 0 ->
case catch gen_server:call(?MODULE, {is_limited, Limiter, Int},
5000) of
true ->
true;
false ->
false;
Err ->
?ERROR_MSG("Call failed: ~p", [Err]),
false
end;
_ ->
false
end.
%%--------------------------------------------------------------------
%% Function: cmd(Cmd) -> Data | {error, Reason}
%% Cmd = string()
@@ -723,76 +552,41 @@ return(Port, TRef, Result) ->
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
case get_prog_name() of
Prog when is_list(Prog) -> true;
false -> false
end.
check_captcha_setup() ->
case is_feature_enabled() andalso not is_feature_available() of
case is_feature_available() of
true ->
?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, "
"but it can't generate images.", []);
case create_image() of
{ok, _, _, _} ->
ok;
_Err ->
?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, "
"but it can't generate images.", []),
throw({error, captcha_cmd_enabled_but_fails})
end;
false ->
ok
end.
lookup_captcha(Id) ->
case string:tokens(Id, "-") of
[_, NodeID] ->
case ejabberd_cluster:get_node_by_id(NodeID) of
Node when Node == node() ->
case ets:lookup(captcha, Id) of
[C] ->
{ok, C};
_ ->
{error, enoent}
end;
Node ->
case catch rpc:call(Node, ets, lookup,
[captcha, Id], ?RPC_TIMEOUT) of
[C] ->
{ok, C};
_ ->
{error, enoent}
end
end;
_ ->
{error, enoent}
clean_treap(Treap, CleanPriority) ->
case treap:is_empty(Treap) of
true ->
Treap;
false ->
{_Key, Priority, _Value} = treap:get_root(Treap),
if
Priority > CleanPriority ->
clean_treap(treap:delete_root(Treap), CleanPriority);
true ->
Treap
end
end.
do_check_captcha(Id, ProvidedKey) ->
case ets:lookup(captcha, Id) of
[#captcha{pid = Pid, args = Args, key = ValidKey, tref = Tref}] ->
ets:delete(captcha, Id),
erlang:cancel_timer(Tref),
if ValidKey == ProvidedKey ->
if is_pid(Pid) ->
Pid ! {captcha_succeed, Args};
true ->
ok
end,
captcha_valid;
true ->
if is_pid(Pid) ->
Pid ! {captcha_failed, Args};
true ->
ok
end,
captcha_non_valid
end;
_ ->
captcha_not_found
end.
now_priority() ->
{MSec, Sec, USec} = now(),
-((MSec*1000000 + Sec)*1000000 + USec).
+3 -5
View File
@@ -5,7 +5,7 @@
%%% Created : 27 Feb 2008 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -46,8 +46,6 @@ config() ->
check_database_modules() ->
[check_database_module(M)||M<-get_db_used()].
check_database_module(host) ->
ok;
check_database_module(odbc) ->
check_modules(odbc, [odbc, odbc_app, odbc_sup, ejabberd_odbc, ejabberd_odbc_sup, odbc_queries]);
check_database_module(mysql) ->
@@ -88,8 +86,8 @@ get_db_used() ->
DBs = lists:foldr(
fun([Domain, DB], Acc) ->
case check_odbc_option(
ejabberd_config:get_local_option
({auth_method, Domain})) of
ejabberd_config:get_local_option(
{auth_method, Domain})) of
true -> [get_db_type(DB)|Acc];
_ -> Acc
end
-177
View File
@@ -1,177 +0,0 @@
%%%-------------------------------------------------------------------
%%% File : ejabberd_cluster.erl
%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% Description :
%%%
%%% Created : 2 Apr 2010 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-module(ejabberd_cluster).
-behaviour(gen_server).
%% API
-export([start_link/0, get_node/1, get_node_new/1, announce/0,
node_id/0, get_node_by_id/1, get_nodes/0, rehash_timeout/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-define(HASHTBL, nodes_hash).
-define(HASHTBL_NEW, nodes_hash_new).
-define(POINTS, 16).
-define(REHASH_TIMEOUT, 5000).
-record(state, {}).
%%====================================================================
%% API
%%====================================================================
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
get_node(Key) ->
Hash = erlang:phash2(Key),
get_node_by_hash(?HASHTBL, Hash).
get_node_new(Key) ->
Hash = erlang:phash2(Key),
get_node_by_hash(?HASHTBL_NEW, Hash).
get_nodes() ->
%% TODO
mnesia:system_info(running_db_nodes).
announce() ->
gen_server:call(?MODULE, announce, infinity).
node_id() ->
integer_to_list(erlang:phash2(node())).
rehash_timeout() ->
?REHASH_TIMEOUT.
get_node_by_id(NodeID) when is_list(NodeID) ->
case catch list_to_existing_atom(NodeID) of
{'EXIT', _} ->
node();
Res ->
get_node_by_id(Res)
end;
get_node_by_id(NodeID) ->
case global:whereis_name(NodeID) of
Pid when is_pid(Pid) ->
node(Pid);
_ ->
node()
end.
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([]) ->
net_kernel:monitor_nodes(true, [{node_type, visible}]),
ets:new(?HASHTBL, [named_table, public, ordered_set]),
ets:new(?HASHTBL_NEW, [named_table, public, ordered_set]),
register_node(),
AllNodes = mnesia:system_info(running_db_nodes),
OtherNodes = case AllNodes of
[_] ->
AllNodes;
_ ->
AllNodes -- [node()]
end,
append_nodes(?HASHTBL, OtherNodes),
append_nodes(?HASHTBL_NEW, AllNodes),
{ok, #state{}}.
handle_call(announce, _From, State) ->
case mnesia:system_info(running_db_nodes) of
[_MyNode] ->
ok;
Nodes ->
OtherNodes = Nodes -- [node()],
lists:foreach(
fun(Node) ->
{?MODULE, Node} ! {node_ready, node()}
end, OtherNodes),
?INFO_MSG("waiting for migration from nodes: ~w",
[OtherNodes]),
timer:sleep(?REHASH_TIMEOUT),
append_node(?HASHTBL, node())
end,
{reply, ok, State};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({node_ready, Node}, State) ->
?INFO_MSG("node ~p is ready, starting migration", [Node]),
append_node(?HASHTBL_NEW, Node),
ejabberd_hooks:run(node_hash_update, [?REHASH_TIMEOUT]),
timer:sleep(?REHASH_TIMEOUT),
?INFO_MSG("adding node ~p to hash", [Node]),
append_node(?HASHTBL, Node),
{noreply, State};
handle_info({nodedown, Node, _}, State) ->
?INFO_MSG("node ~p goes down", [Node]),
delete_node(?HASHTBL, Node),
delete_node(?HASHTBL_NEW, Node),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%--------------------------------------------------------------------
%% Internal functions
%%--------------------------------------------------------------------
append_nodes(Tab, Nodes) ->
lists:foreach(
fun(Node) ->
append_node(Tab, Node)
end, Nodes).
append_node(Tab, Node) ->
lists:foreach(
fun(I) ->
Hash = erlang:phash2({I, Node}),
ets:insert(Tab, {Hash, Node})
end, lists:seq(1, ?POINTS)).
delete_node(Tab, Node) ->
lists:foreach(
fun(I) ->
Hash = erlang:phash2({I, Node}),
ets:delete(Tab, Hash)
end, lists:seq(1, ?POINTS)).
get_node_by_hash(Tab, Hash) ->
NodeHash = case ets:next(Tab, Hash) of
'$end_of_table' ->
ets:first(Tab);
NH ->
NH
end,
if NodeHash == '$end_of_table' ->
erlang:error(no_running_nodes);
true ->
case ets:lookup(Tab, NodeHash) of
[] ->
get_node_by_hash(Tab, Hash);
[{_, Node}] ->
Node
end
end.
register_node() ->
global:register_name(list_to_atom(node_id()), self()).
+2 -2
View File
@@ -5,7 +5,7 @@
%%% Created : 20 May 2008 by Badlop <badlop@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -398,7 +398,7 @@ check_access(all, _) ->
check_access(Access, Auth) ->
{ok, User, Server} = check_auth(Auth),
%% Check this user has access permission
case acl:match_rule(Server, Access, exmpp_jid:make(User, Server, "")) of
case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of
allow -> true;
deny -> false
end.
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+19 -195
View File
@@ -5,7 +5,7 @@
%%% Created : 14 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,32 +27,16 @@
-module(ejabberd_config).
-author('alexey@process-one.net').
-export([start/0, load_file/1, get_host_option/2,
-export([start/0, load_file/1,
add_global_option/2, add_local_option/2,
mne_add_local_option/2, mne_del_local_option/1,
del_global_option/1, del_local_option/1,
get_global_option/1, get_local_option/1]).
-export([for_host/1
,configure_host/2
,delete_host/1
]).
-export([search/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").
-include_lib("stdlib/include/ms_transform.hrl").
-record(state, {opts = [],
hosts = [],
override_local = false,
override_global = false,
override_acls = false}).
%% @type macro() = {macro_key(), macro_value()}
@@ -167,16 +151,7 @@ search_hosts(Term, State) ->
end.
add_hosts_to_option(Hosts, State) ->
PrepHosts1 = normalize_hosts(Hosts),
PrepHosts = ensure_localhost_is_first(PrepHosts1),
mnesia:transaction(
fun() ->
lists:foreach(
fun(H) ->
mnesia:write(#local_config{key = {H, host},
value = []})
end, PrepHosts)
end),
PrepHosts = normalize_hosts(Hosts),
add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
normalize_hosts(Hosts) ->
@@ -184,38 +159,15 @@ normalize_hosts(Hosts) ->
normalize_hosts([], PrepHosts) ->
lists:reverse(PrepHosts);
normalize_hosts([Host|Hosts], PrepHosts) ->
try
PrepHost = exmpp_stringprep:nodeprep(Host),
normalize_hosts(Hosts, [PrepHost|PrepHosts])
catch
_ ->
case jlib:nodeprep(Host) of
error ->
?ERROR_MSG("Can't load config file: "
"invalid host name [~p]", [Host]),
exit("invalid hostname")
exit("invalid hostname");
PrepHost ->
normalize_hosts(Hosts, [PrepHost|PrepHosts])
end.
%% @spec (Hosts::[string()]) -> [Localhost::string() | [string()]]
%% @doc Return the list where the first is surely "localhost".
ensure_localhost_is_first(Hosts) ->
case lists:all(fun is_list/1, Hosts) of
true ->
ensure_localhost_is_first1(Hosts);
false ->
?ERROR_MSG("This list of hosts is bad formed:~n~p", [Hosts]),
ensure_localhost_is_first1([])
end.
ensure_localhost_is_first1(["localhost" | _] = Hosts) ->
Hosts;
ensure_localhost_is_first1(Hosts) ->
case lists:member("localhost", Hosts) of
true ->
["localhost" | lists:delete("localhost", Hosts)];
false ->
?INFO_MSG("ejabberd added the default virtual host \"localhost\""
" to the list of hosts.", []),
["localhost" | Hosts]
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Errors reading the config file
@@ -422,11 +374,12 @@ process_term(Term, State) ->
State;
{hosts, _Hosts} ->
State;
{fqdn, HostFQDN} ->
?DEBUG("FQDN set to: ~p", [HostFQDN]),
add_option(fqdn, HostFQDN, State);
{host_config, Host, Terms} ->
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
State, Terms);
{clusterid, ClusterID} ->
add_option(clusterid, ClusterID, State);
{listen, Listeners} ->
Listeners2 =
lists:map(
@@ -443,8 +396,6 @@ process_term(Term, State) ->
add_option(outgoing_s2s_port, Port, State);
{outgoing_s2s_options, Methods, Timeout} ->
add_option(outgoing_s2s_options, {Methods, Timeout}, State);
{outgoing_s2s_local_address, Addr} ->
add_option(outgoing_s2s_local_address, Addr, State);
{s2s_dns_options, PropList} ->
add_option(s2s_dns_options, PropList, State);
{s2s_use_starttls, Port} ->
@@ -479,19 +430,22 @@ process_term(Term, State) ->
add_option(watchdog_large_heap, LH, State);
{registration_timeout, Timeout} ->
add_option(registration_timeout, Timeout, State);
{ejabberdctl_access_commands, ACs} ->
add_option(ejabberdctl_access_commands, ACs, State);
{captcha_cmd, Cmd} ->
add_option(captcha_cmd, Cmd, State);
{captcha_host, Host} ->
add_option(captcha_host, Host, State);
{captcha_limit, Limit} ->
add_option(captcha_limit, Limit, 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} ->
process_host_term(Term, global, State)
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
State, State#state.hosts)
end.
process_host_term(Term, Host, State) ->
@@ -513,15 +467,6 @@ process_host_term(Term, Host, State) ->
State;
{odbc_server, ODBC_server} ->
add_option({odbc_server, Host}, ODBC_server, State);
{auth_method, Methods} ->
{Methods2, StorageOption} = replace_storage_auth(Host, Methods),
State2 = case StorageOption of
{auth_storage, Storage} ->
add_option({auth_storage, Host}, Storage, State);
undefined ->
State
end,
add_option({auth_method, Host}, Methods2, State2);
{Opt, Val} ->
add_option({Opt, Host}, Val, State)
end.
@@ -625,47 +570,20 @@ add_global_option(Opt, Val) ->
end).
add_local_option(Opt, Val) ->
mnesia:transaction(fun mne_add_local_option/2, [Opt, Val]).
mne_add_local_option(Opt, Val) ->
mnesia:write(#local_config{key = Opt,
value = Val}).
del_global_option(Opt) ->
mnesia:transaction(fun() ->
mnesia:delete({config, Opt})
end).
del_local_option(Opt) ->
mnesia:transaction(fun() ->
mnesia:delete({local_config, Opt})
mnesia:write(#local_config{key = Opt,
value = Val})
end).
get_global_option({Opt1, Host} = Opt) when is_list(Host) ->
case ets:lookup(config, Opt) of
[#config{value = Val}] ->
Val;
_ ->
get_global_option({Opt1, global})
end;
get_global_option(Opt) ->
case ets:lookup(config, Opt) of
[#config{value = Val}] when Opt == hosts ->
ensure_localhost_is_first(Val);
[#config{value = Val}] ->
Val;
_ ->
undefined
end.
get_local_option({Opt1, Host} = Opt) when is_list(Host) ->
case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] ->
Val;
_ ->
get_local_option({Opt1, global})
end;
get_local_option(Opt) ->
case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] ->
@@ -674,17 +592,6 @@ get_local_option(Opt) ->
undefined
end.
get_host_option(Host, Option) ->
case ets:lookup(local_config, {Option, Host}) of
[#local_config{value=V}] -> V;
_ -> undefined
end.
mne_del_local_option({_OptName, Host} = Opt) when is_list(Host) ->
mnesia:delete({local_config, Opt});
mne_del_local_option({Host, host} = Opt) when is_list(Host) ->
mnesia:delete({local_config, Opt}).
%% Return the list of hosts handled by a given module
get_vh_by_auth_method(AuthMethod) ->
mnesia:dirty_select(local_config,
@@ -703,86 +610,3 @@ is_file_readable(Path) ->
{error, _Reason} ->
false
end.
search(Pattern) ->
{atomic, Res} = mnesia:transaction(fun mnesia:select/2, [local_config, Pattern]),
Res.
for_host(Host) ->
mnesia:read({local_config, {Host, host}})
++ mnesia:select(local_config,
ets:fun2ms(fun (#local_config{key={_, H}})
when H =:= Host ->
object()
end))
++ acl:for_host(Host).
delete_host(Host) ->
mnesia_delete_objects(for_host(Host)),
ok.
configure_host(Host, Config) ->
HostExistenceTerm = {{Host, host}, []},
Records = host_terms_to_records(Host, [HostExistenceTerm | Config]),
mnesia_write_objects(Records),
ok.
host_terms_to_records(Host, Terms) ->
lists:foldl(fun (Term, Acc) ->
host_term_to_record(Term, Host, Acc)
end, [], Terms).
host_term_to_record({acl, ACLName, ACLData}, Host, Acc) ->
[acl:to_record(Host, ACLName, ACLData) | Acc];
host_term_to_record({access, RuleName, Rules}, Host, Acc) ->
[#config{key={access, RuleName, Host}, value=Rules} | Acc];
host_term_to_record({shaper, Name, Data}, Host, Acc) ->
[#config{key={shaper, Name, Host}, value=Data} | Acc];
host_term_to_record({host, _}, _Host, Acc) -> Acc;
host_term_to_record({hosts, _}, _Host, Acc) -> Acc;
host_term_to_record({{Host, host}, []}, Host, Acc) ->
[#local_config{key={Host, host}, value=[]} | Acc];
host_term_to_record({Opt, Val}, Host, Acc) when is_atom(Opt) ->
[#local_config{key={Opt, Host}, value=Val} | Acc].
mnesia_delete_objects(List) when is_list(List) ->
true = lists:all(fun (I) ->
ok =:= mnesia:delete_object(I)
end, List).
mnesia_write_objects(List) when is_list(List) ->
true = lists:all(fun (I) ->
ok =:= mnesia:write(I)
end, List).
%% Replace internal and odbc auth_methods with storage.
%% Only one storage type can be used, either internal or odbc.
replace_storage_auth(Host, Val) when not is_list(Val) ->
replace_storage_auth(Host, [Val]);
replace_storage_auth(Host, Val) ->
replace_storage_auth(Host, Val, [], undefined).
replace_storage_auth(_Host, [], Val2, Storage) ->
{lists:reverse(Val2), Storage};
replace_storage_auth(Host, [internal = Val | ValT], Val2, undefined) ->
Storage = {auth_storage, mnesia},
?WARNING_MSG("The auth method '~p' is deprecated.~nReplace it with 'storage'"
" and also add this option: ~n~p.", [Val, Storage]),
replace_storage_auth(Host, ValT, [storage | Val2], Storage);
replace_storage_auth(Host, [odbc = Val | ValT], Val2, undefined) ->
Storage = {auth_storage, odbc},
?WARNING_MSG("The auth method '~p' is deprecated.~nReplace it with 'storage'"
" and also add this option: ~n~p.", [Val, Storage]),
replace_storage_auth(Host, ValT, [storage | Val2], Storage);
replace_storage_auth(Host, [Val | ValT], Val2, Storage)
when (Val /= internal) and (Val /= odbc) ->
replace_storage_auth(Host, ValT, [Val | Val2], Storage);
replace_storage_auth(Host, [Val | _ValT], _Val2, Storage) ->
?CRITICAL_MSG("The auth method '~p' conflicts with~n~p in the host \"~p\"."
"~nOnly one of them can be used in each host.",
[Val, Storage, Host]),
throw({unacceptable_auth_conflict, Host, Val, Storage}).
+6 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -21,3 +21,8 @@
-record(config, {key, value}).
-record(local_config, {key, value}).
-record(state, {opts = [],
hosts = [],
override_local = false,
override_global = false,
override_acls = false}).
+34 -31
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Jan 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -190,7 +190,7 @@ process(["help" | Mode]) ->
print_usage_help(MaxC, ShCode),
?STATUS_SUCCESS;
[CmdString | _] ->
CmdStringU = re:replace(CmdString, "-", "_", [global, {return, list}]),
CmdStringU = ejabberd_regexp:greplace(CmdString, "-", "_"),
print_usage_commands(CmdStringU, MaxC, ShCode),
?STATUS_SUCCESS
end;
@@ -267,8 +267,10 @@ try_run_ctp(Args, Auth, AccessCommands) ->
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()}
try_call_command(Args, Auth, AccessCommands) ->
try call_command(Args, Auth, AccessCommands) of
{error, String} ->
{String, ?STATUS_ERROR};
{error, command_unknown} ->
{io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR};
{error, wrong_command_arguments} ->
{"Error: wrong arguments", ?STATUS_ERROR};
Res ->
Res
catch
@@ -277,13 +279,13 @@ try_call_command(Args, Auth, AccessCommands) ->
{io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR}
end.
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, string()}
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType}
call_command([CmdString | Args], Auth, AccessCommands) ->
CmdStringU = re:replace(CmdString, "-", "_", [global,{return,list}]),
CmdStringU = ejabberd_regexp:greplace(CmdString, "-", "_"),
Command = list_to_atom(CmdStringU),
case ejabberd_commands:get_command_format(Command) of
{error, command_unknown} ->
{error, io_lib:format("Error: command ~p not known.", [CmdString])};
{error, command_unknown};
{ArgsFormat, ResultFormat} ->
case (catch format_args(Args, ArgsFormat)) of
ArgsFormatted when is_list(ArgsFormatted) ->
@@ -296,8 +298,9 @@ call_command([CmdString | Args], Auth, AccessCommands) ->
{L1, L2} when L1 < L2 -> {L2-L1, "less argument"};
{L1, L2} when L1 > L2 -> {L1-L2, "more argument"}
end,
{error, io_lib:format("Error: the command ~p requires ~p ~s.",
[CmdString, NumCompa, TextCompa])}
{io_lib:format("Error: the command ~p requires ~p ~s.",
[CmdString, NumCompa, TextCompa]),
wrong_command_arguments}
end
end.
@@ -438,7 +441,8 @@ print_usage() ->
print_usage(dual, MaxC, ShCode).
print_usage(HelpMode, MaxC, ShCode) ->
AllCommands =
[{"status", [], "Get ejabberd status"},
[
{"status", [], "Get ejabberd status"},
{"stop", [], "Stop ejabberd"},
{"restart", [], "Restart ejabberd"},
{"help", ["[--tags [tag] | com?*]"], "Show help (try: ejabberdctl help help)"},
@@ -610,30 +614,30 @@ print_usage_tags(Tag, MaxC, ShCode) ->
print_usage_help(MaxC, ShCode) ->
LongDesc =
"The special 'help' ejabberdctl command provides help of ejabberd commands.\n\n"
"The format is:\n "++?B("ejabberdctl")++" "++?B("help")++" ["++?B("--tags")++" "++?U("[tag]")++" | "++?U("com?*")++"]\n\n"
["The special 'help' ejabberdctl command provides help of ejabberd commands.\n\n"
"The format is:\n ", ?B("ejabberdctl"), " ", ?B("help"), " [", ?B("--tags"), " ", ?U("[tag]"), " | ", ?U("com?*"), "]\n\n"
"The optional arguments:\n"
" "++?B("--tags")++" Show all tags and the names of commands in each tag\n"
" "++?B("--tags")++" "++?U("tag")++" Show description of commands in this tag\n"
" "++?U("command")++" Show detailed description of the command\n"
" "++?U("com?*")++" Show detailed description of commands that match this glob.\n"
" ",?B("--tags")," Show all tags and the names of commands in each tag\n"
" ",?B("--tags"), " ", ?U("tag")," Show description of commands in this tag\n"
" ",?U("command")," Show detailed description of the command\n"
" ",?U("com?*")," Show detailed description of commands that match this glob.\n"
" You can use ? to match a simple character,\n"
" and * to match several characters.\n"
"\n"
"Some example usages:\n"
" ejabberdctl help\n"
" ejabberdctl help --tags\n"
" ejabberdctl help --tags accounts\n"
" ejabberdctl help register\n"
" ejabberdctl help regist*\n"
"\n"
"Please note that 'ejabberdctl help' shows all ejabberd commands,\n"
"even those that cannot be used in the shell with ejabberdctl.\n"
"Those commands can be identified because the description starts with: *",
"\n",
"Some example usages:\n",
" ejabberdctl help\n",
" ejabberdctl help --tags\n",
" ejabberdctl help --tags accounts\n",
" ejabberdctl help register\n",
" ejabberdctl help regist*\n",
"\n",
"Please note that 'ejabberdctl help' shows all ejabberd commands,\n",
"even those that cannot be used in the shell with ejabberdctl.\n",
"Those commands can be identified because the description starts with: *"],
ArgsDef = [],
C = #ejabberd_commands{
desc = "Show help of ejabberd commands",
longdesc = LongDesc,
longdesc = lists:flatten(LongDesc),
args = ArgsDef,
result = {help, string}},
print_usage_command("help", C, MaxC, ShCode).
@@ -674,10 +678,10 @@ filter_commands(All, SubString) ->
end.
filter_commands_regexp(All, Glob) ->
RegExp = xmerl_regexp:sh_to_awk(Glob),
RegExp = ejabberd_regexp:sh_to_awk(Glob),
lists:filter(
fun(Command) ->
case re:run(Command, RegExp, [{capture, none}]) of
case ejabberd_regexp:run(Command, RegExp) of
match ->
true;
nomatch ->
@@ -696,7 +700,6 @@ print_usage_command(Cmd, MaxC, ShCode) ->
print_usage_command(Cmd, C, MaxC, ShCode)
end.
%% @spec (Cmd::string(), C::ejabberd_commands(), MaxC::integer(), ShCode::boolean()) -> ok
print_usage_command(Cmd, C, MaxC, ShCode) ->
#ejabberd_commands{
tags = TagsAtoms,
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+48 -43
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Aug 2006 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -45,8 +45,6 @@
get_peer_certificate/1,
get_verify_result/1,
close/1,
setopts/2,
change_controller/2,
sockname/1, peername/1]).
%% gen_server callbacks
@@ -96,15 +94,18 @@ start(Module, SockMod, Socket, Opts) ->
todo
end.
starttls(FsmRef, TLSOpts) ->
starttls(FsmRef, TLSOpts, undefined).
starttls(FsmRef, _TLSOpts) ->
%% TODO: Frontend improvements planned by Aleksey
%%gen_server:call(FsmRef, {starttls, TLSOpts}),
FsmRef.
starttls(FsmRef, TLSOpts, Data) ->
gen_server:call(FsmRef, {starttls, TLSOpts, Data}),
FsmRef.
compress(FsmRef) ->
compress(FsmRef, undefined).
gen_server:call(FsmRef, compress),
FsmRef.
compress(FsmRef, Data) ->
gen_server:call(FsmRef, {compress, Data}),
@@ -137,14 +138,11 @@ close(FsmRef) ->
sockname(FsmRef) ->
gen_server:call(FsmRef, sockname).
setopts(FsmRef, Opts) ->
gen_server:call(FsmRef, {setopts, Opts}).
peername(_FsmRef) ->
%% TODO: Frontend improvements planned by Aleksey
%%gen_server:call(FsmRef, peername).
{ok, {{0, 0, 0, 0}, 0}}.
change_controller(FsmRef, C2SPid) ->
gen_server:call(FsmRef, {change_controller, C2SPid}).
peername(FsmRef) ->
gen_server:call(FsmRef, peername).
%%====================================================================
%% gen_server callbacks
@@ -160,16 +158,9 @@ peername(FsmRef) ->
init([Module, SockMod, Socket, Opts, Receiver]) ->
%% TODO: monitor the receiver
Node = ejabberd_node_groups:get_closest_node(backend),
IP = case peername(SockMod, Socket) of
{ok, IP1} ->
IP1;
_ ->
undefined
end,
{SockMod2, Socket2} = check_starttls(SockMod, Socket, Receiver, Opts),
{ok, Pid} =
rpc:call(Node, Module, start,
[{?MODULE, self()}, [{frontend_ip, IP} | Opts]]),
rpc:call(Node, Module, start, [{?MODULE, self()}, Opts]),
ejabberd_receiver:become_controller(Receiver, Pid),
{ok, #state{sockmod = SockMod2,
socket = Socket2,
@@ -184,16 +175,38 @@ init([Module, SockMod, Socket, Opts, Receiver]) ->
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({starttls, TLSOpts, Data}, _From, State) ->
{ok, TLSSocket} = ejabberd_receiver:starttls(
State#state.receiver, TLSOpts, Data),
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};
handle_call({starttls, TLSOpts, Data}, _From, State) ->
{ok, TLSSocket} = tls:tcp_to_tls(State#state.socket, TLSOpts),
ejabberd_receiver:starttls(State#state.receiver, TLSSocket),
catch (State#state.sockmod):send(
State#state.socket, Data),
Reply = ok,
{reply, Reply, State#state{socket = TLSSocket, sockmod = tls},
?HIBERNATE_TIMEOUT};
handle_call(compress, _From, State) ->
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
State#state.sockmod,
State#state.socket),
ejabberd_receiver:compress(State#state.receiver, ZlibSocket),
Reply = ok,
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
?HIBERNATE_TIMEOUT};
handle_call({compress, Data}, _From, State) ->
{ok, ZlibSocket} = ejabberd_receiver:compress(
State#state.receiver, Data),
{ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
State#state.sockmod,
State#state.socket),
ejabberd_receiver:compress(State#state.receiver, ZlibSocket),
catch (State#state.sockmod):send(
State#state.socket, Data),
Reply = ok,
{reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
?HIBERNATE_TIMEOUT};
@@ -233,7 +246,13 @@ handle_call(close, _From, State) ->
handle_call(sockname, _From, State) ->
#state{sockmod = SockMod, socket = Socket} = State,
Reply = peername(SockMod, Socket),
Reply =
case SockMod of
gen_tcp ->
inet:sockname(Socket);
_ ->
SockMod:sockname(Socket)
end,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
handle_call(peername, _From, State) ->
@@ -247,14 +266,6 @@ handle_call(peername, _From, State) ->
end,
{reply, Reply, State, ?HIBERNATE_TIMEOUT};
handle_call({setopts, Opts}, _From, State) ->
ejabberd_receiver:setopts(State#state.receiver, Opts),
{reply, ok, State, ?HIBERNATE_TIMEOUT};
handle_call({change_controller, Pid}, _From, State) ->
ejabberd_receiver:change_controller(State#state.receiver, Pid),
{reply, ok, State, ?HIBERNATE_TIMEOUT};
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State, ?HIBERNATE_TIMEOUT}.
@@ -307,16 +318,10 @@ check_starttls(SockMod, Socket, Receiver, Opts) ->
end, Opts),
if
TLSEnabled ->
{ok, TLSSocket} = ejabberd_receiver:starttls(Receiver, TLSOpts),
{ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts),
ejabberd_receiver:starttls(Receiver, TLSSocket),
{tls, TLSSocket};
true ->
{SockMod, Socket}
end.
peername(SockMod, Socket) ->
case SockMod of
gen_tcp ->
inet:peername(Socket);
_ ->
SockMod:peername(Socket)
end.
-280
View File
@@ -1,280 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_global_router.erl
%%% Author : Geoff Cant <gcant@process-one.net>
%%% Purpose : Router for virtual global routes
%%% Created : 07 Aug 2002 by Geoff Cant <gcant@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2009 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_global_router).
-behaviour(gen_server).
-include("ejabberd.hrl").
-include("ejabberd_global_router.hrl").
%% API
-export([start_link/0
,route/3
,route/4
,find_route/1
,register_route/1
,register_route/2
,unregister_route/1
,unregister_route/2
,expand_routes/1
,all_prefixes/0
,server_host/2
]).
%% Eunit test exports.
-export([remove_prefix/2
,find_prefix/2
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {}).
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% @spec start_link() -> {ok,Pid} | ignore | {error,Error}
%% @doc Starts the server
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
route(From, To, Packet) ->
case find_route(To) of
Route = #global_route{} ->
route(Route, From, To, Packet);
no_route ->
ok
end.
route(#global_route{pids=Pids}, From, To, Packet) ->
Pid = pick_route(Pids),
Pid ! {route, From, To, Packet},
ok.
find_route(Domain) ->
case prefix_match(Domain, all_prefixes()) of
nomatch ->
no_route;
Prefix when is_list(Prefix) ->
dirty_get_route(Prefix)
end.
register_route(Prefix) ->
register_route(Prefix, self()).
register_route(Prefix, Pid) ->
Route = #global_route{prefix=Prefix,
pids=[Pid]},
{atomic, ok} = mnesia:transaction(fun write_route/1,
[Route]),
ok.
unregister_route(Prefix) ->
unregister_route(Prefix, self()).
unregister_route(Prefix, Pid) ->
mnesia:transaction(fun delete_route/2, [Prefix, Pid]).
expand_routes(Domain) ->
[expand_route(Prefix, Domain) || Prefix <- all_prefixes()].
expand_route(Prefix, Domain) ->
lists:append([Prefix, ".", Domain]).
all_prefixes() ->
mnesia:dirty_all_keys(global_route).
server_host(Host, Pid) ->
#global_route{prefix=P,pids=Pids} = find_route(Host),
true = lists:member(Pid, Pids),
remove_prefix(P, Host).
%%====================================================================
%% gen_server callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% @private
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @doc Initialises the server's state
%% @end
%%--------------------------------------------------------------------
init([]) ->
update_tables(),
mnesia:create_table(global_route,
[{ram_copies, [node()]},
{type, set},
{attributes,
record_info(fields, global_route)}]),
mnesia:add_table_copy(global_route, node(), ram_copies),
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @spec
%% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @doc Call message handler callbacks
%% @end
%%--------------------------------------------------------------------
handle_call(Call, _From, State) ->
?WARNING_MSG("Unexpected call ~p.", [Call]),
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @spec
%% handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @doc Cast message handler callbacks
%% @end
%%--------------------------------------------------------------------
handle_cast(Msg, State) ->
?WARNING_MSG("Unexpected cast ~p", [Msg]),
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @spec
%% handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @doc Non gen-server message handler callbacks
%% @end
%%--------------------------------------------------------------------
handle_info(Info, State) ->
?WARNING_MSG("Unexpected info ~p", [Info]),
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @spec terminate(Reason, State) -> void()
%% @doc This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @doc Convert process state when code is changed
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
pick_route(Pids) when is_list(Pids) ->
pick_local_route(Pids).
pick_local_route(Pids) when is_list(Pids) ->
case [Pid || Pid <- Pids,
node(Pid) =:= node()] of
[] -> pick_remote_route(Pids);
LocalPids -> pick_one_route(LocalPids)
end.
pick_remote_route(Pids) when is_list(Pids) -> pick_one_route(Pids).
pick_one_route(Pids) when is_list(Pids) ->
hd(Pids). % should pick random pid?
update_tables() ->
CorrectAttributes = record_info(fields, global_route),
case catch mnesia:table_info(global_route, attributes) of
CorrectAttributes ->
ok;
IncorrectAttributes when is_list(IncorrectAttributes) ->
mnesia:delete_table(global_route);
{'EXIT', _} ->
ok
end.
write_route(R = #global_route{prefix=Prefix}) ->
NewRoute = case mnesia:read({global_route, Prefix}) of
[] -> R;
[OldRoute] ->
combine_routes(OldRoute, R)
end,
ok = mnesia:write(NewRoute).
delete_route(Prefix, Pid) ->
case mnesia:read({global_route, Prefix}, write) of
[] -> ok;
[#global_route{pids=[Pid]}] ->
mnesia:delete({global_route, Prefix});
[Route = #global_route{pids=Pids}] ->
mnesia:write(Route#global_route{pids=Pids -- [Pid]})
end.
combine_routes(R = #global_route{prefix=P, pids=APids},
#global_route{prefix=P, pids=BPids}) ->
R#global_route{pids=lists:usort(APids ++ BPids)}.
prefix_match(Domain, Prefixes) ->
case find_prefix(Domain, Prefixes) of
[] -> nomatch;
[Prefix] -> Prefix;
_Prefixes ->
erlang:error(multiple_prefix_matches)
end.
dirty_get_route(Prefix) ->
case mnesia:dirty_read({global_route, Prefix}) of
[Route = #global_route{}] ->
Route;
_ -> no_route
end.
find_prefix(Domain, PossiblePrefixes) ->
[Prefix
|| Prefix <- PossiblePrefixes,
lists:prefix(Prefix, Domain)].
remove_prefix(Prefix, Domain) ->
[$. | BareDomain] = Domain -- Prefix,
BareDomain.
%%--------------------------------------------------------------------
%%% Eunit Tests.
%%--------------------------------------------------------------------
-27
View File
@@ -1,27 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_global_router.hrl
%%% Author : Geoff Cant <gcant@process-one.net>
%%% Purpose : Virtual global routes record definitions
%%% Created : 08 Aug 2002 by Geoff Cant <gcant@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2009 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(global_route, {prefix, pids}).
+17 -49
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -81,8 +81,7 @@ add(Hook, Host, Function, Seq) when is_function(Function) ->
add(Hook, Module, Function, Seq) ->
add(Hook, global, Module, Function, Seq).
add(Hook, Host, Module, Function, Seq)
when is_binary(Host) orelse is_atom(Host) ->
add(Hook, Host, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}).
add_dist(Hook, Node, Module, Function, Seq) ->
@@ -105,8 +104,7 @@ delete(Hook, Host, Function, Seq) when is_function(Function) ->
delete(Hook, Module, Function, Seq) ->
delete(Hook, global, Module, Function, Seq).
delete(Hook, Host, Module, Function, Seq)
when is_binary(Host) orelse is_atom(Host) ->
delete(Hook, Host, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}).
delete_dist(Hook, Node, Module, Function, Seq) ->
@@ -119,27 +117,14 @@ delete_dist(Hook, Host, Node, Module, Function, Seq) ->
%% @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) ->
runx(Hook, global, Args).
run(Hook, global, Args).
run(Hook, Host, Args) when is_binary(Host) ->
case runx(Hook, Host, Args) of
stop -> stop;
_ -> runx(Hook, global, Args)
end;
run(Hook, Host, Args) when Host == global ->
runx(Hook, Host, Args).
runx(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) ->
case ets:lookup(hooks, {Hook, ejabberd:normalize_host(Host)}) of
run(Hook, Host, Args) ->
case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
run1(Ls, Hook, Args);
[] ->
case ets:lookup(hooks, {Hook, global}) of
[{_, Ls}] ->
run1(Ls, Hook, Args);
[] ->
ok
end
ok
end.
%% @spec (Hook::atom(), Val, Args) -> Val | stopped | NewVal
@@ -149,29 +134,14 @@ runx(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) ->
%% 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_foldx(Hook, global, Val, Args).
run_fold(Hook, global, Val, Args).
%% @spec (Hook::atom(), Host, Val, Args) -> Val | stopped | NewVal
%% Host = global | binary()
run_fold(Hook, Host, Val, Args) when is_binary(Host) ->
case run_foldx(Hook, Host, Val, Args) of
stopped -> stopped;
Val2 -> run_foldx(Hook, global, Val2, Args)
end;
run_fold(Hook, Host, Val, Args) when Host == global ->
run_foldx(Hook, Host, Val, Args).
run_foldx(Hook, Host, Val, Args) ->
case ets:lookup(hooks, {Hook, ejabberd:normalize_host(Host)}) of
run_fold(Hook, Host, Val, Args) ->
case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
run_fold1(Ls, Hook, Val, Args);
[] ->
case ets:lookup(hooks, {Hook, global}) of
[{_, Ls}] ->
run_fold1(Ls, Hook, Val, Args);
[] ->
Val
end
Val
end.
%%%----------------------------------------------------------------------
@@ -199,8 +169,7 @@ init([]) ->
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) ->
NHost = ejabberd:normalize_host(Host),
Reply = case ets:lookup(hooks, {Hook, NHost}) of
Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
El = {Seq, Module, Function},
case lists:member(El, Ls) of
@@ -208,12 +177,12 @@ handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) ->
ok;
false ->
NewLs = lists:merge(Ls, [El]),
ets:insert(hooks, {{Hook, NHost}, NewLs}),
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok
end;
[] ->
NewLs = [{Seq, Module, Function}],
ets:insert(hooks, {{Hook, NHost}, NewLs}),
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok
end,
{reply, Reply, State};
@@ -236,11 +205,10 @@ handle_call({add, Hook, Host, Node, Module, Function, Seq}, _From, State) ->
end,
{reply, Reply, State};
handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) ->
NHost = ejabberd:normalize_host(Host),
Reply = case ets:lookup(hooks, {Hook, NHost}) of
Reply = case ets:lookup(hooks, {Hook, Host}) of
[{_, Ls}] ->
NewLs = lists:delete({Seq, Module, Function}, Ls),
ets:insert(hooks, {{Hook, NHost}, NewLs}),
ets:insert(hooks, {{Hook, Host}, NewLs}),
ok;
[] ->
ok
@@ -327,7 +295,7 @@ run1([{_Seq, Module, Function} | Ls], Hook, Args) ->
[Reason, {Hook, Args}]),
run1(Ls, Hook, Args);
stop ->
stop;
ok;
_ ->
run1(Ls, Hook, Args)
end.
-492
View File
@@ -1,492 +0,0 @@
%%%-------------------------------------------------------------------
%%% File : ejabberd_hosts.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Description : Synchronises running VHosts with the hosts table in the Mnesia database.
%%% Created : 16 Nov 2007 by Alexey Shchepin <alexey@process-one.net>
%%%-------------------------------------------------------------------
%%% Database schema (version / storage / table)
%%%
%%% 3.0.0-alpha-x / mnesia / hosts
%%% host = string()
%%% clusterid = integer()
%%% config = string()
%%%
%%% 3.0.0-alpha-x / odbc / hosts
%%% host = varchar150
%%% clusterid = integer
%%% config = text
-module(ejabberd_hosts).
-behaviour(gen_server).
%% External API
-export([start_link/0
,reload/0
]).
%% Host Registration API
-export([register/1
,register/2
,registered/1
,running/1
,registered/0
,remove/1
,update_host_conf/2
]).
%% Host control API
-export([start_host/1
,start_hosts/1
,stop_host/1
,stop_hosts/1
,load_host_cert/2
]).
%% Private utility functions
-export([get_hosts/1
,config_from_string/2
,get_host_config/2
,diff_hosts/0
,diff_hosts/1
,diff_hosts/2
,reload_hosts/0
,delete_host_config/1
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd_config.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-record(state, {state=wait_odbc,
backend=mnesia,
odbc_wait_time=120}).
-record(hosts, {host, clusterid, config}).
-define(RELOAD_INTERVAL, timer:seconds(60)).
-define(ODBC_STARTUP_TIME, 120). % 2minute limit for ODBC startup.
%% The vhost where the table 'hosts' is stored
%% The table 'hosts' is defined in gen_storage as being for the "localhost" vhost
-define(HOSTS_HOST, list_to_binary(?MYNAME)).
%%====================================================================
%% API
%%====================================================================
reload() ->
?MODULE ! reload.
%% Creates a vhost in the system.
register(Host) when is_list(Host) -> ?MODULE:register(Host, "").
register(Host, Config) when is_list(Host), is_list(Config) ->
true = exmpp_stringprep:is_node(Host),
ID = get_clusterid(),
H = #hosts{host = Host, clusterid = ID, config = Config},
ok = gen_storage:dirty_write(?HOSTS_HOST, H),
reload(),
ok.
%% Updates host configuration
update_host_conf(Host, Config) when is_list(Host), is_list(Config) ->
true = exmpp_stringprep:is_node(Host),
case registered(Host) of
false -> {error, host_process_not_registered};
true ->
remove(Host),
?MODULE:register(Host, Config)
end.
%% Removes a vhost from the system,
%% XXX deleting all ODBC data.
remove(Host) when is_list(Host) ->
true = exmpp_stringprep:is_node(Host),
ID = get_clusterid(),
gen_storage:dirty_delete_where(
?HOSTS_HOST, hosts,
[{'andalso',
{'==', clusterid, ID},
{'==', host, Host}}]),
reload(),
ok.
registered() ->
mnesia:dirty_select(local_config,
ets:fun2ms(fun (#local_config{key={Host, host}}) ->
Host
end)).
registered(Host) when is_list(Host) ->
case mnesia:dirty_read({local_config, {Host, host}}) of
[{local_config, {Host, host}, _}] -> true;
[] -> false
end.
running(global) -> true;
running(HostString) when is_list(HostString) ->
Host = list_to_binary(HostString),
Routes = [H
|| {H, _, {apply, ejabberd_local, route}} <- ejabberd_router:read_route(Host),
H =:= Host],
Routes =/= [].
load_host_cert(Host, PemData) ->
File = cert_filename(Host),
ok = file:write_file(File, PemData),
configure_host_cert(Host, File).
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
%%====================================================================
%% gen_server callbacks
%%====================================================================
%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([]) ->
Backend = mnesia, %%+++ TODO: allow to configure this in ejabberd.cfg
configure_static_hosts(),
get_clusterid(), %% this is to report an error if the option wasn't configured
ejabberd_commands:register_commands(commands()),
%% Wait up to 120 seconds for odbc to start
{ok, #state{state=wait_odbc,backend=Backend,odbc_wait_time=?ODBC_STARTUP_TIME}, timer:seconds(1)}.
%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
%% Wait for odbc to start.
handle_info(timeout, State = #state{state=wait_odbc,backend=Backend,odbc_wait_time=N}) when N > 0 ->
case (Backend /= odbc) orelse ejabberd_odbc:running(?MYNAME) of
true ->
?DEBUG("ejabberd_hosts: odbc now running.",[]),
%% The table 'hosts' is defined in gen_storage as being for the "localhost" vhost
Host = ?MYNAME,
HostB = list_to_binary(Host),
gen_storage:create_table(Backend, HostB, hosts,
[{disc_only_copies, [node()]},
{odbc_host, Host},
{attributes, record_info(fields, hosts)},
{types, [{host, text},
{clusterid, int},
{config, text}]}]),
%% Now let's add the default vhost: "localhost"
gen_storage:dirty_write(HostB, #hosts{host = Host,
clusterid = 1,
config = ""}),
self() ! reload,
timer:send_interval(?RELOAD_INTERVAL, reload),
{noreply, State#state{state=running,odbc_wait_time=0}};
false ->
{noreply,State#state{odbc_wait_time=N-1},timer:seconds(1)}
end;
handle_info(timeout, State=#state{state=running}) ->
?WARNING_MSG("Spurious timeout message when odbc is already running.", []),
{noreply, State};
handle_info(reload, State = #state{state=running}) ->
try reload_hosts()
catch
Class:Error ->
StackTrace = erlang:get_stacktrace(),
?ERROR_MSG("~p while synchonising running vhosts with database: ~p~n~p", [Class, Error, StackTrace])
end,
{noreply, State};
handle_info(reload, State = #state{state=wait_odbc}) ->
?ERROR_MSG("Tried to reload vhosts while waiting for odbc startup.", []),
handle_info(timeout, State);
handle_info({reload, Host}, State = #state{state=running}) ->
try reload_host(Host)
catch
Class:Error ->
StackTrace = erlang:get_stacktrace(),
?ERROR_MSG("~p while synchonising running ~p with database: ~p~n~p", [Host, Class, Error, StackTrace])
end,
{noreply, State};
handle_info({reload, Host}, State = #state{state=wait_odbc}) ->
?ERROR_MSG("Tried to reload ~p while waiting for odbc startup.", [Host]),
handle_info(timeout, State);
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ejabberd_commands:unregister_commands(commands()),
ok.
%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
reload_hosts() ->
reload_hosts(get_hosts(odbc)).
reload_hosts(NewHosts) ->
{AddedHosts,RemovedHosts} = diff_hosts(NewHosts),
%% Avoid removing permanent hosts (staticly configured hosts)
DeletedHosts = [H || H <- RemovedHosts,
ejabberd_config:get_host_option(H, permanent) =/= true],
AddHostConfig = lists:map(fun (Host) ->
{Host, get_host_config(odbc,Host)}
end, AddedHosts),
update_config(AddHostConfig,DeletedHosts),
RemovedNotDelete = RemovedHosts -- DeletedHosts,
ejabberd_config:add_global_option(hosts, NewHosts++RemovedNotDelete), % overwrite hosts list
stop_hosts(DeletedHosts),
start_hosts(AddedHosts),
ejabberd_local:refresh_iq_handlers(),
{DeletedHosts, AddedHosts}.
%% updates the configuration of an existing virtual host
reload_host(Host) ->
Config = get_host_config(odbc,Host),
F = fun() ->
mnesia:write_lock_table(local_config),
ejabberd_config:configure_host(Host, Config),
ok
end,
{atomic, ok} = mnesia:transaction(F),
% restart host
stop_host(Host),
start_host(Host),
ejabberd_local:refresh_iq_handlers(),
ok.
%% Apply the vhost changes (new, removed vhosts, configuration) to mnesia
update_config(AddHostConfig, RemoveHosts) ->
F = fun() ->
mnesia:write_lock_table(local_config),
lists:foreach(fun configure_new_host/1, AddHostConfig),
lists:foreach(fun delete_host_config/1, RemoveHosts),
ok
end,
{atomic, ok} = mnesia:transaction(F).
%% Write the configuration data for a new vhost to mnesia (currently only modules)
configure_new_host({H, Config}) when is_list(Config) ->
reconfigure_host_cert(H),
ejabberd_config:configure_host(H, Config).
%% Delete the mnesia config data for a vhost.
%% Needs to mirror any data we insert in configure_new_host (currently only modules)
delete_host_config(Host) ->
ejabberd_config:delete_host(Host).
%% Startup a list of vhosts
start_hosts([]) -> ok;
start_hosts(AddHosts) when is_list(AddHosts) ->
?DEBUG("ejabberd_hosts adding hosts: ~P", [AddHosts, 10]),
lists:foreach(fun start_host/1, AddHosts).
%% Start a single vhost (route, modules)
start_host(Host) when is_list(Host) ->
?DEBUG("Starting host ~p", [Host]),
ejabberd_router:register_route(Host, {apply, ejabberd_local, route}),
case ejabberd_config:get_local_option({modules, Host}) of
undefined -> ok;
Modules when is_list(Modules) ->
lists:foreach(
fun({Module, Args}) ->
gen_mod:start_module(Host, Module, Args)
end, Modules)
end,
case auth_method(Host) of
{host_method, HostMethod} ->
ejabberd_auth:start_method(Host, HostMethod)
end,
ok.
%% Shut down a list of vhosts.
stop_hosts([]) -> ok;
stop_hosts(RemoveHosts) when is_list(RemoveHosts)->
?DEBUG("ejabberd_hosts removing hosts: ~p", [RemoveHosts]),
lists:foreach(fun stop_host/1, RemoveHosts).
%% Shut down a single vhost. (Routes, modules)
stop_host(Host) when is_list(Host) ->
?DEBUG("Stopping host ~p", [Host]),
ejabberd_router:force_unregister_route(list_to_binary(Host)),
lists:foreach(fun(Module) ->
gen_mod:stop_module_keep_config(Host, Module)
end, gen_mod:loaded_modules(Host)),
case auth_method(Host) of
{host_method, Method} ->
ejabberd_auth:stop_method(Host, Method)
end.
%% Get the current vhost list from a variety of sources (ODBC, internal)
get_hosts(ejabberd) -> ?MYHOSTS;
get_hosts(odbc) ->
ClusterID = get_clusterid(),
Hosts = gen_storage:dirty_select(?HOSTS_HOST, hosts, [{'=', clusterid, ClusterID}]),
lists:map(fun (#hosts{host = Host}) ->
exmpp_stringprep:nameprep(Host)
end, Hosts).
%% Retreive the text format config for host Host from ODBC and covert
%% it into a {host, Host, Config} tuple.
get_host_config(odbc, Host) ->
case gen_storage:dirty_read(?HOSTS_HOST, hosts, Host) of
[] ->
erlang:error({no_such_host, Host});
[H] ->
config_from_string(Host, H#hosts.config);
E ->
erlang:error({host_config_error, E})
end.
%% Convert a plaintext string into a host config tuple.
config_from_string(_Host, "") -> [];
config_from_string(_Host, Config) ->
{ok, Tokens, _} = erl_scan:string(Config),
case erl_parse:parse_term(Tokens) of
{ok, List} when is_list(List) ->
List;
E ->
erlang:error({bad_host_config, Config, E})
end.
diff_hosts() ->
diff_hosts(get_hosts(odbc)).
diff_hosts(NewHosts) ->
diff_hosts(NewHosts, get_hosts(ejabberd)).
%% Given the new list of vhosts and the old list, return the list of
%% hosts added since last time and the list of hosts that have been
%% removed.
diff_hosts(NewHosts, OldHosts) ->
RemoveHosts = OldHosts -- NewHosts,
AddHosts = NewHosts -- OldHosts,
{AddHosts,RemoveHosts}.
%% XXX - this should be part of auth, not hosts.
auth_method(Host) ->
case ejabberd_config:get_host_option(Host, auth_method) of
undefined ->
[Default] = ejabberd_config:get_host_option(global, auth_method),
{host_method, Default};
Other ->
{host_method, Other}
end.
configure_static_hosts() ->
?DEBUG("Node startup - configuring hosts: ~p", [?MYHOSTS]),
%% Add a null configuration for all MYHOSTS - this ensures
%% the 'I'm a host' term gets written to the config table.
%% We don't need any configuration options because these are
%% statically configured hosts already configured by ejabberd_config.
F = fun () ->
lists:foreach(fun (H) -> ejabberd_config:configure_host(H, [{permanent, true}]) end,
?MYHOSTS)
end,
mnesia:transaction(F).
cert_filename(Host) ->
Dir = ejabberd_config:get_local_option({domain_certdir, global}),
filename:join(Dir, Host ++ ".pem").
configure_host_cert(Host, File) ->
ejabberd_config:add_local_option({domain_certfile, Host}, File),
ok.
reconfigure_host_cert(Host) ->
File = cert_filename(Host),
case ejabberd_config:is_file_readable(File) of
true ->
ejabberd_config:mne_add_local_option({domain_certfile, Host}, File),
ok;
false ->
no_cert
end.
get_clusterid() ->
case ejabberd_config:get_local_option(clusterid) of
ID when is_integer(ID) ->
ID;
undefined ->
?ERROR_MSG("Please add to your ejabberd.cfg the line: ~n {clusterid, 1}.", []),
1;
Other ->
?ERROR_MSG("Change your misconfigured {clusterid, ~p} to the value: ~p", [Other, 1]),
1
end.
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 = host_list, tags = [hosts],
desc = "Get a list of registered virtual hosts",
module = ?MODULE, function = registered,
args = [],
result = {hosts, {list, {host, string}}}},
#ejabberd_commands{name = host_register, tags = [hosts],
desc = "Register and start a virtual host",
module = ?MODULE, function = register,
args = [{host, string}], result = {res, rescode}},
#ejabberd_commands{name = host_remove, tags = [hosts],
desc = "Stop and remove a virtual host",
module = ?MODULE, function = remove,
args = [{host, string}], result = {res, rescode}}
].
+6 -46
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -35,8 +35,7 @@
stop_listener/2,
parse_listener_portip/2,
add_listener/3,
delete_listener/2,
rate_limit/2
delete_listener/2
]).
-include("ejabberd.hrl").
@@ -275,9 +274,6 @@ get_ip_tuple(IPOpt, _IPVOpt) ->
IPOpt.
accept(ListenSocket, Module, Opts) ->
accept(ListenSocket, Module, Opts, 0).
accept(ListenSocket, Module, Opts, Interval) ->
NewInterval = check_rate_limit(Interval),
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
case {inet:sockname(Socket), inet:peername(Socket)} of
@@ -292,11 +288,11 @@ accept(ListenSocket, Module, Opts, Interval) ->
false -> ejabberd_socket
end,
CallMod:start(strip_frontend(Module), gen_tcp, Socket, Opts),
accept(ListenSocket, Module, Opts, NewInterval);
accept(ListenSocket, Module, Opts);
{error, Reason} ->
?INFO_MSG("(~w) Failed TCP accept: ~w",
[ListenSocket, Reason]),
accept(ListenSocket, Module, Opts, NewInterval)
?ERROR_MSG("(~w) Failed TCP accept: ~w",
[ListenSocket, Reason]),
accept(ListenSocket, Module, Opts)
end.
udp_recv(Socket, Module, Opts) ->
@@ -524,39 +520,3 @@ format_error(Reason) ->
ReasonStr ->
ReasonStr
end.
%% Set interval between two accepts on given port
rate_limit([], _Interval) ->
ok;
rate_limit([Port|Ports], Interval) ->
rate_limit(Port, Interval),
rate_limit(Ports, Interval);
rate_limit(Port, Interval) ->
case get_listener_pid_by_port(Port) of
undefined -> no_listener;
Pid -> Pid ! {rate_limit, Interval}, ok
end.
get_listener_pid_by_port(Port) ->
ListenerPids = [Pid || {{P,_,_},Pid,_,_} <-
supervisor:which_children(erlang:whereis(ejabberd_listeners)),
P == Port],
ListenerPid = case ListenerPids of
[] -> undefined;
[LPid|_] -> LPid
end,
ListenerPid.
check_rate_limit(Interval) ->
NewInterval = receive
{rate_limit, AcceptInterval} ->
AcceptInterval
after 0 ->
Interval
end,
case NewInterval of
0 -> ok;
Ms ->
timer:sleep(Ms)
end,
NewInterval.
+77 -93
View File
@@ -5,7 +5,7 @@
%%% Created : 30 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -50,9 +50,8 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include_lib("exmpp/include/exmpp.hrl").
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(state, {}).
@@ -63,12 +62,6 @@
%% This value is used in SIP and Megaco for a transaction lifetime.
-define(IQ_TIMEOUT, 32000).
% These are the namespace already declared by the stream opening. This is
% used at serialization time.
-define(DEFAULT_NS, ?NS_JABBER_CLIENT).
-define(PREFIXED_NS,
[{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]).
%%====================================================================
%% API
%%====================================================================
@@ -80,38 +73,33 @@ start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
process_iq(From, To, Packet) ->
case exmpp_iq:xmlel_to_iq(Packet) of
#iq{kind = request, ns = XMLNS} = IQ_Rec ->
Host = exmpp_jid:prep_domain(To),
case ets:lookup(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}) of
IQ = jlib:iq_query_info(Packet),
case IQ of
#iq{xmlns = XMLNS} ->
Host = To#jid.lserver,
case ets:lookup(?IQTABLE, {XMLNS, Host}) of
[{_, Module, Function}] ->
ResIQ = Module:Function(From, To, IQ_Rec),
ResIQ = Module:Function(From, To, IQ),
if
ResIQ /= ignore ->
Reply = exmpp_iq:iq_to_xmlel(ResIQ, To, From),
ejabberd_router:route(To, From, Reply);
ejabberd_router:route(
To, From, jlib:iq_to_xml(ResIQ));
true ->
ok
end;
[{_, Module, Function, Opts}] ->
gen_iq_handler:handle(Host, Module, Function, Opts,
From, To, IQ_Rec);
From, To, IQ);
[] ->
case ets:lookup(?IQTABLE, {XMLNS, global}) of
[{_, Module, Function, Opts}] ->
gen_iq_handler:handle(
global, Module, Function, Opts,
From, To, IQ_Rec);
[] ->
Err = exmpp_iq:error(Packet, 'feature-not-implemented'),
ejabberd_router:route(To, From, Err)
end
Err = jlib:make_error_reply(
Packet, ?ERR_FEATURE_NOT_IMPLEMENTED),
ejabberd_router:route(To, From, Err)
end;
#iq{kind = response} = IQReply ->
%%IQReply = jlib:iq_query_or_response_info(IQ_Rec),
process_iq_reply(From, To, IQReply);
reply ->
IQReply = jlib:iq_query_or_response_info(Packet),
process_iq_reply(From, To, IQReply);
_ ->
Err = exmpp_iq:error(Packet, 'bad-request'),
Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST),
ejabberd_router:route(To, From, Err),
ok
end.
@@ -127,18 +115,7 @@ process_iq_reply(From, To, #iq{id = ID} = IQ) ->
_ ->
nothing
end.
%% #xmlelement{} used for retro-compatibility
route(FromOld, ToOld, #xmlelement{} = PacketOld) ->
catch throw(for_stacktrace), % To have a stacktrace.
io:format("~nLOCAL: old #xmlelement:~n~p~n~p~n~n",
[PacketOld, erlang:get_stacktrace()]),
% XXX OLD FORMAT: From, To, Packet.
From = jlib:from_old_jid(FromOld),
To = jlib:from_old_jid(ToOld),
Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT],
[{?NS_XMPP, ?NS_XMPP_pfx}]),
route(From, To, Packet);
route(From, To, Packet) ->
case catch do_route(From, To, Packet) of
{'EXIT', Reason} ->
@@ -153,12 +130,12 @@ route_iq(From, To, IQ, F) ->
route_iq(From, To, #iq{type = Type} = IQ, F, Timeout) when is_function(F) ->
Packet = if Type == set; Type == get ->
ID = list_to_binary(ejabberd_router:make_id()),
Host = exmpp_jid:prep_domain(From),
ID = randoms:get_string(),
Host = From#jid.lserver,
register_iq_response_handler(Host, ID, undefined, F, Timeout),
exmpp_iq:iq_to_xmlel(IQ#iq{id = ID});
jlib:iq_to_xml(IQ#iq{id = ID});
true ->
exmpp_iq:iq_to_xmlel(IQ)
jlib:iq_to_xml(IQ)
end,
ejabberd_router:route(From, To, Packet).
@@ -173,10 +150,10 @@ register_iq_response_handler(_Host, ID, Module, Function, Timeout0) ->
N
end,
TRef = erlang:start_timer(Timeout, ejabberd_local, ID),
ets:insert(iq_response, #iq_response{id = ID,
module = Module,
function = Function,
timer = TRef}).
mnesia:dirty_write(#iq_response{id = ID,
module = Module,
function = Function,
timer = TRef}).
register_iq_handler(Host, XMLNS, Module, Fun) ->
ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}.
@@ -195,7 +172,7 @@ refresh_iq_handlers() ->
ejabberd_local ! refresh_iq_handlers.
bounce_resource_packet(From, To, Packet) ->
Err = exmpp_stanza:reply_with_error(Packet, 'item-not-found'),
Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND),
ejabberd_router:route(To, From, Err),
stop.
@@ -213,14 +190,16 @@ bounce_resource_packet(From, To, Packet) ->
init([]) ->
lists:foreach(
fun(Host) ->
ejabberd_router:register_route(Host, {apply, ?MODULE, route})
ejabberd_router:register_route(Host, {apply, ?MODULE, route}),
ejabberd_hooks:add(local_send_to_resource_hook, Host,
?MODULE, bounce_resource_packet, 100)
end, ?MYHOSTS),
ejabberd_hooks:add(local_send_to_resource_hook, global,
?MODULE, bounce_resource_packet, 100),
catch ets:new(?IQTABLE, [named_table, public]),
mnesia:delete_table(iq_response),
catch ets:new(iq_response, [named_table, public,
{keypos, #iq_response.id}]),
update_table(),
mnesia:create_table(iq_response,
[{ram_copies, [node()]},
{attributes, record_info(fields, iq_response)}]),
mnesia:add_table_copy(iq_response, node(), ram_copies),
{ok, #state{}}.
%%--------------------------------------------------------------------
@@ -251,18 +230,6 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
%% #xmlelement{} used for retro-compatibility
handle_info({route, FromOld, ToOld, #xmlelement{} = PacketOld}, State) ->
catch throw(for_stacktrace), % To have a stacktrace.
io:format("~nLOCAL: old #xmlelement:~n~p~n~p~n~n",
[PacketOld, erlang:get_stacktrace()]),
% XXX OLD FORMAT: From, To, Packet.
From = jlib:from_old_jid(FromOld),
To = jlib:from_old_jid(ToOld),
Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT],
[{?NS_XMPP, ?NS_XMPP_pfx}]),
handle_info({route, From, To, Packet}, State);
handle_info({route, From, To, Packet}, State) ->
case catch do_route(From, To, Packet) of
{'EXIT', Reason} ->
@@ -273,21 +240,21 @@ handle_info({route, From, To, Packet}, State) ->
end,
{noreply, State};
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
ets:insert(?IQTABLE, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function}),
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
catch mod_disco:register_feature(Host, XMLNS),
{noreply, State};
handle_info({register_iq_handler, Host, XMLNS, Module, Function, Opts}, State) ->
ets:insert(?IQTABLE, {{XMLNS, ejabberd:normalize_host(Host)}, Module, Function, Opts}),
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function, Opts}),
catch mod_disco:register_feature(Host, XMLNS),
{noreply, State};
handle_info({unregister_iq_handler, Host, XMLNS}, State) ->
case ets:lookup(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}) of
case ets:lookup(?IQTABLE, {XMLNS, Host}) of
[{_, Module, Function, Opts}] ->
gen_iq_handler:stop_iq_handler(Module, Function, Opts);
_ ->
ok
end,
ets:delete(?IQTABLE, {XMLNS, ejabberd:normalize_host(Host)}),
ets:delete(?IQTABLE, {XMLNS, Host}),
catch mod_disco:unregister_feature(Host, XMLNS),
{noreply, State};
handle_info(refresh_iq_handlers, State) ->
@@ -304,7 +271,7 @@ handle_info(refresh_iq_handlers, State) ->
end, ets:tab2list(?IQTABLE)),
{noreply, State};
handle_info({timeout, _TRef, ID}, State) ->
spawn(fun() -> process_iq_timeout(ID) end),
process_iq_timeout(ID),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
@@ -332,50 +299,67 @@ code_change(_OldVsn, State, _Extra) ->
do_route(From, To, Packet) ->
?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n",
[From, To, Packet, 8]),
LNode = exmpp_jid:prep_node(To),
LResource = exmpp_jid:prep_resource(To),
if
LNode /= undefined ->
To#jid.luser /= "" ->
ejabberd_sm:route(From, To, Packet);
LResource == undefined ->
case Packet of
_ when ?IS_IQ(Packet) ->
To#jid.lresource == "" ->
{xmlelement, Name, _Attrs, _Els} = Packet,
case Name of
"iq" ->
process_iq(From, To, Packet);
_ when ?IS_MESSAGE(Packet) ->
"message" ->
ok;
_ when ?IS_PRESENCE(Packet) ->
"presence" ->
ok;
_ ->
ok
end;
true ->
case exmpp_stanza:get_type(Packet) of
<<"error">> -> ok;
<<"result">> -> ok;
{xmlelement, _Name, Attrs, _Els} = Packet,
case xml:get_attr_s("type", Attrs) of
"error" -> ok;
"result" -> ok;
_ ->
ejabberd_hooks:run(local_send_to_resource_hook,
exmpp_jid:prep_domain(To),
To#jid.lserver,
[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 ets:lookup(iq_response, ID) of
case mnesia:dirty_read(iq_response, ID) of
[#iq_response{module = Module, timer = TRef,
function = Function}] ->
cancel_timer(TRef),
ets:delete(iq_response, ID),
mnesia:dirty_delete(iq_response, ID),
{ok, Module, Function};
_ ->
error
end.
process_iq_timeout(ID) ->
case get_iq_callback(ID) of
{ok, undefined, Function} ->
Function(timeout);
_ ->
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.
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 23 Oct 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -7
View File
@@ -9,7 +9,7 @@
%%% Created : 29 Nov 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
%%% ejabberd, Copyright (C) 2002-2012 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -33,7 +33,6 @@
-export([set/1,
get/0,
get_default/0,
set_custom/2,
clear_custom/0,
clear_custom/1]).
@@ -68,11 +67,6 @@
%% @spec () -> {DefaultLevelOrdinal::integer(), [{Module::atom(), LevelOrdinal::integer()}]}
%% @doc Get the default and all custom levels
get() ->
ejabberd_logger:get().
%% @spec () -> {Ordinal::integer(), Name::atom(), Description::string()}
%% @doc Get the default level
get_default() ->
{DefaultLevel, _CustomLevels} = ejabberd_logger:get(),
case lists:keysearch(DefaultLevel, #loglevel.ordinal, ?LOG_LEVELS) of
{value, Result = #loglevel{}} ->

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