Compare commits
2106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4ec23919d | |||
| 1c095b609a | |||
| a819514e43 | |||
| 16cd93d587 | |||
| a8e5984f5f | |||
| 1a45637860 | |||
| 8cb3f61f88 | |||
| 4bc4f54e43 | |||
| 08774b1b5a | |||
| 300e765e20 | |||
| 951599be21 | |||
| 8bea14837e | |||
| 09250d6121 | |||
| 5968b35320 | |||
| f364fcda56 | |||
| 170874e115 | |||
| bec499a4a1 | |||
| d6709bd53a | |||
| 1cd1dd9f23 | |||
| af198dbe92 | |||
| 80ff4ad3d3 | |||
| 6e1691e2fa | |||
| e52c324a5e | |||
| e7b1f21e1c | |||
| a2d2581199 | |||
| eedd9496e4 | |||
| 3d4775d555 | |||
| 7f11f4a1fb | |||
| 612f15ab17 | |||
| af9ff6f1a1 | |||
| 9664de5242 | |||
| b13c51c8cf | |||
| 8229ee8dd8 | |||
| 476acbfa44 | |||
| 23dd81d18c | |||
| f08595b0e5 | |||
| 50b8500bd5 | |||
| 1cacd48261 | |||
| cf11acc450 | |||
| 0c18dd7068 | |||
| 4e807d69e8 | |||
| a61b7b1d98 | |||
| a55c85252f | |||
| 0168e39bb3 | |||
| 8f8b6870a0 | |||
| dc7208ed1c | |||
| 60b0b918a6 | |||
| d9e2d4e6a9 | |||
| 8fc80178b6 | |||
| c801bd9411 | |||
| b9d5a3350d | |||
| 2bb0095a32 | |||
| eda360914e | |||
| 042172eae1 | |||
| 0eaab78f67 | |||
| 5ec65571f8 | |||
| 7bbc98b04c | |||
| eda6b80ece | |||
| 2ddb7be19a | |||
| 04f20a21fb | |||
| 40ae9b33ef | |||
| e2357ecd96 | |||
| 0116287405 | |||
| 6ee534b262 | |||
| 42f72a49b1 | |||
| 771acc3ac7 | |||
| 5706aaa89c | |||
| c17bbc8859 | |||
| 8f317c0059 | |||
| d1c654a7e1 | |||
| ae5c31b06d | |||
| b09cda5c17 | |||
| 7887392c1d | |||
| cc2b7d2832 | |||
| 0a69935b6b | |||
| 4b7c74415f | |||
| 418baf4fa6 | |||
| fcf647738d | |||
| 3c9ab9e53d | |||
| c339c9b2ad | |||
| 4ef32bb18f | |||
| 0f87034539 | |||
| acee58f6bb | |||
| ceeef24faa | |||
| 201b0b3725 | |||
| 5f8b41a357 | |||
| a003ef556b | |||
| cb91e10803 | |||
| 5190866a24 | |||
| 473a58e3c2 | |||
| 3e6b88cbc3 | |||
| 362d7f617d | |||
| d11df52abf | |||
| 906161b27f | |||
| 347e8b28ef | |||
| c85c2796f4 | |||
| df72de96ae | |||
| e1f8233d08 | |||
| 38d2a27c56 | |||
| 6a42119292 | |||
| 89787875d4 | |||
| d76ae701cd | |||
| c4db156ad2 | |||
| d95778ea16 | |||
| a9b452fba9 | |||
| afed9e919e | |||
| 5252dcbd2c | |||
| a5cfac76dd | |||
| 45aa32f6fe | |||
| 2372e30150 | |||
| f3b55596b2 | |||
| 84eee8d5a7 | |||
| a800a5d4df | |||
| dfa47556d1 | |||
| 77111aeec1 | |||
| c9ac75474f | |||
| 0fcaef0566 | |||
| 031c7412a8 | |||
| 594ff79514 | |||
| 8f3f74a6d7 | |||
| ff2050b301 | |||
| 89ea1dd1c4 | |||
| 66902b788b | |||
| ec8cb81c0d | |||
| 1a24ac62e5 | |||
| 78fb913a00 | |||
| e521c8368a | |||
| ac8c536b50 | |||
| 84d9ee07b4 | |||
| ab9ac62138 | |||
| beaf351ba4 | |||
| 37d3a4e1f5 | |||
| 566c046cd5 | |||
| df921fef40 | |||
| 56e7affdfd | |||
| bef66dba24 | |||
| e62af41fa8 | |||
| 472089a328 | |||
| c4d582ace4 | |||
| a4e320c263 | |||
| 7d3d008940 | |||
| 3be9c27509 | |||
| 3ef6e4c834 | |||
| a15e689386 | |||
| 7c8a452b00 | |||
| e5d202a0bf | |||
| 083dfe01ea | |||
| f0c745b916 | |||
| 9ff1a80db4 | |||
| 5480ee29fd | |||
| 0d4b0b4218 | |||
| cfe396e155 | |||
| 2163cbb22e | |||
| 6b3f228327 | |||
| e58e6a09dd | |||
| 2d05ddd466 | |||
| 975f4c56d4 | |||
| 8eef2f02bf | |||
| 2f7c69fd14 | |||
| 02eeebd41a | |||
| 99610c3357 | |||
| aad740f34c | |||
| a70c72e50e | |||
| a2fdc75730 | |||
| b82789f11d | |||
| 6b7d70adf6 | |||
| 10f10a2fd3 | |||
| 35c4e740ab | |||
| e3085a4d48 | |||
| e8d008c392 | |||
| 674ab27700 | |||
| 9442a583bc | |||
| 9787416e88 | |||
| fbe2995696 | |||
| 33251cd5a8 | |||
| f387934886 | |||
| fb39b163df | |||
| 011535f0de | |||
| 75d3152a0f | |||
| 6c94d040fa | |||
| e8921d79ba | |||
| db8bd0126b | |||
| 6719d9669b | |||
| 8b13226d00 | |||
| 545f9ce525 | |||
| 437f68a9f3 | |||
| 7f1e9d3972 | |||
| 453e249de3 | |||
| 8688030d7a | |||
| 6e2003c2e2 | |||
| 5ed8959eba | |||
| 7623ebd327 | |||
| 522eb0fe9d | |||
| 7dd171322d | |||
| 752652e56c | |||
| 2582a478ab | |||
| 52ff5de564 | |||
| ba793af8b7 | |||
| 3304ecd1f0 | |||
| 4e0394cab3 | |||
| eaa963a840 | |||
| 31c13cc1c8 | |||
| 310aa7a00d | |||
| fafd605d4d | |||
| 078f3583f0 | |||
| 0b337329ba | |||
| f5df63554f | |||
| 46c4f46451 | |||
| e034864c12 | |||
| 91f38cc849 | |||
| e616d2686f | |||
| 5a09d671ab | |||
| 58d49d2867 | |||
| 8bb58ba3c3 | |||
| 017ce4e092 | |||
| 49859683b0 | |||
| 169b83b36d | |||
| 86435ba9aa | |||
| 431c34709c | |||
| cf6d67ceed | |||
| e2d6bc95a4 | |||
| ef0cf5d3d7 | |||
| 06f570f4ff | |||
| 730dfe8fc7 | |||
| e99ecf6d06 | |||
| 83c7da3831 | |||
| 8dc4dd7f3b | |||
| 66b7caafe0 | |||
| 7c0b2f5425 | |||
| 4645885180 | |||
| 472d046426 | |||
| 613d175f37 | |||
| 5619d39bd3 | |||
| 959e0ff1c9 | |||
| 2c228e6414 | |||
| 82468bff00 | |||
| 5f82846732 | |||
| 09c75af15c | |||
| 91964b1aba | |||
| af2e9169e6 | |||
| 4637e2c66b | |||
| 1f1a98d7ae | |||
| cea23b055b | |||
| 41a0eae0bd | |||
| 5fab00011e | |||
| ca5f028016 | |||
| b43444f674 | |||
| 866085c918 | |||
| 585c5afd1a | |||
| 6ec5c7c4d8 | |||
| 6b3875814c | |||
| a63bbe8a23 | |||
| bc118986b7 | |||
| 3a51c801e1 | |||
| 983da9c887 | |||
| 8d8dee5acf | |||
| 92feebd0fa | |||
| 0b423eb287 | |||
| f7b6446c74 | |||
| deb87f2dfa | |||
| 7d7c739cb3 | |||
| b1e2538488 | |||
| 7b9e59d15d | |||
| 794d0bbe69 | |||
| 60d422eb8e | |||
| 52df4fa024 | |||
| f7ffdfa15d | |||
| 4900ac31a7 | |||
| 6ebebdd02d | |||
| 112a18f966 | |||
| 7d623d5eb4 | |||
| 4819738e8f | |||
| e30e7686e3 | |||
| 290432c0ee | |||
| 6563267055 | |||
| ecf7b0282e | |||
| ea6e85d926 | |||
| b4d107301d | |||
| 948318ca19 | |||
| 89aa7baa5b | |||
| fead37d1c5 | |||
| 95928a7cd4 | |||
| 1ecc9ac48c | |||
| eaecb9b65c | |||
| 288196c7e8 | |||
| 2948cddebf | |||
| 438dc57def | |||
| 4d64fbb0ac | |||
| 0283c6cdfe | |||
| d4e7b0cda0 | |||
| e0781d9217 | |||
| bcdae19141 | |||
| 6edbbded40 | |||
| 684cac274d | |||
| ce7b008b8f | |||
| a3c58f2896 | |||
| f04fe5f743 | |||
| 3839f1055a | |||
| 66a5aff323 | |||
| 94350ddb3a | |||
| 5746c08f72 | |||
| 919cdc27db | |||
| 2029e39299 | |||
| 39acf823ef | |||
| 2ea9e6ed59 | |||
| 707bb0a321 | |||
| 298a4a3acf | |||
| 21c75ebce5 | |||
| 262157c88d | |||
| 37107af7b4 | |||
| 13a9ca65a4 | |||
| d3369c83e7 | |||
| 48308042b6 | |||
| d30ad8ba28 | |||
| cf973f27bb | |||
| 87df27109a | |||
| 32e0a88edc | |||
| bd91e2da16 | |||
| 89e4e822bf | |||
| b89d4c7476 | |||
| ee968b5573 | |||
| 1f97740cfa | |||
| f3d24b6a07 | |||
| d1377da151 | |||
| 07cfc000ea | |||
| d471be26cf | |||
| 31f6a9e66e | |||
| d736c47649 | |||
| 944791e888 | |||
| 0656377165 | |||
| 0e4806820e | |||
| 1a419972d2 | |||
| 98b150e1a4 | |||
| 3850b91571 | |||
| 7b0174a626 | |||
| 2270df86d9 | |||
| a04131c6d7 | |||
| 96800e9b75 | |||
| e5830253b9 | |||
| c1d479f863 | |||
| b7a07087d1 | |||
| adf56dedf3 | |||
| 4be7984a0e | |||
| 3b0b318730 | |||
| 6bfd8b8e9a | |||
| 39bc499b10 | |||
| de4d4a4bbb | |||
| 8631dd14e9 | |||
| e7d12f4b9e | |||
| f17a531e15 | |||
| ff57c8a58c | |||
| 499b884c67 | |||
| 0c261fb903 | |||
| 322263fd5c | |||
| 845f5cabec | |||
| f919349173 | |||
| a91ae03dc6 | |||
| faed7698c2 | |||
| eb8347f92b | |||
| c53ffe6dc5 | |||
| 7c8eab4f43 | |||
| b1d8168dd3 | |||
| c196c1f5e5 | |||
| 604563af76 | |||
| 6848d3affe | |||
| 6708914e99 | |||
| 5921f9c506 | |||
| 6193ed63b1 | |||
| 18dd0d08cb | |||
| 8dd6f128bf | |||
| 04267930de | |||
| d83716dece | |||
| c77358bdc1 | |||
| 44987479a5 | |||
| 30d89abf66 | |||
| f175be6b78 | |||
| 2a41ca0628 | |||
| c4f9a050c9 | |||
| 1babae067d | |||
| 32ff6b56eb | |||
| 33c0ebb100 | |||
| cb9aecf35e | |||
| d5b4d67858 | |||
| 9f4ae07100 | |||
| 32fc36b17d | |||
| 3ae4797848 | |||
| 33766a124d | |||
| ede8d57373 | |||
| 86f0a9790d | |||
| 54acf9bde4 | |||
| 2494e39c9e | |||
| 8f27a697c0 | |||
| 07fdd089a0 | |||
| c9a712a16a | |||
| d6e81ac06b | |||
| 228a587fc5 | |||
| e432ff58f9 | |||
| b8969f68e0 | |||
| dbb2d1c229 | |||
| 609b7ed5c5 | |||
| 3eca0259f7 | |||
| 20f3fc96c3 | |||
| 76a174a007 | |||
| 0fde148a9f | |||
| 6b0eb1f09d | |||
| f3c90ee266 | |||
| 2482c9c5ed | |||
| da555fb908 | |||
| 7ae7d6315f | |||
| eccb499346 | |||
| 0c1796ea40 | |||
| 826fab9999 | |||
| 3b95108a3a | |||
| ab2a298ebf | |||
| 8b5fa88b6f | |||
| de712e5ccb | |||
| ffdf5cb206 | |||
| f1a91108ef | |||
| ffe063a0e9 | |||
| d74f02e367 | |||
| 0da2107974 | |||
| 1994c8a174 | |||
| 2434be4803 | |||
| b0b371d23a | |||
| d6fcee4faa | |||
| 41d028d101 | |||
| 75fc431fb8 | |||
| 917d1be994 | |||
| 900b013658 | |||
| dd772404c5 | |||
| 84486dcb2c | |||
| 9a190f3bc4 | |||
| c76bbdf16f | |||
| 24c5063b99 | |||
| bed5e80ef9 | |||
| a0f8a2c3a4 | |||
| 3edea6c806 | |||
| 9ccdb5d78b | |||
| abebabc487 | |||
| 1ee6eae684 | |||
| 24852b9be8 | |||
| e80b92b481 | |||
| 5bef1a8f77 | |||
| 4f1637fa40 | |||
| 573a84b2ec | |||
| 796cb6634b | |||
| bb5480756a | |||
| edb030f49a | |||
| 0ed4ceebea | |||
| 31f7eadfca | |||
| 1c72c45404 | |||
| 75f8e174dc | |||
| f8fd9969e1 | |||
| 8d09655a89 | |||
| a06b627631 | |||
| e690afc33b | |||
| 493b664f19 | |||
| cb41c8ef80 | |||
| d4cea0f78f | |||
| 4d20abd7b6 | |||
| 351ad528f9 | |||
| 006da5589e | |||
| 5f32dd3959 | |||
| a9269df2aa | |||
| a7d82d6ecb | |||
| 5b10b58c9f | |||
| ae24f7d787 | |||
| 83014fb77b | |||
| 1dfd9fd568 | |||
| f655ab2ffc | |||
| 1a4722e909 | |||
| 369fefd5a8 | |||
| cc0aa707c4 | |||
| 7e14b2d46a | |||
| 1e88c3f180 | |||
| 49ee637a5c | |||
| 71f085fec0 | |||
| 302294faec | |||
| caa84e2731 | |||
| b6a637c121 | |||
| 60009ece44 | |||
| 2787df035c | |||
| 32da749041 | |||
| 0cbd702419 | |||
| 15f664af26 | |||
| d673ff5fad | |||
| f112df2cfc | |||
| 35644cf73c | |||
| 6cc6c04c4a | |||
| b9e1bc34da | |||
| f4d0b201ad | |||
| aff99097e7 | |||
| 18f6b02065 | |||
| 33544569fb | |||
| 529ab22a79 | |||
| 9f6afab09c | |||
| 2137c03da1 | |||
| 58fe9d3345 | |||
| deb5e45bff | |||
| bd1df027c6 | |||
| 20290cab01 | |||
| adcf2d5c4e | |||
| 8faafc5b0d | |||
| 370093afde | |||
| 32d3d1626b | |||
| d4d28e038b | |||
| 41fad8956b | |||
| d6a076dae8 | |||
| 2cacf21d51 | |||
| 0874b93e7c | |||
| f0c32433dc | |||
| ba9094a089 | |||
| bfebcebeb7 | |||
| 78f50c58bf | |||
| 1c0b99e162 | |||
| f850bcbbc9 | |||
| 133b8d42a3 | |||
| 7bc879c6f4 | |||
| f7d532f2f7 | |||
| 3785b3e951 | |||
| 70e1545d3a | |||
| 8aaf9bffa0 | |||
| d65b785f5d | |||
| 9aabd59a1f | |||
| 8806fdc1c2 | |||
| dfbf32ecba | |||
| 17abbf3d82 | |||
| 1922bf21f0 | |||
| dfbfd90f8c | |||
| c98ddeb59f | |||
| 613214da18 | |||
| 84c1cf8033 | |||
| 38693a670b | |||
| 5a0cfe7e2b | |||
| 714dce84db | |||
| a97a60a888 | |||
| b807b21a59 | |||
| 49365da481 | |||
| 70e84021f2 | |||
| 24e033ac79 | |||
| 658ab235ba | |||
| 2f16a160c0 | |||
| 4a2f62062e | |||
| 4f4c8eb61e | |||
| 3952888f94 | |||
| 9b145385af | |||
| 897b46c31d | |||
| 72299ab078 | |||
| e7ab83b612 | |||
| 07cf6f09b8 | |||
| 252ee6228b | |||
| cf6264f507 | |||
| 4f1ececbd1 | |||
| 70bf5b4eda | |||
| f59a979f7c | |||
| 05e3893f60 | |||
| 7d7621c67c | |||
| 33d4126290 | |||
| 449e56ed52 | |||
| aded966370 | |||
| dac1f328d7 | |||
| 87315e92a8 | |||
| 90ea752046 | |||
| 494add4fd0 | |||
| 3b7458bbc2 | |||
| f05a4d1638 | |||
| 75d2cbcb14 | |||
| f9fa168d84 | |||
| e4b3bd5005 | |||
| 5ad1d08b89 | |||
| dcb068c7ad | |||
| 2d32d2f25e | |||
| abcbcd1f2c | |||
| 18fd67b311 | |||
| b116957982 | |||
| a1f20a5bc0 | |||
| e0d14c3b8d | |||
| 1548a18b5e | |||
| 339fa6e41b | |||
| db0962804d | |||
| 677d8b1a29 | |||
| 850218c2df | |||
| 1c89914382 | |||
| 307e57a105 | |||
| fe40a9c5f6 | |||
| bc0ae5a017 | |||
| 8e68e89816 | |||
| 91ab7e029b | |||
| c3a88c713b | |||
| 1564060c6c | |||
| f39ccd73c5 | |||
| fd52f2cb7d | |||
| f91eb52890 | |||
| ca59a7f027 | |||
| 01689bc6b9 | |||
| 6dea2d2307 | |||
| 024a80d41f | |||
| f485109c39 | |||
| bde46896d6 | |||
| 0c30b012f7 | |||
| 650b2802b5 | |||
| 6ddc66db9f | |||
| 14b39a0ee4 | |||
| 792512459d | |||
| 0359e345b0 | |||
| a09c319357 | |||
| 36166aa40e | |||
| a25c9c5df3 | |||
| 6e3a9ac4fd | |||
| e380eee223 | |||
| 1959546ff9 | |||
| 92f5509b35 | |||
| f4c74c147b | |||
| 0edda6150b | |||
| 1a2e6b02ab | |||
| 56bf156b6f | |||
| 5632901820 | |||
| 92b6c12420 | |||
| 062d58026a | |||
| 7ef85dddea | |||
| 4a9e7f0a3a | |||
| bd43505db9 | |||
| cffe224d4a | |||
| 15c27c9ddd | |||
| a2e1d2030a | |||
| 149f8e2b45 | |||
| 4c8b034874 | |||
| 2ab31cb613 | |||
| b47c50145d | |||
| b9f4daca46 | |||
| 606c207e21 | |||
| 03870f962c | |||
| 405e9b24b0 | |||
| d9c01e8ed9 | |||
| 3c51ca06d5 | |||
| 02cfb11a6d | |||
| 4e875c7fb7 | |||
| 3e9c9fc750 | |||
| fbcb9bb154 | |||
| 6242fd2bb8 | |||
| 1c566057f8 | |||
| aa59d8f1f0 | |||
| 6dd35923b0 | |||
| b9bbe19d4c | |||
| 44b2002504 | |||
| faf422202f | |||
| eb884c80d0 | |||
| b83dd9f954 | |||
| fd828c3e9b | |||
| 79648ce853 | |||
| ddc94a8c96 | |||
| aa413d63da | |||
| 548be4cf3d | |||
| 21f2817f40 | |||
| 31e4ccf78b | |||
| bfedd21c98 | |||
| 0e5b0b43fa | |||
| 8258f5940b | |||
| c890b17834 | |||
| f0a848ef45 | |||
| 9f3cdad3f7 | |||
| 931866ee33 | |||
| 20d66e6736 | |||
| 731c9b86e0 | |||
| 955343f6aa | |||
| 1b73ac5118 | |||
| 9ee8191939 | |||
| f2231a2282 | |||
| 3e24408710 | |||
| 3e67200d64 | |||
| 6374b5b1e7 | |||
| 26ac75bdc9 | |||
| 1d1496a667 | |||
| e34eebb5ad | |||
| 776930fa06 | |||
| 38af7c85a6 | |||
| b3facf092a | |||
| 99b7a285d7 | |||
| 19e20f75d7 | |||
| b8d6aee1ce | |||
| 48b768b5b0 | |||
| bd604945c9 | |||
| 0a59ebe405 | |||
| 32eaa01929 | |||
| baf9363bdf | |||
| 12aaa0125b | |||
| cb7cd9abb8 | |||
| ca701e1675 | |||
| 9b88fd6646 | |||
| 76ca7ae7f0 | |||
| 1ab223568d | |||
| 043effc3ce | |||
| 4fd1a8ba63 | |||
| 36303fb4be | |||
| 62357b9589 | |||
| 808029b868 | |||
| cfd377b98e | |||
| 6eeb355a22 | |||
| a0e2e943b4 | |||
| 78931d8efa | |||
| 0d2a8cd04f | |||
| 97087eb3b9 | |||
| 6eeef62ce4 | |||
| 0ccff15599 | |||
| 325fb8caef | |||
| 18ef908759 | |||
| 1f1d2bd5f5 | |||
| 0c484369c9 | |||
| 100f2e9a13 | |||
| 510fd8cf73 | |||
| 080922a3de | |||
| cb7d8c8ead | |||
| c47252aea1 | |||
| f96074057c | |||
| dfaeb3bc88 | |||
| c31f59e326 | |||
| 7c2b9eaf97 | |||
| 79f5251d69 | |||
| 917e8640c2 | |||
| c4bc0e7252 | |||
| 1f16e4783c | |||
| 7f3a5066c6 | |||
| 6f3713a67d | |||
| abfb4a2841 | |||
| f672fd0824 | |||
| 60b36beda8 | |||
| c4289095e0 | |||
| 31757116fc | |||
| 70c1e1d0b1 | |||
| 2f68733708 | |||
| dccaff0544 | |||
| 184ec38510 | |||
| 2d59efb515 | |||
| 195d22d906 | |||
| ab80513755 | |||
| 8a116411bb | |||
| bd3889b6ec | |||
| 400fb69f15 | |||
| 9da45d40c7 | |||
| 23db206ea1 | |||
| 964b7b6b67 | |||
| 9c5f34794a | |||
| eca7588abf | |||
| a15d583d4d | |||
| e03c453c78 | |||
| aea394861d | |||
| 641dc7d695 | |||
| 0a1b0498a6 | |||
| a6858a6ce4 | |||
| f4beeb1706 | |||
| 2e33904bb8 | |||
| 75298b4c27 | |||
| 2d3bbd43d7 | |||
| 011464e6ac | |||
| 6c0e9ef575 | |||
| ca62271a89 | |||
| c96a1805e8 | |||
| babff870a8 | |||
| 5cd3de9cd7 | |||
| 437d8c6b7c | |||
| 440eef74e9 | |||
| c849552177 | |||
| 6134c67df4 | |||
| aa60140ba8 | |||
| 59135cac6f | |||
| 8d69d4aaba | |||
| 426b7ca769 | |||
| b61d16dd33 | |||
| 807af3c08a | |||
| c53e8012b2 | |||
| fe04d57284 | |||
| d07424365d | |||
| 70fe2948b9 | |||
| 0f3bd782c4 | |||
| 91cf9194d8 | |||
| e2dbad6242 | |||
| 84d4a1619b | |||
| 16fae4d117 | |||
| 76f7548935 | |||
| a5166f3946 | |||
| 2d08dcf11a | |||
| 7af47b9dbe | |||
| 437da38342 | |||
| 801ee586b7 | |||
| 6ff3fda14b | |||
| cfca2b502a | |||
| e1a4ae8264 | |||
| 19826858a4 | |||
| 0c2677bc50 | |||
| d1c1902687 | |||
| 11b00b92e9 | |||
| a5230c46c2 | |||
| 95ce77f80d | |||
| c10e43f95f | |||
| eeffc77a1a | |||
| 254686ab46 | |||
| 4a6fc46713 | |||
| bde3bce1e7 | |||
| f76dcd0d48 | |||
| 7da8d9e4e3 | |||
| a93f4f7750 | |||
| ac87749d55 | |||
| 3a7d02dbd3 | |||
| 350af319bf | |||
| 50b747041f | |||
| 36df8c9035 | |||
| 58a5ed9cdc | |||
| 5ea909885e | |||
| f81473fc65 | |||
| 1f2c9b7971 | |||
| c13940e1de | |||
| b6dcd41225 | |||
| db2baa8f84 | |||
| a894d25b1f | |||
| a93991bef2 | |||
| 7127d067c8 | |||
| ba326eb976 | |||
| fd50b2169b | |||
| 00d8b2ac30 | |||
| cac23c39c9 | |||
| a5813b798f | |||
| 8e5297f4c3 | |||
| 191cd2af3c | |||
| f2cfee11de | |||
| 3278f019cb | |||
| e2c3925b7d | |||
| b0c79c57b0 | |||
| 8ea523889b | |||
| b44c462b0e | |||
| 0987700a27 | |||
| ff4f052bb1 | |||
| 100b821c1a | |||
| 893c47a2e0 | |||
| 694af69982 | |||
| c576f340f9 | |||
| 179a0cf255 | |||
| a45ecb70ff | |||
| df1ab9149f | |||
| cb54444f00 | |||
| c77e7fbb7d | |||
| 40625b29f2 | |||
| 2624f3ba51 | |||
| 44832e12b3 | |||
| caa8d0c411 | |||
| 7e72d18292 | |||
| b0a81778af | |||
| 652774a83c | |||
| 2aea503a2a | |||
| 0d8aacb3e7 | |||
| e6be70943f | |||
| c86e4faba3 | |||
| c3c06ccd1c | |||
| 18b569a356 | |||
| 261acfce54 | |||
| c8567f1de2 | |||
| 8a0ccfc401 | |||
| 35a0e27d04 | |||
| 73f7b2ba38 | |||
| 8a693df6e6 | |||
| c41bdea1f1 | |||
| cccbf7de12 | |||
| 660a2735f0 | |||
| 77136bccdf | |||
| b8b6fc0da5 | |||
| 8ecf8d7e27 | |||
| 4134edf8de | |||
| a77d53d738 | |||
| 49a3424a26 | |||
| 92a60ff7fd | |||
| 33c7d36a95 | |||
| 6c7316cbdd | |||
| 09da9eeb95 | |||
| 76d4ba66b2 | |||
| f284fc3284 | |||
| c29b2fda99 | |||
| 86a59fb469 | |||
| 31da259a75 | |||
| 363711a370 | |||
| bf98fa0c01 | |||
| cd923838c3 | |||
| a22ebd3c49 | |||
| 353d16b8ef | |||
| 6bb0dc12f1 | |||
| ad00ec1518 | |||
| c75b7b2b12 | |||
| c754c91ad1 | |||
| c03140d4be | |||
| 6952324509 | |||
| 4b5ef8f2ce | |||
| d87fff1a4c | |||
| ea8aa1f25b | |||
| 8fe6ed011d | |||
| 35cde6787d | |||
| 3024bb0cbf | |||
| f8dd973373 | |||
| 23b28ec60f | |||
| 972440c2ca | |||
| b14899d41a | |||
| d2d8a09b4a | |||
| 1ea09b09a2 | |||
| 071c0a1afe | |||
| 4ed00c3d1f | |||
| 59ae9bea76 | |||
| 7be707f7bc | |||
| c9ff370278 | |||
| 8ab8da82c4 | |||
| 4b6a42f539 | |||
| 8a251ccafe | |||
| 550363cd52 | |||
| 367353100b | |||
| 5113d28bb4 | |||
| c8df607173 | |||
| c8033833f9 | |||
| cf4f0dbe6d | |||
| 200815dcdb | |||
| 2d1c416daf | |||
| 3aaebe98f4 | |||
| 8c4884d665 | |||
| 26f6eebaa9 | |||
| ac84267b22 | |||
| 2ee7642816 | |||
| bf63d09d80 | |||
| 5030f35558 | |||
| d7930d7f82 | |||
| 28c4c87956 | |||
| d0b7cd599b | |||
| cc1839a250 | |||
| 7d37715f8b | |||
| 091b4568d5 | |||
| cc0503fd5e | |||
| 4862251f34 | |||
| 987d796439 | |||
| 628571f8cf | |||
| 42ddc297fe | |||
| e82db8cc7f | |||
| 10d43c7cc6 | |||
| d539fd28c1 | |||
| 12e00c57f9 | |||
| 0c95cf7e61 | |||
| d106f741d9 | |||
| 6c96157d1b | |||
| a42a012f94 | |||
| 7e90d6cf92 | |||
| e19ac27803 | |||
| c100cbedd1 | |||
| 4c2e7e38a1 | |||
| fa22b23435 | |||
| c3c23a04f6 | |||
| ae6545989e | |||
| baeb3d076e | |||
| 0ac5684bf0 | |||
| 715cc5ea3b | |||
| d9e2931ed9 | |||
| 1531541331 | |||
| b7e02cc42e | |||
| 3ab90c9d3a | |||
| 1b7948f50a | |||
| fe23dbd76e | |||
| 21d2f4efab | |||
| f66f049ef3 | |||
| 49dd83e731 | |||
| 9cd2d5e0cf | |||
| fab705dc13 | |||
| a84f8bc9ef | |||
| 2477b735bf | |||
| 8db328af60 | |||
| bc2280be70 | |||
| a28aaa1fdd | |||
| afa0f4d403 | |||
| 0e5b930b22 | |||
| 7d8f8a7e99 | |||
| a7924adee9 | |||
| d4ec7a2f01 | |||
| e0fab19345 | |||
| 4646a5dbb8 | |||
| 1567592ac7 | |||
| 3b735c269c | |||
| 5bdef05f12 | |||
| 077626c40a | |||
| c544384c83 | |||
| d56522c8a0 | |||
| b83e77ca21 | |||
| 361400691d | |||
| ba9247c530 | |||
| 91d22109c8 | |||
| cb702a770d | |||
| db059bdfaf | |||
| 2291a6afea | |||
| af7fe0c21e | |||
| 7ce3291603 | |||
| 07e870271e | |||
| a5f8aeb6da | |||
| 1777ecd15a | |||
| d4d45f3a50 | |||
| 9900be3d68 | |||
| b88372c313 | |||
| e4aab7f749 | |||
| 42cbd0c1c4 | |||
| 9318678e08 | |||
| bd992bcb87 | |||
| 01d2bcfd92 | |||
| 0bfda4e628 | |||
| a2f659a2c6 | |||
| 9a04a60c7d | |||
| 7238ab6f05 | |||
| dd954ef1c2 | |||
| f1b8853339 | |||
| 479a2adaae | |||
| dd3c939025 | |||
| 767e7d65ef | |||
| 5feb20afd0 | |||
| 9038bbd3e7 | |||
| 506fbbe7f7 | |||
| 08f1f55e0c | |||
| 5ea9a0ddb7 | |||
| d4e0fab06b | |||
| 217aaf78f9 | |||
| 2ee788e0bf | |||
| f0f4b2719c | |||
| 406a31c8be | |||
| c32332898b | |||
| 4bbf6684b4 | |||
| 9476d8a2c3 | |||
| 6ac46c6171 | |||
| 6ae8b9c4d6 | |||
| 39119192a1 | |||
| 25e4038623 | |||
| f58d03c12e | |||
| 58590cf08d | |||
| cce57310b0 | |||
| 516d369174 | |||
| 7fc1207661 | |||
| 951808658d | |||
| cd9e1621f9 | |||
| 650966ce2c | |||
| 2a99af8cce | |||
| 3ba0061ada | |||
| 705c5b4c1c | |||
| 6ae1f62469 | |||
| 1c00a9713d | |||
| 5e7d8868c0 | |||
| 55dbdf5dba | |||
| 2ff291899d | |||
| 2d375e0429 | |||
| 4669ae0a81 | |||
| c2362db03d | |||
| 1405e9d375 | |||
| 84c4d75735 | |||
| 41aa693896 | |||
| 44b282474a | |||
| 70cfcb1008 | |||
| fa28c8baf6 | |||
| 584fa98564 | |||
| 214c62bf9c | |||
| 962b66b099 | |||
| 417cf11bdd | |||
| b3da1c7d86 | |||
| 839b406903 | |||
| 95e085beb7 | |||
| df63fcd353 | |||
| 77e549e504 | |||
| 20c2bc54cd | |||
| 63ccbe90d3 | |||
| 1f02b5db0f | |||
| 6bde01cd45 | |||
| f36ac2b809 | |||
| e4f19df428 | |||
| 606860e1cc | |||
| 22d490486a | |||
| d2d06403ac | |||
| 6ee8ec49a5 | |||
| 6e878d17e6 | |||
| 4984320f17 | |||
| 09250c0b65 | |||
| 6e8f5a9cd3 | |||
| c3edcd0575 | |||
| 6fb99fbb48 | |||
| 31c3a78453 | |||
| a3f2588df6 | |||
| 41c455fabb | |||
| 8045fec882 | |||
| 414004eae4 | |||
| 8e8a1a3bf5 | |||
| fbd8547d94 | |||
| 6df9a6ab33 | |||
| 2907446e87 | |||
| f60804b060 | |||
| e569087d83 | |||
| 4a7a33168a | |||
| d7fbad6fa1 | |||
| e6c23e0413 | |||
| 35e00ebcf6 | |||
| 1a96944929 | |||
| bc69b96e4c | |||
| 35c9c95e4b | |||
| 47ee65d101 | |||
| 8a856df2f0 | |||
| 6795675108 | |||
| 6867ca43e4 | |||
| ab0905ce56 | |||
| a71b47ea27 | |||
| 2cca00acc0 | |||
| 7c36e304f0 | |||
| 10c16b1cdf | |||
| 8bd37462cb | |||
| 78f1fe9ba5 | |||
| b17c7848fd | |||
| 071aa123e8 | |||
| abdb7f2742 | |||
| bc70e90853 | |||
| 787e078f6a | |||
| 17607ecaa4 | |||
| 9d84caebdb | |||
| 35bcadde7a | |||
| d9e345a4d8 | |||
| 46c667c567 | |||
| db3f8487fc | |||
| 34234b4a46 | |||
| 03454c7f1d | |||
| 1cced15c0d | |||
| 4c8beae585 | |||
| 0a3cfeeed9 | |||
| 933d4a69b8 | |||
| 352afa7902 | |||
| ce18cfb41b | |||
| 4fe8d76b83 | |||
| d804698541 | |||
| 1b1a0d7ed3 | |||
| a0de5bc317 | |||
| a77b6946cf | |||
| cbbb7256ae | |||
| 16bd626fc9 | |||
| 8068fdf4e3 | |||
| b6aa6d6f09 | |||
| 86794b1d23 | |||
| 3e4858f348 | |||
| 7aff5defac | |||
| 6ad93eb609 | |||
| 9f5246cacc | |||
| 855d427182 | |||
| 4d85297c85 | |||
| 7b76fdcde7 | |||
| 6179daaf99 | |||
| 0cc58d7a71 | |||
| e5373de2b9 | |||
| 6ddff15b39 | |||
| 392ea78acf | |||
| 024b688c1d | |||
| 276f890c50 | |||
| ee77257d41 | |||
| e7a8bf6154 | |||
| 4f643ce9b8 | |||
| 8447dfa4b1 | |||
| 7b05ba0e1e | |||
| c8fd680d92 | |||
| 24aefc429c | |||
| 0bf9832187 | |||
| 761ed1b192 | |||
| 05ee83bddc | |||
| f30783a2d2 | |||
| ee41e1eb70 | |||
| 8d218dd2b9 | |||
| 7cbda8badb | |||
| 15a27c0566 | |||
| d9a1eecdca | |||
| 5d749de74d | |||
| dbad3df333 | |||
| 50137aa98d | |||
| f0863e1dfe | |||
| 1713bf635d | |||
| 9bee86178f | |||
| 455d85a278 | |||
| d812975565 | |||
| 9aa9c34a57 | |||
| 34d5d08501 | |||
| 71142e336d | |||
| c7f4f39c03 | |||
| b2d6a25240 | |||
| 4a57f5db74 | |||
| 4cdf7fba4f | |||
| 341e47c2a4 | |||
| 675c24f5eb | |||
| 15abddb7a8 | |||
| 3df45683ff | |||
| ef49822a47 | |||
| 402a8c0d35 | |||
| d24449488c | |||
| b9e57a341d | |||
| 79be929d96 | |||
| 65aed47873 | |||
| 8ac16a0ec1 | |||
| 3250c24ff1 | |||
| 88b6849e69 | |||
| e3b4c99b00 | |||
| 1f5bf8fbc0 | |||
| f044d6ed28 | |||
| 3aa242e2c7 | |||
| 8983cba129 | |||
| bd97c40f92 | |||
| 5a006b977d | |||
| 3658da3ae8 | |||
| 2265f52c34 | |||
| 7b244652f1 | |||
| 325e67f4cb | |||
| 6ce660b9c2 | |||
| 575e07a986 | |||
| 20d1011194 | |||
| 3df5277728 | |||
| ea4f379bd5 | |||
| 51594b6011 | |||
| 58425ba45d | |||
| 7fd3d67ff3 | |||
| 1716b090f9 | |||
| e5e777694d | |||
| 6cf3ae8050 | |||
| 26c572b7e7 | |||
| 311bf4dbb1 | |||
| 1511a5dc82 | |||
| 041d947e83 | |||
| 2007b3d496 | |||
| 09e847b97d | |||
| b9f911554c | |||
| 24323e8b3b | |||
| 1a5eb4f73d | |||
| 3930715712 | |||
| 64bc97d471 | |||
| 4aec8dda48 | |||
| 9192c75e1a | |||
| 512d701ef8 | |||
| ef3dd090c7 | |||
| 3d5fe6a337 | |||
| 0906a68c27 | |||
| 798853abb6 | |||
| 5e3fdbeeed | |||
| 04545f2668 | |||
| 8ce1e790ac | |||
| a232d16ff4 | |||
| f2a37597cf | |||
| 257e4c34a8 | |||
| 66cd86e726 | |||
| 84a1cc943d | |||
| 47d86f5ad1 | |||
| da50ec6215 | |||
| 69c4d5d89b | |||
| 006515020a | |||
| f86318a179 | |||
| b667148982 | |||
| cbf6abc263 | |||
| 355648dc7e | |||
| 3128c26766 | |||
| c311ea1505 | |||
| 2c48515e7c | |||
| 25523371fc | |||
| 3e9e967429 | |||
| c79489fb65 | |||
| 4039f4a14f | |||
| 14232df14c | |||
| 72535ee14d | |||
| 0a77892391 | |||
| c10984f61b | |||
| ce1364b414 | |||
| e780126c9e | |||
| 4667cefb62 | |||
| 6fa0f68239 | |||
| a126a1883e | |||
| 4606f33081 | |||
| 726545ae86 | |||
| 1c585e74bc | |||
| dc474cf9d5 | |||
| e2ba1f4f1d | |||
| 330d6f7b6e | |||
| 68fd22af87 | |||
| f25b2266bd | |||
| 8107b2b7dc | |||
| 3c3cd099de | |||
| 4936c2dc58 | |||
| fc1dd42e5a | |||
| 325660a547 | |||
| d6f63ceec5 | |||
| 8d47a20d63 | |||
| eab6c09e0c | |||
| 9aee12d83b | |||
| 970973cb9a | |||
| 719aff1088 | |||
| ff1622c658 | |||
| 717837172c | |||
| ae70faef94 | |||
| c86a73f894 | |||
| 4b8d7dd19b | |||
| 49894fe065 | |||
| 58d690376c | |||
| c841505a07 | |||
| 31c6d6194f | |||
| d678a21f21 | |||
| 860957d20c | |||
| 9d8de17b4d | |||
| 0d108d5b1e | |||
| 07f457f49f | |||
| 55fef3c3e7 | |||
| a033b06150 | |||
| 4d3708b637 | |||
| fd57ec5872 | |||
| a5c5808911 | |||
| f6c6a7ee31 | |||
| 19dead97a3 | |||
| 2568c616f7 | |||
| dab4adaaee | |||
| fdc6149c08 | |||
| e29c992cbf | |||
| 156c496a27 | |||
| 5e99d3416d | |||
| b6f50972b6 | |||
| ff1fc2b4f0 | |||
| 57aefa240f | |||
| 2fdabe8b5b | |||
| 217d3131c8 | |||
| 51e2896914 | |||
| 054ad379ce | |||
| 2425c51ae4 | |||
| c137715902 | |||
| 670d7c7ebd | |||
| 2c735c91d6 | |||
| eca4d9c963 | |||
| 64976e18b3 | |||
| f303a40973 | |||
| 3909f95ac1 | |||
| ca403c25e7 | |||
| 1b81a2e3d6 | |||
| 342ea2753c | |||
| 73282e0760 | |||
| 11be369987 | |||
| ad7a8fffd5 | |||
| e6b05199a8 | |||
| dabea295aa | |||
| c8e7a4f4ac | |||
| 2a505d1d86 | |||
| 4be5c0c90c | |||
| f9119a3ec6 | |||
| 49fe1399af | |||
| 56e52f0571 | |||
| 7c76c65c8c | |||
| 1efdf914f3 | |||
| ea06dc92bc | |||
| df30831421 | |||
| 6952aae506 | |||
| 0a159a0850 | |||
| 0a89bbaaa1 | |||
| 0ec33b0868 | |||
| fd16591a2a | |||
| b70b742a9e | |||
| f2bd9e01b0 | |||
| 45b12ec886 | |||
| 0192913405 | |||
| cf6d39487a | |||
| 3571ef9767 | |||
| 3e45bdcc2d | |||
| 5ddfccd45e | |||
| 14e95f91d1 | |||
| 2999a11f4b | |||
| 7fb6a4696a | |||
| 2e68058508 | |||
| 3f8a4a5756 | |||
| f6258b2f46 | |||
| cbc78674e5 | |||
| 1e148d4260 | |||
| 46ae4e7340 | |||
| 695ff58c55 | |||
| 268fe029fd | |||
| 3dc88feec9 | |||
| 5098964df0 | |||
| d3f9819c0f | |||
| 06cee5a654 | |||
| 5438504fbf | |||
| 56f525c475 | |||
| 44ac69f8de | |||
| 60932b67b1 | |||
| 208ec6c076 | |||
| 3eaf796cca | |||
| 0c2222745f | |||
| 01a9f981f4 | |||
| d967054a9f | |||
| 73fabfe3a6 | |||
| 5490d7efe8 | |||
| 0e8dd70ed5 | |||
| dd2be928af | |||
| 29cb0ae7ba | |||
| 14b22a4f98 | |||
| c1d2a9305a | |||
| 6b6cb345ba | |||
| 54ff94e3e3 | |||
| f9a8b9ff31 | |||
| 0b03106946 | |||
| 5598d34478 | |||
| 0ad45b1a93 | |||
| d6f3182731 | |||
| 53626d16e3 | |||
| 59c88fcfe7 | |||
| 0cc9d8f8a0 | |||
| 95239baf85 | |||
| 3625681cf4 | |||
| 16be92cc9f | |||
| 720fd7605d | |||
| 9fbef39193 | |||
| fc0209fec9 | |||
| 6bd9bac716 | |||
| 26ace9829a | |||
| 31d6fe3c7d | |||
| b08c061683 | |||
| cd68e0021e | |||
| f4330e9ed3 | |||
| ea96fe3fd1 | |||
| 548be039b3 | |||
| 458b28eeff | |||
| a528c62bba | |||
| bf10d1e956 | |||
| 1262b0e353 | |||
| 9d9fca5e19 | |||
| ff1f4f5a35 | |||
| 164e1520d4 | |||
| 140d938bc3 | |||
| b3eb800be1 | |||
| 94a638da85 | |||
| fef762243c | |||
| 46735f7c62 | |||
| 7dfdd5d654 | |||
| 5346a7df02 | |||
| 46304da5d7 | |||
| 367365f816 | |||
| 360b4916b1 | |||
| 480c98e991 | |||
| 9df5639974 | |||
| 2729285977 | |||
| 08a72c1693 | |||
| c54fb0c9f2 | |||
| d49fe6e60d | |||
| 5413c72ed5 | |||
| b31ca0cd36 | |||
| 0287d50ff4 | |||
| 5475f35f9f | |||
| a7eb5a77eb | |||
| fc55db403e | |||
| 67052929d5 | |||
| 4f0cd053c4 | |||
| 29ea2738cc | |||
| 49688feaf2 | |||
| f145a32b79 | |||
| 35dc60c534 | |||
| 523239d5a7 | |||
| edb5211f5f | |||
| 2159829168 | |||
| 29a11c89b1 | |||
| 46ff889bd3 | |||
| 6140047edf | |||
| 34a490361f | |||
| 534d6a49f9 | |||
| 2594c7d687 | |||
| 38b342e36f | |||
| 19fbe884d7 | |||
| 95aa4653cb | |||
| d950fb96b6 | |||
| ada531bd8d | |||
| caf9c4f65e | |||
| 606e1982a9 | |||
| 660bbaee3d | |||
| 65bc1122b2 | |||
| 7f8c01b150 | |||
| 20060d9cf6 | |||
| 67570668b6 | |||
| 5fc16bc830 | |||
| feded4b0b7 | |||
| 15a6e660b9 | |||
| 1ce4eb06a7 | |||
| 3e9b5d4ed4 | |||
| b8478c50b9 | |||
| e9ee9959a1 | |||
| 2d9f715d65 | |||
| 44c2259a43 | |||
| 17de26d800 | |||
| 154a0d1c96 | |||
| 1626ede210 | |||
| e14c3f4699 | |||
| 9e309d2a38 | |||
| a00b7fd89b | |||
| d036802891 | |||
| 0047e4192b | |||
| 261b7dc0d9 | |||
| b42dd00a53 | |||
| 4a83538cf6 | |||
| a314cdf26f | |||
| 51a55723cf | |||
| 4dac8f437f | |||
| 7bfd87bec6 | |||
| bb26498faf | |||
| 222cabb745 | |||
| c55ee29a24 | |||
| 4cce314c11 | |||
| 8a89b1737f | |||
| e7417c2f8b | |||
| 4ebeb4d6d0 | |||
| eea6a1a544 | |||
| fbf4a7aa35 | |||
| 9b8d897b5f | |||
| f248cfd18d | |||
| 100befc771 | |||
| 4ed01b98de | |||
| 68ae80ed2f | |||
| 0da3b27dfe | |||
| 3dbfd827bb | |||
| 70fd795a1b | |||
| 2e402c27f4 | |||
| 673a7aad55 | |||
| 88d32b1064 | |||
| 5b09c35dea | |||
| 18f183e4e3 | |||
| 15b0841282 | |||
| da6c4f9941 | |||
| 7ed7ca6e1e | |||
| bbe82647e8 | |||
| c34999cc96 | |||
| e43271216f | |||
| c4e80abeac | |||
| 1bcc001615 | |||
| 83e96f155a | |||
| 3681835668 | |||
| d2684bc3e8 | |||
| c4ca19d313 | |||
| a9ab002f48 | |||
| b416ed03c9 | |||
| 2190055a06 | |||
| 7e426b9623 | |||
| bd106bd45f | |||
| 99fe76f8bc | |||
| eedef994a9 | |||
| 732ad47559 | |||
| 83ffe1989a | |||
| e0370d89b4 | |||
| de15168cdb | |||
| ddd3e58f35 | |||
| 50b73664e2 | |||
| 6f080f7fed | |||
| ce7e9129d9 | |||
| f767def249 | |||
| 5583a3f7dc | |||
| b7fd730409 | |||
| 1266bf48e6 | |||
| 459074fd97 | |||
| 3b5a74b34e | |||
| 049b7c5d11 | |||
| 97e2b39b69 | |||
| 48392832ef | |||
| 72b842d8d1 | |||
| 05187325ee | |||
| fa5b06f542 | |||
| bf57f712da | |||
| c27d6fddf4 | |||
| 6bd70aaf09 | |||
| cdd3ab17ae | |||
| 039d5b8367 | |||
| af32a18b4b | |||
| 4094482a9f | |||
| 7f5cce8196 | |||
| ffe2d532bf | |||
| 29607291ae | |||
| 5c00365550 | |||
| 31aa201ee8 | |||
| 3ec3e78baa | |||
| 11c4dba442 | |||
| 270662c07b | |||
| b8f094b080 | |||
| dffe808895 | |||
| b5964c2a5f | |||
| 5f67072e06 | |||
| 08ba5346db | |||
| 5a68b44be1 | |||
| dfc97beaef | |||
| 4c1eefb791 | |||
| 8af1c41a3e | |||
| e3eac4f00d | |||
| 257efddd1b | |||
| 20088d8a92 | |||
| 077b9cd4db | |||
| 7e370d0201 | |||
| 90263cf0e7 | |||
| 18af5f8675 | |||
| 299d6fe72f | |||
| 3d766c1cb5 | |||
| fec3742aaa | |||
| 90abb578e6 | |||
| dff6e28b2d | |||
| 9b370787c2 | |||
| a4b715516e | |||
| 0ed0c45aba | |||
| 5ae96e4065 | |||
| f8780bc6ee | |||
| b2659e4a6f | |||
| e45e486fd2 | |||
| 7c4e7dea4b | |||
| 709a536fb7 | |||
| cabf128bbb | |||
| e1fd7c444e | |||
| fc9ba11afe | |||
| bda111b145 | |||
| eab7a509f9 | |||
| 6acf7fb5ec | |||
| b59ecb83e8 | |||
| aedb847a81 | |||
| ca8eeaac57 | |||
| d7223ea6ef | |||
| 8654991333 | |||
| a26a7463a0 | |||
| 34df1f502c | |||
| 38f5b8f093 | |||
| 0b8a6d92f8 | |||
| 621fab55e2 | |||
| d22c483781 | |||
| 5db572171b | |||
| f954d6829b | |||
| 1dad64a1cc | |||
| 0770e0eee4 | |||
| e740cfcc47 | |||
| 412f65a0cb | |||
| cd6587d9df | |||
| 549fa6e836 | |||
| 409ab48068 | |||
| 7d0de522dd | |||
| b326b7eb74 | |||
| f4c88768da | |||
| 4dd21545a0 | |||
| 7c415f3fdf | |||
| 5a6f837800 | |||
| f80c848692 | |||
| ad0565cf7c | |||
| 46efb20947 | |||
| a93a3370ef | |||
| bc39341633 | |||
| 1ac385f499 | |||
| b789ee630d | |||
| 9aadefa5b0 | |||
| 3834bcc07e | |||
| 7e924341e4 | |||
| f214b8c528 | |||
| a72023c03e | |||
| d4b5e94635 | |||
| 064d1af5de | |||
| 51faa601fa | |||
| d28efabb79 | |||
| ad7bca0e78 | |||
| 787d225f1e | |||
| 06eb54fef8 | |||
| 0e8f56f0b3 | |||
| f826dc2f9f | |||
| 5cc3985b73 | |||
| ea715129e9 | |||
| b3c39d120f | |||
| 965585eb56 | |||
| 020d6a46c5 | |||
| 117b67a31c | |||
| 64f2945892 | |||
| 3a5fb440cc | |||
| b766109f66 | |||
| 67e24366ee | |||
| c5c97a8edf | |||
| fd26056d01 | |||
| 1650a946f2 | |||
| 04fde3620d | |||
| b6208955f3 | |||
| e6324f8a02 | |||
| ce03742e1b | |||
| 6e055f60de | |||
| 74763be4dd | |||
| e4a3cdb486 | |||
| 4659ae7683 | |||
| b0cc0cdcf9 | |||
| 22d87353be | |||
| f6ddd8bc5b | |||
| 2bd54854ec | |||
| b0e749eca5 | |||
| d0f1300a84 | |||
| 70e431787e | |||
| d0fc8fe056 | |||
| a06bffa413 | |||
| 3524172856 | |||
| d1001a99c2 | |||
| bb13c9e8ab | |||
| ec31aef6cb | |||
| 96c1307ebf | |||
| 2f45d7ecc1 | |||
| e321a241b7 | |||
| aab07df37b | |||
| dd49b98580 | |||
| e790ceea60 | |||
| 8530e628b4 | |||
| 8fa76b9015 | |||
| e2fa195e20 | |||
| ee1140483c | |||
| d0273f4630 | |||
| b9caf7e610 | |||
| d6fa5c2903 | |||
| 3e2048ace9 | |||
| 2e511c78af | |||
| 978effade4 | |||
| 579e1972d5 | |||
| 43e12a3702 | |||
| 47ff640292 | |||
| d041c1127d | |||
| 1c7b41f02e | |||
| 52930b77d8 | |||
| 43a98ab69b | |||
| ba2eb35590 | |||
| 55db20d4b7 | |||
| b3328c08a6 | |||
| 562e6c8d39 | |||
| f09509502e | |||
| 1ac9246a49 | |||
| 8090011126 | |||
| c170783a49 | |||
| 38dcae1fc8 | |||
| 91897882d2 | |||
| eaa1644ebd | |||
| f0af10e600 | |||
| a1f0ad3300 | |||
| 967bbe7f03 | |||
| 14bc7cf77f | |||
| 9f80ec4fb6 | |||
| a0d48c63a3 | |||
| b1252f837f | |||
| 91a7110941 | |||
| 01d761a901 | |||
| e710a24860 | |||
| 1f57a380c8 | |||
| df478a8e90 | |||
| 5a5ab955cb | |||
| 85fdf7cb25 | |||
| 707aa4fb8c | |||
| 1944aa097f | |||
| 394245620e | |||
| 682909e0fc | |||
| 11825e7a33 | |||
| 594bc36ce5 | |||
| 7808dc11af | |||
| 35b1e2885e | |||
| 17cbd1614a | |||
| 4d20367a0c | |||
| 5adfcfad7a | |||
| 42036d8f68 | |||
| af2fa5b5f5 | |||
| 74f15f790a | |||
| 4469880c2e | |||
| c0fb556a01 | |||
| 8f43867091 | |||
| 867ce5be32 | |||
| a800ac5a4e | |||
| 620cbc765c | |||
| 6e5a32308a | |||
| e8635b99c8 | |||
| 07e9ad307e | |||
| 23ce0b312d | |||
| dceb817853 | |||
| c443ee4f4a | |||
| e2d8154a80 | |||
| 4618ec1fef | |||
| 8e32cc11cb | |||
| 9e679aa621 | |||
| bc9ba75c2b | |||
| f124bb3d10 | |||
| 60ae1b47c5 | |||
| 7348f4a553 | |||
| 964cb84864 | |||
| 78b90e9300 | |||
| 340562e452 | |||
| 6a785fa536 | |||
| e68a731219 | |||
| 11e5617efc | |||
| cc858469ec | |||
| c2d81c59b6 | |||
| 91b328b7d5 | |||
| 9f110a6352 | |||
| add568169e | |||
| d5d89c2ab3 | |||
| 4709ed58aa | |||
| 10e3f2cf92 | |||
| 02d68146bd | |||
| 8cdebd485a | |||
| f032cf3380 | |||
| ff6891cdd0 | |||
| 9d521c9dd0 | |||
| 9e55a1291a | |||
| 426e75a298 | |||
| cdcf2d380b | |||
| 7181957506 | |||
| 5264d9299d | |||
| f6e2a58772 | |||
| 0083e56c22 | |||
| a910c4baa1 | |||
| 9a71d6b87a | |||
| 7c736a5ea0 | |||
| 6bd76ebfda | |||
| fa18b35df5 | |||
| 2af52abdba | |||
| 42115a8cfb | |||
| 9a66082998 | |||
| 04981b5e44 | |||
| 3bfe585364 | |||
| d5c3006136 | |||
| 416a939352 | |||
| f2bd87b7cf | |||
| 25d1094468 | |||
| 10ab81f4b4 | |||
| dda582db13 | |||
| be2f6e0517 | |||
| 9194c25a4e | |||
| b2d21cb71c | |||
| 385a1d3f0f | |||
| b65caa82fb | |||
| 10ab4e6782 | |||
| 2f8127d343 | |||
| a2340ea8b8 | |||
| 744b827169 | |||
| 8883e4ad8b | |||
| 3a2fb34a61 | |||
| 16a508cdb9 | |||
| 43647c6d50 | |||
| 70dd325aef | |||
| eabd25a8bf | |||
| 7ff346f612 | |||
| 81c70c347f | |||
| e9d62b39ef | |||
| df39f93b80 | |||
| 943b126d0e | |||
| b6a706756e | |||
| 7ed3ebfaa9 | |||
| 11788b2953 | |||
| dfc62ca5be | |||
| 0832ad392d | |||
| 11f74201ab | |||
| 5c9069d677 | |||
| 2d226b39bf | |||
| 35ed848fe8 | |||
| d08b1c62bb | |||
| 38205691f4 | |||
| e37723f4a2 | |||
| 4ae1bda33f | |||
| 7b1547b2bd | |||
| 2be5cb9b50 | |||
| 61a639d5d9 | |||
| bf9377e9a6 | |||
| 2660be962a | |||
| 73a8d9e373 | |||
| ac30a976d4 | |||
| 422d34ddaf | |||
| 80e925d71d | |||
| 1d6570cdec | |||
| 62f22e8976 | |||
| fa86e6aa85 | |||
| 4fcd5f8cbe | |||
| 60308df929 | |||
| bc8fd0607b | |||
| 3a5fb23427 | |||
| 91339fa8f0 | |||
| 7b3efbe4eb | |||
| c3bda4aaee | |||
| 756cd06625 | |||
| 2660bc514f | |||
| a323504a32 | |||
| c68baa953e | |||
| 46e83cce55 | |||
| 1e11525405 | |||
| ce9902da72 | |||
| 55cfcafd92 | |||
| 211966b42e | |||
| 135da533fd | |||
| c7d45af0aa | |||
| 2c3260d07b | |||
| e509da74e8 | |||
| d8dc734d38 | |||
| 7a49880ffc | |||
| 543fb2d7e4 | |||
| fb43bb0109 | |||
| 999c81e79c | |||
| 1b7a36bf64 | |||
| e361835cea | |||
| be140c1a23 | |||
| 970e9e0843 | |||
| e0e7797e99 | |||
| ece37b1dad | |||
| 0b3f830188 | |||
| 6c0f497281 | |||
| 596b2dbe12 | |||
| 3f87768c8c | |||
| d76ca7c65b | |||
| f25316c1e7 | |||
| 6134205383 | |||
| 871d1dfad6 | |||
| 983022438e | |||
| e7b42f9499 | |||
| 429b7bc169 | |||
| cd5bc22bdb | |||
| f1f0bb0431 | |||
| a2bed6709c | |||
| fc911a43ff | |||
| 1f004c56ac | |||
| e3ba72f3dd | |||
| 70d2682c6a | |||
| 19308d34e2 | |||
| 92ce9af092 | |||
| f74fb8ea2d | |||
| 9626c41817 | |||
| 19a1ddfa44 | |||
| 52390e1876 | |||
| d5e2002ffa | |||
| 35d25d3420 | |||
| 2ccf410a75 | |||
| 5e25cbcaa9 | |||
| 152efbb112 | |||
| b6fd0a5ca5 | |||
| 7a3069b68d | |||
| cf8be23af1 | |||
| 5fdcb52306 | |||
| fe82bf3e81 | |||
| 638d789ae6 | |||
| cbf63d06a8 | |||
| e22913d46f | |||
| 44e0a17d80 | |||
| 8f7d9de0b6 | |||
| d27f41a9e8 | |||
| 795263b5d4 | |||
| a8140bca89 | |||
| 9507a0001d | |||
| ff94e586eb | |||
| be8d1902d0 | |||
| 95462d3f25 | |||
| 59201f1def | |||
| 1e345eb0fc | |||
| 110a4b4518 | |||
| 5e9576ffa3 | |||
| cf42ea0bcb | |||
| c4366a54cc | |||
| f383511e0d | |||
| 3c1efb8c4d | |||
| 9bdaa45981 | |||
| 30f54a6bfc | |||
| b503e02b09 | |||
| 8dae53abda | |||
| 8a8a02431f | |||
| 4e77bae206 | |||
| c892a60da5 | |||
| 5bec1eedc1 | |||
| da56452fba | |||
| 98e47e8c73 | |||
| 977a20700a | |||
| 1a2bb06075 | |||
| e4f098a104 | |||
| 740ce75599 | |||
| a664579b58 | |||
| 8267194d5e | |||
| 2304f8cbc8 | |||
| ef531fb208 | |||
| e5879f4349 | |||
| 1cbfc60570 | |||
| edf1ed5c87 | |||
| 85d3b27d71 | |||
| 4c937ab94e | |||
| 0b5720906c | |||
| c88a4650ba | |||
| b1756e8e34 | |||
| 797544333c | |||
| 96f0c001d9 | |||
| ee6aae8211 | |||
| 981a4a9cd8 | |||
| d46b7d5908 | |||
| 7c64509c46 | |||
| cf8c08c980 | |||
| ab9b30c4d4 | |||
| b994e4bab2 | |||
| 9733e6874e | |||
| 8b690c9f9f | |||
| bd884274c0 | |||
| 367610dd38 | |||
| bbf90da6d0 | |||
| b8b2bde8d0 | |||
| 2af65d4f42 | |||
| 1b13449194 | |||
| 2498bdaad9 | |||
| 076132a5d4 | |||
| 2c8cc8ae2d | |||
| 2f65188edb | |||
| 1649dec58e | |||
| f0ee4f999d | |||
| 37fc28ef49 | |||
| 39b35cf54b | |||
| ef6ce3c7c0 | |||
| 5fd627b85b | |||
| 273c076ef6 | |||
| dcc00bca6d | |||
| 2510d71ae6 | |||
| f634e4dc0d | |||
| e13908c26c | |||
| ab1610021d | |||
| 9b3926baf1 | |||
| 28c082551d | |||
| 48e066999b | |||
| ea510f9d48 | |||
| 9e5721a5d9 | |||
| 2d363b8a5c | |||
| f40476e12f | |||
| f7a9e5bac0 | |||
| 30739179ee | |||
| 86df7de48f | |||
| efec28ada7 | |||
| 1247a98cf2 | |||
| 618af5e07a | |||
| b2bd9759c8 | |||
| 694baba127 | |||
| 4cef493b91 | |||
| 320c266276 | |||
| 4cf68c2f9f | |||
| 295da9cf02 | |||
| 04aec272db | |||
| 7c377783fa | |||
| 40442b9c99 | |||
| d2eb00d814 | |||
| 9ae1282854 | |||
| 07454d8f1a | |||
| 78ce676e81 | |||
| 0f9102e4d1 | |||
| 5cb8f4826c | |||
| ee339aebb8 | |||
| 53e804575f | |||
| 0f4ee703c6 | |||
| 735b34e7b7 | |||
| a65273690d | |||
| 76245f0fcf | |||
| 993ffe9096 | |||
| 8283a9faf3 | |||
| 22a5bce9de | |||
| 868182d1c8 | |||
| f4f3d06120 | |||
| 2ef35b89ca | |||
| de433ef4c1 | |||
| ac99c7fc7d | |||
| 0316caafd3 | |||
| c3a5b5b0fe | |||
| 4bac690f90 | |||
| 9466b1a21f | |||
| 6e3ac3a5a0 | |||
| 56e9971435 | |||
| a021731c09 | |||
| 04d688c1ba | |||
| def7b0ff90 | |||
| aa22e20e0a | |||
| 08a4392fa9 | |||
| 0eb8aafc0d | |||
| 1309f26f06 | |||
| def8f81f20 | |||
| 866e5c2d82 | |||
| edad54d961 | |||
| 0ae7f15ce7 | |||
| 4b5632a260 | |||
| 7f6cdc6cfe | |||
| 8104eac23a | |||
| 116966ce44 | |||
| 8ff5599d3a | |||
| 2fa599c40f | |||
| 0beb1c8116 | |||
| ac204f0849 | |||
| 4e096f1590 | |||
| ba419eae59 | |||
| 24a7d86577 | |||
| 65981598ed | |||
| fff45aca21 | |||
| fb6c0d4771 | |||
| b6ff597740 | |||
| 45b01994e2 | |||
| cdc1698c8b | |||
| a34feb9b1a | |||
| cca5d7fcbe | |||
| c8e580987d | |||
| 58c491ade3 | |||
| f361633f36 | |||
| 864d2056a7 | |||
| 2d2fcc8210 | |||
| 983e51d5fb | |||
| 1b030db9f2 | |||
| 38976270b4 | |||
| 25e6bddf29 | |||
| aa685c7794 | |||
| b106f894e4 | |||
| 20c27ea9d9 | |||
| 04eb1c6641 | |||
| b3bf437dd1 | |||
| 7672515e76 | |||
| 635978b137 | |||
| 74d52708b0 | |||
| 1a1f9d1488 | |||
| c2e12d716b | |||
| b23d82bc1e | |||
| c7e9fe1059 | |||
| 86438f1693 | |||
| e0fc360cf8 | |||
| f3aa8a03d3 | |||
| 4562a79b69 | |||
| 264ea1c25f | |||
| e14d70529c | |||
| 24d2fc10f0 | |||
| 29095be0d4 | |||
| 24f20c0dbb |
+18
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# You can add personal rules in your file .git/info/exclude
|
||||
*.swp
|
||||
*~
|
||||
/contrib/extract_translations/extract_translations.beam
|
||||
/doc/*.aux
|
||||
/doc/*.haux
|
||||
/doc/*.html
|
||||
/doc/*.htoc
|
||||
/doc/*.idx
|
||||
/doc/*.ilg
|
||||
/doc/*.ind
|
||||
/doc/*.log
|
||||
/doc/*.out
|
||||
/doc/*.pdf
|
||||
/doc/*.toc
|
||||
/doc/contributed_modules.tex
|
||||
/doc/version.tex
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
REBAR = @REBAR@
|
||||
INSTALL = @INSTALL@
|
||||
SED = @SED@
|
||||
ERL = @ERL@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
DESTDIR =
|
||||
|
||||
# /etc/ejabberd/
|
||||
ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd
|
||||
|
||||
# /sbin/
|
||||
SBINDIR = $(DESTDIR)@sbindir@
|
||||
|
||||
# /lib/ejabberd/
|
||||
EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
|
||||
|
||||
# /share/doc/ejabberd
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
datarootdir = @datarootdir@
|
||||
DOCDIR = $(DESTDIR)@docdir@
|
||||
|
||||
# /usr/lib/ejabberd/ebin/
|
||||
BEAMDIR = $(EJABBERDDIR)/ebin
|
||||
|
||||
# /usr/lib/ejabberd/include/
|
||||
INCLUDEDIR = $(EJABBERDDIR)/include
|
||||
|
||||
# /usr/lib/ejabberd/priv/
|
||||
PRIVDIR = $(EJABBERDDIR)/priv
|
||||
|
||||
# /usr/lib/ejabberd/priv/bin
|
||||
PBINDIR = $(PRIVDIR)/bin
|
||||
|
||||
# /usr/lib/ejabberd/priv/lib
|
||||
SODIR = $(PRIVDIR)/lib
|
||||
|
||||
# /usr/lib/ejabberd/priv/msgs
|
||||
MSGSDIR = $(PRIVDIR)/msgs
|
||||
|
||||
# /var/lib/ejabberd/
|
||||
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
|
||||
|
||||
# /var/lock/ejabberdctl
|
||||
CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl
|
||||
|
||||
# /var/lib/ejabberd/.erlang.cookie
|
||||
COOKIEFILE = $(SPOOLDIR)/.erlang.cookie
|
||||
|
||||
# /var/log/ejabberd/
|
||||
LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd
|
||||
|
||||
INSTALLUSER=@INSTALLUSER@
|
||||
# if no user was enabled, don't set privileges or ownership
|
||||
ifeq ($(INSTALLUSER),)
|
||||
O_USER=
|
||||
G_USER=
|
||||
CHOWN_COMMAND=echo
|
||||
CHOWN_OUTPUT=/dev/null
|
||||
INIT_USER=root
|
||||
else
|
||||
O_USER=-o $(INSTALLUSER)
|
||||
G_USER=-g $(INSTALLUSER)
|
||||
CHOWN_COMMAND=chown
|
||||
CHOWN_OUTPUT=&1
|
||||
INIT_USER=$(INSTALLUSER)
|
||||
endif
|
||||
|
||||
all: deps src
|
||||
|
||||
deps:
|
||||
$(REBAR) get-deps
|
||||
|
||||
src:
|
||||
$(REBAR) compile
|
||||
|
||||
translations:
|
||||
contrib/extract_translations/prepare-translation.sh -updateall
|
||||
|
||||
doc:
|
||||
echo making $$target in doc; \
|
||||
(cd doc && $(MAKE) $$target) || exit 1
|
||||
|
||||
edoc:
|
||||
$(ERL) -noinput +B -eval \
|
||||
'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
|
||||
|
||||
install: all
|
||||
#
|
||||
# Configuration files
|
||||
$(INSTALL) -d -m 750 $(G_USER) $(ETCDIR)
|
||||
[ -f $(ETCDIR)/ejabberd.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
|
||||
$(SED) -e "s*{{rootdir}}*@prefix@*" \
|
||||
-e "s*{{installuser}}*@INSTALLUSER@*" \
|
||||
-e "s*{{libdir}}*@libdir@*" \
|
||||
-e "s*{{sysconfdir}}*@sysconfdir@*" \
|
||||
-e "s*{{localstatedir}}*@localstatedir@*" \
|
||||
-e "s*{{docdir}}*@docdir@*" \
|
||||
-e "s*{{erl}}*@ERL@*" ejabberdctl.template \
|
||||
> ejabberdctl.example
|
||||
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
|
||||
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
|
||||
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
|
||||
$(INSTALL) -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
|
||||
#
|
||||
# Administration script
|
||||
[ -d $(SBINDIR) ] || $(INSTALL) -d -m 755 $(SBINDIR)
|
||||
$(INSTALL) -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
|
||||
#
|
||||
# Init script
|
||||
$(SED) -e "s*@ctlscriptpath@*$(SBINDIR)*" \
|
||||
-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
|
||||
> ejabberd.init
|
||||
chmod 755 ejabberd.init
|
||||
#
|
||||
# Binary Erlang files
|
||||
$(INSTALL) -d $(BEAMDIR)
|
||||
$(INSTALL) -m 644 ebin/*.app $(BEAMDIR)
|
||||
$(INSTALL) -m 644 ebin/*.beam $(BEAMDIR)
|
||||
$(INSTALL) -m 644 deps/*/ebin/*.app $(BEAMDIR)
|
||||
$(INSTALL) -m 644 deps/*/ebin/*.beam $(BEAMDIR)
|
||||
rm -f $(BEAMDIR)/configure.beam
|
||||
#
|
||||
# ejabberd header files
|
||||
$(INSTALL) -d $(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 include/*.hrl $(INCLUDEDIR)
|
||||
$(INSTALL) -m 644 deps/*/include/*.hrl $(INCLUDEDIR)
|
||||
#
|
||||
# Binary C programs
|
||||
$(INSTALL) -d $(PBINDIR)
|
||||
$(INSTALL) -m 750 $(O_USER) tools/captcha.sh $(PBINDIR)
|
||||
#
|
||||
# Binary system libraries
|
||||
$(INSTALL) -d $(SODIR)
|
||||
#$(INSTALL) -m 644 priv/lib/*.so $(SODIR)
|
||||
$(INSTALL) -m 644 deps/*/priv/lib/*.so $(SODIR)
|
||||
#
|
||||
# Translated strings
|
||||
$(INSTALL) -d $(MSGSDIR)
|
||||
$(INSTALL) -m 644 priv/msgs/*.msg $(MSGSDIR)
|
||||
#
|
||||
# Spool directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(SPOOLDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(SPOOLDIR)
|
||||
[ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; }
|
||||
#
|
||||
# ejabberdctl lock directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(CTLLOCKDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(CTLLOCKDIR)
|
||||
#
|
||||
# Log directory
|
||||
$(INSTALL) -d -m 750 $(O_USER) $(LOGDIR)
|
||||
$(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT)
|
||||
chmod -R 750 $(LOGDIR)
|
||||
#
|
||||
# Documentation
|
||||
$(INSTALL) -d $(DOCDIR)
|
||||
$(INSTALL) -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) \
|
||||
|| echo "No doc/guide.pdf was built"
|
||||
$(INSTALL) -m 644 COPYING $(DOCDIR)
|
||||
|
||||
uninstall: uninstall-binary
|
||||
|
||||
uninstall-binary:
|
||||
rm -f $(SBINDIR)/ejabberdctl
|
||||
rm -fr $(DOCDIR)
|
||||
rm -f $(BEAMDIR)/*.beam
|
||||
rm -f $(BEAMDIR)/*.app
|
||||
rm -fr $(BEAMDIR)
|
||||
rm -f $(INCLUDEDIR)/*.hrl
|
||||
rm -fr $(INCLUDEDIR)
|
||||
rm -fr $(PBINDIR)
|
||||
rm -f $(SODIR)/*.so
|
||||
rm -fr $(SODIR)
|
||||
rm -f $(MSGSDIR)/*.msgs
|
||||
rm -fr $(MSGSDIR)
|
||||
rm -fr $(PRIVDIR)
|
||||
rm -fr $(EJABBERDDIR)
|
||||
|
||||
uninstall-all: uninstall-binary
|
||||
rm -rf $(ETCDIR)
|
||||
rm -rf $(EJABBERDDIR)
|
||||
rm -rf $(SPOOLDIR)
|
||||
rm -rf $(CTLLOCKDIR)
|
||||
rm -rf $(LOGDIR)
|
||||
|
||||
clean:
|
||||
$(REBAR) clean
|
||||
|
||||
clean-rel:
|
||||
rm -rf rel/ejabberd
|
||||
|
||||
distclean: clean clean-rel
|
||||
rm -f config.status
|
||||
rm -f config.log
|
||||
rm -rf autom4te.cache
|
||||
rm -rf deps
|
||||
rm -rf ebin
|
||||
rm -f Makefile
|
||||
rm -f vars.config
|
||||
rm -f src/ejabberd.app.src
|
||||
[ ! -f ../ChangeLog ] || rm -f ../ChangeLog
|
||||
|
||||
rel: all
|
||||
$(REBAR) generate
|
||||
|
||||
TAGS:
|
||||
etags *.erl
|
||||
|
||||
Makefile: Makefile.in
|
||||
|
||||
deps := $(filter-out deps/riak_pb/ebin, $(wildcard deps/*/ebin))
|
||||
|
||||
erlang.plt:
|
||||
-dialyzer --build_plt --output_plt erlang.plt \
|
||||
--apps kernel stdlib sasl crypto public_key ssl mnesia \
|
||||
inets odbc tools compiler erts webtool runtime_tools asn1 \
|
||||
observer xmerl et gs wx syntax_tools $(deps)
|
||||
|
||||
plt: erlang.plt
|
||||
|
||||
dialyzer: plt
|
||||
-dialyzer --plt erlang.plt --add_to_plt --output_plt ejabberd.plt \
|
||||
--get_warnings -o dialyzer.log ebin
|
||||
|
||||
.PHONY: src doc edoc dialyzer Makefile TAGS clean clean-rel distclean rel plt \
|
||||
install uninstall uninstall-binary uninstall-all translations
|
||||
@@ -59,6 +59,8 @@ release : build release_clean
|
||||
copy mod_muc\*.erl $(SRC_DIR)\mod_muc
|
||||
mkdir $(SRC_DIR)\mod_pubsub
|
||||
copy mod_pubsub\*.erl $(SRC_DIR)\mod_pubsub
|
||||
mkdir $(SRC_DIR)\mod_pubsub_ng
|
||||
copy mod_pubsub_ng\*.erl $(SRC_DIR)\mod_pubsub_ng
|
||||
mkdir $(SRC_DIR)\mod_proxy65
|
||||
copy mod_proxy65\*.erl $(SRC_DIR)\mod_proxy65
|
||||
copy mod_proxy65\*.hrl $(SRC_DIR)\mod_proxy65
|
||||
@@ -66,6 +68,9 @@ release : build release_clean
|
||||
copy stringprep\*.erl $(SRC_DIR)\stringprep
|
||||
copy stringprep\*.c $(SRC_DIR)\stringprep
|
||||
copy stringprep\*.tcl $(SRC_DIR)\stringprep
|
||||
mkdir $(SRC_DIR)\stun
|
||||
copy stun\*.erl $(SRC_DIR)\stun
|
||||
copy stun\*.hrl $(SRC_DIR)\stun
|
||||
mkdir $(SRC_DIR)\tls
|
||||
copy tls\*.erl $(SRC_DIR)\tls
|
||||
copy tls\*.c $(SRC_DIR)\tls
|
||||
@@ -97,10 +102,14 @@ all-recursive :
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_pubsub
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_pubsub_ng
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\mod_proxy65
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\stringprep
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\stun
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\tls
|
||||
nmake -nologo -f Makefile.win32
|
||||
cd ..\ejabberd_zlib
|
||||
@@ -138,10 +147,14 @@ clean-recursive :
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_pubsub
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_pubsub_ng
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\mod_proxy65
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\stringprep
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\stun
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\tls
|
||||
nmake -nologo -f Makefile.win32 clean
|
||||
cd ..\ejabberd_zlib
|
||||
@@ -163,8 +176,7 @@ LD=link.exe
|
||||
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$@ $<
|
||||
@@ -8,21 +8,22 @@ Quickstart guide
|
||||
To compile ejabberd you need:
|
||||
- GNU Make
|
||||
- GCC
|
||||
- libexpat 1.95 or higher
|
||||
- Erlang/OTP R10B-9 up to R11B-5. Erlang R12 releases are not yet
|
||||
officially supported, and are not recommended for production
|
||||
servers
|
||||
- OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL
|
||||
encryption. Optional, highly recommended.
|
||||
- Libexpat 1.95 or higher
|
||||
- Erlang/OTP R10B-9 or higher. Recommended: R13B04 and R14B04.
|
||||
Avoid R14A and R14B.
|
||||
- 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.
|
||||
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
|
||||
- GNU Iconv 1.8 or higher, for the IRC Transport
|
||||
(mod_irc). Optional. Not needed on systems with GNU Libc.
|
||||
- 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
|
||||
|
||||
To compile ejabberd, go to the directory src/ and execute the commands:
|
||||
To compile ejabberd execute the commands:
|
||||
./configure
|
||||
make
|
||||
|
||||
@@ -32,9 +33,11 @@ To install ejabberd, run this command with system administrator rights
|
||||
sudo make install
|
||||
|
||||
These commands will:
|
||||
- Install a startup script: /sbin/ejabberdctl
|
||||
- Install ejabberd in /var/lib/ejabberd/
|
||||
- Install the configuration files in /etc/ejabberd/
|
||||
- Install ejabberd binary, header and runtime files in /lib/ejabberd/
|
||||
- Install the administration script: /sbin/ejabberdctl
|
||||
- Install ejabberd documentation in /share/doc/ejabberd/
|
||||
- Create a spool directory: /var/lib/ejabberd/
|
||||
- Create a directory for log files: /var/log/ejabberd/
|
||||
|
||||
|
||||
|
||||
@@ -286,6 +286,16 @@ ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
|
||||
responseName [10] LDAPOID OPTIONAL,
|
||||
response [11] OCTET STRING OPTIONAL }
|
||||
|
||||
passwdModifyOID LDAPOID ::= "1.3.6.1.4.1.4203.1.11.1"
|
||||
|
||||
PasswdModifyRequestValue ::= SEQUENCE {
|
||||
userIdentity [0] OCTET STRING OPTIONAL,
|
||||
oldPasswd [1] OCTET STRING OPTIONAL,
|
||||
newPasswd [2] OCTET STRING OPTIONAL }
|
||||
|
||||
PasswdModifyResponseValue ::= SEQUENCE {
|
||||
genPasswd [0] OCTET STRING OPTIONAL }
|
||||
|
||||
END
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+266
@@ -0,0 +1,266 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.53)
|
||||
AC_PACKAGE_VERSION(3.0.0)
|
||||
AC_INIT(ejabberd, 3.0.0, [ejabberd@process-one.net], [ejabberd])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_SED
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
CFLAGS="$CFLAGS -Wall"
|
||||
fi
|
||||
|
||||
# Checks Erlang runtime and compiler
|
||||
AC_ERLANG_NEED_ERL
|
||||
AC_ERLANG_NEED_ERLC
|
||||
|
||||
# Checks and sets ERLANG_ROOT_DIR and ERLANG_LIB_DIR variable
|
||||
# AC_ERLANG_SUBST_ROOT_DIR
|
||||
# AC_ERLANG_SUBST_LIB_DIR
|
||||
|
||||
#locating escript
|
||||
AC_PATH_PROG([ESCRIPT], [escript], [])
|
||||
|
||||
#locating rebar
|
||||
AC_PATH_PROG([REBAR], [rebar], [./rebar])
|
||||
|
||||
#locating make
|
||||
AC_CHECK_PROG([MAKE], [make], [make], [])
|
||||
|
||||
if test "x$ESCRIPT" = "x"; then
|
||||
AC_MSG_ERROR(['escript' was not found])
|
||||
fi
|
||||
|
||||
if test "x$MAKE" = "x"; then
|
||||
AC_MSG_ERROR(['make' was not found])
|
||||
fi
|
||||
|
||||
# Change default prefix
|
||||
AC_PREFIX_DEFAULT(/)
|
||||
|
||||
AC_ARG_ENABLE(hipe,
|
||||
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) hipe=true ;;
|
||||
no) hipe=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-hipe) ;;
|
||||
esac],[hipe=false])
|
||||
|
||||
AC_ARG_ENABLE(roster_gateway_workaround,
|
||||
[AC_HELP_STRING([--enable-roster-gateway-workaround], [turn on workaround for processing gateway subscriptions (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) roster_gateway_workaround=true ;;
|
||||
no) roster_gateway_workaround=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-roster-gateway-workaround) ;;
|
||||
esac],[roster_gateway_workaround=false])
|
||||
|
||||
AC_ARG_ENABLE(flash_hack,
|
||||
[AC_HELP_STRING([--enable-flash-hack], [support Adobe Flash client XML (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) flash_hack=true ;;
|
||||
no) flash_hack=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-flash-hack) ;;
|
||||
esac],[flash_hack=false])
|
||||
|
||||
AC_ARG_ENABLE(transient_supervisors,
|
||||
[AC_HELP_STRING([--enable-transient_supervisors], [use Erlang supervision for transient process (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) transient_supervisors=true ;;
|
||||
no) transient_supervisors=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-transient_supervisors) ;;
|
||||
esac],[transient_supervisors=false])
|
||||
|
||||
AC_ARG_ENABLE(full_xml,
|
||||
[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])],
|
||||
[case "${enableval}" in
|
||||
yes) full_xml=true ;;
|
||||
no) full_xml=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-full-xml) ;;
|
||||
esac],[full_xml=false])
|
||||
|
||||
AC_ARG_ENABLE(mssql,
|
||||
[AC_HELP_STRING([--enable-mssql], [use Microsoft SQL Server database (default: no, requires --enable-odbc)])],
|
||||
[case "${enableval}" in
|
||||
yes) db_type=mssql ;;
|
||||
no) db_type=generic ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mssql) ;;
|
||||
esac],[db_type=generic])
|
||||
|
||||
AC_ARG_ENABLE(tools,
|
||||
[AC_HELP_STRING([--enable-tools], [build development tools (currently the ejabberd profiler only, default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) tools=true ;;
|
||||
no) tools=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
|
||||
esac],[tools=false])
|
||||
|
||||
AC_ARG_ENABLE(all,
|
||||
[AC_HELP_STRING([--enable-all], [same as --enable-nif --enable-mysql --enable-pgsql --enable-pam --enable-zlib --enable-stun --enable-riak --enable-json --enable-iconv --enable-debug --enable-pubsub-ng --enable-http (useful for Dialyzer checks, default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) nif=true mysql=true pgsql=true pam=true zlib=true stun=true riak=true json=true iconv=true debug=true pubsub_ng=true http=true ;;
|
||||
no) nif=false mysql=false pgsql=false pam=false zlib=false stun=false riak=false json=false iconv=false debug=false pubsub_ng=false http=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-all) ;;
|
||||
esac],[])
|
||||
|
||||
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],[if test "x$nif" = "x"; then nif=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(mysql,
|
||||
[AC_HELP_STRING([--enable-mysql], [enable MySQL support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) mysql=true ;;
|
||||
no) mysql=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mysql) ;;
|
||||
esac],[if test "x$mysql" = "x"; then mysql=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(pgsql,
|
||||
[AC_HELP_STRING([--enable-pgsql], [enable PostgreSQL support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pgsql=true ;;
|
||||
no) pgsql=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pgsql) ;;
|
||||
esac],[if test "x$pgsql" = "x"; then pgsql=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(pam,
|
||||
[AC_HELP_STRING([--enable-pam], [enable PAM support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pam=true ;;
|
||||
no) pam=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pam) ;;
|
||||
esac],[if test "x$pam" = "x"; then pam=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(zlib,
|
||||
[AC_HELP_STRING([--enable-zlib], [enable Stream Compression (XEP-0138) using zlib (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) zlib=true ;;
|
||||
no) zlib=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-zlib) ;;
|
||||
esac],[if test "x$zlib" = "x"; then zlib=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(stun,
|
||||
[AC_HELP_STRING([--enable-stun], [enable STUN support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) stun=true ;;
|
||||
no) stun=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-stun) ;;
|
||||
esac],[if test "x$stun" = "x"; then stun=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(riak,
|
||||
[AC_HELP_STRING([--enable-riak], [enable Riak support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) riak=true ;;
|
||||
no) riak=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-riak) ;;
|
||||
esac],[if test "x$riak" = "x"; then riak=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(json,
|
||||
[AC_HELP_STRING([--enable-json], [enable JSON support for mod_bosh (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) json=true ;;
|
||||
no) json=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-json) ;;
|
||||
esac],[if test "x$json" = "x"; then json=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) iconv=true ;;
|
||||
no) iconv=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-iconv) ;;
|
||||
esac],[if test "x$iconv" = "x"; then iconv=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
|
||||
[case "${enableval}" in
|
||||
yes) debug=true ;;
|
||||
no) debug=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
|
||||
esac],[if test "x$debug" = "x"; then debug=true; fi])
|
||||
|
||||
AC_ARG_ENABLE(pubsub_ng,
|
||||
[AC_HELP_STRING([--enable-pubsub-ng], [enable PubSub NG (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) pubsub_ng=true ;;
|
||||
no) pubsub_ng=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pubsub-ng) ;;
|
||||
esac],[if test "x$pubsub_ng" = "x"; then pubsub_ng=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(http,
|
||||
[AC_HELP_STRING([--enable-http], [build external HTTP libraries ('ibrowse' and 'lhttpc', default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) http=true ;;
|
||||
no) http=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-http) ;;
|
||||
esac],[if test "x$http" = "x"; then http=false; fi])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
vars.config
|
||||
src/ejabberd.app.src])
|
||||
|
||||
ENABLEUSER=""
|
||||
AC_ARG_ENABLE(user,
|
||||
[AS_HELP_STRING([--enable-user[[[[=USER]]]]], [allow this system user to start ejabberd (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) ENABLEUSER=`whoami` ;;
|
||||
no) ENABLEUSER="" ;;
|
||||
*) ENABLEUSER=$enableval
|
||||
esac],
|
||||
[])
|
||||
if test "$ENABLEUSER" != ""; then
|
||||
echo "allow this system user to start ejabberd: $ENABLEUSER"
|
||||
AC_SUBST([INSTALLUSER], [$ENABLEUSER])
|
||||
fi
|
||||
|
||||
AC_ERLANG_CHECK_LIB([sasl], [],
|
||||
[AC_MSG_ERROR([Erlang application 'sasl' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([crypto], [],
|
||||
[AC_MSG_ERROR([Erlang application 'crypto' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([public_key], [],
|
||||
[AC_MSG_ERROR([Erlang application 'public_key' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([ssl], [],
|
||||
[AC_MSG_ERROR([Erlang application 'ssl' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([mnesia], [],
|
||||
[AC_MSG_ERROR([Erlang application 'mnesia' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([inets], [],
|
||||
[AC_MSG_ERROR([Erlang application 'inets' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([odbc], [],
|
||||
[AC_MSG_ERROR([Erlang application 'odbc' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([compiler], [],
|
||||
[AC_MSG_ERROR([Erlang application 'compiler' was not found])])
|
||||
if test "x$tools" = "xtrue"; then
|
||||
AC_ERLANG_CHECK_LIB([tools], [],
|
||||
[AC_MSG_ERROR([Erlang application 'tools' was not found])])
|
||||
AC_ERLANG_CHECK_LIB([runtime_tools], [],
|
||||
[AC_MSG_ERROR([Erlang application 'runtime_tools' was not found])])
|
||||
fi
|
||||
|
||||
AC_SUBST(hipe)
|
||||
AC_SUBST(roster_gateway_workaround)
|
||||
AC_SUBST(flash_hack)
|
||||
AC_SUBST(transient_supervisors)
|
||||
AC_SUBST(full_xml)
|
||||
AC_SUBST(nif)
|
||||
AC_SUBST(db_type)
|
||||
AC_SUBST(mysql)
|
||||
AC_SUBST(pgsql)
|
||||
AC_SUBST(pam)
|
||||
AC_SUBST(zlib)
|
||||
AC_SUBST(stun)
|
||||
AC_SUBST(riak)
|
||||
AC_SUBST(json)
|
||||
AC_SUBST(iconv)
|
||||
AC_SUBST(debug)
|
||||
AC_SUBST(pubsub_ng)
|
||||
AC_SUBST(http)
|
||||
AC_SUBST(tools)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -1,5 +0,0 @@
|
||||
% List of ejabberd-modules to add for ejabberd packaging (source archive and installer)
|
||||
%
|
||||
% HTTP-binding:
|
||||
https://svn.process-one.net/ejabberd-modules/http_bind/trunk
|
||||
https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk
|
||||
@@ -20,9 +20,14 @@
|
||||
|
||||
start() ->
|
||||
ets:new(translations, [named_table, public]),
|
||||
ets:new(translations_obsolete, [named_table, public]),
|
||||
ets:new(files, [named_table, public]),
|
||||
ets:new(vars, [named_table, public]),
|
||||
case init:get_plain_arguments() of
|
||||
["-srcmsg2po", Dir, File] ->
|
||||
print_po_header(File),
|
||||
Status = process(Dir, File, srcmsg2po),
|
||||
halt(Status);
|
||||
["-unused", Dir, File] ->
|
||||
Status = process(Dir, File, unused),
|
||||
halt(Status);
|
||||
@@ -50,7 +55,11 @@ process(Dir, File, Used) ->
|
||||
unused ->
|
||||
ets:foldl(fun({Key, _}, _) ->
|
||||
io:format("~p~n", [Key])
|
||||
end, ok, translations);
|
||||
end, ok, translations);
|
||||
srcmsg2po ->
|
||||
ets:foldl(fun({Key, Trans}, _) ->
|
||||
print_translation_obsolete(Key, Trans)
|
||||
end, ok, translations_obsolete);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
@@ -59,7 +68,7 @@ process(Dir, File, Used) ->
|
||||
|
||||
parse_file(Dir, File, Used) ->
|
||||
ets:delete_all_objects(vars),
|
||||
case epp:parse_file(File, [Dir, filename:dirname(File)], []) of
|
||||
case epp:parse_file(File, [Dir, filename:dirname(File) | code:get_path()], []) of
|
||||
{ok, Forms} ->
|
||||
lists:foreach(
|
||||
fun(F) ->
|
||||
@@ -71,49 +80,57 @@ parse_file(Dir, File, Used) ->
|
||||
|
||||
parse_form(Dir, File, Form, Used) ->
|
||||
case Form of
|
||||
%%{undefined, Something} ->
|
||||
%% io:format("Undefined: ~p~n", [Something]);
|
||||
{call,
|
||||
_,
|
||||
{remote, _, {atom, _, translate}, {atom, _, translate}},
|
||||
[_, {string, _, Str}]
|
||||
[_, {string, Line, Str}]
|
||||
} ->
|
||||
process_string(Dir, File, Str, Used);
|
||||
process_string(Dir, File, Line, Str, Used);
|
||||
{call,
|
||||
_,
|
||||
{remote, _, {atom, _, translate}, {atom, _, translate}},
|
||||
[_, {var, _, Name}]
|
||||
} ->
|
||||
case ets:lookup(vars, Name) of
|
||||
[{_Name, Value}] ->
|
||||
process_string(Dir, File, Value, Used);
|
||||
[{_Name, Value, Line}] ->
|
||||
process_string(Dir, File, Line, Value, Used);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
{match,
|
||||
_,
|
||||
{var, _, Name},
|
||||
{string, _, Value}
|
||||
{string, Line, Value}
|
||||
} ->
|
||||
ets:insert(vars, {Name, Value});
|
||||
ets:insert(vars, {Name, Value, Line});
|
||||
L when is_list(L) ->
|
||||
lists:foreach(
|
||||
fun(F) ->
|
||||
parse_form(Dir, File, F, Used)
|
||||
parse_form(Dir, File, F, Used)
|
||||
end, L);
|
||||
T when is_tuple(T) ->
|
||||
lists:foreach(
|
||||
fun(F) ->
|
||||
parse_form(Dir, File, F, Used)
|
||||
parse_form(Dir, File, F, Used)
|
||||
end, tuple_to_list(T));
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
process_string(_Dir, File, Str, Used) ->
|
||||
process_string(_Dir, _File, _Line, "", _Used) ->
|
||||
ok;
|
||||
|
||||
process_string(_Dir, File, Line, Str, Used) ->
|
||||
case {ets:lookup(translations, Str), Used} of
|
||||
{[{_Key, _Trans}], unused} ->
|
||||
ets:delete(translations, Str);
|
||||
{[{_Key, _Trans}], used} ->
|
||||
ok;
|
||||
{[{_Key, Trans}], srcmsg2po} ->
|
||||
ets:delete(translations_obsolete, Str),
|
||||
print_translation(File, Line, Str, Trans);
|
||||
{_, used} ->
|
||||
case ets:lookup(files, File) of
|
||||
[{_}] ->
|
||||
@@ -127,6 +144,15 @@ process_string(_Dir, File, Str, Used) ->
|
||||
_ -> io:format("{~p, \"\"}.~n", [Str])
|
||||
end,
|
||||
ets:insert(translations, {Str, ""});
|
||||
{_, srcmsg2po} ->
|
||||
case ets:lookup(files, File) of
|
||||
[{_}] ->
|
||||
ok;
|
||||
_ ->
|
||||
ets:insert(files, {File})
|
||||
end,
|
||||
ets:insert(translations, {Str, ""}),
|
||||
print_translation(File, Line, Str, "");
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
@@ -140,7 +166,8 @@ load_file(File) ->
|
||||
"" ->
|
||||
ok;
|
||||
_ ->
|
||||
ets:insert(translations, {Orig, Trans})
|
||||
ets:insert(translations, {Orig, Trans}),
|
||||
ets:insert(translations_obsolete, {Orig, Trans})
|
||||
end
|
||||
end, Terms);
|
||||
Err ->
|
||||
@@ -191,3 +218,77 @@ print_usage() ->
|
||||
" extract_translations . ./msgs/ru.msg~n"
|
||||
).
|
||||
|
||||
|
||||
%%%
|
||||
%%% Gettext
|
||||
%%%
|
||||
|
||||
print_po_header(File) ->
|
||||
MsgProps = get_msg_header_props(File),
|
||||
{Language, [LastT | AddT]} = prepare_props(MsgProps),
|
||||
application:load(ejabberd),
|
||||
{ok, Version} = application:get_key(ejabberd, vsn),
|
||||
print_po_header(Version, Language, LastT, AddT).
|
||||
|
||||
get_msg_header_props(File) ->
|
||||
{ok, F} = file:open(File, [read]),
|
||||
Lines = get_msg_header_props(F, []),
|
||||
file:close(F),
|
||||
Lines.
|
||||
|
||||
get_msg_header_props(F, Lines) ->
|
||||
String = io:get_line(F, ""),
|
||||
case io_lib:fread("% ", String) of
|
||||
{ok, [], RemString} ->
|
||||
case io_lib:fread("~s", RemString) of
|
||||
{ok, [Key], Value} when Value /= "\n" ->
|
||||
%% The first character in Value is a blankspace:
|
||||
%% And the last characters are 'slash n'
|
||||
ValueClean = string:substr(Value, 2, string:len(Value)-2),
|
||||
get_msg_header_props(F, Lines ++ [{Key, ValueClean}]);
|
||||
_ ->
|
||||
get_msg_header_props(F, Lines)
|
||||
end;
|
||||
_ ->
|
||||
Lines
|
||||
end.
|
||||
|
||||
prepare_props(MsgProps) ->
|
||||
Language = proplists:get_value("Language:", MsgProps),
|
||||
Authors = proplists:get_all_values("Author:", MsgProps),
|
||||
{Language, Authors}.
|
||||
|
||||
print_po_header(Version, Language, LastTranslator, AdditionalTranslatorsList) ->
|
||||
AdditionalTranslatorsString = build_additional_translators(AdditionalTranslatorsList),
|
||||
HeaderString =
|
||||
"msgid \"\"\n"
|
||||
"msgstr \"\"\n"
|
||||
"\"Project-Id-Version: " ++ Version ++ "\\n\"\n"
|
||||
++ "\"X-Language: " ++ Language ++ "\\n\"\n"
|
||||
"\"Last-Translator: " ++ LastTranslator ++ "\\n\"\n"
|
||||
++ AdditionalTranslatorsString ++
|
||||
"\"MIME-Version: 1.0\\n\"\n"
|
||||
"\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
|
||||
"\"Content-Transfer-Encoding: 8bit\\n\"\n",
|
||||
io:format("~s~n", [HeaderString]).
|
||||
|
||||
build_additional_translators(List) ->
|
||||
lists:foldl(
|
||||
fun(T, Str) ->
|
||||
Str ++ "\"X-Additional-Translator: " ++ T ++ "\\n\"\n"
|
||||
end,
|
||||
"",
|
||||
List).
|
||||
|
||||
print_translation(File, Line, Str, StrT) ->
|
||||
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 = 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]).
|
||||
|
||||
|
||||
@@ -3,17 +3,25 @@
|
||||
# Frontend for ejabberd's extract_translations.erl
|
||||
# by Badlop
|
||||
|
||||
# How to create template files for a new language:
|
||||
# NEWLANG=zh
|
||||
# cp msgs/ejabberd.pot msgs/$NEWLANG.po
|
||||
# echo \{\"\",\"\"\}. > msgs/$NEWLANG.msg
|
||||
# ../../extract_translations/prepare-translation.sh -updateall
|
||||
|
||||
prepare_dirs ()
|
||||
{
|
||||
# Where is Erlang binary
|
||||
ERL=`which erl`
|
||||
|
||||
EJA_DIR=`pwd`/../..
|
||||
EJA_SRC_DIR=$EJA_DIR/src/
|
||||
EJA_MSGS_DIR=$EJA_DIR/priv/msgs/
|
||||
EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/
|
||||
EXTRACT_ERL=extract_translations.erl
|
||||
EXTRACT_BEAM=extract_translations.beam
|
||||
SRC_DIR=$EJA_DIR/src
|
||||
MSGS_DIR=$SRC_DIR/msgs
|
||||
EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl
|
||||
EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam
|
||||
|
||||
SRC_DIR=$RUN_DIR/src
|
||||
MSGS_DIR=$EJA_DIR/priv/msgs
|
||||
|
||||
if !([[ -n $EJA_DIR ]])
|
||||
then
|
||||
@@ -22,9 +30,7 @@ prepare_dirs ()
|
||||
|
||||
if !([[ -x $EXTRACT_BEAM ]])
|
||||
then
|
||||
echo -n "Compiling extract_translations.erl: "
|
||||
sh -c "cd $EXTRACT_DIR; $ERL -compile $EXTRACT_ERL"
|
||||
echo "ok"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -76,22 +82,22 @@ extract_lang ()
|
||||
extract_lang_all ()
|
||||
{
|
||||
cd $MSGS_DIR
|
||||
for i in *.msg; do
|
||||
for i in $( ls *.msg ) ; do
|
||||
extract_lang $i;
|
||||
done
|
||||
|
||||
echo -e "File\tMissing\tLanguage\t\tLast translator"
|
||||
echo -e "----\t-------\t--------\t\t---------------"
|
||||
cd $MSGS_DIR
|
||||
for i in *.msg; do
|
||||
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
|
||||
|
||||
cd $MSGS_DIR
|
||||
REVISION=`svn info | grep "^Rev" | head -1 | awk '{print $2}'`
|
||||
REVISION=`git describe --always`
|
||||
zip $HOME/ejabberd-langs-$REVISION.zip *.translate;
|
||||
|
||||
rm *.translate
|
||||
@@ -140,6 +146,130 @@ find_unused_full ()
|
||||
cd ..
|
||||
}
|
||||
|
||||
extract_lang_srcmsg2po ()
|
||||
{
|
||||
LANG=$1
|
||||
LANG_CODE=$LANG.$PROJECT
|
||||
MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
|
||||
PO_PATH=$MSGS_DIR/$LANG_CODE.po
|
||||
|
||||
echo $MSGS_PATH
|
||||
|
||||
$ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1
|
||||
sed -e 's/ \[\]$/ \"\"/g;' $PO_PATH.1 > $PO_PATH.2
|
||||
msguniq --sort-by-file $PO_PATH.2 --output-file=$PO_PATH
|
||||
|
||||
rm $PO_PATH.*
|
||||
}
|
||||
|
||||
extract_lang_src2pot ()
|
||||
{
|
||||
LANG_CODE=$PROJECT
|
||||
MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg
|
||||
POT_PATH=$MSGS_DIR/$LANG_CODE.pot
|
||||
|
||||
echo -n "" >$MSGS_PATH
|
||||
echo "% Language: Language Name" >>$MSGS_PATH
|
||||
echo "% Author: Translator name and contact method" >>$MSGS_PATH
|
||||
echo "" >>$MSGS_PATH
|
||||
|
||||
cd $SRC_DIR
|
||||
$ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1
|
||||
sed -e 's/ \[\]$/ \"\"/g;' $POT_PATH.1 > $POT_PATH.2
|
||||
|
||||
#msguniq --sort-by-file $POT_PATH.2 $EJA_MSGS_DIR --output-file=$POT_PATH
|
||||
msguniq --sort-by-file $POT_PATH.2 --output-file=$POT_PATH
|
||||
|
||||
rm $POT_PATH.*
|
||||
rm $MSGS_PATH
|
||||
|
||||
# If the project is a specific module, not the main ejabberd
|
||||
if [[ $PROJECT != ejabberd ]] ; then
|
||||
# Remove from project.pot the strings that are already present in the general ejabberd
|
||||
EJABBERD_MSG_FILE=$EJA_MSGS_DIR/es.po # This is just some file with translated strings
|
||||
POT_PATH_TEMP=$POT_PATH.temp
|
||||
msgattrib --set-obsolete --only-file=$EJABBERD_MSG_FILE -o $POT_PATH_TEMP $POT_PATH
|
||||
mv $POT_PATH_TEMP $POT_PATH
|
||||
fi
|
||||
}
|
||||
|
||||
extract_lang_popot2po ()
|
||||
{
|
||||
LANG_CODE=$1
|
||||
PO_PATH=$MSGS_DIR/$LANG_CODE.po
|
||||
POT_PATH=$MSGS_DIR/$PROJECT.pot
|
||||
|
||||
msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null
|
||||
mv $PO_PATH.translate $PO_PATH
|
||||
}
|
||||
|
||||
extract_lang_po2msg ()
|
||||
{
|
||||
LANG_CODE=$1
|
||||
PO_PATH=$LANG_CODE.po
|
||||
MS_PATH=$PO_PATH.ms
|
||||
MSGID_PATH=$PO_PATH.msgid
|
||||
MSGSTR_PATH=$PO_PATH.msgstr
|
||||
MSGS_PATH=$LANG_CODE.msg
|
||||
|
||||
cd $MSGS_DIR
|
||||
|
||||
# Check PO has correct ~
|
||||
# Let's convert to C format so we can use msgfmt
|
||||
PO_TEMP=$LANG_CODE.po.temp
|
||||
cat $PO_PATH | sed 's/%/perc/g' | sed 's/~/%/g' | sed 's/#:.*/#, c-format/g' >$PO_TEMP
|
||||
msgfmt $PO_TEMP --check-format
|
||||
result=$?
|
||||
rm $PO_TEMP
|
||||
if [ $result -ne 0 ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH
|
||||
grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH
|
||||
grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH
|
||||
paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >$MSGS_PATH
|
||||
|
||||
rm $MS_PATH
|
||||
rm $MSGID_PATH
|
||||
rm $MSGSTR_PATH
|
||||
}
|
||||
|
||||
extract_lang_updateall ()
|
||||
{
|
||||
echo "Generating POT"
|
||||
extract_lang_src2pot
|
||||
|
||||
cd $MSGS_DIR
|
||||
echo ""
|
||||
echo -e "File Missing Language Last translator"
|
||||
echo -e "---- ------- -------- ---------------"
|
||||
for i in $( ls *.msg ) ; do
|
||||
LANG_CODE=${i%.msg}
|
||||
echo -n $LANG_CODE | awk '{printf "%-6s", $1 }'
|
||||
|
||||
# Convert old MSG file to PO
|
||||
PO=$LANG_CODE.po
|
||||
[ -f $PO ] || extract_lang_srcmsg2po $LANG_CODE
|
||||
|
||||
extract_lang_popot2po $LANG_CODE
|
||||
extract_lang_po2msg $LANG_CODE
|
||||
|
||||
MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4 }'`
|
||||
echo -n " $MISSING"
|
||||
|
||||
LANGUAGE=`grep "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'`
|
||||
echo " $LASTAUTH"
|
||||
done
|
||||
echo ""
|
||||
rm messages.mo
|
||||
|
||||
cd ..
|
||||
}
|
||||
|
||||
translation_instructions ()
|
||||
{
|
||||
echo ""
|
||||
@@ -158,34 +288,76 @@ translation_instructions ()
|
||||
echo " $MSGS_PATH"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
-help)
|
||||
echo "Options:"
|
||||
echo " -langall"
|
||||
echo " -lang LANGUAGE_FILE"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " ./prepare-translation.sh -lang es.msg"
|
||||
exit 0
|
||||
EJA_DIR=`pwd`
|
||||
RUN_DIR=`pwd`
|
||||
PROJECT=ejabberd
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
PARAM=$1
|
||||
shift
|
||||
case $PARAM in
|
||||
--) break ;;
|
||||
-project)
|
||||
PROJECT=$1
|
||||
shift
|
||||
;;
|
||||
-ejadir)
|
||||
EJA_DIR=$1
|
||||
shift
|
||||
;;
|
||||
-rundir)
|
||||
RUN_DIR=$1
|
||||
shift
|
||||
;;
|
||||
-lang)
|
||||
LANGU=$2
|
||||
LANGU=$1
|
||||
prepare_dirs
|
||||
extract_lang $LANGU
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-langall)
|
||||
prepare_dirs
|
||||
extract_lang_all
|
||||
;;
|
||||
-srcmsg2po)
|
||||
LANG_CODE=$1
|
||||
prepare_dirs
|
||||
extract_lang_srcmsg2po $LANG_CODE
|
||||
shift
|
||||
;;
|
||||
-popot2po)
|
||||
LANG_CODE=$1
|
||||
prepare_dirs
|
||||
extract_lang_popot2po $LANG_CODE
|
||||
shift
|
||||
;;
|
||||
-src2pot)
|
||||
prepare_dirs
|
||||
extract_lang_src2pot
|
||||
;;
|
||||
-po2msg)
|
||||
LANG_CODE=$1
|
||||
prepare_dirs
|
||||
extract_lang_po2msg $LANG_CODE
|
||||
shift
|
||||
;;
|
||||
-updateall)
|
||||
prepare_dirs
|
||||
extract_lang_updateall
|
||||
;;
|
||||
*)
|
||||
echo "unknown option: '$1 $2'"
|
||||
shift
|
||||
shift
|
||||
echo "Options:"
|
||||
echo " -langall"
|
||||
echo " -lang LANGUAGE_FILE"
|
||||
echo " -srcmsg2po LANGUAGE Construct .msg file using source code to PO file"
|
||||
echo " -src2pot Generate template POT file from source code"
|
||||
echo " -popot2po LANGUAGE Update PO file with template POT file"
|
||||
echo " -po2msg LANGUAGE Export PO file to MSG file"
|
||||
echo " -updateall Generate POT and update all PO"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " ./prepare-translation.sh -lang es.msg"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "End."
|
||||
esac
|
||||
done
|
||||
|
||||
+25
-12
@@ -3,12 +3,9 @@
|
||||
SHELL = /bin/bash
|
||||
|
||||
CONTRIBUTED_MODULES = ""
|
||||
ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex)
|
||||
CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}"
|
||||
endif
|
||||
ifeq ($(shell ls mod_http_fileserver.tex),mod_http_fileserver.tex)
|
||||
CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpfileserver}{true}"
|
||||
endif
|
||||
#ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex)
|
||||
# CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}"
|
||||
#endif
|
||||
|
||||
|
||||
all: release pdf html
|
||||
@@ -16,23 +13,23 @@ all: release pdf html
|
||||
release:
|
||||
@echo "Notes for the releaser:"
|
||||
@echo "* Do not forget to add a link to the release notes in guide.tex"
|
||||
@echo "* Do not forget to update the version number in src/ejabberd.hrl!"
|
||||
@echo "* Do not forget to update the version number in src/ejabberd.app!"
|
||||
@echo "* Do not forget to update the features in introduction.tex (including \new{} and \improved{} tags)."
|
||||
@echo "Press any key to continue"
|
||||
@read foo
|
||||
##@read foo
|
||||
@echo "% ejabberd version (automatically generated)." > version.tex
|
||||
@echo "\newcommand{\version}{"`sed '/VERSION/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.hrl`"}" >> version.tex
|
||||
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
|
||||
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
|
||||
@echo -e "$(CONTRIBUTED_MODULES)" >> contributed_modules.tex
|
||||
@echo "% mod_admin_p1 commands list."
|
||||
|
||||
html: guide.html dev.html features.html
|
||||
html: guide.html dev.html features.html commercial.html
|
||||
|
||||
pdf: guide.pdf features.pdf
|
||||
pdf: guide.pdf features.pdf commercial.pdf
|
||||
|
||||
clean:
|
||||
rm -f *.aux
|
||||
rm -f *.haux
|
||||
rm -f *.html
|
||||
rm -f *.htoc
|
||||
rm -f *.idx
|
||||
rm -f *.ilg
|
||||
@@ -41,6 +38,10 @@ clean:
|
||||
rm -f *.out
|
||||
rm -f *.pdf
|
||||
rm -f *.toc
|
||||
[ ! -f contributed_modules.tex ] || rm contributed_modules.tex
|
||||
|
||||
distclean: clean
|
||||
rm -f *.html
|
||||
|
||||
guide.html: guide.tex
|
||||
hevea -fix -pedantic guide.tex
|
||||
@@ -60,3 +61,15 @@ guide.pdf: guide.tex
|
||||
|
||||
features.pdf: features.tex
|
||||
pdflatex features.tex
|
||||
|
||||
commercial.html: commercial.tex
|
||||
./mod_admin_p1_commands.sh
|
||||
hevea -fix -pedantic commercial.tex
|
||||
|
||||
commercial.pdf: commercial.tex
|
||||
./mod_admin_p1_commands.sh
|
||||
pdflatex commercial.tex
|
||||
pdflatex commercial.tex
|
||||
pdflatex commercial.tex
|
||||
makeindex commercial.idx
|
||||
pdflatex commercial.tex
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
APPNAME = ejabberd
|
||||
VSN = SVN
|
||||
VSN = $(shell sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../../src/ejabberd.app)
|
||||
|
||||
DOCDIR=.
|
||||
SRCDIR=../../src
|
||||
@@ -11,6 +11,7 @@ all: docs
|
||||
clean:
|
||||
rm -f *.html
|
||||
rm edoc-info
|
||||
rm erlang.png
|
||||
|
||||
docs:
|
||||
erl -noshell -run edoc_run application \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@author Mickael Remond <mickael.remond@process-one.net>
|
||||
[http://www.process-one.net/]
|
||||
@copyright 2007 Process-one
|
||||
@copyright 2012 ProcessOne
|
||||
@version {@vsn}, {@date} {@time}
|
||||
@title ejabberd Development API Documentation
|
||||
|
||||
|
||||
+13
-1
@@ -71,10 +71,22 @@ pre, tt, code {
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-left: 1em;
|
||||
margin:1ex 2ex;
|
||||
border:1px dashed lightgrey;
|
||||
background-color:#f9f9f9;
|
||||
padding:0.5ex;
|
||||
}
|
||||
|
||||
pre em {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dt {
|
||||
margin:0ex 2ex;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin:0ex 0ex 1ex 4ex;
|
||||
}
|
||||
|
||||
+6184
File diff suppressed because it is too large
Load Diff
+12
-9
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.0.1 Developers Guide
|
||||
<TITLE>Ejabberd 2.1.11 Developers Guide
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -49,7 +49,7 @@ TD P{margin:0px;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.1 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
|
||||
</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">
|
||||
@@ -84,7 +84,7 @@ Kevin Smith, Current maintainer of the Psi project</I></BLOCKQUOTE><!--TOC secti
|
||||
</LI><LI CLASS="li-toc"><A HREF="#htoc15">8.2  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</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
|
||||
<A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang/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>  Key Features</H2><!--SEC END --><P>
|
||||
<A NAME="keyfeatures"></A>
|
||||
</P><P><TT>ejabberd</TT> is:
|
||||
@@ -98,7 +98,7 @@ Comprehensive documentation.
|
||||
</LI><LI CLASS="li-itemize">Capability to send announce messages.
|
||||
</LI></UL></LI><LI CLASS="li-itemize">Internationalized: <TT>ejabberd</TT> leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
|
||||
<UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
Translated to 24 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
|
||||
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.
|
||||
@@ -139,14 +139,14 @@ Support for virtual hosting.
|
||||
</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-00163.html">Personal Eventing via Pubsub</A>.
|
||||
</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>  How it Works</H2><!--SEC END --><P>
|
||||
<A NAME="howitworks"></A></P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can
|
||||
<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
|
||||
@@ -159,7 +159,7 @@ router;
|
||||
</LI><LI CLASS="li-itemize">session manager;
|
||||
</LI><LI CLASS="li-itemize">S2S manager;
|
||||
</LI></UL><!--TOC subsection Router-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc4">3.1</A>  Router</H3><!--SEC END --><P>This module is the main router of Jabber packets on each node. It routes
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc4">3.1</A>  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
|
||||
@@ -170,10 +170,10 @@ manager.</P><!--TOC subsection Local Router-->
|
||||
name. If destination JID has a non-empty user part, then it routed to the
|
||||
session manager, else it is processed depending on it’s content.</P><!--TOC subsection Session Manager-->
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc6">3.3</A>  Session Manager</H3><!--SEC END --><P>This module routes packets to local users. It searches for what user resource
|
||||
packet must be sended via presence table. If this resource is connected to
|
||||
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>  S2S Manager</H3><!--SEC END --><P>This module routes packets to other Jabber servers. First, it checks if an
|
||||
<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc7">3.4</A>  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
|
||||
@@ -194,6 +194,9 @@ operation are as follows:
|
||||
auth:User:Server:Password (check if a username/password pair is correct)
|
||||
</LI><LI CLASS="li-itemize">isuser:User:Server (check if it’s a valid user)
|
||||
</LI><LI CLASS="li-itemize">setpass:User:Server:Password (set user’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
|
||||
|
||||
+8
-4
@@ -26,6 +26,7 @@
|
||||
\newcommand{\ns}[1]{\texttt{#1}}
|
||||
\newcommand{\ejabberd}{\texttt{ejabberd}}
|
||||
\newcommand{\Jabber}{Jabber}
|
||||
\newcommand{\XMPP}{XMPP}
|
||||
|
||||
%% Modules
|
||||
\newcommand{\module}[1]{\texttt{#1}}
|
||||
@@ -100,7 +101,7 @@
|
||||
\label{howitworks}
|
||||
|
||||
|
||||
A \Jabber{} domain is served by one or more \ejabberd{} nodes. These nodes can
|
||||
A \XMPP{} domain is served by one or more \ejabberd{} nodes. These nodes can
|
||||
be run on different machines that are connected via a network. They all must
|
||||
have the ability to connect to port 4369 of all another nodes, and must have
|
||||
the same magic cookie (see Erlang/OTP documentation, in other words the file
|
||||
@@ -121,7 +122,7 @@ Each \ejabberd{} node have following modules:
|
||||
|
||||
\subsection{Router}
|
||||
|
||||
This module is the main router of \Jabber{} packets on each node. It routes
|
||||
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
|
||||
@@ -140,14 +141,14 @@ session manager, else it is processed depending on it's content.
|
||||
\subsection{Session Manager}
|
||||
|
||||
This module routes packets to local users. It searches for what user resource
|
||||
packet must be sended via presence table. If this resource is connected to
|
||||
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.
|
||||
|
||||
|
||||
\subsection{S2S Manager}
|
||||
|
||||
This module routes packets to other \Jabber{} servers. First, it checks if an
|
||||
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
|
||||
@@ -175,6 +176,9 @@ That script is supposed to do theses actions, in an infinite loop:
|
||||
\item auth:User:Server:Password (check if a username/password pair is correct)
|
||||
\item isuser:User:Server (check if it's a valid user)
|
||||
\item setpass:User:Server:Password (set user's password)
|
||||
\item tryregister:User:Server:Password (try to register an account)
|
||||
\item removeuser:User:Server (remove this account)
|
||||
\item removeuser3:User:Server:Password (remove this account if the password is correct)
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item write to stdout: AABB
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Ejabberd 2.0.1 Feature Sheet
|
||||
<TITLE>Ejabberd 2.1.11 Feature Sheet
|
||||
</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
||||
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
|
||||
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
|
||||
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
|
||||
|
||||
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.0.1 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
|
||||
</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">
|
||||
@@ -61,7 +61,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
|
||||
</DIV><BLOCKQUOTE CLASS="quotation"><FONT COLOR="#921700"><I>I can thoroughly recommend ejabberd for ease of setup –
|
||||
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. —
|
||||
Joeri</I></FONT></BLOCKQUOTE><P><TT>ejabberd</TT> is a <B><FONT SIZE=4><FONT COLOR="#001376">free and open source</FONT></FONT></B> instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is <B><FONT SIZE=4><FONT COLOR="#001376">cross-platform</FONT></FONT></B>, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a <B><FONT SIZE=4><FONT COLOR="#001376">rock-solid and feature rich</FONT></FONT></B> XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be <B><FONT SIZE=4><FONT COLOR="#001376">scalable</FONT></FONT></B> or not, as well as extremely big deployments.</P><!--TOC section Key Features-->
|
||||
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. —
|
||||
@@ -76,7 +76,7 @@ Comprehensive documentation.
|
||||
</LI><LI CLASS="li-itemize">Capability to send announce messages.
|
||||
</LI></UL></LI><LI CLASS="li-itemize"><B><FONT SIZE=4><FONT COLOR="#001376">Internationalized:</FONT></FONT></B> <TT>ejabberd</TT> leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
|
||||
<UL CLASS="itemize"><LI CLASS="li-itemize">
|
||||
Translated to 24 languages. </LI><LI CLASS="li-itemize">Support for <A HREF="http://www.ietf.org/rfc/rfc3490.txt">IDNA</A>.
|
||||
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.
|
||||
@@ -118,7 +118,7 @@ Support for virtual hosting.
|
||||
</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-00163.html">Personal Eventing via Pubsub</A>.
|
||||
</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.
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@
|
||||
%% Fancy header
|
||||
\fancyhf{}
|
||||
\pagestyle{fancy}
|
||||
\rhead{\textcolor{ejblue}{The Expandable Jabber Daemon.}}
|
||||
\rhead{\textcolor{ejblue}{The Expandable Jabber/XMPP Daemon.}}
|
||||
\renewcommand{\headrule}{{\color{ejblue}%
|
||||
\hrule width\headwidth height\headrulewidth \vskip-\headrulewidth}}
|
||||
\lhead{\setlength{\unitlength}{-6mm}
|
||||
@@ -133,4 +133,4 @@
|
||||
% "What I find interesting is that *no* XMPP servers truly provide clustering. This includes all the commercial
|
||||
% servers. The one partial exception appears to be ejabberd, which can cluster certain data such as sessions,
|
||||
% but not all services such as MUC."
|
||||
% * try it today: links to migration tutorials
|
||||
% * try it today: links to migration tutorials
|
||||
|
||||
+3072
-1772
File diff suppressed because it is too large
Load Diff
+3626
-1728
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,146 @@
|
||||
# Managing pubsub nodes through HTTP Atompub #
|
||||
|
||||
|
||||
## Configuration ##
|
||||
|
||||
These options will be used by the service to know how to build URLs. Using the previous configuration items the service should be accessed through `http://notify.push.bbc.co.uk:5280/pshb/<host>/<node>/`.
|
||||
|
||||
Also, in the ejabberd_http handler configuration, add the identified line.
|
||||
|
||||
{5280, ejabberd_http, [
|
||||
http_poll,
|
||||
web_admin,
|
||||
{request_handlers, [{["pshb"], pshb_http}]} % this should be added
|
||||
]}
|
||||
|
||||
It will automatically detect the version of mod_pubsub (odbc or mnesia) and call the appropriate module.
|
||||
|
||||
## Important notice ##
|
||||
|
||||
In the current version of the code, some security checks are not done :
|
||||
|
||||
* node creation uses the default `all` access_createnode acl, not checking for the actual configuration.
|
||||
|
||||
* most read operations are successfully executed without authentication. HOWEVER listing items can only be done when the node access_model is "open". In all other cases, the service returns 403. A finer grained authentication will be implemented.
|
||||
|
||||
|
||||
## Usage example with cURL ##
|
||||
|
||||
### Errors ###
|
||||
|
||||
HTTP status codes are used as intended. Additionally, the XMPP error stanza can also be set in the body :
|
||||
|
||||
$ curl -i -X POST -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost
|
||||
HTTP/1.1 409 Conflict
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Content-Length: 95
|
||||
Content-type: application/xml
|
||||
|
||||
<error code='409' type='cancel'><conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
|
||||
|
||||
or
|
||||
|
||||
$ curl -i -X DELETE -u cstar@localhost:encore http://localhost:5280/pshb/localhost/princely_musings
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Content-Length: 101
|
||||
Content-type: application/xml
|
||||
|
||||
<error code='404' type='cancel'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>
|
||||
|
||||
### Getting the service document ###
|
||||
|
||||
No authentication necessary. All nodes are listed.
|
||||
|
||||
$ curl -i http://host:port/pshb/domain/
|
||||
|
||||
### Getting items from a node ###
|
||||
|
||||
No authentication done, and all nodes are accessible.
|
||||
|
||||
$ curl -i http://host:port/pshb/domain/node/
|
||||
|
||||
|
||||
### Posting a new item ###
|
||||
|
||||
$ curl -u jid:password -i -X POST -d @entry.atom http://post:port/pshb/domain/node
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
### Editing a new item ###
|
||||
|
||||
$ curl -u jid:password -i -X POST -d @entry.atom http://post:port/pshb/domain/node/itemid
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
### Deleting an item ###
|
||||
|
||||
$ curl -u jid:password -i -X DELETE http://post:port/pshb/domain/node/itemid
|
||||
|
||||
User ability to post is based on node configuration.
|
||||
|
||||
|
||||
### Creating a new node ###
|
||||
|
||||
An instant node can be created if server configuration allows:
|
||||
|
||||
$ curl -X POST -u cstar@localhost:encore -d "" http://localhost:5280/pshb/localhost
|
||||
|
||||
or
|
||||
|
||||
$ curl -X POST -u cstar@localhost:encore -d "<pubsub><create node='princely_musings'/></pubsub>" http://localhost:5280/pshb/localhost
|
||||
|
||||
configure element (as per XEP-60) can be passed in the pubsub body.
|
||||
|
||||
$ cat createnode.xml
|
||||
<pubsub><create node='princely_musings' type='flat'/>
|
||||
<x xmlns='jabber:x:data' type='submit'>
|
||||
<field var='FORM_TYPE' type='hidden'>
|
||||
<value>http://jabber.org/protocol/pubsub#node_config</value>
|
||||
</field>
|
||||
<field var='pubsub#title'><value>Princely Musings (Atom)</value></field>
|
||||
<field var='pubsub#max_payload_size'><value>1028</value></field>
|
||||
<field var='pubsub#type'><value>Atom</value></field>
|
||||
</x>
|
||||
</pubsub>
|
||||
|
||||
$ curl -i -X POST -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 130
|
||||
Content-Type: application/xml
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?><pubsub xmlns='http://jabber.org/protocol/pubsub'><create node='princely_musings'/></pubsub>
|
||||
|
||||
### Editing a node configuration ###
|
||||
|
||||
$ cat editnode.xml
|
||||
<pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
|
||||
<configure node='princely_musings'>
|
||||
<x xmlns='jabber:x:data' type='submit'>
|
||||
<field var='FORM_TYPE' type='hidden'>
|
||||
<value>http://jabber.org/protocol/pubsub#node_config</value>
|
||||
</field>
|
||||
<field var='pubsub#title'><value>Princely Musings (Atom)</value></field>
|
||||
<field var='pubsub#deliver_notifications'><value>1</value></field>
|
||||
<field var='pubsub#deliver_payloads'><value>1</value></field>
|
||||
<field var='pubsub#persist_items'><value>1</value></field>
|
||||
<field var='pubsub#max_items'><value>10</value></field>
|
||||
<field var='pubsub#item_expire'><value>604800</value></field>
|
||||
<field var='pubsub#access_model'><value>roster</value></field>
|
||||
</x>
|
||||
</configure>
|
||||
</pubsub>
|
||||
|
||||
|
||||
$ curl -i -X PUT -u cstar@localhost:encore -d @createnode.xml http://localhost:5280/pshb/localhost/princely_musings
|
||||
|
||||
|
||||
|
||||
### Deleting a node ###
|
||||
|
||||
A node is deleted by:
|
||||
|
||||
$ curl -X DELETE -u cstar@localhost:encore http://localhost:5280/pshb/localhost/princely_musings
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Joeri}
|
||||
|
||||
%ejabberd is a free and open source instant messaging server written in Erlang. ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication (Jabber/XMPP).
|
||||
|
||||
\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang}.
|
||||
\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang/OTP}.
|
||||
|
||||
\ejabberd{} is \marking{cross-platform}, distributed, fault-tolerant, and based on open standards to achieve real-time communication.
|
||||
|
||||
@@ -68,7 +68,7 @@ Peter Saint-Andr\'e, Executive Director of the Jabber Software Foundation}
|
||||
|
||||
\item \marking{Internationalized:} \ejabberd{} leads in internationalization. Hence it is very well suited in a globalized world. Related features are:
|
||||
\begin{itemize}
|
||||
\item Translated to 24 languages. %%\improved{}
|
||||
\item Translated to 25 languages. %%\improved{}
|
||||
\item Support for \footahref{http://www.ietf.org/rfc/rfc3490.txt}{IDNA}.
|
||||
\end{itemize}
|
||||
|
||||
@@ -125,7 +125,7 @@ Moreover, \ejabberd{} comes with a wide range of other state-of-the-art features
|
||||
\item IPv6 support both for c2s and s2s connections.
|
||||
\item \txepref{0045}{Multi-User Chat} module with support for clustering and HTML logging. %%\improved{}
|
||||
\item Users Directory based on users vCards.
|
||||
\item \txepref{0060}{Publish-Subscribe} component with support for \txepref{00163}{Personal Eventing via Pubsub}.
|
||||
\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.
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env escript
|
||||
%% -*- erlang -*-
|
||||
|
||||
-record(cmd, {name, desc, longdesc, args, result}).
|
||||
|
||||
main(_) ->
|
||||
Dir = filename:absname(filename:join(["..", "src"])),
|
||||
FileIn = filename:join([Dir, "mod_admin_p1.erl"]),
|
||||
{ok, Forms1} = epp_dodger:parse_file(FileIn, [no_fail]),
|
||||
Comments = erl_comment_scan:file(FileIn),
|
||||
Forms = erl_recomment:recomment_forms(Forms1, Comments),
|
||||
Tree = erl_syntax:flatten_form_list(Forms),
|
||||
AuxFile = "mod_admin.tex",
|
||||
case file:open(AuxFile, [write]) of
|
||||
{ok, Fd} ->
|
||||
io:format(Fd, "\\newcommand{\\modadminsection}{\\begin{description}~n", []),
|
||||
process(Fd, Tree),
|
||||
io:format(Fd, "\\end{description}}~n", []),
|
||||
file:close(Fd),
|
||||
halt(0);
|
||||
{error, Why} ->
|
||||
io:format("failed to open file ~s: ~s",
|
||||
[AuxFile, file:format_error(Why)]),
|
||||
halt(1)
|
||||
end.
|
||||
|
||||
process(Fd, Tree) ->
|
||||
case erl_syntax:type(Tree) of
|
||||
record_expr ->
|
||||
case erl_syntax_lib:analyze_record_expr(Tree) of
|
||||
{record_expr, {ejabberd_commands, _}} ->
|
||||
Fs = erl_syntax:record_expr_fields(Tree),
|
||||
Cmd = lists:foldl(
|
||||
fun(F, C) ->
|
||||
Name = erl_syntax:record_field_name(F),
|
||||
Value = erl_syntax:record_field_value(F),
|
||||
case {erl_syntax:concrete(Name),
|
||||
catch erl_syntax:concrete(Value)} of
|
||||
{_, {'EXIT', _}} ->
|
||||
C;
|
||||
{name, V} ->
|
||||
C#cmd{name = V};
|
||||
{desc, V} ->
|
||||
C#cmd{desc = V};
|
||||
{longdesc, V} ->
|
||||
C#cmd{longdesc = V};
|
||||
{args, V} ->
|
||||
C#cmd{args = V};
|
||||
{result, V} ->
|
||||
C#cmd{result = V};
|
||||
_ ->
|
||||
C
|
||||
end
|
||||
end, #cmd{}, Fs),
|
||||
format_command(Fd, Cmd);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
case erl_syntax:subtrees(Tree) of
|
||||
[] ->
|
||||
ok;
|
||||
List ->
|
||||
lists:foreach(
|
||||
fun(Group) ->
|
||||
lists:foreach(
|
||||
fun(Subtree) ->
|
||||
process(Fd, Subtree)
|
||||
end, Group)
|
||||
end, List)
|
||||
end
|
||||
end.
|
||||
|
||||
-define(B(S), S).
|
||||
|
||||
format_command(Fd, #cmd{name = Cmd,
|
||||
desc = Desc,
|
||||
longdesc = _LongDesc,
|
||||
args = ArgsDef,
|
||||
result = _ResultDef}) ->
|
||||
io:format(Fd, "\\titem{~s ~s} ~s~n",
|
||||
[escape_underscores(atom_to_list(Cmd)),
|
||||
flatten_arguments(ArgsDef),
|
||||
escape_underscores(Desc)]).
|
||||
|
||||
flatten_arguments(Args) ->
|
||||
string:join(
|
||||
lists:map(
|
||||
fun({Name, _Type}) ->
|
||||
escape_underscores(io_lib:format("~s", [Name]))
|
||||
end, Args),
|
||||
" ").
|
||||
|
||||
escape_underscores(S) ->
|
||||
lists:flatten(
|
||||
[case C of
|
||||
$_ -> "\\_";
|
||||
_ -> C
|
||||
end || C <- S]).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,34 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.0.2
|
||||
28 August 2008
|
||||
|
||||
ejabberd 2.0.2 is the second bug fix release for ejabberd 2.0.x branch.
|
||||
|
||||
ejabberd 2.0.2 includes many bugfixes and a few improvements.
|
||||
A complete list of changes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.0.2
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
Recent changes include:
|
||||
|
||||
- Anti-abuse feature: client blacklist support by IP.
|
||||
- Guide: new section Securing ejabberd; improved usability.
|
||||
- LDAP filter optimisation: ability to filter user in ejabberd and not LDAP.
|
||||
- MUC improvements: room options to restrict visitors; broadcast reasons.
|
||||
- Privacy rules: fix MySQL storage.
|
||||
- Pub/Sub and PEP: many improvements in implementation and protocol compliance.
|
||||
- Proxy65: send valid SOCKS5 reply (removed support for Psi < 0.10).
|
||||
- Web server embedded: better support for HTTPS.
|
||||
- Binary installers: SMP on Windows; don't remove config when uninstalling.
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
END
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.0.3
|
||||
14 January 2009
|
||||
|
||||
ejabberd 2.0.3 is the third bugfix release for ejabberd 2.0.x branch.
|
||||
|
||||
ejabberd 2.0.3 includes several bugfixes and a few improvements.
|
||||
A complete list of changes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.0.3
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
Recent changes include:
|
||||
|
||||
- Do not ask certificate for client (c2s)
|
||||
- Check digest-uri in SASL digest authentication
|
||||
- Use send timeout to avoid locking on gen_tcp:send
|
||||
- Fix ejabberd reconnection to database
|
||||
- HTTP-Bind: handle wrong order of packets
|
||||
- MUC: Improve traffic regulation management
|
||||
- PubSub: Several bugfixes and improvements for best coverage of XEP-0060 v1.12
|
||||
- Shared Roster Groups: push immediately membership changes
|
||||
- Rotate also sasl.log on "reopen-log" command
|
||||
- Binary Windows installer: better detect "Error running Post Install Script"
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
END
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.0.4
|
||||
|
||||
ejabberd 2.0.4 is the fourth bugfix release for ejabberd 2.0.x branch.
|
||||
|
||||
ejabberd 2.0.4 includes several bugfixes.
|
||||
A detailed list of changes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.0.4
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
- Ensure ID attribute in roster push is unique
|
||||
- Authentication: Fix Anonymous auth when enabled with broken ODBC
|
||||
- Authentication: Unquote correctly backslash in DIGEST-MD5 SASL responses
|
||||
- Authentication: Cancel presence subscriptions on account deletion
|
||||
- LDAP: Close a connection on tcp_error
|
||||
- LDAP: Implemented queue for pending queries
|
||||
- LDAP: On failure of LDAP connection, waiting is done on pending queue
|
||||
- MUC: Owner of a password protected room must also provide the password
|
||||
- MUC: Prevent XSS in MUC logs by linkifying only a few known protocols
|
||||
- Privacy rules: Items are now processed in the specified order
|
||||
- Privacy rules: Fix to correctly block subscription requests
|
||||
- Proxy65: If ip option is not defined, take an IP address of a local hostname
|
||||
- PubSub: Add roster subscription handling; send PEP events to all resources
|
||||
- PubSub: Allow node creation without configure item
|
||||
- PubSub: Requesting items on a node which exists, but empty returns an error
|
||||
- PEP: Fix sending notifications to other domains and s2s
|
||||
- S2S: Fix problem with encrypted connection to Gtalk and recent Openfire
|
||||
- S2S: Workaround to get DNS SRV lookup to work on Windows machine
|
||||
- Shared Roster Groups: Fix to not resend authorization request
|
||||
- WebAdmin: Fix encryption problem for ejabberd_http after timeout
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
END
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.0.5
|
||||
|
||||
ejabberd 2.0.5 is the fifth bugfix release in ejabberd 2.0.x branch.
|
||||
|
||||
ejabberd 2.0.5 includes three bugfixes.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.0.5
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
- Fix two problems introduced in ejabberd 2.0.4: subscription request
|
||||
produced many authorization requests with some clients and
|
||||
transports; and subscription requests were not stored for later
|
||||
delivery when receiver was offline.
|
||||
|
||||
- Fix warning in expat_erl.c about implicit declaration of x_fix_buff
|
||||
|
||||
- HTTP-Bind (BOSH): Fix a missing stream:error in the returned
|
||||
remote-stream-error stanza
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
END
|
||||
@@ -0,0 +1,281 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.0
|
||||
|
||||
ejabberd 2.1.0 is a major new version for ejabberd adding many
|
||||
new features, performance and scalability improvements.
|
||||
|
||||
ejabberd 2.1.0 includes many new features, improvements and bug fixes.
|
||||
A complete list of changes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.0
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
New features and improvements:
|
||||
|
||||
* Anti-abuse
|
||||
- Captcha support (XEP-0158). The example script uses ImageMagick.
|
||||
- New option: registration_timeout to limit registrations by time
|
||||
- Use send timeout to avoid locking on gen_tcp:send
|
||||
- mod_ip_blacklist: client blacklist support by IP
|
||||
|
||||
* API
|
||||
- ejabberd_http provides Host, Port, Headers and Protocol in HTTP requests
|
||||
- Export function to create MUC room
|
||||
- New events: s2s_send_packet and s2s_receive_packet
|
||||
- New event: webadmin_user_parse_query when POST in web admin user page
|
||||
- Support distributed hooks over the cluster
|
||||
|
||||
* Authentification
|
||||
- Extauth responses: log strange responses and add timeout
|
||||
|
||||
* Binary Installer
|
||||
- Includes exmpp library to support import/export XML files
|
||||
|
||||
* Caps
|
||||
- Remove useless caps tables entries
|
||||
- mod_caps must handle correctly external contacts with several resources
|
||||
- Complain if mod_caps disabled and mod_pubsub has PEP plugin enabled
|
||||
|
||||
* Clustering and Architecture
|
||||
|
||||
* Configuration
|
||||
- Added option access_max_user_messages for mod_offline
|
||||
- Added option backlog for ejabberd_listener to increase TCP backlog
|
||||
- Added option define_macro and use_macro
|
||||
- Added option include_config_file to include additional configuration files
|
||||
- Added option max_fsm_queue
|
||||
- Added option outgoing_s2s_options to define IP address families and timeout
|
||||
- Added option registration_timeout to ejabberd.cfg.example
|
||||
- Added option s2s_dns_options to define DNS timeout and retries
|
||||
- Added option ERL_OPTIONS to ejabberdctl.cfg
|
||||
- Added option FIREWALL_WINDOW to ejabberdctl.cfg
|
||||
- Added option EJABBERD_PID_PATH to ejabberdctl.cfg
|
||||
- Deleted option user_max_messages of mod_offline
|
||||
- Check certfiles are readable on server start and listener start
|
||||
- Config file management mix file reading and sanity check
|
||||
- Include example PAM configuration file: ejabberd.pam
|
||||
- New ejabberd listener: ejabberd_stun
|
||||
- Support to bind the same port to multiple interfaces
|
||||
- New syntax to specify the IP address and IPv6 in listeners
|
||||
configuration. The old options {ip,{1,2,3,4}} and inet6 are
|
||||
supported even if they aren't documented.
|
||||
- New syntax to specify the network protocol: tcp or udp
|
||||
- Report error at startup if a listener module isn't available
|
||||
- Only listen in a port when actually ready to serve requests
|
||||
- In default config, only local accounts can create rooms and PubSub nodes
|
||||
|
||||
* Core architecture
|
||||
- More verbose error reporting for xml:element_to_string
|
||||
- Deliver messages when first presence is Invisible
|
||||
- Better log message when config file is not found
|
||||
- Include original timestamp on delayed presences
|
||||
|
||||
* Crypto
|
||||
- Do not ask certificate for client (c2s)
|
||||
- SSL code remove from ejabberd in favor of TLS
|
||||
- Support Zlib compression after STARTTLS encryption
|
||||
- tls v1 client hello
|
||||
|
||||
* Documentation
|
||||
- Document possible default MUC room options
|
||||
- Document service_check_from in the Guide
|
||||
- Document s2s_default_policy and s2s_host in the Guide
|
||||
- new command and guide instructions to change node name in a Mnesia database
|
||||
|
||||
* ejabberd commands
|
||||
- ejabberd commands: separate command definition and calling interface
|
||||
- access_commands restricts who can execute what commands and arguments
|
||||
- ejabberdctl script now displays help and categorization of commands
|
||||
|
||||
* HTTP Binding and HTTP Polling
|
||||
- HTTP-Bind: module optimization and clean-up
|
||||
- HTTP-Bind: allow configuration of max_inactivity timeout
|
||||
- HTTP-Poll: turn session timeout into a config file parameter
|
||||
|
||||
* Jingle
|
||||
- STUN server that facilitates the client-to-client negotiation process
|
||||
|
||||
* LDAP
|
||||
- Faster reconnection to LDAP servers
|
||||
- LDAP filter optimisation: Add ability to filter user in ejabberd and not LDAP
|
||||
- LDAP differentiates failed auth and unavailable auth service
|
||||
- Improve LDAP logging
|
||||
- LDAPS support using TLS.
|
||||
|
||||
* Localization
|
||||
- Use Gettext PO for translators, export to ejabberd MSG
|
||||
- Support translation files for additional projects
|
||||
- Most translations are updated to latest code
|
||||
- New translation to Greek language
|
||||
|
||||
* Multi-User Chat (MUC)
|
||||
- Allow admins to send messages to rooms
|
||||
- Allow to store room description
|
||||
- Captcha support in MUC: the admin of a room can configure it to
|
||||
require participants to fill a captcha to join the room.
|
||||
- Limit number of characters in Room ID, Name and Description
|
||||
- Prevent unvoiced occupants from changing nick
|
||||
- Support Result Set Management (XEP-0059) for listing rooms
|
||||
- Support for decline of invitation to MUC room
|
||||
- mod_muc_log options: plaintext format; filename with only room name
|
||||
|
||||
* Performance
|
||||
- Run roster_get_jid_info only if privacy list has subscription or group item
|
||||
- Significant PubSub performance improvements
|
||||
|
||||
* Publish-Subscribe
|
||||
- Add nodetree filtering/authorization
|
||||
- Add subscription option support for collection nodes
|
||||
- Allow Multiple Subscriptions
|
||||
- Check option of the nodetree instead of checking configuration
|
||||
- Implement whitelist authorize and roster access model
|
||||
- Implicit item deletion is not notified when deleting node
|
||||
- Make PubSub x-data configuration form handles list value
|
||||
- Make default node name convention XEP-compatible, document usage of hierarchy
|
||||
- Node names are used verbatim, without separating by slash, unless a
|
||||
node plugin uses its own separator
|
||||
- Send authorization update event (XEP-0060, 8.6)
|
||||
- Support of collection node subscription options
|
||||
- Support ODBC storage. Experimental, needs more testing.
|
||||
|
||||
* Relational databases:
|
||||
- Added MSSQL 2000 and 2005
|
||||
- Privacy rules storage in MySQL
|
||||
- Implement reliable ODBC transaction nesting
|
||||
|
||||
* Source Package
|
||||
- Default installation directories changed. Please see the upgrade notes below.
|
||||
- Allow more environment variable overrides in ejabberdctl
|
||||
- ChangeLog is not edited manually anymore; it's generated automatically.
|
||||
- Install the ejabberd Guide
|
||||
- Install the ejabberd include files
|
||||
- New option for the 'configure' script: --enable-user which installs
|
||||
ejabberd granting permission to manage it to a regular system user;
|
||||
no need to use root account to.
|
||||
- Only try to install epam if pam was enabled in configure script
|
||||
- Spool, config and log dirs: owner writes, group reads, others do nothing.
|
||||
- Provides an example ejabberd.init file
|
||||
|
||||
* S2S
|
||||
- Option to define s2s outgoing behaviour: IPv4, IPv6 and timeout
|
||||
- DNS timeout and retries, configurable with s2s_dns_options.
|
||||
|
||||
* Shared rosters
|
||||
- When a member is added/removed to group, send roster upgrade to group members
|
||||
|
||||
* Users management
|
||||
- When account is deleted, cancel presence subscription for all roster items
|
||||
|
||||
* XEP Support
|
||||
- Added XEP-0059 Result Set Management (for listing rooms)
|
||||
- Added XEP-0082 Date Time
|
||||
- Added XEP-0085 Chat State Notifications
|
||||
- Added XEP-0157 Contact Addresses for XMPP Services
|
||||
- Added XEP-0158 CAPTCHA Forms (in MUC rooms)
|
||||
- Added STUN server, for XEP-0176: Jingle ICE-UDP Transport Method
|
||||
- Added XEP-0199 XMPP Ping
|
||||
- Added XEP-0202 Entity Time
|
||||
- Added XEP-0203 Delayed Delivery
|
||||
- Added XEP-0227 Portable Import/Export Format for XMPP-IM Servers
|
||||
- Added XEP-0237 Roster Versioning
|
||||
|
||||
* Web Admin
|
||||
- Display the connection method of user sessions
|
||||
- Cross link of ejabberd users in the list of users and rosters
|
||||
- Improved the browsing menu: don't disappear when browsing a host or node
|
||||
- Include Last-Modified HTTP header in responses to allow caching
|
||||
- Make some Input areas multiline: options of listening ports and modules
|
||||
- Support PUT and DELETE methods in ejabberd_http
|
||||
- WebAdmin serves Guide and links to related sections
|
||||
|
||||
* Web plugins
|
||||
- mod_http_fileserver: new option directory_indices, and improve logging
|
||||
|
||||
|
||||
Important Notes:
|
||||
|
||||
- ejabberd 2.1.0 requires Erlang R10B-9 or higher.
|
||||
R12B-5 is the recommended version. Support for R13B is experimental.
|
||||
|
||||
|
||||
Upgrading From ejabberd 1.x.x:
|
||||
|
||||
- Check the Release Notes of the intermediate versions for additional
|
||||
information about database or configuration changes.
|
||||
|
||||
|
||||
Upgrading From ejabberd 2.0.x:
|
||||
|
||||
- The database schemas have three changes since ejabberd 2.0.x.
|
||||
Check the database creation SQL files and update your database.
|
||||
1) New table roster_version to support roster versioning.
|
||||
2) Six new tables for optional pubsub ODBC storage.
|
||||
3) Some tables in the MySQL database have a new created_at column.
|
||||
|
||||
- As usual, it is recommended to backup the Mnesia spool directory and
|
||||
your SQL database (if used) before upgrading ejabberd.
|
||||
|
||||
- Between ejabberd 2.0.0 and 2.0.5, mod_pubsub used "default" as the
|
||||
default node plugin. But in 2.1.0 this is renamed to "hometree".
|
||||
You have to edit your ejabberd config file and replace those names.
|
||||
If you used ejabberd 2.0.5 or older, the database will be updated
|
||||
automatically. But if you were using ejabberd from SVN, you must
|
||||
manually run ejabberdctl with the command: rename_default_nodeplugin.
|
||||
Running this command on already updated database does nothing.
|
||||
|
||||
- The listener options 'ip' and 'inet6' are not documented anymore
|
||||
but they are supported and you can continue using them.
|
||||
There is a new syntax to define IP address and IP version.
|
||||
As usual, check the ejabberd Guide for more information.
|
||||
|
||||
- The log file sasl.log is now called erlang.log
|
||||
|
||||
- ejabberdctl commands now have _ characters instead of -.
|
||||
For backwards compatibility, it is still supported -.
|
||||
|
||||
- mod_offline has a new option: access_max_user_messages.
|
||||
The old option user_max_messages is no longer supported.
|
||||
|
||||
- If you upgrade from ejabberd trunk SVN, you must execute this:
|
||||
$ ejabberdctl rename_default_nodeplugin
|
||||
|
||||
- Default installation directories changed a bit:
|
||||
* The Mnesia spool files that were previously stored in
|
||||
/var/lib/ejabberd/db/NODENAME/*
|
||||
are now stored in
|
||||
/var/lib/ejabberd/*
|
||||
* The directories
|
||||
/var/lib/ejabberd/ebin
|
||||
/var/lib/ejabberd/priv
|
||||
and their content is now installed as
|
||||
/lib/ejabberd/ebin
|
||||
/lib/ejabberd/priv
|
||||
* There is a new directory with Erlang header files:
|
||||
/lib/ejabberd/include
|
||||
* There is a new directory for ejabberd documentation,
|
||||
which includes the Admin Guide and the release notes::
|
||||
/share/doc/ejabberd
|
||||
|
||||
- How to upgrade from previous version to ejabberd 2.1.0:
|
||||
1. Stop the old instance of ejabberd.
|
||||
2. Run 'make install' of new ejabberd 2.1.0 to create the new directories.
|
||||
3. Copy the content of your old directory:
|
||||
/var/lib/ejabberd/db/NODENAME/
|
||||
to the new location:
|
||||
/var/lib/ejabberd/
|
||||
so you will have the files like this:
|
||||
/var/lib/ejabberd/acl.DCD ...
|
||||
4. You can backup the content of those directories and delete them:
|
||||
/var/lib/ejabberd/ebin
|
||||
/var/lib/ejabberd/priv
|
||||
/var/lib/ejabberd/db
|
||||
5. Now try to start your new ejabberd 2.1.0.
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.1
|
||||
|
||||
ejabberd 2.1.1 is the first bugfix release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.1 includes several important bugfixes.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.1
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The changes are:
|
||||
|
||||
* Core
|
||||
- Call ejabberd_router:route/3 instead of sending a message
|
||||
- Can't connect if starttls_required and zlib are set
|
||||
- Routes vCard request to the occupant full JID, but should to bare JID
|
||||
- S2S: fix allow_host/2 on subdomains. added hook s2s_allow_host
|
||||
|
||||
* MUC
|
||||
- Support converting one-to-one chat to MUC
|
||||
- Add support for serving a Unique Room Name
|
||||
|
||||
* Publish Subscribe
|
||||
- Receive same last published PEP items at reconnect if several resources online
|
||||
- Typo in mod_pubsub_odbc breaks Service Discovery and more
|
||||
|
||||
* Web
|
||||
- Fix memory and port leak when TLS is enabled in HTTP
|
||||
- WebAdmin doesn't report correct last activity with postgresql backend
|
||||
- Option to define custom HTTP headers in mod_http_fileserver
|
||||
- Show informative webpage when browsing the HTTP-Poll page
|
||||
|
||||
* Other
|
||||
- Change captcha.sh to not depend on bash
|
||||
- Generate main XML file also when exporting only a vhost
|
||||
- Fix last newline in ejabberdctl result
|
||||
- Guide: fix -setcookie, mod_pubsub_odbc host, content_types
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -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/
|
||||
@@ -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/
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.2
|
||||
|
||||
ejabberd 2.1.2 is the second bugfix release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.2 includes several bugfixes.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.2
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
The major changes are:
|
||||
|
||||
* Core
|
||||
- Close sessions that were half connected
|
||||
- Fix SASL PLAIN authentication message for RFC4616 compliance
|
||||
- Fix support for old Erlang/OTP R10 and R11
|
||||
- Return proper error (not 'conflict') when register is forbidden by ACL
|
||||
- When ejabberd stops, send stream close to clients
|
||||
|
||||
* ejabberdctl
|
||||
- Check for EGID in ejabberdctl command
|
||||
- Command to stop ejabberd informing users, with grace period
|
||||
- If there's a problem in config file, display config lines and stop node
|
||||
|
||||
* MUC
|
||||
- Kick occupants with reason when room is stopped due to MUC shutdown
|
||||
- Write in room log when a room is created, destroyed, started, stopped
|
||||
|
||||
* PubSub and PEP
|
||||
- Don't call gen_server on internal event (improves performance and scalability)
|
||||
- Fix duplicate SHIM header in Pubsub message
|
||||
- Notification messages of Pubsub node config change contained a SHIM header
|
||||
- SubID SHIM header missing in Pubsub message with multiple
|
||||
subscriptions on the same node
|
||||
- PEP: last published item not sent from unavailable users when the
|
||||
subscription is implicit (XEP-0115)
|
||||
- pep_mapping not working due to Node type mismatch
|
||||
|
||||
* WebAdmin
|
||||
- If big offline message queue, show only subset on WebAdmin
|
||||
- Support in user list page of WebAdmin when mod_offline is disabled
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.3
|
||||
|
||||
ejabberd 2.1.3 is the third release in ejabberd 2.1.x branch.
|
||||
|
||||
ejabberd 2.1.3 includes many bugfixes, and some improvements.
|
||||
More details of those fixes can be retrieved from:
|
||||
http://redir.process-one.net/ejabberd-2.1.3
|
||||
|
||||
The new code can be downloaded from ejabberd download page:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
This is the full list of changes:
|
||||
|
||||
* Client connections
|
||||
- Avoid 'invalid' value in iq record
|
||||
- Avoid resending stream:error stanzas on terminate (EJAB-1180)
|
||||
- Close also legacy sessions that were half connected (EJAB-1165)
|
||||
- iq_query_info/1 now returns 'invalid' if XMLNS is invalid
|
||||
- New ejabberd_c2s option support: max_fsm_queue
|
||||
- Rewrite mnesia counter functions to use dirty_update_counter (EJAB-1177)
|
||||
- Run user_receive_packet also when sending offline messages (EJAB-1193)
|
||||
- Use p1_fsm behaviour in c2s FSM (EJAB-1173)
|
||||
|
||||
* Clustering
|
||||
- Fix cluster race condition in route read
|
||||
- New command to set master Mnesia node
|
||||
- Use mnesia:async_dirty when cleaning table from failed node
|
||||
|
||||
* Documentation
|
||||
- Add quotes in documentation of some erl arguments (EJAB-1191)
|
||||
- Add option access_from (EJAB-1187)
|
||||
- Add option max_fsm_queue (EJAB-1185)
|
||||
- Fix documentation installation, no need for executable permission (EJAB-1170)
|
||||
- Fix typo in EJABBERD_BIN_PATH (EJAB-891)
|
||||
- Fix typos in example config comments (EJAB-1192)
|
||||
|
||||
* ejabberdctl
|
||||
- Support concurrent connections with bound connection names
|
||||
- Add support for Jot in ctl and TTY in debug
|
||||
- Support help command names with old - characters
|
||||
- Fix to really use the variable ERL_PROCESSES
|
||||
|
||||
* Erlang compatibility
|
||||
- Don't call queue:filter/2 to keep compatibility with older Erlang versions
|
||||
- Use alternative of file:read_line/1 to not require R13B02
|
||||
|
||||
* HTTP
|
||||
- Add new debugging hook to the http receiving process
|
||||
- Allow a request_handler to serve a file in root of HTTP
|
||||
|
||||
* HTTP-Bind (BOSH)
|
||||
- Cross-domain HTTP-Bind support (EJAB-1168)
|
||||
- Hibernate http-bind process after handling a request
|
||||
- Reduce verbosity of HTTP Binding log messages
|
||||
|
||||
* LDAP
|
||||
- Document ldap_dn_filter, fetch only needed attributes in search (EJAB-1204)
|
||||
- Use "%u" pattern as default for ldap_uids (EJAB-1203)
|
||||
|
||||
* Localization
|
||||
- Fix German translation (EJAB-1195)
|
||||
- Fix Russian translation
|
||||
|
||||
* ODBC
|
||||
- Fix MSSQL support, which was broken (EJAB-1201)
|
||||
- Improved SQL reconnect behaviour
|
||||
|
||||
* Pubsub, PEP and Caps
|
||||
- Add extended stanza addressing 'replyto' on PEP (EJAB-1198)
|
||||
- Add pubsub#purge_offline (EJAB-1186)
|
||||
- Fix pubsub#title option (EJAB-1190)
|
||||
- Fix remove_user for node subscriptions (EJAB-1172)
|
||||
- Optimizations in mod_caps
|
||||
|
||||
* Other
|
||||
- mod_register: Add new acl access_from, default is to deny
|
||||
- mod_sic: new module for the experimental XEP-0279 Server IP Check (EJAB-1205)
|
||||
- PIEFXIS: Catch errors when exporting to PIEFXIS file (EJAB-1178)
|
||||
- Proxy65: new option "hostname" (EJAB-838)
|
||||
- Roster: Fix resending authorization problem
|
||||
- Shared Roster Groups: get contacts nickname from vcard (EJAB-114)
|
||||
- S2S: Improved s2s connections clean up (EJAB-1202)
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.4
|
||||
|
||||
ejabberd 2.1.4 is the fourth release in ejabberd 2.1.x branch,
|
||||
and includes many small bugfixes and improvements.
|
||||
|
||||
Read more details about the changes in:
|
||||
http://redir.process-one.net/ejabberd-2.1.4
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
This is the full list of changes:
|
||||
|
||||
* Authentication
|
||||
- Extauth: Optionally cache extauth users in mnesia (EJAB-641)
|
||||
- LDAP: Allow inband password change (EJAB-199)
|
||||
- LDAP: Extensible match support (EJAB-722)
|
||||
- LDAP: New option ldap_tls_verify is added (EJAB-1229)
|
||||
- PAM: New option pam_userinfotype to provide username or JID (EJAB-652)
|
||||
|
||||
* HTTP
|
||||
- Add xml default content type
|
||||
- Don't show HTTP request in logs, because reveals password (EJAB-1231)
|
||||
- Move HTTP session timeout log from warning level to info
|
||||
- New Access rule webadmin_view for read-only
|
||||
|
||||
* HTTP-Bind (BOSH)
|
||||
- Change max inactivity from 30 to 120 seconds
|
||||
- Export functions to facilitate prebinding methods
|
||||
- Use dirty_delete when removing the session
|
||||
- Remove an unneeded delay of 100 milliseconds
|
||||
|
||||
* Pubsub, PEP and Caps
|
||||
- Enforce pubsub#presence_based_delivery (EJAB-1221)
|
||||
- Enforce pubsub#show_values subscription option (EJAB-1096)
|
||||
- Fix error code when unsubscribing from a non-existent node
|
||||
- Fix to send node notifications (EJAB-1225)
|
||||
- Full support for XEP-0115 v1.5 (EJAB-1223)(EJAB-1189)
|
||||
- Make last_item_cache feature to be cluster aware
|
||||
- Prevent orphaned pubsub node (EJAB-1233)
|
||||
- Send created node notifications
|
||||
|
||||
* Other
|
||||
- Bounce messages when closing c2s session
|
||||
- Bugfixes when handling Service Discovery to contacts (EJAB-1207)
|
||||
- Compilation of ejabberd_debug.erl is now optional
|
||||
- Don't send error stanza as reply to error stanza (EJAB-930)
|
||||
- Don't store blocked messages in offline queue
|
||||
- Reduce verbosity of log when captcha_cmd is checked but not configured
|
||||
- Use a standard method to get a random seed (EJAB-1229)
|
||||
- Commands: new update_list and update to update modified modules (EJAB-1237)
|
||||
- Localization: Updated most translations
|
||||
- MUC: Refactor code to reduce calls to get_affiliation and get_role
|
||||
- ODBC: Add created_at column also to PostgreSQL schema
|
||||
- Vcard: Automatic vcard avatar addition in presence
|
||||
|
||||
|
||||
Upgrading From previous ejabberd releases:
|
||||
|
||||
- If you use PostgreSQL, maybe you want to add the column created_at
|
||||
to several tables. This is only a suggestion; ejabberd doesn't use
|
||||
that column. Add it to your existing database executing those SQL
|
||||
statements:
|
||||
|
||||
ALTER TABLE users ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE rosterusers ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE spool ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE vcard ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE privacy_list ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
ALTER TABLE privacy_storage ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT now();
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.5
|
||||
|
||||
ejabberd 2.1.5 is the fifth release in ejabberd 2.1.x branch,
|
||||
and includes several minor bugfixes and a few improvements.
|
||||
|
||||
Read more details about the changes in:
|
||||
http://redir.process-one.net/ejabberd-2.1.4
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
This is the full list of changes:
|
||||
|
||||
* Authentication
|
||||
- Extauth: Support parallel script running (EJAB-1280)
|
||||
- mod_register: Return Registered element when account exists
|
||||
|
||||
* ejabberdctl
|
||||
- Fix print of command result that contains ~
|
||||
- Fix problem when FIREWALL_WINDOW options for erl kernel were used
|
||||
- Fix typo in update_list command (EJAB-1237)
|
||||
- Some systems delete the lock dir; in such case don't use flock at all
|
||||
- The command Update now returns meaningful message and exit-status (EJAB-1237)
|
||||
|
||||
* HTTP-Bind (BOSH)
|
||||
- Don't say v1.2 in the Bind HTTP page
|
||||
- New optional BOSH connection attribute process-delay (EJAB-1257)
|
||||
|
||||
* MUC
|
||||
- Document the mod_muc option captcha_protected
|
||||
- Now admins are able to see private rooms in disco (EJAB-1269)
|
||||
- Show some more room options in the log file
|
||||
|
||||
* ODBC
|
||||
- Correct handling of SQL boolean types (EJAB-1275)
|
||||
- Discard too old queued requests (the caller has already got a timeout)
|
||||
- Fixes wrong SQL escaping when --enable-full-xml is set
|
||||
- Use ets insead of asking supervisor in ejabberd_odbc_sup:get_pids/1
|
||||
|
||||
* Pubsub, PEP and Caps
|
||||
- Enforce disco features results (EJAB-1033, EJAB-1228, EJAB-1238)
|
||||
- Support all the hash functions required by Caps XEP-0115
|
||||
|
||||
* Requirements
|
||||
- Fixed support for Erlang R12; which doesn't support: true andalso ok
|
||||
- Support OTP R14A by using public_key library instead of old ssl (EJAB-953)
|
||||
- Requirement of OpenSSL increased from 0.9.6 to 0.9.8
|
||||
- OpenSSL is now required, not optional
|
||||
|
||||
* Other
|
||||
- Don't ask for client certificate when using tls (EJAB-1267)
|
||||
- Fix typo in --enable-transient_supervisors
|
||||
- Fix privacy check when serving local Last (EJAB-1271)
|
||||
- Inform client that SSL session caching is disabled
|
||||
- New configure option: --enable-nif
|
||||
- Use driver allocator in C files for reflecting memory in erlang:memory(system)
|
||||
- Debug: New p1_prof compiled with: make debugtools=true
|
||||
- Debug: Added functions to collect stats about queues, memory, reductions etc
|
||||
- HTTP: Log error if request has ambiguous Host header (EJAB-1261)
|
||||
- Logs: When logging s2s out connection attempt or success, log if TLS is used
|
||||
- Shared Rosters: When account is deleted, delete also member of stored rosters
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
Release Notes
|
||||
ejabberd 2.1.6
|
||||
|
||||
ejabberd 2.1.6 is the sixth 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.6
|
||||
|
||||
Download the source code and installers from:
|
||||
http://www.process-one.net/en/ejabberd/
|
||||
|
||||
|
||||
Some of the changes are:
|
||||
|
||||
* Account register
|
||||
- mod_register: New ip_access option restricts which IPs can register (EJAB-915)
|
||||
- mod_register: Default configuration allows registrations only from localhost
|
||||
- mod_register: New password_strength for entropy check (EJAB-1326)
|
||||
- mod_register: New captcha_protected option to require CAPTCHA (EJAB-1262)
|
||||
- mod_register_web: New module, with CAPTCHA support (EJAB-471)
|
||||
|
||||
* BOSH
|
||||
- Don't loop when there is nothing after a stream start (EJAB-1358)
|
||||
- Fix http-bind supervisor to support multiple vhosts (EJAB-1321)
|
||||
- Support to restart http-bind (EJAB-1318)
|
||||
- Support for X-Forwarded-For HTTP header (EJAB-1356)
|
||||
|
||||
* Erlang/OTP compatibility
|
||||
- R11: Fix detection of Erlang R11 and older (EJAB-1287)
|
||||
- R12B5: Fix compatibility in ejabberd_http_bind.erl (EJAB-1343)
|
||||
- R14A: Make xml.c correctly compile (EJAB-1288)
|
||||
- R14A, R14B: Disapprove the use of R14A and R14B due to the rwlock bug
|
||||
- R14B: Use pg2 from this version in systems with older ones (EJAB-1349)
|
||||
|
||||
* Listeners
|
||||
- Bind listener ports early and start accepting connections later
|
||||
- Fix a leak of ejabberd_receiver processes
|
||||
- Speed up ejabberd_s2s:is_service/2, allow_host/2 (EJAB-1319)
|
||||
- S2S: New option to require encryption (EJAB-495)
|
||||
- S2S: New option to reject connection if untrusted certificate (EJAB-464)
|
||||
- S2S: Include From attribute in the stream header of outgoing S2S connections
|
||||
- S2S: Fix domain_certfile tlsopts modifications for S2S connections (EJAB-1086)
|
||||
|
||||
* Pubsub/PEP/Caps
|
||||
- Fix pubsub cross domain eventing (EJAB-1340)
|
||||
- Use one_queue IQ discipline by default
|
||||
- Implement lifetime for broken hashes
|
||||
- New CAPS processing
|
||||
|
||||
* ODBC
|
||||
- Increase maximum restart strategy to handle some SQL timeouts
|
||||
- Support PostgreSQL 9.0 (EJAB-1359)
|
||||
- Use MEDIUMTEXT type for vcard avatars in MySQL schema (EJAB-1252)
|
||||
|
||||
* Miscellanea:
|
||||
- mod_shared_roster_ldap: New Shared Roster Groups using LDAP information
|
||||
- mod_privacy: Fix to allow block by group and subscription again
|
||||
- Support timezone West of UTC (EJAB-1301)
|
||||
- Support to change loglevel per module at runtime (EJAB-225)
|
||||
|
||||
|
||||
Bug reports
|
||||
|
||||
You can officially report bugs on ProcessOne support site:
|
||||
http://support.process-one.net/
|
||||
@@ -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/
|
||||
|
||||
@@ -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/
|
||||
@@ -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/
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
% ejabberd version (automatically generated).
|
||||
\newcommand{\version}{2.0.1}
|
||||
\newcommand{\version}{3.0.0}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
%%%
|
||||
%%% ejabberd configuration file
|
||||
%%%
|
||||
%%%'
|
||||
|
||||
%%% The parameters used in this configuration file are explained in more detail
|
||||
%%% in the ejabberd Installation and Operation Guide.
|
||||
%%% Please consult the Guide in case of doubts, it is included in
|
||||
%%% Please consult the Guide in case of doubts, it is included with
|
||||
%%% your copy of ejabberd, and is also available online at
|
||||
%%% http://www.process-one.net/en/ejabberd/docs/
|
||||
|
||||
@@ -16,26 +17,26 @@
|
||||
%%% - Each term ends in a dot, for example:
|
||||
%%% override_global.
|
||||
%%%
|
||||
%%% - A tuple has a fixed definition, its elements are
|
||||
%%% - A tuple has a fixed definition, its elements are
|
||||
%%% enclosed in {}, and separated with commas:
|
||||
%%% {loglevel, 4}.
|
||||
%%%
|
||||
%%% - A list can have as many elements as you want,
|
||||
%%% - A list can have as many elements as you want,
|
||||
%%% and is enclosed in [], for example:
|
||||
%%% [http_poll, web_admin, tls]
|
||||
%%%
|
||||
%%% - A keyword of ejabberd is a word in lowercase.
|
||||
%%% The strings are enclosed in "" and can have spaces, dots...
|
||||
%%% - A keyword of ejabberd is a word in lowercase.
|
||||
%%% Strings are enclosed in "" and can contain spaces, dots, ...
|
||||
%%% {language, "en"}.
|
||||
%%% {ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%% {ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%%
|
||||
%%% - This term includes a tuple, a keyword, a list and two strings:
|
||||
%%% - This term includes a tuple, a keyword, a list, and two strings:
|
||||
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
|
||||
%%%
|
||||
|
||||
|
||||
%%% =======================
|
||||
%%% OVERRIDE STORED OPTIONS
|
||||
%%%. =======================
|
||||
%%%' OVERRIDE STORED OPTIONS
|
||||
|
||||
%%
|
||||
%% Override the old values stored in the database.
|
||||
@@ -57,8 +58,8 @@
|
||||
%%override_acls.
|
||||
|
||||
|
||||
%%% =========
|
||||
%%% DEBUGGING
|
||||
%%%. =========
|
||||
%%%' DEBUGGING
|
||||
|
||||
%%
|
||||
%% loglevel: Verbosity of log files generated by ejabberd.
|
||||
@@ -72,14 +73,15 @@
|
||||
{loglevel, 4}.
|
||||
|
||||
%%
|
||||
%% watchdog_admins: If an ejabberd process consumes too much memory,
|
||||
%% send live notifications to those Jabber accounts.
|
||||
%% watchdog_admins: Only useful for developers: if an ejabberd process
|
||||
%% consumes a lot of memory, send live notifications to these XMPP
|
||||
%% accounts.
|
||||
%%
|
||||
%%{watchdog_admins, ["bob@example.com"]}.
|
||||
|
||||
|
||||
%%% ================
|
||||
%%% SERVED HOSTNAMES
|
||||
%%%. ================
|
||||
%%%' SERVED HOSTNAMES
|
||||
|
||||
%%
|
||||
%% hosts: Domains served by ejabberd.
|
||||
@@ -89,19 +91,19 @@
|
||||
{hosts, ["localhost"]}.
|
||||
|
||||
%%
|
||||
%% route_subdomains: Delegate subdomains to other Jabber server.
|
||||
%% route_subdomains: Delegate subdomains to other XMPP servers.
|
||||
%% For example, if this ejabberd serves example.org and you want
|
||||
%% to allow communication with a Jabber server called im.example.org.
|
||||
%% to allow communication with an XMPP server called im.example.org.
|
||||
%%
|
||||
%%{route_subdomains, s2s}.
|
||||
|
||||
|
||||
%%% ===============
|
||||
%%% LISTENING PORTS
|
||||
%%%. ===============
|
||||
%%%' LISTENING PORTS
|
||||
|
||||
%%
|
||||
%% listen: Which ports will ejabberd listen, which service handles it
|
||||
%% and what options to start it with.
|
||||
%% listen: The ports ejabberd will listen on, which service each is handled
|
||||
%% by and what options to start it with.
|
||||
%%
|
||||
{listen,
|
||||
[
|
||||
@@ -109,8 +111,8 @@
|
||||
{5222, ejabberd_c2s, [
|
||||
|
||||
%%
|
||||
%% If TLS is compiled and you installed a SSL
|
||||
%% certificate, put the correct path to the
|
||||
%% If TLS is compiled in and you installed a SSL
|
||||
%% certificate, specify the full path to the
|
||||
%% file and uncomment this line:
|
||||
%%
|
||||
%%{certfile, "/path/to/ssl.pem"}, starttls,
|
||||
@@ -121,7 +123,7 @@
|
||||
]},
|
||||
|
||||
%%
|
||||
%% To enable the old SSL connection method in port 5223:
|
||||
%% To enable the old SSL connection method on port 5223:
|
||||
%%
|
||||
%%{5223, ejabberd_c2s, [
|
||||
%% {access, c2s},
|
||||
@@ -136,10 +138,10 @@
|
||||
]},
|
||||
|
||||
%%
|
||||
%% ejabberd_service: Interact with external components (transports...)
|
||||
%% ejabberd_service: Interact with external components (transports, ...)
|
||||
%%
|
||||
%%{8888, ejabberd_service, [
|
||||
%% {access, all},
|
||||
%% {access, all},
|
||||
%% {shaper_rule, fast},
|
||||
%% {ip, {127, 0, 0, 1}},
|
||||
%% {hosts, ["icq.example.org", "sms.example.org"],
|
||||
@@ -147,8 +149,27 @@
|
||||
%% }
|
||||
%% ]},
|
||||
|
||||
%%
|
||||
%% ejabberd_stun: Handles STUN Binding requests
|
||||
%%
|
||||
%%{{3478, udp}, ejabberd_stun, []},
|
||||
|
||||
%%
|
||||
%% To handle XML-RPC requests that provide admin credentials:
|
||||
%%
|
||||
%%{4560, ejabberd_xmlrpc, [
|
||||
%% {access_commands, [{admin, all, []}]}
|
||||
%% ]},
|
||||
|
||||
{5280, ejabberd_http, [
|
||||
http_poll,
|
||||
%%{request_handlers,
|
||||
%% [
|
||||
%% {["pub", "archive"], mod_http_fileserver}
|
||||
%% ]},
|
||||
captcha,
|
||||
http_bind,
|
||||
http_poll,
|
||||
%%register,
|
||||
web_admin
|
||||
]}
|
||||
|
||||
@@ -156,10 +177,10 @@
|
||||
|
||||
%%
|
||||
%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
|
||||
%% Allowed values are: true or false.
|
||||
%% Allowed values are: false optional required required_trusted
|
||||
%% You must specify a certificate file.
|
||||
%%
|
||||
%%{s2s_use_starttls, true}.
|
||||
%%{s2s_use_starttls, optional}.
|
||||
|
||||
%%
|
||||
%% s2s_certfile: Specify a certificate file.
|
||||
@@ -185,17 +206,32 @@
|
||||
%%{{s2s_host, "goodhost.org"}, allow}.
|
||||
%%{{s2s_host, "badhost.org"}, deny}.
|
||||
|
||||
%%
|
||||
%% Outgoing S2S options
|
||||
%%
|
||||
%% Preferred address families (which to try first) and connect timeout
|
||||
%% in milliseconds.
|
||||
%%
|
||||
%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
|
||||
|
||||
%%% ==============
|
||||
%%% AUTHENTICATION
|
||||
|
||||
%%%. ==============
|
||||
%%%' AUTHENTICATION
|
||||
|
||||
%%
|
||||
%% auth_method: Method used to authenticate the users.
|
||||
%% The default method is the internal.
|
||||
%% If you want to use a different method,
|
||||
%% If you want to use a different method,
|
||||
%% comment this line and enable the correct ones.
|
||||
%%
|
||||
{auth_method, internal}.
|
||||
%%
|
||||
%% Store the plain passwords or hashed for SCRAM:
|
||||
%%{auth_password_format, plain}.
|
||||
%%{auth_password_format, scram}.
|
||||
%%
|
||||
%% Define the FQDN if ejabberd doesn't detect it:
|
||||
%%{fqdn, "server3.example.com"}.
|
||||
|
||||
%%
|
||||
%% Authentication using external script
|
||||
@@ -222,19 +258,30 @@
|
||||
%%{auth_method, ldap}.
|
||||
%%
|
||||
%% List of LDAP servers:
|
||||
%%{ldap_servers, ["localhost"]}.
|
||||
%%{ldap_servers, ["localhost"]}.
|
||||
%%
|
||||
%% LDAP attribute that holds user ID:
|
||||
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
|
||||
%% Encryption of connection to LDAP servers:
|
||||
%%{ldap_encrypt, none}.
|
||||
%%{ldap_encrypt, tls}.
|
||||
%%
|
||||
%% Search base of LDAP directory:
|
||||
%%{ldap_base, "dc=example,dc=com"}.
|
||||
%% Port to connect to on LDAP servers:
|
||||
%%{ldap_port, 389}.
|
||||
%%{ldap_port, 636}.
|
||||
%%
|
||||
%% LDAP manager:
|
||||
%%{ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%{ldap_rootdn, "dc=example,dc=com"}.
|
||||
%%
|
||||
%% Password to LDAP manager:
|
||||
%%{ldap_password, "******"}.
|
||||
%% Password of LDAP manager:
|
||||
%%{ldap_password, "******"}.
|
||||
%%
|
||||
%% Search base of LDAP directory:
|
||||
%%{ldap_base, "dc=example,dc=com"}.
|
||||
%%
|
||||
%% LDAP attribute that holds user ID:
|
||||
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
|
||||
%%
|
||||
%% LDAP filter:
|
||||
%%{ldap_filter, "(objectClass=shadowAccount)"}.
|
||||
|
||||
%%
|
||||
%% Anonymous login support:
|
||||
@@ -251,14 +298,14 @@
|
||||
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
|
||||
|
||||
|
||||
%%% ==============
|
||||
%%% DATABASE SETUP
|
||||
%%%. ==============
|
||||
%%%' DATABASE SETUP
|
||||
|
||||
%% ejabberd uses by default the internal Mnesia database,
|
||||
%% so you can avoid this section.
|
||||
%% ejabberd by default uses the internal Mnesia database,
|
||||
%% so you do not necessarily need this section.
|
||||
%% This section provides configuration examples in case
|
||||
%% you want to use other database backends.
|
||||
%% Please consult the ejabberd Guide for details about database creation.
|
||||
%% Please consult the ejabberd Guide for details on database creation.
|
||||
|
||||
%%
|
||||
%% MySQL server:
|
||||
@@ -292,32 +339,38 @@
|
||||
%%{odbc_pool_size, 10}.
|
||||
|
||||
%%
|
||||
%% Interval to make a dummy SQL request to keep alive the connections
|
||||
%% to the database. Specify in seconds: for example 28800 means 8 hours
|
||||
%% Interval to make a dummy SQL request to keep the connections to the
|
||||
%% database alive. Specify in seconds: for example 28800 means 8 hours
|
||||
%%
|
||||
%%{odbc_keepalive_interval, undefined}.
|
||||
|
||||
|
||||
%%% ===============
|
||||
%%% TRAFFIC SHAPERS
|
||||
%%%. ===============
|
||||
%%%' TRAFFIC SHAPERS
|
||||
|
||||
%%
|
||||
%% The "normal" shaper limits traffic speed to 1.000 B/s
|
||||
%% The "normal" shaper limits traffic speed to 1000 B/s
|
||||
%%
|
||||
{shaper, normal, {maxrate, 1000}}.
|
||||
|
||||
%%
|
||||
%% The "fast" shaper limits traffic speed to 50.000 B/s
|
||||
%% The "fast" shaper limits traffic speed to 50000 B/s
|
||||
%%
|
||||
{shaper, fast, {maxrate, 50000}}.
|
||||
|
||||
%%
|
||||
%% This option specifies the maximum number of elements in the queue
|
||||
%% of the FSM. Refer to the documentation for details.
|
||||
%%
|
||||
{max_fsm_queue, 1000}.
|
||||
|
||||
%%% ====================
|
||||
%%% ACCESS CONTROL LISTS
|
||||
|
||||
%%%. ====================
|
||||
%%%' ACCESS CONTROL LISTS
|
||||
|
||||
%%
|
||||
%% The 'admin' ACL grants administrative privileges to Jabber accounts.
|
||||
%% You can put as many accounts as you want.
|
||||
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
|
||||
%% You can put here as many accounts as you want.
|
||||
%%
|
||||
%%{acl, admin, {user, "aleksey", "localhost"}}.
|
||||
%%{acl, admin, {user, "ermine", "example.org"}}.
|
||||
@@ -351,12 +404,15 @@
|
||||
%%}.
|
||||
|
||||
|
||||
%%% ============
|
||||
%%% ACCESS RULES
|
||||
%%%. ============
|
||||
%%%' ACCESS RULES
|
||||
|
||||
%% Maximum number of simultaneous sessions allowed for a single user:
|
||||
{access, max_user_sessions, [{10, all}]}.
|
||||
|
||||
%% Maximum number of offline messages that users can have:
|
||||
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
|
||||
|
||||
%% This rule allows access only for local users:
|
||||
{access, local, [{allow, local}]}.
|
||||
|
||||
@@ -364,34 +420,41 @@
|
||||
{access, c2s, [{deny, blocked},
|
||||
{allow, all}]}.
|
||||
|
||||
%% For C2S connections, all users except admins use "normal" shaper
|
||||
%% For C2S connections, all users except admins use the "normal" shaper
|
||||
{access, c2s_shaper, [{none, admin},
|
||||
{normal, all}]}.
|
||||
|
||||
%% All S2S connections use "fast" shaper
|
||||
%% All S2S connections use the "fast" shaper
|
||||
{access, s2s_shaper, [{fast, all}]}.
|
||||
|
||||
%% Only admins can send announcement messages:
|
||||
{access, announce, [{allow, admin}]}.
|
||||
|
||||
%% Only admins can use configuration interface:
|
||||
%% Only admins can use the configuration interface:
|
||||
{access, configure, [{allow, admin}]}.
|
||||
|
||||
%% Admins of this server are also admins of MUC service:
|
||||
%% Admins of this server are also admins of the MUC service:
|
||||
{access, muc_admin, [{allow, admin}]}.
|
||||
|
||||
%% All users are allowed to use MUC service:
|
||||
%% Only accounts of the local ejabberd server can create rooms:
|
||||
{access, muc_create, [{allow, local}]}.
|
||||
|
||||
%% All users are allowed to use the MUC service:
|
||||
{access, muc, [{allow, all}]}.
|
||||
|
||||
%% Only accounts on the local ejabberd server can create Pubsub nodes:
|
||||
{access, pubsub_createnode, [{allow, local}]}.
|
||||
|
||||
%% In-band registration allows registration of any possible username.
|
||||
%% To disable in-band registration, replace 'allow' with 'deny'.
|
||||
{access, register, [{allow, all}]}.
|
||||
|
||||
%% Everybody can create pubsub nodes
|
||||
{access, pubsub_createnode, [{allow, all}]}.
|
||||
%% By default the frequency of account registrations from the same IP
|
||||
%% is limited to 1 account every 10 minutes. To disable, specify: infinity
|
||||
%%{registration_timeout, 600}.
|
||||
|
||||
%%
|
||||
%% Define specific Access rules in a virtual host.
|
||||
%% Define specific Access Rules in a virtual host.
|
||||
%%
|
||||
%%{host_config, "localhost",
|
||||
%% [
|
||||
@@ -401,8 +464,8 @@
|
||||
%%}.
|
||||
|
||||
|
||||
%%% ================
|
||||
%%% DEFAULT LANGUAGE
|
||||
%%%. ================
|
||||
%%%' DEFAULT LANGUAGE
|
||||
|
||||
%%
|
||||
%% language: Default language used for server messages.
|
||||
@@ -417,8 +480,26 @@
|
||||
%%}.
|
||||
|
||||
|
||||
%%% =======
|
||||
%%% MODULES
|
||||
%%%. =======
|
||||
%%%' 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"}.
|
||||
|
||||
%%
|
||||
%% Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
|
||||
%%
|
||||
%%{captcha_limit, 5}.
|
||||
|
||||
%%%. =======
|
||||
%%%' MODULES
|
||||
|
||||
%%
|
||||
%% Modules enabled in all ejabberd virtual hosts.
|
||||
@@ -427,44 +508,83 @@
|
||||
[
|
||||
{mod_adhoc, []},
|
||||
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
|
||||
{mod_caps, []},
|
||||
{mod_blocking,[]}, % requires mod_privacy
|
||||
{mod_caps, []},
|
||||
{mod_configure,[]}, % requires mod_adhoc
|
||||
{mod_disco, []},
|
||||
%%{mod_echo, [{host, "echo.localhost"}]},
|
||||
{mod_irc, []},
|
||||
{mod_http_bind, []},
|
||||
%%{mod_http_fileserver, [
|
||||
%% {docroot, "/var/www"},
|
||||
%% {accesslog, "/var/log/ejabberd/access.log"}
|
||||
%% ]},
|
||||
{mod_last, []},
|
||||
{mod_muc, [
|
||||
%%{host, "conference.@HOST@"},
|
||||
{access, muc},
|
||||
{access_create, muc},
|
||||
{access_persistent, muc},
|
||||
{access_create, muc_create},
|
||||
{access_persistent, muc_create},
|
||||
{access_admin, muc_admin}
|
||||
]},
|
||||
%%{mod_muc_log,[]},
|
||||
{mod_offline, []},
|
||||
{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, [ % requires mod_caps
|
||||
{mod_pubsub, [
|
||||
{access_createnode, pubsub_createnode},
|
||||
{plugins, ["default", "pep"]}
|
||||
{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, [
|
||||
%%
|
||||
%% After successful registration, the user receives
|
||||
%% a message with this subject and body.
|
||||
%% Protect In-Band account registrations with CAPTCHA.
|
||||
%%
|
||||
{welcome_message, {"Welcome!",
|
||||
"Welcome to this Jabber server."}},
|
||||
%%{captcha_protected, true},
|
||||
|
||||
%%
|
||||
%% When a user registers, send a notification to
|
||||
%% these Jabber accounts.
|
||||
%% Set the minimum informational entropy for passwords.
|
||||
%%
|
||||
%%{password_strength, 32},
|
||||
|
||||
%%
|
||||
%% After successful registration, the user receives
|
||||
%% a message with this subject and body.
|
||||
%%
|
||||
{welcome_message, {"Welcome!",
|
||||
"Hi.\nWelcome to this XMPP server."}},
|
||||
|
||||
%%
|
||||
%% When a user registers, send a notification to
|
||||
%% these XMPP accounts.
|
||||
%%
|
||||
%%{registration_watchers, ["admin1@example.org"]},
|
||||
|
||||
%%
|
||||
%% Only clients in the server machine can register accounts
|
||||
%%
|
||||
{ip_access, [{allow, "127.0.0.0/8"},
|
||||
{deny, "0.0.0.0/0"}]},
|
||||
|
||||
%%
|
||||
%% Local c2s or remote s2s users cannot register accounts
|
||||
%%
|
||||
%%{access_from, deny},
|
||||
|
||||
{access, register}
|
||||
]},
|
||||
%%{mod_register_web, [
|
||||
%%
|
||||
%% When a user registers, send a notification to
|
||||
%% these XMPP accounts.
|
||||
%%
|
||||
%%{registration_watchers, ["admin1@example.org"]}
|
||||
%% ]},
|
||||
{mod_roster, []},
|
||||
%%{mod_service_log,[]},
|
||||
{mod_shared_roster,[]},
|
||||
@@ -486,9 +606,12 @@
|
||||
%% ]}.
|
||||
|
||||
|
||||
%%%.
|
||||
%%%'
|
||||
|
||||
%%% $Id$
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: erlang
|
||||
%%% End:
|
||||
%%% vim: set filetype=erlang tabstop=8:
|
||||
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker:
|
||||
@@ -0,0 +1,63 @@
|
||||
#! /bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: ejabberd
|
||||
# Required-Start: $remote_fs $network $named $time
|
||||
# Required-Stop: $remote_fs $network $named $time
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Starts ejabberd jabber server
|
||||
# Description: Starts ejabberd jabber server, an XMPP
|
||||
# compliant server written in Erlang.
|
||||
### END INIT INFO
|
||||
|
||||
# chkconfig: 2345 90 10
|
||||
# description: ejabberd XMPP server
|
||||
|
||||
set -o errexit
|
||||
|
||||
DIR=@ctlscriptpath@
|
||||
CTL="$DIR"/ejabberdctl
|
||||
USER=@installuser@
|
||||
|
||||
test -x "$CTL" || {
|
||||
echo "ERROR: ejabberd not found: $DIR"
|
||||
exit 1
|
||||
}
|
||||
grep ^"$USER": /etc/passwd >/dev/null || {
|
||||
echo "ERROR: System user not found: $USER"
|
||||
exit 2
|
||||
}
|
||||
|
||||
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
test -x "$CTL" || exit 0
|
||||
echo "Starting ejabberd..."
|
||||
su - $USER -c "$CTL start"
|
||||
su - $USER -c "$CTL started"
|
||||
echo "done."
|
||||
;;
|
||||
stop)
|
||||
test -x "$CTL" || exit 0
|
||||
echo "Stopping ejabberd..."
|
||||
su - $USER -c "$CTL stop"
|
||||
su - $USER -c "$CTL stopped"
|
||||
echo "done."
|
||||
;;
|
||||
status)
|
||||
test -x "$CTL" || exit 0
|
||||
echo "Getting ejabberd status..."
|
||||
su - $USER -c "$CTL status"
|
||||
;;
|
||||
force-reload|restart)
|
||||
"$0" stop
|
||||
"$0" start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|force-reload|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,154 @@
|
||||
#
|
||||
# In this file you can configure options that are passed by ejabberdctl
|
||||
# to the erlang runtime system when starting ejabberd
|
||||
#
|
||||
|
||||
#' POLL: Kernel polling ([true|false])
|
||||
#
|
||||
# The kernel polling option requires support in the kernel.
|
||||
# Additionally, you need to enable this feature while compiling Erlang.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
#POLL=true
|
||||
|
||||
#.
|
||||
#' SMP: SMP support ([enable|auto|disable])
|
||||
#
|
||||
# Explanation in Erlang/OTP documentation:
|
||||
# enable: starts the Erlang runtime system with SMP support enabled.
|
||||
# This may fail if no runtime system with SMP support is available.
|
||||
# auto: starts the Erlang runtime system with SMP support enabled if it
|
||||
# is available and more than one logical processor are detected.
|
||||
# disable: starts a runtime system without SMP support.
|
||||
#
|
||||
# Default: auto
|
||||
#
|
||||
#SMP=auto
|
||||
|
||||
#.
|
||||
#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
|
||||
#
|
||||
# ejabberd consumes two or three ports for every connection, either
|
||||
# from a client or from another Jabber server. So take this into
|
||||
# account when setting this limit.
|
||||
#
|
||||
# Default: 32000
|
||||
# Maximum: 268435456
|
||||
#
|
||||
#ERL_MAX_PORTS=32000
|
||||
|
||||
#.
|
||||
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
|
||||
#
|
||||
# If Ejabberd is configured to run in cluster, and a firewall is blocking ports,
|
||||
# it's possible to make Erlang use a defined range of port (instead of dynamic
|
||||
# ports) for node communication.
|
||||
#
|
||||
# Default: not defined
|
||||
# Example: 4200-4210
|
||||
#
|
||||
#FIREWALL_WINDOW=
|
||||
|
||||
#.
|
||||
#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes
|
||||
#
|
||||
# This communication is used by ejabberdctl command line tool,
|
||||
# and in a cluster of several ejabberd nodes.
|
||||
# Notice that the IP address must be specified in the Erlang syntax.
|
||||
#
|
||||
# Default: {127,0,0,1}
|
||||
#
|
||||
INET_DIST_INTERFACE={127,0,0,1}
|
||||
|
||||
#.
|
||||
#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
|
||||
#
|
||||
# IMPORTANT: This option works only in Erlang/OTP R14B03 and newer.
|
||||
#
|
||||
# This environment variable may be set to a comma-separated
|
||||
# list of IP addresses, in which case the epmd daemon
|
||||
# will listen only on the specified address(es) and on the
|
||||
# loopback address (which is implicitly added to the list if it
|
||||
# has not been specified). The default behaviour is to listen on
|
||||
# all available IP addresses.
|
||||
#
|
||||
# Default: 0.0.0.0
|
||||
#
|
||||
#ERL_EPMD_ADDRESS=127.0.0.1
|
||||
|
||||
#.
|
||||
#' ERL_PROCESSES: Maximum number of Erlang processes
|
||||
#
|
||||
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
|
||||
# on ejabberd so that the maximum number of processes is reached, people will
|
||||
# experience greater latency times. As these processes are implemented in
|
||||
# Erlang, and therefore not related to the operating system processes, you do
|
||||
# not have to worry about allowing a huge number of them.
|
||||
#
|
||||
# Default: 250000
|
||||
# Maximum: 268435456
|
||||
#
|
||||
#ERL_PROCESSES=250000
|
||||
|
||||
#.
|
||||
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
|
||||
#
|
||||
# The number of concurrent ETS and Mnesia tables is limited. When the limit is
|
||||
# reached, errors will appear in the logs:
|
||||
# ** Too many db tables **
|
||||
# You can safely increase this limit when starting ejabberd. It impacts memory
|
||||
# consumption but the difference will be quite small.
|
||||
#
|
||||
# Default: 1400
|
||||
#
|
||||
#ERL_MAX_ETS_TABLES=1400
|
||||
|
||||
#.
|
||||
#' ERL_OPTIONS: Additional Erlang options
|
||||
#
|
||||
# The next variable allows to specify additional options passed to erlang while
|
||||
# starting ejabberd. Some useful options are -noshell, -detached, -heart. When
|
||||
# ejabberd is started from an init.d script options -noshell and -detached are
|
||||
# added implicitly. See erl(1) for more info.
|
||||
#
|
||||
# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you
|
||||
# want to add local modules in this path.
|
||||
#
|
||||
# Default: ""
|
||||
#
|
||||
#ERL_OPTIONS=""
|
||||
|
||||
#.
|
||||
#' ERLANG_NODE: Erlang node name
|
||||
#
|
||||
# The next variable allows to explicitly specify erlang node for ejabberd
|
||||
# It can be given in different formats:
|
||||
# ERLANG_NODE=ejabberd
|
||||
# Lets erlang add hostname to the node (ejabberd uses short name in this case)
|
||||
# ERLANG_NODE=ejabberd@hostname
|
||||
# Erlang uses node name as is (so make sure that hostname is a real
|
||||
# machine hostname or you'll not be able to control ejabberd)
|
||||
# ERLANG_NODE=ejabberd@hostname.domainname
|
||||
# The same as previous, but erlang will use long hostname
|
||||
# (see erl (1) manual for details)
|
||||
#
|
||||
# Default: ejabberd@localhost
|
||||
#
|
||||
#ERLANG_NODE=ejabberd@localhost
|
||||
|
||||
#.
|
||||
#' EJABBERD_PID_PATH: ejabberd PID file
|
||||
#
|
||||
# Indicate the full path to the ejabberd Process identifier (PID) file.
|
||||
# If this variable is defined, ejabberd writes the PID file when starts,
|
||||
# and deletes it when stops.
|
||||
# Remember to create the directory and grant write permission to ejabberd.
|
||||
#
|
||||
# Default: don't write PID file
|
||||
#
|
||||
#EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid
|
||||
|
||||
#.
|
||||
#'
|
||||
# vim: foldmarker=#',#. foldmethod=marker:
|
||||
Executable
+411
@@ -0,0 +1,411 @@
|
||||
#!/bin/sh
|
||||
|
||||
# define default configuration
|
||||
POLL=true
|
||||
SMP=auto
|
||||
ERL_MAX_PORTS=32000
|
||||
ERL_PROCESSES=250000
|
||||
ERL_MAX_ETS_TABLES=1400
|
||||
|
||||
SCRIPT_DIR=$(cd ${0%/*} && pwd)
|
||||
|
||||
# define default environment variables
|
||||
NODE=ejabberd
|
||||
HOST=localhost
|
||||
ERLANG_NODE=$NODE@$HOST
|
||||
ERL={{erl}}
|
||||
INSTALLUSER={{installuser}}
|
||||
|
||||
# parse command line parameters
|
||||
ARGS=
|
||||
while [ $# -ne 0 ] ; do
|
||||
PARAM=$1
|
||||
shift
|
||||
case $PARAM in
|
||||
--) break ;;
|
||||
--node) ERLANG_NODE_ARG=$1; shift ;;
|
||||
--config-dir) ETCDIR=$1 ; shift ;;
|
||||
--config) EJABBERD_CONFIG_PATH=$1 ; shift ;;
|
||||
--ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;;
|
||||
--logs) LOGS_DIR=$1 ; shift ;;
|
||||
--spool) SPOOLDIR=$1 ; shift ;;
|
||||
*) ARGS="$ARGS $PARAM" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Define ejabberd variable if they have not been defined from the command line
|
||||
if [ "$ETCDIR" = "" ] ; then
|
||||
ETCDIR={{sysconfdir}}/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
|
||||
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
|
||||
fi
|
||||
if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then
|
||||
EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg
|
||||
fi
|
||||
if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then
|
||||
. "$EJABBERDCTL_CONFIG_PATH"
|
||||
fi
|
||||
if [ "$LOGS_DIR" = "" ] ; then
|
||||
LOGS_DIR={{localstatedir}}/log/ejabberd
|
||||
fi
|
||||
if [ "$SPOOLDIR" = "" ] ; then
|
||||
SPOOLDIR={{localstatedir}}/lib/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_DOC_PATH" = "" ] ; then
|
||||
EJABBERD_DOC_PATH={{docdir}}
|
||||
fi
|
||||
if [ "$ERLANG_NODE_ARG" != "" ] ; then
|
||||
ERLANG_NODE=$ERLANG_NODE_ARG
|
||||
NODE=${ERLANG_NODE%@*}
|
||||
fi
|
||||
|
||||
# check the proper system user is used
|
||||
ID=`id -g`
|
||||
GIDS=`id -G`
|
||||
EJID=`id -g $INSTALLUSER`
|
||||
EXEC_CMD="false"
|
||||
for GID in $GIDS; do
|
||||
if [ $GID -eq 0 ] ; then
|
||||
EXEC_CMD="su ${INSTALLUSER} -p -c"
|
||||
fi
|
||||
done
|
||||
if [ "$ID" -eq "$EJID" ] ; then
|
||||
EXEC_CMD="sh -c"
|
||||
fi
|
||||
if [ "$EXEC_CMD" = "false" ] ; then
|
||||
echo "This command can only be run by root or the user $INSTALLUSER" >&2
|
||||
exit 4
|
||||
fi
|
||||
|
||||
NAME=-name
|
||||
if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then
|
||||
NAME=-sname
|
||||
fi
|
||||
|
||||
KERNEL_OPTS=""
|
||||
if [ "$FIREWALL_WINDOW" != "" ] ; then
|
||||
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
|
||||
fi
|
||||
if [ "$INET_DIST_INTERFACE" != "" ] ; then
|
||||
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE}\""
|
||||
fi
|
||||
|
||||
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
|
||||
|
||||
# define additional environment variables
|
||||
if [ "{{release}}" != "true" ] ; then
|
||||
if [ "$EJABBERDDIR" = "" ] ; then
|
||||
EJABBERDDIR={{libdir}}/ejabberd
|
||||
fi
|
||||
if [ "$EJABBERD_EBIN_PATH" = "" ] ; then
|
||||
EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin
|
||||
fi
|
||||
if [ "$EJABBERD_PRIV_PATH" = "" ] ; then
|
||||
EJABBERD_PRIV_PATH=$EJABBERDDIR/priv
|
||||
fi
|
||||
if [ "$EJABBERD_BIN_PATH" = "" ] ; then
|
||||
EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin
|
||||
fi
|
||||
if [ "$EJABBERD_SO_PATH" = "" ] ; then
|
||||
EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib
|
||||
fi
|
||||
if [ "$EJABBERD_MSGS_PATH" = "" ] ; then
|
||||
EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs
|
||||
fi
|
||||
fi
|
||||
|
||||
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
|
||||
SASL_LOG_PATH=$LOGS_DIR/erlang.log
|
||||
DATETIME=`date "+%Y%m%d-%H%M%S"`
|
||||
ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump
|
||||
ERL_INETRC=$ETCDIR/inetrc
|
||||
HOME=$SPOOLDIR
|
||||
|
||||
# create the home dir with the proper user if doesn't exist, because it stores cookie file
|
||||
[ -d $HOME ] || $EXEC_CMD "mkdir -p $HOME"
|
||||
|
||||
# Change to a directory readable by INSTALLUSER to
|
||||
# prevent "File operation error: eacces." messages
|
||||
cd $HOME
|
||||
|
||||
# export global variables
|
||||
export EJABBERD_CONFIG_PATH
|
||||
export EJABBERD_MSGS_PATH
|
||||
export EJABBERD_LOG_PATH
|
||||
export EJABBERD_SO_PATH
|
||||
export EJABBERD_BIN_PATH
|
||||
export EJABBERD_DOC_PATH
|
||||
export EJABBERD_PID_PATH
|
||||
export ERL_CRASH_DUMP
|
||||
export ERL_EPMD_ADDRESS
|
||||
export ERL_INETRC
|
||||
export ERL_MAX_PORTS
|
||||
export ERL_MAX_ETS_TABLES
|
||||
export HOME
|
||||
export EXEC_CMD
|
||||
|
||||
|
||||
# Compatibility in ZSH
|
||||
#setopt shwordsplit 2>/dev/null
|
||||
|
||||
# start server
|
||||
start ()
|
||||
{
|
||||
check_start
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME $ERLANG_NODE \
|
||||
-noinput -detached \
|
||||
-pa $EJABBERD_EBIN_PATH \
|
||||
-mnesia dir \"\\\"$SPOOLDIR\\\"\" \
|
||||
$KERNEL_OPTS \
|
||||
-s ejabberd \
|
||||
-sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \
|
||||
$ERLANG_OPTS $ARGS \"$@\""
|
||||
}
|
||||
|
||||
# attach to server
|
||||
debug ()
|
||||
{
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo ""
|
||||
echo "IMPORTANT: we will attempt to attach an INTERACTIVE shell"
|
||||
echo "to an already running ejabberd node."
|
||||
echo "If an ERROR is printed, it means the connection was not successful."
|
||||
echo "You can interact with the ejabberd node if you know how to use it."
|
||||
echo "Please be extremely cautious with your actions,"
|
||||
echo "and exit immediately if you are not completely sure."
|
||||
echo ""
|
||||
echo "To detach this shell from ejabberd, press:"
|
||||
echo " control+c, control+c"
|
||||
echo ""
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
fi
|
||||
echo ""
|
||||
TTY=`tty | sed -e 's/.*\///g'`
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME debug-${TTY}-${ERLANG_NODE} \
|
||||
-remsh $ERLANG_NODE \
|
||||
-hidden \
|
||||
$KERNEL_OPTS \
|
||||
$ERLANG_OPTS $ARGS \"$@\""
|
||||
}
|
||||
|
||||
# start interactive server
|
||||
live ()
|
||||
{
|
||||
check_start
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo ""
|
||||
echo "IMPORTANT: ejabberd is going to start in LIVE (interactive) mode."
|
||||
echo "All log messages will be shown in the command shell."
|
||||
echo "You can interact with the ejabberd node if you know how to use it."
|
||||
echo "Please be extremely cautious with your actions,"
|
||||
echo "and exit immediately if you are not completely sure."
|
||||
echo ""
|
||||
echo "To exit this LIVE mode and stop ejabberd, press:"
|
||||
echo " q(). and press the Enter key"
|
||||
echo ""
|
||||
echo "--------------------------------------------------------------------"
|
||||
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
|
||||
echo " EJABBERD_BYPASS_WARNINGS=true"
|
||||
echo "Press any key to continue"
|
||||
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
|
||||
read foo
|
||||
fi
|
||||
echo ""
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME $ERLANG_NODE \
|
||||
-pa $EJABBERD_EBIN_PATH \
|
||||
-mnesia dir \"\\\"$SPOOLDIR\\\"\" \
|
||||
$KERNEL_OPTS \
|
||||
-s ejabberd \
|
||||
$ERLANG_OPTS $ARGS \"$@\""
|
||||
}
|
||||
|
||||
etop()
|
||||
{
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME debug-${TTY}-${ERLANG_NODE} \
|
||||
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
|
||||
}
|
||||
|
||||
help ()
|
||||
{
|
||||
echo ""
|
||||
echo "Commands to start an ejabberd node:"
|
||||
echo " start Start an ejabberd node in server mode"
|
||||
echo " debug Attach an interactive Erlang shell to a running ejabberd node"
|
||||
echo " live Start an ejabberd node in live (interactive) mode"
|
||||
echo ""
|
||||
echo "Optional parameters when starting an ejabberd node:"
|
||||
echo " --config-dir dir Config ejabberd: $ETCDIR"
|
||||
echo " --config file Config ejabberd: $EJABBERD_CONFIG_PATH"
|
||||
echo " --ctl-config file Config ejabberdctl: $EJABBERDCTL_CONFIG_PATH"
|
||||
echo " --logs dir Directory for logs: $LOGS_DIR"
|
||||
echo " --spool dir Database spool dir: $SPOOLDIR"
|
||||
echo " --node nodename ejabberd node name: $ERLANG_NODE"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# common control function
|
||||
ctl ()
|
||||
{
|
||||
COMMAND=$@
|
||||
|
||||
# Control number of connections identifiers
|
||||
# using flock if available. Expects a linux-style
|
||||
# flock that can lock a file descriptor.
|
||||
MAXCONNID=100
|
||||
CONNLOCKDIR={{localstatedir}}/lock/ejabberdctl
|
||||
FLOCK='/usr/bin/flock'
|
||||
if [ ! -x "$FLOCK" ] || [ ! -d "$CONNLOCKDIR" ] ; then
|
||||
JOT='/usr/bin/jot'
|
||||
if [ ! -x "$JOT" ] ; then
|
||||
# no flock or jot, simply invoke ctlexec()
|
||||
CTL_CONN="ctl-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
else
|
||||
# no flock, but at least there is jot
|
||||
RAND=`jot -r 1 0 $MAXCONNID`
|
||||
CTL_CONN="ctl-${RAND}-${ERLANG_NODE}"
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
result=$?
|
||||
fi
|
||||
else
|
||||
# we have flock so we get a lock
|
||||
# on one of a limited number of
|
||||
# conn names -- this allows
|
||||
# concurrent invocations using a bound
|
||||
# number of atoms
|
||||
for N in $(seq 1 $MAXCONNID); do
|
||||
CTL_CONN="ejabberdctl-$N"
|
||||
CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN"
|
||||
(
|
||||
exec 8>"$CTL_LOCKFILE"
|
||||
if flock --nb 8; then
|
||||
ctlexec $CTL_CONN $COMMAND
|
||||
ssresult=$?
|
||||
# segregate from possible flock exit(1)
|
||||
ssresult=$(expr $ssresult \* 10)
|
||||
exit $ssresult
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
)
|
||||
result=$?
|
||||
if [ $result -eq 1 ] ; then
|
||||
# means we errored out in flock
|
||||
# rather than in the exec - stay in the loop
|
||||
# trying other conn names...
|
||||
badlock=1
|
||||
else
|
||||
badlock=""
|
||||
break;
|
||||
fi
|
||||
done
|
||||
result=$(expr $result / 10)
|
||||
fi
|
||||
|
||||
if [ "$badlock" ] ;then
|
||||
echo "Ran out of connections to try. Your ejabberd processes" >&2
|
||||
echo "may be stuck or this is a very busy server. For very" >&2
|
||||
echo "busy servers, consider raising MAXCONNID in ejabberdctl">&2
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
case $result in
|
||||
0) :;;
|
||||
1) :;;
|
||||
2) help;;
|
||||
3) help;;
|
||||
esac
|
||||
return $result
|
||||
}
|
||||
|
||||
ctlexec ()
|
||||
{
|
||||
CONN_NAME=$1; shift
|
||||
COMMAND=$@
|
||||
$EXEC_CMD "$ERL \
|
||||
$NAME ${CONN_NAME} \
|
||||
-noinput \
|
||||
-hidden \
|
||||
-pa $EJABBERD_EBIN_PATH \
|
||||
$KERNEL_OPTS \
|
||||
-s ejabberd_ctl -extra $ERLANG_NODE $COMMAND"
|
||||
}
|
||||
|
||||
# display ctl usage
|
||||
usage ()
|
||||
{
|
||||
ctl
|
||||
exit
|
||||
}
|
||||
|
||||
# stop epmd if there is no other running node
|
||||
stop_epmd()
|
||||
{
|
||||
epmd -names | grep -q name || epmd -kill
|
||||
}
|
||||
|
||||
# make sure node not already running and node name unregistered
|
||||
check_start()
|
||||
{
|
||||
epmd -names | grep -q $NODE && {
|
||||
ps ux | grep -v grep | grep -q $ERLANG_NODE && {
|
||||
echo "ERROR: The ejabberd node '$ERLANG_NODE' is already running."
|
||||
exit 4
|
||||
} || {
|
||||
ps ux | grep beam | grep -v "grep beam" && {
|
||||
echo "ERROR: The ejabberd node '$ERLANG_NODE' is registered,"
|
||||
echo " but no ejabberd process has been found."
|
||||
echo "Shutdown other erlang nodes, and call 'epmd -kill'."
|
||||
exit 5
|
||||
} || {
|
||||
epmd -kill
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# allow sync calls
|
||||
wait_for_status()
|
||||
{
|
||||
# args: status try delay
|
||||
# return: 0 OK, 1 KO
|
||||
timeout=$2
|
||||
status=4
|
||||
while [ $status -ne $1 ] ; do
|
||||
sleep $3
|
||||
timeout=$(($timeout - 1))
|
||||
[ $timeout -eq 0 ] && {
|
||||
status=$1
|
||||
} || {
|
||||
ctl status > /dev/null
|
||||
status=$?
|
||||
}
|
||||
done
|
||||
[ $timeout -eq 0 ] && {
|
||||
status=1
|
||||
} || {
|
||||
status=0
|
||||
}
|
||||
return $status
|
||||
}
|
||||
|
||||
case $ARGS in
|
||||
' start') start;;
|
||||
' debug') debug;;
|
||||
' live') live;;
|
||||
' etop') etop;;
|
||||
' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
|
||||
' stopped') wait_for_status 3 15 2; stop_epmd;; # wait 15x2s before timeout
|
||||
*) ctl $ARGS;;
|
||||
esac
|
||||
Regular → Executable
+16
@@ -42,6 +42,22 @@ while(1)
|
||||
# password is null. Return 1 if the user $user\@$domain exitst.
|
||||
$result = 1;
|
||||
},last SWITCH;
|
||||
|
||||
$op eq 'tryregister' and do
|
||||
{
|
||||
$result = 1;
|
||||
},last SWITCH;
|
||||
|
||||
$op eq 'removeuser' and do
|
||||
{
|
||||
# password is null. Return 1 if the user $user\@$domain exitst.
|
||||
$result = 1;
|
||||
},last SWITCH;
|
||||
|
||||
$op eq 'removeuser3' and do
|
||||
{
|
||||
$result = 1;
|
||||
},last SWITCH;
|
||||
};
|
||||
my $out = pack "nn",2,$result ? 1 : 0;
|
||||
syswrite STDOUT,$out;
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : sha.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose :
|
||||
%%% Created : 20 Dec 2002 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -16,7 +11,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -24,26 +19,27 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(sha).
|
||||
-author('alexey@process-one.net').
|
||||
-record(adhoc_request,
|
||||
{
|
||||
lang = <<"">> :: binary(),
|
||||
node = <<"">> :: binary(),
|
||||
sessionid = <<"">> :: binary(),
|
||||
action = <<"">> :: binary(),
|
||||
xdata = false :: false | xmlel(),
|
||||
others = [] :: [xmlel()]
|
||||
}).
|
||||
|
||||
-export([start/0, sha/1]).
|
||||
|
||||
start() ->
|
||||
crypto:start().
|
||||
|
||||
digit_to_xchar(D) when (D >= 0) and (D < 10) ->
|
||||
D + 48;
|
||||
digit_to_xchar(D) ->
|
||||
D + 87.
|
||||
|
||||
sha(Text) ->
|
||||
Bin = crypto:sha(Text),
|
||||
lists:reverse(ints_to_rxstr(binary_to_list(Bin), [])).
|
||||
|
||||
ints_to_rxstr([], Res) ->
|
||||
Res;
|
||||
ints_to_rxstr([N | Ns], Res) ->
|
||||
ints_to_rxstr(Ns, [digit_to_xchar(N rem 16),
|
||||
digit_to_xchar(N div 16) | Res]).
|
||||
-record(adhoc_response,
|
||||
{
|
||||
lang = <<"">> :: binary(),
|
||||
node = <<"">> :: binary(),
|
||||
sessionid = <<"">> :: binary(),
|
||||
status :: atom(),
|
||||
defaultaction = <<"">> :: binary(),
|
||||
actions = [] :: [binary()],
|
||||
notes = [] :: [{binary(), binary()}],
|
||||
elements = [] :: [xmlel()]
|
||||
}).
|
||||
|
||||
-type adhoc_request() :: #adhoc_request{}.
|
||||
-type adhoc_response() :: #adhoc_response{}.
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -11,7 +11,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -19,13 +19,34 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(roster, {usj,
|
||||
us,
|
||||
jid,
|
||||
name = "",
|
||||
subscription = none,
|
||||
ask = none,
|
||||
groups = [],
|
||||
askmessage = [],
|
||||
xs = []}).
|
||||
-define(CT_XML,
|
||||
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
|
||||
|
||||
-define(CT_PLAIN,
|
||||
{<<"Content-Type">>, <<"text/plain">>}).
|
||||
|
||||
-define(CT_JSON,
|
||||
{<<"Content-Type">>, <<"application/json">>}).
|
||||
|
||||
-define(AC_ALLOW_ORIGIN,
|
||||
{<<"Access-Control-Allow-Origin">>, <<"*">>}).
|
||||
|
||||
-define(AC_ALLOW_METHODS,
|
||||
{<<"Access-Control-Allow-Methods">>,
|
||||
<<"GET, POST, OPTIONS">>}).
|
||||
|
||||
-define(AC_ALLOW_HEADERS,
|
||||
{<<"Access-Control-Allow-Headers">>,
|
||||
<<"Content-Type">>}).
|
||||
|
||||
-define(AC_MAX_AGE,
|
||||
{<<"Access-Control-Max-Age">>, <<"86400">>}).
|
||||
|
||||
-define(OPTIONS_HEADER,
|
||||
[?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS,
|
||||
?AC_ALLOW_HEADERS, ?AC_MAX_AGE]).
|
||||
|
||||
-define(HEADER(CType),
|
||||
[CType, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_bosh).
|
||||
@@ -0,0 +1,61 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(VERSION, ejabberd_config:get_version()).
|
||||
|
||||
-define(MYHOSTS, ejabberd_config:get_myhosts()).
|
||||
|
||||
-define(MYNAME, hd(ejabberd_config:get_myhosts())).
|
||||
|
||||
-define(MYLANG, ejabberd_config:get_mylang()).
|
||||
|
||||
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
|
||||
|
||||
-define(CONFIG_PATH, <<"ejabberd.cfg">>).
|
||||
|
||||
-define(LOG_PATH, <<"ejabberd.log">>).
|
||||
|
||||
-ifdef(ENABLE_FLASH_HACK).
|
||||
|
||||
-define(FLASH_HACK, true).
|
||||
|
||||
-else.
|
||||
|
||||
-define(FLASH_HACK, false).
|
||||
|
||||
-endif.
|
||||
|
||||
-define(EJABBERD_URI,
|
||||
<<"http://www.process-one.net/en/ejabberd/">>).
|
||||
|
||||
-define(S2STIMEOUT, 600000).
|
||||
|
||||
%%-define(DBGFSM, true).
|
||||
|
||||
-record(scram,
|
||||
{storedkey = <<"">>,
|
||||
serverkey = <<"">>,
|
||||
salt = <<"">>,
|
||||
iterationcount = 0 :: integer()}).
|
||||
|
||||
-type scram() :: #scram{}.
|
||||
|
||||
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
|
||||
@@ -0,0 +1,93 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-ifndef(mod_privacy_hrl).
|
||||
|
||||
-include("mod_privacy.hrl").
|
||||
|
||||
-endif.
|
||||
|
||||
%-define(SETS, gb_sets).
|
||||
-define(SETS, ejabberd_sets).
|
||||
|
||||
-define(DICT, dict).
|
||||
|
||||
-record(state,
|
||||
{socket,
|
||||
sockmod = ejabberd_socket :: ejabberd_socket | ejabberd_frontend_socket,
|
||||
socket_monitor = make_ref() :: reference(),
|
||||
xml_socket = false :: boolean(),
|
||||
streamid = <<"">> :: binary(),
|
||||
sasl_state :: any(),
|
||||
access :: atom(),
|
||||
shaper = none :: shaper:shaper(),
|
||||
zlib = false :: boolean(),
|
||||
tls = false :: boolean(),
|
||||
tls_required = false :: boolean(),
|
||||
tls_enabled = false :: boolean(),
|
||||
tls_options = [] :: list(),
|
||||
authenticated = false :: boolean() | replaced | rebinded,
|
||||
jid = #jid{} :: jid(),
|
||||
user = <<"">> :: binary(),
|
||||
server = ?MYNAME :: binary(),
|
||||
resource = <<"">> :: binary(),
|
||||
sid = {now(), self()} :: ejabberd_sm:sid(),
|
||||
pres_t = (?SETS):new() :: ?SETS:ej_set() | {pres_t, non_neg_integer()},
|
||||
pres_f = (?SETS):new() :: ?SETS:ej_set() | {pres_f, non_neg_integer()},
|
||||
pres_a = (?SETS):new() :: ?SETS:ej_set() | {pres_a, non_neg_integer()},
|
||||
pres_last :: xmlel(),
|
||||
pres_timestamp :: calendar:datetime(),
|
||||
privacy_list = #userlist{} :: userlist(),
|
||||
conn = unknown :: atom(),
|
||||
auth_module = unknown :: atom(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
redirect = false :: boolean(),
|
||||
aux_fields = [] :: [{atom(), any()}],
|
||||
fsm_limit_opts = [] :: [{atom(), any()}],
|
||||
lang = ?MYLANG :: binary(),
|
||||
debug = false :: boolean(),
|
||||
flash_hack = false :: boolean(),
|
||||
flash_connection = false :: boolean(),
|
||||
reception = true :: boolean(),
|
||||
standby = false :: boolean(),
|
||||
queue = queue:new() :: queue(),
|
||||
queue_len = 0 :: integer(),
|
||||
pres_queue = gb_trees:empty() :: gb_tree(),
|
||||
keepalive_timer :: reference(),
|
||||
keepalive_timeout :: timeout(),
|
||||
oor_timeout :: timeout(),
|
||||
oor_status = <<"">> :: binary(),
|
||||
oor_show = <<"">> :: binary(),
|
||||
oor_notification :: xmlel(),
|
||||
oor_send_body = all :: first_per_user | first | all | none,
|
||||
oor_send_groupchat = false :: boolean(),
|
||||
oor_send_from = jid :: jid | username | name | none,
|
||||
oor_appid = <<"">> :: binary(),
|
||||
oor_unread = 0 :: integer(),
|
||||
oor_unread_users = (?SETS):new() :: ?SETS:ej_set(),
|
||||
oor_unread_client = 0 :: integer(),
|
||||
oor_offline = false :: boolean(),
|
||||
ack_enabled = false :: boolean(),
|
||||
ack_counter = 0 :: integer(),
|
||||
ack_queue = queue:new() :: queue(),
|
||||
ack_timer :: reference()}).
|
||||
|
||||
-type c2s_state() :: #state{}.
|
||||
@@ -0,0 +1,82 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-type aterm() :: {atom(), atype()}.
|
||||
-type atype() :: integer | string | binary |
|
||||
{tuple, [aterm()]} | {list, aterm()}.
|
||||
-type rterm() :: {atom(), rtype()}.
|
||||
-type rtype() :: integer | string | atom |
|
||||
{tuple, [rterm()]} | {list, rterm()} |
|
||||
rescode | restuple.
|
||||
|
||||
-record(ejabberd_commands,
|
||||
{name :: atom(),
|
||||
tags = [] :: [atom()] | '_' | '$2',
|
||||
desc = "" :: string() | '_' | '$3',
|
||||
longdesc = "" :: string() | '_',
|
||||
module :: atom(),
|
||||
function :: atom(),
|
||||
args = [] :: [aterm()] | '_' | '$1' | '$2',
|
||||
result = {res, rescode} :: rterm() | '_' | '$2',
|
||||
args_desc = none :: none | [string()],
|
||||
result_desc = none :: none | string(),
|
||||
args_example = none :: [any()],
|
||||
result_example = none :: any()}).
|
||||
|
||||
-type ejabberd_commands() :: #ejabberd_commands{name :: atom(),
|
||||
tags :: [atom()],
|
||||
desc :: string(),
|
||||
longdesc :: string(),
|
||||
module :: atom(),
|
||||
function :: atom(),
|
||||
args :: [aterm()],
|
||||
result :: rterm(),
|
||||
args_desc :: none | [string()],
|
||||
result_desc :: none | string(),
|
||||
args_example :: [any()],
|
||||
result_example :: any()}.
|
||||
|
||||
%% @type ejabberd_commands() = #ejabberd_commands{
|
||||
%% name = atom(),
|
||||
%% tags = [atom()],
|
||||
%% desc = string(),
|
||||
%% longdesc = string(),
|
||||
%% module = atom(),
|
||||
%% function = atom(),
|
||||
%% args = [aterm()],
|
||||
%% result = rterm()
|
||||
%% }.
|
||||
%% desc: Description of the command
|
||||
%% args: Describe the accepted arguments.
|
||||
%% This way the function that calls the command can format the
|
||||
%% arguments before calling.
|
||||
|
||||
%% @type atype() = integer | string | {tuple, [aterm()]} | {list, aterm()}.
|
||||
%% Allowed types for arguments are integer, string, tuple and list.
|
||||
|
||||
%% @type rtype() = integer | string | atom | {tuple, [rterm()]} | {list, rterm()} | rescode | restuple.
|
||||
%% A rtype is either an atom or a tuple with two elements.
|
||||
|
||||
%% @type aterm() = {Name::atom(), Type::atype()}.
|
||||
%% An argument term is a tuple with the term name and the term type.
|
||||
|
||||
%% @type rterm() = {Name::atom(), Type::rtype()}.
|
||||
%% A result term is a tuple with the term name and the term type.
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -11,7 +11,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -19,17 +19,16 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(eldap_search, {scope = wholeSubtree,
|
||||
base = [],
|
||||
filter,
|
||||
limit = 0,
|
||||
attributes = [],
|
||||
types_only = false,
|
||||
timeout = 0}).
|
||||
-record(config, {key :: any(), value :: any()}).
|
||||
|
||||
-record(local_config, {key :: any(), value :: any()}).
|
||||
|
||||
-record(eldap_search_result, {entries,
|
||||
referrals}).
|
||||
-type config() :: #config{}.
|
||||
-type local_config() :: #local_config{}.
|
||||
|
||||
-record(eldap_entry, {object_name,
|
||||
attributes}).
|
||||
-record(state,
|
||||
{opts = [] :: [acl:acl() | config() | local_config()],
|
||||
hosts = [] :: [binary()],
|
||||
override_local = false :: boolean(),
|
||||
override_global = false :: boolean(),
|
||||
override_acls = false :: boolean()}).
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -11,7 +11,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -20,6 +20,9 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(STATUS_SUCCESS, 0).
|
||||
-define(STATUS_ERROR, 1).
|
||||
-define(STATUS_USAGE, 2).
|
||||
-define(STATUS_BADRPC, 3).
|
||||
|
||||
-define(STATUS_ERROR, 1).
|
||||
|
||||
-define(STATUS_USAGE, 2).
|
||||
|
||||
-define(STATUS_BADRPC, 3).
|
||||
@@ -0,0 +1,55 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(request,
|
||||
{method :: method(),
|
||||
path = [] :: [binary()],
|
||||
q = [] :: [{binary() | nokey, binary()}],
|
||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
||||
auth :: {binary(), binary()} |
|
||||
{auth_jid, {binary(), binary()}, jlib:jid()},
|
||||
lang = <<"">> :: binary(),
|
||||
data = <<"">> :: binary(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
host = <<"">> :: binary(),
|
||||
port = 5280 :: inet:port_number(),
|
||||
tp = http :: protocol(),
|
||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
||||
|
||||
-record(ws,
|
||||
{socket :: inet:socket() | tls:tls_socket(),
|
||||
sockmod = gen_tcp :: gen_tcp | tls,
|
||||
ws_autoexit = false :: boolean(),
|
||||
ip :: {inet:ip_address(), inet:port_number()},
|
||||
vsn :: vsn(),
|
||||
origin = <<"">> :: binary(),
|
||||
host = <<"">> :: binary(),
|
||||
port = 5280 :: inet:port_number(),
|
||||
path = [] :: [binary()],
|
||||
headers = [] :: [{atom() | binary(), binary()}],
|
||||
local_path = [] :: [binary()],
|
||||
q = [] :: [{binary() | nokey, binary()}],
|
||||
buf :: binary()}).
|
||||
|
||||
-type method() :: 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'PUT' | 'POST' | 'TRACE'.
|
||||
-type protocol() :: http | https.
|
||||
-type http_request() :: #request{}.
|
||||
-type vsn() :: {'draft-hybi' | 'draft-hixie', non_neg_integer()}.
|
||||
@@ -0,0 +1,102 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(X(Name),
|
||||
#xmlel{name = Name, attrs = [], children = []}).
|
||||
|
||||
-define(XA(Name, Attrs),
|
||||
#xmlel{name = Name, attrs = Attrs, children = []}).
|
||||
|
||||
-define(XE(Name, Els),
|
||||
#xmlel{name = Name, attrs = [], children = Els}).
|
||||
|
||||
-define(XAE(Name, Attrs, Els),
|
||||
#xmlel{name = Name, attrs = Attrs, children = Els}).
|
||||
|
||||
-define(C(Text), {xmlcdata, Text}).
|
||||
|
||||
-define(XC(Name, Text), ?XE(Name, [?C(Text)])).
|
||||
|
||||
-define(XAC(Name, Attrs, Text),
|
||||
?XAE(Name, Attrs, [?C(Text)])).
|
||||
|
||||
-define(T(Text), translate:translate(Lang, Text)).
|
||||
|
||||
-define(CT(Text), ?C((?T(Text)))).
|
||||
|
||||
-define(XCT(Name, Text), ?XC(Name, (?T(Text)))).
|
||||
|
||||
-define(XACT(Name, Attrs, Text),
|
||||
?XAC(Name, Attrs, (?T(Text)))).
|
||||
|
||||
-define(LI(Els), ?XE(<<"li">>, Els)).
|
||||
|
||||
-define(A(URL, Els),
|
||||
?XAE(<<"a">>, [{<<"href">>, URL}], Els)).
|
||||
|
||||
-define(AC(URL, Text), ?A(URL, [?C(Text)])).
|
||||
|
||||
-define(ACT(URL, Text), ?AC(URL, (?T(Text)))).
|
||||
|
||||
-define(P, ?X(<<"p">>)).
|
||||
|
||||
-define(BR, ?X(<<"br">>)).
|
||||
|
||||
-define(INPUT(Type, Name, Value),
|
||||
?XA(<<"input">>,
|
||||
[{<<"type">>, Type}, {<<"name">>, Name},
|
||||
{<<"value">>, Value}])).
|
||||
|
||||
-define(INPUTT(Type, Name, Value),
|
||||
?INPUT(Type, Name, (?T(Value)))).
|
||||
|
||||
-define(INPUTS(Type, Name, Value, Size),
|
||||
?XA(<<"input">>,
|
||||
[{<<"type">>, Type}, {<<"name">>, Name},
|
||||
{<<"value">>, Value}, {<<"size">>, Size}])).
|
||||
|
||||
-define(INPUTST(Type, Name, Value, Size),
|
||||
?INPUT(Type, Name, (?T(Value)), Size)).
|
||||
|
||||
-define(ACLINPUT(Text),
|
||||
?XE(<<"td">>,
|
||||
[?INPUT(<<"text">>, <<"value", ID/binary>>, Text)])).
|
||||
|
||||
-define(TEXTAREA(Name, Rows, Cols, Value),
|
||||
?XAC(<<"textarea">>,
|
||||
[{<<"name">>, Name}, {<<"rows">>, Rows},
|
||||
{<<"cols">>, Cols}],
|
||||
Value)).
|
||||
|
||||
-define(XRES(Text),
|
||||
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
|
||||
|
||||
-define(XREST(Text), ?XRES((?T(Text)))).
|
||||
|
||||
-define(GL(Ref, Title),
|
||||
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
|
||||
[?XAE(<<"a">>,
|
||||
[{<<"href">>, <<"/admin/doc/guide.html#", Ref/binary>>},
|
||||
{<<"target">>, <<"_blank">>}],
|
||||
[?C(<<"[Guide: ", Title/binary, "]">>)])])).
|
||||
|
||||
-define(H1GL(Name, Ref, Title),
|
||||
[?XC(<<"h1">>, Name), ?GL(Ref, Title)]).
|
||||
@@ -0,0 +1,65 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(LDAP_PORT, 389).
|
||||
|
||||
-define(LDAPS_PORT, 636).
|
||||
|
||||
-type scope() :: baseObject | singleLevel | wholeSubtree.
|
||||
|
||||
-record(eldap_search,
|
||||
{scope = wholeSubtree :: scope(),
|
||||
base = <<"">> :: binary(),
|
||||
filter :: eldap:filter(),
|
||||
limit = 0 :: non_neg_integer(),
|
||||
attributes = [] :: [binary()],
|
||||
types_only = false :: boolean(),
|
||||
deref_aliases = neverDerefAliases :: neverDerefAliases |
|
||||
derefInSearching |
|
||||
derefFindingBaseObj |
|
||||
derefAlways,
|
||||
timeout = 0 :: non_neg_integer()}).
|
||||
|
||||
-record(eldap_search_result, {entries = [] :: [eldap_entry()],
|
||||
referrals = [] :: list()}).
|
||||
|
||||
-record(eldap_entry, {object_name = <<>> :: binary(),
|
||||
attributes = [] :: [{binary(), [binary()]}]}).
|
||||
|
||||
-type tlsopts() :: [{encrypt, tls | starttls | none} |
|
||||
{tls_cacertfile, binary() | undefined} |
|
||||
{tls_certfile, binary() | undefined} |
|
||||
{tls_depth, non_neg_integer() | undefined} |
|
||||
{tls_verify, hard | soft | false}].
|
||||
|
||||
-record(eldap_config, {servers = [] :: [binary()],
|
||||
backups = [] :: [binary()],
|
||||
tls_options = [] :: tlsopts(),
|
||||
port = ?LDAP_PORT :: inet:port_number(),
|
||||
dn = <<"">> :: binary(),
|
||||
password = <<"">> :: binary(),
|
||||
base = <<"">> :: binary(),
|
||||
deref_aliases = never :: never | searching |
|
||||
finding | always}).
|
||||
|
||||
-type eldap_config() :: #eldap_config{}.
|
||||
-type eldap_search() :: #eldap_search{}.
|
||||
-type eldap_entry() :: #eldap_entry{}.
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -11,7 +11,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -19,18 +19,29 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(adhoc_request, {lang,
|
||||
node,
|
||||
sessionid,
|
||||
action,
|
||||
xdata,
|
||||
others}).
|
||||
-define(CT_XML,
|
||||
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
|
||||
|
||||
-record(adhoc_response, {lang,
|
||||
node,
|
||||
sessionid,
|
||||
status,
|
||||
defaultaction = "",
|
||||
actions = [],
|
||||
notes = [],
|
||||
elements = []}).
|
||||
-define(CT_PLAIN,
|
||||
{<<"Content-Type">>, <<"text/plain">>}).
|
||||
|
||||
-define(AC_ALLOW_ORIGIN,
|
||||
{<<"Access-Control-Allow-Origin">>, <<"*">>}).
|
||||
|
||||
-define(AC_ALLOW_METHODS,
|
||||
{<<"Access-Control-Allow-Methods">>,
|
||||
<<"GET, POST, OPTIONS">>}).
|
||||
|
||||
-define(AC_ALLOW_HEADERS,
|
||||
{<<"Access-Control-Allow-Headers">>,
|
||||
<<"Content-Type">>}).
|
||||
|
||||
-define(AC_MAX_AGE,
|
||||
{<<"Access-Control-Max-Age">>, <<"86400">>}).
|
||||
|
||||
-define(OPTIONS_HEADER,
|
||||
[?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS,
|
||||
?AC_ALLOW_HEADERS, ?AC_MAX_AGE]).
|
||||
|
||||
-define(HEADER,
|
||||
[?CT_XML, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
|
||||
@@ -0,0 +1,701 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
|
||||
-define(NS_DISCO_ITEMS,
|
||||
<<"http://jabber.org/protocol/disco#items">>).
|
||||
|
||||
-define(NS_DISCO_INFO,
|
||||
<<"http://jabber.org/protocol/disco#info">>).
|
||||
|
||||
-define(NS_VCARD, <<"vcard-temp">>).
|
||||
|
||||
-define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>).
|
||||
|
||||
-define(NS_AUTH, <<"jabber:iq:auth">>).
|
||||
|
||||
-define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>).
|
||||
|
||||
-define(NS_REGISTER, <<"jabber:iq:register">>).
|
||||
|
||||
-define(NS_SEARCH, <<"jabber:iq:search">>).
|
||||
|
||||
-define(NS_ROSTER, <<"jabber:iq:roster">>).
|
||||
|
||||
-define(NS_ROSTER_VER,
|
||||
<<"urn:xmpp:features:rosterver">>).
|
||||
|
||||
-define(NS_PRIVACY, <<"jabber:iq:privacy">>).
|
||||
|
||||
-define(NS_BLOCKING, <<"urn:xmpp:blocking">>).
|
||||
|
||||
-define(NS_PRIVATE, <<"jabber:iq:private">>).
|
||||
|
||||
-define(NS_VERSION, <<"jabber:iq:version">>).
|
||||
|
||||
-define(NS_TIME90, <<"jabber:iq:time">>).
|
||||
|
||||
-define(NS_TIME, <<"urn:xmpp:time">>).
|
||||
|
||||
-define(NS_LAST, <<"jabber:iq:last">>).
|
||||
|
||||
-define(NS_XDATA, <<"jabber:x:data">>).
|
||||
|
||||
-define(NS_IQDATA, <<"jabber:iq:data">>).
|
||||
|
||||
-define(NS_DELAY91, <<"jabber:x:delay">>).
|
||||
|
||||
-define(NS_DELAY, <<"urn:xmpp:delay">>).
|
||||
|
||||
-define(NS_EXPIRE, <<"jabber:x:expire">>).
|
||||
|
||||
-define(NS_EVENT, <<"jabber:x:event">>).
|
||||
|
||||
-define(NS_CHATSTATES,
|
||||
<<"http://jabber.org/protocol/chatstates">>).
|
||||
|
||||
-define(NS_XCONFERENCE, <<"jabber:x:conference">>).
|
||||
|
||||
-define(NS_STATS,
|
||||
<<"http://jabber.org/protocol/stats">>).
|
||||
|
||||
-define(NS_MUC, <<"http://jabber.org/protocol/muc">>).
|
||||
|
||||
-define(NS_MUC_USER,
|
||||
<<"http://jabber.org/protocol/muc#user">>).
|
||||
|
||||
-define(NS_MUC_ADMIN,
|
||||
<<"http://jabber.org/protocol/muc#admin">>).
|
||||
|
||||
-define(NS_MUC_OWNER,
|
||||
<<"http://jabber.org/protocol/muc#owner">>).
|
||||
|
||||
-define(NS_MUC_UNIQUE,
|
||||
<<"http://jabber.org/protocol/muc#unique">>).
|
||||
|
||||
-define(NS_PUBSUB,
|
||||
<<"http://jabber.org/protocol/pubsub">>).
|
||||
|
||||
-define(NS_PUBSUB_EVENT,
|
||||
<<"http://jabber.org/protocol/pubsub#event">>).
|
||||
|
||||
-define(NS_PUBSUB_META_DATA,
|
||||
<<"http://jabber.org/protocol/pubsub#meta-data">>).
|
||||
|
||||
-define(NS_PUBSUB_OWNER,
|
||||
<<"http://jabber.org/protocol/pubsub#owner">>).
|
||||
|
||||
-define(NS_PUBSUB_NMI,
|
||||
<<"http://jabber.org/protocol/pubsub#node-meta-info">>).
|
||||
|
||||
-define(NS_PUBSUB_ERRORS,
|
||||
<<"http://jabber.org/protocol/pubsub#errors">>).
|
||||
|
||||
-define(NS_PUBSUB_NODE_CONFIG,
|
||||
<<"http://jabber.org/protocol/pubsub#node_config">>).
|
||||
|
||||
-define(NS_PUBSUB_SUB_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
||||
|
||||
-define(NS_PUBSUB_SUBSCRIBE_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
||||
|
||||
-define(NS_PUBSUB_PUBLISH_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#publish_options">>).
|
||||
|
||||
-define(NS_PUBSUB_SUB_AUTH,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_authorization">>).
|
||||
|
||||
-define(NS_PUBSUB_GET_PENDING,
|
||||
<<"http://jabber.org/protocol/pubsub#get-pending">>).
|
||||
|
||||
-define(NS_COMMANDS,
|
||||
<<"http://jabber.org/protocol/commands">>).
|
||||
|
||||
-define(NS_BYTESTREAMS,
|
||||
<<"http://jabber.org/protocol/bytestreams">>).
|
||||
|
||||
-define(NS_ADMIN,
|
||||
<<"http://jabber.org/protocol/admin">>).
|
||||
-define(NS_ADMIN_ANNOUNCE,
|
||||
<<"http://jabber.org/protocol/admin#announce">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALL,
|
||||
<<"http://jabber.org/protocol/admin#announce-all">>).
|
||||
-define(NS_ADMIN_SET_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#set-motd">>).
|
||||
-define(NS_ADMIN_EDIT_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#edit-motd">>).
|
||||
-define(NS_ADMIN_DELETE_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#delete-motd">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#announce-allhosts">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#announce-all-allhosts">>).
|
||||
-define(NS_ADMIN_SET_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#set-motd-allhosts">>).
|
||||
-define(NS_ADMIN_EDIT_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#edit-motd-allhosts">>).
|
||||
-define(NS_ADMIN_DELETE_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#delete-motd-allhosts">>).
|
||||
|
||||
-define(NS_SERVERINFO,
|
||||
<<"http://jabber.org/network/serverinfo">>).
|
||||
|
||||
-define(NS_RSM, <<"http://jabber.org/protocol/rsm">>).
|
||||
|
||||
-define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>).
|
||||
|
||||
-define(NS_STREAM,
|
||||
<<"http://etherx.jabber.org/streams">>).
|
||||
|
||||
-define(NS_FLASH_STREAM,
|
||||
<<"http://www.jabber.com/streams/flash">>).
|
||||
|
||||
-define(NS_STANZAS,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-stanzas">>).
|
||||
|
||||
-define(NS_STREAMS,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-streams">>).
|
||||
|
||||
-define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>).
|
||||
|
||||
-define(NS_SASL,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-sasl">>).
|
||||
|
||||
-define(NS_SESSION,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-session">>).
|
||||
|
||||
-define(NS_BIND,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-bind">>).
|
||||
|
||||
-define(NS_FEATURE_IQAUTH,
|
||||
<<"http://jabber.org/features/iq-auth">>).
|
||||
|
||||
-define(NS_FEATURE_IQREGISTER,
|
||||
<<"http://jabber.org/features/iq-register">>).
|
||||
|
||||
-define(NS_FEATURE_COMPRESS,
|
||||
<<"http://jabber.org/features/compress">>).
|
||||
|
||||
-define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>).
|
||||
|
||||
-define(NS_COMPRESS,
|
||||
<<"http://jabber.org/protocol/compress">>).
|
||||
|
||||
-define(NS_CAPS, <<"http://jabber.org/protocol/caps">>).
|
||||
|
||||
-define(NS_SHIM, <<"http://jabber.org/protocol/shim">>).
|
||||
|
||||
-define(NS_ADDRESS,
|
||||
<<"http://jabber.org/protocol/address">>).
|
||||
|
||||
-define(NS_OOB, <<"jabber:x:oob">>).
|
||||
|
||||
-define(NS_CAPTCHA, <<"urn:xmpp:captcha">>).
|
||||
|
||||
-define(NS_MEDIA, <<"urn:xmpp:media-element">>).
|
||||
|
||||
-define(NS_BOB, <<"urn:xmpp:bob">>).
|
||||
|
||||
-include("xml.hrl").
|
||||
|
||||
-define(STANZA_ERROR(Code, Type, Condition),
|
||||
#xmlel{name = <<"error">>,
|
||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
||||
children = []}]}).
|
||||
|
||||
-define(ERR_BAD_FORMAT,
|
||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
||||
<<"bad-format">>)).
|
||||
|
||||
-define(ERR_BAD_REQUEST,
|
||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
||||
<<"bad-request">>)).
|
||||
|
||||
-define(ERR_CONFLICT,
|
||||
?STANZA_ERROR(<<"409">>, <<"cancel">>, <<"conflict">>)).
|
||||
|
||||
-define(ERR_FEATURE_NOT_IMPLEMENTED,
|
||||
?STANZA_ERROR(<<"501">>, <<"cancel">>,
|
||||
<<"feature-not-implemented">>)).
|
||||
|
||||
-define(ERR_FORBIDDEN,
|
||||
?STANZA_ERROR(<<"403">>, <<"auth">>, <<"forbidden">>)).
|
||||
|
||||
-define(ERR_GONE,
|
||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"gone">>)).
|
||||
|
||||
-define(ERR_INTERNAL_SERVER_ERROR,
|
||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
||||
<<"internal-server-error">>)).
|
||||
|
||||
-define(ERR_ITEM_NOT_FOUND,
|
||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
||||
<<"item-not-found">>)).
|
||||
|
||||
-define(ERR_JID_MALFORMED,
|
||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
||||
<<"jid-malformed">>)).
|
||||
|
||||
-define(ERR_NOT_ACCEPTABLE,
|
||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
||||
<<"not-acceptable">>)).
|
||||
|
||||
-define(ERR_NOT_ALLOWED,
|
||||
?STANZA_ERROR(<<"405">>, <<"cancel">>,
|
||||
<<"not-allowed">>)).
|
||||
|
||||
-define(ERR_NOT_AUTHORIZED,
|
||||
?STANZA_ERROR(<<"401">>, <<"auth">>,
|
||||
<<"not-authorized">>)).
|
||||
|
||||
-define(ERR_PAYMENT_REQUIRED,
|
||||
?STANZA_ERROR(<<"402">>, <<"auth">>,
|
||||
<<"payment-required">>)).
|
||||
|
||||
-define(ERR_POLICY_VIOLATION,
|
||||
?STANZA_ERROR(<<"405">>, <<"cancel">>,
|
||||
<<"policy-violation">>)).
|
||||
|
||||
-define(ERR_RECIPIENT_UNAVAILABLE,
|
||||
?STANZA_ERROR(<<"404">>, <<"wait">>,
|
||||
<<"recipient-unavailable">>)).
|
||||
|
||||
-define(ERR_REDIRECT,
|
||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"redirect">>)).
|
||||
|
||||
-define(ERR_REGISTRATION_REQUIRED,
|
||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
||||
<<"registration-required">>)).
|
||||
|
||||
-define(ERR_REMOTE_SERVER_NOT_FOUND,
|
||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
||||
<<"remote-server-not-found">>)).
|
||||
|
||||
-define(ERR_REMOTE_SERVER_TIMEOUT,
|
||||
?STANZA_ERROR(<<"504">>, <<"wait">>,
|
||||
<<"remote-server-timeout">>)).
|
||||
|
||||
-define(ERR_RESOURCE_CONSTRAINT,
|
||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
||||
<<"resource-constraint">>)).
|
||||
|
||||
-define(ERR_SERVICE_UNAVAILABLE,
|
||||
?STANZA_ERROR(<<"503">>, <<"cancel">>,
|
||||
<<"service-unavailable">>)).
|
||||
|
||||
-define(ERR_SUBSCRIPTION_REQUIRED,
|
||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
||||
<<"subscription-required">>)).
|
||||
|
||||
-define(ERR_UNEXPECTED_REQUEST,
|
||||
?STANZA_ERROR(<<"400">>, <<"wait">>,
|
||||
<<"unexpected-request">>)).
|
||||
|
||||
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
|
||||
?STANZA_ERROR(<<"401">>, <<"cancel">>,
|
||||
<<"unexpected-request">>)).
|
||||
|
||||
%-define(ERR_,
|
||||
% ?STANZA_ERROR("", "", "")).
|
||||
|
||||
-define(STANZA_ERRORT(Code, Type, Condition, Lang,
|
||||
Text),
|
||||
#xmlel{name = <<"error">>,
|
||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
|
||||
#xmlel{name = <<"text">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
translate:translate(Lang, Text)}]}]}).
|
||||
|
||||
-define(ERRT_BAD_FORMAT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
||||
<<"bad-format">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_BAD_REQUEST(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
||||
<<"bad-request">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_CONFLICT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"409">>, <<"cancel">>, <<"conflict">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"501">>, <<"cancel">>,
|
||||
<<"feature-not-implemented">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_FORBIDDEN(Lang, Text),
|
||||
?STANZA_ERRORT(<<"403">>, <<"auth">>, <<"forbidden">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_GONE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"gone">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
||||
<<"internal-server-error">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_ITEM_NOT_FOUND(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
||||
<<"item-not-found">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_JID_MALFORMED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
||||
<<"jid-malformed">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_ACCEPTABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
||||
<<"not-acceptable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_ALLOWED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"405">>, <<"cancel">>,
|
||||
<<"not-allowed">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_AUTHORIZED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"401">>, <<"auth">>,
|
||||
<<"not-authorized">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_PAYMENT_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"402">>, <<"auth">>,
|
||||
<<"payment-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"wait">>,
|
||||
<<"recipient-unavailable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REDIRECT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"redirect">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_REGISTRATION_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
||||
<<"registration-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
||||
<<"remote-server-not-found">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"504">>, <<"wait">>,
|
||||
<<"remote-server-timeout">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_RESOURCE_CONSTRAINT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
||||
<<"resource-constraint">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_SERVICE_UNAVAILABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"503">>, <<"cancel">>,
|
||||
<<"service-unavailable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
||||
<<"subscription-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_UNEXPECTED_REQUEST(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"wait">>,
|
||||
<<"unexpected-request">>, Lang, Text)).
|
||||
|
||||
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
|
||||
?ERRT_NOT_ACCEPTABLE(Lang, <<"No resource provided">>)).
|
||||
|
||||
-define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang),
|
||||
?ERRT_NOT_ACCEPTABLE(Lang,
|
||||
<<"Illegal resource format">>)).
|
||||
|
||||
-define(ERR_AUTH_RESOURCE_CONFLICT(Lang),
|
||||
?ERRT_CONFLICT(Lang, <<"Resource conflict">>)).
|
||||
|
||||
-define(STREAM_ERROR(Condition, Cdata),
|
||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children = [{xmlcdata, Cdata}]}]}).
|
||||
|
||||
-define(SERR_BAD_FORMAT,
|
||||
?STREAM_ERROR(<<"bad-format">>, <<"">>)).
|
||||
|
||||
-define(SERR_BAD_NAMESPACE_PREFIX,
|
||||
?STREAM_ERROR(<<"bad-namespace-prefix">>, <<"">>)).
|
||||
|
||||
-define(SERR_CONFLICT,
|
||||
?STREAM_ERROR(<<"conflict">>, <<"">>)).
|
||||
|
||||
-define(SERR_CONNECTION_TIMEOUT,
|
||||
?STREAM_ERROR(<<"connection-timeout">>, <<"">>)).
|
||||
|
||||
-define(SERR_HOST_GONE,
|
||||
?STREAM_ERROR(<<"host-gone">>, <<"">>)).
|
||||
|
||||
-define(SERR_HOST_UNKNOWN,
|
||||
?STREAM_ERROR(<<"host-unknown">>, <<"">>)).
|
||||
|
||||
-define(SERR_IMPROPER_ADDRESSING,
|
||||
?STREAM_ERROR(<<"improper-addressing">>, <<"">>)).
|
||||
|
||||
-define(SERR_INTERNAL_SERVER_ERROR,
|
||||
?STREAM_ERROR(<<"internal-server-error">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_FROM,
|
||||
?STREAM_ERROR(<<"invalid-from">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_ID,
|
||||
?STREAM_ERROR(<<"invalid-id">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_NAMESPACE,
|
||||
?STREAM_ERROR(<<"invalid-namespace">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_XML,
|
||||
?STREAM_ERROR(<<"invalid-xml">>, <<"">>)).
|
||||
|
||||
-define(SERR_NOT_AUTHORIZED,
|
||||
?STREAM_ERROR(<<"not-authorized">>, <<"">>)).
|
||||
|
||||
-define(SERR_POLICY_VIOLATION,
|
||||
?STREAM_ERROR(<<"policy-violation">>, <<"">>)).
|
||||
|
||||
-define(SERR_REMOTE_CONNECTION_FAILED,
|
||||
?STREAM_ERROR(<<"remote-connection-failed">>, <<"">>)).
|
||||
|
||||
-define(SERR_RESOURSE_CONSTRAINT,
|
||||
?STREAM_ERROR(<<"resource-constraint">>, <<"">>)).
|
||||
|
||||
-define(SERR_RESTRICTED_XML,
|
||||
?STREAM_ERROR(<<"restricted-xml">>, <<"">>)).
|
||||
|
||||
-define(SERR_SEE_OTHER_HOST(Host),
|
||||
?STREAM_ERROR(<<"see-other-host">>, Host)).
|
||||
|
||||
-define(SERR_SYSTEM_SHUTDOWN,
|
||||
?STREAM_ERROR(<<"system-shutdown">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_ENCODING,
|
||||
?STREAM_ERROR(<<"unsupported-encoding">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_STANZA_TYPE,
|
||||
?STREAM_ERROR(<<"unsupported-stanza-type">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_VERSION,
|
||||
?STREAM_ERROR(<<"unsupported-version">>, <<"">>)).
|
||||
|
||||
-define(SERR_XML_NOT_WELL_FORMED,
|
||||
?STREAM_ERROR(<<"xml-not-well-formed">>, <<"">>)).
|
||||
|
||||
%-define(SERR_,
|
||||
% ?STREAM_ERROR("", "")).
|
||||
|
||||
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
|
||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children = [{xmlcdata, Cdata}]},
|
||||
#xmlel{name = <<"text">>,
|
||||
attrs =
|
||||
[{<<"xml:lang">>, Lang},
|
||||
{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
translate:translate(Lang, Text)}]}]}).
|
||||
|
||||
-define(SERRT_BAD_FORMAT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"bad-format">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
|
||||
?STREAM_ERRORT(<<"bad-namespace-prefix">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_CONFLICT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"conflict">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"connection-timeout">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_HOST_GONE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"host-gone">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_HOST_UNKNOWN(Lang, Text),
|
||||
?STREAM_ERRORT(<<"host-unknown">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
|
||||
?STREAM_ERRORT(<<"improper-addressing">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
||||
?STREAM_ERRORT(<<"internal-server-error">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_FROM(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-from">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_ID(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-id">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-namespace">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_INVALID_XML(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-xml">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"not-authorized">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
||||
?STREAM_ERRORT(<<"policy-violation">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"remote-connection-failed">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"resource-constraint">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_RESTRICTED_XML(Lang, Text),
|
||||
?STREAM_ERRORT(<<"restricted-xml">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
|
||||
?STREAM_ERRORT(<<"see-other-host">>, Host, Lang, Text)).
|
||||
|
||||
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
|
||||
?STREAM_ERRORT(<<"system-shutdown">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-encoding">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-stanza-type">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-version">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"xml-not-well-formed">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-record(jid, {user = <<"">> :: binary(),
|
||||
server = <<"">> :: binary(),
|
||||
resource = <<"">> :: binary(),
|
||||
luser = <<"">> :: binary(),
|
||||
lserver = <<"">> :: binary(),
|
||||
lresource = <<"">> :: binary()}).
|
||||
|
||||
-type(jid() :: #jid{}).
|
||||
|
||||
-type(ljid() :: {binary(), binary(), binary()}).
|
||||
|
||||
-record(iq, {id = <<"">> :: binary(),
|
||||
type = get :: get | set | result | error,
|
||||
xmlns = <<"">> :: binary(),
|
||||
lang = <<"">> :: binary(),
|
||||
sub_el = #xmlel{} :: xmlel() | [xmlel()]}).
|
||||
|
||||
-type(iq_get()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: get,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: xmlel()
|
||||
}
|
||||
).
|
||||
|
||||
-type(iq_set()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: set,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: xmlel()
|
||||
}
|
||||
).
|
||||
|
||||
-type iq_request() :: iq_get() | iq_set().
|
||||
|
||||
-type(iq_result()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: result,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: [xmlel()]
|
||||
}
|
||||
).
|
||||
|
||||
-type(iq_error()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: error,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: [xmlel()]
|
||||
}
|
||||
).
|
||||
|
||||
-type iq_reply() :: iq_result() | iq_error() .
|
||||
|
||||
-type(iq() :: iq_request() | iq_reply()).
|
||||
|
||||
-record(rsm_in, {max :: integer(),
|
||||
direction :: before | aft,
|
||||
id :: binary(),
|
||||
index :: integer()}).
|
||||
|
||||
-record(rsm_out, {count :: integer(),
|
||||
index :: integer(),
|
||||
first :: binary(),
|
||||
last :: binary()}).
|
||||
|
||||
-type(rsm_in() :: #rsm_in{}).
|
||||
|
||||
-type(rsm_out() :: #rsm_out{}).
|
||||
|
||||
-type broadcast() :: {broadcast, broadcast_data()}.
|
||||
|
||||
-type broadcast_data() ::
|
||||
{rebind, pid(), binary()} | %% ejabberd_c2s
|
||||
{item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster
|
||||
{exit, binary()} | %% mod_roster/mod_shared_roster
|
||||
{privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy
|
||||
{blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking
|
||||
|
||||
-record(xmlelement, {name = "" :: string(),
|
||||
attrs = [] :: [{string(), string()}],
|
||||
children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
|
||||
|
||||
-type xmlelement() :: #xmlelement{}.
|
||||
@@ -0,0 +1 @@
|
||||
-define(IS_VALID, true).
|
||||
@@ -1,6 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -11,27 +11,26 @@
|
||||
%%% 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
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
-define(PRINT(Format, Args), io:format(Format, Args)).
|
||||
|
||||
-record(privacy, {us,
|
||||
default = none,
|
||||
lists = []}).
|
||||
-define(DEBUG(Format, Args),
|
||||
ejabberd_logger:debug_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-record(listitem, {type = none,
|
||||
value = none,
|
||||
action,
|
||||
order,
|
||||
match_all = false,
|
||||
match_iq = false,
|
||||
match_message = false,
|
||||
match_presence_in = false,
|
||||
match_presence_out = false
|
||||
}).
|
||||
-define(INFO_MSG(Format, Args),
|
||||
ejabberd_logger:info_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-record(userlist, {name = none, list = []}).
|
||||
-define(WARNING_MSG(Format, Args),
|
||||
ejabberd_logger:warning_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(ERROR_MSG(Format, Args),
|
||||
ejabberd_logger:error_msg(?MODULE, ?LINE, Format, Args)).
|
||||
|
||||
-define(CRITICAL_MSG(Format, Args),
|
||||
ejabberd_logger:critical_msg(?MODULE, ?LINE, Format, Args)).
|
||||
@@ -0,0 +1,117 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(MAX_USERS_DEFAULT, 200).
|
||||
|
||||
-define(SETS, gb_sets).
|
||||
|
||||
-define(DICT, dict).
|
||||
|
||||
-record(lqueue,
|
||||
{
|
||||
queue :: queue(),
|
||||
len :: integer(),
|
||||
max :: integer()
|
||||
}).
|
||||
|
||||
-type lqueue() :: #lqueue{}.
|
||||
|
||||
-record(config,
|
||||
{
|
||||
title = <<"">> :: binary(),
|
||||
description = <<"">> :: binary(),
|
||||
allow_change_subj = true :: boolean(),
|
||||
allow_query_users = true :: boolean(),
|
||||
allow_private_messages = true :: boolean(),
|
||||
allow_private_messages_from_visitors = anyone :: anyone | moderators | nobody ,
|
||||
allow_visitor_status = true :: boolean(),
|
||||
allow_visitor_nickchange = true :: boolean(),
|
||||
public = true :: boolean(),
|
||||
public_list = true :: boolean(),
|
||||
persistent = false :: boolean(),
|
||||
moderated = true :: boolean(),
|
||||
captcha_protected = false :: boolean(),
|
||||
members_by_default = true :: boolean(),
|
||||
members_only = false :: boolean(),
|
||||
allow_user_invites = false :: boolean(),
|
||||
password_protected = false :: boolean(),
|
||||
password = <<"">> :: binary(),
|
||||
anonymous = true :: boolean(),
|
||||
allow_voice_requests = true :: boolean(),
|
||||
voice_request_min_interval = 1800 :: non_neg_integer(),
|
||||
max_users = ?MAX_USERS_DEFAULT :: non_neg_integer() | none,
|
||||
logging = false :: boolean(),
|
||||
captcha_whitelist = (?SETS):empty() :: gb_set()
|
||||
}).
|
||||
|
||||
-type config() :: #config{}.
|
||||
|
||||
-type role() :: moderator | participant | visitor | none.
|
||||
|
||||
-record(user,
|
||||
{
|
||||
jid :: jid(),
|
||||
nick :: binary(),
|
||||
role :: role(),
|
||||
last_presence :: xmlel()
|
||||
}).
|
||||
|
||||
-record(activity,
|
||||
{
|
||||
message_time = 0 :: integer(),
|
||||
presence_time = 0 :: integer(),
|
||||
message_shaper :: shaper:shaper(),
|
||||
presence_shaper :: shaper:shaper(),
|
||||
message :: xmlel(),
|
||||
presence :: {binary(), xmlel()}
|
||||
}).
|
||||
|
||||
-record(state,
|
||||
{
|
||||
room = <<"">> :: binary(),
|
||||
host = <<"">> :: binary(),
|
||||
server_host = <<"">> :: binary(),
|
||||
access = {none,none,none,none} :: {atom(), atom(), atom(), atom()},
|
||||
jid = #jid{} :: jid(),
|
||||
config = #config{} :: config(),
|
||||
users = (?DICT):new() :: dict(),
|
||||
last_voice_request_time = treap:empty() :: treap:treap(),
|
||||
robots = (?DICT):new() :: dict(),
|
||||
nicks = (?DICT):new() :: dict(),
|
||||
affiliations = (?DICT):new() :: dict(),
|
||||
history :: lqueue(),
|
||||
persist_history = false :: boolean(),
|
||||
subject = <<"">> :: binary(),
|
||||
subject_author = <<"">> :: binary(),
|
||||
just_created = false :: boolean(),
|
||||
activity = treap:empty() :: treap:treap(),
|
||||
room_shaper = none :: shaper:shaper(),
|
||||
room_queue = queue:new() :: queue()
|
||||
}).
|
||||
|
||||
-record(muc_online_users, {us = {<<>>, <<>>} :: {binary(), binary()},
|
||||
resource = <<>> :: binary() | '_',
|
||||
room = <<>> :: binary() | '_',
|
||||
host = <<>> :: binary() | '_'}).
|
||||
|
||||
-type muc_online_users() :: #muc_online_users{}.
|
||||
|
||||
-type muc_room_state() :: #state{}.
|
||||
@@ -0,0 +1,46 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(mod_privacy_hrl, true).
|
||||
|
||||
-record(privacy, {us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||
default = none :: none | binary(),
|
||||
lists = [] :: [{binary(), [listitem()]}]}).
|
||||
|
||||
-record(listitem, {type = none :: none | jid | group | subscription,
|
||||
value = none :: none | both | from | to | ljid() | binary(),
|
||||
action = allow :: allow | deny,
|
||||
order = 0 :: integer(),
|
||||
match_all = false :: boolean(),
|
||||
match_iq = false :: boolean(),
|
||||
match_message = false :: boolean(),
|
||||
match_presence_in = false :: boolean(),
|
||||
match_presence_out = false :: boolean()}).
|
||||
|
||||
-type listitem() :: #listitem{}.
|
||||
|
||||
-record(userlist, {name = none :: none | binary(),
|
||||
list = [] :: [listitem()],
|
||||
needdb = false :: boolean()}).
|
||||
|
||||
-type userlist() :: #userlist{}.
|
||||
|
||||
-export_type([userlist/0]).
|
||||
@@ -2,7 +2,7 @@
|
||||
%%% RFC 1928 constants.
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2008 Process-one
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
@@ -13,7 +13,7 @@
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
@@ -21,41 +21,48 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%% Version
|
||||
-define(VERSION_5, 5).
|
||||
|
||||
%% Authentication methods
|
||||
-define(AUTH_ANONYMOUS, 0).
|
||||
-define(AUTH_GSSAPI, 1).
|
||||
-define(AUTH_PLAIN, 2).
|
||||
-define(AUTH_NO_METHODS, 16#FF).
|
||||
|
||||
%% Address Type
|
||||
-define(AUTH_GSSAPI, 1).
|
||||
|
||||
-define(AUTH_PLAIN, 2).
|
||||
|
||||
-define(AUTH_NO_METHODS, 255).
|
||||
|
||||
-define(ATYP_IPV4, 1).
|
||||
|
||||
-define(ATYP_DOMAINNAME, 3).
|
||||
|
||||
-define(ATYP_IPV6, 4).
|
||||
|
||||
%% Commands
|
||||
-define(CMD_CONNECT, 1).
|
||||
|
||||
-define(CMD_BIND, 2).
|
||||
|
||||
-define(CMD_UDP, 3).
|
||||
|
||||
%% RFC 1928 replies
|
||||
-define(SUCCESS, 0).
|
||||
|
||||
-define(ERR_GENERAL_FAILURE, 1).
|
||||
|
||||
-define(ERR_NOT_ALLOWED, 2).
|
||||
|
||||
-define(ERR_NETWORK_UNREACHABLE, 3).
|
||||
|
||||
-define(ERR_HOST_UNREACHABLE, 4).
|
||||
|
||||
-define(ERR_CONNECTION_REFUSED, 5).
|
||||
|
||||
-define(ERR_TTL_EXPIRED, 6).
|
||||
|
||||
-define(ERR_COMMAND_NOT_SUPPORTED, 7).
|
||||
|
||||
-define(ERR_ADDRESS_TYPE_NOT_SUPPORTED, 8).
|
||||
|
||||
%% RFC 1928 defined timeout.
|
||||
-define(SOCKS5_REPLY_TIMEOUT, 10000).
|
||||
|
||||
-record(s5_request, {
|
||||
rsv = 0,
|
||||
cmd,
|
||||
sha1
|
||||
}).
|
||||
-record(s5_request, {rsv = 0 :: integer(),
|
||||
cmd = connect :: connect | udp,
|
||||
sha1 = <<"">> :: binary()}).
|
||||
@@ -0,0 +1,42 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License
|
||||
%%% along with this program; if not, write to the Free Software
|
||||
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
%%% 02111-1307 USA
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-record(roster,
|
||||
{
|
||||
usj = {<<>>, <<>>, {<<>>, <<>>, <<>>}} :: {binary(), binary(), ljid()} | '_',
|
||||
us = {<<>>, <<>>} :: {binary(), binary()} | '_',
|
||||
jid = {<<>>, <<>>, <<>>} :: ljid(),
|
||||
name = <<>> :: binary() | '_',
|
||||
subscription = none :: subscription() | '_',
|
||||
ask = none :: ask() | '_',
|
||||
groups = [] :: [binary()] | '_',
|
||||
askmessage = <<"">> :: binary() | '_',
|
||||
xs = [] :: [xmlel()] | '_'
|
||||
}).
|
||||
|
||||
-record(roster_version,
|
||||
{
|
||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
||||
version = <<>> :: binary()
|
||||
}).
|
||||
|
||||
-type ask() :: none | in | out | both | subscribe | unsubscribe.
|
||||
-type subscription() :: none | both | from | to | remove.
|
||||
@@ -0,0 +1,207 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% copyright 2006-2013 ProcessOne
|
||||
%%%
|
||||
%%% This file contains pubsub types definition.
|
||||
%%% ====================================================================
|
||||
|
||||
-define(ERR_EXTENDED(E, C),
|
||||
mod_pubsub:extended_error(E, C)).
|
||||
|
||||
-define(MAXITEMS, 10).
|
||||
|
||||
-define(MAX_PAYLOAD_SIZE, 60000).
|
||||
|
||||
%% -------------------------------
|
||||
%% Pubsub types
|
||||
|
||||
-type(hostPubsub() :: binary()).
|
||||
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
||||
%% <tt>"pubsub.localhost"</tt>.</p>
|
||||
|
||||
-type(hostPEP() :: {binary(), binary(), <<>>}).
|
||||
%% @type hostPEP() = {User, Server, Resource}
|
||||
%% User = string()
|
||||
%% Server = string()
|
||||
%% Resource = [].
|
||||
%% <p>For example, it can be :
|
||||
%% ```{"bob", "example.org", []}'''.</p>
|
||||
|
||||
-type(host() :: hostPubsub() | hostPEP()).
|
||||
%% @type host() = hostPubsub() | hostPEP().
|
||||
|
||||
-type(nodeId() :: binary()).
|
||||
%% @type nodeId() = binary().
|
||||
%% <p>A node is defined by a list of its ancestors. The last element is the name
|
||||
%% of the current node. For example:
|
||||
%% ```<<"/home/localhost/user">>'''</p>
|
||||
|
||||
-type(nodeIdx() :: pos_integer()).
|
||||
%% @type nodeIdx() = integer().
|
||||
|
||||
-type(itemId() :: binary()).
|
||||
%% @type itemId() = string().
|
||||
|
||||
-type(subId() :: binary()).
|
||||
%% @type subId() = string().
|
||||
|
||||
|
||||
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
|
||||
|
||||
%% @type stanzaError() = #xmlelement{}.
|
||||
%% Example:
|
||||
%% ```{xmlelement, "error",
|
||||
%% [{"code", Code}, {"type", Type}],
|
||||
%% [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}'''
|
||||
%% @type pubsubIQResponse() = #xmlelement{}.
|
||||
%% Example:
|
||||
%% ```{xmlelement, "pubsub",
|
||||
%% [{"xmlns", ?NS_PUBSUB_EVENT}],
|
||||
%% [{xmlelement, "affiliations", [],
|
||||
%% []}]}'''
|
||||
|
||||
-type(nodeOption() ::
|
||||
{Option::atom(),
|
||||
Value::binary() | [binary()] | boolean() | non_neg_integer()
|
||||
}).
|
||||
|
||||
-type(nodeOptions() :: [NodeOption::mod_pubsub:nodeOption(),...]).
|
||||
|
||||
%% @type nodeOption() = {Option, Value}
|
||||
%% Option = atom()
|
||||
%% Value = term().
|
||||
%% Example:
|
||||
%% ```{deliver_payloads, true}'''
|
||||
|
||||
-type(subOption() ::
|
||||
{Option::atom(),
|
||||
Value::binary() | [binary()] | boolean()
|
||||
}).
|
||||
|
||||
-type(subOptions() :: [SubOption::mod_pubsub:subOption(),...]).
|
||||
|
||||
%% @type nodeType() = string().
|
||||
%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub
|
||||
%% plugin to use to manage a given node. For example, it can be
|
||||
%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p>
|
||||
|
||||
%% @type jid() = {jid, User, Server, Resource, LUser, LServer, LResource}
|
||||
%% User = string()
|
||||
%% Server = string()
|
||||
%% Resource = string()
|
||||
%% LUser = string()
|
||||
%% LServer = string()
|
||||
%% LResource = string().
|
||||
|
||||
%-type(ljid() :: {binary(), binary(), binary()}).
|
||||
%% @type ljid() = {User, Server, Resource}
|
||||
%% User = string()
|
||||
%% Server = string()
|
||||
%% Resource = string().
|
||||
|
||||
-type(affiliation() :: 'none'
|
||||
| 'owner'
|
||||
| 'publisher'
|
||||
%| 'publish-only'
|
||||
| 'member'
|
||||
| 'outcast'
|
||||
).
|
||||
%% @type affiliation() = 'none' | 'owner' | 'publisher' | 'publish-only' | 'member' | 'outcast'.
|
||||
|
||||
-type(subscription() :: 'none'
|
||||
| 'pending'
|
||||
| 'unconfigured'
|
||||
| 'subscribed'
|
||||
).
|
||||
%% @type subscription() = 'none' | 'pending' | 'unconfigured' | 'subscribed'.
|
||||
|
||||
-type(accessModel() :: 'open'
|
||||
| 'presence'
|
||||
| 'roster'
|
||||
| 'authorize'
|
||||
| 'whitelist'
|
||||
).
|
||||
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
||||
|
||||
-type(publishModel() :: 'publishers'
|
||||
| 'subscribers'
|
||||
| 'open'
|
||||
).
|
||||
|
||||
|
||||
-record(pubsub_index,
|
||||
{
|
||||
index :: atom(),
|
||||
last :: mod_pubsub:nodeIdx(),
|
||||
free :: [mod_pubsub:nodeIdx()]
|
||||
}).
|
||||
|
||||
-record(pubsub_node,
|
||||
{
|
||||
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
|
||||
id ,%:: mod_pubsub:nodeIdx(),
|
||||
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()],
|
||||
type = <<"flat">> ,%:: binary(),
|
||||
owners = [] ,%:: [Owner::ljid(),...],
|
||||
options = [] %:: mod_pubsub:nodeOptions()
|
||||
}).
|
||||
|
||||
|
||||
%-record(pubsub_state,
|
||||
% {stateid, nodeidx, items = [], affiliation = none,
|
||||
% subscriptions = []}).
|
||||
-record(pubsub_state,
|
||||
{
|
||||
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: mod_pubsub:nodeIdx(),
|
||||
items = [] ,%:: [ItemId::mod_pubsub:itemId()],
|
||||
affiliation = 'none' ,%:: mod_pubsub:affiliation(),
|
||||
subscriptions = [] %:: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
||||
}).
|
||||
|
||||
%-record(pubsub_item,
|
||||
% {itemid, nodeidx, creation = {unknown, unknown},
|
||||
% modification = {unknown, unknown}, payload = []}).
|
||||
|
||||
-record(pubsub_item,
|
||||
{
|
||||
itemid ,%:: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: mod_pubsub_nodeIdx(),
|
||||
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
||||
payload = [] %:: mod_pubsub:payload()
|
||||
}).
|
||||
|
||||
%-record(pubsub_subscription, {subid, options}).
|
||||
-record(pubsub_subscription,
|
||||
{
|
||||
subid ,%:: mod_pubsub:subId(),
|
||||
options %:: [] | mod_pubsub:subOptions()
|
||||
}).
|
||||
|
||||
%-record(pubsub_last_item,
|
||||
% {nodeid, itemid, creation, payload}).
|
||||
|
||||
-record(pubsub_last_item,
|
||||
{
|
||||
nodeid ,%:: mod_pubsub:nodeIdx(),
|
||||
itemid ,%:: mod_pubsub:itemId(),
|
||||
creation ,%:: {erlang:timestamp(), ljid()},
|
||||
payload %:: mod_pubsub:payload()
|
||||
}).
|
||||
+520
@@ -0,0 +1,520 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# 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
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names starting with `-'.
|
||||
case $src in
|
||||
-*) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dst=$dst_arg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
-*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test -z "$d" && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
@@ -0,0 +1,685 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(exmpp_pubsub).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
|
||||
%% --------------------------------------------------------------------
|
||||
%% Documentation / type definitions.
|
||||
%% --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
%-- Affiliations --%
|
||||
-export_type([
|
||||
affiliation/0,
|
||||
%%
|
||||
affiliation_owner/0,
|
||||
affiliation_publisher/0,
|
||||
affiliation_publish_only/0,
|
||||
affiliation_member/0,
|
||||
affiliation_none/0,
|
||||
affiliation_outcast/0
|
||||
]).
|
||||
|
||||
%% @type affiliation_owner() = 'owner'.
|
||||
-type(affiliation_owner() :: 'owner').
|
||||
|
||||
%% @type affiliation_publisher() = 'publisher'.
|
||||
-type(affiliation_publisher() :: 'publisher').
|
||||
|
||||
%% @type affiliation_publish_only() = 'publish-only'.
|
||||
-type(affiliation_publish_only() :: 'publish-only').
|
||||
|
||||
%% @type affiliation_member() = 'member'.
|
||||
-type(affiliation_member() :: 'member').
|
||||
|
||||
%% @type affiliation_none() = 'none'.
|
||||
-type(affiliation_none() :: 'none').
|
||||
|
||||
%% @type affiliation_outcast() = 'outcast'.
|
||||
-type(affiliation_outcast() :: 'outcast').
|
||||
|
||||
%% @type affiliation() = Owner | Publisher | Publish_Only | Member | None | Outcast
|
||||
%% Owner = exmpp_pubsub:affiliation_owner()
|
||||
%% Publisher = exmpp_pubsub:affiliation_publisher()
|
||||
%% Publish_Only = exmpp_pubsub:affiliation_publish_only()
|
||||
%% Member = exmpp_pubsub:affiliation_member()
|
||||
%% None = exmpp_pubsub:affiliation_none()
|
||||
%% Outcast = exmpp_pubsub:affiliation_outcast().
|
||||
-type(affiliation() :: exmpp_pubsub:affiliation_owner()
|
||||
| exmpp_pubsub:affiliation_publisher()
|
||||
| exmpp_pubsub:affiliation_publish_only()
|
||||
| exmpp_pubsub:affiliation_member()
|
||||
| exmpp_pubsub:affiliation_none()
|
||||
| exmpp_pubsub:affiliation_outcast()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Things identifiers --%
|
||||
-export_type([
|
||||
index/0,
|
||||
itemId/0,
|
||||
itemIds/0,
|
||||
level/0,
|
||||
nodeId/0,
|
||||
nodeIdx/0,
|
||||
subId/0,
|
||||
plugin/0
|
||||
]).
|
||||
|
||||
%% @type index() = 'node'.
|
||||
-type(index() :: 'node' ).
|
||||
|
||||
%% @type itemId() = binary().
|
||||
-type(itemId() :: binary()).
|
||||
|
||||
%% @type itemIds() = [ItemId::exmpp_pubsub:itemId(),...].
|
||||
-type(itemIds() :: [ItemId::exmpp_pubsub:itemId(),...]).
|
||||
|
||||
%% @type level() = non_neg_integer().
|
||||
-type(level() :: non_neg_integer()).
|
||||
|
||||
%% @type nodeId() = binary().
|
||||
-type(nodeId() :: binary()).
|
||||
|
||||
%% @type nodeIdx() = non_neg_integer().
|
||||
-type(nodeIdx() :: non_neg_integer()).
|
||||
|
||||
%% @type plugin() = module().
|
||||
-type(plugin() :: module()).
|
||||
|
||||
%% @type subId() = binary().
|
||||
-type(subId() :: binary()).
|
||||
|
||||
|
||||
-export_type([
|
||||
t_now/0
|
||||
]).
|
||||
|
||||
%% Temporary -type, until calendar.erl -type is exported
|
||||
-type(t_now()
|
||||
:: {MegaSec::non_neg_integer(),
|
||||
Sec::non_neg_integer(),
|
||||
MilliSec::non_neg_integer()}
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
feature/0,
|
||||
features/0,
|
||||
pubsub_feature/0,
|
||||
pubsub_features/0
|
||||
]).
|
||||
|
||||
-type(feature() :: binary()).
|
||||
|
||||
-type(features() :: Features::[Feature::exmpp_pubsub:feature(),...]).
|
||||
|
||||
-type(pubsub_feature() :: exmpp_pubsub:feature()).
|
||||
|
||||
-type(pubsub_features() :: Pubsub_Features::[Pubsub_Feature::exmpp_pubsub:feature(),...]).
|
||||
|
||||
%%
|
||||
|
||||
%-- Payload types --%
|
||||
-export_type([
|
||||
payload/0,
|
||||
%%
|
||||
payload_empty/0,
|
||||
payload_full/0
|
||||
]).
|
||||
|
||||
%% @type payload_empty() = [].
|
||||
-type(payload_empty() :: []).
|
||||
|
||||
%% @type payload_full() = #xmlel{}.
|
||||
-type(payload_full() :: xmlel()).
|
||||
|
||||
%% @type payload() = Empty_Payload | Full_Payload
|
||||
%% Empty_Payload = exmpp_pubsub:payload_empty()
|
||||
%% Full_Payload = exmpp_pubsub:payload_full().
|
||||
-type(payload() :: exmpp_pubsub:payload_empty()
|
||||
| exmpp_pubsub:payload_full()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Pusbub Host --%
|
||||
-export_type([
|
||||
host/0,
|
||||
%%
|
||||
host_pubsub/0,
|
||||
host_pep/0
|
||||
]).
|
||||
|
||||
%% @type host_pubsub() = xmpp_jid:domain_jid().
|
||||
%% ```<<"pubsub.shakespeare.lit">>'''
|
||||
%% Identifier type of the Pubsub service
|
||||
-type(host_pubsub() :: binary()).
|
||||
|
||||
%% @type host_pep() = xmpp_jid:usr_contact_bare().
|
||||
%% ```{<<"juliet">>, <<"capulet.lit">>, undefined}'''
|
||||
%% Identifier type of the Pubsub-On-Jid service
|
||||
-type(host_pep() :: xmpp_jid:usr_contact_bare()).
|
||||
|
||||
%% @type host() = Pubsub_Host | Pubsub_On_Jid_Host
|
||||
%% Pubsub_Host = exmpp_pubsub:host_pubsub()
|
||||
%% Pubsub_On_Jid_Host = exmpp_pubsub:host_pep().
|
||||
%% Identifier types of the Pubsub and PEP (Pubsub-On-Jid) services
|
||||
%% ```* Pubsub_Host : <<"pubsub.shakespeare.lit">>
|
||||
%% * Pubsub_PEP : {<<"juliet">>, <<"capulet.lit">>, undefined}'''
|
||||
-type(host() :: exmpp_pubsub:host_pubsub()
|
||||
| exmpp_pubsub:host_pep()
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
%-- Subscription States --%
|
||||
-export_type([
|
||||
subscription_state/0,
|
||||
%%
|
||||
subscription_state_none/0,
|
||||
subscription_state_pending/0,
|
||||
subscription_state_unconfigured/0,
|
||||
subscription_state_subscribed/0
|
||||
]).
|
||||
|
||||
%% @type subscription_state_none() = 'none'.
|
||||
-type(subscription_state_none() :: 'none').
|
||||
|
||||
%% @type subscription_state_pending() = 'pending'.
|
||||
-type(subscription_state_pending() :: 'pending').
|
||||
|
||||
%% @type subscription_state_unconfigured() = 'unconfigured'.
|
||||
-type(subscription_state_unconfigured() :: 'unconfigured').
|
||||
|
||||
%% @type subscription_state_subscribed() = 'subscribed'.
|
||||
-type(subscription_state_subscribed() :: 'subscribed').
|
||||
|
||||
%% @type subscription_state() = None | Pending | Unconfigured | Subscribed
|
||||
%% None = exmpp_pubsub:subscription_state_none()
|
||||
%% Pending = exmpp_pubsub:subscription_state_pending()
|
||||
%% Unconfigured = exmpp_pubsub:subscription_state_unconfigured()
|
||||
%% Subscribed = exmpp_pubsub:subscription_state_subscribed()
|
||||
-type(subscription_state() :: exmpp_pubsub:subscription_state_pending()
|
||||
| exmpp_pubsub:subscription_state_unconfigured()
|
||||
| exmpp_pubsub:subscription_state_subscribed()
|
||||
).
|
||||
|
||||
%%
|
||||
|
||||
%-- Subscription -- %%
|
||||
-export_type([
|
||||
subscriptions/0,
|
||||
subscription/0,
|
||||
%%
|
||||
subscription_subscribed/0,
|
||||
subscription_unconfigured/0,
|
||||
subscription_pending/0
|
||||
]).
|
||||
|
||||
-type(subscription_subscribed()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_subscribed(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription()}
|
||||
).
|
||||
|
||||
-type(subscription_unconfigured()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_unconfigured(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: []}
|
||||
).
|
||||
|
||||
-type(subscription_pending()
|
||||
:: {Subscription_State :: exmpp_pubsub:subscription_state_pending(),
|
||||
SubId :: exmpp_pubsub:subId(),
|
||||
Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: []}
|
||||
).
|
||||
|
||||
%% -type(subscription()
|
||||
%% :: {Subscription_State :: exmpp_pubsub:subscription_state(),
|
||||
%% SubId :: exmpp_pubsub:subId(),
|
||||
%% Resource :: undefined | xmpp_jid:resource_jid() | {'caps', xmpp_jid:resource_jid()},
|
||||
%% Subscription_Options :: [] | pubsub_options:options_subscription()}
|
||||
%% %% :: exmpp_pubsub:subscription_subscribed()
|
||||
%% %% | exmpp_pubsub:subscription_pending()
|
||||
%% %% | exmpp_pubsub:subscription_unconfigured()
|
||||
%% ).
|
||||
|
||||
-type(subscriptions()
|
||||
:: [exmpp_pubsub:subscription(),...]
|
||||
%% :: [exmpp_pubsub:subscription_subscribed(),...]
|
||||
%% | [exmpp_pubsub:subscription_unconfigured(),...]
|
||||
%% | [exmpp_pubsub:subscription_pending(),...]
|
||||
).
|
||||
|
||||
%% TODO : commented -type unions return the following dialyzer error (bug ?) :
|
||||
%% ...
|
||||
%% Adding information from /home/meta/otp-exmpp.plt to ejabberd.plt...
|
||||
%%=ERROR REPORT==== 29-Jul-2011::15:14:42 ===
|
||||
%Error in process <0.2604.0> with exit value: {function_clause,[{erl_types,inf_tuples_in_sets,4},{erl_types,inf_tuple_sets,4},{erl_types,inf_tuple_sets,3},{erl_types,t_inf,3},{erl_types,t_inf_lists_strict,4},{erl_types,t_inf,3},{dialyzer_typesig,solve_one_c...
|
||||
%%
|
||||
%%
|
||||
%%dialyzer: Analysis failed with error: {function_clause,[{erl_types,inf_tuples_in_sets,4},
|
||||
%% {erl_types,inf_tuple_sets,4},
|
||||
%% {erl_types,inf_tuple_sets,3},
|
||||
%% {erl_types,t_inf,3},
|
||||
%% {erl_types,t_inf_lists_strict,4},
|
||||
%% {erl_types,t_inf,3},
|
||||
%% {dialyzer_typesig,solve_one_c,...},
|
||||
%% {dialyzer_typesig,...}]}
|
||||
%%Last messages in the log cache:
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,make_xhtml,5}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,make_xhtml,4}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,process_admin,2}]
|
||||
%% Typesig analysis for SCC: [{ejabberd_web_admin,process,2}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,get_local_stat,3}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,get_local_stats,3}]
|
||||
%% Typesig analysis for SCC: [{mod_stats,process_local_iq,3}]
|
||||
%% Typesig analysis for SCC: [{mod_register_web,send_registration_notifications,2}]
|
||||
%% Typesig analysis for SCC: [{mod_register_web,process,2}]
|
||||
%% Typesig analysis for SCC: [{pubsub_db,create_node,5}]
|
||||
|
||||
%%
|
||||
|
||||
|
||||
%% Pubsub #xmlel{} templates
|
||||
|
||||
|
||||
%% --------------------------------------------------------------------
|
||||
%% Functions.
|
||||
%% --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
%% @spec nodeId() -> NodeId::exmpp_pubsub:nodeId()
|
||||
-spec(nodeId/0 :: () -> NodeId::exmpp_pubsub:nodeId()).
|
||||
|
||||
nodeId() ->
|
||||
randoms:get_string().
|
||||
|
||||
%% @spec subId() -> SubId::exmpp_pubsub:subId()
|
||||
-spec(subId/0 :: () -> SubId::exmpp_pubsub:subId()).
|
||||
|
||||
subId() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
%% @spec itemId() -> ItemId::exmpp_pubsub:itemId()
|
||||
-spec(itemId/0 :: () -> ItemId::exmpp_pubsub:itemId()).
|
||||
|
||||
itemId() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
id() ->
|
||||
{T1, T2, T3} = now(),
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscription_subscribed/2 ::
|
||||
(
|
||||
Resource :: undefined
|
||||
| xmpp_jid:resource_jid()
|
||||
| {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription())
|
||||
-> Subscription_Subscribed::exmpp_pubsub:subscription_subscribed()
|
||||
).
|
||||
|
||||
subscription_subscribed(Resource, Subscription_Options) ->
|
||||
{'subscribed', subId(), Resource, Subscription_Options}.
|
||||
|
||||
%%
|
||||
-spec(subscription_pending/2 ::
|
||||
(
|
||||
Resource :: undefined
|
||||
| xmpp_jid:resource_jid()
|
||||
| {'caps', xmpp_jid:resource_jid()},
|
||||
Subscription_Options :: [] | pubsub_options:options_subscription())
|
||||
-> Subscription_Pending::exmpp_pubsub:subscription_pending()
|
||||
).
|
||||
|
||||
subscription_pending(Resource, Subscription_Options) ->
|
||||
{'pending', subId(), Resource, Subscription_Options}.
|
||||
|
||||
|
||||
|
||||
%% Pubsub Xmlel templates
|
||||
|
||||
xmlcdata(CData) ->
|
||||
{xmlcdata, CData}.
|
||||
|
||||
xmlattr(Name, Value) ->
|
||||
{Name, Value}.
|
||||
|
||||
|
||||
xmlel('disco#info', Name, Attrs, Children) ->
|
||||
xmlel(?NS_DISCO_INFO, Name, Attrs, Children);
|
||||
xmlel('disco#items', Name, Attrs, Children) ->
|
||||
xmlel(?NS_DISCO_ITEMS, Name, Attrs, Children);
|
||||
xmlel('jabber:client', Name, Attrs, Children) ->
|
||||
xmlel(?NS_JABBER_CLIENT, Name, Attrs, Children);
|
||||
xmlel('pubsub', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB, Name, Attrs, Children);
|
||||
xmlel('pubsub#event', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB_EVENT, Name, Attrs, Children);
|
||||
xmlel('pubsub#owner', Name, Attrs, Children) ->
|
||||
xmlel(?NS_PUBSUB_OWNER, Name, Attrs, Children);
|
||||
xmlel('shim', Name, Attrs, Children) ->
|
||||
xmlel(?NS_SHIM, Name, Attrs, Children);
|
||||
xmlel(NS, Name, Attrs, Children) ->
|
||||
#xmlel{name = Name, attrs = [{<<"xmlns">>, NS} | Attrs], children = Children}.
|
||||
%%
|
||||
xmlattr_affiliation(Affiliation) ->
|
||||
xmlattr(<<"affiliation">>, list_to_binary(atom_to_list(Affiliation))).
|
||||
%%
|
||||
xmlattr_category(Category) ->
|
||||
xmlattr(<<"category">>, Category).
|
||||
%%
|
||||
xmlattr_id(ItemId) ->
|
||||
xmlattr(<<"id">>, ItemId).
|
||||
%%
|
||||
xmlattr_jid(Jid) ->
|
||||
xmlattr(<<"jid">>, Jid).
|
||||
%%
|
||||
xmlattr_name(Name) ->
|
||||
xmlattr(<<"name">>, Name).
|
||||
%%
|
||||
xmlattr_node(NodeId) ->
|
||||
xmlattr(<<"node">>, NodeId).
|
||||
%%
|
||||
xmlattr_publisher(Publisher) ->
|
||||
xmlattr(<<"publisher">>, Publisher).
|
||||
%%
|
||||
xmlattr_subid(SubId) ->
|
||||
xmlattr(<<"subid">>, SubId).
|
||||
%%
|
||||
xmlattr_subscription(Subscription_State) ->
|
||||
xmlattr(<<"subscription">>, list_to_binary(atom_to_list(Subscription_State))).
|
||||
%%
|
||||
xmlattr_type(Type) when is_atom(Type)->
|
||||
xmlattr(<<"type">>, list_to_binary(atom_to_list(Type)));
|
||||
%%
|
||||
xmlattr_type(Type) ->
|
||||
xmlattr(<<"type">>, Type).
|
||||
%%
|
||||
xmlattr_uri(URI) ->
|
||||
xmlattr(<<"uri">>, URI).
|
||||
%%
|
||||
xmlattr_var(Var) ->
|
||||
xmlattr(<<"var">>, Var).
|
||||
|
||||
%%
|
||||
xmlel_affiliation('pubsub', NodeId, Affiliation) ->
|
||||
xmlel('pubsub', <<"affiliation">>,
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_affiliation(Affiliation)],
|
||||
[]);
|
||||
xmlel_affiliation('pubsub#owner', Jid, Affiliation) ->
|
||||
xmlel('pubsub#owner', <<"affiliation">>,
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_affiliation(Affiliation)],
|
||||
[]).
|
||||
%%
|
||||
xmlel_affiliations('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"affiliations">>, [], Xmlels).
|
||||
|
||||
xmlel_affiliations('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"affiliations">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_create(NodeId) ->
|
||||
xmlel('pubsub', <<"create">>, [xmlattr_node(NodeId)], []).
|
||||
|
||||
%%
|
||||
xmlel_configure('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"configure">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_default('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"default">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_default('pubsub#owner', Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"default">>, [], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_default('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"default">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_delete(NodeId, RedirectURI) ->
|
||||
xmlel('pubsub#event', <<"delete">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
case RedirectURI of
|
||||
undefined -> [];
|
||||
_RedirectURI -> [xmlel_redirect(RedirectURI)]
|
||||
end).
|
||||
%%
|
||||
xmlel_event(Xmlels) ->
|
||||
xmlel('pubsub#event', <<"event">>, [], Xmlels).
|
||||
%%
|
||||
xmlel_feature('disco#info', Feature) ->
|
||||
xmlel('disco#info', <<"feature">>, [xmlattr_var(Feature)], []).
|
||||
%%
|
||||
xmlel_header(SubId) ->
|
||||
xmlel('shim', <<"header">>, [xmlattr_name(<<"SubID">>)], [xmlcdata(SubId)]).
|
||||
%%
|
||||
xmlel_headers(Xmlels_Header) ->
|
||||
xmlel('shim', <<"headers">>, [], Xmlels_Header).
|
||||
|
||||
|
||||
xmlel_identity('disco#info', Category, Type, Name) ->
|
||||
xmlel('disco#info', <<"identity">>,
|
||||
case Name of
|
||||
undefined ->
|
||||
[xmlattr_category(Category),
|
||||
xmlattr_type(Type)];
|
||||
_ ->
|
||||
[xmlattr_category(Category),
|
||||
xmlattr_name(Name),
|
||||
xmlattr_type(Type)]
|
||||
end,
|
||||
[]).
|
||||
|
||||
%%
|
||||
xmlel_item('pubsub', ItemId) ->
|
||||
xmlel('pubsub', <<"item">>, [xmlattr_id(ItemId)], []).
|
||||
|
||||
%%
|
||||
xmlel_item('disco#items', ItemId, Jid) ->
|
||||
xmlel('disco#items', <<"item">>,
|
||||
[xmlattr_name(ItemId),
|
||||
xmlattr_jid(Jid)],
|
||||
[]);
|
||||
xmlel_item('pubsub', ItemId, Payload) ->
|
||||
xmlel('pubsub', <<"item">>, [xmlattr_id(ItemId)],
|
||||
case Payload of
|
||||
[] -> [];
|
||||
_Payload -> [Payload]
|
||||
end).
|
||||
|
||||
xmlel_item('disco#items', NodeId, Jid, Name) ->
|
||||
xmlel('disco#items', <<"item">>,
|
||||
case Name of
|
||||
undefined ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_node(NodeId)];
|
||||
_ ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_node(NodeId),
|
||||
xmlattr_name(Name)]
|
||||
end,
|
||||
[]);
|
||||
%%
|
||||
xmlel_item('pubsub#event', ItemId, Publisher, Payload) ->
|
||||
xmlel('pubsub#event', <<"item">>,
|
||||
case Publisher of
|
||||
undefined ->
|
||||
[xmlattr_id(ItemId)];
|
||||
_Publisher ->
|
||||
[xmlattr_id(ItemId),
|
||||
xmlattr_publisher(Publisher)]
|
||||
end,
|
||||
case Payload of
|
||||
[] -> [];
|
||||
_Payload -> [Payload]
|
||||
end).
|
||||
%%
|
||||
xmlel_items('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"items">>, [xmlattr_node(NodeId)], Xmlels);
|
||||
%%
|
||||
xmlel_items('pubsub#event', undefined = _NodeId, Xmlels) ->
|
||||
xmlel('pubsub#event', <<"items">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_items('pubsub#event', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#event', <<"items">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_items('pubsub#event', NodeId, undefined = _ItemId, _Publisher, _Payload) ->
|
||||
xmlel('pubsub#event', <<"items">>, [xmlattr_node(NodeId)], []);
|
||||
xmlel_items('pubsub#event', NodeId, ItemId, Publisher, Payload) ->
|
||||
xmlel('pubsub#event', <<"items">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
[xmlel_item('pubsub#event', ItemId, Publisher, Payload)]).
|
||||
%%
|
||||
xmlel_message(undefined = _Type, Xmlels) ->
|
||||
xmlel_message('normal', Xmlels);
|
||||
xmlel_message(Type, Xmlels) ->
|
||||
xmlel('jabber:client', <<"message">>,
|
||||
[xmlattr_type(Type),
|
||||
xmlattr_id(_Id = id())],
|
||||
Xmlels).
|
||||
%%
|
||||
xmlel_options('pubsub', NodeId, Jid, SubId, Xmlels) ->
|
||||
xmlel('pubsub', <<"options">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid)];
|
||||
_ ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId)]
|
||||
end,
|
||||
Xmlels).
|
||||
%%
|
||||
xmlel_publish('pubsub', NodeId, Xmlels) ->
|
||||
xmlel('pubsub', <<"publish">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_purge(NodeId) ->
|
||||
xmlel('pubsub#event', <<"purge">>, [xmlattr_node(NodeId)], []).
|
||||
|
||||
%%
|
||||
xmlel_query('disco#info', Xmlels) ->
|
||||
xmlel('disco#info', <<"query">>, [], Xmlels);
|
||||
%%
|
||||
xmlel_query('disco#items', Xmlels) ->
|
||||
xmlel('disco#items', <<"query">>, [], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_query('disco#info', NodeId, Xmlels) ->
|
||||
xmlel('disco#info', <<"query">>, [xmlattr_node(NodeId)], Xmlels);
|
||||
xmlel_query('disco#items', NodeId, Xmlels) ->
|
||||
xmlel('disco#items', 'query', [xmlattr_node(NodeId)], Xmlels).
|
||||
|
||||
%%
|
||||
xmlel_redirect(RedirectURI) ->
|
||||
xmlel('pubsub#event', <<"redirect">>, [xmlattr_uri(RedirectURI)], []).
|
||||
%%
|
||||
xmlel_retract(undefined = _ItemId) ->
|
||||
xmlel('pubsub#event', <<"retract">>, [], []);
|
||||
xmlel_retract(ItemId) ->
|
||||
xmlel('pubsub#event', <<"retract">>, [xmlattr_id(ItemId)], []).
|
||||
%%
|
||||
xmlel_subscription('pubsub', NodeId, Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub', <<"subscription">>,
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)],
|
||||
[]);
|
||||
xmlel_subscription('pubsub#event', NodeId, Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub#event', <<"subscription">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subscription(Subscription_State)];
|
||||
_SubId ->
|
||||
[xmlattr_node(NodeId),
|
||||
xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)]
|
||||
end,
|
||||
[]).
|
||||
%%
|
||||
xmlel_subscription('pubsub#owner', Jid, SubId, Subscription_State) ->
|
||||
xmlel('pubsub#owner', <<"subscription">>,
|
||||
case SubId of
|
||||
undefined ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_subscription(Subscription_State)];
|
||||
_SubId ->
|
||||
[xmlattr_jid(Jid),
|
||||
xmlattr_subid(SubId),
|
||||
xmlattr_subscription(Subscription_State)]
|
||||
end,
|
||||
[]).
|
||||
%%
|
||||
xmlel_subscriptions('pubsub', Xmlels) ->
|
||||
xmlel('pubsub', <<"subscriptions">>, [], Xmlels).
|
||||
|
||||
xmlel_subscriptions('pubsub#owner', NodeId, Xmlels) ->
|
||||
xmlel('pubsub#owner', <<"subscriptions">>, [xmlattr_node(NodeId)], Xmlels).
|
||||
%%
|
||||
xmlel_publish(NodeId, undefined = _ItemId) ->
|
||||
xmlel('pubsub', <<"publish">>, [xmlattr_node(NodeId)], []);
|
||||
xmlel_publish(NodeId, ItemId) ->
|
||||
xmlel('pubsub', <<"publish">>,
|
||||
[xmlattr_node(NodeId)],
|
||||
[xmlel_item('pubsub', ItemId)]).
|
||||
%%
|
||||
xmlel_pubsub('pubsub', Children) ->
|
||||
xmlel('pubsub', <<"pubsub">>, [], Children);
|
||||
%%
|
||||
xmlel_pubsub('pubsub#owner', Children) ->
|
||||
xmlel('pubsub#owner', <<"pubsub">>, [], Children).
|
||||
|
||||
@@ -0,0 +1,863 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(mod_pubsub_dev).
|
||||
-author('christophe.romain@process-one.net').
|
||||
-author('karim.gemayel@process-one.net').
|
||||
-version('1.13-0').
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
-include("pubsub_api.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
%%% Export Functions
|
||||
|
||||
%% API and gen_server callbacks
|
||||
-export([
|
||||
start_link/2,
|
||||
start/2,
|
||||
stop/1,
|
||||
init/1,
|
||||
handle_call/3,
|
||||
handle_cast/2,
|
||||
handle_info/2,
|
||||
terminate/2,
|
||||
code_change/3
|
||||
]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
resource_show/0,
|
||||
presence_cache/0
|
||||
]).
|
||||
|
||||
-type(resource_show()
|
||||
:: {Resource :: xmpp_jid:resource_jid(),
|
||||
Show :: 'away' | 'chat' | 'dnd' | 'online' | 'xa' }
|
||||
).
|
||||
|
||||
-type(presence_cache() :: [Resource_Show::resource_show()]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
resource_subids/0,
|
||||
resources_subids/0
|
||||
]).
|
||||
|
||||
-type(resource_subids()
|
||||
:: {Resource :: xmpp_jid:resource_jid(),
|
||||
SubIds :: [SubId::exmpp_pubsub:subId(),...]}
|
||||
).
|
||||
|
||||
-type(resources_subids() :: [Resource_SubIds::resource_subids(),...]).
|
||||
|
||||
%%%
|
||||
-export_type([
|
||||
entity/0,
|
||||
n0de/0,
|
||||
cache/0,
|
||||
subids/0,
|
||||
event/0
|
||||
]).
|
||||
|
||||
-type(entity() :: #entity{}).
|
||||
% id :: xmpp_jid:usr_bare(),
|
||||
% affiliation :: 'member' | 'owner' | 'publisher',
|
||||
% subscriptions :: []%[exmpp_pubsub:subscription(),...]
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(n0de() :: #node{}).
|
||||
% id :: exmpp_pubsub:nodeId(),
|
||||
% owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
% access_model :: pubsub_options:access_model(),
|
||||
% itemreply :: 'owner' | 'publisher',
|
||||
% notification_type :: 'headline' | 'normal',
|
||||
% presence_based_delivery :: boolean(),
|
||||
% rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed()
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(cache() :: #cache{}).
|
||||
% presence :: undefined | mod_pubsub_dev:presence_cache(),
|
||||
% presence_subscriptions :: undefined | boolean(),
|
||||
% rosters_groups :: undefined | boolean()
|
||||
%}).
|
||||
|
||||
%%%
|
||||
-type(subids() :: #subids{}).
|
||||
% presence :: undefined | [] | mod_pubsub_dev:resources_subids(),
|
||||
% no_presence :: undefined | [] | mod_pubsub_dev:resources_subids()
|
||||
%}).
|
||||
|
||||
%%
|
||||
-type(event() :: #event{
|
||||
% host :: xmpp_jid:raw_jid_component_bare(),
|
||||
% component :: xmpp_jid:component_bare(),
|
||||
% entity :: mod_pubsub_dev:entity(),
|
||||
% node :: mod_pubsub_dev:n0de(),
|
||||
% cache :: mod_pubsub_dev:cache(),
|
||||
% subids :: mod_pubsub_dev:subids()
|
||||
}).
|
||||
|
||||
%%%
|
||||
-export_type([
|
||||
item/0,
|
||||
published_item/0,
|
||||
retracted_item/0
|
||||
]).
|
||||
|
||||
-type(published_item() :: #item{
|
||||
access_model :: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery :: undefined | boolean(),
|
||||
rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed(),
|
||||
stanza :: xmlel()
|
||||
}).
|
||||
|
||||
-type(retracted_item() :: #item{
|
||||
access_model :: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery :: undefined | boolean(),
|
||||
rosters_groups_allowed :: [] | pubsub_options:rosters_groups_allowed(),
|
||||
stanza :: xmlel()
|
||||
}).
|
||||
|
||||
-type(item() :: published_item() | retracted_item()).
|
||||
|
||||
|
||||
%%
|
||||
|
||||
-export_type([
|
||||
pubsub_itemId/0,
|
||||
pubsub_nodeId/0,
|
||||
pubsub_stateId/0,
|
||||
item_owners/0,
|
||||
node_owners/0,
|
||||
item_creation/0,
|
||||
item_modification/0,
|
||||
node_creation/0
|
||||
]).
|
||||
|
||||
-type(pubsub_itemId()
|
||||
:: {ItemId::exmpp_pubsub:itemId(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
).
|
||||
|
||||
-type(pubsub_nodeId()
|
||||
:: {Pubsub_Host :: exmpp_pubsub:host(), NodeId :: exmpp_pubsub:nodeId()}
|
||||
).
|
||||
|
||||
-type(pubsub_stateId()
|
||||
:: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
).
|
||||
|
||||
-type(item_owners() :: [Entity::xmpp_jid:usr_bare(),...]).
|
||||
-type(node_owners() :: [Entity::xmpp_jid:usr_bare(),...]).
|
||||
|
||||
-type(item_creation()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
-type(item_modification()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
-type(node_creation()
|
||||
:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()}
|
||||
).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_state/0,
|
||||
pubsub_states/0,
|
||||
%
|
||||
pubsub_state_owner/0,
|
||||
pubsub_state_publisher/0,
|
||||
pubsub_state_publish_only/0,
|
||||
pubsub_state_member/0,
|
||||
pubsub_state_none/0,
|
||||
pubsub_state_outcast/0
|
||||
]).
|
||||
|
||||
-type(pubsub_state_owner()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'owner',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_publisher()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'publisher',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_publish_only()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'publish-only',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_member()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
access :: undefined | 'pending' | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
access :: undefined | 'pending' | 'presence' | 'roster',
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending(),...],
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'member',
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending() |
|
||||
% exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_none()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: []
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: exmpp_pubsub:itemIds()
|
||||
}
|
||||
%%
|
||||
| #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'none',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [],
|
||||
itemids :: exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-type(pubsub_state_outcast()
|
||||
:: #pubsub_state_dev{
|
||||
id :: mod_pubsub_dev:pubsub_stateId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
affiliation :: 'outcast',
|
||||
access :: undefined | 'presence' | 'roster',
|
||||
subscriptions :: [exmpp_pubsub:subscription()],
|
||||
%subscriptions :: [exmpp_pubsub:subscription_pending() |
|
||||
% exmpp_pubsub:subscription_subscribed() |
|
||||
% exmpp_pubsub:subscription_unconfigured()],
|
||||
itemids :: [] | exmpp_pubsub:itemIds()
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
%%
|
||||
-type(pubsub_state() :: mod_pubsub_dev:pubsub_state_owner()
|
||||
| mod_pubsub_dev:pubsub_state_publisher()
|
||||
| mod_pubsub_dev:pubsub_state_publish_only()
|
||||
| mod_pubsub_dev:pubsub_state_member()
|
||||
| mod_pubsub_dev:pubsub_state_none()
|
||||
| mod_pubsub_dev:pubsub_state_outcast()
|
||||
).
|
||||
|
||||
-type(pubsub_states() :: [Pubsub_State::mod_pubsub_dev:pubsub_state(),...]).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_node/0,
|
||||
pubsub_nodes/0
|
||||
]).
|
||||
|
||||
-type(pubsub_node()
|
||||
:: #pubsub_node_dev{
|
||||
id :: mod_pubsub_dev:pubsub_nodeId(),
|
||||
idx :: exmpp_pubsub:nodeIdx(),
|
||||
creation :: mod_pubsub_dev:node_creation(),
|
||||
level :: exmpp_pubsub:level(),
|
||||
owners :: mod_pubsub_dev:node_owners(),
|
||||
itemids :: [] | exmpp_pubsub:itemIds(),
|
||||
options :: pubsub_options:options_node()
|
||||
}
|
||||
).
|
||||
|
||||
-type(pubsub_nodes() :: [Pubsub_Node::mod_pubsub_dev:pubsub_node(),...]).
|
||||
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_item/0,
|
||||
pubsub_items/0
|
||||
]).
|
||||
|
||||
-type(pubsub_item()
|
||||
:: #pubsub_item_dev{
|
||||
id :: mod_pubsub_dev:pubsub_itemId(),
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
owners :: mod_pubsub_dev:item_owners(),
|
||||
creation :: mod_pubsub_dev:item_creation(),
|
||||
modification :: mod_pubsub_dev:item_modification(),
|
||||
payload :: exmpp_pubsub:payload(),
|
||||
options :: [] | pubsub_options:options_item()
|
||||
}
|
||||
).
|
||||
|
||||
-type(pubsub_items() :: [Pubsub_Item::mod_pubsub_dev:pubsub_item(),...]).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_last_item/0
|
||||
]).
|
||||
|
||||
-type(pubsub_last_item()
|
||||
:: #pubsub_last_item_dev{
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
id :: exmpp_pubsub:itemId(),
|
||||
owners :: mod_pubsub_dev:item_owners(),
|
||||
creation :: mod_pubsub_dev:item_creation(),
|
||||
payload :: exmpp_pubsub:payload(),
|
||||
options :: [] | pubsub_options:options_item()
|
||||
}
|
||||
).
|
||||
|
||||
%%
|
||||
-export_type([
|
||||
pubsub_subscription_pending/0
|
||||
]).
|
||||
|
||||
-type(pubsub_subscription_pending()
|
||||
:: #pubsub_subscription_pending{
|
||||
id :: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()},
|
||||
nodeidx :: exmpp_pubsub:nodeIdx(),
|
||||
subids :: [SubId::exmpp_pubsub:subId(),...]
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_pubsub_dev).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-record(state,
|
||||
{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub_host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub :: #capabilities{},
|
||||
pubsub_on_jid :: #capabilities{}
|
||||
}).
|
||||
|
||||
-type(state()
|
||||
:: #state{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub_host :: xmpp_jid:raw_jid_component_bare(),
|
||||
pubsub :: #capabilities{},
|
||||
pubsub_on_jid :: #capabilities{}
|
||||
}
|
||||
).
|
||||
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
||||
%% Description: Starts the server
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% @spec start_link(Host, Options) -> {'ok', pid()} | 'ignore' | {'error', atom()}
|
||||
%% Host = string()
|
||||
%% Options = {Option::atom(), Value::term()}
|
||||
-spec(start_link/2 ::
|
||||
(
|
||||
Host :: string(),
|
||||
Options :: [Option::{Key::atom(), Value::term()}])
|
||||
-> {'ok', pid()} | 'ignore' | {'error', _}
|
||||
).
|
||||
|
||||
start_link(Host, Options) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:start_link({local, Proc}, ?MODULE, [Host, Options], []).
|
||||
|
||||
%% @spec start(Host, Options) -> {'error',atom()} | {'ok','undefined' | pid()} | {'ok','undefined' | pid(),any()}
|
||||
%% Host = string()
|
||||
%% Options = {Option::atom(), Value::term()}
|
||||
-spec(start/2 ::
|
||||
(
|
||||
Host :: string(),
|
||||
Options :: [Option::{Key::atom(), Value::term()}])
|
||||
-> {'error',_} | {'ok','undefined' | pid()} | {'ok','undefined' | pid(),_}
|
||||
).
|
||||
|
||||
start(Host, Options) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
ChildSpec = {Proc,
|
||||
{?MODULE, start_link, [Host, Options]},
|
||||
transient, 1000, worker, [?MODULE]},
|
||||
supervisor:start_child(ejabberd_sup, ChildSpec).
|
||||
|
||||
%% @spec stop(Host) -> 'ok' | {'error','not_found' | 'running' | 'simple_one_for_one'}
|
||||
%% Host = string()
|
||||
-spec(stop/1 ::
|
||||
(
|
||||
Host :: string())
|
||||
-> 'ok' | {'error','not_found' | 'running' | 'simple_one_for_one'}
|
||||
).
|
||||
|
||||
stop(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:call(Proc, stop),
|
||||
supervisor:delete_child(ejabberd_sup, Proc).
|
||||
|
||||
|
||||
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: init(Args) -> {ok, State} |
|
||||
%% {ok, State, Timeout} |
|
||||
%% ignore |
|
||||
%% {stop, Reason}
|
||||
%% Description: Initiates the server
|
||||
%%--------------------------------------------------------------------
|
||||
-spec(init/1 ::
|
||||
(
|
||||
Args :: [binary() | [{Option::atom(), Value::term()}]])
|
||||
-> {'ok', State::state()}
|
||||
).
|
||||
|
||||
init([Host, Options] = _Args) ->
|
||||
?DEBUG("pubsub init ~p ~p",[Host, Options]),
|
||||
Pubsub_Host = gen_mod:expand_host_name(Host, Options, <<"pubsub">>),
|
||||
IQDisc = gen_mod:get_opt('iqdisc', Options, 'one_queue'),
|
||||
|
||||
% mod_disco:register_feature(Server_HostB, ?NS_PUBSUB_s),
|
||||
%%
|
||||
%% Pubsub Hooks
|
||||
%% - Service disco hooks
|
||||
%% * disco_local_identity
|
||||
%% * disco_local_features
|
||||
%% * disco_local_items
|
||||
%% * disco_local_forms
|
||||
%% - Connectivity hooks
|
||||
%% * presence_probe_hook
|
||||
%% * sm_remove_connection_hook
|
||||
%% - Roster hooks
|
||||
%% * roster_in_subscription
|
||||
%% * roster_out_subscription
|
||||
%% - User managment hooks
|
||||
%% * remove_user
|
||||
%% * anonymous_purge_hook
|
||||
%%
|
||||
%% Pubsub On Jid hooks
|
||||
%% - Service disco hooks
|
||||
%% * disco_sm_identity
|
||||
%% * disco_sm_features
|
||||
%% * disco_sm_items
|
||||
%% * disco_sm_forms
|
||||
%% - Connectitivy
|
||||
%% * caps_update
|
||||
|
||||
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
% mod_disco:register_feature(Server_HostB, ?NS_PUBSUB_s),
|
||||
pubsub_db:init('mnesia', 'dev'),
|
||||
%% Register hooks according to available Pubsub Features
|
||||
register_hooks(Host, Pubsub_Features, pubsub_hooks),
|
||||
%%
|
||||
ejabberd_router:register_route(Pubsub_Host),
|
||||
{ok,
|
||||
#state{
|
||||
host = Host,
|
||||
pubsub_host = Pubsub_Host,
|
||||
pubsub = node_flat_dev:capabilities()
|
||||
}
|
||||
}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% 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
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, State}
|
||||
%% Description: Handling cast messages
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
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
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
|
||||
handle_info({route, From, #jid{resource = undefined} = To, Stanza},
|
||||
#state{host = Host, pubsub = Capabilities} = State) ->
|
||||
do_route(Host, To, From, Stanza, Capabilities),
|
||||
{noreply, 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.
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
%% @todo : -spec
|
||||
-spec(terminate/2 ::
|
||||
(
|
||||
Reason :: _,
|
||||
State :: state())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
terminate(_Reason, #state{host = Host, pubsub_host = Pubsub_Host}) ->
|
||||
ejabberd_router:unregister_route(Pubsub_Host),
|
||||
ok.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
||||
%% Description: Convert process state when code is changed
|
||||
%%--------------------------------------------------------------------
|
||||
%% @private
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
|
||||
%%
|
||||
-define(Is_Stanza_IQ(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"iq">>
|
||||
)).
|
||||
|
||||
-define(Is_Stanza_Message(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"message">>
|
||||
)).
|
||||
|
||||
-define(Is_Stanza_Presence(Stanza),
|
||||
(
|
||||
Stanza#xmlel.name == <<"presence">>
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Ignore(IQ),
|
||||
(
|
||||
IQ#iq.type == 'result'
|
||||
orelse
|
||||
IQ#iq.type == 'error'
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Pubsub(IQ),
|
||||
(
|
||||
(IQ#iq.type == 'set'
|
||||
orelse
|
||||
IQ#iq.type == 'get')
|
||||
andalso
|
||||
(IQ#iq.xmlns == ?NS_PUBSUB
|
||||
orelse
|
||||
IQ#iq.xmlns == ?NS_PUBSUB_OWNER)
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"pubsub">>
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Get_Disco_Info(IQ),
|
||||
(
|
||||
IQ#iq.type == 'get'
|
||||
andalso
|
||||
IQ#iq.xmlns == ?NS_DISCO_INFO
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"query">>
|
||||
% andalso
|
||||
% IQ#iq.payload#xmlel.children == []
|
||||
)).
|
||||
|
||||
-define(Is_IQ_Get_Disco_Items(IQ),
|
||||
(
|
||||
IQ#iq.type == 'get'
|
||||
andalso
|
||||
IQ#iq.xmlns == ?NS_DISCO_ITEMS
|
||||
andalso
|
||||
IQ#iq.sub_el#xmlel.name == <<"query">>
|
||||
% andalso
|
||||
% IQ#iq.payload#xmlel.children == []
|
||||
)).
|
||||
|
||||
%%
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_IQ,
|
||||
#capabilities{privacy = Privacy, plugin = Plugin} = Capabilities)
|
||||
when ?Is_Stanza_IQ(Stanza_IQ) ->
|
||||
case IQ = jlib:iq_query_or_response_info(Stanza_IQ) of
|
||||
IQ when ?Is_IQ_Ignore(IQ) ->
|
||||
ok;
|
||||
IQ when ?Is_IQ_Get_Disco_Info(IQ) ->
|
||||
case
|
||||
pubsub_disco:iq_disco_info('dev', Host, Pubsub_Host,
|
||||
Privacy, {U,S,undefined},
|
||||
case S of
|
||||
Host -> 'local';
|
||||
_ -> 'remote'
|
||||
end,
|
||||
Plugin,
|
||||
case xml:get_tag_attr_s(<<"node">>, IQ#iq.sub_el) of
|
||||
<<>> -> undefined;
|
||||
NodeId -> NodeId
|
||||
end,
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children))
|
||||
of
|
||||
{result, Xmlel_Query} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = [Xmlel_Query]
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end;
|
||||
IQ when ?Is_IQ_Get_Disco_Items(IQ) ->
|
||||
case
|
||||
pubsub_disco:iq_disco_items('dev', Host, Pubsub_Host,
|
||||
Privacy, {U,S,undefined},
|
||||
case S of
|
||||
Host -> 'local';
|
||||
_ -> 'remote'
|
||||
end,
|
||||
Plugin,
|
||||
case xml:get_tag_attr_s(<<"node">>, IQ#iq.sub_el) of
|
||||
<<>> -> undefined;
|
||||
NodeId -> NodeId
|
||||
end,
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children))
|
||||
of
|
||||
{result, Xmlel_Query} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = [Xmlel_Query]
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end;
|
||||
IQ when ?Is_IQ_Pubsub(IQ) ->
|
||||
case
|
||||
iq_pubsub(Host, Pubsub_Host, {U,S,R}, IQ#iq.type,
|
||||
_Rsm = lists:member(?NS_RSM, Plugin:features()),
|
||||
xml:remove_cdata(IQ#iq.sub_el#xmlel.children),
|
||||
IQ#iq.lang, Capabilities)
|
||||
of
|
||||
{result, []} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = []
|
||||
}));
|
||||
{result, Xmlels} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:iq_to_xml(IQ#iq{
|
||||
type = result,
|
||||
sub_el = Xmlels
|
||||
}));
|
||||
{error, Error} ->
|
||||
ejabberd_router:route(Pubsub_Component, Entity,
|
||||
jlib:make_error_reply(Stanza_IQ, Error))
|
||||
end
|
||||
end;
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_Message,
|
||||
Capabilities)
|
||||
when ?Is_Stanza_Message(Stanza_Message) ->
|
||||
ok;
|
||||
do_route(Host,
|
||||
#jid{lserver = Pubsub_Host} = Pubsub_Component,
|
||||
#jid{luser = U, lserver = S, lresource = R} = Entity, Stanza_Presence,
|
||||
Capabilities)
|
||||
when ?Is_Stanza_Presence(Stanza_Presence) ->
|
||||
ok.
|
||||
|
||||
|
||||
iq_pubsub(Host, Pubsub_Host, Entity, IQ_Type, Rsm, Xmlels, _Lang,
|
||||
#capabilities{api = #api{parser = Parser, core = API_Core}} = Capabilities) ->
|
||||
case Parser:parse(IQ_Type, Xmlels, Rsm, API_Core) of
|
||||
{result, Module, Function, Parameters} ->
|
||||
Module:Function(Host, Pubsub_Host, Entity, Parameters, Capabilities);
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
|
||||
|
||||
register_hooks(Host, Pubsub_Features, Module) ->
|
||||
register_hooks('roster', Host, Pubsub_Features, Module),
|
||||
register_hooks('presence', Host, Pubsub_Features, Module).
|
||||
|
||||
%ejabberd_hooks:add(roster_in_subscription, Host, pubsub_hooks, roster_in_subscription, 50),
|
||||
%ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, roster_out_subscription, 50),
|
||||
%ejabberd_hooks:add(roster_get, Host, ?MODULE, roster_get, 50),
|
||||
%ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, roster_get_jid_info, 50),
|
||||
%ejabberd_hooks:add(roster_get_subscription_lists, Host, ?MODULE, roster_get_subscription_lists, 50),
|
||||
%%ejabberd_hooks:add(roster_process_item, Host, pubsub_hooks, roster_process_item, 50).
|
||||
|
||||
|
||||
register_hooks('roster', Host, Pubsub_Features, Module) ->
|
||||
case lists:member("access-roster", Pubsub_Features) of
|
||||
true ->
|
||||
ejabberd_hooks:add(roster_process_item, Host, Module,
|
||||
roster_process_item, 50),
|
||||
ok;
|
||||
false ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
register_hooks('presence', Host, Pubsub_Features, Module) ->
|
||||
case
|
||||
lists:member(<<"access-presence">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"last-published">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"leased-subscription">>, Pubsub_Features)
|
||||
orelse
|
||||
lists:member(<<"presence-notifications">>, Pubsub_Features)
|
||||
of
|
||||
true ->
|
||||
ejabberd_hooks:add(presence_probe_hook, Host, Module,
|
||||
presence_online, 80),
|
||||
ejabberd_hooks:add(sm_remove_connection_hook, Host, Module,
|
||||
presence_offline, 80),
|
||||
ok;
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
|
||||
roster_get(Acc, {User, Server}) ->
|
||||
?INFO_MSG("ROSTER_GET Acc ~p ~nUser ~p ~nServer ~p ~n",
|
||||
[Acc, User, Server]).
|
||||
|
||||
roster_get_jid_info(Acc, User, Server, JID) ->
|
||||
?INFO_MSG("ROSTER_GET_JID_INFO Acc ~p ~nUser ~p ~nServer ~p ~nJID ~p ~n",
|
||||
[Acc, User, Server, JID]).
|
||||
|
||||
roster_get_subscription_lists(Acc, User, Server) ->
|
||||
?INFO_MSG("ROSTER_GET_SUBSCRIPTION_LISTS Acc ~p ~nUser ~p ~nServer ~p ~n",
|
||||
[Acc, User, Server]).
|
||||
|
||||
roster_in_subscription(User, Server, JID, SubscriptionType, Reason, A) ->
|
||||
?INFO_MSG("ROSTER_IN_SUBSCRITION User ~p ~n Server ~p ~n JID ~p ~n SubscriptionType ~p ~n, Reason ~p ~nA ~p ~n",
|
||||
[User, Server, JID, SubscriptionType, Reason, A]).
|
||||
|
||||
roster_out_subscription(User, Server, JID, SubscriptionType) ->
|
||||
?INFO_MSG("ROSTER_OUT_SUBSCRITION User ~p ~n Server ~p ~n JID ~p ~n SubscriptionType ~p ~n",
|
||||
[User, Server, JID, SubscriptionType]).
|
||||
|
||||
roster_process_item(RosterItem, Server) ->
|
||||
?INFO_MSG("ROSTER_PROCESS_ITEM RosterItem ~p ~nServer ~p ~n",
|
||||
[RosterItem, Server]),
|
||||
RosterItem.
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(node_flat_dev).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
-include("pubsub_api.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(capabilities/0 :: () -> #capabilities{}).
|
||||
|
||||
capabilities() ->
|
||||
#capabilities{plugin = ?MODULE}.
|
||||
|
||||
|
||||
%%
|
||||
-spec(pubsub_features/0 :: () -> Pubsub_Features::exmpp_pubsub:pubsub_features()).
|
||||
|
||||
pubsub_features() ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"presence-notifications">>,
|
||||
%"presence-subscribe">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>].
|
||||
|
||||
%%
|
||||
-spec(pubsub_features/1 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote')
|
||||
-> Pubsub_Features::exmpp_pubsub:pubsub_features()
|
||||
).
|
||||
|
||||
pubsub_features('local') ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"presence-notifications">>,
|
||||
%<<"presence-subscribe">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>];
|
||||
%%
|
||||
pubsub_features('remote') ->
|
||||
[<<"access-authorize">>,
|
||||
<<"access-open">>,
|
||||
<<"access-presence">>,
|
||||
<<"access-roster">>,
|
||||
<<"access-whitelist">>,
|
||||
<<"auto-create">>,
|
||||
<<"auto-subscribe">>,
|
||||
%<<"collections">>,
|
||||
<<"config-node">>,
|
||||
<<"create-and-configure">>,
|
||||
<<"create-nodes">>,
|
||||
<<"delete-items">>,
|
||||
<<"delete-nodes">>,
|
||||
%<<"filtered-notifications">>,
|
||||
<<"get-pending">>,
|
||||
<<"instant-nodes">>,
|
||||
<<"item-ids">>,
|
||||
<<"last-published">>,
|
||||
%<<"leased-subscription">>,
|
||||
<<"manage-subscriptions">>,
|
||||
<<"member-affiliation">>,
|
||||
<<"meta-data">>,
|
||||
<<"modify-affiliations">>,
|
||||
%<<"multi-collections">>,
|
||||
<<"multi-subscribe">>,
|
||||
<<"outcast-affiliation">>,
|
||||
<<"persistent-items">>,
|
||||
<<"publish">>,
|
||||
<<"publish-only-affiliation">>,
|
||||
<<"publish-options">>,
|
||||
<<"publisher-affiliation">>,
|
||||
<<"purge-nodes">>,
|
||||
<<"retract-items">>,
|
||||
<<"retrieve-affiliations">>,
|
||||
<<"retrieve-default">>,
|
||||
<<"retrieve-default-sub">>,
|
||||
<<"retrieve-items">>,
|
||||
<<"retrieve-subscriptions">>,
|
||||
<<"subscribe">>,
|
||||
<<"subscription-notifications">>,
|
||||
<<"subscription-options">>].
|
||||
|
||||
%%
|
||||
%%
|
||||
-spec(node_options/1 ::
|
||||
(
|
||||
Node_Type :: 'leaf' | 'collection')
|
||||
-> Node_Options :: pubsub_options:options_node_leaf()
|
||||
| pubsub_options:options_node_collection()
|
||||
).
|
||||
|
||||
node_options('leaf') ->
|
||||
[{'access_model', open},
|
||||
{'contact', []},
|
||||
%{'collection', []},
|
||||
{'deliver_notifications', true},
|
||||
{'deliver_payloads', true},
|
||||
{'description', undefined},
|
||||
{'item_expire', undefined},
|
||||
{'itemreply', publisher},
|
||||
{'language', <<"en">>},
|
||||
{'max_items', 2},
|
||||
{'max_payload_size', undefined},
|
||||
{'node_type', leaf},
|
||||
{'notification_type', normal},
|
||||
{'notify_config', true},
|
||||
{'notify_delete', true},
|
||||
{'notify_retract', true},
|
||||
{'notify_sub', true},
|
||||
{'persist_items', true},
|
||||
{'presence_based_delivery', true},
|
||||
{'publish_model', open},
|
||||
{'purge_offline', false},
|
||||
{'roster_groups_allowed', []},
|
||||
{'send_last_published_item', on_sub_and_presence},
|
||||
{'subscribe', true},
|
||||
{'tempsub', false},
|
||||
{'title', undefined},
|
||||
{'type', undefined}];
|
||||
%%
|
||||
node_options('collection') ->
|
||||
[].
|
||||
|
||||
item_options() ->
|
||||
[{'access_model', open},
|
||||
{'deliver_notifications', true},
|
||||
{'deliver_payloads', true},
|
||||
{'item_expire', undefined},
|
||||
{'itemreply', publisher},
|
||||
% {'max_payload_size', undefined},
|
||||
{'notification_type', normal},
|
||||
{'notify_config', true},
|
||||
{'notify_retract', true},
|
||||
{'persist_items', true},
|
||||
{'presence_based_delivery', true},
|
||||
% {'publish_model', open},
|
||||
{'purge_offline', false},
|
||||
{'roster_groups_allowed', []},
|
||||
{'send_last_published_item', on_sub_and_presence},
|
||||
{'type', undefined}].
|
||||
|
||||
%%
|
||||
-spec(subscription_options/2 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote',
|
||||
Node_Type :: 'leaf' | 'collection')
|
||||
-> Subscription_Options :: [] | pubsub_options:options_subscription()
|
||||
).
|
||||
|
||||
subscription_options('local', 'leaf') ->
|
||||
[];
|
||||
subscription_options('remote', 'leaf') ->
|
||||
[];
|
||||
subscription_options('local', 'collection') ->
|
||||
[];
|
||||
subscription_options('remote', 'collection') ->
|
||||
[].
|
||||
|
||||
%%
|
||||
-spec(default_subscription_options/2 ::
|
||||
(
|
||||
Entity_Type :: 'local' | 'remote',
|
||||
Node_Type :: 'leaf')%| 'collection')
|
||||
-> Subscription_Options :: pubsub_options:options_subscription_leaf()
|
||||
).
|
||||
|
||||
default_subscription_options('local', 'leaf') ->
|
||||
[{'deliver', true},
|
||||
{'expire', undefined},
|
||||
%{'include_body', undefined},
|
||||
{'show-values', ['away', 'chat', 'dnd', 'online', 'xa']}];
|
||||
%%
|
||||
default_subscription_options('remote', 'leaf') ->
|
||||
[{'deliver', true}
|
||||
%{'include_body', undefined}
|
||||
].
|
||||
%%
|
||||
%%default_subscription_options('local', 'collection') ->
|
||||
%% [{'deliver', true},
|
||||
%% %{'expire', undefined},
|
||||
%% %{'include_body', undefined},
|
||||
%% {'show-values', ['away', 'chat', 'dnd', 'online', 'xa']},
|
||||
%% {'subscription_type', 'all'},
|
||||
%% {'subscription_depth', 1}];
|
||||
%%
|
||||
%%default_subscription_options('remote', 'collection') ->
|
||||
%% [{'deliver', true},
|
||||
%% %{'include_body', undefined},
|
||||
%% {'show-values', ['away', 'chat', 'dnd', 'online', 'xa']},
|
||||
%% {'subscription_type', 'all'},
|
||||
%% {'subscription_depth', 1}].
|
||||
|
||||
%%
|
||||
-spec(features/0 :: () -> Features::exmpp_pubsub:features()).
|
||||
|
||||
features() ->
|
||||
[%?NS_ADDRESS,
|
||||
?NS_DISCO_INFO,
|
||||
?NS_DISCO_ITEMS,
|
||||
%?NS_RSM,
|
||||
?NS_VCARD].
|
||||
|
||||
%%
|
||||
identity() ->
|
||||
[{<<"pubsub">>, <<"Publish-Subscribe">>, <<"service">>},
|
||||
{<<"pubsub">>, <<"ejabberd/mod_pubsub/flat">>, <<"service">>}].
|
||||
@@ -0,0 +1,101 @@
|
||||
%% API function definition
|
||||
|
||||
-record(api_core,
|
||||
{
|
||||
create_node = 'pubsub_core' :: module(),
|
||||
delete_node = 'pubsub_core' :: module(),
|
||||
purge_node = 'pubsub_core' :: module(),
|
||||
get_configure_node = 'pubsub_core' :: module(),
|
||||
get_configure_node_default = 'pubsub_core' :: module(),
|
||||
%%
|
||||
publish_item = 'pubsub_core' :: module(),
|
||||
retract_item = 'pubsub_core' :: module(),
|
||||
%%
|
||||
subscribe_node = 'pubsub_core' :: module(),
|
||||
unsubscribe_node = 'pubsub_core' :: module(),
|
||||
set_configure_subscription = 'pubsub_core' :: module(),
|
||||
get_configure_subscription = 'pubsub_core' :: module(),
|
||||
get_configure_subscription_default = 'pubsub_core' :: module(),
|
||||
get_items = 'pubsub_core' :: module(),
|
||||
%%
|
||||
get_entity_affiliations = 'pubsub_core' :: module(),
|
||||
get_entity_subscriptions = 'pubsub_core' :: module(),
|
||||
%%
|
||||
get_node_affiliations = 'pubsub_core' :: module(),
|
||||
get_node_subscriptions = 'pubsub_core' :: module()
|
||||
}).
|
||||
|
||||
-record(api_db,
|
||||
{
|
||||
create_node = 'pubsub_db' :: module(),
|
||||
delete_node = 'pubsub_db' :: module(),
|
||||
purge_node = 'pubsub_db' :: module(),
|
||||
get_configure_node = 'pubsub_db' :: module(),
|
||||
%get_configure_node_default = 'pubsub_db' :: module(),
|
||||
%%
|
||||
publish_item = 'pubsub_db' :: module(),
|
||||
retract_item = 'pubsub_db' :: module(),
|
||||
%%
|
||||
subscribe_node = 'pubsub_db' :: module(),
|
||||
unsubscribe_node = 'pubsub_db' :: module(),
|
||||
set_configure_subscription = 'pubsub_db' :: module(),
|
||||
get_configure_subscription = 'pubsub_db' :: module(),
|
||||
get_configure_subscription_default = 'pubsub_db' :: module(),
|
||||
get_items = 'pubsub_db' :: module(),
|
||||
%%
|
||||
get_entity_affiliations = 'pubsub_db' :: module(),
|
||||
get_entity_subscriptions = 'pubsub_db' :: module(),
|
||||
%%
|
||||
get_node_affiliations = 'pubsub_db' :: module(),
|
||||
get_node_subscriptions = 'pubsub_db' :: module()
|
||||
}).
|
||||
|
||||
-record(api_broadcast,
|
||||
{
|
||||
broadcast_publish = 'pubsub_broadcast' :: module(),
|
||||
broadcast_publish_last = 'pubsub_broadcast' :: module(),
|
||||
notify_create = 'pubsub_broadcast' :: module(),
|
||||
notify_delete = 'pubsub_broadcast' :: module(),
|
||||
notify_publish = 'pubsub_broadcast' :: module(),
|
||||
notify_purge = 'pubsub_broadcast' :: module(),
|
||||
notify_retract = 'pubsub_broadcast' :: module(),
|
||||
notify_subscription = 'pubsub_broadcast' :: module(),
|
||||
notify_subscriptions = 'pubsub_broadcast' :: module()
|
||||
}).
|
||||
|
||||
-record(api,
|
||||
{
|
||||
core = #api_core{} :: #api_core{},
|
||||
db = #api_db{} :: #api_db{},
|
||||
broadcast = #api_broadcast{} :: #api_broadcast{},
|
||||
parser = 'pubsub_parser' :: module(),
|
||||
options = 'pubsub_options' :: module()
|
||||
}).
|
||||
|
||||
-record(capabilities,
|
||||
{
|
||||
plugin :: exmpp_pubsub:plugin(),
|
||||
privacy = false :: boolean(),
|
||||
api = #api{} :: #api{}
|
||||
}).
|
||||
|
||||
-record(api2,
|
||||
{
|
||||
func,
|
||||
core :: 'core',
|
||||
db :: 'db',
|
||||
bkd :: 'mnesia',
|
||||
rtr :: 'router'
|
||||
}).
|
||||
|
||||
-record(mod_pubsub,
|
||||
{
|
||||
server,
|
||||
component,
|
||||
plugin,
|
||||
entity,
|
||||
parameters,
|
||||
features,
|
||||
parser,
|
||||
options
|
||||
}).
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,147 @@
|
||||
|
||||
|
||||
%-include_lib("exmpp/include/exmpp.hrl").
|
||||
%-include_lib("exmpp/include/exmpp_jid.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
-include("jlib.hrl").
|
||||
%-include("pubsub_api.hrl").
|
||||
|
||||
-define(NS_JABBER_CLIENT, <<"jabber:client">>).
|
||||
|
||||
%%
|
||||
%% Pubsub Node
|
||||
-record(pubsub_node_dev,
|
||||
{
|
||||
id ,%:: {Pubsub_Host :: exmpp_pubsub:host(),
|
||||
% NodeId :: undefined | exmpp_pubsub:nodeId()},
|
||||
idx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
level = 0 ,%:: exmpp_pubsub:level(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
itemids = [] ,%:: [ItemId::exmpp_pubsub:itemId()],
|
||||
options = [] %:: pubsub_options:options_node()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub State
|
||||
-record(pubsub_state_dev,
|
||||
{
|
||||
id ,%:: {Entity :: xmpp_jid:usr_bare(),
|
||||
% NodeIdx :: exmpp_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
affiliation = 'none' ,%:: exmpp_pubsub:affiliation(),
|
||||
access ,%:: pubsub_options:access_model(),
|
||||
subscriptions = [] ,%:: [] | exmpp_pubsub:subscriptions(),
|
||||
%groups = [] ,%:: [Roster_Group::binary()],
|
||||
itemids = [] %:: [ItemId::exmpp_pubsub:itemId()]
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Item
|
||||
-record(pubsub_item_dev,
|
||||
{
|
||||
id ,%:: {ItemId::exmpp_pubsub:itemId(), NodeIdx::exmpp_pubsub:nodeIdx()},
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
modification ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
payload ,%:: exmpp_pubsub:payload(),
|
||||
options = [] %:: [] | pubsub_options:options_item()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Last Item
|
||||
-record(pubsub_last_item_dev,
|
||||
{
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx(),
|
||||
id ,%:: exmpp_pubsub:itemId(),
|
||||
owners = [] ,%:: [Owner::xmpp_jid:usr_bare(),...],
|
||||
creation ,%:: {DateTime::erlang:timestamp(), Entity::xmpp_jid:usr_entity()},
|
||||
payload ,%:: exmpp_pubsub:payload(),
|
||||
options = [] %:: [] | pubsub_options:options_item()
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub Index
|
||||
-record(pubsub_index_dev,
|
||||
{
|
||||
index :: exmpp_pubsub:index(),
|
||||
last :: exmpp_pubsub:nodeIdx(),
|
||||
free :: [exmpp_pubsub:nodeIdx()]
|
||||
}).
|
||||
|
||||
%%
|
||||
%% Pubsub_Subscription_Pending
|
||||
-record(pubsub_subscription_pending,
|
||||
{
|
||||
id ,%:: {Entity::xmpp_jid:usr_bare(), NodeIdx::exmpp_pubsub:nodeIdx()}
|
||||
nodeidx ,%:: exmpp_pubsub:nodeIdx()
|
||||
subids %:: [SubId::exmpp_pubsub:subId(),...]
|
||||
}).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
%% Internal data structures
|
||||
%%
|
||||
-record(entity,
|
||||
{
|
||||
id :: xmpp_jid:usr_bare(),
|
||||
local :: boolean(),
|
||||
affiliation :: 'member' | 'owner' | 'publisher',
|
||||
subscriptions :: []%[exmpp_pubsub:subscription(),...]
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(node,
|
||||
{
|
||||
id :: exmpp_pubsub:nodeId(),
|
||||
owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
access_model :: pubsub_options:access_model(),
|
||||
% itemreply :: 'owner' | 'publisher',
|
||||
% notification_type :: 'headline' | 'normal',
|
||||
% presence_based_delivery :: boolean(),
|
||||
rosters_groups_allowed = [] :: [] | pubsub_options:rosters_groups_allowed()
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(item,
|
||||
{
|
||||
access_model ,%:: undefined | pubsub_options:access_model(),
|
||||
presence_based_delivery ,%:: undefined | boolean(),
|
||||
rosters_groups_allowed = [],%:: [] | pubsub_options:rosters_groups_allowed()
|
||||
stanza %::#xmlel{}
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(cache,
|
||||
{
|
||||
%% Entity is online
|
||||
presence :: undefined | mod_pubsub_dev:presence_cache(),
|
||||
%% Entity has presence subscriptions with at least one node owner
|
||||
presence_subscriptions :: undefined | boolean(),
|
||||
%% Entity has presence subscriptions with at least one node owner
|
||||
%% and is contained in at least one roster group from the node owner
|
||||
rosters_groups :: undefined | boolean() %% TODO : use a list
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(subids,
|
||||
{
|
||||
presence = undefined :: undefined | [] | mod_pubsub_dev:resources_subids(),
|
||||
no_presence = undefined :: undefined | [] | mod_pubsub_dev:resources_subids()
|
||||
}).
|
||||
|
||||
%%
|
||||
-record(event,
|
||||
{
|
||||
host :: xmpp_jid:raw_jid_component_bare(),
|
||||
component :: xmpp_jid:component_bare(),
|
||||
entity :: mod_pubsub_dev:entity(),
|
||||
node :: mod_pubsub_dev:n0de(),
|
||||
cache :: mod_pubsub_dev:cache(),
|
||||
subids :: mod_pubsub_dev:subids()
|
||||
}).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,904 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_groups).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-import(pubsub_tools,
|
||||
[
|
||||
get_option/2,
|
||||
get_option/3,
|
||||
get_value/2,
|
||||
get_value/3,
|
||||
set_value/3,
|
||||
%%
|
||||
check_acces_model/3,
|
||||
check_acces_model/7,
|
||||
check_publish_model/3,
|
||||
get_entity_roster/1,
|
||||
is_contact_subscribed_to_node_owners/3,
|
||||
is_contact_in_allowed_roster_groups/2,
|
||||
has_subscriptions/1,
|
||||
get_resources/2,
|
||||
get_resources_show/2,
|
||||
rosters_groups_allowed_cache/2
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
|
||||
-type(group() :: binary()).
|
||||
|
||||
-type(node_group() :: group()).
|
||||
|
||||
-type(roster_group() :: group()).
|
||||
|
||||
-type(node_groups() :: [Node_Group::node_group(),...]).
|
||||
|
||||
-type(roster_groups() :: [Roster_Group::roster_group(),...]).
|
||||
|
||||
-type(nodeIdxs() :: [NodeIdx::exmpp_pubsub:nodeIdx(),...]).
|
||||
|
||||
-type(n0de()
|
||||
:: {NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Groups :: node_groups()}
|
||||
).
|
||||
|
||||
-type(n0des() :: [Node::n0de(),...]).
|
||||
|
||||
%% -type(subscription()
|
||||
%% :: {NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
%% Groups :: roster_groups()}
|
||||
%% ).
|
||||
|
||||
-type(subscriptions() :: [Subscription::subscription(),...]).
|
||||
|
||||
-type(contact()
|
||||
:: {Entity :: xmpp_jid:usr_bare(),
|
||||
Subscriptions :: subscriptions()}
|
||||
).
|
||||
|
||||
-type(contacts() :: [Contact::contact(),...]).
|
||||
|
||||
|
||||
-record(pubsub_groups,
|
||||
{
|
||||
owner :: xmpp_jid:usr_bare(),
|
||||
nodes = [] :: n0des(),
|
||||
contacts = [] :: [] | contacts()
|
||||
}).
|
||||
|
||||
|
||||
create_table_pubsub_groups(Suffix) ->
|
||||
mnesia:create_table(table('pubsub_groups', Suffix),
|
||||
[{type, set},
|
||||
{disc_copies, [node()]},
|
||||
{record_name, pubsub_groups},
|
||||
{attributes, record_info(fields, pubsub_groups)}]).
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(register_groups/4 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Owner :: xmpp_jid:usr_bare(),
|
||||
Groups :: [] | node_groups())
|
||||
-> undefined
|
||||
%
|
||||
| {Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
register_groups(Suffix, NodeIdx, Owner, [] = _Groups) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'),
|
||||
Owner, write)
|
||||
of
|
||||
%%
|
||||
[] ->
|
||||
undefined;
|
||||
%%
|
||||
[#pubsub_groups{nodes = [{NodeIdx, _Node_Groups}]} = Pubsub_Groups] ->
|
||||
mnesia:delete_object(Table_Pubsub_Groups, Pubsub_Groups, write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = lists:foldl(fun
|
||||
({Entity, Subscriptions}, Unsubscribers) ->
|
||||
case lists:keymember(NodeIdx, 1, Subscriptions) of
|
||||
true -> [Entity | Unsubscribers];
|
||||
false -> Unsubscribers
|
||||
end
|
||||
%
|
||||
end, [], Pubsub_Groups#pubsub_groups.contacts)};
|
||||
%%
|
||||
[Pubsub_Groups] ->
|
||||
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
|
||||
{_NodeIdx, Node_Groups} ->
|
||||
{Contacts, Unsubscribers} = subscriptions1(NodeIdx,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
false ->
|
||||
undefined
|
||||
end
|
||||
end;
|
||||
%%
|
||||
register_groups(Suffix, NodeIdx, Owner, Groups) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', 'dev'), Owner,
|
||||
write)
|
||||
of
|
||||
[] ->
|
||||
{Contacts, Subscribers} = subscriptions2(NodeIdx, Owner, Groups),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
#pubsub_groups{
|
||||
owner = Owner,
|
||||
nodes = [{NodeIdx, Groups}],
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = Subscribers,
|
||||
_Unsubscribers = []};
|
||||
[Pubsub_Groups] ->
|
||||
case lists:keyfind(NodeIdx, 1, Pubsub_Groups#pubsub_groups.nodes) of
|
||||
{_NodeIdx, Node_Groups} ->
|
||||
case diff_groups(Groups, Node_Groups) of
|
||||
%%
|
||||
{[] = _New_Groups, [] = _Old_Groups} ->
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = []};
|
||||
%%
|
||||
{[] = _New_Groups, Old_Groups} ->
|
||||
{Contacts, Unsubscribers}
|
||||
= subscriptions3(NodeIdx, Old_Groups,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = lists:keyreplace(NodeIdx, 1,
|
||||
Pubsub_Groups#pubsub_groups.nodes,
|
||||
{NodeIdx, Groups}),
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = [],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{_New_Groups, _Old_Groups} ->
|
||||
{Contacts, Subscribers, Unsubscribers}
|
||||
= subscriptions4(NodeIdx, Owner, Node_Groups,
|
||||
Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = lists:keyreplace(NodeIdx, 1,
|
||||
Pubsub_Groups#pubsub_groups.nodes,
|
||||
{NodeIdx, Node_Groups}),
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end;
|
||||
false ->
|
||||
{Contacts, Subscribers}
|
||||
= subscriptions5(NodeIdx, Owner, Groups,
|
||||
_Contacts = Pubsub_Groups#pubsub_groups.contacts),
|
||||
%
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
nodes = [{NodeIdx, Groups}
|
||||
| Pubsub_Groups#pubsub_groups.nodes],
|
||||
contacts = Contacts
|
||||
},
|
||||
write),
|
||||
%
|
||||
{_Subscribers = Subscribers,
|
||||
_Unsubscribers = []}
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
%% TODO : fix this hook managment
|
||||
-spec(monitor_contacts/3 ::
|
||||
(
|
||||
_ :: 'subscribed',
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Jid_Contacts :: xmpp_jid:entity_bare())
|
||||
-> undefined
|
||||
%
|
||||
| {Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Contact :: xmpp_jid:usr_bare(),
|
||||
_ :: {'subscribed', NodeIdxs :: nodeIdxs()}}
|
||||
).
|
||||
|
||||
monitor_contacts('subscribed', {_, Server, _} = Entity, Jid_Contact) ->
|
||||
case roster_groups(Entity, Contact = jlid:jid_to_lower(Jid_Contact)) of
|
||||
[] ->
|
||||
undefined;
|
||||
Roster_Groups ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
|
||||
_Owner = Entity, write)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
[Pubsub_Groups] ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
Roster_Groups)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = case
|
||||
lists:keyreplace(Contact, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts,
|
||||
{Contact, Subscriptions})
|
||||
of
|
||||
_Contacts
|
||||
when _Contacts ==
|
||||
Pubsub_Groups#pubsub_groups.contacts ->
|
||||
[{Contact, Subscriptions}
|
||||
| Pubsub_Groups#pubsub_groups.contacts];
|
||||
Contacts ->
|
||||
Contacts
|
||||
end
|
||||
},
|
||||
write),
|
||||
{Server, Entity, Contact,
|
||||
{'subscribed',
|
||||
_NodeIdx = lists:map(fun
|
||||
({NodeIdx, _Groups}) ->
|
||||
NodeIdx
|
||||
end, Subscriptions)}}
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
%%
|
||||
-spec(monitor_groups/2 ::
|
||||
(
|
||||
Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Roster :: #roster{groups :: [] | roster_groups()})
|
||||
-> undefined
|
||||
%
|
||||
| {Server :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}}
|
||||
).
|
||||
|
||||
monitor_groups(Server, #roster{us = {U,S}} = _Roster) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Groups = table('pubsub_groups', dev),
|
||||
_Owner = {U,S,undefined}, write)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
[Pubsub_Groups] ->
|
||||
case
|
||||
lists:keyfind(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
of %%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when _Roster#roster.subscription == 'delete'
|
||||
orelse _Roster#roster.subscription == 'none' ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
%%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when (_Roster#roster.subscription == 'both'
|
||||
orelse
|
||||
_Roster#roster.subscription == 'from')
|
||||
andalso _Roster#roster.groups == [] ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid, 1,
|
||||
Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
%%
|
||||
{_Entity, Old_Subscriptions}
|
||||
when _Roster#roster.subscription == 'both'
|
||||
orelse _Roster#roster.subscription == 'from' ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
_Roster#roster.groups)
|
||||
of
|
||||
[] ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keydelete(_Roster#roster.jid,
|
||||
1, Pubsub_Groups#pubsub_groups.contacts)
|
||||
},
|
||||
write),
|
||||
{Server, _Roster#roster.jid,
|
||||
diff_nodeidxs(_New_Subscriptions = [],
|
||||
Old_Subscriptions)};
|
||||
New_Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = lists:keyreplace(_Roster#roster.jid,
|
||||
1, Pubsub_Groups#pubsub_groups.contacts,
|
||||
{_Roster#roster.jid, New_Subscriptions})
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
|
||||
Old_Subscriptions)}
|
||||
end;
|
||||
%%
|
||||
false
|
||||
when (_Roster#roster.subscription == 'both'
|
||||
orelse
|
||||
_Roster#roster.subscription == 'from')
|
||||
andalso _Roster#roster.groups =/= [] ->
|
||||
case
|
||||
filter_subscriptions(Pubsub_Groups#pubsub_groups.nodes,
|
||||
_Roster#roster.groups)
|
||||
of
|
||||
[] ->
|
||||
undefined;
|
||||
New_Subscriptions ->
|
||||
mnesia:write(Table_Pubsub_Groups,
|
||||
Pubsub_Groups#pubsub_groups{
|
||||
contacts = [{_Roster#roster.jid, New_Subscriptions}
|
||||
| Pubsub_Groups#pubsub_groups.contacts]
|
||||
},
|
||||
write),
|
||||
{Server,
|
||||
_Entity = _Roster#roster.jid,
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions,
|
||||
_Old_Subscriptions = [])}
|
||||
end;
|
||||
%%
|
||||
_ ->
|
||||
undefined
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%
|
||||
%%
|
||||
-spec(subscriptions1/2 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: [] | contacts())
|
||||
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions1(NodeIdx, Contacts) ->
|
||||
_Diff_Contacts = subscriptions1(NodeIdx, _Old_Contacts = Contacts,
|
||||
{_New_Contacts = [], _Unsubscribers = []}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions1/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: [] | contacts(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {New_Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions1(_NodeIdx, [] = _Old_Contacts, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions1(NodeIdx, [{Entity, Subscriptions} | Old_Contacts],
|
||||
{Contacts, Unsubscribers}) ->
|
||||
subscriptions1(NodeIdx, Old_Contacts,
|
||||
_Diff_Contacts = case lists:keydelete(NodeIdx, 1, Subscriptions) of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
Subscriptions ->
|
||||
{_Contacts = [{Entity, Subscriptions} | Contacts],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = [{Entity, New_Subscriptions} | Contacts],
|
||||
_Unsubscribers = [Entity | Unsubscribers]}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions2/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Owner :: xmpp_jid:usr_bare(),
|
||||
Node_Groups :: node_groups())
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions2(NodeIdx, Owner, Node_Groups) ->
|
||||
subscriptions2(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
{_New_Contacts = [], _Subscribers = []}).
|
||||
|
||||
%%
|
||||
-spec(subscriptions2/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Rosters :: [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions2(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions2(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])
|
||||
of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers};
|
||||
Roster_Groups ->
|
||||
{_Contacts = [{_Roster#roster.jid, [{NodeIdx, Roster_Groups}]}
|
||||
| Contacts],
|
||||
_Subscribers = [_Roster#roster.jid | Subscribers]}
|
||||
end);
|
||||
%%
|
||||
subscriptions2(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions2(NodeIdx, Rosters, Node_Groups, Diff_Contacts).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions3/3 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Groups :: roster_groups(),
|
||||
Contacts :: contacts() | [])
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
subscriptions3(NodeIdx, Old_Groups, Contacts) ->
|
||||
subscriptions3(NodeIdx, Contacts, Old_Groups, {[],[]}).
|
||||
|
||||
%%
|
||||
-spec(subscriptions3/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
Old_Contacts :: contacts() | [],
|
||||
Old_Groups :: roster_groups(),
|
||||
Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions3(_NodeIdx, [] = _Contacts, _Old_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions3(NodeIdx, [{Entity, Subscriptions} | Old_Contacts], Old_Groups,
|
||||
{Contacts, Unsubscribers}) ->
|
||||
subscriptions3(NodeIdx, Old_Contacts, Old_Groups,
|
||||
_Diff_Contacts = case lists:keyfind(NodeIdx, 1, Subscriptions) of
|
||||
{_NodeIdx, Roster_Groups} ->
|
||||
case delete_groups(Old_Groups, Roster_Groups) of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
Groups ->
|
||||
{_Contacts = [{Entity,
|
||||
lists:keyreplace(NodeIdx, 1,
|
||||
Subscriptions, {NodeIdx, Groups})}
|
||||
| Contacts],
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end;
|
||||
false ->
|
||||
{_Contacts = [{Entity, Subscriptions} | Contacts],
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(subscriptions4/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
_ :: xmpp_jid:usr_bare()
|
||||
| [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
_ :: [] | contacts()
|
||||
| {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()],
|
||||
Unsubscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions4(_NodeIdx, [] = _Rosters, _Node_Groups, Diff_Contacts) ->
|
||||
Diff_Contacts;
|
||||
%%
|
||||
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups,
|
||||
{Contacts, Subscribers, Unsubscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions4(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
{lists:keyfind(Entity = _Roster#roster.jid, 1, Contacts),
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])}
|
||||
of
|
||||
%%
|
||||
{false, [] = _Groups} ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{false, Groups} ->
|
||||
{_Contacts = [{Entity, [{NodeIdx, Groups}]} | Contacts],
|
||||
_Subscribers = [Entity | Subscribers],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
%%
|
||||
{{_Entity, [{NodeIdx, _Roster_Groups}] = _Subscriptions}, [] = _Groups} ->
|
||||
{_Contacts = lists:keydelete(Entity, 1, Contacts),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = [Entity | Unsubscribers]};
|
||||
%%
|
||||
{{_Entity, Subscriptions}, [] = _Groups} ->
|
||||
case lists:keydelete(NodeIdx, 1, Subscriptions) of
|
||||
Subscriptions ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, New_Subscriptions}),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = [Entity | Unsubscribers]}
|
||||
end;
|
||||
{{_Entity, Subscriptions}, Groups} ->
|
||||
case lists:keyreplace(NodeIdx, 1, Subscriptions, {NodeIdx, Groups}) of
|
||||
Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity,
|
||||
[{NodeIdx, Groups} | Subscriptions]}),
|
||||
_Subscribers = [Entity | Subscribers],
|
||||
_Unsubscribers = Unsubscribers};
|
||||
New_Subscriptions ->
|
||||
{_Contacts = lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, New_Subscriptions}),
|
||||
_Subscribers = Subscribers,
|
||||
_Unsubscribers = Unsubscribers}
|
||||
end
|
||||
end);
|
||||
%%
|
||||
subscriptions4(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions4(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
|
||||
%%
|
||||
subscriptions4(NodeIdx, Owner, Node_Groups, Contacts) ->
|
||||
subscriptions4(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
_Diff_Contacts = {Contacts, _Subscribers = [], _Unsubscribers = []}).
|
||||
|
||||
|
||||
|
||||
-spec(subscriptions5/4 ::
|
||||
(
|
||||
NodeIdx :: exmpp_pubsub:nodeIdx(),
|
||||
_ :: xmpp_jid:usr_bare()
|
||||
| [Roster::#roster{groups :: [] | roster_groups()}],
|
||||
Node_Groups :: node_groups(),
|
||||
_ :: [] | contacts()
|
||||
| {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]})
|
||||
-> Diff_Contacts :: {Contacts :: [] | contacts(),
|
||||
Subscribers :: [Entity::xmpp_jid:usr_bare()]}
|
||||
).
|
||||
|
||||
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, {Contacts, Subscribers})
|
||||
when _Roster#roster.groups =/= [] ->
|
||||
subscriptions5(NodeIdx, Rosters, Node_Groups,
|
||||
_Diff_Contacts = case
|
||||
filter_groups(_Roster#roster.groups, Node_Groups, [])
|
||||
of
|
||||
[] ->
|
||||
{_Contacts = Contacts,
|
||||
_Subscribers = Subscribers};
|
||||
Groups ->
|
||||
{_Contacts = case
|
||||
lists:keyfind(_Roster#roster.jid, 1, Contacts)
|
||||
of
|
||||
false ->
|
||||
[{_Roster#roster.jid, [{NodeIdx, Groups}]} | Contacts];
|
||||
{Entity, Subscriptions} ->
|
||||
lists:keyreplace(Entity, 1, Contacts,
|
||||
{Entity, [{NodeIdx, Groups} | Subscriptions]})
|
||||
end,
|
||||
_Subscribers = [_Roster#roster.jid | Subscribers]}
|
||||
end);
|
||||
%%
|
||||
subscriptions5(NodeIdx, [_Roster | Rosters], Node_Groups, Diff_Contacts) ->
|
||||
subscriptions5(NodeIdx, Rosters, Node_Groups, Diff_Contacts);
|
||||
%%
|
||||
subscriptions5(NodeIdx, Owner, Node_Groups, Contacts) ->
|
||||
subscriptions5(NodeIdx, _Rosters = get_entity_roster(Owner), Node_Groups,
|
||||
_Diff_Contacts = {Contacts, _Subscribers = []}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(delete_groups/2 ::
|
||||
(
|
||||
Old_Groups :: roster_groups(),
|
||||
Groups :: [] | roster_groups())
|
||||
-> Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
delete_groups(_Old_Groups, [] = _Groups) ->
|
||||
_Groups = [];
|
||||
%%
|
||||
delete_groups([] = _Old_Groups, Groups) ->
|
||||
Groups;
|
||||
%%
|
||||
delete_groups([Old_Group | Old_Groups], Groups) ->
|
||||
_Groups = delete_groups(Old_Groups, lists:delete(Old_Group, Groups)).
|
||||
|
||||
|
||||
%%
|
||||
-spec(diff_groups/2 ::
|
||||
(
|
||||
Groups :: node_groups() | [],
|
||||
_ :: node_groups()
|
||||
| {New_Groups :: [] | node_groups(),
|
||||
Old_Groups :: [] | node_groups()})
|
||||
-> Diff_Groups :: {New_Groups :: [] | node_groups(),
|
||||
Old_Groups :: [] | node_groups()}
|
||||
).
|
||||
|
||||
diff_groups([] = _Groups, Diff_Groups) -> %% when is_tuple(Diff_Groups)
|
||||
Diff_Groups;
|
||||
%%
|
||||
diff_groups([Group | Groups], {New_Groups, Old_Groups}) ->
|
||||
diff_groups(Groups,
|
||||
_Diff_Groups = case lists:delete(Group, Old_Groups) of
|
||||
Old_Groups -> {[Group | New_Groups], Old_Groups};
|
||||
Old_Groups2 -> {New_Groups, Old_Groups2}
|
||||
end);
|
||||
%%
|
||||
diff_groups(New_Groups, Old_Groups) ->
|
||||
diff_groups(New_Groups, {[], Old_Groups}).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_groups/3 ::
|
||||
(
|
||||
Roster_Groups :: roster_groups() | [],
|
||||
Node_Groups :: node_groups(),
|
||||
Groups :: [] | roster_groups())
|
||||
-> Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
filter_groups([] = _Roster_Groups, _Node_Groups, Groups) ->
|
||||
Groups;
|
||||
%%
|
||||
filter_groups([Roster_Group | Roster_Groups], Node_Groups, Groups) ->
|
||||
filter_groups(Roster_Groups, Node_Groups,
|
||||
_Groups = case lists:member(Roster_Group, Node_Groups) of
|
||||
true -> [Roster_Group | Groups];
|
||||
false -> Groups
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_subscriptions/2 ::
|
||||
(
|
||||
Nodes :: n0des(),
|
||||
Roster_Groups :: roster_groups())
|
||||
-> Subscriptions :: [] | subscriptions()
|
||||
).
|
||||
|
||||
filter_subscriptions(Nodes, Roster_Groups) ->
|
||||
_Subscriptions = filter_subscriptions(Nodes, Roster_Groups, []).
|
||||
|
||||
%%
|
||||
-spec(filter_subscriptions/3 ::
|
||||
(
|
||||
Nodes :: n0des(),
|
||||
Roster_Groups :: roster_groups(),
|
||||
Subscriptions :: [] | subscriptions())
|
||||
-> Subscriptions :: [] | subscriptions()
|
||||
).
|
||||
|
||||
filter_subscriptions([] = _Nodes, _Roster_Groups, Subscriptions) ->
|
||||
Subscriptions;
|
||||
%%
|
||||
filter_subscriptions([{NodeIdx, Node_Groups} | Nodes], Roster_Groups,
|
||||
Subscriptions) ->
|
||||
filter_subscriptions(Nodes, Roster_Groups,
|
||||
_Subscriptions = case filter_groups(Roster_Groups, Node_Groups, []) of
|
||||
[] -> Subscriptions;
|
||||
Groups -> [{NodeIdx, Groups} | Subscriptions]
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(diff_nodeidxs/2 ::
|
||||
(
|
||||
New_Subscriptions :: [] | subscriptions(),
|
||||
Old_Subscriptions :: [] | subscriptions())
|
||||
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
|
||||
).
|
||||
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions) ->
|
||||
_Diff_NodeIdxs = diff_nodeidxs(New_Subscriptions, Old_Subscriptions, []).
|
||||
|
||||
%%
|
||||
-spec(diff_nodeidxs/3 ::
|
||||
(
|
||||
New_Subscriptions :: [] | subscriptions(),
|
||||
Old_Subscriptions :: [] | subscriptions(),
|
||||
NodeIdxs_Subscriptions :: [] | nodeIdxs())
|
||||
-> Diff_NodeIdxs :: {NodeIdxs_Subscriptions :: [] | nodeIdxs(),
|
||||
NodeIdxs_Unsubscriptions :: [] | nodeIdxs()}
|
||||
).
|
||||
|
||||
diff_nodeidxs([] = _New_Subscriptions, Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
_Diff_NodeIdxs = {
|
||||
_NodeIdxs_Subscriptions = NodeIdxs_Subscriptions,
|
||||
_NodeIdxs_Unsubscriptions = lists:map(fun
|
||||
({NodeIdx, _Roster_Groups}) ->
|
||||
NodeIdx
|
||||
end, Old_Subscriptions)};
|
||||
%%
|
||||
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], [] = Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
|
||||
[NodeIdx | NodeIdxs_Subscriptions]);
|
||||
%%
|
||||
diff_nodeidxs([{NodeIdx, _Groups} | New_Subscriptions], Old_Subscriptions,
|
||||
NodeIdxs_Subscriptions) ->
|
||||
case lists:keydelete(NodeIdx, 1, Old_Subscriptions) of
|
||||
Old_Subscriptions ->
|
||||
diff_nodeidxs(New_Subscriptions, Old_Subscriptions,
|
||||
[NodeIdx | NodeIdxs_Subscriptions]);
|
||||
Subscriptions ->
|
||||
diff_nodeidxs(New_Subscriptions, _Old_Subscriptions = Subscriptions,
|
||||
NodeIdxs_Subscriptions)
|
||||
end.
|
||||
|
||||
|
||||
%% TODO : use a new mod_roster_api for this call
|
||||
-spec(roster_groups/2 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Contact :: xmpp_jid:usr_bare())
|
||||
-> Roster_Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
roster_groups({User, Server, _} = _Entity, Contact) ->
|
||||
_Roster_Groups = case
|
||||
gen_storage:transaction(Server, rosteritem,
|
||||
fun() ->
|
||||
gen_storage:select(Server, rostergroup,
|
||||
[{'=', user_host_jid, {User, Server, Contact}}])
|
||||
end)
|
||||
of
|
||||
{atomic, _RosterGroups} ->
|
||||
lists:map(fun
|
||||
(_RosterGroup) ->
|
||||
_RosterGroup#roster.groups
|
||||
end, _RosterGroups);
|
||||
_Error
|
||||
-> {error, 'internal-server-error'}
|
||||
end.
|
||||
|
||||
|
||||
%%
|
||||
-spec(select_roster_groups/1 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_entity())
|
||||
-> Roster_Groups :: [] | roster_groups()
|
||||
).
|
||||
|
||||
select_roster_groups({User, Server, _} = Entity) ->
|
||||
_Roster_Groups = case
|
||||
gen_storage:transaction(Server, rosteritem,
|
||||
fun() ->
|
||||
gen_storage:select(Server, rostergroup,
|
||||
[{'=', user_host_jid, {User, Server, '_'}}])
|
||||
end)
|
||||
of
|
||||
{atomic, _RosterGroups} ->
|
||||
lists:map(fun
|
||||
(_RosterGroup) ->
|
||||
_RosterGroup#roster.groups
|
||||
end, _RosterGroups);
|
||||
_Error
|
||||
-> {error, 'internal-server-error'}
|
||||
end.
|
||||
|
||||
|
||||
%% TESTS
|
||||
|
||||
%%
|
||||
monitor_roster_groups(Server, Roster) ->
|
||||
?INFO_MSG("SERVER ~p ROSTER ~p", [Server, Roster]),
|
||||
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_groups,
|
||||
[Server, Roster]),
|
||||
?INFO_MSG("MONITOR ROSTER GROUPS ~p", [Result]).
|
||||
|
||||
|
||||
monitor_contacts2('subscribed', Entity, Jid_Contact) ->
|
||||
Result = pubsub_db:transaction('mnesia', ?MODULE, monitor_contacts,
|
||||
['subscribed', Entity, Jid_Contact]),
|
||||
?INFO_MSG("MONITOR CONTACTS2 ~p", [Result]).
|
||||
|
||||
register1(NodeIdx, User, Groups) ->
|
||||
Server = <<"localhost">>,
|
||||
Owner = {list_to_binary(atom_to_list(User)), Server, undefined},
|
||||
Groups_B = lists:map(fun(Group) -> list_to_binary(atom_to_list(Group)) end, Groups),
|
||||
register_groups(dev, NodeIdx, Owner, Groups_B).
|
||||
|
||||
register(NodeIdx, User, Groups) ->
|
||||
pubsub_db:transaction('mnesia', ?MODULE, register1, [NodeIdx, User, Groups]).
|
||||
@@ -0,0 +1,570 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_hooks).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-import(pubsub_tools,
|
||||
[
|
||||
get_option/2,
|
||||
get_option/3,
|
||||
get_value/2,
|
||||
get_value/3,
|
||||
set_value/3,
|
||||
%%
|
||||
check_access_model/3,
|
||||
check_access_model/7,
|
||||
check_publish_model/3,
|
||||
is_contact_subscribed_to_node_owners/3,
|
||||
is_contact_in_allowed_roster_groups/2,
|
||||
has_subscriptions/1
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
%% 'node_config#send_last_published_item'
|
||||
-spec(presence_online/3 ::
|
||||
(
|
||||
From :: xmpp_jid:entity_full(),
|
||||
To :: xmpp_jid:entity_full(),
|
||||
C2SPid :: pid())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_online(#jid{luser = U, lserver = S, lresource = R} = Jid, Jid, C2SPid) ->
|
||||
?INFO_MSG("PRESENCE ONLINE From ~p ~n, To ~p ~n, C2SPid ~p ~n",
|
||||
[Jid, Jid, C2SPid]),
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
case lists:member(<<"last-published">>, Pubsub_Features) of
|
||||
true ->
|
||||
spawn(?MODULE, last_published_items,
|
||||
[_Host = <<"localhost">>, {U,S,R}]);
|
||||
false ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
presence_online(_, _, _) ->
|
||||
ok.
|
||||
|
||||
|
||||
%%
|
||||
-spec(last_published_items/2 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_full())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
last_published_items(Host, {U,S,_R} = Entity) ->
|
||||
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
||||
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
||||
Table_Pubsub_Last_Item = table('pubsub_last_item', 'dev'),
|
||||
lists:foreach(fun
|
||||
(State) ->
|
||||
last_published_items(Host, Entity, Table_Pubsub_Node,
|
||||
Table_Pubsub_Last_Item, State)
|
||||
end,
|
||||
mnesia:dirty_select(Table_Pubsub_State,
|
||||
[{#pubsub_state_dev{
|
||||
id = {{U,S,undefined}, '$1'},
|
||||
affiliation = '$2',
|
||||
access = '$3',
|
||||
subscriptions = '$4',
|
||||
_ = '_'
|
||||
},
|
||||
[{'=/=', '$2', 'outcast'},
|
||||
{'=/=', '$3', 'pending'},
|
||||
{'=/=', '$4', []}],
|
||||
['$$']}])).
|
||||
|
||||
%%
|
||||
-spec(last_published_items/5 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_full(),
|
||||
Table_Pubsub_Node :: atom(),
|
||||
Table_Pubsub_Last_Item :: atom(),
|
||||
State :: [exmpp_pubsub:nodeIdx() |
|
||||
'member' | 'owner' | 'publisher' |
|
||||
_ |
|
||||
exmpp_pubsub:subscriptions(),... ])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
last_published_items(Host, {_, _, Online_Resource} = Entity,
|
||||
Table_Pubsub_Node, Table_Pubsub_Last_Item,
|
||||
[NodeIdx, Affiliation, _Access, Subscriptions]) ->
|
||||
case mnesia:dirty_index_read(Table_Pubsub_Node, NodeIdx, idx) of
|
||||
[#pubsub_node_dev{
|
||||
id = {Pubsub_Host, NodeId},
|
||||
owners = Node_Owners,
|
||||
options = Node_Options
|
||||
}] ->
|
||||
case get_value(Node_Options, 'send_last_published_item') of
|
||||
'on_sub_and_presence' ->
|
||||
case mnesia:dirty_read(Table_Pubsub_Last_Item, NodeIdx) of
|
||||
[#pubsub_last_item_dev{
|
||||
id = ItemId,
|
||||
creation = {DateTime, Publisher},
|
||||
payload = Payload,
|
||||
options = Item_Options
|
||||
}] ->
|
||||
spawn(pubsub_broadcast, broadcast_publish_last2,
|
||||
[Host, Pubsub_Host, NodeId, Node_Options,
|
||||
Node_Owners,
|
||||
[{ItemId, Item_Options, Payload, Publisher, DateTime}],
|
||||
Entity, Affiliation,
|
||||
lists:foldl(fun
|
||||
({Subscription_State, SubId, Resource, Subscription_Options},
|
||||
Acc)
|
||||
when Subscription_State =/= 'pending'
|
||||
andalso (Resource == undefined
|
||||
orelse
|
||||
Resource == Online_Resource) ->
|
||||
[{Subscription_State, SubId,
|
||||
Online_Resource, Subscription_Options}
|
||||
| Acc];
|
||||
(_Subscription, Acc) ->
|
||||
Acc
|
||||
end, [], Subscriptions)]);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%% 'node_config#purge_offline'
|
||||
%% 'node_config#tempsub'
|
||||
%% 'subscribe_options#expire'
|
||||
|
||||
-spec(presence_offline/3 ::
|
||||
(
|
||||
_ :: _,
|
||||
Jid :: xmpp_jid:entity_full(),
|
||||
_ :: _)
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_offline({_DateTime, _Pid},
|
||||
#jid{luser = U, lserver = S, lresource = Offline_Resource} = _Jid, _) ->
|
||||
Host = <<"localhost">>,
|
||||
Pubsub_Features = node_flat_dev:pubsub_features(),
|
||||
Subscribe = lists:member(<<"subscribe">>, Pubsub_Features),
|
||||
Leased_Subscription = lists:member(<<"leased-subscription">>, Pubsub_Features),
|
||||
Purge_Nodes = lists:member(<<"purge-nodes">>, Pubsub_Features),
|
||||
Persistent_Items = lists:member(<<"persistent-items">>, Pubsub_Features),
|
||||
Subscription_Notifications = lists:member(<<"subscription-notifications">>,
|
||||
Pubsub_Features),
|
||||
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
||||
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
||||
Online_Resources = case ejabberd_sm:get_user_resources(U, S) of
|
||||
[] -> false;
|
||||
_ -> true
|
||||
end,
|
||||
lists:foreach(fun
|
||||
(Pubsub_State) ->
|
||||
presence_offline(Host,
|
||||
_Entity = {U,S,undefined},
|
||||
Table_Pubsub_State,
|
||||
Pubsub_State,
|
||||
Table_Pubsub_Node,
|
||||
Offline_Resource,
|
||||
Online_Resources,
|
||||
{Subscribe,
|
||||
Leased_Subscription,
|
||||
Purge_Nodes,
|
||||
Persistent_Items,
|
||||
Subscription_Notifications})
|
||||
end,
|
||||
mnesia:dirty_match_object(Table_Pubsub_State,
|
||||
#pubsub_state_dev{
|
||||
id = {{U,S,undefined}, '_'},
|
||||
_ = '_'
|
||||
})).
|
||||
|
||||
%%
|
||||
-spec(presence_offline/8 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
Table_Pubsub_State :: atom(),
|
||||
Pubsub_State :: mod_pubsub_dev:pubsub_state(),
|
||||
Table_Pubsub_Node :: atom(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Pubsub_Features :: {Subscribe :: boolean(),
|
||||
Leased_Subscription :: boolean(),
|
||||
Purge_Nodes :: boolean(),
|
||||
Persistent_Items :: boolean(),
|
||||
Subscription_Notifications :: boolean()})
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
presence_offline(Host, Entity, Table_Pubsub_State, Pubsub_State,
|
||||
Table_Pubsub_Node, Offline_Resource, Online_Resources,
|
||||
{Subscribe, Leased_Subscription, Purge_Nodes, Persistent_Items,
|
||||
Subscription_Notifications}) ->
|
||||
case
|
||||
mnesia:dirty_index_read(Table_Pubsub_Node,
|
||||
Pubsub_State#pubsub_state_dev.nodeidx, idx)
|
||||
of
|
||||
[#pubsub_node_dev{id = {Pubsub_Host, NodeId}} = Pubsub_Node] ->
|
||||
Node_Options = Pubsub_Node#pubsub_node_dev.options,
|
||||
|
||||
case
|
||||
Subscribe == true
|
||||
andalso
|
||||
get_value(Node_Options, 'tempsub') == true
|
||||
of
|
||||
true ->
|
||||
case
|
||||
filter_tempsub_subscriptions(
|
||||
get_value(Node_Options, 'notify_sub'),
|
||||
Pubsub_State#pubsub_state_dev.subscriptions,
|
||||
Offline_Resource, Online_Resources, {[], []})
|
||||
of
|
||||
%%
|
||||
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
||||
ok;
|
||||
%%
|
||||
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
||||
when Pubsub_State#pubsub_state_dev.affiliation == 'member'
|
||||
andalso Pubsub_State#pubsub_state_dev.itemids == [] ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_State,
|
||||
Pubsub_State),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case Subscription_Notifications of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok;
|
||||
%%
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
||||
mnesia:dirty_write(Table_Pubsub_State,
|
||||
Pubsub_State#pubsub_state_dev{
|
||||
subscriptions = Unexpired_Subscriptions
|
||||
}),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case Subscription_Notifications of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
case Subscribe == true andalso Leased_Subscription == true of
|
||||
true ->
|
||||
case
|
||||
filter_expired_subscriptions(
|
||||
get_value(Node_Options, 'notify_sub'),
|
||||
Pubsub_State#pubsub_state_dev.subscriptions,
|
||||
Offline_Resource, Online_Resources, {[], []})
|
||||
of
|
||||
%%
|
||||
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
||||
ok;
|
||||
%%
|
||||
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
||||
when Pubsub_State#pubsub_state_dev.affiliation == 'member' ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_State,
|
||||
Pubsub_State),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case
|
||||
Subscription_Notifications
|
||||
of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
|Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok;
|
||||
%%
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
||||
mnesia:dirty_write(Table_Pubsub_State,
|
||||
Pubsub_State#pubsub_state_dev{
|
||||
subscriptions = Unexpired_Subscriptions
|
||||
}),
|
||||
Notification_Type = get_value(Node_Options,
|
||||
'notification_type', 'headline'),
|
||||
notify_subscriptions(Host, Pubsub_Host,
|
||||
Entity, NodeId, Notification_Type,
|
||||
_Recipients = case
|
||||
Subscription_Notifications
|
||||
of
|
||||
true ->
|
||||
case
|
||||
lists:member(Entity,
|
||||
Pubsub_Node#pubsub_node_dev.owners)
|
||||
of
|
||||
true ->
|
||||
Pubsub_Node#pubsub_node_dev.owners;
|
||||
false ->
|
||||
[Entity
|
||||
| Pubsub_Node#pubsub_node_dev.owners]
|
||||
end;
|
||||
false ->
|
||||
Pubsub_Node#pubsub_node_dev.owners
|
||||
end,
|
||||
Expired_Subscriptions),
|
||||
ok
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end;
|
||||
[] ->
|
||||
ok
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(notify_subscriptions/7 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Pubsub_Host :: exmpp_pubsub:host(),
|
||||
Entity :: xmpp_jid:usr_bare(),
|
||||
NodeId :: exmpp_pubsub:nodeId(),
|
||||
Notification_Type :: 'message' | 'headline',
|
||||
Recipients :: [Entity::xmpp_jid:usr_bare(),...],
|
||||
Subscriptions :: [Subscription::exmpp_pubsub:subscription(),...])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
notify_subscriptions(Host, Pubsub_Host, {U,S,_} = _Entity, NodeId,
|
||||
Notification_Type, Recipients, Subscriptions) ->
|
||||
Pubsub_Component_Jid = jlib:make_jid(<<>>, Pubsub_Host, <<>>),
|
||||
Jids = [pubsub_tools:make_jid(Recipient) || Recipient <- Recipients],
|
||||
lists:foreach(fun
|
||||
({_, SubId, Resource, _}) ->
|
||||
Subscriber = jlib:jid_to_string({U,S,Resource}),
|
||||
lists:foreach(fun
|
||||
(Recipient) ->
|
||||
spawn(pubsub_broadcast, notify_subscription,
|
||||
[Host, NodeId, Pubsub_Component_Jid, Recipient,
|
||||
Notification_Type, {Subscriber, 'none', SubId}])
|
||||
end, Jids)
|
||||
end, Subscriptions).
|
||||
|
||||
%%
|
||||
filter_purged_offline_itemids([Publisher_ItemId | Publisher_ItemIds],
|
||||
Table_Pubsub_Item, NodeIdx, {U,S,R} = _Entity,
|
||||
{Node_ItemIds, Unpurged_ItemIds, Purged_ItemIds}) ->
|
||||
filter_purged_offline_itemids(Publisher_ItemIds, Table_Pubsub_Item, NodeIdx,
|
||||
{U,S,R},
|
||||
case
|
||||
mnesia:dirty_index_match_object(Table_Pubsub_Item,
|
||||
#pubsub_item_dev{
|
||||
id = {Publisher_ItemId, NodeIdx},
|
||||
nodeidx = NodeIdx,
|
||||
_ = '_'
|
||||
},
|
||||
nodeidx)
|
||||
of
|
||||
[#pubsub_item_dev{creation = {_DateTime, {U,S,_}}} = Pubsub_Item] ->
|
||||
mnesia:dirty_delete_object(Table_Pubsub_Item, Pubsub_Item);
|
||||
_ ->
|
||||
{Node_ItemIds,
|
||||
[Publisher_ItemId | Unpurged_ItemIds],
|
||||
Purged_ItemIds}
|
||||
end).
|
||||
|
||||
|
||||
%%
|
||||
-spec(filter_tempsub_subscriptions/5 ::
|
||||
(
|
||||
Notify_Sub :: boolean() | 'none',
|
||||
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Filtered_TempSub_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
})
|
||||
-> Filtered_TempSub_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
}
|
||||
).
|
||||
|
||||
filter_tempsub_subscriptions(_Notify_Sub, [] = _Subscriptions,
|
||||
_Offline_Resource, _Online_Resources, Filtered_TempSub_Subscriptions) ->
|
||||
Filtered_TempSub_Subscriptions;
|
||||
%%
|
||||
filter_tempsub_subscriptions(Notify_Sub,
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions})
|
||||
when ((Online_Resources == false
|
||||
andalso
|
||||
(Resource == undefined orelse Resource == Offline_Resource))
|
||||
orelse
|
||||
(Online_Resources == true
|
||||
andalso
|
||||
Resource == Offline_Resource)) ->
|
||||
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{Unexpired_Subscriptions,
|
||||
_Expired_Subscriptions = case Notify_Sub of
|
||||
true ->
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Expired_Subscriptions];
|
||||
_ ->
|
||||
Expired_Subscriptions
|
||||
end});
|
||||
%%
|
||||
filter_tempsub_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
||||
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
||||
|
||||
%%
|
||||
-spec(filter_expired_subscriptions/5 ::
|
||||
(
|
||||
Notify_Sub :: boolean() | 'none',
|
||||
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Offline_Resource :: xmpp_jid:resource_jid(),
|
||||
Online_Resources :: boolean(),
|
||||
Filtered_Expired_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
})
|
||||
-> Filtered_Expired_Subscriptions :: {
|
||||
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
||||
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
||||
}
|
||||
).
|
||||
|
||||
filter_expired_subscriptions(_Notify_Sub, [] = _Subscriptions, _Offline_Resource,
|
||||
_Online_Resources, Filtered_Expired_Subscriptions) ->
|
||||
Filtered_Expired_Subscriptions;
|
||||
%%
|
||||
filter_expired_subscriptions(Notify_Sub,
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions})
|
||||
when Subscription_Options =/= []
|
||||
andalso ((Online_Resources == false
|
||||
andalso
|
||||
(Resource == undefined orelse Resource == Offline_Resource))
|
||||
orelse
|
||||
(Online_Resources == true
|
||||
andalso
|
||||
Resource == Offline_Resource)) ->
|
||||
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
case get_value(Subscription_Options, 'expire') of
|
||||
'presence' ->
|
||||
{Unexpired_Subscriptions,
|
||||
_Expired_Subscriptions = case Notify_Sub of
|
||||
true ->
|
||||
[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Expired_Subscriptions];
|
||||
false ->
|
||||
Expired_Subscriptions
|
||||
end};
|
||||
_ ->
|
||||
{[{Subscription_State, SubId, Resource, Subscription_Options}
|
||||
| Unexpired_Subscriptions],
|
||||
Expired_Subscriptions}
|
||||
end);
|
||||
%%
|
||||
filter_expired_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
||||
Offline_Resource, Online_Resources,
|
||||
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
||||
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
||||
Online_Resources,
|
||||
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
||||
|
||||
|
||||
%%
|
||||
roster_process_item(Roster_Item, Server) ->
|
||||
spawn(pubsub_groups, monitor_roster_groups, [Server, Roster_Item]),
|
||||
Roster_Item.
|
||||
|
||||
|
||||
|
||||
roster_in_subscription(Boolean, User, Server, Jid_Contact,
|
||||
'subscribed' = _Subscription_Type) ->
|
||||
spawn(pubsub_groups, monitor_contacts2,
|
||||
['subscribed', {User, Server, undefined}, Jid_Contact]),
|
||||
Boolean;
|
||||
roster_in_subscription(Boolean, _User, _Server, _JID, _SubscriptionType) ->
|
||||
Boolean.
|
||||
@@ -0,0 +1,113 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%% important note:
|
||||
%% new/1 and free/2 MUST be called inside a transaction bloc
|
||||
|
||||
-module(pubsub_index_dev).
|
||||
-author('christophe.romain@process-one.net').
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
-export([
|
||||
init/1,
|
||||
new/2,
|
||||
free/3
|
||||
]).
|
||||
|
||||
-import(pubsub_db_mnesia,
|
||||
[
|
||||
table/2
|
||||
]).
|
||||
|
||||
|
||||
%%
|
||||
-spec(init/1 ::
|
||||
(
|
||||
Suffix::atom()) -> 'ok'
|
||||
).
|
||||
|
||||
init(Suffix) ->
|
||||
mnesia:create_table(table('pubsub_index_dev', Suffix),
|
||||
[{disc_copies, [node()]},
|
||||
{record_name, pubsub_index_dev},
|
||||
{attributes, record_info(fields, pubsub_index_dev)}]).
|
||||
|
||||
%%
|
||||
-spec(new/2 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
Index :: exmpp_pubsub:index())
|
||||
-> Idx::exmpp_pubsub:nodeIdx()
|
||||
).
|
||||
|
||||
new(Suffix, Index) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Index = table('pubsub_index_dev', Suffix),
|
||||
Index, write)
|
||||
of
|
||||
[#pubsub_index_dev{free = []} = Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
last = Idx = Pubsub_Index#pubsub_index_dev.last + 1
|
||||
},
|
||||
write),
|
||||
Idx;
|
||||
[#pubsub_index_dev{free = [Idx|Free]} = Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
free = Free
|
||||
},
|
||||
write),
|
||||
Idx;
|
||||
_ ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
#pubsub_index_dev{index = Index, last = 1, free = []}, write),
|
||||
1
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(free/3 ::
|
||||
(
|
||||
Suffix :: atom(),
|
||||
Index :: exmpp_pubsub:index(),
|
||||
Idx :: exmpp_pubsub:nodeIdx())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
free(Suffix, Index, Idx) ->
|
||||
case
|
||||
mnesia:read(Table_Pubsub_Index = table('pubsub_index_dev', Suffix),
|
||||
Index, write)
|
||||
of
|
||||
[Pubsub_Index] ->
|
||||
mnesia:write(Table_Pubsub_Index,
|
||||
Pubsub_Index#pubsub_index_dev{
|
||||
free = [Idx | Pubsub_Index#pubsub_index_dev.free]
|
||||
},
|
||||
write);
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,685 @@
|
||||
%%% ====================================================================
|
||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
||||
%%% compliance with the License. You should have received a copy of the
|
||||
%%% Erlang Public License along with this software. If not, it can be
|
||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
||||
%%%
|
||||
%%% Software distributed under the License is distributed on an "AS IS"
|
||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
%%% the License for the specific language governing rights and limitations
|
||||
%%% under the License.
|
||||
%%%
|
||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
||||
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
||||
%%% All Rights Reserved.''
|
||||
%%% This software is copyright 2006-2013, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2013 ProcessOne
|
||||
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
%%% ====================================================================
|
||||
|
||||
%%% @headerfile "pubsub_dev.hrl"
|
||||
|
||||
-module(pubsub_tools).
|
||||
-author('karim.gemayel@process-one.net').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-include("pubsub_dev.hrl").
|
||||
|
||||
jid_to_string({undefined, S, undefined}) ->
|
||||
jlib:jid_to_string({<<>>, S, <<>>});
|
||||
jid_to_string({undefined, S, R}) ->
|
||||
jlib:jid_to_string({<<>>, S, R});
|
||||
jid_to_string({U, S, undefined}) ->
|
||||
jlib:jid_to_string({U, S, <<>>});
|
||||
jid_to_string(USR) ->
|
||||
jlib:jid_to_string(USR).
|
||||
|
||||
make_jid({undefined, S, undefined}) ->
|
||||
jlib:make_jid(<<>>, S, <<>>);
|
||||
make_jid({U, S, undefined}) ->
|
||||
jlib:make_jid({U, S, <<>>});
|
||||
make_jid(Entity) ->
|
||||
jlib:make_jid(Entity).
|
||||
|
||||
%% @doc Determine if data is a JID
|
||||
-spec(is_jid/1 ::
|
||||
(
|
||||
Data :: binary() | undefined)
|
||||
-> xmpp_jid:entity() | {error, 'jid-malformed'}
|
||||
).
|
||||
|
||||
is_jid(Data) ->
|
||||
try jlib:string_to_jid(Data) of
|
||||
#jid{} = Jid -> Jid
|
||||
catch
|
||||
_Error -> {error, 'jid-malformed'}
|
||||
end.
|
||||
|
||||
%%%
|
||||
%-spec(get_value/2 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
% | [],
|
||||
% Key :: atom())
|
||||
% -> Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | 'none'
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...]
|
||||
%).
|
||||
|
||||
get_value({Node_Options, [] = _Item_Options}, Key) ->
|
||||
get_value(Node_Options, Key, 0);
|
||||
%%
|
||||
get_value({Node_Options, Item_Options}, Key) ->
|
||||
case get_value(Item_Options, Key, 'none') of
|
||||
'none' -> get_value(Node_Options, Key, false);
|
||||
Value -> Value
|
||||
end;
|
||||
%%
|
||||
get_value([], _Key) -> 'none';
|
||||
%%
|
||||
get_value(Options, Key) ->
|
||||
get_value(Options, Key, 'none').
|
||||
|
||||
%%%
|
||||
%-spec(get_value/3 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Default :: term())
|
||||
% -> Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...]
|
||||
%).
|
||||
get_value({Node_Options, [] = _Item_Options}, Key, Default) ->
|
||||
get_value(Node_Options, Key, Default);
|
||||
%%
|
||||
get_value({Node_Options, Item_Options}, Key, Default) ->
|
||||
case get_value(Item_Options, Key, 'none') of
|
||||
'none' -> get_value(Node_Options, Key, Default);
|
||||
Value -> Value
|
||||
end;
|
||||
%%
|
||||
get_value(Options, Key, Default) ->
|
||||
case lists:keyfind(Key, 1, Options) of
|
||||
{_Key, Value} -> Value;
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
%%%
|
||||
%-spec(set_value/3 ::
|
||||
%(
|
||||
% Options :: pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Value :: atom()
|
||||
% | binary()
|
||||
% | boolean()
|
||||
% | non_neg_integer()
|
||||
% | undefined
|
||||
% | []
|
||||
% | [atom(),...]
|
||||
% | [binary(),...]
|
||||
% | [boolean(),...]
|
||||
% | [non_neg_integer(),...])
|
||||
% -> Options :: pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
%).
|
||||
|
||||
set_value(Options, Key, Value) ->
|
||||
lists:keyreplace(Key, 1, Options, {Key, Value}).
|
||||
|
||||
%%
|
||||
|
||||
%-spec(get_option/2 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription()
|
||||
% | [],
|
||||
% Key :: atom())
|
||||
% -> Option :: pubsub_options:option_item()
|
||||
% | pubsub_options:option_node()
|
||||
% | pubsub_options:option_subscription()
|
||||
% | 'none'
|
||||
%).
|
||||
|
||||
get_option({Node_Options, [] = _Item_Options}, Key) ->
|
||||
get_option(Node_Options, Key, 'none');
|
||||
%%
|
||||
get_option({Node_Options, Item_Options}, Key) ->
|
||||
case get_option(Item_Options, Key, 'none') of
|
||||
'none' -> get_option(Node_Options, Key, 'none');
|
||||
Option -> Option
|
||||
end;
|
||||
%%
|
||||
get_option([], _Key) -> 'none';
|
||||
%%
|
||||
get_option(Options, Key) ->
|
||||
get_option(Options, Key, 'none').
|
||||
|
||||
%%%
|
||||
%-spec(get_option/3 ::
|
||||
%(
|
||||
% Options :: {Node_Options :: pubsub_options:options_node(),
|
||||
% Item_Options :: [] | pubsub_options:options_item()}
|
||||
% | pubsub_options:options_item()
|
||||
% | pubsub_options:options_node()
|
||||
% | pubsub_options:options_subscription(),
|
||||
% Key :: atom(),
|
||||
% Default :: term())
|
||||
% -> Option :: pubsub_options:option_item()
|
||||
% | pubsub_options:option_node()
|
||||
% | pubsub_options:option_subscription()
|
||||
% | term()
|
||||
%).
|
||||
|
||||
get_option({Node_Options, [] = _Item_Options}, Key, Default) ->
|
||||
get_option(Node_Options, Key, Default);
|
||||
%%
|
||||
get_option({Node_Options, Item_Options}, Key, Default) ->
|
||||
case get_option(Item_Options, Key, 'none') of
|
||||
'none' -> get_option(Node_Options, Key, Default);
|
||||
Option -> Option
|
||||
end;
|
||||
%%
|
||||
get_option(Options, Key, Default) ->
|
||||
case lists:keyfind(Key, 1, Options) of
|
||||
{_Key, Value} -> _Option = {Key, Value};
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(get_entity_roster/1 ::
|
||||
(
|
||||
Entity :: xmpp_jid:usr_entity()
|
||||
| xmpp_jid:entity())
|
||||
-> Roster::[Roster_Item::#roster{}]
|
||||
).
|
||||
|
||||
get_entity_roster({U,S, _R} = _USR_Entity) ->
|
||||
_Roster = ejabberd_hooks:run_fold(roster_get, S, [], [{U,S}]);
|
||||
get_entity_roster(#jid{luser = U, lserver = S} = _Jid_Entity) ->
|
||||
_Roster = get_entity_roster({U,S, undefined}).
|
||||
|
||||
%%
|
||||
-spec(check_access_model/3 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_entity(),
|
||||
Criteria :: {Access_Model :: pubsub_options:access_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions(),
|
||||
Node_Owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed()})
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
).
|
||||
|
||||
check_access_model(_Host, _Entity,
|
||||
{_Access_Model, 'outcast' = _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'open' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity,
|
||||
{'presence' = _Access_Model, _Affiliation, _Subscriptions, Node_Owners,
|
||||
_Rosters_Groups_Allowed}) ->
|
||||
case is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners) of
|
||||
false ->
|
||||
{error, 'forbidden'};
|
||||
_Node_Owner ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, Entity,
|
||||
{'roster' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
Rosters_Groups_Allowed}) ->
|
||||
case is_contact_in_allowed_roster_groups(Entity, Rosters_Groups_Allowed) of
|
||||
false ->
|
||||
{error, 'forbidden'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'whitelist' = _Access_Model, Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed})
|
||||
when Affiliation == 'member'
|
||||
%%orelse Affiliation == 'owner'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
check_access_model(_Host, _Entity,
|
||||
{'whitelist' = _Access_Model, _Affiliation, _Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed}) ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
check_access_model(_Host, _Entity,
|
||||
{'authorize' = _Access_Model, _Affiliation, Subscriptions, _Node_Owners,
|
||||
_Roster_Groups_Allowed}) ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true -> ok;
|
||||
false -> {error, 'forbidden'}
|
||||
end.
|
||||
|
||||
|
||||
|
||||
%%
|
||||
-spec(check_access_model/7 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Entity :: xmpp_jid:usr_entity(),
|
||||
Access_Model :: pubsub_options:access_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions(),
|
||||
Node_Owners :: [Node_Owner::xmpp_jid:usr_bare(),...],
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
| {error, 'item-not-found'}
|
||||
).
|
||||
|
||||
check_access_model(_Host, _Entity, _Access_Model, 'owner' = _Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity, Access_Model, 'outcast' = _Affiliation,
|
||||
_Subscriptions, Node_Owners, Rosters_Groups_Allowed) ->
|
||||
case Access_Model of
|
||||
%%
|
||||
'open'->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
'presence' ->
|
||||
case
|
||||
is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners)
|
||||
of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
_Node_Owner ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
'roster' ->
|
||||
case
|
||||
is_contact_in_allowed_roster_groups(Entity,
|
||||
Rosters_Groups_Allowed)
|
||||
of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
'authorize' ->
|
||||
{error, 'forbidden'};
|
||||
%%
|
||||
'whitelist' ->
|
||||
{error, 'item-not-found'}
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'open' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
ok;
|
||||
%%
|
||||
check_access_model(Host, Entity, 'presence' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, Node_Owners, _Rosters_Groups_Allowed) ->
|
||||
case is_contact_subscribed_to_node_owners(Host, Entity, Node_Owners) of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
_Node_Owner ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, Entity, 'roster' = _Access_Model, _Affiliation,
|
||||
_Subscriptions, _Node_Owners, Rosters_Groups_Allowed) ->
|
||||
case is_contact_in_allowed_roster_groups(Entity, Rosters_Groups_Allowed) of
|
||||
false ->
|
||||
{error, 'item-not-found'};
|
||||
{_Node_Owner, _Roster_Group_Allowed} ->
|
||||
ok
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'whitelist' = _Access_Model, Affiliation,
|
||||
_Subscriptions, _Node_Owners, _Roster_Groups_Allowed) ->
|
||||
case Affiliation of
|
||||
Affiliation
|
||||
when Affiliation == 'member'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
{error, 'item-not-found'}
|
||||
end;
|
||||
%%
|
||||
check_access_model(_Host, _Entity, 'authorize' = _Access_Model, _Affiliation,
|
||||
Subscriptions, _Node_Owners, _Roster_Groups_Allowed) ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
{error, 'item-not-found'}
|
||||
end.
|
||||
|
||||
|
||||
-spec(check_publish_model/3 ::
|
||||
(
|
||||
Publish_Model :: pubsub_options:publish_model(),
|
||||
Affiliation :: exmpp_pubsub:affiliation(),
|
||||
Subscriptions :: exmpp_pubsub:subscriptions())
|
||||
-> ok
|
||||
%%%
|
||||
| {error, 'forbidden'}
|
||||
).
|
||||
|
||||
check_publish_model('open' = _Publish_Model, _Affiliation, _Subscriptions) ->
|
||||
ok;
|
||||
%%
|
||||
check_publish_model('publishers' = _Publish_Model, Affiliation, _Subscriptions) ->
|
||||
case Affiliation of
|
||||
Affiliation
|
||||
when Affiliation == 'owner'
|
||||
orelse Affiliation == 'publish-only'
|
||||
orelse Affiliation == 'publisher' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
%%
|
||||
check_publish_model('subscribers' = _Publish_Model, Affiliation, Subscriptions) ->
|
||||
case Affiliation of
|
||||
'owner' ->
|
||||
ok;
|
||||
_Affiliation ->
|
||||
case has_subscriptions(Subscriptions) of
|
||||
true ->
|
||||
ok;
|
||||
false ->
|
||||
{error, 'forbidden'}
|
||||
end
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(has_subscriptions/1 ::
|
||||
(
|
||||
Subscriptions :: exmpp_pubsub:subscriptions())
|
||||
-> Has_Subscriptions::boolean()
|
||||
).
|
||||
|
||||
has_subscriptions([] = _Subscriptions) ->
|
||||
false;
|
||||
has_subscriptions(
|
||||
[{'pending' = _Subscription_State, _SubId, _Resource, _Subscription_Options}]) ->
|
||||
false;
|
||||
has_subscriptions(_Subscriptions) ->
|
||||
true.
|
||||
|
||||
%%
|
||||
%% @doc Check if a contact is subscribed to at least one local node owner
|
||||
%% amongst a list of (remote and local) node owners
|
||||
-spec(is_contact_subscribed_to_node_owners/3 ::
|
||||
(
|
||||
Host :: xmpp_jid:raw_jid_component_bare(),
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Node_Owners :: [] | [Node_Owner::xmpp_jid:usr_bare(),...])
|
||||
-> Is_Contact_Subscribed_To_Node_Owners :: false | xmpp_jid:usr_bare()
|
||||
).
|
||||
|
||||
is_contact_subscribed_to_node_owners(_Host, _Contact, [] = _Node_Owners) ->
|
||||
false;
|
||||
%% The node owner is a local entity, check if the contact is subscribed to it
|
||||
is_contact_subscribed_to_node_owners(Host, Contact,
|
||||
[{_U, Host, _R} = Local_Node_Owner | Node_Owners] = _Node_Owners) ->
|
||||
_Is_Contact_Subscribed_To_Node_Owners = case
|
||||
is_contact_subscribed_to_entity(Contact,
|
||||
_Local_Node_Owner_Roster = get_entity_roster(Local_Node_Owner))
|
||||
of
|
||||
true ->
|
||||
Local_Node_Owner;
|
||||
false ->
|
||||
is_contact_subscribed_to_node_owners(Host, Contact, Node_Owners)
|
||||
end;
|
||||
%% The node owner is a remote entity, don't check if the contact is subscribed to it
|
||||
is_contact_subscribed_to_node_owners(Host, Contact,
|
||||
[_Remote_Node_Owner | Node_Owners] = _Node_Owners) ->
|
||||
is_contact_subscribed_to_node_owners(Host, Contact, Node_Owners).
|
||||
|
||||
%%
|
||||
%% @doc Check if an entity is in a #roster{}
|
||||
%% with #roster.subscription == 'from' or
|
||||
%% with #roster.subscription == 'both'
|
||||
-spec(is_contact_subscribed_to_entity/2 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Entity_Roster :: [] | [Roster_Item::#roster{},...])
|
||||
-> Is_Contact_Subscribed::boolean()
|
||||
).
|
||||
|
||||
is_contact_subscribed_to_entity(_Contact, [] = _Entity_Roster) ->
|
||||
_Is_Contact_Subscribed = false;
|
||||
%% Contact is included in a #roster{} item with
|
||||
%% a subscription of type 'from' and 'both' (i.e. is subscribed to it)
|
||||
is_contact_subscribed_to_entity({U, S, _R} = _Contact,
|
||||
[#roster{jid = {U, S, _}, subscription = Subscription} = _Roster_Item
|
||||
| _Roster_Items] = _Entity_Roster)
|
||||
when Subscription == 'from' orelse Subscription == 'both' ->
|
||||
_Is_Contact_Subscribed = true;
|
||||
%% Contact is not included in a #roster{} item
|
||||
%% or has a subscription of type different than 'from' and 'both'
|
||||
%% ( i.e. is not subscribed to it),
|
||||
%% check next roster items
|
||||
is_contact_subscribed_to_entity(Contact,
|
||||
[_Roster_Item | Roster_Items] = _Entity_Roster) ->
|
||||
_Is_Contact_Subscribed = is_contact_subscribed_to_entity(Contact,
|
||||
Roster_Items).
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_groups/2 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed())
|
||||
-> Roster_Group_Allowed :: false
|
||||
| {Entity :: xmpp_jid:usr_bare(),
|
||||
Roster_Group :: pubsub_options:roster_group()}
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_groups(_Contact, [] = _Rosters_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_groups(Contact,
|
||||
[{Entity, Entity_Roster_Groups_Allowed} | Rosters_Groups_Allowed]
|
||||
= _Rosters_Groups_Allowed) ->
|
||||
case
|
||||
is_contact_in_allowed_roster_group(Contact,
|
||||
_Entity_Roster = get_entity_roster(Entity),
|
||||
Entity_Roster_Groups_Allowed)
|
||||
of
|
||||
false ->
|
||||
is_contact_in_allowed_roster_groups(Contact, Rosters_Groups_Allowed);
|
||||
Roster_Group ->
|
||||
{Entity, Roster_Group}
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_group/3 ::
|
||||
(
|
||||
Contact :: xmpp_jid:usr_entity(),
|
||||
Entity_Roster :: [] | [Roster_Item::#roster{groups::pubsub_options:roster_groups()}],
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group(),...])
|
||||
-> Roster_Group :: false | pubsub_options:roster_group()
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_group(_Contact, [] = _Entity_Roster,
|
||||
_Roster_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_group({U, S, _R} = _Contact,
|
||||
[#roster{jid = {U, S, _}, subscription = Subscription, groups = Roster_Groups}
|
||||
| _Other_Roster_Items] = _Entity_Roster, Roster_Groups_Allowed)
|
||||
when Subscription == 'from' orelse Subscription == 'both' ->
|
||||
is_contact_in_allowed_roster_group(Roster_Groups, Roster_Groups_Allowed);
|
||||
%%
|
||||
is_contact_in_allowed_roster_group(Contact,
|
||||
[_Roster_Item | Roster_Items] = _Entity_Roster, Roster_Groups_Allowed) ->
|
||||
is_contact_in_allowed_roster_group(Contact, Roster_Items,
|
||||
Roster_Groups_Allowed).
|
||||
|
||||
%%
|
||||
-spec(is_contact_in_allowed_roster_group/2 ::
|
||||
(
|
||||
Roster_Groups :: [] | [Roster_Group::pubsub_options:roster_group()],
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group(),...])
|
||||
-> Roster_Group :: false | pubsub_options:roster_group()
|
||||
).
|
||||
|
||||
is_contact_in_allowed_roster_group([] = _Roster_Groups, _Roster_Groups_Allowed) ->
|
||||
false;
|
||||
%%
|
||||
is_contact_in_allowed_roster_group([Roster_Group | Roster_Groups]
|
||||
= _Roster_Groups, Roster_Groups_Allowed) ->
|
||||
case lists:member(Roster_Group, Roster_Groups_Allowed) of
|
||||
true ->
|
||||
Roster_Group;
|
||||
false ->
|
||||
is_contact_in_allowed_roster_group(Roster_Groups,
|
||||
Roster_Groups_Allowed)
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(get_user_resources/2 ::
|
||||
(
|
||||
User :: binary(),
|
||||
Server :: binary())
|
||||
-> Resources::[Resource::xmpp_jid:resource_jid()]
|
||||
).
|
||||
|
||||
get_user_resources(User, Server) ->
|
||||
ejabberd_sm:get_user_resources(User, Server).
|
||||
|
||||
%%
|
||||
-spec(get_resources_show/2 ::
|
||||
(
|
||||
User :: binary(),
|
||||
Server :: binary())
|
||||
-> Resources_Show :: [{Resource :: xmpp_jid:resource_jid(),
|
||||
Show :: 'away' | 'chat' | 'dnd' | 'online' | 'xa' }]
|
||||
).
|
||||
|
||||
get_resources_show(User, Server) ->
|
||||
_Resources_Show = lists:foldl(fun
|
||||
(Resource, Resources_Show) ->
|
||||
case ejabberd_sm:get_session_pid(User, Server, Resource) of
|
||||
C2SPid when is_pid(C2SPid) ->
|
||||
case ejabberd_c2s:get_presence(C2SPid) of
|
||||
{_User, _Resource, Show, _} ->
|
||||
[{Resource, list_to_atom(Show)} | Resources_Show];
|
||||
_ ->
|
||||
Resources_Show
|
||||
end;
|
||||
_ ->
|
||||
Resources_Show
|
||||
end
|
||||
end, [], _Resources = ejabberd_sm:get_user_resources(User, Server)).
|
||||
|
||||
|
||||
%%
|
||||
-spec(rosters_groups_allowed_cache/2 ::
|
||||
(
|
||||
Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed(),
|
||||
Rosters_Groups_Allowed_Cache :: pubsub_options:rosters_groups_allowed())
|
||||
-> Is_Roster_Groups_Cached::boolean()
|
||||
).
|
||||
|
||||
rosters_groups_allowed_cache(_Rosters_Groups_Allowed,
|
||||
[] = _Rosters_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
rosters_groups_allowed_cache([] = _Rosters_Groups_Allowed,
|
||||
_Rosters_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
rosters_groups_allowed_cache(
|
||||
[{Entity, Roster_Groups_Allowed} | Rosters_Groups_Allowed],
|
||||
Rosters_Groups_Allowed_Cache) ->
|
||||
case lists:keyfind(Entity, 1, Rosters_Groups_Allowed_Cache) of
|
||||
{_Entity, Roster_Groups_Allowed_Cache} ->
|
||||
case
|
||||
roster_groups_allowed_cache(Roster_Groups_Allowed,
|
||||
Roster_Groups_Allowed_Cache)
|
||||
of
|
||||
true ->
|
||||
true;
|
||||
false ->
|
||||
rosters_groups_allowed_cache(Rosters_Groups_Allowed,
|
||||
Rosters_Groups_Allowed_Cache)
|
||||
end;
|
||||
false ->
|
||||
rosters_groups_allowed_cache(Rosters_Groups_Allowed,
|
||||
Rosters_Groups_Allowed_Cache)
|
||||
end.
|
||||
|
||||
%%
|
||||
-spec(roster_groups_allowed_cache/2 ::
|
||||
(
|
||||
Roster_Groups_Allowed :: [Roster_Group_Allowed::pubsub_options:roster_group()],
|
||||
Roster_Groups_Allowed_Cache :: [Roster_Group_Allowed_Cache::pubsub_options:roster_group()])
|
||||
-> Is_Roster_Groups_Cached :: boolean()
|
||||
).
|
||||
|
||||
roster_groups_allowed_cache(_Roster_Groups_Allowed,
|
||||
[] = _Roster_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
roster_groups_allowed_cache([] = _Roster_Groups_Allowed,
|
||||
_Roster_Groups_Allowed_Cache) ->
|
||||
false;
|
||||
%%
|
||||
roster_groups_allowed_cache([Roster_Group_Allowed | Roster_Groups_Allowed],
|
||||
Roster_Groups_Allowed_Cache) ->
|
||||
case lists:member(Roster_Group_Allowed, Roster_Groups_Allowed_Cache) of
|
||||
true ->
|
||||
true;
|
||||
false ->
|
||||
roster_groups_allowed_cache(Roster_Groups_Allowed,
|
||||
Roster_Groups_Allowed_Cache)
|
||||
end.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
-module(xmpp_xdata).
|
||||
|
||||
|
||||
-include("jlib.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-compile(export_all).
|
||||
|
||||
xmlcdata(CData) ->
|
||||
{xmlcdata, CData}.
|
||||
|
||||
xmlattr(Name, Value) ->
|
||||
% #xmlattr{name = Name, value = Value}.
|
||||
{Name, Value}.
|
||||
|
||||
xmlattr_label(Label) ->
|
||||
xmlattr(<<"label">>, Label).
|
||||
|
||||
xmlattr_type(Type) ->
|
||||
xmlattr(<<"type">>, Type).
|
||||
|
||||
xmlattr_var(Var) ->
|
||||
xmlattr(<<"var">>, Var).
|
||||
|
||||
|
||||
xmlel(NS, Name, Attrs, Children) ->
|
||||
#xmlel{name = Name, attrs = [{<<"xmlns">>, NS} | Attrs], children = Children}.
|
||||
|
||||
xmlel(Name, Attrs, Children) ->
|
||||
xmlel(?NS_XDATA, Name, Attrs, Children).
|
||||
|
||||
xmlel_desc(CData) ->
|
||||
xmlel(<<"desc">>, [], [xmlcdata(CData)]).
|
||||
|
||||
xmlel_value(Value) ->
|
||||
xmlel(<<"value">>, [], [xmlcdata(Value)]).
|
||||
|
||||
xmlel_option({Value, Label}) ->
|
||||
xmlel(<<"option">>, [xmlattr_label(Label)], [xmlel_value(Value)]);
|
||||
xmlel_option(Value) ->
|
||||
xmlel(<<"option">>, [], [xmlel_value(Value)]).
|
||||
|
||||
xmlel_field(Var, Type, Values) ->
|
||||
xmlel(<<"field">>,
|
||||
[xmlattr_var(Var),
|
||||
xmlattr_type(Type)],
|
||||
[xmlel_value(Value) || Value <- Values]).
|
||||
|
||||
xmlel_field(Var, Type, Label, Values, Options) ->
|
||||
xmlel(<<"field">>,
|
||||
[xmlattr_var(Var),
|
||||
xmlattr_label(Label),
|
||||
xmlattr_type(Type)],
|
||||
[xmlel_option(Option) || Option <- Options]
|
||||
++
|
||||
[xmlel_value(Value) || Value <- Values]).
|
||||
|
||||
xmlel_field_boolean(Var, Label, Value) ->
|
||||
xmlel_field(Var, <<"boolean">>, Label, [Value], []).
|
||||
|
||||
%%
|
||||
xmlel_field_fixed(Var, Label, Value) ->
|
||||
xmlel_field(Var, <<"fixed">>, Label, [Value], []).
|
||||
|
||||
%%
|
||||
xmlel_field_hidden(Var, Value) ->
|
||||
xmlel_field(Var, <<"hidden">>, [Value]).
|
||||
|
||||
%%
|
||||
xmlel_field_list_single(Var, Label, Value, Options) ->
|
||||
xmlel_field(Var, <<"list-single">>, Label, [Value], Options).
|
||||
|
||||
%%
|
||||
xmlel_field_list_multi(Var, Label, Values, Options) ->
|
||||
xmlel_field(Var, <<"list-multi">>, Label, Values, Options).
|
||||
|
||||
%%
|
||||
xmlel_field_text_single(Var, Label, undefined = _Text) ->
|
||||
xmlel_field(Var, <<"text-single">>, Label, [], []);
|
||||
%%
|
||||
xmlel_field_text_single(Var, Label, Text) ->
|
||||
xmlel_field(Var, <<"text-single">>, Label, [Text], []).
|
||||
|
||||
%%
|
||||
xmlel_field_text_multi(Var, Label, Values) ->
|
||||
xmlel_field(Var, <<"text-multi">>, Label, Values, []).
|
||||
|
||||
%%
|
||||
xmlel_field_jid_multi(Var, Label, Jids) ->
|
||||
xmlel_field(Var, <<"jid-multi">>, Label, Jids, []).
|
||||
|
||||
%%
|
||||
xmlel_field_jid_single(Var, Label, Jid) ->
|
||||
xmlel_field(Var, <<"jid-single">>, Label, [Jid], []).
|
||||
|
||||
%%
|
||||
xmlel_x(Type, Fields) ->
|
||||
xmlel(<<"x">>, [xmlattr_type(Type)], Fields).
|
||||
|
||||
%%
|
||||
xmlel_title(Title) ->
|
||||
xmlel(<<"title">>, [], [xmlcdata(Title)]).
|
||||
|
||||
%%
|
||||
xmlel_instructions(Instructions) when is_list(Instructions) ->
|
||||
lists:map(fun xmlel_instructions/1, Instructions);
|
||||
%%
|
||||
xmlel_instructions(Instruction) when is_binary(Instruction) ->
|
||||
xmlel(<<"instructions">>, [], [xmlcdata(Instruction)]).
|
||||
@@ -0,0 +1,421 @@
|
||||
{"Access Configuration","Configuració d'accesos"}.
|
||||
{"Access Control List Configuration","Configuració de la Llista de Control d'Accés"}.
|
||||
{"Access Control Lists","Llista de Control d'Accés"}.
|
||||
{"Access control lists","Llistes de Control de Accés"}.
|
||||
{"Access denied by service policy","Accés denegat per la política del servei"}.
|
||||
{"Access rules","Regles d'accés"}.
|
||||
{"Access Rules","Regles d'Accés"}.
|
||||
{"Action on user","Acció en l'usuari"}.
|
||||
{"Add Jabber ID","Afegir Jabber ID"}.
|
||||
{"Add New","Afegir nou"}.
|
||||
{"Add User","Afegir usuari"}.
|
||||
{"Administration","Administració"}.
|
||||
{"Administration of ","Administració de "}.
|
||||
{"Administrator privileges required","Es necessita tenir privilegis d'administrador"}.
|
||||
{"A friendly name for the node","Un nom per al node"}.
|
||||
{"All activity","Tota l'activitat"}.
|
||||
{"Allow this Jabber ID to subscribe to this pubsub node?","Permetre que aquesta Jabber ID es puga subscriure a aquest node pubsub"}.
|
||||
{"Allow users to change the subject","Permetre que els usuaris canviin el tema"}.
|
||||
{"Allow users to query other users","Permetre que els usuaris fagen peticions a altres usuaris"}.
|
||||
{"Allow users to send invites","Permetre que els usuaris envien invitacions"}.
|
||||
{"Allow users to send private messages","Permetre que els usuaris envien missatges privats"}.
|
||||
{"Allow visitors to change nickname","Permetre als visitants canviar el Nickname"}.
|
||||
{"Allow visitors to send private messages to","Permetre als visitants enviar missatges privats a"}.
|
||||
{"Allow visitors to send status text in presence updates","Permetre als visitants enviar text d'estat en les actualitzacions de presència"}.
|
||||
{"Allow visitors to send voice requests","Permetre als visitants enviar peticions de veu"}.
|
||||
{"All Users","Tots els usuaris"}.
|
||||
{"Announcements","Anuncis"}.
|
||||
{"anyone","qualsevol"}.
|
||||
{"A password is required to enter this room","Es necessita contrasenya per a entrar en aquesta sala"}.
|
||||
{"April","Abril"}.
|
||||
{"August","Agost"}.
|
||||
{"Backup","Guardar còpia de seguretat"}.
|
||||
{"Backup Management","Gestió de còpia de seguretat"}.
|
||||
{"Backup of ","Còpia de seguretat de "}.
|
||||
{"Backup to File at ","Desar còpia de seguretat a fitxer en "}.
|
||||
{"Bad format","Format erroni"}.
|
||||
{"Birthday","Aniversari"}.
|
||||
{"CAPTCHA web page","Pàgina web del CAPTCHA"}.
|
||||
{"Change Password","Canviar Contrasenya"}.
|
||||
{"Change User Password","Canviar Contrasenya d'Usuari"}.
|
||||
{"Characters not allowed:","Caràcters no permesos:"}.
|
||||
{"Chatroom configuration modified","Configuració de la sala de xat modificada"}.
|
||||
{"Chatroom is created","La sala s'ha creat"}.
|
||||
{"Chatroom is destroyed","La sala s'ha destruït"}.
|
||||
{"Chatroom is started","La sala s'ha iniciat"}.
|
||||
{"Chatroom is stopped","La sala s'ha aturat"}.
|
||||
{"Chatrooms","Sales de xat"}.
|
||||
{"Choose a username and password to register with this server","Tria nom d'usuari i contrasenya per a registrar-te en aquest servidor"}.
|
||||
{"Choose modules to stop","Selecciona mòduls a detindre"}.
|
||||
{"Choose storage type of tables","Selecciona el tipus d'almacenament de les taules"}.
|
||||
{"Choose whether to approve this entity's subscription.","Tria si aprova aquesta entitat de subscripció"}.
|
||||
{"City","Ciutat"}.
|
||||
{"Commands","Comandaments"}.
|
||||
{"Conference room does not exist","La sala de conferències no existeix"}.
|
||||
{"Configuration","Configuració"}.
|
||||
{"Configuration of room ~s","Configuració de la sala ~s"}.
|
||||
{"Connected Resources:","Recursos connectats:"}.
|
||||
{"Connections parameters","Paràmetres de connexió"}.
|
||||
{"Country","Pais"}.
|
||||
{"CPU Time:","Temps de CPU"}.
|
||||
{"Database","Base de dades"}.
|
||||
{"Database Tables at ","Taules de la base de dades en "}.
|
||||
{"Database Tables Configuration at ","Configuració de la base de dades en "}.
|
||||
{"December","Decembre"}.
|
||||
{"Default users as participants","Els usuaris són participants per defecte"}.
|
||||
{"Delete","Eliminar"}.
|
||||
{"Delete message of the day","Eliminar el missatge del dia"}.
|
||||
{"Delete message of the day on all hosts","Elimina el missatge del dis de tots els hosts"}.
|
||||
{"Delete Selected","Eliminar els seleccionats"}.
|
||||
{"Delete User","Eliminar Usuari"}.
|
||||
{"Deliver event notifications","Entrega de notificacions d'events"}.
|
||||
{"Deliver payloads with event notifications","Enviar payloads junt a les notificacions d'events"}.
|
||||
{"Description:","Descripció:"}.
|
||||
{"Disc only copy","Còpia sols en disc"}.
|
||||
{"Displayed Groups:","Mostrar grups:"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","No li donis la teva contrasenya a ningú, ni tan sols als administradors del servidor Jabber."}.
|
||||
{"Dump Backup to Text File at ","Exporta còpia de seguretat a fitxer de text en "}.
|
||||
{"Dump to Text File","Exportar a fitxer de text"}.
|
||||
{"Edit Properties","Editar propietats"}.
|
||||
{"Either approve or decline the voice request.","Aprova o denega la petició de veu"}.
|
||||
{"ejabberd IRC module","mòdul ejabberd IRC"}.
|
||||
{"ejabberd MUC module","mòdul ejabberd MUC"}.
|
||||
{"ejabberd Publish-Subscribe module","Mòdul ejabberd Publicar-Subscriure"}.
|
||||
{"ejabberd SOCKS5 Bytestreams module","mòdul ejabberd SOCKS5 Bytestreams"}.
|
||||
{"ejabberd vCard module","Mòdul ejabberd vCard"}.
|
||||
{"ejabberd Web Admin","Web d'administració del ejabberd"}.
|
||||
{"Elements","Elements"}.
|
||||
{"Email","Email"}.
|
||||
{"Enable logging","Habilitar el registre de la conversa"}.
|
||||
{"Encoding for server ~b","Codificació pel servidor ~b"}.
|
||||
{"End User Session","Finalitzar Sesió d'Usuari"}.
|
||||
{"Enter list of {Module, [Options]}","Introdueix llista de {mòdul, [opcions]}"}.
|
||||
{"Enter nickname you want to register","Introdueix el nickname que vols registrar"}.
|
||||
{"Enter path to backup file","Introdueix ruta al fitxer de còpia de seguretat"}.
|
||||
{"Enter path to jabberd14 spool dir","Introdueix la ruta al directori de jabberd14 spools"}.
|
||||
{"Enter path to jabberd14 spool file","Introdueix ruta al fitxer jabberd14 spool"}.
|
||||
{"Enter path to text file","Introdueix ruta al fitxer de text"}.
|
||||
{"Enter the text you see","Introdueix el text que veus"}.
|
||||
{"Enter username and encodings you wish to use for connecting to IRC servers. Press 'Next' to get more fields to fill in. Press 'Complete' to save settings.","Introdueix el nom d'usuari i les codificacions de caràcters per a utilitzar als servidors de IRC. Apreta \"Seguent\" per veure més caps per omplir. Apreta \"Completar\" per guardar la configuració. "}.
|
||||
{"Enter username, encodings, ports and passwords you wish to use for connecting to IRC servers","Introdueix el nom d'usuari, les codificacions de caràcters, els ports i contrasenyes per a utilitzar al connectar als servidors de IRC"}.
|
||||
{"Erlang Jabber Server","Servidor Erlang Jabber"}.
|
||||
{"Error","Error"}.
|
||||
{"Example: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}].","Exemple: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."}.
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","Excloure Jabber IDs de la comprovació CAPTCHA"}.
|
||||
{"Export data of all users in the server to PIEFXIS files (XEP-0227):","Exportar dades de tots els usuaris del servidor a arxius PIEFXIS (XEP-0227):"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Exportar dades d'usuaris d'un host a arxius PIEFXIS (XEP-0227):"}.
|
||||
{"Failed to extract JID from your voice request approval","No s'ha pogut extraure el JID de la teva aprovació de petició de veu"}.
|
||||
{"Family Name","Cognom"}.
|
||||
{"February","Febrer"}.
|
||||
{"Fill in fields to search for any matching Jabber User","Emplena camps per a buscar usuaris Jabber que concorden"}.
|
||||
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Emplena el formulari per a buscar usuaris Jabber. Afegix * al final d'un camp per a buscar subcadenes."}.
|
||||
{"Friday","Divendres"}.
|
||||
{"From","De"}.
|
||||
{"From ~s","De ~s"}.
|
||||
{"Full Name","Nom complet"}.
|
||||
{"Get Number of Online Users","Obtenir Número d'Usuaris Connectats"}.
|
||||
{"Get Number of Registered Users","Obtenir Número d'Usuaris Registrats"}.
|
||||
{"Get User Last Login Time","Obtenir la última connexió d'Usuari"}.
|
||||
{"Get User Password","Obtenir Contrasenya d'usuari"}.
|
||||
{"Get User Statistics","Obtenir Estadístiques d'Usuari"}.
|
||||
{"Grant voice to this person?","Concedir veu a aquesta persona?"}.
|
||||
{"Group ","Grup "}.
|
||||
{"Groups","Grups"}.
|
||||
{"has been banned","Has sigut banejat"}.
|
||||
{"has been kicked because of an affiliation change","Has sigut expulsat a causa d'un canvi d'afiliació"}.
|
||||
{"has been kicked because of a system shutdown","Has sigut expulsat perquè el sistema s'ha apagat"}.
|
||||
{"has been kicked because the room has been changed to members-only","Has sigut expulsat perquè la sala ha canviat a sols membres"}.
|
||||
{"has been kicked","Has sigut expulsat"}.
|
||||
{" has set the subject to: "," ha posat l'assumpte: "}.
|
||||
{"Host","Host"}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Si no veus la imatge CAPTCHA açí, visita la pàgina web."}.
|
||||
{"If you want to specify different ports, passwords, encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\", port, \"password\"}'. By default this service use \"~s\" encoding, port ~p, empty password.","Si vols especificar codificacions de caràcters diferents per a cada servidor IRC emplena aquesta llista amb els valors amb el format '{\"servidor irc\", \"codificació\", port, \"contrasenya\"}'. Aquest servei utilitza per defecte la codificació \"~s\", port ~p, no contrasenya."}.
|
||||
{"Import Directory","Importar directori"}.
|
||||
{"Import File","Importar fitxer"}.
|
||||
{"Import user data from jabberd14 spool file:","Importar dades d'usuaris de l'arxiu de spool de jabberd14"}.
|
||||
{"Import User from File at ","Importa usuari des de fitxer en "}.
|
||||
{"Import users data from a PIEFXIS file (XEP-0227):","Importar dades d'usuaris des d'un arxiu PIEFXIS (XEP-0227):"}.
|
||||
{"Import users data from jabberd14 spool directory:","Importar dades d'usuaris del directori de spool de jabberd14:"}.
|
||||
{"Import Users from Dir at ","Importar usuaris des del directori en "}.
|
||||
{"Import Users From jabberd14 Spool Files","Importar usuaris de jabberd14"}.
|
||||
{"Improper message type","Tipus de missatge incorrecte"}.
|
||||
{"Incorrect password","Contrasenya incorrecta"}.
|
||||
{"Invalid affiliation: ~s","Afiliació invàlida: ~s"}.
|
||||
{"Invalid role: ~s","Rol invàlid: ~s"}.
|
||||
{"IP addresses","Adreça IP"}.
|
||||
{"IP","IP"}.
|
||||
{"IRC channel (don't put the first #)","Canal d'IRC (no posis la primera #)"}.
|
||||
{"IRC server","Servidor d'IRC"}.
|
||||
{"IRC settings","Configuració d'IRC."}.
|
||||
{"IRC Transport","Transport a IRC"}.
|
||||
{"IRC username","Nom d'usuari al IRC"}.
|
||||
{"IRC Username","Nom d'usuari al IRC"}.
|
||||
{"is now known as","ara es conegut com"}.
|
||||
{"It is not allowed to send private messages","No està permés enviar missatges privats"}.
|
||||
{"It is not allowed to send private messages of type \"groupchat\"","No està permés enviar missatges del tipus \"groupchat\""}.
|
||||
{"It is not allowed to send private messages to the conference","No està permès l'enviament de missatges privats a la sala"}.
|
||||
{"Jabber Account Registration","Registre de compte Jabber"}.
|
||||
{"Jabber ID","ID Jabber"}.
|
||||
{"Jabber ID ~s is invalid","El Jabber ID ~s no és vàlid"}.
|
||||
{"January","Gener"}.
|
||||
{"Join IRC channel","Entra a canal d'IRC"}.
|
||||
{"joins the room","Entrar a la sala"}.
|
||||
{"Join the IRC channel here.","Entra al canal d'IRC aquí."}.
|
||||
{"Join the IRC channel in this Jabber ID: ~s","Entra al canal d'IRC en aquesta Jabber ID: ~s"}.
|
||||
{"July","Juliol"}.
|
||||
{"June","Juny"}.
|
||||
{"Last Activity","Última activitat"}.
|
||||
{"Last login","Últim login"}.
|
||||
{"Last month","Últim mes"}.
|
||||
{"Last year","Últim any"}.
|
||||
{"leaves the room","Deixar la sala"}.
|
||||
{"Listened Ports at ","Ports a la escolta en "}.
|
||||
{"Listened Ports","Ports a l'escolta"}.
|
||||
{"List of modules to start","Llista de mòduls a iniciar"}.
|
||||
{"Low level update script","Script d'actualització de baix nivell"}.
|
||||
{"Make participants list public","Crear una llista de participants pública"}.
|
||||
{"Make room CAPTCHA protected","Crear una sala protegida per CAPTCHA"}.
|
||||
{"Make room members-only","Crear una sala de \"només membres\""}.
|
||||
{"Make room moderated","Crear una sala moderada"}.
|
||||
{"Make room password protected","Crear una sala amb contrasenya"}.
|
||||
{"Make room persistent","Crear una sala persistent"}.
|
||||
{"Make room public searchable","Crear una sala pública"}.
|
||||
{"March","Març"}.
|
||||
{"Maximum Number of Occupants","Número màxim d'ocupants"}.
|
||||
{"Max # of items to persist","Màxim # d'elements que persistixen"}.
|
||||
{"Max payload size in bytes","Màxim tamany del payload en bytes"}.
|
||||
{"May","Maig"}.
|
||||
{"Membership is required to enter this room","Necessites ser membre d'aquesta sala per a poder entrar"}.
|
||||
{"Members:","Membre:"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Memoritza la teva contrasenya, o escriu-la en un paper guardat a un lloc segur.A Jabber no hi ha una forma automatitzada de recuperar la teva contrasenya si la oblides."}.
|
||||
{"Memory","Memòria"}.
|
||||
{"Message body","Missatge"}.
|
||||
{"Middle Name","Segon nom"}.
|
||||
{"Minimum interval between voice requests (in seconds)","Interval mínim entre peticions de veu (en segons)"}.
|
||||
{"Moderator privileges required","Es necessita tenir privilegis de moderador"}.
|
||||
{"moderators only","només moderadors"}.
|
||||
{"Modified modules","Mòduls modificats"}.
|
||||
{"Module","Mòdul"}.
|
||||
{"Modules at ","Mòduls en "}.
|
||||
{"Modules","Mòduls"}.
|
||||
{"Monday","Dilluns"}.
|
||||
{"Name:","Nom:"}.
|
||||
{"Name","Nom"}.
|
||||
{"Never","Mai"}.
|
||||
{"New Password:","Nova Contrasenya:"}.
|
||||
{"Nickname","Nickname"}.
|
||||
{"Nickname Registration at ","Registre del Nickname en "}.
|
||||
{"Nickname ~s does not exist in the room","El Nickname ~s no existeix a la sala"}.
|
||||
{"nobody","ningú"}.
|
||||
{"No body provided for announce message","No hi ha proveedor per al missatge anunci"}.
|
||||
{"No Data","No hi ha dades"}.
|
||||
{"Node ID","ID del Node"}.
|
||||
{"Node ","Node "}.
|
||||
{"Node not found","Node no trobat"}.
|
||||
{"Nodes","Nodes"}.
|
||||
{"No limit","Sense Llímit"}.
|
||||
{"None","Cap"}.
|
||||
{"No resource provided","Recurs no disponible"}.
|
||||
{"Not Found","No Trobat"}.
|
||||
{"Notify subscribers when items are removed from the node","Notificar subscriptors quan els elements són eliminats del node"}.
|
||||
{"Notify subscribers when the node configuration changes","Notificar subscriptors quan canvia la configuració del node"}.
|
||||
{"Notify subscribers when the node is deleted","Notificar subscriptors quan el node és eliminat"}.
|
||||
{"November","Novembre"}.
|
||||
{"Number of occupants","Número d'ocupants"}.
|
||||
{"Number of online users","Número d'usuaris connectats"}.
|
||||
{"Number of registered users","Número d'Usuaris Registrats"}.
|
||||
{"October","Octubre"}.
|
||||
{"Offline Messages:","Missatges fora de línia:"}.
|
||||
{"Offline Messages","Missatges offline"}.
|
||||
{"OK","Acceptar"}.
|
||||
{"Old Password:","Antiga contrasenya:"}.
|
||||
{"Online","Connectat"}.
|
||||
{"Online Users","Usuaris conectats"}.
|
||||
{"Online Users:","Usuaris en línia:"}.
|
||||
{"Only deliver notifications to available users","Sols enviar notificacions als usuaris disponibles"}.
|
||||
{"Only moderators and participants are allowed to change the subject in this room","Només els moderadors i participants poden canviar l'assumpte d'aquesta sala"}.
|
||||
{"Only moderators are allowed to change the subject in this room","Només els moderadors poden canviar l'assumpte d'aquesta sala"}.
|
||||
{"Only moderators can approve voice requests","Només els moderadors poden aprovar les peticions de veu"}.
|
||||
{"Only occupants are allowed to send messages to the conference","Sols els ocupants poden enviar missatges a la sala"}.
|
||||
{"Only occupants are allowed to send queries to the conference","Sols els ocupants poden enviar sol·licituds a la sala"}.
|
||||
{"Only service administrators are allowed to send service messages","Sols els administradors del servei tenen permís per a enviar missatges de servei"}.
|
||||
{"Options","Opcions"}.
|
||||
{"Organization Name","Nom de la organizació"}.
|
||||
{"Organization Unit","Unitat de la organizació"}.
|
||||
{"Outgoing s2s Connections:","Connexions d'eixida s2s"}.
|
||||
{"Outgoing s2s Connections","Connexions s2s d'eixida"}.
|
||||
{"Outgoing s2s Servers:","Servidors d'eixida de s2s"}.
|
||||
{"Owner privileges required","Es requerixen privilegis de propietari de la sala"}.
|
||||
{"Packet","Paquet"}.
|
||||
{"Password ~b","Contrasenya ~b"}.
|
||||
{"Password:","Contrasenya:"}.
|
||||
{"Password","Contrasenya"}.
|
||||
{"Password Verification:","Verificació de la Contrasenya:"}.
|
||||
{"Password Verification","Verificació de la Contrasenya"}.
|
||||
{"Path to Dir","Ruta al directori"}.
|
||||
{"Path to File","Ruta al fitxer"}.
|
||||
{"Pending","Pendent"}.
|
||||
{"Period: ","Període: "}.
|
||||
{"Persist items to storage","Persistir elements al guardar"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Recorda que aquestes opcions només fan còpia de seguretat de la base de dades Mnesia. Si estàs utilitzant el mòdul d'ODBC també deus de fer una còpia de seguretat de la base de dades de SQL a part."}.
|
||||
{"Please, wait for a while before sending new voice request","Si us plau, espera una mica abans d'enviar una nova petició de veu"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Port ~b","Port ~b"}.
|
||||
{"Port","Port"}.
|
||||
{"Present real Jabber IDs to","Presentar Jabber ID's reals a"}.
|
||||
{"private, ","privat"}.
|
||||
{"Protocol","Protocol"}.
|
||||
{"Publish-Subscribe","Publicar-subscriure't"}.
|
||||
{"PubSub subscriber request","Petició de subscriptor PubSub"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Eliminar tots els elements quan el publicant relevant es desconnecti"}.
|
||||
{"Queries to the conference members are not allowed in this room"," En aquesta sala no es permeten sol·licituds als membres de la conferència"}.
|
||||
{"RAM and disc copy","Còpia en RAM i disc"}.
|
||||
{"RAM copy","Còpia en RAM"}.
|
||||
{"Raw","en format text"}.
|
||||
{"Really delete message of the day?","Segur que vols eliminar el missatge del dia?"}.
|
||||
{"Recipient is not in the conference room","El receptor no està en la sala de conferència"}.
|
||||
{"Register a Jabber account","Registrar un compte Jabber"}.
|
||||
{"Registered Users:","Usuaris registrats:"}.
|
||||
{"Registered Users","Usuaris registrats"}.
|
||||
{"Register","Registrar"}.
|
||||
{"Registration in mod_irc for ","Registre en mod_irc per a"}.
|
||||
{"Remote copy","Còpia remota"}.
|
||||
{"Remove All Offline Messages","Eliminar tots els missatges offline"}.
|
||||
{"Remove","Borrar"}.
|
||||
{"Remove User","Eliminar usuari"}.
|
||||
{"Replaced by new connection","Reemplaçat per una nova connexió"}.
|
||||
{"Resources","Recursos"}.
|
||||
{"Restart","Reiniciar"}.
|
||||
{"Restart Service","Reiniciar el Servei"}.
|
||||
{"Restore Backup from File at ","Restaura còpia de seguretat des del fitxer en "}.
|
||||
{"Restore binary backup after next ejabberd restart (requires less memory):","Restaurar una còpia de seguretat binària després de reiniciar el ejabberd (requereix menys memòria:"}.
|
||||
{"Restore binary backup immediately:","Restaurar una còpia de seguretat binària ara mateix."}.
|
||||
{"Restore plain text backup immediately:","Restaurar una còpia de seguretat en format de text pla ara mateix:"}.
|
||||
{"Restore","Restaurar"}.
|
||||
{"Room Configuration","Configuració de la sala"}.
|
||||
{"Room creation is denied by service policy","Se t'ha denegat el crear la sala per política del servei"}.
|
||||
{"Room description","Descripció de la sala:"}.
|
||||
{"Room Occupants","Nombre d'ocupants"}.
|
||||
{"Room title","Títol de la sala"}.
|
||||
{"Roster groups allowed to subscribe","Llista de grups que tenen permés subscriures"}.
|
||||
{"Roster","Llista de contactes"}.
|
||||
{"Roster of ","Llista de contactes de "}.
|
||||
{"Roster size","Tamany de la llista"}.
|
||||
{"RPC Call Error","Error de cridada RPC"}.
|
||||
{"Running Nodes","Nodes funcionant"}.
|
||||
{"~s access rule configuration","Configuració de les Regles d'Accés ~s"}.
|
||||
{"Saturday","Dissabte"}.
|
||||
{"Script check","Comprovar script"}.
|
||||
{"Search Results for ","Resultat de la búsqueda"}.
|
||||
{"Search users in ","Cerca usuaris en "}.
|
||||
{"Send announcement to all online users","Enviar anunci a tots els usuaris connectats"}.
|
||||
{"Send announcement to all online users on all hosts","Enviar anunci a tots els usuaris connectats a tots els hosts"}.
|
||||
{"Send announcement to all users","Enviar anunci a tots els usuaris"}.
|
||||
{"Send announcement to all users on all hosts","Enviar anunci a tots els usuaris de tots els hosts"}.
|
||||
{"September","Setembre"}.
|
||||
{"Server ~b","Servidor ~b"}.
|
||||
{"Server:","Servidor:"}.
|
||||
{"Set message of the day and send to online users","Configurar el missatge del dia i enviar a tots els usuaris"}.
|
||||
{"Set message of the day on all hosts and send to online users","Escriure missatge del dia en tots els hosts i enviar-ho als usuaris connectats"}.
|
||||
{"Shared Roster Groups","Grups de contactes compartits"}.
|
||||
{"Show Integral Table","Mostrar Taula Integral"}.
|
||||
{"Show Ordinary Table","Mostrar Taula Ordinaria"}.
|
||||
{"Shut Down Service","Apager el Servei"}.
|
||||
{"~s invites you to the room ~s","~s et convida a la sala ~s"}.
|
||||
{"Some Jabber clients can store your password in your computer. Use that feature only if you trust your computer is safe.","Alguns clients Jabber poden emmagatzemar la teva contrasenya al teu ordinador. Fes servir aquesta característica només si saps que el teu ordinador és segur."}.
|
||||
{"Specify the access model","Especificar el model d'accés"}.
|
||||
{"Specify the event message type","Especifica el tipus de missatge d'event"}.
|
||||
{"Specify the publisher model","Especificar el model del publicant"}.
|
||||
{"~s's Offline Messages Queue","~s's cua de missatges offline"}.
|
||||
{"Start","Iniciar"}.
|
||||
{"Start Modules at ","Iniciar mòduls en "}.
|
||||
{"Start Modules","Iniciar mòduls"}.
|
||||
{"Statistics","Estadístiques"}.
|
||||
{"Statistics of ~p","Estadístiques de ~p"}.
|
||||
{"Stop","Detindre"}.
|
||||
{"Stop Modules at ","Detindre mòduls en "}.
|
||||
{"Stop Modules","Parar mòduls"}.
|
||||
{"Stopped Nodes","Nodes parats"}.
|
||||
{"Storage Type","Tipus d'emmagatzematge"}.
|
||||
{"Store binary backup:","Guardar una còpia de seguretat binària:"}.
|
||||
{"Store plain text backup:","Guardar una còpia de seguretat en format de text pla:"}.
|
||||
{"Subject","Assumpte"}.
|
||||
{"Submit","Enviar"}.
|
||||
{"Submitted","Enviat"}.
|
||||
{"Subscriber Address","Adreça del Subscriptor"}.
|
||||
{"Subscription","Subscripció"}.
|
||||
{"Sunday","Diumenge"}.
|
||||
{"That nickname is already in use by another occupant","El Nickname està siguent utilitzat per una altra persona"}.
|
||||
{"That nickname is registered by another person","El nickname ja està registrat per una altra persona"}.
|
||||
{"The CAPTCHA is valid.","El CAPTCHA es vàlid."}.
|
||||
{"The CAPTCHA verification has failed","La verificació CAPTCHA ha fallat"}.
|
||||
{"The collections with which a node is affiliated","Les col.leccions amb les que un node està afiliat"}.
|
||||
{"the password is","la contrasenya és"}.
|
||||
{"The password is too weak","La contrasenya és massa simple"}.
|
||||
{"The password of your Jabber account was successfully changed.","La contrasenya del teu compte Jabber s'ha canviat correctament."}.
|
||||
{"There was an error changing the password: ","Hi ha hagut un error canviant la contrasenya: "}.
|
||||
{"There was an error creating the account: ","Hi ha hagut un error creant el compte: "}.
|
||||
{"There was an error deleting the account: ","Hi ha hagut un error esborrant el compte: "}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Això no distingeix majúscules de minúscules: macbeth es el mateix que MacBeth i Macbeth."}.
|
||||
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Aquesta pàgina permet crear un compte Jabber en aquest servidor Jabber. El teu JID (Jabber IDentifier; Identificador Jabber) tindrà aquesta forma: usuari@servidor. Si us plau, llegeix amb cura les instruccions per emplenar correctament els camps."}.
|
||||
{"This page allows to unregister a Jabber account in this Jabber server.","Aquesta pàgina permet anul·lar el registre d'un compte Jabber en aquest servidor Jabber."}.
|
||||
{"This participant is kicked from the room because he sent an error message","Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge d'error"}.
|
||||
{"This participant is kicked from the room because he sent an error message to another participant","Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge erroni a un altre participant"}.
|
||||
{"This participant is kicked from the room because he sent an error presence","Aquest participant ha sigut expulsat de la sala perque ha enviat un error de presencia"}.
|
||||
{"This room is not anonymous","Aquesta sala no és anònima"}.
|
||||
{"Thursday","Dijous"}.
|
||||
{"Time","Data"}.
|
||||
{"Time delay","Temps de retard"}.
|
||||
{"Too many CAPTCHA requests","Massa peticions de CAPTCHA"}.
|
||||
{"To","Per a"}.
|
||||
{"To ~s","A ~s"}.
|
||||
{"Traffic rate limit is exceeded","El llímit de tràfic ha sigut sobrepassat"}.
|
||||
{"Transactions Aborted:","Transaccions Avortades"}.
|
||||
{"Transactions Committed:","Transaccions Realitzades:"}.
|
||||
{"Transactions Logged:","Transaccions registrades"}.
|
||||
{"Transactions Restarted:","Transaccions reiniciades"}.
|
||||
{"Tuesday","Dimarts"}.
|
||||
{"Unable to generate a CAPTCHA","No s'ha pogut generar un CAPTCHA"}.
|
||||
{"Unauthorized","No autoritzat"}.
|
||||
{"Unregister a Jabber account","Anul·lar el registre d'un compte Jabber"}.
|
||||
{"Unregister","Anul·lar el registre"}.
|
||||
{"Update ","Actualitzar"}.
|
||||
{"Update","Actualitzar"}.
|
||||
{"Update message of the day (don't send)","Actualitzar el missatge del dia (no enviar)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Actualitza el missatge del dia en tots els hosts (no enviar)"}.
|
||||
{"Update plan","Pla d'actualització"}.
|
||||
{"Update script","Script d'actualització"}.
|
||||
{"Uptime:","Temps en marxa"}.
|
||||
{"Use of STARTTLS required","És obligatori utilitzar STARTTLS"}.
|
||||
{"User JID","JID del usuari "}.
|
||||
{"User Management","Gestió d'Usuaris"}.
|
||||
{"Username:","Nom d'usuari:"}.
|
||||
{"Users are not allowed to register accounts so quickly","Els usuaris no tenen permís per a crear comptes tan depresa"}.
|
||||
{"Users Last Activity","Última activitat d'usuari"}.
|
||||
{"Users","Usuaris"}.
|
||||
{"User ","Usuari "}.
|
||||
{"User","Usuari"}.
|
||||
{"Validate","Validar"}.
|
||||
{"vCard User Search","Recerca de vCard d'usuari"}.
|
||||
{"Virtual Hosts","Hosts virtuals"}.
|
||||
{"Visitors are not allowed to change their nicknames in this room","Els visitants no tenen permés canviar el seus Nicknames en esta sala"}.
|
||||
{"Visitors are not allowed to send messages to all occupants","Els visitants no poden enviar missatges a tots els ocupants"}.
|
||||
{"Voice request","Petició de veu"}.
|
||||
{"Voice requests are disabled in this conference","Les peticions de veu es troben desactivades en aquesta conferència"}.
|
||||
{"Wednesday","Dimecres"}.
|
||||
{"When to send the last published item","Quan s'ha enviat l'última publicació"}.
|
||||
{"Whether to allow subscriptions","Permetre subscripcions"}.
|
||||
{"You can later change your password using a Jabber client.","Podràs canviar la teva contrasenya més endavant utilitzant un client Jabber."}.
|
||||
{"You have been banned from this room","Has sigut bloquejat en aquesta sala"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Deus d'omplir el camp \"Nickname\" al formulari"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","Necessites un client amb suport x:data i de CAPTCHA para poder registrar-te"}.
|
||||
{"You need a client that supports x:data to register the nickname","Necessites un client amb suport x:data per a poder registrar el Nickname"}.
|
||||
{"You need an x:data capable client to configure mod_irc settings","Necessites un client amb suport x:data per a configurar les opcions de mod_irc"}.
|
||||
{"You need an x:data capable client to configure room","Necessites un client amb suport x:data per a configurar la sala"}.
|
||||
{"You need an x:data capable client to search","Necessites un client amb suport x:data per a poder buscar"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","La teva llista de privacitat activa ha denegat l'encaminament d'aquesta stanza."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","La cua de missatges offline és plena. El missatge ha sigut descartat"}.
|
||||
{"Your Jabber account was successfully created.","El teu compte Jabber ha sigut creat correctament."}.
|
||||
{"Your Jabber account was successfully deleted.","El teu compte Jabber ha sigut esborrat correctament."}.
|
||||
{"Your messages to ~s are being blocked. To unblock them, visit ~s","Els teus missatges per ~s s'estan bloquejant. Per desbloquejar-los, visita ~s"}.
|
||||
+1872
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,421 @@
|
||||
{"Access Configuration","Konfigurace přístupů"}.
|
||||
{"Access Control List Configuration","Konfigurace seznamu přístupových práv (ACL)"}.
|
||||
{"Access control lists","Seznamy přístupových práv (ACL)"}.
|
||||
{"Access Control Lists","Seznamy přístupových práv (ACL)"}.
|
||||
{"Access denied by service policy","Přístup byl zamítnut nastavením služby"}.
|
||||
{"Access rules","Pravidla přístupů"}.
|
||||
{"Access Rules","Pravidla přístupů"}.
|
||||
{"Action on user","Akce aplikovaná na uživatele"}.
|
||||
{"Add Jabber ID","Přidat Jabber ID"}.
|
||||
{"Add New","Přidat nový"}.
|
||||
{"Add User","Přidat uživatele"}.
|
||||
{"Administration","Administrace"}.
|
||||
{"Administration of ","Administrace "}.
|
||||
{"Administrator privileges required","Potřebujete práva administrátora"}.
|
||||
{"A friendly name for the node","Přívětivé jméno pro uzel"}.
|
||||
{"All activity","Všechny aktivity"}.
|
||||
{"Allow this Jabber ID to subscribe to this pubsub node?","Povolit tomuto Jabber ID odebírat tento pubsub uzel?"}.
|
||||
{"Allow users to change the subject","Povolit uživatelům měnit téma místnosti"}.
|
||||
{"Allow users to query other users","Povolit uživatelům odesílat požadavky (query) ostatním uživatelům"}.
|
||||
{"Allow users to send invites","Povolit uživatelům posílání pozvánek"}.
|
||||
{"Allow users to send private messages","Povolit uživatelům odesílat soukromé zprávy"}.
|
||||
{"Allow visitors to change nickname","Povolit návštěvníkům měnit přezdívku"}.
|
||||
{"Allow visitors to send private messages to","Povolit návštěvníkům odesílat soukromé zprávy"}.
|
||||
{"Allow visitors to send status text in presence updates","Povolit návštěvníkům posílat stavové zprávy ve statusu"}.
|
||||
{"Allow visitors to send voice requests","Povolit uživatelům posílat žádosti o voice práva"}.
|
||||
{"All Users","Všichni uživatelé"}.
|
||||
{"Announcements","Oznámení"}.
|
||||
{"anyone","každému"}.
|
||||
{"A password is required to enter this room","Pro vstup do místnosti musíte zadat heslo"}.
|
||||
{"April",". dubna"}.
|
||||
{"August",". srpna"}.
|
||||
{"Backup Management","Správa zálohování"}.
|
||||
{"Backup of ","Záloha na "}.
|
||||
{"Backup to File at ","Záloha do souboru na "}.
|
||||
{"Backup","Zálohovat"}.
|
||||
{"Bad format","Nesprávný formát"}.
|
||||
{"Birthday","Datum narození"}.
|
||||
{"CAPTCHA web page","Webová stránka CAPTCHA"}.
|
||||
{"Change Password","Změnit heslo"}.
|
||||
{"Change User Password","Změnit heslo uživatele"}.
|
||||
{"Characters not allowed:","Nepřípustné znaky:"}.
|
||||
{"Chatroom configuration modified","Nastavení diskuzní místnosti bylo změněno"}.
|
||||
{"Chatroom is created","Konference vytvořena"}.
|
||||
{"Chatroom is destroyed","Konference zrušena"}.
|
||||
{"Chatroom is started","Konference spuštěna"}.
|
||||
{"Chatroom is stopped","Konference zastavena"}.
|
||||
{"Chatrooms","Konference"}.
|
||||
{"Choose a username and password to register with this server","Zadejte jméno uživatele a heslo pro registraci na tomto serveru"}.
|
||||
{"Choose modules to stop","Vyberte moduly, které mají být zastaveny"}.
|
||||
{"Choose storage type of tables","Vyberte typ úložiště pro tabulky"}.
|
||||
{"Choose whether to approve this entity's subscription.","Zvolte, zda chcete schválit odebírání touto entitou"}.
|
||||
{"City","Město"}.
|
||||
{"Commands","Příkazy"}.
|
||||
{"Conference room does not exist","Konferenční místnost neexistuje"}.
|
||||
{"Configuration","Konfigurace"}.
|
||||
{"Configuration of room ~s","Konfigurace místnosti ~s"}.
|
||||
{"Connected Resources:","Připojené zdroje:"}.
|
||||
{"Connections parameters","Parametry spojení"}.
|
||||
{"Country","Země"}.
|
||||
{"CPU Time:","Čas procesoru"}.
|
||||
{"Database","Databáze"}.
|
||||
{"Database Tables at ","Databázové tabulky na "}.
|
||||
{"Database Tables Configuration at ","Konfigurace databázových tabulek "}.
|
||||
{"December",". prosince"}.
|
||||
{"Default users as participants","Uživatelé jsou implicitně členy"}.
|
||||
{"Delete message of the day on all hosts","Smazat zprávu dne na všech hostitelích"}.
|
||||
{"Delete message of the day","Smazat zprávu dne"}.
|
||||
{"Delete Selected","Smazat vybrané"}.
|
||||
{"Delete","Smazat"}.
|
||||
{"Delete User","Smazat uživatele"}.
|
||||
{"Deliver event notifications","Doručovat upozornění na události"}.
|
||||
{"Deliver payloads with event notifications","Doručovat náklad s upozorněním na událost"}.
|
||||
{"Description:","Popis:"}.
|
||||
{"Disc only copy","Jen kopie disku"}.
|
||||
{"Displayed Groups:","Zobrazené skupiny:"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","Nikdy nikomu nesdělujte své heslo, ani administrátorovi serveru Jabberu."}.
|
||||
{"Dump Backup to Text File at ","Uložit zálohu do textového souboru na "}.
|
||||
{"Dump to Text File","Uložit do textového souboru"}.
|
||||
{"Edit Properties","Upravit vlastnosti"}.
|
||||
{"Either approve or decline the voice request.","Povolit nebo odmítnout voice žádost."}.
|
||||
{"ejabberd IRC module","ejabberd IRC modul"}.
|
||||
{"ejabberd MUC module","ejabberd MUC modul"}.
|
||||
{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe modul"}.
|
||||
{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams modul"}.
|
||||
{"ejabberd vCard module","ejabberd vCard modul"}.
|
||||
{"ejabberd Web Admin","Webová administrace ejabberd"}.
|
||||
{"Elements","Položek"}.
|
||||
{"Email","E-mail"}.
|
||||
{"Enable logging","Zaznamenávat konverzace"}.
|
||||
{"Encoding for server ~b","Kódování pro server ~b"}.
|
||||
{"End User Session","Ukončit sezení uživatele"}.
|
||||
{"Enter list of {Module, [Options]}","Vložte seznam modulů {Modul, [Parametry]}"}.
|
||||
{"Enter nickname you want to register","Zadejte přezdívku, kterou chcete zaregistrovat"}.
|
||||
{"Enter path to backup file","Zadajte cestu k souboru se zálohou"}.
|
||||
{"Enter path to jabberd14 spool dir","Zadejte cestu k jabberd14 spool adresáři"}.
|
||||
{"Enter path to jabberd14 spool file","Zadejte cestu k spool souboru jabberd14"}.
|
||||
{"Enter path to text file","Zadajte cestu k textovému souboru"}.
|
||||
{"Enter the text you see","Zadejte text, který vidíte"}.
|
||||
{"Enter username and encodings you wish to use for connecting to IRC servers. Press 'Next' to get more fields to fill in. Press 'Complete' to save settings.","Zadejte přezdívku a kódování, které chcete používat pro připojení k serverům IRC. Stiskněte 'Další' pro více políček k vyplnění. Stiskněte 'Dokončit' pro uložení nastavení."}.
|
||||
{"Enter username, encodings, ports and passwords you wish to use for connecting to IRC servers","Zadejte přezdívku, kódování, porty a hesla, které chcete používat pro připojení k serverům IRC"}.
|
||||
{"Erlang Jabber Server","Erlang Jabber Server"}.
|
||||
{"Error","Chyba"}.
|
||||
{"Example: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}].","Příklad: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}].2\"}]."}.
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","Vyloučit Jabber ID z procesu CAPTCHA ověřování"}.
|
||||
{"Export data of all users in the server to PIEFXIS files (XEP-0227):","Exportovat všechny uživatele do souboru ve formátu PIEFXIS (XEP-0227):"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Exportovat uživatele na hostiteli do souboru ve formátu PIEFXIS (XEP-0227):"}.
|
||||
{"Failed to extract JID from your voice request approval","Došlo k chybě při získávání Jabber ID z vaší žádosti o voice práva"}.
|
||||
{"Family Name","Příjmení"}.
|
||||
{"February",". února"}.
|
||||
{"Fill in fields to search for any matching Jabber User","Vyplňte políčka pro vyhledání uživatele Jabberu"}.
|
||||
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Pro vyhledání uživatele Jabberu vyplňte formulář (na konec přidejte znak * pro vyhledání podřetězce)"}.
|
||||
{"Friday","Pátek"}.
|
||||
{"From","Od"}.
|
||||
{"From ~s","Od ~s"}.
|
||||
{"Full Name","Celé jméno"}.
|
||||
{"Get Number of Online Users","Získat počet online uživatelů"}.
|
||||
{"Get Number of Registered Users","Získat počet registrovaných uživatelů"}.
|
||||
{"Get User Last Login Time","Získat čas podleního přihlášení uživatele"}.
|
||||
{"Get User Password","Získat heslo uživatele"}.
|
||||
{"Get User Statistics","Získat statistiky uživatele"}.
|
||||
{"Grant voice to this person?","Udělit voice práva této osobě?"}.
|
||||
{"Group ","Skupina "}.
|
||||
{"Groups","Skupiny"}.
|
||||
{"has been banned","byl(a) zablokován(a)"}.
|
||||
{"has been kicked because of an affiliation change","byl(a) vyhozen(a) kvůli změně přiřazení"}.
|
||||
{"has been kicked because of a system shutdown","byl(a) vyhozen(a), protože dojde k vypnutí systému"}.
|
||||
{"has been kicked because the room has been changed to members-only","byl(a) vyhozen(a), protože mísnost je nyní pouze pro členy"}.
|
||||
{"has been kicked","byl(a) vyhozen(a) z místnosti"}.
|
||||
{" has set the subject to: "," změnil(a) téma na: "}.
|
||||
{"Host","Hostitel"}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Pokud zde nevidíte obrázek CAPTCHA, přejděte na webovou stránku."}.
|
||||
{"If you want to specify different ports, passwords, encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\", port, \"password\"}'. By default this service use \"~s\" encoding, port ~p, empty password.","Pokud chcete zadat jiné kódování pro IRC servery, vyplňte seznam s hodnotami ve formátu '{\"irc server\",\"encoding\", port, \"password\"}'. Výchozí kódování pro tuto službu je \"~s\", port ~p, empty password."}.
|
||||
{"Import Directory","Import adresáře"}.
|
||||
{"Import File","Import souboru"}.
|
||||
{"Import user data from jabberd14 spool file:","Importovat uživatele z jabberd14 spool souborů:"}.
|
||||
{"Import User from File at ","Importovat uživatele ze souboru na "}.
|
||||
{"Import users data from a PIEFXIS file (XEP-0227):","Importovat uživatele ze souboru ve formátu PIEFXIS (XEP-0227):"}.
|
||||
{"Import users data from jabberd14 spool directory:","Importovat uživatele z jabberd14 spool souborů:"}.
|
||||
{"Import Users from Dir at ","Importovat uživatele z adresáře na "}.
|
||||
{"Import Users From jabberd14 Spool Files","Importovat uživatele z jabberd14 spool souborů"}.
|
||||
{"Improper message type","Nesprávný typ zprávy"}.
|
||||
{"Incorrect password","Nesprávné heslo"}.
|
||||
{"Invalid affiliation: ~s","Neplatné přiřazení: ~s"}.
|
||||
{"Invalid role: ~s","Neplatná role: ~s"}.
|
||||
{"IP addresses","IP adresy"}.
|
||||
{"IP","IP"}.
|
||||
{"IRC channel (don't put the first #)","IRC kanál (bez počátečního #)"}.
|
||||
{"IRC server","IRC přezdívka"}.
|
||||
{"IRC settings","Nastavení IRC"}.
|
||||
{"IRC Transport","IRC transport"}.
|
||||
{"IRC username","IRC přezdívka"}.
|
||||
{"IRC Username","IRC přezdívka"}.
|
||||
{"is now known as","se přejmenoval(a) na"}.
|
||||
{"It is not allowed to send private messages","Je zakázáno posílat soukromé zprávy"}.
|
||||
{"It is not allowed to send private messages of type \"groupchat\"","Není dovoleno odeslání soukromé zprávy typu \"skupinová zpráva\" "}.
|
||||
{"It is not allowed to send private messages to the conference","Není povoleno odesílat soukromé zprávy do konference"}.
|
||||
{"Jabber Account Registration","Registrace účtu Jabberu"}.
|
||||
{"Jabber ID","Jabber ID"}.
|
||||
{"Jabber ID ~s is invalid","Jabber ID ~s je neplatné"}.
|
||||
{"January",". ledna"}.
|
||||
{"Join IRC channel","Vstoupit do IRC kanálu"}.
|
||||
{"joins the room","vstoupil(a) do místnosti"}.
|
||||
{"Join the IRC channel here.","Vstoupit do tohoto IRC kanálu."}.
|
||||
{"Join the IRC channel in this Jabber ID: ~s","Vstupte do IRC kanálu s tímto Jabber ID: ~s"}.
|
||||
{"July",". července"}.
|
||||
{"June",". června"}.
|
||||
{"Last Activity","Poslední aktivita"}.
|
||||
{"Last login","Poslední přihlášení"}.
|
||||
{"Last month","Poslední měsíc"}.
|
||||
{"Last year","Poslední rok"}.
|
||||
{"leaves the room","opustil(a) místnost"}.
|
||||
{"Listened Ports at ","Otevřené porty na "}.
|
||||
{"Listened Ports","Otevřené porty"}.
|
||||
{"List of modules to start","Seznam modulů, které mají být spuštěné"}.
|
||||
{"Low level update script","Nízkoúrovňový aktualizační skript"}.
|
||||
{"Make participants list public","Nastavit seznam účastníků jako veřejný"}.
|
||||
{"Make room CAPTCHA protected","Chránit místnost pomocí CAPTCHA"}.
|
||||
{"Make room members-only","Zpřístupnit místnost jen členům"}.
|
||||
{"Make room moderated","Nastavit místnost jako moderovanou"}.
|
||||
{"Make room password protected","Chránit místnost heslem"}.
|
||||
{"Make room persistent","Nastavit místnost jako stálou"}.
|
||||
{"Make room public searchable","Nastavit místnost jako veřejnou"}.
|
||||
{"March",". března"}.
|
||||
{"Maximum Number of Occupants","Počet účastníků"}.
|
||||
{"Max # of items to persist","Maximální počet položek, které je možné natrvalo uložit"}.
|
||||
{"Max payload size in bytes","Maximální náklad v bajtech"}.
|
||||
{"May",". května"}.
|
||||
{"Members:","Členové:"}.
|
||||
{"Membership is required to enter this room","Pro vstup do místnosti musíte být členem"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Svoje heslo si zapamatujte, nebo si jej poznamenejte na papírek a ten uschovejte v bezpečí. Jabber nemá žádný automatizovaný způsob obnovy hesla."}.
|
||||
{"Memory","Paměť"}.
|
||||
{"Message body","Tělo zprávy"}.
|
||||
{"Middle Name","Druhé jméno"}.
|
||||
{"Minimum interval between voice requests (in seconds)","Minimální interval mezi žádostmi o voice práva (v sekundách)"}.
|
||||
{"Moderator privileges required","Potřebujete práva moderátora"}.
|
||||
{"moderators only","moderátorům"}.
|
||||
{"Modified modules","Aktualizované moduly"}.
|
||||
{"Module","Modul"}.
|
||||
{"Modules at ","Moduly na "}.
|
||||
{"Modules","Moduly"}.
|
||||
{"Monday","Pondělí"}.
|
||||
{"Name:","Jméno:"}.
|
||||
{"Name","Jméno"}.
|
||||
{"Never","Nikdy"}.
|
||||
{"New Password:","Nové heslo:"}.
|
||||
{"Nickname","Přezdívka"}.
|
||||
{"Nickname Registration at ","Registrace přezdívky na "}.
|
||||
{"Nickname ~s does not exist in the room","Přezdívka ~s v místnosti neexistuje"}.
|
||||
{"nobody","nikdo"}.
|
||||
{"No body provided for announce message","Zpráva neobsahuje text"}.
|
||||
{"No Data","Žádná data"}.
|
||||
{"Node ID","ID uzlu"}.
|
||||
{"Node not found","Uzel nenalezen"}.
|
||||
{"Nodes","Uzly"}.
|
||||
{"Node ","Uzel "}.
|
||||
{"No limit","Bez limitu"}.
|
||||
{"None","Nic"}.
|
||||
{"No resource provided","Nebyl poskytnut žádný zdroj"}.
|
||||
{"Not Found","Nenalezeno"}.
|
||||
{"Notify subscribers when items are removed from the node","Upozornit odběratele na odstranění položek z uzlu"}.
|
||||
{"Notify subscribers when the node configuration changes","Upozornit odběratele na změnu nastavení uzlu"}.
|
||||
{"Notify subscribers when the node is deleted","Upozornit odběratele na smazání uzlu"}.
|
||||
{"November",". listopadu"}.
|
||||
{"Number of occupants","Počet účastníků"}.
|
||||
{"Number of online users","Počet online uživatelů"}.
|
||||
{"Number of registered users","Počet registrovaných uživatelů"}.
|
||||
{"October",". října"}.
|
||||
{"Offline Messages:","Offline zprávy:"}.
|
||||
{"Offline Messages","Offline zprávy"}.
|
||||
{"OK","OK"}.
|
||||
{"Old Password:","Současné heslo:"}.
|
||||
{"Online","Online"}.
|
||||
{"Online Users:","Online uživatelé:"}.
|
||||
{"Online Users","Online uživatelé"}.
|
||||
{"Only deliver notifications to available users","Doručovat upozornění jen právě přihlášeným uživatelům"}.
|
||||
{"Only moderators and participants are allowed to change the subject in this room","Jen moderátoři a účastníci mají povoleno měnit téma této místnosti"}.
|
||||
{"Only moderators are allowed to change the subject in this room","Jen moderátoři mají povoleno měnit téma místnosti"}.
|
||||
{"Only moderators can approve voice requests","Pouze moderátoři mohou schválit žádosti o voice práva"}.
|
||||
{"Only occupants are allowed to send messages to the conference","Jen členové mají povolené zasílat zprávy do konference"}.
|
||||
{"Only occupants are allowed to send queries to the conference","Jen členové mohou odesílat požadavky (query) do konference"}.
|
||||
{"Only service administrators are allowed to send service messages","Pouze správci služby smí odesílat servisní zprávy"}.
|
||||
{"Options","Nastavení"}.
|
||||
{"Organization Name","Název firmy"}.
|
||||
{"Organization Unit","Oddělení"}.
|
||||
{"Outgoing s2s Connections:","Odchozí s2s spojení:"}.
|
||||
{"Outgoing s2s Connections","Odchozí s2s spojení"}.
|
||||
{"Outgoing s2s Servers:","Odchozí s2s servery:"}.
|
||||
{"Owner privileges required","Jsou vyžadována práva vlastníka"}.
|
||||
{"Packet","Paket"}.
|
||||
{"Password ~b","Heslo ~b"}.
|
||||
{"Password:","Heslo:"}.
|
||||
{"Password","Heslo"}.
|
||||
{"Password Verification:","Ověření hesla:"}.
|
||||
{"Password Verification","Ověření hesla"}.
|
||||
{"Path to Dir","Cesta k adresáři"}.
|
||||
{"Path to File","Cesta k souboru"}.
|
||||
{"Pending","Čekající"}.
|
||||
{"Period: ","Čas: "}.
|
||||
{"Persist items to storage","Uložit položky natrvalo do úložiště"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Podotýkáme, že tato nastavení budou zálohována do zabudované databáze Mnesia. Pokud používáte ODBC modul, musíte zálohovat svoji SQL databázi samostatně."}.
|
||||
{"Please, wait for a while before sending new voice request","Prosím, počkejte chvíli před posláním nové žádosti o voice práva"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Port ~b","Port ~b"}.
|
||||
{"Port","Port"}.
|
||||
{"Present real Jabber IDs to","Odhalovat skutečná Jabber ID"}.
|
||||
{"private, ","soukromá, "}.
|
||||
{"Protocol","Protokol"}.
|
||||
{"Publish-Subscribe","Publish-Subscribe"}.
|
||||
{"PubSub subscriber request","Žádost odběratele PubSub"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Smazat všechny položky, pokud se příslušný poskytovatel odpojí"}.
|
||||
{"Queries to the conference members are not allowed in this room","Požadavky (queries) na členy konference nejsou v této místnosti povolené"}.
|
||||
{"RAM and disc copy","Kopie RAM a disku"}.
|
||||
{"RAM copy","Kopie RAM"}.
|
||||
{"Raw","Zdroj"}.
|
||||
{"Really delete message of the day?","Skutečně smazat zprávu dne?"}.
|
||||
{"Recipient is not in the conference room","Příjemce se nenachází v konferenční místnosti"}.
|
||||
{"Register a Jabber account","Zaregistrujte si účet Jabberu"}.
|
||||
{"Registered Users","Registrovaní uživatelé"}.
|
||||
{"Registered Users:","Registrovaní živatelé:"}.
|
||||
{"Register","Zaregistrovat se"}.
|
||||
{"Registration in mod_irc for ","Registrace do mod_irc na "}.
|
||||
{"Remote copy","Vzdálená kopie"}.
|
||||
{"Remove All Offline Messages","Odstranit všechny offline zprávy"}.
|
||||
{"Remove","Odstranit"}.
|
||||
{"Remove User","Odstranit uživatele"}.
|
||||
{"Replaced by new connection","Nahrazeno novým spojením"}.
|
||||
{"Resources","Zdroje"}.
|
||||
{"Restart","Restart"}.
|
||||
{"Restart Service","Restartovat službu"}.
|
||||
{"Restore Backup from File at ","Obnovit zálohu ze souboru na "}.
|
||||
{"Restore binary backup after next ejabberd restart (requires less memory):","Obnovit binární zálohu při následujícím restartu ejabberd (vyžaduje méně paměti)"}.
|
||||
{"Restore binary backup immediately:","Okamžitě obnovit binární zálohu:"}.
|
||||
{"Restore","Obnovit"}.
|
||||
{"Restore plain text backup immediately:","Okamžitě obnovit zálohu z textového souboru:"}.
|
||||
{"Room Configuration","Nastavení místnosti"}.
|
||||
{"Room creation is denied by service policy","Pravidla služby nepovolují vytvořit místnost"}.
|
||||
{"Room description","Popis místnosti"}.
|
||||
{"Room Occupants","Počet účastníků"}.
|
||||
{"Room title","Název místnosti"}.
|
||||
{"Roster groups allowed to subscribe","Skupiny kontaktů, které mohou odebírat"}.
|
||||
{"Roster of ","Seznam kontaktů "}.
|
||||
{"Roster","Seznam kontaktů"}.
|
||||
{"Roster size","Velikost seznamu kontaktů"}.
|
||||
{"RPC Call Error","Chyba RPC volání"}.
|
||||
{"Running Nodes","Běžící uzly"}.
|
||||
{"~s access rule configuration","~s konfigurace pravidla přístupu"}.
|
||||
{"Saturday","Sobota"}.
|
||||
{"Script check","Kontrola skriptu"}.
|
||||
{"Search Results for ","Výsledky hledání pro "}.
|
||||
{"Search users in ","Hledat uživatele v "}.
|
||||
{"Send announcement to all online users","Odeslat oznámení všem online uživatelům"}.
|
||||
{"Send announcement to all online users on all hosts","Odeslat oznámení všem online uživatelům na všech hostitelích"}.
|
||||
{"Send announcement to all users","Odeslat oznámení všem uživatelům"}.
|
||||
{"Send announcement to all users on all hosts","Odeslat oznámení všem uživatelům na všech hostitelích"}.
|
||||
{"September",". září"}.
|
||||
{"Server ~b","Server ~b"}.
|
||||
{"Server:","Server:"}.
|
||||
{"Set message of the day and send to online users","Nastavit zprávu dne a odeslat ji online uživatelům"}.
|
||||
{"Set message of the day on all hosts and send to online users","Nastavit zprávu dne a odeslat ji online uživatelům"}.
|
||||
{"Shared Roster Groups","Skupiny pro sdílený seznam kontaktů"}.
|
||||
{"Show Integral Table","Zobrazit kompletní tabulku"}.
|
||||
{"Show Ordinary Table","Zobrazit běžnou tabulku"}.
|
||||
{"Shut Down Service","Vypnout službu"}.
|
||||
{"~s invites you to the room ~s","~s vás zve do místnosti ~s"}.
|
||||
{"Some Jabber clients can store your password in your computer. Use that feature only if you trust your computer is safe.","Někteří klienti umí uložit vaše heslo na disk počítače. Tuto funkci používejte, pouze pokud věříte zabezpečení svého počítače."}.
|
||||
{"Specify the access model","Uveďte přístupový model"}.
|
||||
{"Specify the event message type","Zvolte typ zpráv pro události"}.
|
||||
{"Specify the publisher model","Specifikovat model pro publikování"}.
|
||||
{"~s's Offline Messages Queue","Fronta offline zpráv uživatele ~s"}.
|
||||
{"Start Modules at ","Spustit moduly na "}.
|
||||
{"Start Modules","Spustit moduly"}.
|
||||
{"Start","Start"}.
|
||||
{"Statistics of ~p","Statistiky ~p"}.
|
||||
{"Statistics","Statistiky"}.
|
||||
{"Stop Modules at ","Zastavit moduly na "}.
|
||||
{"Stop Modules","Zastavit moduly"}.
|
||||
{"Stopped Nodes","Zastavené uzly"}.
|
||||
{"Stop","Stop"}.
|
||||
{"Storage Type","Typ úložiště"}.
|
||||
{"Store binary backup:","Uložit binární zálohu:"}.
|
||||
{"Store plain text backup:","Uložit zálohu do textového souboru:"}.
|
||||
{"Subject","Předmět"}.
|
||||
{"Submit","Odeslat"}.
|
||||
{"Submitted","Odeslané"}.
|
||||
{"Subscriber Address","Adresa odběratele"}.
|
||||
{"Subscription","Přihlášení"}.
|
||||
{"Sunday","Neděle"}.
|
||||
{"That nickname is already in use by another occupant","Přezdívka je již používána jiným členem"}.
|
||||
{"That nickname is registered by another person","Přezdívka je zaregistrována jinou osobou"}.
|
||||
{"The CAPTCHA is valid.","CAPTCHA souhlasí."}.
|
||||
{"The CAPTCHA verification has failed","Ověření CAPTCHA se nezdařilo"}.
|
||||
{"The collections with which a node is affiliated","Kolekce, se kterými je uzel spřízněn"}.
|
||||
{"the password is","heslo je"}.
|
||||
{"The password is too weak","Heslo je příliš slabé"}.
|
||||
{"The password of your Jabber account was successfully changed.","Heslo vašeho účtu Jabberu bylo úspěšně změněno."}.
|
||||
{"There was an error changing the password: ","Při změně hesla došlo k chybě: "}.
|
||||
{"There was an error creating the account: ","Při vytváření účtu došlo k chybě."}.
|
||||
{"There was an error deleting the account: ","Při mazání účtu došlo k chybě: "}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Zde nezáleží na velikosti písmen: macbeth je stejný jako MacBeth a Macbeth."}.
|
||||
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Na této stránce si můžete vytvořit účet na tomto serveru Jabberu. Vaše JID (Jabber IDentifikátor) bude mít tvar: uživatelskéjméno@server. Přečtěte si prosím pozorně instrukce pro vyplnění údajů."}.
|
||||
{"This page allows to unregister a Jabber account in this Jabber server.","Zde můžete zrušit registraci účtu na tomto serveru Jabberu."}.
|
||||
{"This participant is kicked from the room because he sent an error message","Tento účastník byl vyhozen, protože odeslal chybovou zprávu"}.
|
||||
{"This participant is kicked from the room because he sent an error message to another participant","Tento účastník byl vyhozen, protože odeslal chybovou zprávu jinému účastníkovi"}.
|
||||
{"This participant is kicked from the room because he sent an error presence","Tento účastník byl vyhozen, protože odeslal chybový status"}.
|
||||
{"This room is not anonymous","Tato místnost není anonymní"}.
|
||||
{"Thursday","Čtvrtek"}.
|
||||
{"Time","Čas"}.
|
||||
{"Time delay","Časový posun"}.
|
||||
{"Too many CAPTCHA requests","Přiliš mnoho CAPTCHA žádostí"}.
|
||||
{"To","Pro"}.
|
||||
{"To ~s","Pro ~s"}.
|
||||
{"Traffic rate limit is exceeded","Byl překročen limit"}.
|
||||
{"Transactions Aborted:","Transakce zrušena"}.
|
||||
{"Transactions Committed:","Transakce potvrzena"}.
|
||||
{"Transactions Logged:","Transakce zaznamenána"}.
|
||||
{"Transactions Restarted:","Transakce restartována"}.
|
||||
{"Tuesday","Úterý"}.
|
||||
{"Unable to generate a CAPTCHA","Nebylo možné vygenerovat CAPTCHA"}.
|
||||
{"Unauthorized","Nemáte oprávnění"}.
|
||||
{"Unregister a Jabber account","Zrušte registraci účtu Jabberu"}.
|
||||
{"Unregister","Zrušit registraci"}.
|
||||
{"Update ","Aktualizovat "}.
|
||||
{"Update","Aktualizovat"}.
|
||||
{"Update message of the day (don't send)","Aktualizovat zprávu dne (neodesílat)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Aktualizovat zprávu dne pro všechny hostitele (neodesílat)"}.
|
||||
{"Update plan","Aktualizovat plán"}.
|
||||
{"Update script","Aktualizované skripty"}.
|
||||
{"Uptime:","Čas běhu:"}.
|
||||
{"Use of STARTTLS required","Je vyžadováno STARTTLS"}.
|
||||
{"User JID","Jabber ID uživatele"}.
|
||||
{"User Management","Správa uživatelů"}.
|
||||
{"Username:","Uživatelské jméno:"}.
|
||||
{"Users are not allowed to register accounts so quickly","Je zakázáno registrovat účty v tak rychlém sledu"}.
|
||||
{"Users Last Activity","Poslední aktivita uživatele"}.
|
||||
{"Users","Uživatelé"}.
|
||||
{"User ","Uživatel "}.
|
||||
{"User","Uživatel"}.
|
||||
{"Validate","Ověřit"}.
|
||||
{"vCard User Search","Hledání uživatelů podle vizitek"}.
|
||||
{"Virtual Hosts","Virtuální hostitelé"}.
|
||||
{"Visitors are not allowed to change their nicknames in this room","Návštěvníkům této místnosti je zakázáno měnit přezdívku"}.
|
||||
{"Visitors are not allowed to send messages to all occupants","Návštevníci nemají povoleno zasílat zprávy všem účastníkům konference"}.
|
||||
{"Voice requests are disabled in this conference","Voice žádosti jsou v této konferenci zakázány"}.
|
||||
{"Voice request","Žádost o voice práva"}.
|
||||
{"Wednesday","Středa"}.
|
||||
{"When to send the last published item","Kdy odeslat poslední publikovanou položku"}.
|
||||
{"Whether to allow subscriptions","Povolit odebírání"}.
|
||||
{"You can later change your password using a Jabber client.","Později můžete své heslo změnit pomocí klienta Jabberu."}.
|
||||
{"You have been banned from this room","Byl jste vyloučen z této místnosti"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Musíte vyplnit políčko \"Přezdívka\" ve formuláři"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","Pro registraci potřebujete klienta s podporou x:data a CAPTCHA"}.
|
||||
{"You need a client that supports x:data to register the nickname","Pro registraci přezdívky potřebujete klienta s podporou x:data"}.
|
||||
{"You need an x:data capable client to configure mod_irc settings","Pro konfiguraci mod_irc potřebujete klienta s podporou x:data"}.
|
||||
{"You need an x:data capable client to configure room","Ke konfiguraci místnosti potřebujete klienta podporujícího x:data"}.
|
||||
{"You need an x:data capable client to search","K vyhledávání potřebujete klienta podporujícího x:data"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","Vaše nastavení soukromí znemožnilo směrování této stance."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","Fronta offline zpráv pro váš kontakt je plná. Zpráva byla zahozena."}.
|
||||
{"Your Jabber account was successfully created.","Váš účet Jabberu byl úspěšně vytvořen."}.
|
||||
{"Your Jabber account was successfully deleted.","Váš účet Jabberu byl úspěšně smazán."}.
|
||||
{"Your messages to ~s are being blocked. To unblock them, visit ~s","Nesmíte posílat zprávy na ~s. Pro povolení navštivte ~s"}.
|
||||
+1838
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,421 @@
|
||||
{"Access Configuration","Zugangskonfiguration"}.
|
||||
{"Access Control List Configuration","Konfiguration der Zugangskontrolllisten"}.
|
||||
{"Access control lists","Zugangskontroll-Listen (ACL)"}.
|
||||
{"Access Control Lists","Zugangskontroll-Listen (ACL)"}.
|
||||
{"Access denied by service policy","Zugang aufgrund der Dienstrichtlinien verweigert"}.
|
||||
{"Access rules","Zugangsregeln"}.
|
||||
{"Access Rules","Zugangsregeln"}.
|
||||
{"Action on user","Aktion auf Benutzer"}.
|
||||
{"Add Jabber ID","Jabber-ID hinzufügen"}.
|
||||
{"Add New","Neue hinzufügen"}.
|
||||
{"Add User","Benutzer hinzufügen"}.
|
||||
{"Administration of ","Administration von "}.
|
||||
{"Administration","Verwaltung"}.
|
||||
{"Administrator privileges required","Administratorenrechte benötigt"}.
|
||||
{"A friendly name for the node","Ein merkbarer Name für den Knoten"}.
|
||||
{"All activity","Alle Aktivitäten"}.
|
||||
{"Allow this Jabber ID to subscribe to this pubsub node?","Dieser Jabber-ID das Abonnement dieses pubsub-Knotens erlauben?"}.
|
||||
{"Allow users to change the subject","Erlaube Benutzern das Thema zu ändern"}.
|
||||
{"Allow users to query other users","Erlaube Benutzern Informationen über andere Benutzer abzufragen"}.
|
||||
{"Allow users to send invites","Erlaube Benutzern Einladungen zu senden"}.
|
||||
{"Allow users to send private messages","Erlaube Benutzern private Nachrichten zu senden"}.
|
||||
{"Allow visitors to change nickname","Erlaube Besuchern ihren Spitznamen zu ändern"}.
|
||||
{"Allow visitors to send private messages to","Erlaube Besuchern das Senden von privaten Nachrichten an"}.
|
||||
{"Allow visitors to send status text in presence updates","Erlaube Besuchern einen Text bei Statusänderung zu senden"}.
|
||||
{"Allow visitors to send voice requests","Anfragen von Sprachrechten für Benutzer erlauben"}.
|
||||
{"All Users","Alle Benutzer"}.
|
||||
{"Announcements","Ankündigungen"}.
|
||||
{"anyone","jeden"}.
|
||||
{"A password is required to enter this room","Sie brauchen ein Passwort um diesen Raum zu betreten"}.
|
||||
{"April","April"}.
|
||||
{"August","August"}.
|
||||
{"Backup","Datensicherung"}.
|
||||
{"Backup Management","Datensicherungsverwaltung"}.
|
||||
{"Backup of ","Sicherung von "}.
|
||||
{"Backup to File at ","Datensicherung in die Datei "}.
|
||||
{"Bad format","Ungültiges Format"}.
|
||||
{"Birthday","Geburtsdatum"}.
|
||||
{"CAPTCHA web page","CAPTCHA Webseite"}.
|
||||
{"Change Password","Passwort ändern"}.
|
||||
{"Change User Password","Benutzer-Passwort ändern"}.
|
||||
{"Characters not allowed:","Nicht erlaubte Zeichen:"}.
|
||||
{"Chatroom configuration modified","Chatraum-Konfiguration geändert"}.
|
||||
{"Chatroom is created","Chatraum wurde erstellt"}.
|
||||
{"Chatroom is destroyed","Chatraum wurde entfernt"}.
|
||||
{"Chatroom is started","Chatraum wurde gestartet"}.
|
||||
{"Chatroom is stopped","Chatraum wurde beendet"}.
|
||||
{"Chatrooms","Chaträume"}.
|
||||
{"Choose a username and password to register with this server","Wählen sie zum Registrieren einen Benutzernamen und ein Passwort"}.
|
||||
{"Choose modules to stop","Wähle zu stoppende Module"}.
|
||||
{"Choose storage type of tables","Wähle Speichertyp der Tabellen"}.
|
||||
{"Choose whether to approve this entity's subscription.","Wähle Sie, ob dieses Abonnement akzeptiert werden soll."}.
|
||||
{"City","Stadt"}.
|
||||
{"Commands","Befehle"}.
|
||||
{"Conference room does not exist","Konferenzraum existiert nicht"}.
|
||||
{"Configuration","Konfiguration"}.
|
||||
{"Configuration of room ~s","Konfiguration für Raum ~s"}.
|
||||
{"Connected Resources:","Verbundene Ressourcen:"}.
|
||||
{"Connections parameters","Verbindungsparameter"}.
|
||||
{"Country","Land"}.
|
||||
{"CPU Time:","CPU-Zeit:"}.
|
||||
{"Database","Datenbank"}.
|
||||
{"Database Tables at ","Datenbanktabellen auf "}.
|
||||
{"Database Tables Configuration at ","Datenbanktabellen-Konfiguration auf "}.
|
||||
{"December","Dezember"}.
|
||||
{"Default users as participants","Standardbenutzer als Teilnehmer"}.
|
||||
{"Delete","Löschen"}.
|
||||
{"Delete message of the day","Lösche Nachricht des Tages"}.
|
||||
{"Delete message of the day on all hosts","Lösche Nachricht des Tages auf allen Hosts"}.
|
||||
{"Delete Selected","Markierte löschen"}.
|
||||
{"Delete User","Benutzer löschen"}.
|
||||
{"Deliver event notifications","Ereignisbenachrichtigung zustellen"}.
|
||||
{"Deliver payloads with event notifications","Nachrichten mit Ereignis-Benachrichtigungen zustellen"}.
|
||||
{"Description:","Beschreibung:"}.
|
||||
{"Disc only copy","Nur auf Festplatte"}.
|
||||
{"Displayed Groups:","Angezeigte Gruppen:"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","Geben sie niemandem ihr Passwort, auch nicht den Administratoren des Jabber Servers."}.
|
||||
{"Dump Backup to Text File at ","Ausgabe der Sicherung in diese Textdatei "}.
|
||||
{"Dump to Text File","Ausgabe in Textdatei"}.
|
||||
{"Edit Properties","Einstellungen ändern"}.
|
||||
{"Either approve or decline the voice request.","Diese Anfrage für Sprachrechte bestätigen oder ablehnen."}.
|
||||
{"ejabberd IRC module","ejabberd IRC-Modul"}.
|
||||
{"ejabberd MUC module","ejabberd MUC-Modul"}.
|
||||
{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe-Modul"}.
|
||||
{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5-Bytestreams-Modul"}.
|
||||
{"ejabberd vCard module","ejabberd vCard-Modul"}.
|
||||
{"ejabberd Web Admin","ejabberd Web-Admin"}.
|
||||
{"Elements","Elemente"}.
|
||||
{"Email","E-Mail"}.
|
||||
{"Enable logging","Protokollierung aktivieren"}.
|
||||
{"Encoding for server ~b","Kodierung für Server ~b"}.
|
||||
{"End User Session","Benutzer-Sitzung beenden"}.
|
||||
{"Enter list of {Module, [Options]}","Geben sie eine Liste bestehend aus {Modul, [Optionen]} ein"}.
|
||||
{"Enter nickname you want to register","Geben sie den zu registrierenden Benutzernamen ein"}.
|
||||
{"Enter path to backup file","Geben sie den Pfad zur Datensicherung ein"}.
|
||||
{"Enter path to jabberd14 spool dir","Geben Sie den Pfad zum jabberd14-Spool-Verzeichnis ein"}.
|
||||
{"Enter path to jabberd14 spool file","Geben Sie den Pfad zur jabberd14-Spool-Datei ein"}.
|
||||
{"Enter path to text file","Geben sie den Pfad zur Textdatei ein"}.
|
||||
{"Enter the text you see","Geben sie den Text den sie sehen ein"}.
|
||||
{"Enter username and encodings you wish to use for connecting to IRC servers. Press 'Next' to get more fields to fill in. Press 'Complete' to save settings.","Geben sie Benutzernamen und Kodierung für Verbindungen zu IRC Servern an. Drücken sie 'Mehr' um leere Felder hinzuzufügen. Drücken sie 'Beenden' um die Einstellungen zu speichern."}.
|
||||
{"Enter username, encodings, ports and passwords you wish to use for connecting to IRC servers","Geben Sie Benutzernamen und Zeichenkodierung für die Verbindung zum IRC-Server an"}.
|
||||
{"Erlang Jabber Server","Erlang Jabber Server"}.
|
||||
{"Error","Fehler"}.
|
||||
{"Example: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}].","Beispiel: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."}.
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","Von CAPTCHA Überprüfung ausgeschlossene Jabber IDs"}.
|
||||
{"Export data of all users in the server to PIEFXIS files (XEP-0227):","Alle Benutzerdaten des Servers in PIEFXIS Dateien (XEP-0227) exportieren:"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Alle Benutzerdaten des Hosts in PIEFXIS Dateien (XEP-0227) exportieren:"}.
|
||||
{"Failed to extract JID from your voice request approval","Fehler beim Auslesen der JID aus der Anfragenbestätigung für Sprachrechte"}.
|
||||
{"Family Name","Nachname"}.
|
||||
{"February","Februar"}.
|
||||
{"Fill in fields to search for any matching Jabber User","Füllen Sie die Felder aus, um nach passenden Jabber-Benutzern zu suchen"}.
|
||||
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Füllen Sie die Felder aus, um nach passenden Jabber-Benutzern zu suchen (beenden Sie ein Feld mit *, um auch nach Teilzeichenketten zu suchen)"}.
|
||||
{"Friday","Freitag"}.
|
||||
{"From ~s","Von ~s"}.
|
||||
{"From","Von"}.
|
||||
{"Full Name","Vollständiger Name"}.
|
||||
{"Get Number of Online Users","Anzahl der angemeldeten Benutzer abrufen"}.
|
||||
{"Get Number of Registered Users","Anzahl der registrierten Benutzer abrufen"}.
|
||||
{"Get User Last Login Time","letzte Anmeldezeit abrufen"}.
|
||||
{"Get User Password","Benutzer-Passwort abrufen"}.
|
||||
{"Get User Statistics","Benutzer-Statistiken abrufen"}.
|
||||
{"Grant voice to this person?","Sprachrechte dieser Person erteilen?"}.
|
||||
{"Group ","Gruppe "}.
|
||||
{"Groups","Gruppen"}.
|
||||
{"has been banned","wurde gebannt"}.
|
||||
{"has been kicked because of an affiliation change","wurde wegen Änderung des Mitgliederstatus gekickt"}.
|
||||
{"has been kicked because of a system shutdown","wurde wegen Systemabschaltung gekickt"}.
|
||||
{"has been kicked because the room has been changed to members-only","wurde gekickt weil der Raum auf Nur-Mitglieder umgestellt wurde"}.
|
||||
{"has been kicked","wurde gekickt"}.
|
||||
{" has set the subject to: "," hat das Thema geändert auf: "}.
|
||||
{"Host","Host"}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Wenn sie das CAPTCHA Bild nicht sehen, besuchen sie bitte die Webseite."}.
|
||||
{"If you want to specify different ports, passwords, encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\", port, \"password\"}'. By default this service use \"~s\" encoding, port ~p, empty password.","Wenn sie verschiedene Ports, Passwörter und Kodierungen für IRC Server angeben wollen, erstellen sie die Liste mit folgendem Format '{\"IRC Server\", \"Kodierung\", Port, \"Passwort\"}'. Standardmäßig benutzt dieser Dienst die \"~s\" Kodierung, den Port ~p und kein Passwort."}.
|
||||
{"Import Directory","Verzeichnis importieren"}.
|
||||
{"Import File","Datei importieren"}.
|
||||
{"Import user data from jabberd14 spool file:","Importiere Benutzer von jabberd14 Spool Datei:"}.
|
||||
{"Import User from File at ","Benutzer aus dieser Datei importieren "}.
|
||||
{"Import users data from a PIEFXIS file (XEP-0227):","Benutzerdaten von einer PIEFXIS Datei (XEP-0227) importieren:"}.
|
||||
{"Import users data from jabberd14 spool directory:","Importiere Benutzer von jabberd14 Spool Verzeichnis:"}.
|
||||
{"Import Users from Dir at ","Benutzer importieren aus dem Verzeichnis "}.
|
||||
{"Import Users From jabberd14 Spool Files","Importiere Benutzer aus jabberd14-Spool-Dateien"}.
|
||||
{"Improper message type","Unzulässiger Nachrichtentyp"}.
|
||||
{"Incorrect password","Falsches Passwort"}.
|
||||
{"Invalid affiliation: ~s","Ungültige Mitgliedschaft: ~s"}.
|
||||
{"Invalid role: ~s","Ungültige Rolle: ~s"}.
|
||||
{"IP addresses","IP Adressen"}.
|
||||
{"IP","IP"}.
|
||||
{"IRC channel (don't put the first #)","IRC Channel (ohne dem ersten #)"}.
|
||||
{"IRC server","IRC Server"}.
|
||||
{"IRC settings","IRC Einstellungen"}.
|
||||
{"IRC Transport","IRC Transport"}.
|
||||
{"IRC username","IRC Benutzername"}.
|
||||
{"IRC Username","IRC-Benutzername"}.
|
||||
{"is now known as","ist nun bekannt als"}.
|
||||
{"It is not allowed to send private messages","Es ist nicht erlaubt private Nachrichten zu senden"}.
|
||||
{"It is not allowed to send private messages of type \"groupchat\"","Es ist nicht erlaubt private Nachrichten des Typs \"Gruppenchat\" zu senden"}.
|
||||
{"It is not allowed to send private messages to the conference","Es ist nicht erlaubt private Nachrichten an den Raum zu schicken"}.
|
||||
{"Jabber Account Registration","Jabber Konto Anmeldung"}.
|
||||
{"Jabber ID","Jabber ID"}.
|
||||
{"Jabber ID ~s is invalid","Die Jabber-ID ~s ist ungültig"}.
|
||||
{"January","Januar"}.
|
||||
{"Join IRC channel","IRC Channel beitreten"}.
|
||||
{"joins the room","betretet den Raum"}.
|
||||
{"Join the IRC channel here.","Hier den IRC Channel beitreten."}.
|
||||
{"Join the IRC channel in this Jabber ID: ~s","Den IRC Channel mit dieser Jabber ID beitreten: ~s"}.
|
||||
{"July","Juli"}.
|
||||
{"June","Juni"}.
|
||||
{"Last Activity","Letzte Aktivität"}.
|
||||
{"Last login","Letzte Anmeldung"}.
|
||||
{"Last month","Letzter Monat"}.
|
||||
{"Last year","Letztes Jahr"}.
|
||||
{"leaves the room","verlässt den Raum"}.
|
||||
{"Listened Ports","Aktive Ports"}.
|
||||
{"Listened Ports at ","Aktive Ports bei"}.
|
||||
{"List of modules to start","Liste der zu startenden Module"}.
|
||||
{"Low level update script","Low level Aktualisierungsscript"}.
|
||||
{"Make participants list public","Teilnehmerliste öffentlich machen"}.
|
||||
{"Make room CAPTCHA protected","Raum mit Verifizierung (Captcha) versehen"}.
|
||||
{"Make room members-only","Raum nur für Mitglieder zugänglich machen"}.
|
||||
{"Make room moderated","Raum moderiert machen"}.
|
||||
{"Make room password protected","Raum mit Passwort schützen"}.
|
||||
{"Make room persistent","Raum persistent machen"}.
|
||||
{"Make room public searchable","Raum öffentlich suchbar machen"}.
|
||||
{"March","März"}.
|
||||
{"Maximum Number of Occupants","Maximale Anzahl von Teilnehmern"}.
|
||||
{"Max # of items to persist","Maximale Anzahl dauerhaft zu speichernder Einträge"}.
|
||||
{"Max payload size in bytes","Maximale Nutzlastgrösse in Bytes"}.
|
||||
{"May","Mai"}.
|
||||
{"Membership is required to enter this room","Um diesen Raum zu betreten müssen sie Mitglied sein"}.
|
||||
{"Members:","Mitglieder:"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Merken sie sich ihr Passwort, oder schreiben sie es auf einen Zettel den sie sicher verwahren. Bei Jabber gibt es keine automatische Möglichkeit, das Passwort wiederherzustellen."}.
|
||||
{"Memory","Speicher"}.
|
||||
{"Message body","Nachrichtentext"}.
|
||||
{"Middle Name","Zweiter Vorname"}.
|
||||
{"Minimum interval between voice requests (in seconds)","Mindestdauer zwischen Anfragen für Sprachrechte (in Sekunden)"}.
|
||||
{"Moderator privileges required","Moderatorrechte benötigt"}.
|
||||
{"moderators only","ausschliesslich Moderatoren"}.
|
||||
{"Modified modules","Geänderte Module"}.
|
||||
{"Module","Modul"}.
|
||||
{"Modules at ","Module bei "}.
|
||||
{"Modules","Module"}.
|
||||
{"Monday","Montag"}.
|
||||
{"Name:","Name:"}.
|
||||
{"Name","Vorname"}.
|
||||
{"Never","Nie"}.
|
||||
{"New Password:","Neues Passwort:"}.
|
||||
{"Nickname","Benutzername"}.
|
||||
{"Nickname Registration at ","Registrieren des Benutzernames auf"}.
|
||||
{"Nickname ~s does not exist in the room","Der Benutzername ~s existiert im Raum nicht"}.
|
||||
{"nobody","niemanden"}.
|
||||
{"No body provided for announce message","Kein Text für die Ankündigung angegeben"}.
|
||||
{"No Data","Keine Daten"}.
|
||||
{"Node ID","Knoten-ID"}.
|
||||
{"Node ","Knoten "}.
|
||||
{"Node not found","Knoten nicht gefunden"}.
|
||||
{"Nodes","Knoten"}.
|
||||
{"No limit","Keine Begrenzung"}.
|
||||
{"None","Keine"}.
|
||||
{"No resource provided","Keine Ressource angegeben"}.
|
||||
{"Not Found","Nicht gefunden"}.
|
||||
{"Notify subscribers when items are removed from the node","Abonnenten benachrichtigen, wenn Einträge vom Knoten entfernt werden"}.
|
||||
{"Notify subscribers when the node configuration changes","Abonnenten benachrichtigen, wenn sich die Knotenkonfiguration ändert"}.
|
||||
{"Notify subscribers when the node is deleted","Abonnenten benachrichtigen, wenn der Knoten gelöscht wird"}.
|
||||
{"November","November"}.
|
||||
{"Number of occupants","Anzahl der Teilnehmer"}.
|
||||
{"Number of online users","Anzahl der angemeldeten Benutzer"}.
|
||||
{"Number of registered users","Anzahl der registrierten Benutzer"}.
|
||||
{"October","Oktober"}.
|
||||
{"Offline Messages:","Offline-Nachrichten:"}.
|
||||
{"Offline Messages","Offline-Nachrichten"}.
|
||||
{"OK","OK"}.
|
||||
{"Old Password:","Aktuelles Passwort:"}.
|
||||
{"Online","Angemeldet"}.
|
||||
{"Online Users:","Angemeldete Benutzer:"}.
|
||||
{"Online Users","Angemeldete Benutzer"}.
|
||||
{"Only deliver notifications to available users","Benachrichtigungen nur an verfügbare Benutzer schicken"}.
|
||||
{"Only moderators and participants are allowed to change the subject in this room","Nur Moderatoren und Mitglieder dürfen das Thema in diesem Raum ändern"}.
|
||||
{"Only moderators are allowed to change the subject in this room","Nur Moderatoren dürfen das Thema in diesem Raum ändern"}.
|
||||
{"Only moderators can approve voice requests","Nur Moderatoren können Anfragen für Sprachrechte bestätigen"}.
|
||||
{"Only occupants are allowed to send messages to the conference","Nur Teilnehmer dürfen Nachrichten an den Raum schicken"}.
|
||||
{"Only occupants are allowed to send queries to the conference","Nur Teilnehmer sind berechtigt Anfragen an die Konferenz zu senden"}.
|
||||
{"Only service administrators are allowed to send service messages","Nur Service-Administratoren sind berechtigt, Servicenachrichten zu versenden"}.
|
||||
{"Options","Optionen"}.
|
||||
{"Organization Name","Organisation"}.
|
||||
{"Organization Unit","Abteilung"}.
|
||||
{"Outgoing s2s Connections:","Ausgehende s2s-Verbindungen:"}.
|
||||
{"Outgoing s2s Connections","Ausgehende s2s-Verbindungen"}.
|
||||
{"Outgoing s2s Servers:","Ausgehende s2s-Server:"}.
|
||||
{"Owner privileges required","Besitzerrechte benötigt"}.
|
||||
{"Packet","Paket"}.
|
||||
{"Password ~b","Passwort ~b"}.
|
||||
{"Password:","Passwort:"}.
|
||||
{"Password","Passwort"}.
|
||||
{"Password Verification:","Passwort bestätigen:"}.
|
||||
{"Password Verification","Passwort bestätigen"}.
|
||||
{"Path to Dir","Pfad zum Verzeichnis"}.
|
||||
{"Path to File","Pfad zur Datei"}.
|
||||
{"Pending","anhängig"}.
|
||||
{"Period: ","Zeitraum: "}.
|
||||
{"Persist items to storage","Einträge dauerhaft speichern"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Beachten sie, das diese Optionen nur die eingebaute Mnesia-Datenbank sichern. Wenn sie das ODBC-Modul verwenden, müssen sie die SQL-Datenbank manuell sichern."}.
|
||||
{"Please, wait for a while before sending new voice request","Bitte warten sie ein wenig, bevor sie eine weitere Anfrage für Sprachrechte senden"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Port ~b","Port ~b"}.
|
||||
{"Port","Port"}.
|
||||
{"Present real Jabber IDs to","Echte Jabber-IDs anzeigen für"}.
|
||||
{"private, ","privat, "}.
|
||||
{"Protocol","Protokoll"}.
|
||||
{"Publish-Subscribe","Publish-Subscribe"}.
|
||||
{"PubSub subscriber request","PubSub-Abonnenten-Anfrage"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Alle Einträge entfernen, wenn der relevante Veröffentlicher offline geht"}.
|
||||
{"Queries to the conference members are not allowed in this room","Anfragen an die Teilnehmer sind in diesem Raum nicht erlaubt"}.
|
||||
{"RAM and disc copy","RAM und Festplatte"}.
|
||||
{"RAM copy","Nur RAM"}.
|
||||
{"Raw","Unformatiert"}.
|
||||
{"Really delete message of the day?","Die Nachricht des Tages wirklich löschen?"}.
|
||||
{"Recipient is not in the conference room","Der Empfänger ist nicht im Raum"}.
|
||||
{"Register a Jabber account","Jabber Konto registrieren"}.
|
||||
{"Register","Anmelden"}.
|
||||
{"Registered Users:","Registrierte Benutzer:"}.
|
||||
{"Registered Users","Registrierte Benutzer"}.
|
||||
{"Registration in mod_irc for ","Registrierung in mod_irc für "}.
|
||||
{"Remote copy","Fernkopie"}.
|
||||
{"Remove All Offline Messages","Alle Offline Nachrichten löschen"}.
|
||||
{"Remove","Entfernen"}.
|
||||
{"Remove User","Benutzer löschen"}.
|
||||
{"Replaced by new connection","Durch neue Verbindung ersetzt"}.
|
||||
{"Resources","Ressourcen"}.
|
||||
{"Restart","Neustart"}.
|
||||
{"Restart Service","Dienst neustarten"}.
|
||||
{"Restore Backup from File at ","Datenwiederherstellung aus der Datei "}.
|
||||
{"Restore binary backup after next ejabberd restart (requires less memory):","Stelle binäre Sicherung beim nächsten ejabberd-Neustart wieder her (benötigt weniger Speicher):"}.
|
||||
{"Restore binary backup immediately:","Stelle binäre Sicherung sofort wieder her:"}.
|
||||
{"Restore plain text backup immediately:","Stelle Klartext-Sicherung sofort wieder her:"}.
|
||||
{"Restore","Wiederherstellung"}.
|
||||
{"Room Configuration","Raum-Konfiguration"}.
|
||||
{"Room creation is denied by service policy","Anlegen des Raumes aufgrund der Dienstrichtlinien verweigert"}.
|
||||
{"Room description","Raum Beschreibung"}.
|
||||
{"Room Occupants","Teilnehmer in diesem Raum"}.
|
||||
{"Room title","Raumname"}.
|
||||
{"Roster groups allowed to subscribe","Kontaktlisten-Gruppen die abonnieren dürfen"}.
|
||||
{"Roster","Kontaktliste"}.
|
||||
{"Roster of ","Kontaktliste von "}.
|
||||
{"Roster size","Kontaktlistengröße"}.
|
||||
{"RPC Call Error","Fehler bei RPC-Aufruf"}.
|
||||
{"Running Nodes","Aktive Knoten"}.
|
||||
{"~s access rule configuration","~s Zugangsregel-Konfiguration"}.
|
||||
{"Saturday","Samstag"}.
|
||||
{"Script check","Script-Überprüfung"}.
|
||||
{"Search Results for ","Suchergebnisse für "}.
|
||||
{"Search users in ","Benutzer suchen in "}.
|
||||
{"Send announcement to all online users on all hosts","Sende Ankündigung an alle angemeldeten Benutzer auf allen Hosts"}.
|
||||
{"Send announcement to all online users","Sende Ankündigung an alle angemeldeten Benutzer"}.
|
||||
{"Send announcement to all users on all hosts","Sende Ankündigung an alle Benutzer auf allen Hosts"}.
|
||||
{"Send announcement to all users","Sende Ankündigung an alle Benutzer"}.
|
||||
{"September","September"}.
|
||||
{"Server ~b","Server ~b"}.
|
||||
{"Server:","Server:"}.
|
||||
{"Set message of the day and send to online users","Setze Nachricht des Tages und sende sie an alle angemeldeten Benutzer"}.
|
||||
{"Set message of the day on all hosts and send to online users","Setze Nachricht des Tages auf allen Hosts und sende sie an alle angemeldeten Benutzer"}.
|
||||
{"Shared Roster Groups","Gruppen der gemeinsamen Kontaktliste"}.
|
||||
{"Show Integral Table","Vollständige Tabelle anzeigen"}.
|
||||
{"Show Ordinary Table","Normale Tabelle anzeigen"}.
|
||||
{"Shut Down Service","Dienst herunterfahren"}.
|
||||
{"~s invites you to the room ~s","~s lädt Sie in den Raum ~s ein"}.
|
||||
{"Some Jabber clients can store your password in your computer. Use that feature only if you trust your computer is safe.","Einige Jabber Client Programme speichern ihr Passwort auf ihrem Computer. Verwenden sie diese Möglichkeit nur auf Computern, die sie als sicher einstufen."}.
|
||||
{"Specify the access model","Geben sie das Zugangsmodell an"}.
|
||||
{"Specify the event message type","Geben sie den Ereignis-Nachrichtentyp an"}.
|
||||
{"Specify the publisher model","Geben sie das Publikationsmodell an"}.
|
||||
{"~s's Offline Messages Queue","~s's Offline-Nachrichten-Warteschlange"}.
|
||||
{"Start Modules at ","Starte Module auf "}.
|
||||
{"Start Modules","Module starten"}.
|
||||
{"Start","Starten"}.
|
||||
{"Statistics of ~p","Statistiken von ~p"}.
|
||||
{"Statistics","Statistik"}.
|
||||
{"Stop Modules at ","Stoppe Module auf "}.
|
||||
{"Stop Modules","Module stoppen"}.
|
||||
{"Stopped Nodes","Inaktive Knoten"}.
|
||||
{"Stop","Stoppen"}.
|
||||
{"Storage Type","Speichertyp"}.
|
||||
{"Store binary backup:","Speichere binäre Sicherung:"}.
|
||||
{"Store plain text backup:","Speichere Klartext-Sicherung:"}.
|
||||
{"Subject","Betreff"}.
|
||||
{"Submit","Senden"}.
|
||||
{"Submitted","Gesendet"}.
|
||||
{"Subscriber Address","Abonnenten-Adresse"}.
|
||||
{"Subscription","Abonnement"}.
|
||||
{"Sunday","Sonntag"}.
|
||||
{"That nickname is already in use by another occupant","Dieser Benutzername wird bereits von einem Teilnehmer genutzt"}.
|
||||
{"That nickname is registered by another person","Dieser Benutzername wurde bereits von jemand anderem registriert"}.
|
||||
{"The CAPTCHA is valid.","Die Verifizierung ist gültig."}.
|
||||
{"The CAPTCHA verification has failed","Die CAPTCHA Verifizierung schlug fehl"}.
|
||||
{"The collections with which a node is affiliated","Sammlungen, mit denen ein Knoten verknüpft ist"}.
|
||||
{"the password is","das Passwort lautet"}.
|
||||
{"The password is too weak","Das Passwort ist zu einfach"}.
|
||||
{"The password of your Jabber account was successfully changed.","Das Passwort von ihrem Jabber Konto wurde geändert."}.
|
||||
{"There was an error changing the password: ","Es trat ein Fehler beim Ändern des Passworts auf:"}.
|
||||
{"There was an error creating the account: ","Es trat ein Fehler beim erstellen des Kontos auf:"}.
|
||||
{"There was an error deleting the account: ","Es trat ein Fehler beim Löschen des Kontos auf:"}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Groß/Klein-Schreibung spielt hierbei keine Rolle: macbeth ist gleich MacBeth und Macbeth."}.
|
||||
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Diese Seite erlaubt das anlegen eines Jabber Kontos auf diesem Jabber Server. Ihre JID (Jabber IDentifier) setzt sich folgend zusammen: benutzername@server. Bitte lesen sie die Hinweise genau durch, um die Felder korrekt auszufüllen."}.
|
||||
{"This page allows to unregister a Jabber account in this Jabber server.","Diese Seite erlaubt es, ein Jabber Konto von diesem Server zu entfernen."}.
|
||||
{"This participant is kicked from the room because he sent an error message","Dieser Teilnehmer wurde aus dem Raum geworfen, da er eine fehlerhafte Nachricht gesendet hat"}.
|
||||
{"This participant is kicked from the room because he sent an error message to another participant","Dieser Teilnehmer wurde aus dem Raum geworfen, da er eine fehlerhafte Nachricht an einen anderen Teilnehmer gesendet hat"}.
|
||||
{"This participant is kicked from the room because he sent an error presence","Dieser Teilnehmer wurde aus dem Raum gekickt, da er einen fehlerhaften Status gesendet hat"}.
|
||||
{"This room is not anonymous","Dieser Raum ist nicht anonym"}.
|
||||
{"Thursday","Donnerstag"}.
|
||||
{"Time delay","Zeitverzögerung"}.
|
||||
{"Time","Zeit"}.
|
||||
{"To","An"}.
|
||||
{"Too many CAPTCHA requests","Zu viele CAPTCHA Anfragen"}.
|
||||
{"To ~s","An ~s"}.
|
||||
{"Traffic rate limit is exceeded","Datenratenlimit wurde überschritten"}.
|
||||
{"Transactions Aborted:","Abgebrochene Transaktionen:"}.
|
||||
{"Transactions Committed:","Durchgeführte Transaktionen:"}.
|
||||
{"Transactions Logged:","Protokollierte Transaktionen:"}.
|
||||
{"Transactions Restarted:","Neu gestartete Transaktionen:"}.
|
||||
{"Tuesday","Dienstag"}.
|
||||
{"Unable to generate a CAPTCHA","Konnte CAPTCHA nicht erstellen"}.
|
||||
{"Unauthorized","Nicht berechtigt"}.
|
||||
{"Unregister","Abmelden"}.
|
||||
{"Unregister a Jabber account","Jabber Konto entfernen"}.
|
||||
{"Update","Aktualisieren"}.
|
||||
{"Update ","Aktualisierung "}.
|
||||
{"Update message of the day (don't send)","Aktualisiere Nachricht des Tages (nicht senden)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Aktualisiere Nachricht des Tages auf allen Hosts (nicht senden)"}.
|
||||
{"Update plan","Aktualisierungsplan"}.
|
||||
{"Update script","Aktualisierungsscript"}.
|
||||
{"Uptime:","Betriebszeit:"}.
|
||||
{"Use of STARTTLS required","Verwendung von STARTTLS erforderlich"}.
|
||||
{"User ","Benutzer "}.
|
||||
{"User","Benutzer"}.
|
||||
{"User JID","Benutzer JID"}.
|
||||
{"User Management","Benutzerverwaltung"}.
|
||||
{"Username:","Benutzername:"}.
|
||||
{"Users are not allowed to register accounts so quickly","Benutzer dürfen Konten nicht so schnell registrieren"}.
|
||||
{"Users","Benutzer"}.
|
||||
{"Users Last Activity","Letzte Benutzeraktivität"}.
|
||||
{"Validate","Validieren"}.
|
||||
{"vCard User Search","vCard-Benutzer-Suche"}.
|
||||
{"Virtual Hosts","Virtuelle Hosts"}.
|
||||
{"Visitors are not allowed to change their nicknames in this room","Besucher dürfen in diesem Raum ihren Benutzernamen nicht ändern"}.
|
||||
{"Visitors are not allowed to send messages to all occupants","Besucher dürfen nicht an alle Teilnehmer Nachrichten verschicken"}.
|
||||
{"Voice request","Anfrage für Sprachrechte"}.
|
||||
{"Voice requests are disabled in this conference","Anfragen für Sprachrechte sind in diesem Raum deaktiviert"}.
|
||||
{"Wednesday","Mittwoch"}.
|
||||
{"When to send the last published item","Wann soll das letzte veröffentlichte Objekt gesendet werden"}.
|
||||
{"Whether to allow subscriptions","Ob Abonnements erlaubt sind"}.
|
||||
{"You can later change your password using a Jabber client.","Sie können das Passwort später mit einem Jabber Client Programm ändern."}.
|
||||
{"You have been banned from this room","Sie wurden aus diesem Raum verbannt"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Sie müssen das Feld \"Benutzername\" ausfüllen"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","Sie benötigen einen Client, der x:data und CAPTCHA unterstützt, um Ihren Benutzernamen zu registrieren"}.
|
||||
{"You need a client that supports x:data to register the nickname","Sie benötigen einen Client, der x:data unterstützt, um Ihren Benutzernamen zu registrieren"}.
|
||||
{"You need an x:data capable client to configure mod_irc settings","Sie benötigen einen Client, der x:data unterstützt, um die mod_irc-Einstellungen zu konfigurieren"}.
|
||||
{"You need an x:data capable client to configure room","Sie benötigen einen Client, der x:data unterstützt, um den Raum zu konfigurieren"}.
|
||||
{"You need an x:data capable client to search","Sie benötigen einen Client, der x:data unterstützt, um die Suche verwenden zu können"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","Ihre aktive Privacy Liste hat die Weiterleitung des Stanzas unterbunden."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","Ihre Offline-Nachrichten-Warteschlange ist voll. Die Nachricht wurde verworfen."}.
|
||||
{"Your Jabber account was successfully created.","Ihr Jabber Konto wurde erfolgreich erstellt."}.
|
||||
{"Your Jabber account was successfully deleted.","Ihr Jabber Konto wurde erfolgreich gelöscht."}.
|
||||
{"Your messages to ~s are being blocked. To unblock them, visit ~s","Ihre Nachrichten an ~s werden blockiert. Um dies zu ändern, besuchen sie ~s"}.
|
||||
+1883
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,421 @@
|
||||
{"Access Configuration","Διαμόρφωση Πρόσβασης"}.
|
||||
{"Access Control List Configuration","Διαχείριση στις Λίστες Ελέγχου Πρόσβασης"}.
|
||||
{"Access control lists","Λίστες Ελέγχου Πρόσβασης"}.
|
||||
{"Access Control Lists","Λίστες Ελέγχου Πρόσβασης"}.
|
||||
{"Access denied by service policy","Άρνηση πρόσβασης, λόγω τακτικής παροχής υπηρεσιών"}.
|
||||
{"Access rules","Κανόνες Πρόσβασης"}.
|
||||
{"Access Rules","Κανόνες Πρόσβασης"}.
|
||||
{"Action on user","Eνέργεια για το χρήστη"}.
|
||||
{"Add Jabber ID","Προσθήκη Jabber Ταυτότητας"}.
|
||||
{"Add New","Προσθήκη νέου"}.
|
||||
{"Add User","Προσθήκη Χρήστη"}.
|
||||
{"Administration of ","Διαχείριση του"}.
|
||||
{"Administration","Διαχείριση"}.
|
||||
{"Administrator privileges required","Aπαιτούνται προνόμια διαχειριστή"}.
|
||||
{"A friendly name for the node","Ένα φιλικό όνομα για τον κόμβο"}.
|
||||
{"All activity","Όλες οι δραστηριότητες"}.
|
||||
{"Allow this Jabber ID to subscribe to this pubsub node?","Επιτρέπετε σε αυτή την Jabber Ταυτότητα να εγγραφεί σε αυτό τον κόμβο Δημοσίευσης-Εγγραφής;"}.
|
||||
{"Allow users to change the subject","Επιτρέψετε στους χρήστες να αλλάζουν το θέμα"}.
|
||||
{"Allow users to query other users","Επιτρέπστε στους χρήστες να ερωτούν άλλους χρήστες"}.
|
||||
{"Allow users to send invites","Επιτρέψετε στους χρήστες να αποστέλλουν προσκλήσεις"}.
|
||||
{"Allow users to send private messages","Επιτρέψετε στους χρήστες να αποστέλλουν ιδιωτικά μηνύματα"}.
|
||||
{"Allow visitors to change nickname","Επιτρέψετε στους επισκέπτες να αλλάζου ψευδώνυμο"}.
|
||||
{"Allow visitors to send private messages to","Επιτρέψετε στους χρήστες να αποστέλλουν ιδιωτικά μηνύματα σε"}.
|
||||
{"Allow visitors to send status text in presence updates","Επιτρέψτε στους επισκέπτες να αποστέλλουν κατάσταση στις ενημερώσεις παρουσίας"}.
|
||||
{"Allow visitors to send voice requests","Επιτρέψτε στους επισκέπτες να στέλνουν αιτήματα φωνής"}.
|
||||
{"All Users","Όλοι οι χρήστες"}.
|
||||
{"Announcements","Ανακοινώσεις"}.
|
||||
{"anyone","οποιοσδήποτε"}.
|
||||
{"A password is required to enter this room","Απαιτείται κωδικός πρόσβασης για είσοδο σε αυτή την αίθουσα"}.
|
||||
{"April","Απρίλιος"}.
|
||||
{"August","Αύγουστος"}.
|
||||
{"Backup Management","Διαχείριση Αντιγράφου Ασφαλείας"}.
|
||||
{"Backup of ","Αντιγράφο Ασφαλείας του "}.
|
||||
{"Backup to File at ","Αποθήκευση Αντιγράφου Ασφαλείας σε Αρχείο στο "}.
|
||||
{"Backup","Αποθήκευση Αντιγράφου Ασφαλείας"}.
|
||||
{"Bad format","Ακατάλληλη μορφή"}.
|
||||
{"Birthday","Γενέθλια"}.
|
||||
{"CAPTCHA web page","Ιστοσελίδα CAPTCHA "}.
|
||||
{"Change Password","Αλλαγή κωδικού"}.
|
||||
{"Change User Password","Αλλαγή Κωδικού Πρόσβασης Χρήστη"}.
|
||||
{"Characters not allowed:","Χαρακτήρες δεν επιτρέπονται:"}.
|
||||
{"Chatroom configuration modified","Διαμόρφωση Αίθουσaς σύνεδριασης τροποποιηθηκε"}.
|
||||
{"Chatroom is created","Η αίθουσα σύνεδριασης δημιουργήθηκε"}.
|
||||
{"Chatroom is destroyed","Η αίθουσα σύνεδριασης διαγράφηκε"}.
|
||||
{"Chatroom is started","Η αίθουσα σύνεδριασης έχει ξεκινήσει"}.
|
||||
{"Chatroom is stopped","Η αίθουσα σύνεδριασης έχει σταματήσει"}.
|
||||
{"Chatrooms","Αίθουσες σύνεδριασης"}.
|
||||
{"Choose a username and password to register with this server","Επιλέξτε ένα όνομα χρήστη και κωδικό πρόσβασης για να εγγραφείτε σε αυτό τον διακομιστή"}.
|
||||
{"Choose modules to stop","Επιλέξτε modules για να σταματήσουν"}.
|
||||
{"Choose storage type of tables","Επιλέξτε τύπο αποθήκευσης των πινάκων"}.
|
||||
{"Choose whether to approve this entity's subscription.","Επιλέξτε αν θα εγκρίθεί η εγγραφή αυτής της οντότητας."}.
|
||||
{"City","Πόλη"}.
|
||||
{"Commands","Εντολές"}.
|
||||
{"Conference room does not exist","Αίθουσα σύνεδριασης δεν υπάρχει"}.
|
||||
{"Configuration of room ~s","Διαμόρφωση Αίθουσας σύνεδριασης ~s"}.
|
||||
{"Configuration","Διαμόρφωση"}.
|
||||
{"Connected Resources:","Συνδεδεμένοι Πόροι:"}.
|
||||
{"Connections parameters","Παράμετροι Συνδέσης"}.
|
||||
{"Country","Χώρα"}.
|
||||
{"CPU Time:","Ώρα CPU:"}.
|
||||
{"Database Tables at ","Πίνακες βάσης δεδομένων στο "}.
|
||||
{"Database Tables Configuration at ","Διαμόρφωση Πίνακων βάσης δεδομένων στο "}.
|
||||
{"Database","Βάση δεδομένων"}.
|
||||
{"December","Δεκέμβριος"}.
|
||||
{"Default users as participants","Προεπιλογη χρήστων ως συμμετέχοντες"}.
|
||||
{"Delete message of the day on all hosts","Διαγράψτε το μήνυμα της ημέρας σε όλους τους κεντρικούς υπολογιστές"}.
|
||||
{"Delete message of the day","Διαγράψτε το μήνυμα της ημέρας"}.
|
||||
{"Delete Selected","Διαγραφή επιλεγμένων"}.
|
||||
{"Delete User","Διαγραφή Χρήστη"}.
|
||||
{"Delete","Διαγραφή"}.
|
||||
{"Deliver event notifications","Κοινοποιήσεις παράδοσης"}.
|
||||
{"Deliver payloads with event notifications","Κοινοποιήσεις με την παράδοση φορτίων"}.
|
||||
{"Description:","Περιγραφή:"}.
|
||||
{"Disc only copy","Αντίγραφο μόνο σε δίσκο"}.
|
||||
{"Displayed Groups:","Εμφανίσμενες Ομάδες:"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the Jabber server.","Μην πείτε τον κωδικό πρόσβασής σας σε κανέναν, ακόμη και στους διαχειριστές του διακομιστή Jabber."}.
|
||||
{"Dump Backup to Text File at ","Αποθήκευση Αντιγράφου Ασφαλείας σε αρχείο κειμένου στο "}.
|
||||
{"Dump to Text File","Αποθήκευση σε αρχείο κειμένου"}.
|
||||
{"Edit Properties","Επεξεργασία ιδιοτήτων"}.
|
||||
{"Either approve or decline the voice request.","Είτε εγκρίνετε ή απορρίψτε το αίτημα φωνής."}.
|
||||
{"ejabberd IRC module","ejabberd IRC module"}.
|
||||
{"ejabberd MUC module","ejabberd MUC module"}.
|
||||
{"ejabberd Publish-Subscribe module","ejabberd module Δημοσίευσης-Εγγραφής"}.
|
||||
{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}.
|
||||
{"ejabberd vCard module","ejabberd vCard module"}.
|
||||
{"ejabberd Web Admin","ejabberd Web Admin"}.
|
||||
{"Elements","Στοιχεία"}.
|
||||
{"Email","Email"}.
|
||||
{"Enable logging","Ενεργοποίηση καταγραφής"}.
|
||||
{"Encoding for server ~b","Κωδικοποίηση για διακομιστή ~b"}.
|
||||
{"End User Session","Τερματισμός Συνεδρίας Χρήστη"}.
|
||||
{"Enter list of {Module, [Options]}","Εισάγετε κατάλογο των (Module, [Επιλογές])"}.
|
||||
{"Enter nickname you want to register","Πληκτρολογήστε το ψευδώνυμο που θέλετε να εγγραφείτε"}.
|
||||
{"Enter path to backup file","Εισάγετε τοποθεσία αρχείου αντιγράφου ασφαλείας"}.
|
||||
{"Enter path to jabberd14 spool dir","Εισάγετε κατάλογο αρχείων σειράς jabberd14"}.
|
||||
{"Enter path to jabberd14 spool file","Εισάγετε τοποθεσία αρχείου σειράς jabberd14"}.
|
||||
{"Enter path to text file","Εισάγετε Τοποθεσία Αρχείου Κειμένου"}.
|
||||
{"Enter the text you see","Πληκτρολογήστε το κείμενο που βλέπετε"}.
|
||||
{"Enter username and encodings you wish to use for connecting to IRC servers. Press 'Next' to get more fields to fill in. Press 'Complete' to save settings.","Πληκτρολογήστε το όνομα χρήστη και κωδικοποιήσεις που θέλετε να χρησιμοποιήσετε για τη σύνδεση με διακομιστές IRC. Πατήστε 'Next' για να πάρετε περισσότερα πεδία να συμπληρώσετε. Πατήστε 'Complete' για να αποθηκεύσετε ρυθμίσεις."}.
|
||||
{"Enter username, encodings, ports and passwords you wish to use for connecting to IRC servers","Εισάγετε το όνομα χρήστη, κωδικοποιήσεις, τις θύρες και τους κωδικούς πρόσβασης που θέλετε να χρησιμοποιήσετε για σύνδεση με IRC διακομιστή"}.
|
||||
{"Erlang Jabber Server","Erlang Jabber Διακομιστής"}.
|
||||
{"Error","Σφάλμα"}.
|
||||
{"Example: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}].","Παράδειγμα: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."}.
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","Εξαίρεση από τις ταυτότητες Jabber, ή CAPTCHA πρόκληση"}.
|
||||
{"Export data of all users in the server to PIEFXIS files (XEP-0227):","Εξαγωγή δεδομένων όλων των χρηστών του διακομιστή σε PIEFXIS αρχεία (XEP-0227):"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Εξαγωγή δεδομένων των χρηστών κεντρικού υπολογιστή σε PIEFXIS αρχεία (XEP-0227):"}.
|
||||
{"Failed to extract JID from your voice request approval","Απέτυχε η εξαγωγή JID από την έγκριση του αιτήματος φωνής σας"}.
|
||||
{"Family Name","Επώνυμο"}.
|
||||
{"February","Φεβρουάριος"}.
|
||||
{"Fill in fields to search for any matching Jabber User","Συμπληρώστε τα πεδία για να αναζητήσετε οποιαδήποτε ταιριάζοντα Jabber χρήστη"}.
|
||||
{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Συμπληρώστε τη φόρμα για να αναζητήσετε οποιαδήποτε Jabber χρήστη που ταιριάζει (Προσθέστε * στο τέλος τού πεδίου για να ταιριάξει σε μεγαλύτερες γραμματοσηρές)"}.
|
||||
{"Friday","Παρασκευή"}.
|
||||
{"From ~s","Από ~s"}.
|
||||
{"From","Από"}.
|
||||
{"Full Name","Ονοματεπώνυμο"}.
|
||||
{"Get Number of Online Users","Έκθεση αριθμού συνδεδεμένων χρηστών"}.
|
||||
{"Get Number of Registered Users","Έκθεση αριθμού εγγεγραμμένων χρηστών"}.
|
||||
{"Get User Last Login Time","Έκθεση Τελευταίας Ώρας Σύνδεσης Χρήστη"}.
|
||||
{"Get User Password","Έκθεση Κωδικού Πρόσβασης Χρήστη"}.
|
||||
{"Get User Statistics","Έκθεση Στατιστικών Χρήστη"}.
|
||||
{"Grant voice to this person?","Παραχώρηση φωνής σε αυτό το άτομο;"}.
|
||||
{"Groups","Ομάδες"}.
|
||||
{"Group ","Ομάδα"}.
|
||||
{"has been banned","έχει απαγορευθεί"}.
|
||||
{"has been kicked because of an affiliation change","Έχει αποβληθεί λόγω αλλαγής υπαγωγής"}.
|
||||
{"has been kicked because of a system shutdown","αποβλήθηκε λόγω τερματισμού συστήματος"}.
|
||||
{"has been kicked because the room has been changed to members-only","αποβλήθηκε επειδή η αίθουσα αλλάξε γιά μέλη μόνο"}.
|
||||
{"has been kicked","αποβλήθηκε "}.
|
||||
{" has set the subject to: "," έχει θέσει το θέμα σε: "}.
|
||||
{"Host","Κεντρικός Υπολογιστής"}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Εάν δεν βλέπετε την εικόνα CAPTCHA εδώ, επισκεφθείτε την ιστοσελίδα."}.
|
||||
{"If you want to specify different ports, passwords, encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\", port, \"password\"}'. By default this service use \"~s\" encoding, port ~p, empty password.","Εάν θέλετε να καθορίσετε διαφορετικές θύρες, κωδικούς πρόσβασης, κωδικοποιήσεις για IRC διακομιστές, εισάγετε πληροφορίες στη μορφή '{\"irc διακομιστής\", \"κωδικοποιήσεις\", θύρα, \"κωδικός πρόσβασης\"}'. Προεπιλεγμενα αυτή η υπηρεσία χρησιμοποιεί \"~s\" κωδικοποιήση, θύρα ~p, κενό κωδικό πρόσβασης."}.
|
||||
{"Import Directory","Εισαγωγή κατάλογου αρχείων"}.
|
||||
{"Import File","Εισαγωγή αρχείων"}.
|
||||
{"Import user data from jabberd14 spool file:","Εισαγωγή δεδομένων χρήστη από το αρχείο σειράς jabberd14:"}.
|
||||
{"Import User from File at ","Εισαγωγή χρηστών από αρχείο στο "}.
|
||||
{"Import users data from a PIEFXIS file (XEP-0227):","Εισαγωγή δεδομένων χρηστών από ένα αρχείο PIEFXIS (XEP-0227):"}.
|
||||
{"Import users data from jabberd14 spool directory:","Εισαγωγή δεδομένων χρηστών από κατάλογο αρχείων σειράς jabberd14:"}.
|
||||
{"Import Users from Dir at ","Εισαγωγή χρηστών από κατάλογο αρχείων στο "}.
|
||||
{"Import Users From jabberd14 Spool Files","Εισαγωγή Χρηστών από αρχεία σειράς jabberd14"}.
|
||||
{"Improper message type","Ακατάλληλο είδος μηνύματος"}.
|
||||
{"Incorrect password","Εσφαλμένος κωδικός πρόσβασης"}.
|
||||
{"Invalid affiliation: ~s","Άκυρη υπαγωγή: ~s"}.
|
||||
{"Invalid role: ~s","Άκυρος ρόλο: ~s"}.
|
||||
{"IP addresses","Διευθύνσεις IP"}.
|
||||
{"IP","IP"}.
|
||||
{"IRC channel (don't put the first #)","IRC κανάλι (μην τεθεί το πρώτο #)"}.
|
||||
{"IRC server","Διακομιστής IRC"}.
|
||||
{"IRC settings","IRC Ρυθμίσεις"}.
|
||||
{"IRC Transport","IRC Διαβιβάσεις"}.
|
||||
{"IRC username","IRC όνομα χρήστη"}.
|
||||
{"IRC Username","IRC Όνομα χρήστη"}.
|
||||
{"is now known as","είναι τώρα γνωστή ως"}.
|
||||
{"It is not allowed to send private messages of type \"groupchat\"","Δεν επιτρέπεται να στείλει προσωπικά μηνύματα του τύπου \"groupchat\""}.
|
||||
{"It is not allowed to send private messages to the conference","Δεν επιτρέπεται να στείλει προσωπικά μηνύματα για τη διάσκεψη"}.
|
||||
{"It is not allowed to send private messages","Δεν επιτρέπεται η αποστολή προσωπικών μηνυμάτων"}.
|
||||
{"Jabber Account Registration","Εγγραφή λογαριασμού Jabber"}.
|
||||
{"Jabber ID ~s is invalid","Η Jabber Ταυτότητα ~s είναι άκυρη"}.
|
||||
{"Jabber ID","Ταυτότητα Jabber"}.
|
||||
{"January","Ιανουάριος"}.
|
||||
{"Join IRC channel","Είσοδος στο IRC κανάλι"}.
|
||||
{"joins the room","συνδέετε στην αίθουσα"}.
|
||||
{"Join the IRC channel here.","Είσοδος στο κανάλι IRC εδώ."}.
|
||||
{"Join the IRC channel in this Jabber ID: ~s","Είσοδος στο κανάλι IRC αυτής της Jabber Ταυτότητας: ~s"}.
|
||||
{"July","Ιούλιος"}.
|
||||
{"June","Ιούνιος"}.
|
||||
{"Last Activity","Τελευταία Δραστηριότητα"}.
|
||||
{"Last login","Τελευταία σύνδεση"}.
|
||||
{"Last month","Περασμένο μήνα"}.
|
||||
{"Last year","Πέρυσι"}.
|
||||
{"leaves the room","εγκαταλείπει την αίθουσα"}.
|
||||
{"Listened Ports at ","Παρακολουθούμενες Θύρες στο "}.
|
||||
{"Listened Ports","Παρακολουθούμενες Θύρες"}.
|
||||
{"List of modules to start","Λίστα των Module για Εκκίνηση"}.
|
||||
{"Low level update script","Προγράμα ενημέρωσης χαμηλού επίπεδου "}.
|
||||
{"Make participants list public","Κάντε κοινό τον κατάλογο συμμετεχόντων"}.
|
||||
{"Make room CAPTCHA protected","Κάντε την αίθουσα CAPTCHA προστατεύονομενη"}.
|
||||
{"Make room members-only","Κάντε την αίθουσα μόνο για μέλη"}.
|
||||
{"Make room moderated","Κάντε την αίθουσα εποπτεύονομενη"}.
|
||||
{"Make room password protected","Κάντε την αίθουσα προστατεύομενη με κωδικό πρόσβασης"}.
|
||||
{"Make room persistent","Κάντε αίθουσα μόνιμη"}.
|
||||
{"Make room public searchable","Κάντε την δημόσια αναζήτηση δυνατή για αυτή την αίθουσα"}.
|
||||
{"March","Μάρτιος"}.
|
||||
{"Maximum Number of Occupants","Μέγιστος αριθμός συμετεχόντων"}.
|
||||
{"Max # of items to persist","Μέγιστος αριθμός μόνιμων στοιχείων"}.
|
||||
{"Max payload size in bytes","Μέγιστο μέγεθος φορτίου σε bytes"}.
|
||||
{"May","Μάιος"}.
|
||||
{"Membership is required to enter this room","Απαιτείται αίτηση συμετοχής για είσοδο σε αυτή την αίθουσα"}.
|
||||
{"Members:","Μέλη:"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In Jabber there isn't an automated way to recover your password if you forget it.","Απομνημονεύστε τον κωδικό πρόσβασής σας, ή γράψετε τον σε ένα χαρτί που είχε τοποθετηθεί σε ασφαλές μέρος. Στο Jabber δεν υπάρχει αυτοματοποιημένος τρόπος για να ανακτήσετε τον κωδικό σας αν τον ξεχάσετε."}.
|
||||
{"Memory","Μνήμη"}.
|
||||
{"Message body","Περιεχόμενο μηνυμάτως"}.
|
||||
{"Middle Name","Πατρώνυμο"}.
|
||||
{"Minimum interval between voice requests (in seconds)","Ελάχιστο χρονικό διάστημα μεταξύ αιτημάτων φωνής (σε δευτερόλεπτα)"}.
|
||||
{"Moderator privileges required","Aπαιτούνται προνόμια συντονιστή"}.
|
||||
{"moderators only","συντονιστές μόνο"}.
|
||||
{"Modified modules","Τροποποιημένα modules"}.
|
||||
{"Module","Module"}.
|
||||
{"Modules at ","Modules στο "}.
|
||||
{"Modules","Modules"}.
|
||||
{"Monday","Δευτέρα"}.
|
||||
{"Name:","Όνομα:"}.
|
||||
{"Name","Όνομα"}.
|
||||
{"Never","Ποτέ"}.
|
||||
{"New Password:","Νέος κωδικός πρόσβασης:"}.
|
||||
{"Nickname Registration at ","Εγγραφή με Ψευδώνυμο στο "}.
|
||||
{"Nickname ~s does not exist in the room","Ψευδώνυμο ~s δεν υπάρχει σε αυτή την αίθουσα"}.
|
||||
{"Nickname","Ψευδώνυμο"}.
|
||||
{"No body provided for announce message","Δεν προμηθεύτικε περιεχόμενο ανακοινώσης"}.
|
||||
{"nobody","κανείς"}.
|
||||
{"No Data","Κανένα στοιχείο"}.
|
||||
{"Node ID","Ταυτότητα Κόμβου"}.
|
||||
{"Node not found","Κόμβος δεν βρέθηκε"}.
|
||||
{"Nodes","Κόμβοι"}.
|
||||
{"Node ","Κόμβος"}.
|
||||
{"No limit","Χωρίς όριο"}.
|
||||
{"None","Κανένα"}.
|
||||
{"No resource provided","Δεν προμηθεύτικε πόρος"}.
|
||||
{"Not Found","Δεν Βρέθηκε"}.
|
||||
{"Notify subscribers when items are removed from the node","Ειδοποιηση στους συνδρομητές όταν αφαίρούντε στοιχεία από τον κόμβο"}.
|
||||
{"Notify subscribers when the node configuration changes","Ειδοποιηση στους συνδρομητές όταν αλλάζει η διαμόρφωση κόμβου"}.
|
||||
{"Notify subscribers when the node is deleted","Ειδοποιηση στους συνδρομητές όταν ο κόμβος διαγράφεται"}.
|
||||
{"November","Νοέμβριος"}.
|
||||
{"Number of occupants","Αριθμός συμετεχόντων"}.
|
||||
{"Number of online users","Αριθμός συνδεδεμένων χρηστών"}.
|
||||
{"Number of registered users","Αριθμός εγγεγραμμένων χρηστών"}.
|
||||
{"October","Οκτώβριος"}.
|
||||
{"Offline Messages:","Χωρίς Σύνδεση Μηνύματα:"}.
|
||||
{"Offline Messages","Χωρίς Σύνδεση Μηνύματα"}.
|
||||
{"OK","Όλλα Καλά"}.
|
||||
{"Old Password:","Παλαιός κωδικός πρόσβασης:"}.
|
||||
{"Online Users:","Online Χρήστες:"}.
|
||||
{"Online Users","Συνδεμένοι χρήστες"}.
|
||||
{"Online","Συνδεδεμένο"}.
|
||||
{"Only deliver notifications to available users","Παράδωση κοινοποιήσεων μόνο σε διαθέσιμους χρήστες"}.
|
||||
{"Only moderators and participants are allowed to change the subject in this room","Μόνο οι συντονιστές και οι συμμετέχοντες μπορούν να αλλάξουν το θέμα αυτής της αίθουσας"}.
|
||||
{"Only moderators are allowed to change the subject in this room","Μόνο οι συντονιστές μπορούν να αλλάξουν το θέμα αυτής της αίθουσας"}.
|
||||
{"Only moderators can approve voice requests","Μόνο οι συντονιστές μπορούν να εγκρίνουν τις αιτήσεις φωνής"}.
|
||||
{"Only occupants are allowed to send messages to the conference","Μόνο οι συμμετέχωντες μπορούν να στέλνουν μηνύματα στο συνέδριο"}.
|
||||
{"Only occupants are allowed to send queries to the conference","Μόνο οι συμετεχόντες μπορούν να στείλουν ερωτήματα στη διάσκεψη"}.
|
||||
{"Only service administrators are allowed to send service messages","Μόνο οι διαχειριστές των υπηρεσιών επιτρέπεται να στείλουν υπηρεσιακά μηνύματα"}.
|
||||
{"Options","Επιλογές"}.
|
||||
{"Organization Name","Όνομα Οργανισμού"}.
|
||||
{"Organization Unit","Μονάδα Οργανισμού"}.
|
||||
{"Outgoing s2s Connections:","Εξερχόμενες S2S Συνδέσεις:"}.
|
||||
{"Outgoing s2s Connections","Εξερχόμενες S2S Συνδέσεις"}.
|
||||
{"Outgoing s2s Servers:","Εξερχόμενοι S2S διακομιστές:"}.
|
||||
{"Owner privileges required","Aπαιτούνται προνόμια ιδιοκτήτη"}.
|
||||
{"Packet","Πακέτο"}.
|
||||
{"Password ~b","Κωδικός πρόσβασης ~b"}.
|
||||
{"Password Verification:","Επαλήθευση κωδικού πρόσβασης:"}.
|
||||
{"Password Verification","Επαλήθευση κωδικού πρόσβασης"}.
|
||||
{"Password","Κωδικός Πρόσβασης"}.
|
||||
{"Password:","Κωδικός πρόσβασης:"}.
|
||||
{"Path to Dir","Τοποθεσία κατάλογου αρχείων"}.
|
||||
{"Path to File","Τοποθεσία Αρχείου"}.
|
||||
{"Pending","Εκκρεμεί"}.
|
||||
{"Period: ","Περίοδος: "}.
|
||||
{"Persist items to storage","Μονιμη αποθήκευση στοιχείων"}.
|
||||
{"Ping","Πινγκ"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Παρακαλώ σημειώστε ότι οι επιλογές αυτές θα αποθήκευσουν Αντιγράφο Ασφαλείας μόνο της ενσωματωμένης βάσης δεδομένων Mnesia. Εάν χρησιμοποιείτε το module ODBC, θα πρέπει επίσης να κάνετε χωριστά Αντιγράφο Ασφαλείας της SQL βάση δεδομένων σας ."}.
|
||||
{"Please, wait for a while before sending new voice request","Παρακαλώ, περιμένετε για λίγο πριν την αποστολή νέου αιτήματος φωνής"}.
|
||||
{"Pong","Πονγκ"}.
|
||||
{"Port ~b","Θύρα ~b"}.
|
||||
{"Port","Θύρα"}.
|
||||
{"Present real Jabber IDs to","Παρούσιαση πραγματικών ταυτοτήτων Jabber σε"}.
|
||||
{"private, ","ιδιωτικό,"}.
|
||||
{"Protocol","Πρωτόκολλο"}.
|
||||
{"Publish-Subscribe","Δημοσίευση-Εγγραφή"}.
|
||||
{"PubSub subscriber request","Αίτηση συνδρομητή Δημοσίευσης-Εγγραφής"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Διαγραφή όλων των στοιχείων όταν ο σχετικός εκδότης αποσυνδέεται"}.
|
||||
{"Queries to the conference members are not allowed in this room","Ερωτήματα πρώς τα μέλη της διασκέψεως δεν επιτρέπονται σε αυτήν την αίθουσα"}.
|
||||
{"RAM and disc copy","Αντίγραφο μόνο σε RAM καί δίσκο"}.
|
||||
{"RAM copy","Αντίγραφο σε RAM"}.
|
||||
{"Raw","Ακατέργαστο"}.
|
||||
{"Really delete message of the day?","Πραγματικά να διαγράψετε το μήνυμα της ημέρας;"}.
|
||||
{"Recipient is not in the conference room","Παραλήπτης δεν είναι στην αίθουσα συνεδριάσεων"}.
|
||||
{"Register a Jabber account","Καταχωρήστε έναν λογαριασμό Jabber"}.
|
||||
{"Registered Users:","Εγγεγραμμένοι Χρήστες:"}.
|
||||
{"Registered Users","Εγγεγραμμένοι Χρήστες"}.
|
||||
{"Register","Καταχωρήστε"}.
|
||||
{"Registration in mod_irc for ","Εγγραφή στο mod_irc για "}.
|
||||
{"Remote copy","Απομεμακρυσμένο αντίγραφο"}.
|
||||
{"Remove All Offline Messages","Αφαίρεση Όλων των Χωρίς Σύνδεση Μηνύματων"}.
|
||||
{"Remove User","Αφαίρεση χρήστη"}.
|
||||
{"Remove","Αφαίρεστε"}.
|
||||
{"Replaced by new connection","Αντικαταστάθικε από νέα σύνδεση"}.
|
||||
{"Resources","Πόροι"}.
|
||||
{"Restart Service","Επανεκκίνηση Υπηρεσίας"}.
|
||||
{"Restart","Επανεκκίνηση"}.
|
||||
{"Restore Backup from File at ","Επαναφορά Αντιγράφου Ασφαλείας από αρχείο στο "}.
|
||||
{"Restore binary backup after next ejabberd restart (requires less memory):","Επαναφορά δυαδικού αντιγράφου ασφαλείας μετά την επόμενη επανεκκίνηση του ejabberd (απαιτεί λιγότερη μνήμη):"}.
|
||||
{"Restore binary backup immediately:","Επαναφορά δυαδικού αντιγράφου ασφαλείας αμέσως:"}.
|
||||
{"Restore plain text backup immediately:","Επαναφορά αντιγράφου ασφαλείας από αρχείο κειμένου αμέσως:"}.
|
||||
{"Restore","Επαναφορά Αντιγράφου Ασφαλείας"}.
|
||||
{"Room Configuration","Διαμόρφωση Αίθουσας σύνεδριασης"}.
|
||||
{"Room creation is denied by service policy","Άρνηση δημιουργίας αίθουσας , λόγω τακτικής παροχής υπηρεσιών"}.
|
||||
{"Room description","Περιγραφή Αίθουσας"}.
|
||||
{"Room Occupants","Συμετεχόντες Αίθουσας σύνεδριασης"}.
|
||||
{"Room title","Τίτλος Αίθουσας "}.
|
||||
{"Roster groups allowed to subscribe","Ομάδες Καταλόγου Επαφών μπορούν να εγγραφούν"}.
|
||||
{"Roster of ","Καταλόγος Επαφών τού"}.
|
||||
{"Roster size","Μέγεθος Καταλόγου Επαφών"}.
|
||||
{"Roster","Καταλόγος Επαφών"}.
|
||||
{"RPC Call Error","Σφάλμα RPC Κλήσης"}.
|
||||
{"Running Nodes","Ενεργοί Κόμβοι"}.
|
||||
{"~s access rule configuration","~s διαμόρφωση κανόνα πρόσβασης"}.
|
||||
{"Saturday","Σάββατο"}.
|
||||
{"Script check","Script ελέγχου"}.
|
||||
{"Search Results for ","Αποτελέσματα αναζήτησης για "}.
|
||||
{"Search users in ","Αναζήτηση χρηστών στο"}.
|
||||
{"Send announcement to all online users on all hosts","Αποστολή ανακοίνωσης σε όλους τους συνδεδεμένους χρήστες σε όλους τους κεντρικούς υπολογιστές"}.
|
||||
{"Send announcement to all online users","Αποστολή ανακοίνωσης σε όλους τους συνδεδεμένους χρήστες"}.
|
||||
{"Send announcement to all users on all hosts","Αποστολή ανακοίνωσης σε όλους τους χρήστες σε όλους τους κεντρικούς υπολογιστές"}.
|
||||
{"Send announcement to all users","Αποστολή ανακοίνωσης σε όλους τους χρήστες"}.
|
||||
{"September","Σεπτέμβριος"}.
|
||||
{"Server ~b","Διακομιστής ~b"}.
|
||||
{"Server:","Διακομιστής:"}.
|
||||
{"Set message of the day and send to online users","Ορίστε μήνυμα ημέρας και αποστολή στους συνδεδεμένους χρήστες"}.
|
||||
{"Set message of the day on all hosts and send to online users","Ορίστε μήνυμα ημέρας και άμεση αποστολή στους συνδεδεμένους χρήστες σε όλους τους κεντρικούς υπολογιστές"}.
|
||||
{"Shared Roster Groups","Κοινές Ομάδες Καταλόγων Επαφών"}.
|
||||
{"Show Integral Table","Δείτε Ολοκληρωτικό Πίνακα"}.
|
||||
{"Show Ordinary Table","Δείτε Κοινό Πίνακα"}.
|
||||
{"Shut Down Service","Κλείσιμο Υπηρεσίας"}.
|
||||
{"~s invites you to the room ~s","~s σας προσκαλεί στην αίθουσα ~s"}.
|
||||
{"Some Jabber clients can store your password in your computer. Use that feature only if you trust your computer is safe.","Μερικοί πελάτες Jabber μπορεί να αποθηκεύσουν τον κωδικό πρόσβασής σας στον υπολογιστή σας. Χρησιμοποιήστε αυτό το χαρακτηριστικό μόνο εάν εμπιστεύεστε την ασφάλεια του υπολογιστή σας."}.
|
||||
{"Specify the access model","Καθορίστε το μοντέλο πρόσβασης"}.
|
||||
{"Specify the event message type","Καθορίστε τον τύπο μηνύματος συμβάντος"}.
|
||||
{"Specify the publisher model","Καθορίστε το μοντέλο εκδότη"}.
|
||||
{"~s's Offline Messages Queue","Η Σειρά Χωρίς Σύνδεση Μηνύματων τού ~s"}.
|
||||
{"Start Modules at ","Εκκίνηση Modules στο "}.
|
||||
{"Start Modules","Εκκίνηση Modules"}.
|
||||
{"Start","Εκκίνηση"}.
|
||||
{"Statistics of ~p","Στατιστικές του ~p"}.
|
||||
{"Statistics","Στατιστικές"}.
|
||||
{"Stop Modules at ","Παύση Modules στο "}.
|
||||
{"Stop Modules","ΠαύσηModules"}.
|
||||
{"Stopped Nodes","Σταματημένοι Κόμβοι"}.
|
||||
{"Stop","Σταμάτημα"}.
|
||||
{"Storage Type","Τύπος Αποθήκευσης"}.
|
||||
{"Store binary backup:","Αποθηκεύση δυαδικού αντιγράφου ασφαλείας:"}.
|
||||
{"Store plain text backup:","Αποθηκεύση αντιγράφου ασφαλείας σε αρχείο κειμένου:"}.
|
||||
{"Subject","Θέμα"}.
|
||||
{"Submitted","Υποβλήθηκε"}.
|
||||
{"Submit","Υποβοβολή"}.
|
||||
{"Subscriber Address","Διεύθυνση Συνδρομητή"}.
|
||||
{"Subscription","Συνδρομή"}.
|
||||
{"Sunday","Κυριακή"}.
|
||||
{"That nickname is already in use by another occupant","Αυτό το ψευδώνυμο είναι ήδη σε χρήση από άλλον συμμετέχων"}.
|
||||
{"That nickname is registered by another person","Αυτό το ψευδώνυμο είναι καταχωρημένο από άλλο πρόσωπο"}.
|
||||
{"The CAPTCHA is valid.","Το CAPTCHA είναι έγκυρο."}.
|
||||
{"The CAPTCHA verification has failed","Η επαλήθευση της εικόνας CAPTCHA απέτυχε"}.
|
||||
{"The collections with which a node is affiliated","Οι συλλογές με την οποία είναι ένας κόμβος συνδέεται"}.
|
||||
{"The password is too weak","Ο κωδικός πρόσβασης είναι πολύ ασθενές"}.
|
||||
{"the password is","ο κωδικός πρόσβασης είναι"}.
|
||||
{"The password of your Jabber account was successfully changed.","Ο κωδικός πρόσβασης του Jabber λογαριασμού σας έχει αλλάξει επιτυχώς."}.
|
||||
{"There was an error changing the password: ","Υπήρξε ένα σφάλμα κατά την αλλαγή του κωδικού πρόσβασης:"}.
|
||||
{"There was an error creating the account: ","Υπήρξε ένα σφάλμα κατά τη δημιουργία του λογαριασμού:"}.
|
||||
{"There was an error deleting the account: ","Υπήρξε ένα σφάλμα κατά τη διαγραφή του λογαριασμού:"}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Ανεξαρτήτως με πεζά ή κεφαλαία: 'μιαλεξη' είναι το ίδιο με 'ΜιαΛέξη' και 'Μιαλέξη'."}.
|
||||
{"This page allows to create a Jabber account in this Jabber server. Your JID (Jabber IDentifier) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Αυτή η σελίδα σας επιτρέπει να δημιουργήσετε ένα λογαριασμό Jabber σε αυτόν το διακομιστή Jabber. JID σας (Jabber Identifier) θα είναι της μορφής: όνομα_χρήστη@διακομιστής_Jabber. Παρακαλώ διαβάστε προσεκτικά τις οδηγίες για να συμπληρώσετε σωστά τα πεδία."}.
|
||||
{"This page allows to unregister a Jabber account in this Jabber server.","Η σελίδα αυτή δίνει τη δυνατότητα να καταργήσετε την καταχώρηση ενός λογαριασμό Jabber σε αυτόν το διακομιστή Jabber."}.
|
||||
{"This participant is kicked from the room because he sent an error message to another participant","Αυτός ο συμμετέχων αποβλήθηκε από την αίθουσα, επειδή έστειλε ένα μήνυμα σφάλματος σε άλλον συμμετέχων"}.
|
||||
{"This participant is kicked from the room because he sent an error message","Αυτός ο συμμετέχων αποβλήθηκε από την αίθουσα, επειδή έστειλε ένα μήνυμα σφάλματος"}.
|
||||
{"This participant is kicked from the room because he sent an error presence","Αυτός ο συμμετέχων αποβλήθηκε από την αίθουσα, επειδή έστειλε σφάλμα παρουσίας "}.
|
||||
{"This room is not anonymous","Η αίθουσα αυτή δεν είναι ανώνυμη"}.
|
||||
{"Thursday","Πέμπτη"}.
|
||||
{"Time delay","Χρόνος καθυστέρησης"}.
|
||||
{"Time","Χρόνος"}.
|
||||
{"Too many CAPTCHA requests","Πάρα πολλά αιτήματα CAPTCHA"}.
|
||||
{"To ~s","Πρώς ~s"}.
|
||||
{"To","Πρώς"}.
|
||||
{"Traffic rate limit is exceeded","Υπέρφορτωση"}.
|
||||
{"Transactions Aborted:","Αποτυχημένες συναλλαγές:"}.
|
||||
{"Transactions Committed:","Παραδοθείς συναλλαγές:"}.
|
||||
{"Transactions Logged:","Καταγραμμένες συναλλαγές:"}.
|
||||
{"Transactions Restarted:","Επανειλημμένες συναλλαγές:"}.
|
||||
{"Tuesday","Τρίτη"}.
|
||||
{"Unable to generate a CAPTCHA","Αδήνατο να δημιουργηθεί CAPTCHA"}.
|
||||
{"Unauthorized","Χορίς Εξουσιοδότηση"}.
|
||||
{"Unregister a Jabber account","Καταργήστε την εγγραφή ενός λογαριασμού Jabber"}.
|
||||
{"Unregister","Καταργήση εγγραφής"}.
|
||||
{"Update message of the day (don't send)","Ενημέρωση μηνύματως ημέρας (χωρίς άμεση αποστολή)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Ενημέρωση μηνύματως ημέρας σε όλους τους κεντρικούς υπολογιστές (χωρίς άμεση αποστολή)"}.
|
||||
{"Update plan","Σχέδιο ενημέρωσης"}.
|
||||
{"Update script","Προγράμα ενημέρωσης"}.
|
||||
{"Update ","Ενημέρωση"}.
|
||||
{"Update","Ενημέρωση"}.
|
||||
{"Uptime:","Uptime:"}.
|
||||
{"Use of STARTTLS required","Απαιτείται χρήση STARTTLS "}.
|
||||
{"User JID","JID Χρήστη"}.
|
||||
{"User Management","Διαχείριση χρηστών"}.
|
||||
{"Username:","Όνομα χρήστη"}.
|
||||
{"Users are not allowed to register accounts so quickly","Οι χρήστες δεν επιτρέπεται να εγγραφούν λογαριασμούς τόσο γρήγορα"}.
|
||||
{"Users Last Activity","Τελευταία Δραστηριότητα Χρήστη"}.
|
||||
{"Users","Χρήστες"}.
|
||||
{"User ","Χρήστης"}.
|
||||
{"User","Χρήστης"}.
|
||||
{"Validate","Επαληθεύστε"}.
|
||||
{"vCard User Search","vCard Αναζήτηση χρηστών"}.
|
||||
{"Virtual Hosts","εικονικοί κεντρικοί υπολογιστές"}.
|
||||
{"Visitors are not allowed to change their nicknames in this room","Οι επισκέπτες δεν επιτρέπεται να αλλάξουν τα ψευδώνυμα τους σε αυτή την αίθουσα"}.
|
||||
{"Visitors are not allowed to send messages to all occupants","Οι επισκέπτες δεν επιτρέπεται να στείλουν μηνύματα σε όλους τους συμμετέχωντες"}.
|
||||
{"Voice requests are disabled in this conference","Τα αιτήματα φωνής είναι απενεργοποιημένα, σε αυτό το συνέδριο"}.
|
||||
{"Voice request","Αίτημα φωνής"}.
|
||||
{"Wednesday","Τετάρτη"}.
|
||||
{"When to send the last published item","Πότε να αποσταλθεί το τελευταίο στοιχείο που δημοσιεύθηκε"}.
|
||||
{"Whether to allow subscriptions","Εάν επιτρέποντε συνδρομές"}.
|
||||
{"You can later change your password using a Jabber client.","Μπορείτε αργότερα να αλλάξετε τον κωδικό πρόσβασής σας χρησιμοποιώντας έναν πελάτη Jabber."}.
|
||||
{"You have been banned from this room","Σας έχει απαγορευθεί η είσοδος σε αυτή την αίθουσα"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Θα πρέπει να συμπληρώσετε το πεδίο \"Ψευδώνυμο\" στη φόρμα"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","Χρειάζεστε ένα x:data και CAPTCHA ικανό πελάτη για εγγραφή"}.
|
||||
{"You need a client that supports x:data to register the nickname","Χρειάζεστε ένα x:data ικανό πελάτη για εγγραφή με ψευδώνυμο"}.
|
||||
{"You need an x:data capable client to configure mod_irc settings","Χρειάζεστε ένα x:data ικανό πελάτη για να ρυθμίσετε το mod_irc"}.
|
||||
{"You need an x:data capable client to configure room","Χρειάζεστε ένα x:data ικανό πελάτη για να ρυθμίσετε την αίθουσα "}.
|
||||
{"You need an x:data capable client to search","Χρειάζεστε ένα x:data ικανό πελάτη για αναζήτηση"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","Ο ενεργός κατάλογος απορρήτου, έχει αρνηθεί τη δρομολόγηση αυτής της στροφής (stanza)."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","Η μνήμη χωρίς σύνδεση μήνυματών είναι πλήρης. Το μήνυμα έχει απορριφθεί."}.
|
||||
{"Your Jabber account was successfully created.","Ο Jabber λογαριασμός σας δημιουργήθηκε με επιτυχία."}.
|
||||
{"Your Jabber account was successfully deleted.","Ο Jabber λογαριασμός σας διαγράφηκε με επιτυχία."}.
|
||||
{"Your messages to ~s are being blocked. To unblock them, visit ~s","Τα μηνύματά σας πρως ~s είναι αποκλεισμένα. Για αποδεσμεύση, επισκεφθείτε ~s"}.
|
||||
+1889
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user