Compare commits
	
		
			1103 Commits
		
	
	
		
			1.1.8
			...
			slix-1.5.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | c7bd224182 | ||
|   | bac1e9b44a | ||
|   | b62f0e90c1 | ||
|   | 9ace053992 | ||
|   | c7cd2fcf33 | ||
|   | e57289358f | ||
|   | 4aa35c11ab | ||
|   | d6f7d32bbe | ||
|   | 0dd32be7f5 | ||
|   | bf69698af1 | ||
|   | aa732b3c94 | ||
|   | d076cef023 | ||
|   | f884b67b8b | ||
|   | 0d3116dbdf | ||
|   | f1ab9ab964 | ||
|   | e520ab1f5e | ||
|   | 3dcb96d9d8 | ||
|   | 0a7a4c3abe | ||
|   | a4bbc404ed | ||
|   | c3fbc6cb80 | ||
|   | 355d789061 | ||
|   | 47ed67c04e | ||
|   | 34567f450a | ||
|   | 9126bd8392 | ||
|   | 02202f7cd8 | ||
|   | 2add94f5b0 | ||
|   | 5fc757f200 | ||
|   | 98108d0445 | ||
|   | 76f4fb49d6 | ||
|   | 5be46a5e68 | ||
|   | ab9040c30e | ||
|   | a16e2a0f6c | ||
|   | 842aa3be8f | ||
|   | 6c28b49e7f | ||
|   | 621255027d | ||
|   | efe316dc8c | ||
|   | e9a87a0b77 | ||
|   | 85c9967b9c | ||
|   | deb6d4f176 | ||
|   | 7218bb4499 | ||
|   | d85efec7a2 | ||
|   | 115c234527 | ||
|   | a0f5cb6e09 | ||
|   | 110bbf8afc | ||
|   | d97efa0bd8 | ||
|   | 672f1b28f6 | ||
|   | 27d3ae958b | ||
|   | a32794ec35 | ||
|   | aa11ba463e | ||
|   | a83c00e933 | ||
|   | 31f6ef6814 | ||
|   | 9b3874b5df | ||
|   | 0139fb291e | ||
|   | e58988484a | ||
|   | 5d5e5cda19 | ||
|   | 11f707987d | ||
|   | db13794e0f | ||
|   | 37bc1bb9b3 | ||
|   | 9be30e5291 | ||
|   | 9fe20a4056 | ||
|   | 3253d34c0a | ||
|   | fef575ee1a | ||
|   | 540ff89427 | ||
|   | dd8ac8fc87 | ||
|   | 2249d878d1 | ||
|   | 89fa9dc1dd | ||
|   | d7729e8683 | ||
|   | d618f55dea | ||
|   | b0e688eb35 | ||
|   | 0e7176483b | ||
|   | f35569a2c1 | ||
|   | bec6f7c8f3 | ||
|   | 027ce2434d | ||
|   | d57fbb57a2 | ||
|   | 85cd7a9166 | ||
|   | d50d996c68 | ||
|   | 371ad20ca7 | ||
|   | 5f49df6b56 | ||
|   | b50bfb2f34 | ||
|   | b29bb30eb7 | ||
|   | 4435c81d77 | ||
|   | 2638ba2744 | ||
|   | dbc9758311 | ||
|   | 47968963b1 | ||
|   | 4e8800f954 | ||
|   | 40053518aa | ||
|   | 1ee0f72ead | ||
|   | 4bb81228ae | ||
|   | 60a7a5b8df | ||
|   | 946674f424 | ||
|   | 412a9169bd | ||
|   | 72b355de8c | ||
|   | af246dcfe1 | ||
|   | 9612e518fb | ||
|   | fde8264191 | ||
|   | 1cdc656208 | ||
|   | 0042108a67 | ||
|   | 704161a285 | ||
|   | 6b1b58a339 | ||
|   | 4f96e5fa75 | ||
|   | bcb90a653e | ||
|   | 7e435b703d | ||
|   | 2dda6b80d4 | ||
|   | 5629e44710 | ||
|   | 6a06881d8b | ||
|   | 2b666eb1de | ||
|   | 400e7a3903 | ||
|   | fbab3ad214 | ||
|   | 628b357b06 | ||
|   | 88260cc240 | ||
|   | e9f2f503b8 | ||
|   | 696a72247b | ||
|   | 05d76e4b1d | ||
|   | d52d4fbbbe | ||
|   | e53c0fcb30 | ||
|   | 97d68c5196 | ||
|   | b42fafabb4 | ||
|   | 3a44ec8f15 | ||
|   | 93f385562f | ||
|   | 9cab02438b | ||
|   | 74ed50e626 | ||
|   | 9d378c611c | ||
|   | d85d8f4479 | ||
|   | fb75f7cda9 | ||
|   | 41419a2161 | ||
|   | 7cd73b594e | ||
|   | 15c6b775ff | ||
|   | 4b482477e2 | ||
|   | f7e4caadfe | ||
|   | 5f25b0b6a0 | ||
|   | d228bc42ea | ||
|   | ecdc44a601 | ||
|   | 33370e42f1 | ||
|   | 4699861925 | ||
|   | 2d228bdb56 | ||
|   | 570e653ac2 | ||
|   | 282a481059 | ||
|   | f386db380b | ||
|   | 7b87d98fff | ||
|   | 8779d40602 | ||
|   | f0b21c42d5 | ||
|   | e241d4e3c7 | ||
|   | bd22a41a78 | ||
|   | a29a29227a | ||
|   | d4d542b741 | ||
|   | dc4936a6d3 | ||
|   | 897610d819 | ||
|   | d33366badd | ||
|   | 809c500002 | ||
|   | dda4e18b81 | ||
|   | 8c09d932c8 | ||
|   | 31f5e84671 | ||
|   | ad0dc33df9 | ||
|   | 7c3b3827b4 | ||
|   | 9f6fa65139 | ||
|   | 35fa33e3c2 | ||
|   | 86a2f280d2 | ||
|   | 490f15b8fc | ||
|   | 62661ee04f | ||
|   | 37d1f2a6b0 | ||
|   | 20107ad516 | ||
|   | 7738a01311 | ||
|   | a9abed6151 | ||
|   | 0f690d4005 | ||
|   | 59d4420739 | ||
|   | a88f317bbf | ||
|   | 2fc2a88970 | ||
|   | c55e9279ac | ||
|   | 3502480384 | ||
|   | caae713dd6 | ||
|   | df0198abfe | ||
|   | c20f4bf5fa | ||
|   | 9740e93aeb | ||
|   | e7872aaa29 | ||
|   | 037706552c | ||
|   | b881c6729b | ||
|   | 66909aafb3 | ||
|   | cdfb5d56fc | ||
|   | d146ce9fb6 | ||
|   | cb59d60034 | ||
|   | 1d9fe3553e | ||
|   | fe66c022ad | ||
|   | 92ea131721 | ||
|   | dd7f67d10d | ||
|   | c1562b76b2 | ||
|   | 32839f5252 | ||
|   | 80b7cf6ff8 | ||
|   | 128cc2eeb4 | ||
|   | 037912ee89 | ||
|   | 769bc6d3bf | ||
|   | 084d6cb5d9 | ||
|   | 5184713356 | ||
|   | 2f1225bad3 | ||
|   | 841f5a5a5b | ||
|   | 0c6de5e972 | ||
|   | 81dc61c55c | ||
|   | bd63b1ce70 | ||
|   | 29faf114a7 | ||
|   | 94ea8151d4 | ||
|   | 66500ef5fb | ||
|   | 979396bb1e | ||
|   | e177726387 | ||
|   | 20e88fda50 | ||
|   | f252be9b6d | ||
|   | ee98159586 | ||
|   | c6443af29a | ||
|   | d73f56a7af | ||
|   | 7c7f4308c5 | ||
|   | eab8c265f4 | ||
|   | 80b9cd43b1 | ||
|   | af1f9e08ad | ||
|   | e3fd0af9c8 | ||
|   | 27e23672c1 | ||
|   | b38e229359 | ||
|   | 9a563f1425 | ||
|   | 8b6f5953a7 | ||
|   | 2d2a80c73d | ||
|   | 4dfdd5d8e3 | ||
|   | 1994ed3025 | ||
|   | aaa45846d3 | ||
|   | d7ffcb54eb | ||
|   | c33749e57a | ||
|   | e4107d8b4d | ||
|   | da5cb72d3a | ||
|   | c372bd5168 | ||
|   | cabf623131 | ||
|   | ffc240d5b6 | ||
|   | cc4522d9cd | ||
|   | 5bf69dca76 | ||
|   | 59dad12820 | ||
|   | 007c836296 | ||
|   | 3721bf9f6b | ||
|   | 802949eba8 | ||
|   | 24f35e433f | ||
|   | 22664ee7b8 | ||
|   | 6476cfcde5 | ||
|   | 5bb347e884 | ||
|   | eb1251b919 | ||
|   | 820144c40c | ||
|   | 6034df0a78 | ||
|   | df4012e66d | ||
|   | c372f3071a | ||
|   | 829c8b27b6 | ||
|   | fb3ac78bf9 | ||
|   | ffd9436e5c | ||
|   | bbb1344d79 | ||
|   | 457785b286 | ||
|   | 4847f834bd | ||
|   | 53191ff1cf | ||
|   | ffdb6ffd69 | ||
|   | 7560db856b | ||
|   | 63d245ac48 | ||
|   | 7ddd37be29 | ||
|   | a4d3a4a25e | ||
|   | 58bd07628b | ||
|   | 3569038493 | ||
|   | 20c4ff823a | ||
|   | 8a7448a5a1 | ||
|   | d23d8f901e | ||
|   | 391f12eeab | ||
|   | d008988843 | ||
|   | dcacc7d7d5 | ||
|   | c4285961df | ||
|   | 1038f656eb | ||
|   | 8b06aa1146 | ||
|   | 3c7236fe73 | ||
|   | 36824379c3 | ||
|   | a0a37c19ff | ||
|   | 1b5fe57a5e | ||
|   | 5da31db0c7 | ||
|   | f8cea760b6 | ||
|   | 5ef01ecdd1 | ||
|   | 62aafe0ee7 | ||
|   | cf3f36ac52 | ||
|   | b88d2ecd77 | ||
|   | e691850a2b | ||
|   | d4bff8dee6 | ||
|   | 187c350805 | ||
|   | 96d1c26f90 | ||
|   | 46a90749f8 | ||
|   | 0c63a4bbda | ||
|   | e4696e0471 | ||
|   | 8217dc5239 | ||
|   | 2586abc0d3 | ||
|   | 28f84ab3d9 | ||
|   | 813b45aded | ||
|   | 3a9b45e4f2 | ||
|   | b8e091233e | ||
|   | 0edeefd977 | ||
|   | 6ba53cf1ff | ||
|   | d7758eb7f4 | ||
|   | 125336aeee | ||
|   | 7cd1cf32ae | ||
|   | d099e353a4 | ||
|   | 1e4a301c6e | ||
|   | f53b12d227 | ||
|   | e2562dcccf | ||
|   | 7b69ae3738 | ||
|   | ab6df235d7 | ||
|   | 52cd8f4b22 | ||
|   | e28318c271 | ||
|   | 39ee833c29 | ||
|   | 9019e2bc71 | ||
|   | 9208bf5bf1 | ||
|   | f0f1698e46 | ||
|   | eccd7f1c98 | ||
|   | 2587d82af8 | ||
|   | 7ea121b115 | ||
|   | bb81fbbdfc | ||
|   | 1a00a08b7d | ||
|   | 90ea2a3411 | ||
|   | 8fc6814b6d | ||
|   | ffced0ed9a | ||
|   | e7248d9af9 | ||
|   | 6b1a04f59d | ||
|   | 4905407092 | ||
|   | bd6ec10939 | ||
|   | e15e6735f1 | ||
|   | 67afd6a462 | ||
|   | 2e2b97c53b | ||
|   | a35df7fe1f | ||
|   | fbc8562779 | ||
|   | b549db959a | ||
|   | d5188ac68a | ||
|   | ada9444bf8 | ||
|   | acc52fd935 | ||
|   | 1100ff1feb | ||
|   | c17fc3a869 | ||
|   | 4dba697075 | ||
|   | e42d651d7e | ||
|   | 4305eddb4f | ||
|   | c2dc44cfd1 | ||
|   | 5fc14de32e | ||
|   | d245558fd5 | ||
|   | 9d45370e8a | ||
|   | cc1cc61d36 | ||
|   | c6740a4908 | ||
|   | 55114bcffe | ||
|   | 4fa5dedc47 | ||
|   | 5525ef2285 | ||
|   | a7ac969215 | ||
|   | 329cb5a9f8 | ||
|   | d9b47b33f5 | ||
|   | 3582ac9941 | ||
|   | 2a127a57a7 | ||
|   | 7059400020 | ||
|   | 0b14ef82d4 | ||
|   | 83953af53d | ||
|   | 110cf25c6d | ||
|   | f2bf6072ec | ||
|   | 5f9abe2e0e | ||
|   | ea65b672e7 | ||
|   | 93c705fb31 | ||
|   | 0724f623bb | ||
|   | 82e549c0e9 | ||
|   | 1aa15792b4 | ||
|   | ffb2b6bc04 | ||
|   | 27f98bf22c | ||
|   | 3978078710 | ||
|   | 00a0698720 | ||
|   | 4a24f58be2 | ||
|   | da14ce16ec | ||
|   | 18e5abb9dd | ||
|   | 1a75b76916 | ||
|   | 53b56899a0 | ||
|   | 804b23d390 | ||
|   | 04eaf52b1d | ||
|   | dc7fef1064 | ||
|   | 488c433555 | ||
|   | 9c5dd024b1 | ||
|   | 6e61adf3db | ||
|   | 041bd63864 | ||
|   | a366482551 | ||
|   | a721084f6e | ||
|   | 1b4187fa56 | ||
|   | cf7a60705e | ||
|   | 349b05b9b7 | ||
|   | 9fbacf377a | ||
|   | 2da9e35cbc | ||
|   | 8adc8fa2ba | ||
|   | 9efa909dfc | ||
|   | 7f21fdbe26 | ||
|   | f9c7fa92ea | ||
|   | e75a160d52 | ||
|   | 170bd51387 | ||
|   | abcec1e2d3 | ||
|   | eeab646bfa | ||
|   | 2c69144189 | ||
|   | f54ebec654 | ||
|   | 2ce931cb7a | ||
|   | 84eddd2ed2 | ||
|   | 2042e1a4d5 | ||
|   | be14f0cc52 | ||
|   | edd9199be8 | ||
|   | bb094cc649 | ||
|   | dbaa6ed952 | ||
|   | 8c94d894ab | ||
|   | ffc7eac4dc | ||
|   | 555fd6d926 | ||
|   | c024ac8f0b | ||
|   | f00177c0cf | ||
|   | d0ad25745a | ||
|   | 55be23a6da | ||
|   | 75ba283572 | ||
|   | f7164d35d2 | ||
|   | 4afbb0322b | ||
|   | 7bce1ecc8a | ||
|   | bbce16d526 | ||
|   | c29fc39ef1 | ||
|   | 8335c08782 | ||
|   | 224d7ae133 | ||
|   | 04bff00171 | ||
|   | f3e31baf04 | ||
|   | 9b25a7cf77 | ||
|   | 7a908ac07b | ||
|   | 92901637ec | ||
|   | 3590b663ed | ||
|   | a33bde9cc3 | ||
|   | ac50fdccfc | ||
|   | a0c6bf15e9 | ||
|   | a2852eb249 | ||
|   | f1e6d6b0a9 | ||
|   | 116a33ba51 | ||
|   | a8ac115310 | ||
|   | 1345b7c1d0 | ||
|   | d60a652259 | ||
|   | 61a7cecb31 | ||
|   | 192b7e0349 | ||
|   | 80b60fc048 | ||
|   | b8d7b9520c | ||
|   | 0305ce66b7 | ||
|   | 474405ab90 | ||
|   | 4415d3be1a | ||
|   | 058c530787 | ||
|   | 766d0dfd40 | ||
|   | ac31913a65 | ||
|   | d34ddf33db | ||
|   | eb4e09b0ca | ||
|   | ce085bf4f4 | ||
|   | 990113f8e7 | ||
|   | aa022204ee | ||
|   | c1f23b566b | ||
|   | 45f7cb8bda | ||
|   | bdb1f66ac9 | ||
|   | 842157a6cc | ||
|   | a63cc01482 | ||
|   | 1bbb6f3ff9 | ||
|   | 93894247a4 | ||
|   | 16bb5e2537 | ||
|   | d19a6e05b2 | ||
|   | 86e85f9835 | ||
|   | cc145d20b0 | ||
|   | 881d9040c4 | ||
|   | 1e77ea0944 | ||
|   | 140f0885b2 | ||
|   | 83f71a6610 | ||
|   | 271343a32d | ||
|   | 48857b0030 | ||
|   | 1fe7f5f4e6 | ||
|   | d5b1904ebb | ||
|   | b6b0e82dec | ||
|   | 632b7b4afe | ||
|   | 81b7b2c190 | ||
|   | 460de7d301 | ||
|   | 69022c6db7 | ||
|   | 0ef3fa2703 | ||
|   | 8da269de88 | ||
|   | 93ce318259 | ||
|   | 997928de91 | ||
|   | 83d00a5913 | ||
|   | bf5d7c83af | ||
|   | c66a4d4097 | ||
|   | e112e86475 | ||
|   | e034b31d6b | ||
|   | 18a4978456 | ||
|   | 17464b10a4 | ||
|   | 6fb3ecd414 | ||
|   | c214e4f037 | ||
|   | 2ee05d9616 | ||
|   | f795ac02e3 | ||
|   | 6e8235544c | ||
|   | 6e35948276 | ||
|   | 4da870fd19 | ||
|   | cd7ff685fb | ||
|   | 1e4944d47e | ||
|   | e68135f59f | ||
|   | 6408c5a747 | ||
|   | 115fe954ac | ||
|   | 3d243f7da5 | ||
|   | ea5615f236 | ||
|   | 69da1c1d7c | ||
|   | e85fa4203e | ||
|   | 506ca69917 | ||
|   | 8ac0ecdf40 | ||
|   | dbd8115557 | ||
|   | 74b4ea20bf | ||
|   | 11fbaa4241 | ||
|   | 8fd0d7c993 | ||
|   | 1450d36377 | ||
|   | 06358d0665 | ||
|   | 2b3b86e281 | ||
|   | 92e4bc752a | ||
|   | ffb2e05f21 | ||
|   | 1e2665df19 | ||
|   | 4d063e287e | ||
|   | 44f02fb3ab | ||
|   | f6b3a0c6cf | ||
|   | 8b36e918e8 | ||
|   | 9044807121 | ||
|   | 24264d3a07 | ||
|   | 8bc70264ef | ||
|   | 957c635fb7 | ||
|   | 4027927c6e | ||
|   | c16b862200 | ||
|   | a96f608469 | ||
|   | e1f25604ec | ||
|   | 0fe057b5c3 | ||
|   | be76dda21d | ||
|   | ecd124dd06 | ||
|   | 4a8951c4ee | ||
|   | 8afba7de85 | ||
|   | 1ce42d3a2f | ||
|   | 2f4d811db4 | ||
|   | 61127f521d | ||
|   | 62eefdbd6a | ||
|   | 225e07eb64 | ||
|   | 1207c81ab5 | ||
|   | 565da65ccd | ||
|   | 47fbd4cead | ||
|   | 1b9b4199e8 | ||
|   | b5930ca958 | ||
|   | 063e73c0d2 | ||
|   | 423974f90d | ||
|   | d261318e1a | ||
|   | d33cc00fe9 | ||
|   | 5fcf08a415 | ||
|   | 3c06568ed5 | ||
|   | 27582f6fd2 | ||
|   | e328ff4833 | ||
|   | 68e35e631a | ||
|   | ad8c76602b | ||
|   | b5c98ba99e | ||
|   | 711f8dc6af | ||
|   | 5b41fb98de | ||
|   | 6da625dbdb | ||
|   | e862c47b8b | ||
|   | 4a8fe56470 | ||
|   | 7c3e61950d | ||
|   | 61f89eef2e | ||
|   | 06de587ed2 | ||
|   | 49beb3ac08 | ||
|   | 403462fdb8 | ||
|   | f22d8e67b4 | ||
|   | e1c944d723 | ||
|   | 83442b9849 | ||
|   | edd6ffeb01 | ||
|   | 5a8881000c | ||
|   | 70839368c1 | ||
|   | 9d8a2a1a7a | ||
|   | 17174016ec | ||
|   | ed37174a2b | ||
|   | 8660148960 | ||
|   | 67ca2dd0f4 | ||
|   | 882f984b26 | ||
|   | 6175cbcd99 | ||
|   | 476d76a533 | ||
|   | df68bb4896 | ||
|   | 815e647c97 | ||
|   | ad70ffba59 | ||
|   | 0e95015410 | ||
|   | 35f33f1614 | ||
|   | c9f8ddff65 | ||
|   | f5ae98aaf1 | ||
|   | b92dac72f3 | ||
|   | 073e85381a | ||
|   | afc939708f | ||
|   | aabec8b993 | ||
|   | e5e2fbb16b | ||
|   | 3dd379cdf1 | ||
|   | a20582aba4 | ||
|   | 09cdbf1b76 | ||
|   | ca306e7cec | ||
|   | 1bf34f7fe6 | ||
|   | 4144d60017 | ||
|   | 7265682a4d | ||
|   | 08c62a6bf1 | ||
|   | d61f1cd035 | ||
|   | 1063feb33b | ||
|   | 79f3c1ac8f | ||
|   | cdb9a6ff7e | ||
|   | a59148dfeb | ||
|   | a5c03b763a | ||
|   | 3670d82f1c | ||
|   | 07e46837d9 | ||
|   | fa21e262c7 | ||
|   | 93934c7992 | ||
|   | 73edd42774 | ||
|   | ab03ad54aa | ||
|   | 2e571ac950 | ||
|   | 6c15d65107 | ||
|   | e5af0597a6 | ||
|   | 74117453b5 | ||
|   | 5611b30022 | ||
|   | ede9dcd18f | ||
|   | d3b56a5d94 | ||
|   | f5d4334963 | ||
|   | 5c769632e8 | ||
|   | 373505f483 | ||
|   | a2cad40f91 | ||
|   | 4328762076 | ||
|   | c2f6f07776 | ||
|   | 5ab77c7452 | ||
|   | e94a73553d | ||
|   | 577fd71472 | ||
|   | e5582694c0 | ||
|   | 768136e493 | ||
|   | 753cb3580e | ||
|   | 60b050b82a | ||
|   | ad91a8cd5e | ||
|   | 02f79fc94b | ||
|   | 230a73fad2 | ||
|   | d94dd486fe | ||
|   | 6ecc39b816 | ||
|   | 9c240df9db | ||
|   | a918bf3a95 | ||
|   | 9434ae267f | ||
|   | 94187d215a | ||
|   | ef2f5d2978 | ||
|   | 62671e0f56 | ||
|   | 93869f77a0 | ||
|   | 8282d135cc | ||
|   | 9acc78c81d | ||
|   | 3642469630 | ||
|   | 34cd20339c | ||
|   | 7548f44047 | ||
|   | 7cf55ef695 | ||
|   | 543250da13 | ||
|   | 69e55d7316 | ||
|   | 158411e918 | ||
|   | 3f873002c4 | ||
|   | 818f4e5973 | ||
|   | c8d6e512d2 | ||
|   | a2423b8499 | ||
|   | 49acdac776 | ||
|   | 7e1587faa2 | ||
|   | 84a6ed8e80 | ||
|   | 654420e351 | ||
|   | 651915f31c | ||
|   | d9db1b84fe | ||
|   | bd03f071c6 | ||
|   | eb6ac68d5c | ||
|   | 848e6ebd83 | ||
|   | f76524fc9f | ||
|   | b95532b68b | ||
|   | d002d4c06f | ||
|   | 7c03cc622c | ||
|   | cebfd84416 | ||
|   | 12995e280e | ||
|   | 4ae6d44efc | ||
|   | 01e1878900 | ||
|   | df9ad82336 | ||
|   | c183fd5e35 | ||
|   | 820d07f309 | ||
|   | f4e3c04bbf | ||
|   | 540d6e9dbb | ||
|   | 79a3a2befd | ||
|   | 08a0fd5420 | ||
|   | 92d6bc6875 | ||
|   | fb5d20c4f8 | ||
|   | 65e3122f52 | ||
|   | be874e3c70 | ||
|   | beae845281 | ||
|   | 6f64dac262 | ||
|   | cd2d25cf87 | ||
|   | b8b2f37e7b | ||
|   | 00152358de | ||
|   | a2784be4d6 | ||
|   | ad7a57103d | ||
|   | 19b24b276d | ||
|   | 23750357e2 | ||
|   | 07284f380f | ||
|   | e60401278f | ||
|   | 24c474a9ec | ||
|   | 8fd3781ef5 | ||
|   | c85f2494a8 | ||
|   | 6c2fa7a382 | ||
|   | 45689fd879 | ||
|   | 45a2cfb01b | ||
|   | c4bb6c900c | ||
|   | f7c042fc77 | ||
|   | b20dc9fe2b | ||
|   | a030e05993 | ||
|   | 648b03f811 | ||
|   | e57e321d33 | ||
|   | b6e53c7b1b | ||
|   | 1c3bfd949b | ||
|   | 6401c9aaaa | ||
|   | c02adbb8e1 | ||
|   | 88e64dbfae | ||
|   | afd48b9e08 | ||
|   | db0ab9a0b3 | ||
|   | 556e4bd74d | ||
|   | d439c4f215 | ||
|   | a9f2e1482c | ||
|   | 2c26fb0d76 | ||
|   | 18dde97c8c | ||
|   | 85bc6f5301 | ||
|   | 8f364b9a95 | ||
|   | ee6c5632ac | ||
|   | cc81a0e8da | ||
|   | 262652992d | ||
|   | eb63825dfd | ||
|   | c49017c6f1 | ||
|   | 7d08bd3142 | ||
|   | f12c241dca | ||
|   | cedc9dd175 | ||
|   | 669e708b70 | ||
|   | e76a483931 | ||
|   | c0437d2de8 | ||
|   | 37a8043202 | ||
|   | f4c69d4045 | ||
|   | a3606d9e4d | ||
|   | 805f1c0e39 | ||
|   | 7430a8ca40 | ||
|   | 1776e2edcc | ||
|   | baf9aaf26c | ||
|   | 4864b07e13 | ||
|   | 13c919773e | ||
|   | ed3a4fb8d4 | ||
|   | df3e826d0a | ||
|   | a9e7d489b8 | ||
|   | da6b549f8b | ||
|   | 76e07a9089 | ||
|   | 4a590d1497 | ||
|   | 82e1508d6f | ||
|   | 400f08db9d | ||
|   | e48b650caa | ||
|   | d9f595283a | ||
|   | 85fd14f47f | ||
|   | b7adaafb3e | ||
|   | d0bba87cdd | ||
|   | 2cc75d4bbd | ||
|   | 24bd591faa | ||
|   | 2e9ccd0623 | ||
|   | 7b49c82210 | ||
|   | d3284f1604 | ||
|   | 3279697128 | ||
|   | 60cfab995f | ||
|   | 8ec18bdb2c | ||
|   | 3c3cd65235 | ||
|   | 7ac75de19d | ||
|   | fae39e1ab4 | ||
|   | 3732139fc3 | ||
|   | 0a2737dc77 | ||
|   | 481971928c | ||
|   | 020197718f | ||
|   | a0c77c04a5 | ||
|   | 620ee9719f | ||
|   | c0d02d9935 | ||
|   | 01356d23e5 | ||
|   | 8b73c2bcff | ||
|   | 5a771dbe2f | ||
|   | 9ba5b644cf | ||
|   | f76f0c3787 | ||
|   | 01abd6a705 | ||
|   | 44e2b5d945 | ||
|   | 82bbe5d1a6 | ||
|   | a1d71d31e8 | ||
|   | 766e0b685d | ||
|   | 58f5e4702b | ||
|   | d9906756cf | ||
|   | 9a45ebd98b | ||
|   | 7f9ff9d0e7 | ||
|   | 8c763fcf43 | ||
|   | 6dd4456b11 | ||
|   | c30c47d291 | ||
|   | d8c9662302 | ||
|   | ec5e819b16 | ||
|   | 55e50ad979 | ||
|   | 99ecb166d3 | ||
|   | cdeae7e72f | ||
|   | fbf79755d7 | ||
|   | 78bd21b7cf | ||
|   | 88c7c29954 | ||
|   | d4dde89ea6 | ||
|   | 774bf35fab | ||
|   | 1a2db7fb11 | ||
|   | da3223ac92 | ||
|   | b0fed5a48d | ||
|   | 43132dab85 | ||
|   | badd327360 | ||
|   | 9a6bfc6614 | ||
|   | 79914fb56b | ||
|   | 75a792eb6f | ||
|   | 23f112602c | ||
|   | 639a3aa832 | ||
|   | 79a8c5ceae | ||
|   | 97a2f4449d | ||
|   | 7f42d15175 | ||
|   | ef9c8e910c | ||
|   | a1b33da9ca | ||
|   | 1741059cf6 | ||
|   | 1f137735e1 | ||
|   | a186972f09 | ||
|   | 751628401e | ||
|   | 403b1802ec | ||
|   | 9165cbf7f6 | ||
|   | bad405bea9 | ||
|   | 4f9a95b011 | ||
|   | 903e641457 | ||
|   | f34b9399cc | ||
|   | 7d0d96f940 | ||
|   | 27196a21ae | ||
|   | ea0381fa09 | ||
|   | 3423589ba1 | ||
|   | 1f9286d39e | ||
|   | 93b8e66b5d | ||
|   | a1716de683 | ||
|   | ccf7916257 | ||
|   | d86adfa1b1 | ||
|   | 648f3f978a | ||
|   | 5e4b8bd67c | ||
|   | 64ef690432 | ||
|   | 41991b5982 | ||
|   | 01da222d67 | ||
|   | 518eee05c2 | ||
|   | 1dbfa29a1e | ||
|   | 6bac4741f6 | ||
|   | a0266dac6f | ||
|   | ce977a7809 | ||
|   | 8644a83ed9 | ||
|   | 7b45245b1d | ||
|   | f04f4e4a1a | ||
|   | b07f1b3bd3 | ||
|   | 0e7486d7b4 | ||
|   | 6c0afb87b9 | ||
|   | e5750b368e | ||
|   | ef76f923ad | ||
|   | 2c04ae084c | ||
|   | 91dc58d967 | ||
|   | 0e2abe74d5 | ||
|   | fea444925e | ||
|   | 0998429b07 | ||
|   | 597eb1779c | ||
|   | 9ae3a7dbff | ||
|   | 3519e845a3 | ||
|   | 29c049612a | ||
|   | ed48185732 | ||
|   | f431bbfca2 | ||
|   | 8b29900be4 | ||
|   | 6f8a4f8354 | ||
|   | def34f0e42 | ||
|   | e25a49f804 | ||
|   | b820351f64 | ||
|   | 0eb009496e | ||
|   | 2c2498b658 | ||
|   | a1d988fed5 | ||
|   | b0c50b7a59 | ||
|   | 1a2b404076 | ||
|   | 2d066c34fd | ||
|   | 7a1ed64985 | ||
|   | 1b449585f7 | ||
|   | 032d41dbb8 | ||
|   | 3a7569e3ea | ||
|   | d444930494 | ||
|   | 6045a6bfb3 | ||
|   | f3f543b31e | ||
|   | 0fea4262ea | ||
|   | ef1c4368d0 | ||
|   | 4b7ec4a32a | ||
|   | 2229ad8d8e | ||
|   | 61aff9f49a | ||
|   | 67235c4214 | ||
|   | 48def71d0c | ||
|   | a00eee1bbe | ||
|   | 12e8bb6ddc | ||
|   | c8c20fff71 | ||
|   | 75a18b5ffe | ||
|   | 06a690a259 | ||
|   | 52feabbe76 | ||
|   | 14c9e9a9cc | ||
|   | a22ca228cc | ||
|   | d0666a5eb6 | ||
|   | 931d49560a | ||
|   | 2a4e435228 | ||
|   | 3655827ef2 | ||
|   | c5046b9c91 | ||
|   | 4598031dd2 | ||
|   | 12e0e1a16b | ||
|   | 5e9266ba90 | ||
|   | 0d448b8221 | ||
|   | e6c95f0a2a | ||
|   | 63b58edda1 | ||
|   | af9632519c | ||
|   | d367fb938d | ||
|   | 77f2a339e1 | ||
|   | 4190027a78 | ||
|   | ef48a8c4d9 | ||
|   | 829b225053 | ||
|   | 747a6e94e6 | ||
|   | cebc798e72 | ||
|   | 7c485c6a8b | ||
|   | e2e8c4b5dc | ||
|   | 675c0112ac | ||
|   | 4dd2c15775 | ||
|   | 9f6decdbc1 | ||
|   | fc07e23ff8 | ||
|   | 4ea328b9f2 | ||
|   | 84a2fc382b | ||
|   | 098714b3c4 | ||
|   | cf2c94d974 | ||
|   | 657102e938 | ||
|   | 44e7585bf8 | ||
|   | 94488fa2ea | ||
|   | a2c60a4911 | ||
|   | ee9c4abd08 | ||
|   | b5b1c932c7 | ||
|   | b8f04983e1 | ||
|   | 90807dd973 | ||
|   | ef974114ea | ||
|   | f6e1fecdf8 | ||
|   | 94e8b2becf | ||
|   | a6ca6701a0 | ||
|   | c4edb9724b | ||
|   | b5c669bdff | ||
|   | e449dce65c | ||
|   | 73ce9a5ecc | ||
|   | 671f680bb3 | ||
|   | dfff19ffbf | ||
|   | a4abdf9fa6 | ||
|   | 6c57bb0553 | ||
|   | d385b9e708 | ||
|   | c2ae1ee891 | ||
|   | 67147570e9 | ||
|   | fb3e6b7e35 | ||
|   | cf28d4586d | ||
|   | f65eb5eeea | ||
|   | 26fa9bd87e | ||
|   | 0016d9a638 | ||
|   | a88b9737ff | ||
|   | df9ac58d05 | ||
|   | 357406d801 | ||
|   | 19a78f63f4 | ||
|   | c7ec6a72cd | ||
|   | e68b07dbce | ||
|   | e20610ab80 | ||
|   | 1ca0c46333 | ||
|   | e510875f64 | ||
|   | f52a10b061 | ||
|   | 7d382a2bfd | ||
|   | 09bec1c4fe | ||
|   | ff28b0a005 | ||
|   | 8a03bd72ae | ||
|   | a249f8736a | ||
|   | f0e1fc5aad | ||
|   | f09adf0014 | ||
|   | c6ac64ed2d | ||
|   | 04dc68f5f6 | ||
|   | 92be051450 | ||
|   | 5c25208fb5 | ||
|   | 779c258e27 | ||
|   | 962dfad216 | ||
|   | f7a710e55b | ||
|   | 814a50e36f | ||
|   | 230465b946 | ||
|   | d11a67702e | ||
|   | 4e12e228cb | ||
|   | 4a94aeba49 | ||
|   | 14aa831169 | ||
|   | 295d23ccf3 | ||
|   | 75d904ed01 | ||
|   | aebcf6ff82 | ||
|   | 8c2ece3bca | ||
|   | 80a90a6221 | ||
|   | f81d5e4bd6 | ||
|   | 2324c90232 | ||
|   | 2f65fdbc76 | ||
|   | 59ff08174f | ||
|   | 2f4149c7d0 | ||
|   | b84e359770 | ||
|   | fb4275648c | ||
|   | 475ccfa8dc | ||
|   | 267c24c8ef | ||
|   | 06a9d9fc30 | ||
|   | 1383ca19b5 | ||
|   | 4c3ff2abab | ||
|   | 7c6ef18e4f | ||
|   | f8856467d5 | ||
|   | 3bd84b8d27 | ||
|   | bc8b5774ac | ||
|   | 8009b0485e | ||
|   | 8742a56b3e | ||
|   | a792bcdafe | ||
|   | 167d1ce97b | ||
|   | 695cd95657 | ||
|   | 44ce01a70b | ||
|   | e4b4c67637 | ||
|   | 422e77ae40 | ||
|   | 5ae6c8f8fa | ||
|   | 54656b331a | ||
|   | 9047b627a4 | ||
|   | 6645a3be40 | ||
|   | c2189b4ecd | ||
|   | e3fab66dfb | ||
|   | 5867f08bf1 | ||
|   | a06fa2de67 | ||
|   | c9b2cf6043 | ||
|   | 35396d2977 | ||
|   | 3bff743d9f | ||
|   | 5a878f829b | ||
|   | 16ec0f151a | ||
|   | 26dc6e90ea | ||
|   | 94c749fd5a | ||
|   | 7b80ed0807 | ||
|   | 98b7e8b10a | ||
|   | c42f1ad4c7 | ||
|   | 9d8de7fc15 | ||
|   | 70883086b7 | ||
|   | 9a08dfc7d4 | ||
|   | 3e43b36a9d | ||
|   | 352ee2f2fd | ||
|   | 78aa5c3dfa | ||
|   | 613323b5fb | ||
|   | 6c4b01db8a | ||
|   | d06897a635 | ||
|   | 1600bb0aaf | ||
|   | b5c9c98a8b | ||
|   | e4e18a416f | ||
|   | 01cc0e6def | ||
|   | a3ec1af205 | ||
|   | d571d691a7 | ||
|   | ea3d39b50e | ||
|   | 2e580304f9 | ||
|   | fb221a8dc0 | ||
|   | 459e1ed345 | ||
|   | 6680c244f5 | ||
|   | 06423964ec | ||
|   | 5492e9028d | ||
|   | 474390fa00 | ||
|   | 81d3723084 | ||
|   | 32e798967e | ||
|   | 060c9ab679 | ||
|   | acd9c32a9f | ||
|   | b8581b0278 | ||
|   | 917faecdcb | ||
|   | 78f0325398 | ||
|   | f6edaa56a6 | ||
|   | 51fee28bf4 | ||
|   | e8a3e92ceb | ||
|   | 5df3839b7a | ||
|   | 8dcb441f44 | ||
|   | a347cf625a | ||
|   | 46f49c7a12 | ||
|   | 99701c947e | ||
|   | 1baae1b81e | ||
|   | 7d20f0e9a6 | ||
|   | fbad22a1cd | ||
|   | 5af2f62c04 | ||
|   | 4a4a03858e | ||
|   | 1efe049959 | ||
|   | 2393148908 | ||
|   | 6819b57353 | ||
|   | 88b5e60807 | ||
|   | c7594b3ef0 | ||
|   | b210870f48 | ||
|   | 5d6019a962 | ||
|   | eb5df1aa37 | ||
|   | 546066d677 | ||
|   | 3234596974 | ||
|   | 5820d49cd4 | ||
|   | 1ab66e5767 | ||
|   | aab2682f9a | ||
|   | 55d332bcc8 | ||
|   | f89df6e70c | ||
|   | 250d28e870 | ||
|   | 19f65c8510 | ||
|   | f70b49882f | ||
|   | a7b092a305 | ||
|   | daa73a3f3c | ||
|   | 0b51afe87a | ||
|   | 2b298766c9 | ||
|   | 10664d723b | ||
|   | c012208a8f | ||
|   | 0953896d2d | ||
|   | cf9e89d0ae | ||
|   | 48dd01b0bb | ||
|   | 7247efe055 | ||
|   | 8def3758e4 | ||
|   | 1851ab6f5f | ||
|   | 289b052338 | ||
|   | 26147f5ae0 | ||
|   | ae01f1071a | ||
|   | dcdf5dcd09 | ||
|   | c59a6d0f51 | ||
|   | 2cd936318d | ||
|   | 2f38857681 | ||
|   | 39505ae1ff | ||
|   | 44ee0633f2 | ||
|   | b52d2768b0 | ||
|   | cf24b870b1 | ||
|   | 69cffce7dc | ||
|   | a14979375b | ||
|   | 40ef4a16b1 | 
							
								
								
									
										13
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| ################ Please use Gitlab instead of Github ################################### | ||||
|  | ||||
| Hello, thank you for contributing to slixmpp! | ||||
|  | ||||
| You’re about to open a pull request on github. However this github repository is not the official place for contributions on slixmpp. | ||||
|  | ||||
| Please open your merge request on https://lab.louiz.org/poezio/slixmpp/ | ||||
|  | ||||
| You should be able to log in there with your github credentials, clone the slixmpp repository in your namespace, push your existing pull request into a new branch, and then open a merge request with one click, within 3 minutes. | ||||
|  | ||||
| This will help us review your contribution, avoid spreading things everywhere and it will even run the tests automatically with your changes. | ||||
|  | ||||
| Thank you. | ||||
							
								
								
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| *.pyc | ||||
| *.py[co] | ||||
| build/ | ||||
| dist/ | ||||
| MANIFEST | ||||
| @@ -6,4 +6,10 @@ docs/_build/ | ||||
| *.swp | ||||
| .tox/ | ||||
| .coverage | ||||
| sleekxmpp.egg-info/ | ||||
| slixmpp.egg-info/ | ||||
| .ropeproject/ | ||||
| 4913 | ||||
| *~ | ||||
| .baboon/ | ||||
| .DS_STORE | ||||
| .idea/ | ||||
|   | ||||
							
								
								
									
										21
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| stages: | ||||
|   - test | ||||
|   - trigger | ||||
|  | ||||
| test: | ||||
|   stage: test | ||||
|   tags: | ||||
|     - docker | ||||
|   image: ubuntu:latest | ||||
|   script: | ||||
|     - apt update | ||||
|     - apt install -y python3 cython3 gpg | ||||
|     - ./run_tests.py | ||||
|  | ||||
| trigger_poezio: | ||||
|   stage: trigger | ||||
|   tags: | ||||
|     - docker | ||||
|   image: appropriate/curl:latest | ||||
|   script: | ||||
|     - curl --request POST -F token="$SLIXMPP_TRIGGER_TOKEN" -F ref=master https://lab.louiz.org/api/v4/projects/18/trigger/pipeline | ||||
							
								
								
									
										7
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| language: python | ||||
| python: | ||||
|   - "3.7" | ||||
|   - "3.8-dev" | ||||
| install: | ||||
|   - "pip install ." | ||||
| script: testall.py | ||||
							
								
								
									
										14
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| Contributing to the Slixmpp project | ||||
| =================================== | ||||
|  | ||||
| To contribute, the preferred way is to commit your changes on some | ||||
| publicly-available git repository (on a fork `on github | ||||
| <https://github.com/poezio/slixmpp>`_ or on your own repository) and to | ||||
| notify the developers with either: | ||||
|  - a ticket `on the bug tracker <https://lab.louiz.org/poezio/slixmpp/issues/new>`_ | ||||
|  - a pull request on github | ||||
|  - a simple message on `the XMPP MUC <xmpp:slixmpp@muc.poez.io>`_ | ||||
|  | ||||
| Even though Slixmpp’s github repository is just a read-only mirror, we can | ||||
| still be notified of the pull requests and fetch your mirror manually to | ||||
| integrate your changes. | ||||
							
								
								
									
										6
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								INSTALL
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| Pre-requisites: | ||||
| - Python 3.1 or 2.6 | ||||
| - Python 3.7+ | ||||
| - Cython 0.22 and libidn, optionally (making JID faster by compiling the stringprep module) | ||||
| - GnuPG, for testing | ||||
|  | ||||
| Install: | ||||
| > python3 setup.py install | ||||
| @@ -9,4 +11,4 @@ Root install: | ||||
|  | ||||
| To test: | ||||
| > cd examples | ||||
| > python echo_client.py -v -j [USER@example.com] -p [PASSWORD] | ||||
| > python3 echo_client.py -d -j [USER@example.com] -p [PASSWORD] | ||||
|   | ||||
							
								
								
									
										6
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -69,8 +69,8 @@ modification, are permitted provided that the following conditions are met: | ||||
|     * Redistributions in binary form must reproduce the above copyright | ||||
|       notice, this list of conditions and the following disclaimer in the | ||||
|       documentation and/or other materials provided with the distribution. | ||||
|     * Neither the name of Red Innovation nor the names of its contributors  | ||||
|       may be used to endorse or promote products derived from this software  | ||||
|     * Neither the name of Red Innovation nor the names of its contributors | ||||
|       may be used to endorse or promote products derived from this software | ||||
|       without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY | ||||
| @@ -119,7 +119,7 @@ SUELTA – A PURE-PYTHON SASL CLIENT LIBRARY | ||||
|  | ||||
| This software is subject to "The MIT License" | ||||
|  | ||||
| Copyright 2007-2010 David Alan Cridland | ||||
| Copyright 2004-2013 David Alan Cridland | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| include README.rst | ||||
| include LICENSE | ||||
| include testall.py | ||||
| include run_tests.py | ||||
| include slixmpp/stringprep.pyx | ||||
| recursive-include docs Makefile *.bat *.py *.rst *.css *.ttf *.png | ||||
| recursive-include examples *.py | ||||
| recursive-include tests *.py | ||||
|   | ||||
							
								
								
									
										130
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								README.rst
									
									
									
									
									
								
							| @@ -1,78 +1,21 @@ | ||||
| SleekXMPP | ||||
| Slixmpp | ||||
| ######### | ||||
|  | ||||
| SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+, | ||||
| and is featured in examples in | ||||
| `XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_  | ||||
| by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived | ||||
| here from reading the Definitive Guide, please see the notes on updating | ||||
| the examples to the latest version of SleekXMPP. | ||||
| Slixmpp is an MIT licensed XMPP library for Python 3.7+. It is a fork of | ||||
| SleekXMPP. | ||||
|  | ||||
| SleekXMPP's design goals and philosphy are: | ||||
| Slixmpp's goals is to only rewrite the core of the library (the low level | ||||
| socket handling, the timers, the events dispatching) in order to remove all | ||||
| threads. | ||||
|  | ||||
| **Low number of dependencies** | ||||
|     Installing and using SleekXMPP should be as simple as possible, without | ||||
|     having to deal with long dependency chains. | ||||
| Building | ||||
| -------- | ||||
|  | ||||
|     As part of reducing the number of dependencies, some third party | ||||
|     modules are included with SleekXMPP in the ``thirdparty`` directory. | ||||
|     Imports from this module first try to import an existing installed | ||||
|     version before loading the packaged version, when possible. | ||||
| Slixmpp can make use of cython to improve performance on critical modules. | ||||
| To do that, **cython3** is necessary along with **libidn** headers. | ||||
| Otherwise, no compilation is needed. Building is done by running setup.py:: | ||||
|  | ||||
| **Every XEP as a plugin** | ||||
|     Following Python's "batteries included" approach, the goal is to | ||||
|     provide support for all currently active XEPs (final and draft). Since | ||||
|     adding XEP support is done through easy to create plugins, the hope is | ||||
|     to also provide a solid base for implementing and creating experimental | ||||
|     XEPs. | ||||
|  | ||||
| **Rewarding to work with** | ||||
|     As much as possible, SleekXMPP should allow things to "just work" using | ||||
|     sensible defaults and appropriate abstractions. XML can be ugly to work | ||||
|     with, but it doesn't have to be that way. | ||||
|  | ||||
|  | ||||
| Get the Code | ||||
| ------------ | ||||
|  | ||||
| Get the latest stable version from PyPI:: | ||||
|  | ||||
|     pip install sleekxmpp | ||||
|  | ||||
| The latest source code for SleekXMPP may be found on `Github | ||||
| <http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the | ||||
| ``master`` branch, while the latest development version is in the | ||||
| ``develop`` branch. | ||||
|  | ||||
| **Latest Release** | ||||
|     - `1.1.8 <http://github.com/fritzy/SleekXMPP/zipball/1.1.8>`_ | ||||
|  | ||||
| **Develop Releases** | ||||
|     - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_ | ||||
|  | ||||
| **Older Stable Releases** | ||||
|     - `1.0 <http://github.com/fritzy/SleekXMPP/zipball/1.0>`_ | ||||
|  | ||||
| Installing DNSPython | ||||
| --------------------- | ||||
| If you are using Python3 and wish to use dnspython, you will have to checkout and | ||||
| install the ``python3`` branch:: | ||||
|  | ||||
|     git clone http://github.com/rthalley/dnspython | ||||
|     cd dnspython | ||||
|     git checkout python3 | ||||
|     python3 setup.py install | ||||
|  | ||||
| Discussion | ||||
| ---------- | ||||
| A mailing list and XMPP chat room are available for discussing and getting | ||||
| help with SleekXMPP. | ||||
|  | ||||
| **Mailing List** | ||||
|     `SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|  | ||||
| **Chat** | ||||
|     `sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_ | ||||
|     python3 setup.py build_ext --inplace | ||||
|  | ||||
| Documentation and Testing | ||||
| ------------------------- | ||||
| @@ -84,22 +27,22 @@ be in ``docs/_build/html``:: | ||||
|     make html | ||||
|     open _build/html/index.html | ||||
|  | ||||
| To run the test suite for SleekXMPP:: | ||||
| To run the test suite for Slixmpp:: | ||||
|  | ||||
|     python testall.py | ||||
|     python run_tests.py | ||||
|  | ||||
|  | ||||
| The SleekXMPP Boilerplate | ||||
| The Slixmpp Boilerplate | ||||
| ------------------------- | ||||
| Projects using SleekXMPP tend to follow a basic pattern for setting up client/component | ||||
| connections and configuration. Here is the gist of the boilerplate needed for a SleekXMPP | ||||
| based project. See the documetation or examples directory for more detailed archetypes for | ||||
| SleekXMPP projects:: | ||||
| Projects using Slixmpp tend to follow a basic pattern for setting up client/component | ||||
| connections and configuration. Here is the gist of the boilerplate needed for a Slixmpp | ||||
| based project. See the documentation or examples directory for more detailed archetypes for | ||||
| Slixmpp projects:: | ||||
|  | ||||
|     import logging | ||||
|  | ||||
|     from sleekxmpp import ClientXMPP | ||||
|     from sleekxmpp.exceptions import IqError, IqTimeout | ||||
|     from slixmpp import ClientXMPP | ||||
|     from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
|  | ||||
|     class EchoBot(ClientXMPP): | ||||
| @@ -145,7 +88,7 @@ SleekXMPP projects:: | ||||
|  | ||||
|  | ||||
|     if __name__ == '__main__': | ||||
|         # Ideally use optparse or argparse to get JID,  | ||||
|         # Ideally use optparse or argparse to get JID, | ||||
|         # password, and log level. | ||||
|  | ||||
|         logging.basicConfig(level=logging.DEBUG, | ||||
| @@ -153,21 +96,38 @@ SleekXMPP projects:: | ||||
|  | ||||
|         xmpp = EchoBot('somejid@example.com', 'use_getpass') | ||||
|         xmpp.connect() | ||||
|         xmpp.process(block=True) | ||||
|         xmpp.process(forever=True) | ||||
|  | ||||
|  | ||||
| Credits | ||||
| ------- | ||||
| Slixmpp Credits | ||||
| --------------- | ||||
|  | ||||
| **Maintainers:** | ||||
|     - Florent Le Coz (`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_), | ||||
|     - Mathieu Pasquet (`mathieui@mathieui.net <xmpp:mathieui@mathieui.net?message>`_), | ||||
|  | ||||
| **Contributors:** | ||||
|     - Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_) | ||||
|     - Sam Whited (`Sam Whited <mailto:sam@samwhited.com>`_) | ||||
|     - Dan Sully (`Dan Sully <mailto:daniel@electricalrain.com>`_) | ||||
|     - Gasper Zejn (`Gasper Zejn <mailto:zejn@kiberpipa.org>`_) | ||||
|     - Krzysztof Kotlenga (`Krzysztof Kotlenga <mailto:pocek@users.sf.net>`_) | ||||
|     - Tsukasa Hiiragi (`Tsukasa Hiiragi <mailto:bakalolka@gmail.com>`_) | ||||
|     - Maxime Buquet (`pep <xmpp:pep@bouah.net?message>`_) | ||||
|  | ||||
| Credits (SleekXMPP) | ||||
| ------------------- | ||||
|  | ||||
| **Main Author:** Nathan Fritz | ||||
|     `fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,  | ||||
|     `fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_, | ||||
|     `@fritzy <http://twitter.com/fritzy>`_ | ||||
|  | ||||
|     Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP | ||||
|     <http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of  | ||||
|     <http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of | ||||
|     the XMPP Council. | ||||
|  | ||||
| **Co-Author:** Lance Stout | ||||
|     `lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,  | ||||
|     `lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_, | ||||
|     `@lancestout <http://twitter.com/lancestout>`_ | ||||
|  | ||||
| **Contributors:** | ||||
|   | ||||
| @@ -72,17 +72,17 @@ qthelp: | ||||
| 	@echo | ||||
| 	@echo "Build finished; now you can run "qcollectiongenerator" with the" \ | ||||
| 	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | ||||
| 	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SleekXMPP.qhcp" | ||||
| 	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Slixmpp.qhcp" | ||||
| 	@echo "To view the help file:" | ||||
| 	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SleekXMPP.qhc" | ||||
| 	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Slixmpp.qhc" | ||||
|  | ||||
| devhelp: | ||||
| 	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | ||||
| 	@echo | ||||
| 	@echo "Build finished." | ||||
| 	@echo "To view the help file:" | ||||
| 	@echo "# mkdir -p $$HOME/.local/share/devhelp/SleekXMPP" | ||||
| 	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SleekXMPP" | ||||
| 	@echo "# mkdir -p $$HOME/.local/share/devhelp/Slixmpp" | ||||
| 	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Slixmpp" | ||||
| 	@echo "# devhelp" | ||||
|  | ||||
| epub: | ||||
|   | ||||
							
								
								
									
										21
									
								
								docs/_static/haiku.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								docs/_static/haiku.css
									
									
									
									
										vendored
									
									
								
							| @@ -408,24 +408,3 @@ div.viewcode-block:target { | ||||
|     margin: -1px -12px; | ||||
|     padding: 0 12px; | ||||
| } | ||||
|  | ||||
| #from_andyet { | ||||
|     -webkit-box-shadow: #CCC 0px 0px 3px; | ||||
|     background: rgba(255, 255, 255, 1); | ||||
|     bottom: 0px; | ||||
|     right: 17px; | ||||
|     padding: 3px 10px; | ||||
|     position: fixed; | ||||
| } | ||||
|  | ||||
| #from_andyet h2 { | ||||
|     background-image: url("images/from_&yet.png"); | ||||
|     background-repeat: no-repeat; | ||||
|     height: 29px; | ||||
|     line-height: 0; | ||||
|     text-indent: -9999em; | ||||
|     width: 79px; | ||||
|     margin-top: 0; | ||||
|     margin: 0px; | ||||
|     padding: 0px; | ||||
| } | ||||
|   | ||||
							
								
								
									
										68
									
								
								docs/_static/nature.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										68
									
								
								docs/_static/nature.css
									
									
									
									
										vendored
									
									
								
							| @@ -8,11 +8,11 @@ | ||||
|  * :license: BSD, see LICENSE for details. | ||||
|  * | ||||
|  */ | ||||
|   | ||||
|  | ||||
| @import url("basic.css"); | ||||
|   | ||||
|  | ||||
| /* -- page layout ----------------------------------------------------------- */ | ||||
|   | ||||
|  | ||||
| body { | ||||
|     font-family: Arial, sans-serif; | ||||
|     font-size: 100%; | ||||
| @@ -34,18 +34,18 @@ div.bodywrapper { | ||||
| hr { | ||||
|     border: 1px solid #B1B4B6; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.document { | ||||
|     background-color: #eee; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.body { | ||||
|     background-color: #ffffff; | ||||
|     color: #3E4349; | ||||
|     padding: 0 30px 30px 30px; | ||||
|     font-size: 0.9em; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.footer { | ||||
|     color: #555; | ||||
|     width: 100%; | ||||
| @@ -53,12 +53,12 @@ div.footer { | ||||
|     text-align: center; | ||||
|     font-size: 75%; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.footer a { | ||||
|     color: #444; | ||||
|     text-decoration: underline; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.related { | ||||
|     background-color: #6BA81E; | ||||
|     line-height: 32px; | ||||
| @@ -66,11 +66,11 @@ div.related { | ||||
|     text-shadow: 0px 1px 0 #444; | ||||
|     font-size: 0.9em; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.related a { | ||||
|     color: #E2F3CC; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar { | ||||
|     font-size: 0.75em; | ||||
|     line-height: 1.5em; | ||||
| @@ -79,7 +79,7 @@ div.sphinxsidebar { | ||||
| div.sphinxsidebarwrapper{ | ||||
|     padding: 20px 0; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar h3, | ||||
| div.sphinxsidebar h4 { | ||||
|     font-family: Arial, sans-serif; | ||||
| @@ -95,30 +95,30 @@ div.sphinxsidebar h4 { | ||||
| div.sphinxsidebar h4{ | ||||
|     font-size: 1.1em; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar h3 a { | ||||
|     color: #444; | ||||
| } | ||||
|   | ||||
|   | ||||
|  | ||||
|  | ||||
| div.sphinxsidebar p { | ||||
|     color: #888; | ||||
|     padding: 5px 20px; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar p.topless { | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar ul { | ||||
|     margin: 10px 20px; | ||||
|     padding: 0; | ||||
|     color: #000; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar a { | ||||
|     color: #444; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.sphinxsidebar input { | ||||
|     border: 1px solid #ccc; | ||||
|     font-family: sans-serif; | ||||
| @@ -128,19 +128,19 @@ div.sphinxsidebar input { | ||||
| div.sphinxsidebar input[type=text]{ | ||||
|     margin-left: 20px; | ||||
| } | ||||
|   | ||||
|  | ||||
| /* -- body styles ----------------------------------------------------------- */ | ||||
|   | ||||
|  | ||||
| a { | ||||
|     color: #005B81; | ||||
|     text-decoration: none; | ||||
| } | ||||
|   | ||||
|  | ||||
| a:hover { | ||||
|     color: #E32E00; | ||||
|     text-decoration: underline; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.body h1, | ||||
| div.body h2, | ||||
| div.body h3, | ||||
| @@ -155,30 +155,30 @@ div.body h6 { | ||||
|     padding: 5px 0 5px 10px; | ||||
|     text-shadow: 0px 1px 0 white | ||||
| } | ||||
|   | ||||
|  | ||||
| div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } | ||||
| div.body h2 { font-size: 150%; background-color: #C8D5E3; } | ||||
| div.body h3 { font-size: 120%; background-color: #D8DEE3; } | ||||
| div.body h4 { font-size: 110%; background-color: #D8DEE3; } | ||||
| div.body h5 { font-size: 100%; background-color: #D8DEE3; } | ||||
| div.body h6 { font-size: 100%; background-color: #D8DEE3; } | ||||
|   | ||||
|  | ||||
| a.headerlink { | ||||
|     color: #c60f0f; | ||||
|     font-size: 0.8em; | ||||
|     padding: 0 4px 0 4px; | ||||
|     text-decoration: none; | ||||
| } | ||||
|   | ||||
|  | ||||
| a.headerlink:hover { | ||||
|     background-color: #c60f0f; | ||||
|     color: white; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.body p, div.body dd, div.body li { | ||||
|     line-height: 1.5em; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.admonition p.admonition-title + p { | ||||
|     display: inline; | ||||
| } | ||||
| @@ -191,29 +191,29 @@ div.note { | ||||
|     background-color: #eee; | ||||
|     border: 1px solid #ccc; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.seealso { | ||||
|     background-color: #ffc; | ||||
|     border: 1px solid #ff6; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.topic { | ||||
|     background-color: #eee; | ||||
| } | ||||
|   | ||||
|  | ||||
| div.warning { | ||||
|     background-color: #ffe4e4; | ||||
|     border: 1px solid #f66; | ||||
| } | ||||
|   | ||||
|  | ||||
| p.admonition-title { | ||||
|     display: inline; | ||||
| } | ||||
|   | ||||
|  | ||||
| p.admonition-title:after { | ||||
|     content: ":"; | ||||
| } | ||||
|   | ||||
|  | ||||
| pre { | ||||
|     padding: 10px; | ||||
|     background-color: White; | ||||
| @@ -225,7 +225,7 @@ pre { | ||||
|     -webkit-box-shadow: 1px 1px 1px #d8d8d8; | ||||
|     -moz-box-shadow: 1px 1px 1px #d8d8d8; | ||||
| } | ||||
|   | ||||
|  | ||||
| tt { | ||||
|     background-color: #ecf0f3; | ||||
|     color: #222; | ||||
|   | ||||
							
								
								
									
										2
									
								
								docs/_static/sphinxdoc.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								docs/_static/sphinxdoc.css
									
									
									
									
										vendored
									
									
								
							| @@ -134,7 +134,7 @@ div.footer a { | ||||
|  | ||||
| /* -- body styles ----------------------------------------------------------- */ | ||||
|  | ||||
| p {     | ||||
| p { | ||||
|     margin: 0.8em 0 0.5em 0; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								docs/_templates/layout.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								docs/_templates/layout.html
									
									
									
									
										vendored
									
									
								
							| @@ -65,6 +65,5 @@ | ||||
|       <div class="bottomnav"> | ||||
|       {{ nav() }} | ||||
|       </div> | ||||
|       <a id="from_andyet" href="http://andyet.net"><h2>From &yet</h2></a> | ||||
| {% endblock %} | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| BaseXMPP | ||||
| ======== | ||||
|  | ||||
| .. module:: sleekxmpp.basexmpp | ||||
| .. module:: slixmpp.basexmpp | ||||
|  | ||||
| .. autoclass:: BaseXMPP | ||||
|     :members: | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| ClientXMPP | ||||
| ========== | ||||
|  | ||||
| .. module:: sleekxmpp.clientxmpp | ||||
| .. module:: slixmpp.clientxmpp | ||||
|  | ||||
| .. autoclass:: ClientXMPP | ||||
|     :members: | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| ComponentXMPP | ||||
| ============= | ||||
|  | ||||
| .. module:: sleekxmpp.componentxmpp | ||||
| .. module:: slixmpp.componentxmpp | ||||
|  | ||||
| .. autoclass:: ComponentXMPP | ||||
|     :members: | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| Exceptions | ||||
| ========== | ||||
|  | ||||
| .. module:: sleekxmpp.exceptions | ||||
| .. module:: slixmpp.exceptions | ||||
|  | ||||
|  | ||||
|      | ||||
| .. autoexception:: XMPPError | ||||
|     :members: | ||||
|  | ||||
|   | ||||
							
								
								
									
										8
									
								
								docs/api/stanza/iq.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								docs/api/stanza/iq.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| IQ Stanza | ||||
| ========= | ||||
|  | ||||
| .. module:: slixmpp.stanza | ||||
|  | ||||
| .. autoclass:: Iq | ||||
|     :members: | ||||
|  | ||||
							
								
								
									
										7
									
								
								docs/api/stanza/message.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								docs/api/stanza/message.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| Message Stanza | ||||
| ============== | ||||
|  | ||||
| .. module:: slixmpp.stanza | ||||
|  | ||||
| .. autoclass:: Message | ||||
|     :members: | ||||
							
								
								
									
										8
									
								
								docs/api/stanza/presence.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								docs/api/stanza/presence.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| Presence Stanza | ||||
| =============== | ||||
|  | ||||
| .. module:: slixmpp.stanza | ||||
|  | ||||
| .. autoclass:: Presence | ||||
|     :members: | ||||
|  | ||||
							
								
								
									
										8
									
								
								docs/api/stanza/rootstanza.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								docs/api/stanza/rootstanza.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| Root Stanza | ||||
| =========== | ||||
|  | ||||
| .. module:: slixmpp.stanza.rootstanza | ||||
|  | ||||
| .. autoclass:: RootStanza | ||||
|     :members: | ||||
|  | ||||
| @@ -1,12 +0,0 @@ | ||||
| .. module:: sleekxmpp.xmlstream.filesocket | ||||
|  | ||||
| .. _filesocket: | ||||
|  | ||||
| Python 2.6 File Socket Shims | ||||
| ============================ | ||||
|  | ||||
| .. autoclass:: FileSocket | ||||
|     :members: | ||||
|  | ||||
| .. autoclass:: Socket26 | ||||
|     :members: | ||||
| @@ -3,22 +3,26 @@ Stanza Handlers | ||||
|  | ||||
| The Basic Handler | ||||
| ----------------- | ||||
| .. module:: sleekxmpp.xmlstream.handler.base | ||||
| .. module:: slixmpp.xmlstream.handler.base | ||||
|  | ||||
| .. autoclass:: BaseHandler | ||||
|     :members: | ||||
|  | ||||
| Callback | ||||
| -------- | ||||
| .. module:: sleekxmpp.xmlstream.handler.callback | ||||
| .. module:: slixmpp.xmlstream.handler | ||||
|  | ||||
| .. autoclass:: Callback | ||||
|     :members: | ||||
|  | ||||
| CoroutineCallback | ||||
| ----------------- | ||||
|  | ||||
| .. autoclass:: CoroutineCallback | ||||
|     :members: | ||||
|  | ||||
| Waiter | ||||
| ------ | ||||
| .. module:: sleekxmpp.xmlstream.handler.waiter | ||||
|  | ||||
| .. autoclass:: Waiter | ||||
|     :members: | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| Jabber IDs (JID) | ||||
| ================= | ||||
|  | ||||
| .. module:: sleekxmpp.xmlstream.jid | ||||
| .. module:: slixmpp.jid | ||||
|  | ||||
| .. autoclass:: JID | ||||
|     :members: | ||||
|   | ||||
| @@ -3,7 +3,7 @@ Stanza Matchers | ||||
|  | ||||
| The Basic Matcher | ||||
| ----------------- | ||||
| .. module:: sleekxmpp.xmlstream.matcher.base | ||||
| .. module:: slixmpp.xmlstream.matcher.base | ||||
|  | ||||
| .. autoclass:: MatcherBase | ||||
|     :members: | ||||
| @@ -11,7 +11,7 @@ The Basic Matcher | ||||
|  | ||||
| ID Matching | ||||
| ----------- | ||||
| .. module:: sleekxmpp.xmlstream.matcher.id | ||||
| .. module:: slixmpp.xmlstream.matcher.id | ||||
|  | ||||
| .. autoclass:: MatcherId | ||||
|     :members: | ||||
| @@ -19,7 +19,7 @@ ID Matching | ||||
|  | ||||
| Stanza Path Matching | ||||
| -------------------- | ||||
| .. module:: sleekxmpp.xmlstream.matcher.stanzapath | ||||
| .. module:: slixmpp.xmlstream.matcher.stanzapath | ||||
|  | ||||
| .. autoclass:: StanzaPath | ||||
|     :members: | ||||
| @@ -27,7 +27,7 @@ Stanza Path Matching | ||||
|  | ||||
| XPath | ||||
| ----- | ||||
| .. module:: sleekxmpp.xmlstream.matcher.xpath | ||||
| .. module:: slixmpp.xmlstream.matcher.xpath | ||||
|  | ||||
| .. autoclass:: MatchXPath | ||||
|     :members: | ||||
| @@ -35,7 +35,7 @@ XPath | ||||
|  | ||||
| XMLMask | ||||
| ------- | ||||
| .. module:: sleekxmpp.xmlstream.matcher.xmlmask | ||||
| .. module:: slixmpp.xmlstream.matcher.xmlmask | ||||
|  | ||||
| .. autoclass:: MatchXMLMask | ||||
|     :members: | ||||
|   | ||||
| @@ -1,11 +0,0 @@ | ||||
| ========= | ||||
| Scheduler | ||||
| ========= | ||||
|  | ||||
| .. module:: sleekxmpp.xmlstream.scheduler | ||||
|  | ||||
| .. autoclass:: Task | ||||
|     :members: | ||||
|  | ||||
| .. autoclass:: Scheduler | ||||
|     :members: | ||||
| @@ -4,9 +4,9 @@ | ||||
| Stanza Objects | ||||
| ============== | ||||
|  | ||||
| .. module:: sleekxmpp.xmlstream.stanzabase | ||||
| .. module:: slixmpp.xmlstream.stanzabase | ||||
|  | ||||
| The :mod:`~sleekmxpp.xmlstream.stanzabase` module provides a wrapper for the | ||||
| The :mod:`~slixmpp.xmlstream.stanzabase` module provides a wrapper for the | ||||
| standard :mod:`~xml.etree.ElementTree` module that makes working with XML | ||||
| less painful. Instead of having to manually move up and down an element | ||||
| tree and insert subelements and attributes, you can interact with an object | ||||
| @@ -52,17 +52,17 @@ elements of the original XML chunk. | ||||
| .. seealso:: | ||||
|     :ref:`create-stanza-interfaces`. | ||||
|  | ||||
| Because the :mod:`~sleekxmpp.xmlstream.stanzabase` module was developed | ||||
| Because the :mod:`~slixmpp.xmlstream.stanzabase` module was developed | ||||
| as part of an `XMPP <http://xmpp.org>`_ library, these chunks of XML are | ||||
| referred to as :term:`stanzas <stanza>`, and in SleekXMPP we refer to a | ||||
| referred to as :term:`stanzas <stanza>`, and in Slixmpp we refer to a | ||||
| subclass of :class:`ElementBase` which defines the interfaces needed for | ||||
| interacting with a given :term:`stanza` a :term:`stanza object`. | ||||
|  | ||||
| To make dealing with more complicated and nested :term:`stanzas <stanza>` | ||||
| or XML chunks easier, :term:`stanza objects <stanza object>` can be | ||||
| composed in two ways: as iterable child objects or as plugins. Iterable | ||||
| child stanzas, or :term:`substanzas`, are accessible through a special | ||||
| ``'substanzas'`` interface. This option is useful for stanzas which | ||||
| child stanzas, or :term:`substanzas <substanza>`, are accessible through a | ||||
| special ``'substanzas'`` interface. This option is useful for stanzas which | ||||
| may contain more than one of the same kind of element. When there is | ||||
| only one child element, the plugin method is more useful. For plugins, | ||||
| a parent stanza object delegates one of its XML child elements to the | ||||
| @@ -72,7 +72,7 @@ plugin stanza object. Here is an example: | ||||
|  | ||||
|     <iq type="result"> | ||||
|       <query xmlns="http://jabber.org/protocol/disco#info"> | ||||
|         <identity category="client" type="bot" name="SleekXMPP Bot" /> | ||||
|         <identity category="client" type="bot" name="Slixmpp Bot" /> | ||||
|       </query> | ||||
|     </iq> | ||||
|  | ||||
| @@ -84,13 +84,13 @@ we can access the plugin as so:: | ||||
|  | ||||
|     >>> iq['disco_info'] | ||||
|     '<query xmlns="http://jabber.org/protocol/disco#info"> | ||||
|       <identity category="client" type="bot" name="SleekXMPP Bot" /> | ||||
|       <identity category="client" type="bot" name="Slixmpp Bot" /> | ||||
|     </query>' | ||||
|  | ||||
| We can then drill down through the plugin object's interfaces as desired:: | ||||
|  | ||||
|     >>> iq['disco_info']['identities'] | ||||
|     [('client', 'bot', 'SleekXMPP Bot')] | ||||
|     [('client', 'bot', 'Slixmpp Bot')] | ||||
|  | ||||
| Plugins may also add new interfaces to the parent stanza object as if they | ||||
| had been defined by the parent directly, and can also override the behaviour | ||||
| @@ -101,7 +101,7 @@ of an interface defined by the parent. | ||||
|     - :ref:`create-stanza-plugins` | ||||
|     - :ref:`create-extension-plugins` | ||||
|     - :ref:`override-parent-interfaces` | ||||
|       | ||||
|  | ||||
|  | ||||
| Registering Stanza Plugins | ||||
| -------------------------- | ||||
|   | ||||
| @@ -1,19 +1,19 @@ | ||||
| .. module:: sleekxmpp.xmlstream.tostring | ||||
| .. module:: slixmpp.xmlstream.tostring | ||||
|  | ||||
| .. _tostring: | ||||
|  | ||||
| XML Serialization | ||||
| ================= | ||||
|  | ||||
| Since the XML layer of SleekXMPP is based on :mod:`~xml.etree.ElementTree`, | ||||
| Since the XML layer of Slixmpp is based on :mod:`~xml.etree.ElementTree`, | ||||
| why not just use the built-in :func:`~xml.etree.ElementTree.tostring` | ||||
| method? The answer is that using that method produces ugly results when | ||||
| using namespaces. The :func:`tostring()` method used here intelligently | ||||
| hides namespaces when able and does not introduce excessive namespace | ||||
| prefixes:: | ||||
|  | ||||
|     >>> from sleekxmpp.xmlstream.tostring import tostring | ||||
|     >>> from xml.etree import cElementTree as ET | ||||
|     >>> from slixmpp.xmlstream.tostring import tostring | ||||
|     >>> from xml.etree import ElementTree as ET | ||||
|     >>> xml = ET.fromstring('<foo xmlns="bar"><baz /></foo>') | ||||
|     >>> ET.tostring(xml) | ||||
|     '<ns0:foo xmlns:ns0="bar"><ns0:baz /></foo>' | ||||
| @@ -25,10 +25,10 @@ produce unexpected results depending on how the :func:`tostring()` method | ||||
| is invoked. For example, when sending XML on the wire, the main XMPP | ||||
| stanzas with their namespace of ``jabber:client`` will not include the | ||||
| namespace because that is already declared by the stream header. But, if | ||||
| you create a :class:`~sleekxmpp.stanza.message.Message` instance and dump | ||||
| you create a :class:`~slixmpp.stanza.message.Message` instance and dump | ||||
| it to the terminal, the ``jabber:client`` namespace will appear. | ||||
|  | ||||
| .. autofunction:: tostring | ||||
| .. autofunction:: slixmpp.xmlstream.tostring | ||||
|  | ||||
| Escaping Special Characters | ||||
| --------------------------- | ||||
| @@ -43,4 +43,5 @@ In the future, the use of CDATA sections may be allowed to reduce the | ||||
| size of escaped text or for when other XMPP processing agents do not | ||||
| undertand these entities. | ||||
|  | ||||
| .. autofunction:: xml_escape | ||||
| .. | ||||
|     autofunction:: xml_escape | ||||
|   | ||||
| @@ -2,9 +2,7 @@ | ||||
| XML Stream | ||||
| ========== | ||||
|  | ||||
| .. module:: sleekxmpp.xmlstream.xmlstream | ||||
|  | ||||
| .. autoexception:: RestartStream | ||||
| .. module:: slixmpp.xmlstream.xmlstream | ||||
|  | ||||
| .. autoclass:: XMLStream | ||||
|     :members: | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| .. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP | ||||
|  | ||||
| SleekXMPP Architecture | ||||
| Slixmpp Architecture | ||||
| ====================== | ||||
|  | ||||
| The core of SleekXMPP is contained in four classes: ``XMLStream``, | ||||
| The core of Slixmpp is contained in four classes: ``XMLStream``, | ||||
| ``BaseXMPP``, ``ClientXMPP``, and ``ComponentXMPP``. Along side this | ||||
| stack is a library for working with XML objects that eliminates most | ||||
| of the tedium of creating/manipulating XML. | ||||
| @@ -17,28 +17,27 @@ of the tedium of creating/manipulating XML. | ||||
|  | ||||
| The Foundation: XMLStream | ||||
| ------------------------- | ||||
| :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic | ||||
| :class:`~slixmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic | ||||
| class whose purpose is to read and write from a bi-directional XML stream. | ||||
| It also allows for callback functions to execute when XML matching given | ||||
| patterns is received; these callbacks are also referred to as :term:`stream | ||||
| handlers <stream handler>`. The class also provides a basic eventing system | ||||
| which can be triggered either manually or on a timed schedule. | ||||
|  | ||||
| The Main Threads | ||||
| ~~~~~~~~~~~~~~~~ | ||||
| :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` instances run using at | ||||
| least three background threads: the send thread, the read thread, and the | ||||
| scheduler thread. The send thread is in charge of monitoring the send queue | ||||
| and writing text to the outgoing XML stream. The read thread pulls text off | ||||
| of the incoming XML stream and stores the results in an event queue. The | ||||
| scheduler thread is used to emit events after a given period of time. | ||||
| The event loop | ||||
| ~~~~~~~~~~~~~~ | ||||
| :class:`~slixmpp.xmlstream.xmlstream.XMLStream` instances inherit the | ||||
| :class:`asyncio.BaseProtocol` class, and therefore do not have to handle | ||||
| reads and writes directly, but receive data through | ||||
| :meth:`~slixmpp.xmlstream.xmlstream.XMLStream.data_received` and write | ||||
| data in the socket transport. | ||||
|  | ||||
| Additionally, the main event processing loop may be executed in its | ||||
| own thread if SleekXMPP is being used in the background for another | ||||
| application. | ||||
| Upon receiving data, :term:`stream handlers <stream handler>` are run | ||||
| immediately, except if they are coroutines, in which case they are | ||||
| scheduled using :meth:`asyncio.async`. | ||||
|  | ||||
| Short-lived threads may also be spawned as requested for threaded | ||||
| :term:`event handlers <event handler>`. | ||||
| :term:`Event handlers <event handler>` (which are called inside | ||||
| :term:`stream handlers <stream handler>`) work the same way. | ||||
|  | ||||
| How XML Text is Turned into Action | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| @@ -53,7 +52,7 @@ when this bit of XML is received (with an assumed namespace of | ||||
|     </message> | ||||
|  | ||||
|  | ||||
| 1. **Convert XML strings into objects.** | ||||
| #. **Convert XML strings into objects.** | ||||
|  | ||||
|    Incoming text is parsed and converted into XML objects (using | ||||
|    ElementTree) which are then wrapped into what are referred to as | ||||
| @@ -61,95 +60,69 @@ when this bit of XML is received (with an assumed namespace of | ||||
|    new object is determined using a map of namespaced element names to | ||||
|    classes. | ||||
|  | ||||
|    Our incoming XML is thus turned into a :class:`~sleekxmpp.stanza.Message` | ||||
|    Our incoming XML is thus turned into a :class:`~slixmpp.stanza.Message` | ||||
|    :term:`stanza object` because the namespaced element name | ||||
|    ``{jabber:client}message`` is associated with the class | ||||
|    :class:`~sleekxmpp.stanza.Message`. | ||||
|    :class:`~slixmpp.stanza.Message`. | ||||
|  | ||||
| 2. **Match stanza objects to callbacks.** | ||||
| #. **Match stanza objects to callbacks.** | ||||
|  | ||||
|    These objects are then compared against the stored patterns associated | ||||
|    with the registered callback handlers. For each match, a copy of the | ||||
|    :term:`stanza object` is paired with a reference to the handler and | ||||
|    placed into the event queue. | ||||
|    with the registered callback handlers. | ||||
|  | ||||
|    Our :class:`~sleekxmpp.stanza.Message` object is thus paired with the message stanza handler | ||||
|    :meth:`BaseXMPP._handle_message` to create the tuple:: | ||||
|    Each handler matching our :term:`stanza object` is then added to a list. | ||||
|  | ||||
|        ('stanza', stanza_obj, handler) | ||||
| #. **Processing callbacks** | ||||
|  | ||||
| 3. **Process the event queue.** | ||||
|    Every handler in the list is then called with the :term:`stanza object` | ||||
|    as a parameter; if the handler is a | ||||
|    :class:`~slixmpp.xmlstream.handler.CoroutineCallback` | ||||
|    then it will be scheduled in the event loop using :meth:`asyncio.async` | ||||
|    instead of run. | ||||
|  | ||||
|    The event queue is the heart of SleekXMPP. Nearly every action that | ||||
|    takes place is first inserted into this queue, whether that be received | ||||
|    stanzas, custom events, or scheduled events. | ||||
|  | ||||
|    When the stanza is pulled out of the event queue with an associated | ||||
|    callback, the callback function is executed with the stanza as its only | ||||
|    parameter. | ||||
|  | ||||
|    .. warning::  | ||||
|        The callback, aka :term:`stream handler`, is executed in the main event | ||||
|        processing thread. If the handler blocks, event processing will also | ||||
|        block. | ||||
|  | ||||
| 4. **Raise Custom Events** | ||||
| #. **Raise Custom Events** | ||||
|  | ||||
|    Since a :term:`stream handler` shouldn't block, if extensive processing | ||||
|    for a stanza is required (such as needing to send and receive an | ||||
|    :class:`~sleekxmpp.stanza.Iq` stanza), then custom events must be used. | ||||
|    :class:`~slixmpp.stanza.Iq` stanza), then custom events must be used. | ||||
|    These events are not explicitly tied to the incoming XML stream and may | ||||
|    be raised at any time. Importantly, these events may be handled in their | ||||
|    own thread. | ||||
|    be raised at any time. | ||||
|  | ||||
|    When the event is raised, a copy of the stanza is created for each | ||||
|    handler registered for the event. In contrast to :term:`stream handlers | ||||
|    <stream handler>`, these functions are referred to as :term:`event | ||||
|    handlers <event handler>`. Each stanza/handler pair is then put into the | ||||
|    event queue. | ||||
|  | ||||
|    .. note:: | ||||
|        It is possible to skip the event queue and process an event immediately | ||||
|        by using ``direct=True`` when raising the event. | ||||
|    In contrast to :term:`stream handlers <stream handler>`, these functions | ||||
|    are referred to as :term:`event handlers <event handler>`. | ||||
|  | ||||
|    The code for :meth:`BaseXMPP._handle_message` follows this pattern, and | ||||
|    raises a ``'message'`` event:: | ||||
|    raises a ``'message'`` event | ||||
|  | ||||
|        self.event('message', msg) | ||||
|    .. code-block:: python | ||||
|  | ||||
|    The event call then places the message object back into the event queue | ||||
|    paired with an :term:`event handler`:: | ||||
|         self.event('message', msg) | ||||
|  | ||||
|        ('event', 'message', msg_copy1, custom_event_handler_1) | ||||
|        ('event', 'message', msg_copy2, custom_evetn_handler_2)  | ||||
| #. **Process Custom Events** | ||||
|  | ||||
| 5. **Process Custom Events** | ||||
|  | ||||
|    The stanza and :term:`event handler` are then pulled from the event | ||||
|    queue, and the handler is executed, passing the stanza as its only | ||||
|    argument. If the handler was registered as threaded, then a new thread | ||||
|    will be spawned for it. | ||||
|    The :term:`event handlers <event handler>` are then executed, passing | ||||
|    the stanza as the only argument. | ||||
|  | ||||
|    .. note:: | ||||
|        Events may be raised without needing :term:`stanza objects <stanza object>`.  | ||||
|        For example, you could use ``self.event('custom', {'a': 'b'})``.  | ||||
|        You don't even need any arguments: ``self.event('no_parameters')``.  | ||||
|        Events may be raised without needing :term:`stanza objects <stanza object>`. | ||||
|        For example, you could use ``self.event('custom', {'a': 'b'})``. | ||||
|        You don't even need any arguments: ``self.event('no_parameters')``. | ||||
|        However, every event handler MUST accept at least one argument. | ||||
|  | ||||
|    Finally, after a long trek, our message is handed off to the user's | ||||
|    custom handler in order to do awesome stuff:: | ||||
|  | ||||
|        msg.reply() | ||||
|        msg['body'] = "Hey! This is awesome!" | ||||
|        msg.send() | ||||
|        reply = msg.reply() | ||||
|        reply['body'] = "Hey! This is awesome!" | ||||
|        reply.send() | ||||
|  | ||||
|  | ||||
| .. index:: BaseXMPP, XMLStream | ||||
|  | ||||
| Raising XMPP Awareness: BaseXMPP | ||||
| -------------------------------- | ||||
| While :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` attempts to shy away | ||||
| from anything too XMPP specific, :class:`~sleekxmpp.basexmpp.BaseXMPP`'s | ||||
| While :class:`~slixmpp.xmlstream.xmlstream.XMLStream` attempts to shy away | ||||
| from anything too XMPP specific, :class:`~slixmpp.basexmpp.BaseXMPP`'s | ||||
| sole purpose is to provide foundational support for sending and receiving | ||||
| XMPP stanzas. This support includes registering the basic message, | ||||
| presence, and iq stanzas, methods for creating and sending stanzas, and | ||||
| @@ -157,14 +130,14 @@ default handlers for incoming messages and keeping track of presence | ||||
| notifications. | ||||
|  | ||||
| The plugin system for adding new XEP support is also maintained by | ||||
| :class:`~sleekxmpp.basexmpp.BaseXMPP`. | ||||
| :class:`~slixmpp.basexmpp.BaseXMPP`. | ||||
|  | ||||
| .. index:: ClientXMPP, BaseXMPP | ||||
|  | ||||
| ClientXMPP | ||||
| ---------- | ||||
| :class:`~sleekxmpp.clientxmpp.ClientXMPP` extends | ||||
| :class:`~sleekxmpp.clientxmpp.BaseXMPP` with additional logic for connecting | ||||
| :class:`~slixmpp.clientxmpp.ClientXMPP` extends | ||||
| :class:`~slixmpp.clientxmpp.BaseXMPP` with additional logic for connecting | ||||
| to an XMPP server by performing DNS lookups. It also adds support for stream | ||||
| features such as STARTTLS and SASL. | ||||
|  | ||||
| @@ -172,6 +145,6 @@ features such as STARTTLS and SASL. | ||||
|  | ||||
| ComponentXMPP | ||||
| ------------- | ||||
| :class:`~sleekxmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of | ||||
| :class:`~sleekxmpp.basexmpp.BaseXMPP` that implements the component handshake | ||||
| :class:`~slixmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of | ||||
| :class:`~slixmpp.basexmpp.BaseXMPP` that implements the component handshake | ||||
| protocol. | ||||
|   | ||||
							
								
								
									
										27
									
								
								docs/conf.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								docs/conf.py
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # SleekXMPP documentation build configuration file, created by | ||||
| # Slixmpp documentation build configuration file, created by | ||||
| # sphinx-quickstart on Tue Aug  9 22:27:06 2011. | ||||
| # | ||||
| # This file is execfile()d with the current directory set to its containing dir. | ||||
| @@ -12,12 +12,17 @@ | ||||
| # serve to show the default. | ||||
|  | ||||
| import sys, os | ||||
| import datetime | ||||
|  | ||||
| # If extensions (or modules to document with autodoc) are in another directory, | ||||
| # add these directories to sys.path here. If the directory is relative to the | ||||
| # documentation root, use os.path.abspath to make it absolute, like shown here. | ||||
| sys.path.insert(0, os.path.abspath('..')) | ||||
|  | ||||
| # get version automagically from source tree | ||||
| from slixmpp.version import __version__ as version | ||||
| release = ".".join(version.split(".")[0:2]) | ||||
|  | ||||
| # -- General configuration ----------------------------------------------------- | ||||
|  | ||||
| # If your documentation needs a minimal Sphinx version, state it here. | ||||
| @@ -40,17 +45,19 @@ source_suffix = '.rst' | ||||
| master_doc = 'index' | ||||
|  | ||||
| # General information about the project. | ||||
| project = u'SleekXMPP' | ||||
| copyright = u'2011, Nathan Fritz, Lance Stout' | ||||
| project = u'Slixmpp' | ||||
| year = datetime.datetime.now().year | ||||
| copyright = u'{}, Nathan Fritz, Lance Stout'.format(year) | ||||
|  | ||||
| # The version info for the project you're documenting, acts as replacement for | ||||
| # |version| and |release|, also used in various other places throughout the | ||||
| # built documents. | ||||
| # | ||||
| # auto imported from code! | ||||
| # The short X.Y version. | ||||
| version = '1.0' | ||||
| # version = '1.4' | ||||
| # The full version, including alpha/beta/rc tags. | ||||
| release = '1.0' | ||||
| # release = '1.4.0' | ||||
|  | ||||
| # The language for content autogenerated by Sphinx. Refer to documentation | ||||
| # for a list of supported languages. | ||||
| @@ -105,7 +112,7 @@ html_theme = 'haiku' | ||||
|  | ||||
| # The name for this set of Sphinx documents.  If None, it defaults to | ||||
| # "<project> v<release> documentation". | ||||
| html_title = 'SleekXMPP' | ||||
| html_title = 'slixmpp' | ||||
|  | ||||
| # A shorter title for the navigation bar.  Default is the same as html_title. | ||||
| html_short_title = '%s Documentation' % release | ||||
| @@ -168,7 +175,7 @@ html_additional_pages = { | ||||
| #html_file_suffix = None | ||||
|  | ||||
| # Output file base name for HTML help builder. | ||||
| htmlhelp_basename = 'SleekXMPPdoc' | ||||
| htmlhelp_basename = 'Slixmppdoc' | ||||
|  | ||||
|  | ||||
| # -- Options for LaTeX output -------------------------------------------------- | ||||
| @@ -182,7 +189,7 @@ htmlhelp_basename = 'SleekXMPPdoc' | ||||
| # Grouping the document tree into LaTeX files. List of tuples | ||||
| # (source start file, target name, title, author, documentclass [howto/manual]). | ||||
| latex_documents = [ | ||||
|   ('index', 'SleekXMPP.tex', u'SleekXMPP Documentation', | ||||
|   ('index', 'Slixmpp.tex', u'Slixmpp Documentation', | ||||
|    u'Nathan Fritz, Lance Stout', 'manual'), | ||||
| ] | ||||
|  | ||||
| @@ -215,8 +222,8 @@ latex_documents = [ | ||||
| # One entry per manual page. List of tuples | ||||
| # (source start file, name, description, authors, manual section). | ||||
| man_pages = [ | ||||
|     ('index', 'sleekxmpp', u'SleekXMPP Documentation', | ||||
|     ('index', 'slixmpp', u'Slixmpp Documentation', | ||||
|      [u'Nathan Fritz, Lance Stout'], 1) | ||||
| ] | ||||
|  | ||||
| intersphinx_mapping = {'python': ('http://docs.python.org/3.2', 'python-objects.inv')} | ||||
| intersphinx_mapping = {'python': ('http://docs.python.org/3.4', 'python-objects.inv')} | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| .. _create-plugin: | ||||
|  | ||||
| Creating a SleekXMPP Plugin | ||||
| Creating a Slixmpp Plugin | ||||
| =========================== | ||||
|  | ||||
| One of the goals of SleekXMPP is to provide support for every draft or final | ||||
| XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, SleekXMPP has a | ||||
| One of the goals of Slixmpp is to provide support for every draft or final | ||||
| XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, Slixmpp has a | ||||
| plugin mechanism for adding the functionalities required by each XEP. But even | ||||
| though plugins were made to quickly implement and prototype the official XMPP | ||||
| extensions, there is no reason you can't create your own plugin to implement | ||||
| @@ -14,11 +14,11 @@ This guide will help walk you through the steps to | ||||
| implement a rudimentary version of `XEP-0077 In-band | ||||
| Registration <http://xmpp.org/extensions/xep-0077.html>`_. In-band registration | ||||
| was implemented in example 14-6 (page 223) of `XMPP: The Definitive | ||||
| Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no SleekXMPP | ||||
| Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no Slixmpp | ||||
| plugin for XEP-0077 at the time of writing. We will partially fix that issue | ||||
| here by turning the example implementation from *XMPP: The Definitive Guide* | ||||
| into a plugin. Again, note that this will not a complete implementation, and a | ||||
| different, more robust, official plugin for XEP-0077 may be added to SleekXMPP | ||||
| different, more robust, official plugin for XEP-0077 may be added to Slixmpp | ||||
| in the future. | ||||
|  | ||||
| .. note:: | ||||
| @@ -29,10 +29,10 @@ in the future. | ||||
|  | ||||
| First Steps | ||||
| ----------- | ||||
| Every plugin inherits from the class :mod:`base_plugin <sleekxmpp.plugins.base.base_plugin>`, | ||||
| Every plugin inherits from the class :mod:`BasePlugin <slixmpp.plugins.base.BasePlugin`, | ||||
| and must include a ``plugin_init`` method. While the | ||||
| plugins distributed with SleekXMPP must be placed in the plugins directory | ||||
| ``sleekxmpp/plugins`` to be loaded, custom plugins may be loaded from any | ||||
| plugins distributed with Slixmpp must be placed in the plugins directory | ||||
| ``slixmpp/plugins`` to be loaded, custom plugins may be loaded from any | ||||
| module. To do so, use the following form when registering the plugin: | ||||
|  | ||||
| .. code-block:: python | ||||
| @@ -40,9 +40,9 @@ module. To do so, use the following form when registering the plugin: | ||||
|     self.register_plugin('myplugin', module=mod_containing_my_plugin) | ||||
|  | ||||
| The plugin name must be the same as the plugin's class name. | ||||
|   | ||||
|  | ||||
| Now, we can open our favorite text editors and create ``xep_0077.py`` in | ||||
| ``SleekXMPP/sleekxmpp/plugins``. We want to do some basic house-keeping and | ||||
| ``Slixmpp/slixmpp/plugins``. We want to do some basic house-keeping and | ||||
| declare the name and description of the XEP we are implementing. If you | ||||
| are creating your own custom plugin, you don't need to include the ``xep`` | ||||
| attribute. | ||||
| @@ -50,15 +50,15 @@ attribute. | ||||
| .. code-block:: python | ||||
|  | ||||
|     """ | ||||
|     Creating a SleekXMPP Plugin | ||||
|     Creating a Slixmpp Plugin | ||||
|  | ||||
|     This is a minimal implementation of XEP-0077 to serve | ||||
|     as a tutorial for creating SleekXMPP plugins. | ||||
|     as a tutorial for creating Slixmpp plugins. | ||||
|     """ | ||||
|  | ||||
|     from sleekxmpp.plugins.base import base_plugin | ||||
|     from slixmpp.plugins.base import BasePlugin | ||||
|  | ||||
|     class xep_0077(base_plugin): | ||||
|     class xep_0077(BasePlugin): | ||||
|         """ | ||||
|         XEP-0077 In-Band Registration | ||||
|         """ | ||||
| @@ -68,7 +68,7 @@ attribute. | ||||
|             self.xep = "0077" | ||||
|  | ||||
| Now that we have a basic plugin, we need to edit | ||||
| ``sleekxmpp/plugins/__init__.py`` to include our new plugin by adding | ||||
| ``slixmpp/plugins/__init__.py`` to include our new plugin by adding | ||||
| ``'xep_0077'`` to the ``__all__`` declaration. | ||||
|  | ||||
| Interacting with Other Plugins | ||||
| @@ -81,20 +81,20 @@ call in a method named ``post_init`` which will be called once the plugin has | ||||
| been loaded; by doing so we advertise that we can do registrations only after we | ||||
| finish activating the plugin. | ||||
|  | ||||
| The ``post_init`` method needs to call ``base_plugin.post_init(self)`` | ||||
| The ``post_init`` method needs to call ``BasePlugin.post_init(self)`` | ||||
| which will mark that ``post_init`` has been called for the plugin. Once the | ||||
| SleekXMPP object begins processing, ``post_init`` will be called on any plugins | ||||
| Slixmpp object begins processing, ``post_init`` will be called on any plugins | ||||
| that have not already run ``post_init``. This allows you to register plugins and | ||||
| their dependencies without needing to worry about the order in which you do so. | ||||
|  | ||||
| **Note:** by adding this call we have introduced a dependency on the XEP-0030 | ||||
| plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. SleekXMPP | ||||
| plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. Slixmpp | ||||
| does not automatically load plugin dependencies for you. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     def post_init(self): | ||||
|         base_plugin.post_init(self) | ||||
|         BasePlugin.post_init(self) | ||||
|         self.xmpp['xep_0030'].add_feature("jabber:iq:register") | ||||
|  | ||||
| Creating Custom Stanza Objects | ||||
| @@ -141,7 +141,7 @@ behaviour: | ||||
|     **Note:** The accessor methods currently use title case, and not camel case. | ||||
|     Thus if you need to access an item named ``"methodName"`` you will need to | ||||
|     use ``getMethodname``. This naming convention might change to full camel | ||||
|     case in a future version of SleekXMPP. | ||||
|     case in a future version of Slixmpp. | ||||
|  | ||||
| * ``sub_interfaces`` | ||||
|     A subset of ``interfaces``, but these keys map to the text of any | ||||
| @@ -156,14 +156,14 @@ behaviour: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin | ||||
|     from sleekxmpp import Iq | ||||
|     from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin | ||||
|     from slixmpp import Iq | ||||
|  | ||||
|     class Registration(ElementBase): | ||||
|         namespace = 'jabber:iq:register' | ||||
|         name = 'query' | ||||
|         plugin_attrib = 'register' | ||||
|         interfaces = set(('username', 'password', 'registered', 'remove')) | ||||
|         interfaces = {'username', 'password', 'registered', 'remove'} | ||||
|         sub_interfaces = interfaces | ||||
|  | ||||
|         def getRegistered(self): | ||||
| @@ -209,7 +209,7 @@ registration to our ``plugin_init`` method. | ||||
|  | ||||
| Also, we need to associate our ``Registration`` class with IQ stanzas; | ||||
| that requires the use of the ``register_stanza_plugin`` function (in | ||||
| ``sleekxmpp.xmlstream.stanzabase``) which takes the class of a parent stanza | ||||
| ``slixmpp.xmlstream.stanzabase``) which takes the class of a parent stanza | ||||
| type followed by the substanza type. In our case, the parent stanza is an IQ | ||||
| stanza, and the substanza is our registration query. | ||||
|  | ||||
| @@ -222,7 +222,7 @@ handler function to process registration requests. | ||||
|         self.description = "In-Band Registration" | ||||
|         self.xep = "0077" | ||||
|  | ||||
|         self.xmpp.registerHandler( | ||||
|         self.xmpp.register_handler( | ||||
|           Callback('In-Band Registration', | ||||
|             MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns), | ||||
|             self.__handleRegistration)) | ||||
| @@ -347,7 +347,7 @@ method ``setForm`` which will take the names of the fields we wish to include. | ||||
|                 # Add a blank field | ||||
|                 reg.addField(field) | ||||
|  | ||||
|         iq.reply().setPayload(reg.xml) | ||||
|         iq.reply().set_payload(reg.xml) | ||||
|         iq.send() | ||||
|  | ||||
| Note how we are able to access our ``Registration`` stanza object with | ||||
| @@ -421,7 +421,7 @@ to the IQ reply. | ||||
|     ... | ||||
|  | ||||
|     def _sendError(self, iq, code, error_type, name, text=''): | ||||
|         iq.reply().setPayload(iq['register'].xml) | ||||
|         iq.reply().set_payload(iq['register'].xml) | ||||
|         iq.error() | ||||
|         iq['error']['code'] = code | ||||
|         iq['error']['type'] = error_type | ||||
| @@ -464,7 +464,7 @@ component examples below for how to respond to this event. | ||||
|             if self.backend.register(iq['from'].bare, iq['register']): | ||||
|                 # Successful registration | ||||
|                 self.xmpp.event('registered_user', iq) | ||||
|                 iq.reply().setPayload(iq['register'].xml) | ||||
|                 iq.reply().set_payload(iq['register'].xml) | ||||
|                 iq.send() | ||||
|             else: | ||||
|                 # Conflicting registration | ||||
| @@ -484,15 +484,15 @@ and that we specified the form fields we wish to use with | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import sleekxmpp.componentxmpp | ||||
|     import slixmpp.componentxmpp | ||||
|  | ||||
|     class Example(sleekxmpp.componentxmpp.ComponentXMPP): | ||||
|     class Example(slixmpp.componentxmpp.ComponentXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password): | ||||
|             sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888) | ||||
|             slixmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888) | ||||
|  | ||||
|             self.registerPlugin('xep_0030') | ||||
|             self.registerPlugin('xep_0077') | ||||
|             self.register_plugin('xep_0030') | ||||
|             self.register_plugin('xep_0077') | ||||
|             self.plugin['xep_0077'].setForm('username', 'password') | ||||
|  | ||||
|             self.add_event_handler("registered_user", self.reg) | ||||
| @@ -500,11 +500,11 @@ and that we specified the form fields we wish to use with | ||||
|  | ||||
|         def reg(self, iq): | ||||
|             msg = "Welcome! %s" % iq['register']['username'] | ||||
|             self.sendMessage(iq['from'], msg, mfrom=self.fulljid) | ||||
|             self.send_message(iq['from'], msg, mfrom=self.fulljid) | ||||
|  | ||||
|         def unreg(self, iq): | ||||
|             msg = "Bye! %s" % iq['register']['username'] | ||||
|             self.sendMessage(iq['from'], msg, mfrom=self.fulljid) | ||||
|             self.send_message(iq['from'], msg, mfrom=self.fulljid) | ||||
|  | ||||
| **Congratulations!** We now have a basic, functioning implementation of | ||||
| XEP-0077. | ||||
| @@ -517,17 +517,17 @@ with some additional registration fields implemented. | ||||
| .. code-block:: python | ||||
|  | ||||
|     """ | ||||
|     Creating a SleekXMPP Plugin | ||||
|     Creating a Slixmpp Plugin | ||||
|  | ||||
|     This is a minimal implementation of XEP-0077 to serve | ||||
|     as a tutorial for creating SleekXMPP plugins. | ||||
|     as a tutorial for creating Slixmpp plugins. | ||||
|     """ | ||||
|  | ||||
|     from sleekxmpp.plugins.base import base_plugin | ||||
|     from sleekxmpp.xmlstream.handler.callback import Callback | ||||
|     from sleekxmpp.xmlstream.matcher.xpath import MatchXPath | ||||
|     from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin | ||||
|     from sleekxmpp import Iq | ||||
|     from slixmpp.plugins.base import BasePlugin | ||||
|     from slixmpp.xmlstream.handler.callback import Callback | ||||
|     from slixmpp.xmlstream.matcher.xpath import MatchXPath | ||||
|     from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin | ||||
|     from slixmpp import Iq | ||||
|     import copy | ||||
|  | ||||
|  | ||||
| @@ -535,10 +535,10 @@ with some additional registration fields implemented. | ||||
|         namespace = 'jabber:iq:register' | ||||
|         name = 'query' | ||||
|         plugin_attrib = 'register' | ||||
|         interfaces = set(('username', 'password', 'email', 'nick', 'name',  | ||||
|                           'first', 'last', 'address', 'city', 'state', 'zip',  | ||||
|                           'phone', 'url', 'date', 'misc', 'text', 'key',  | ||||
|                           'registered', 'remove', 'instructions')) | ||||
|         interfaces = {'username', 'password', 'email', 'nick', 'name', | ||||
|                       'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                       'phone', 'url', 'date', 'misc', 'text', 'key', | ||||
|                       'registered', 'remove', 'instructions'} | ||||
|         sub_interfaces = interfaces | ||||
|  | ||||
|         def getRegistered(self): | ||||
| @@ -589,7 +589,7 @@ with some additional registration fields implemented. | ||||
|         def unregister(self, jid): | ||||
|             del self.users[jid] | ||||
|  | ||||
|     class xep_0077(base_plugin): | ||||
|     class xep_0077(BasePlugin): | ||||
|         """ | ||||
|         XEP-0077 In-Band Registration | ||||
|         """ | ||||
| @@ -601,14 +601,14 @@ with some additional registration fields implemented. | ||||
|             self.form_instructions = "" | ||||
|             self.backend = UserStore() | ||||
|  | ||||
|             self.xmpp.registerHandler( | ||||
|             self.xmpp.register_handler( | ||||
|                 Callback('In-Band Registration', | ||||
|                          MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns), | ||||
|                          self.__handleRegistration)) | ||||
|             register_stanza_plugin(Iq, Registration) | ||||
|  | ||||
|         def post_init(self): | ||||
|             base_plugin.post_init(self) | ||||
|             BasePlugin.post_init(self) | ||||
|             self.xmpp['xep_0030'].add_feature("jabber:iq:register") | ||||
|  | ||||
|         def __handleRegistration(self, iq): | ||||
| @@ -634,8 +634,9 @@ with some additional registration fields implemented. | ||||
|                 if self.backend.register(iq['from'].bare, iq['register']): | ||||
|                     # Successful registration | ||||
|                     self.xmpp.event('registered_user', iq) | ||||
|                     iq.reply().setPayload(iq['register'].xml) | ||||
|                     iq.send() | ||||
|                     reply = iq.reply() | ||||
|                     reply.set_payload(iq['register'].xml) | ||||
|                     reply.send() | ||||
|                 else: | ||||
|                     # Conflicting registration | ||||
|                     self._sendError(iq, '409', 'cancel', 'conflict', | ||||
| @@ -666,14 +667,16 @@ with some additional registration fields implemented. | ||||
|                     # Add a blank field | ||||
|                     reg.addField(field) | ||||
|  | ||||
|             iq.reply().setPayload(reg.xml) | ||||
|             iq.send() | ||||
|             reply = iq.reply() | ||||
|             reply.set_payload(reg.xml) | ||||
|             reply.send() | ||||
|  | ||||
|         def _sendError(self, iq, code, error_type, name, text=''): | ||||
|             iq.reply().setPayload(iq['register'].xml) | ||||
|             iq.error() | ||||
|             iq['error']['code'] = code | ||||
|             iq['error']['type'] = error_type | ||||
|             iq['error']['condition'] = name | ||||
|             iq['error']['text'] = text | ||||
|             iq.send() | ||||
|             reply = iq.reply() | ||||
|             reply.set_payload(iq['register'].xml) | ||||
|             reply.error() | ||||
|             reply['error']['code'] = code | ||||
|             reply['error']['type'] = error_type | ||||
|             reply['error']['condition'] = name | ||||
|             reply['error']['text'] = text | ||||
|             reply.send() | ||||
|   | ||||
							
								
								
									
										48
									
								
								docs/differences.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								docs/differences.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| .. _differences: | ||||
|  | ||||
| Differences from SleekXMPP | ||||
| ========================== | ||||
|  | ||||
| **Python 3.7+ only** | ||||
|     slixmpp will work on python 3.7 and above. It may work with previous | ||||
|     versions but we provide no guarantees. | ||||
|  | ||||
| **Stanza copies** | ||||
|     The same stanza object is given through all the handlers; a handler that | ||||
|     edits the stanza object should make its own copy. | ||||
|  | ||||
| **Replies** | ||||
|     Because stanzas are not copied anymore, | ||||
|     :meth:`Stanza.reply() <.StanzaBase.reply>` calls | ||||
|     (for :class:`IQs <.Iq>`, :class:`Messages <.Message>`, etc) | ||||
|     now return a new object instead of editing the stanza object | ||||
|     in-place. | ||||
|  | ||||
| **Block and threaded arguments** | ||||
|     All the functions that had a ``threaded=`` or ``block=`` argument | ||||
|     do not have it anymore. Also, :meth:`.Iq.send` **does not block | ||||
|     anymore**. | ||||
|  | ||||
| **Coroutine facilities** | ||||
|     **See** :ref:`using_asyncio` | ||||
|  | ||||
|     If an event handler is a coroutine, it will be called asynchronously | ||||
|     in the event loop instead of inside the event caller. | ||||
|  | ||||
|     A CoroutineCallback class has been added to create coroutine stream | ||||
|     handlers, which will be also handled in the event loop. | ||||
|  | ||||
|     The :class:`~.slixmpp.stanza.Iq` object’s :meth:`~.slixmpp.stanza.Iq.send` | ||||
|     method now **always** return a :class:`~.asyncio.Future` which result will be set | ||||
|     to the IQ reply when it is received, or to ``None`` if the IQ is not of | ||||
|     type ``get`` or ``set``. | ||||
|  | ||||
|     Many plugins (WIP) calls which retrieve information also return the same | ||||
|     future. | ||||
|  | ||||
| **Architectural differences** | ||||
|     slixmpp does not have an event queue anymore, and instead processes | ||||
|     handlers directly after receiving the XML stanza. | ||||
|  | ||||
| .. note:: | ||||
|     If you find something that doesn’t work but should, please report it. | ||||
| @@ -6,27 +6,33 @@ Event Index | ||||
|  | ||||
|     connected | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`~sleekxmpp.clientxmpp.ClientXMPP` | ||||
|         - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` | ||||
|  | ||||
|         Signal that a connection has been made with the XMPP server, but a session | ||||
|         has not yet been established. | ||||
|  | ||||
|     connection_failed | ||||
|         - **Data:** ``{}`` or ``Failure Stanza`` if available | ||||
|         - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` | ||||
|  | ||||
|         Signal that a connection can not be established after number of attempts. | ||||
|  | ||||
|     changed_status | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` | ||||
|  | ||||
|         Triggered when a presence stanza is received from a JID with a show type | ||||
|         different than the last presence stanza from the same JID. | ||||
|  | ||||
|     changed_subscription | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         Triggered whenever a presence stanza with a type of ``subscribe``, | ||||
|         ``subscribed``, ``unsubscribe``, or ``unsubscribed`` is received. | ||||
|  | ||||
|         Note that if the values ``xmpp.auto_authorize`` and ``xmpp.auto_subscribe`` | ||||
|         are set to ``True`` or ``False``, and not ``None``, then SleekXMPP will | ||||
|         are set to ``True`` or ``False``, and not ``None``, then Slixmpp will | ||||
|         either accept or reject all subscription requests before your event handlers | ||||
|         are called. Set these values to ``None`` if you wish to make more complex | ||||
|         subscription decisions. | ||||
| @@ -52,21 +58,21 @@ Event Index | ||||
|         - **Source:** | ||||
|  | ||||
|     disco_info | ||||
|         - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoInfo` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` | ||||
|  | ||||
|         Triggered whenever a ``disco#info`` result stanza is received. | ||||
|  | ||||
|     disco_items | ||||
|         - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoItems` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` | ||||
|  | ||||
|         Triggered whenever a ``disco#items`` result stanza is received. | ||||
|  | ||||
|     disconnected | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`~sleekxmpp.ClientXMPP` | ||||
|          | ||||
|         - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` | ||||
|  | ||||
|         Signal that the connection with the XMPP server has been lost. | ||||
|  | ||||
|     entity_time | ||||
| @@ -75,34 +81,34 @@ Event Index | ||||
|  | ||||
|     failed_auth | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`~sleekxmpp.ClientXMPP`, :py:class:`~sleekxmpp.plugins.xep_0078.xep_0078` | ||||
|         - **Source:** :py:class:`~slixmpp.ClientXMPP`, :py:class:`~slixmpp.plugins.xep_0078.xep_0078` | ||||
|  | ||||
|         Signal that the server has rejected the provided login credentials. | ||||
|  | ||||
|     gmail_notify | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify` | ||||
|          | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` | ||||
|  | ||||
|         Signal that there are unread emails for the Gmail account associated with the current XMPP account. | ||||
|  | ||||
|     gmail_messages | ||||
|         - **Data:** :py:class:`~sleekxmpp.Iq` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Iq` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` | ||||
|  | ||||
|         Signal that there are unread emails for the Gmail account associated with the current XMPP account. | ||||
|  | ||||
|     got_online | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` | ||||
|  | ||||
|         If a presence stanza is received from a JID which was previously marked as | ||||
|         offline, and the presence has a show type of '``chat``', '``dnd``', '``away``', | ||||
|         or '``xa``', then this event is triggered as well. | ||||
|  | ||||
|     got_offline | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` | ||||
|  | ||||
|         Signal that an unavailable presence stanza has been received from a JID. | ||||
|  | ||||
|     groupchat_invite | ||||
| @@ -110,25 +116,25 @@ Event Index | ||||
|         - **Source:** | ||||
|  | ||||
|     groupchat_direct_invite | ||||
|         - **Data:** :py:class:`~sleekxmpp.Message`  | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0249.direct` | ||||
|         - **Data:** :py:class:`~slixmpp.Message` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0249.direct` | ||||
|  | ||||
|     groupchat_message | ||||
|         - **Data:** :py:class:`~sleekxmpp.Message` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Message` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` | ||||
|  | ||||
|         Triggered whenever a message is received from a multi-user chat room. | ||||
|  | ||||
|     groupchat_presence | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` | ||||
|  | ||||
|         Triggered whenever a presence stanza is received from a user in a multi-user chat room. | ||||
|  | ||||
|     groupchat_subject | ||||
|         - **Data:** :py:class:`~sleekxmpp.Message` | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Message` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` | ||||
|  | ||||
|         Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room. | ||||
|  | ||||
|     killed | ||||
| @@ -140,25 +146,32 @@ Event Index | ||||
|         - **Source:** | ||||
|  | ||||
|     message | ||||
|         - **Data:** :py:class:`~sleekxmpp.Message` | ||||
|         - **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Message` | ||||
|         - **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>` | ||||
|  | ||||
|         Makes the contents of message stanzas available whenever one is received. Be | ||||
|         sure to check the message type in order to handle error messages. | ||||
|  | ||||
|     message_error | ||||
|         - **Data:** :py:class:`~slixmpp.Message` | ||||
|         - **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>` | ||||
|  | ||||
|         Makes the contents of message stanzas available whenever one is received. | ||||
|         Only handler messages with an ``error`` type. | ||||
|  | ||||
|     message_form | ||||
|         - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`  | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`  | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` | ||||
|  | ||||
|         Currently the same as :term:`message_xform`. | ||||
|  | ||||
|     message_xform | ||||
|         - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`  | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`  | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` | ||||
|  | ||||
|         Triggered whenever a data form is received inside a message. | ||||
|  | ||||
|     mucc::[room]::got_offline | ||||
|     muc::[room]::got_offline | ||||
|         - **Data:** | ||||
|         - **Source:** | ||||
|  | ||||
| @@ -175,97 +188,95 @@ Event Index | ||||
|         - **Source:** | ||||
|  | ||||
|     presence_available | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``available``' is received. | ||||
|  | ||||
|     presence_error | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``error``' is received. | ||||
|  | ||||
|     presence_form | ||||
|         - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`  | ||||
|         - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`  | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` | ||||
|         - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` | ||||
|  | ||||
|         This event is present in the XEP-0004 plugin code, but is currently not used. | ||||
|  | ||||
|     presence_probe | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``probe``' is received. | ||||
|  | ||||
|     presence_subscribe | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``subscribe``' is received. | ||||
|  | ||||
|     presence_subscribed | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``subscribed``' is received. | ||||
|  | ||||
|     presence_unavailable | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``unavailable``' is received. | ||||
|  | ||||
|     presence_unsubscribe | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``unsubscribe``' is received. | ||||
|  | ||||
|     presence_unsubscribed | ||||
|         - **Data:** :py:class:`~sleekxmpp.Presence` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.Presence` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|  | ||||
|         A presence stanza with a type of '``unsubscribed``' is received. | ||||
|  | ||||
|     roster_update | ||||
|         - **Data:** :py:class:`~sleekxmpp.stanza.Roster`  | ||||
|         - **Source:** :py:class:`~sleekxmpp.ClientXMPP`  | ||||
|          | ||||
|         - **Data:** :py:class:`~slixmpp.stanza.Roster` | ||||
|         - **Source:** :py:class:`~slixmpp.ClientXMPP` | ||||
|  | ||||
|         An IQ result containing roster entries is received. | ||||
|  | ||||
|     sent_presence | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>` | ||||
|          | ||||
|         - **Source:** :py:class:`~slixmpp.roster.multi.Roster` | ||||
|  | ||||
|         Signal that an initial presence stanza has been written to the XML stream. | ||||
|  | ||||
|     session_end | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`,  | ||||
|           :py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>` | ||||
|           :py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>` | ||||
|         - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` | ||||
|  | ||||
|         Signal that a connection to the XMPP server has been lost and the current | ||||
|         stream session has ended. Currently equivalent to :term:`disconnected`, but | ||||
|         future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_ | ||||
|         will distinguish the two events. | ||||
|         implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_ | ||||
|         distinguish between the two events. | ||||
|  | ||||
|         Plugins that maintain session-based state should clear themselves when | ||||
|         this event is fired. | ||||
|  | ||||
|     session_start | ||||
|         - **Data:** ``{}`` | ||||
|         - **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`,  | ||||
|           :py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>` | ||||
|           :py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>` | ||||
|         - **Source:** :py:class:`ClientXMPP <slixmpp.ClientXMPP>`, | ||||
|           :py:class:`ComponentXMPP <slixmpp.ComponentXMPP>` | ||||
|           :py:class:`XEP-0078 <slixmpp.plugins.xep_0078>` | ||||
|  | ||||
|         Signal that a connection to the XMPP server has been made and a session has been established. | ||||
|  | ||||
|     socket_error | ||||
|         - **Data:** ``Socket`` exception object  | ||||
|         - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` | ||||
|         - **Data:** ``Socket`` exception object | ||||
|         - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` | ||||
|  | ||||
|     stream_error | ||||
|         - **Data:** :py:class:`~sleekxmpp.stanza.StreamError` | ||||
|         - **Source:** :py:class:`~sleekxmpp.BaseXMPP` | ||||
|         - **Data:** :py:class:`~slixmpp.stanza.StreamError` | ||||
|         - **Source:** :py:class:`~slixmpp.BaseXMPP` | ||||
|   | ||||
| @@ -5,24 +5,16 @@ Create and Run a Server Component | ||||
| ================================= | ||||
|  | ||||
| .. note:: | ||||
|      | ||||
|  | ||||
|     If you have any issues working through this quickstart guide | ||||
|     or the other tutorials here, please either send a message to the | ||||
|     `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     or join the chat room at `sleek@conference.jabber.org | ||||
|     <xmpp:sleek@conference.jabber.org?join>`_. | ||||
|     join the chat room at `slixmpp@muc.poez.io | ||||
|     <xmpp:slixmpp@muc.poez.io?join>`_. | ||||
|  | ||||
| If you have not yet installed SleekXMPP, do so now by either checking out a version | ||||
| from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` | ||||
| or ``easy_install``. | ||||
| If you have not yet installed Slixmpp, do so now by either checking out a version | ||||
| with `Git <https://lab.louiz.org/poezio/slixmpp>`_. | ||||
|  | ||||
| .. code-block:: sh | ||||
|  | ||||
|     pip install sleekxmpp  # Or: easy_install sleekxmpp | ||||
|  | ||||
|  | ||||
| Many XMPP applications eventually graduate to requiring to run as a server  | ||||
| component in order to meet scalability requirements. To demonstrate how to  | ||||
| Many XMPP applications eventually graduate to requiring to run as a server | ||||
| component in order to meet scalability requirements. To demonstrate how to | ||||
| turn an XMPP client bot into a component, we'll turn the echobot example | ||||
| (:ref:`echobot`) into a component version. | ||||
|  | ||||
| @@ -30,7 +22,7 @@ The first difference is that we will add an additional import statement: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     from sleekxmpp.componentxmpp import ComponentXMPP | ||||
|     from slixmpp.componentxmpp import ComponentXMPP | ||||
|  | ||||
| Likewise, we will change the bot's class definition to match: | ||||
|  | ||||
| @@ -48,7 +40,7 @@ a MUC component, the following could be used: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     muc = ComponentXMPP('muc.sleekxmpp.com', '******', 'sleekxmpp.com', 5555) | ||||
|     muc = ComponentXMPP('muc.slixmpp.com', '******', 'slixmpp.com', 5555) | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
| @@ -62,10 +54,10 @@ with presence. | ||||
| The other, main difference with components is that the | ||||
| ``'from'`` value for every stanza must be explicitly set, since | ||||
| components may send stanzas from multiple JIDs. To do so, | ||||
| the :meth:`~sleekxmpp.basexmpp.BaseXMPP.send_message()` and | ||||
| :meth:`~sleekxmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters | ||||
| the :meth:`~slixmpp.basexmpp.BaseXMPP.send_message()` and | ||||
| :meth:`~slixmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters | ||||
| ``mfrom`` and ``pfrom``, respectively. For any method that uses | ||||
| :class:`~sleekxmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used. | ||||
| :class:`~slixmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used. | ||||
|  | ||||
|  | ||||
| Final Product | ||||
|   | ||||
| @@ -1,25 +1,17 @@ | ||||
| .. _echobot: | ||||
|  | ||||
| =============================== | ||||
| SleekXMPP Quickstart - Echo Bot | ||||
| Slixmpp Quickstart - Echo Bot | ||||
| =============================== | ||||
|  | ||||
| .. note:: | ||||
|      | ||||
|  | ||||
|     If you have any issues working through this quickstart guide | ||||
|     or the other tutorials here, please either send a message to the | ||||
|     `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     or join the chat room at `sleek@conference.jabber.org | ||||
|     <xmpp:sleek@conference.jabber.org?join>`_. | ||||
|  | ||||
| If you have not yet installed SleekXMPP, do so now by either checking out a version | ||||
| from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` | ||||
| or ``easy_install``. | ||||
|  | ||||
| .. code-block:: sh | ||||
|  | ||||
|     pip install sleekxmpp  # Or: easy_install sleekxmpp | ||||
|     join the chat room at `slixmpp@muc.poez.io | ||||
|     <xmpp:slixmpp@muc.poez.io?join>`_. | ||||
|  | ||||
| If you have not yet installed Slixmpp, do so now by either checking out a version | ||||
| with `Git <https://lab.louiz.org/poezio/slixmpp>`_. | ||||
|  | ||||
| As a basic starting project, we will create an echo bot which will reply to any | ||||
| messages sent to it. We will also go through adding some basic command line configuration | ||||
| @@ -44,11 +36,12 @@ To get started, here is a brief outline of the structure that the final project | ||||
|     # -*- coding: utf-8 -*- | ||||
|  | ||||
|     import sys | ||||
|     import asyncio | ||||
|     import logging | ||||
|     import getpass | ||||
|     from optparse import OptionParser | ||||
|  | ||||
|     import sleekxmpp | ||||
|     import slixmpp | ||||
|  | ||||
|     '''Here we will create out echo bot class''' | ||||
|  | ||||
| @@ -59,24 +52,6 @@ To get started, here is a brief outline of the structure that the final project | ||||
|  | ||||
|         '''Finally, we connect the bot and start listening for messages''' | ||||
|  | ||||
| Default Encoding | ||||
| ---------------- | ||||
| XMPP requires support for UTF-8 and so SleekXMPP must use UTF-8 as well. In | ||||
| Python3 this is simple because Unicode is the default string type. For Python2.6+ | ||||
| the situation is not as easy because standard strings are simply byte arrays and | ||||
| use ASCII. We can get Python to use UTF-8 as the default encoding by including: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     if sys.version_info < (3, 0): | ||||
|         reload(sys) | ||||
|         sys.setdefaultencoding('utf8') | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     Until we are able to ensure that SleekXMPP will always use Unicode in Python2.6+, this | ||||
|     may cause issues embedding SleekXMPP into other applications which assume ASCII encoding. | ||||
|  | ||||
| Creating the EchoBot Class | ||||
| -------------------------- | ||||
|  | ||||
| @@ -85,30 +60,30 @@ clients. Since our echo bot will only be responding to a few people, and won't n | ||||
| to remember thousands of users, we will use a client connection. A client connection | ||||
| is the same type that you use with your standard IM client such as Pidgin or Psi. | ||||
|  | ||||
| SleekXMPP comes with a :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` class | ||||
| which we can extend to add our message echoing feature. :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` | ||||
| Slixmpp comes with a :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` class | ||||
| which we can extend to add our message echoing feature. :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` | ||||
| requires the parameters ``jid`` and ``password``, so we will let our ``EchoBot`` class accept those | ||||
| as well. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     class EchoBot(sleekxmpp.ClientXMPP): | ||||
|          | ||||
|     class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password): | ||||
|             super(EchoBot, self).__init__(jid, password) | ||||
|             super().__init__(jid, password) | ||||
|  | ||||
| Handling Session Start | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
| The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once | ||||
| it connects and establishes a session with the XMPP server. Until these two tasks are completed, | ||||
| some servers may not deliver or send messages or presence notifications to the client. So we now | ||||
| need to be sure that we retrieve our roster and send an initial presence once the session has  | ||||
| need to be sure that we retrieve our roster and send an initial presence once the session has | ||||
| started. To do that, we will register an event handler for the :term:`session_start` event. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|      def __init__(self, jid, password): | ||||
|         super(EchoBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|  | ||||
| @@ -132,8 +107,8 @@ Our event handler, like every event handler, accepts a single parameter which ty | ||||
| that was received that caused the event. In this case, ``event`` will just be an empty dictionary since | ||||
| there is no associated data. | ||||
|  | ||||
| Our first task of sending an initial presence is done using :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>`. | ||||
| Calling :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest | ||||
| Our first task of sending an initial presence is done using :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>`. | ||||
| Calling :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest | ||||
| stanza allowed in XMPP: | ||||
|  | ||||
| .. code-block:: xml | ||||
| @@ -141,17 +116,17 @@ stanza allowed in XMPP: | ||||
|     <presence /> | ||||
|  | ||||
|  | ||||
| The second requirement is fulfilled using :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>`, which | ||||
| The second requirement is fulfilled using :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>`, which | ||||
| will send an IQ stanza requesting the roster to the server and then wait for the response. You may be wondering | ||||
| what :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return | ||||
| what :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return | ||||
| value. The roster data is saved by an internal handler to ``self.roster``, and in the case of a :class:`ClientXMPP | ||||
| <sleekxmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and | ||||
| <slixmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and | ||||
| ``self.client_roster`` is that ``self.roster`` supports storing roster information for multiple JIDs, which is useful | ||||
| for components, whereas ``self.client_roster`` stores roster data for just the client's JID.) | ||||
|  | ||||
| It is possible for a timeout to occur while waiting for the server to respond, which can happen if the | ||||
| network is excessively slow or the server is no longer responding. In that case, an :class:`IQTimeout | ||||
| <sleekxmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <sleekxmpp.exceptions.IQError>` exception can | ||||
| <slixmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <slixmpp.exceptions.IQError>` exception can | ||||
| be raised if the request contained bad data or requested the roster for the wrong user. In either case, you can wrap the | ||||
| ``get_roster()`` call in a ``try``/``except`` block to retry the roster retrieval process. | ||||
|  | ||||
| @@ -178,7 +153,7 @@ whenever a messsage is received. | ||||
| .. code-block:: python | ||||
|  | ||||
|      def __init__(self, jid, password): | ||||
|         super(EchoBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|         self.add_event_handler('message', self.message) | ||||
| @@ -198,10 +173,10 @@ or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat | ||||
|  | ||||
| Let's take a closer look at the ``.reply()`` method used above. For message stanzas, | ||||
| ``.reply()`` accepts the parameter ``body`` (also as the first positional argument), | ||||
| which is then used as the value of the ``<body />`` element of the message.  | ||||
| which is then used as the value of the ``<body />`` element of the message. | ||||
| Setting the appropriate ``to`` JID is also handled by ``.reply()``. | ||||
|  | ||||
| Another way to have sent the reply message would be to use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`, | ||||
| Another way to have sent the reply message would be to use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`, | ||||
| which is a convenience method for generating and sending a message based on the values passed to it. If we were to use | ||||
| this method, the above code would look as so: | ||||
|  | ||||
| @@ -229,20 +204,20 @@ Whichever method you choose to use, the results in action will look like this: | ||||
|     XMPP does not require stanzas sent by a client to include a ``from`` attribute, and | ||||
|     leaves that responsibility to the XMPP server. However, if a sent stanza does | ||||
|     include a ``from`` attribute, it must match the full JID of the client or some | ||||
|     servers will reject it. SleekXMPP thus leaves out the ``from`` attribute when replying | ||||
|     servers will reject it. Slixmpp thus leaves out the ``from`` attribute when replying | ||||
|     using a client connection. | ||||
|  | ||||
| Command Line Arguments and Logging | ||||
| ---------------------------------- | ||||
|  | ||||
| While this isn't part of SleekXMPP itself, we do want our echo bot program to be able | ||||
| While this isn't part of Slixmpp itself, we do want our echo bot program to be able | ||||
| to accept a JID and password from the command line instead of hard coding them. We will | ||||
| use the ``optparse`` module for this, though there are several alternative methods, including | ||||
| the newer ``argparse`` module. | ||||
|  | ||||
| We want to accept three parameters: the JID for the echo bot, its password, and a flag for | ||||
| displaying the debugging logs. We also want these to be optional parameters, since passing | ||||
| a password directly through the command line can be a security risk.  | ||||
| a password directly through the command line can be a security risk. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
| @@ -303,21 +278,21 @@ the ``EchoBot.__init__`` method instead. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     If you are using the OpenFire server, you will need to include an additional  | ||||
|     If you are using the OpenFire server, you will need to include an additional | ||||
|     configuration step. OpenFire supports a different version of SSL than what | ||||
|     most servers and SleekXMPP support. | ||||
|     most servers and Slixmpp support. | ||||
|  | ||||
|     .. code-block:: python | ||||
|      | ||||
|  | ||||
|         import ssl | ||||
|         xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
| Now we're ready to connect and begin echoing messages. If you have the package | ||||
| ``dnspython`` installed, then the :meth:`sleekxmpp.clientxmpp.ClientXMPP` method | ||||
| ``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method | ||||
| will perform a DNS query to find the appropriate server to connect to for the | ||||
| given JID. If you do not have ``dnspython``, then SleekXMPP will attempt to  | ||||
| given JID. If you do not have ``aiodns``, then Slixmpp will attempt to | ||||
| connect to the hostname used by the JID, unless an address tuple is supplied | ||||
| to :meth:`sleekxmpp.clientxmpp.ClientXMPP`.  | ||||
| to :meth:`slixmpp.clientxmpp.ClientXMPP`. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
| @@ -330,35 +305,19 @@ to :meth:`sleekxmpp.clientxmpp.ClientXMPP`. | ||||
|         else: | ||||
|             print('Unable to connect') | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     For Google Talk users withouth ``dnspython`` installed, the above code | ||||
|     should look like: | ||||
|  | ||||
|     .. code-block:: python | ||||
|  | ||||
|         if __name__ == '__main__': | ||||
|  | ||||
|             # .. option parsing & echo bot configuration | ||||
|  | ||||
|             if xmpp.connect(('talk.google.com', 5222)): | ||||
|                 xmpp.process(block=True) | ||||
|             else: | ||||
|                 print('Unable to connect') | ||||
|  | ||||
| To begin responding to messages, you'll see we called :meth:`sleekxmpp.basexmpp.BaseXMPP.process` | ||||
| To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process` | ||||
| which will start the event handling, send queue, and XML reader threads. It will also call | ||||
| the :meth:`sleekxmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By | ||||
| passing ``block=True`` to :meth:`sleekxmpp.basexmpp.BaseXMPP.process` we are running the  | ||||
| main processing loop in the main thread of execution. The :meth:`sleekxmpp.basexmpp.BaseXMPP.process` | ||||
| call will not return until after SleekXMPP disconnects. If you need to run the client in the background | ||||
| the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By | ||||
| passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the | ||||
| main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process` | ||||
| call will not return until after Slixmpp disconnects. If you need to run the client in the background | ||||
| for another program, use ``block=False`` to spawn the processing loop in its own thread. | ||||
|  | ||||
| .. note::  | ||||
| .. note:: | ||||
|  | ||||
|     Before 1.0, controlling the blocking behaviour of :meth:`sleekxmpp.basexmpp.BaseXMPP.process` was | ||||
|     Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was | ||||
|     done via the ``threaded`` argument. This arrangement was a source of confusion because some users | ||||
|     interpreted that as controlling whether or not SleekXMPP used threads at all, instead of how | ||||
|     interpreted that as controlling whether or not Slixmpp used threads at all, instead of how | ||||
|     the processing loop itself was spawned. | ||||
|  | ||||
|     The statements ``xmpp.process(threaded=False)`` and ``xmpp.process(block=True)`` are equivalent. | ||||
| @@ -370,7 +329,7 @@ The Final Product | ||||
| ----------------- | ||||
|  | ||||
| Here then is what the final result should look like after working through the guide above. The code | ||||
| can also be found in the SleekXMPP `examples directory <http://github.com/fritzy/SleekXMPP/tree/master/examples>`_. | ||||
| can also be found in the Slixmpp `examples directory <https://lab.louiz.org/poezio/slixmpp/tree/master/examples>`_. | ||||
|  | ||||
| .. compound:: | ||||
|  | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| Send/Receive IQ Stanzas | ||||
| ======================= | ||||
|  | ||||
| Unlike :class:`~sleekxmpp.stanza.message.Message` and | ||||
| :class:`~sleekxmpp.stanza.presence.Presence` stanzas which only use | ||||
| text data for basic usage, :class:`~sleekxmpp.stanza.iq.Iq` stanzas | ||||
| Unlike :class:`~slixmpp.stanza.message.Message` and | ||||
| :class:`~slixmpp.stanza.presence.Presence` stanzas which only use | ||||
| text data for basic usage, :class:`~slixmpp.stanza.iq.Iq` stanzas | ||||
| require using XML payloads, and generally entail creating a new | ||||
| SleekXMPP plugin to provide the necessary convenience methods to | ||||
| Slixmpp plugin to provide the necessary convenience methods to | ||||
| make working with them easier. | ||||
|  | ||||
| Basic Use | ||||
| --------- | ||||
|  | ||||
| XMPP's use of :class:`~sleekxmpp.stanza.iq.Iq` stanzas is built around | ||||
| XMPP's use of :class:`~slixmpp.stanza.iq.Iq` stanzas is built around | ||||
| namespaced ``<query />`` elements. For clients, just sending the | ||||
| empty ``<query />`` element will suffice for retrieving information. For | ||||
| example, a very basic implementation of service discovery would just | ||||
| @@ -26,18 +26,18 @@ need to be able to send: | ||||
| Creating Iq Stanzas | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| SleekXMPP provides built-in support for creating basic :class:`~sleekxmpp.stanza.iq.Iq` | ||||
| Slixmpp provides built-in support for creating basic :class:`~slixmpp.stanza.iq.Iq` | ||||
| stanzas this way. The relevant methods are: | ||||
|  | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq` | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_get` | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_set` | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_result` | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_error` | ||||
| * :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_query` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_get` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_set` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_result` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error` | ||||
| * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query` | ||||
|  | ||||
| These methods all follow the same pattern: create or modify an existing  | ||||
| :class:`~sleekxmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based | ||||
| These methods all follow the same pattern: create or modify an existing | ||||
| :class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based | ||||
| on the method name, and finally add a ``<query />`` element with the given | ||||
| namespace. For example, to produce the query above, you would use: | ||||
|  | ||||
| @@ -50,14 +50,14 @@ namespace. For example, to produce the query above, you would use: | ||||
| Sending Iq Stanzas | ||||
| ~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| Once an :class:`~sleekxmpp.stanza.iq.Iq` stanza is created, sending it | ||||
| over the wire is done using its :meth:`~sleekxmpp.stanza.iq.Iq.send()` | ||||
| Once an :class:`~slixmpp.stanza.iq.Iq` stanza is created, sending it | ||||
| over the wire is done using its :meth:`~slixmpp.stanza.iq.Iq.send()` | ||||
| method, like any other stanza object. However, there are a few extra | ||||
| options to control how to wait for the query's response. | ||||
|  | ||||
| These options are: | ||||
|  | ||||
| * ``block``: The default behaviour is that :meth:`~sleekxmpp.stanza.iq.Iq.send()` | ||||
| * ``block``: The default behaviour is that :meth:`~slixmpp.stanza.iq.Iq.send()` | ||||
|   will block until a response is received and the response stanza will be the | ||||
|   return value. Setting ``block`` to ``False`` will cause the call to return | ||||
|   immediately. In which case, you will need to arrange some way to capture | ||||
| @@ -74,7 +74,7 @@ These options are: | ||||
|   To change the timeout for a single call, the ``timeout`` parameter works: | ||||
|  | ||||
|     .. code-block:: python | ||||
|          | ||||
|  | ||||
|         iq.send(timeout=60) | ||||
|  | ||||
| * ``callback``: When not using a blocking call, using the ``callback`` | ||||
| @@ -85,16 +85,16 @@ These options are: | ||||
|  | ||||
|     .. code-block:: python | ||||
|  | ||||
|        cb_name = iq.send(callback=self.a_callback)  | ||||
|        cb_name = iq.send(callback=self.a_callback) | ||||
|  | ||||
|        # ... later if we need to cancel | ||||
|        self.remove_handler(cb_name) | ||||
|  | ||||
| Properly working with :class:`~sleekxmpp.stanza.iq.Iq` stanzas requires | ||||
| Properly working with :class:`~slixmpp.stanza.iq.Iq` stanzas requires | ||||
| handling the intended, normal flow, error responses, and timed out | ||||
| requests. To make this easier, two exceptions may be thrown by | ||||
| :meth:`~sleekxmpp.stanza.iq.Iq.send()`: :exc:`~sleekxmpp.exceptions.IqError` | ||||
| and :exc:`~sleekxmpp.exceptions.IqTimeout`. These exceptions only | ||||
| :meth:`~slixmpp.stanza.iq.Iq.send()`: :exc:`~slixmpp.exceptions.IqError` | ||||
| and :exc:`~slixmpp.exceptions.IqTimeout`. These exceptions only | ||||
| apply to the default, blocking calls. | ||||
|  | ||||
| .. code-block:: python | ||||
| @@ -110,7 +110,7 @@ apply to the default, blocking calls. | ||||
|         pass | ||||
|  | ||||
| If you do not care to distinguish between errors and timeouts, then you | ||||
| can combine both cases with a generic :exc:`~sleekxmpp.exceptions.XMPPError` | ||||
| can combine both cases with a generic :exc:`~slixmpp.exceptions.XMPPError` | ||||
| exception: | ||||
|  | ||||
| .. code-block:: python | ||||
| @@ -124,24 +124,24 @@ exception: | ||||
| Advanced Use | ||||
| ------------ | ||||
|  | ||||
| Going beyond the basics provided by SleekXMPP requires building at least a | ||||
| rudimentary SleekXMPP plugin to create a :term:`stanza object` for | ||||
| interfacting with the :class:`~sleekxmpp.stanza.iq.Iq` payload. | ||||
| Going beyond the basics provided by Slixmpp requires building at least a | ||||
| rudimentary Slixmpp plugin to create a :term:`stanza object` for | ||||
| interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload. | ||||
|  | ||||
| .. seealso:: | ||||
|  | ||||
|     * :ref:`create-plugin` | ||||
|     * :ref:`work-with-stanzas` | ||||
|     * :ref:`using-handlers-matchers` | ||||
|      | ||||
|  | ||||
| The typical way to respond to :class:`~sleekxmpp.stanza.iq.Iq` requests is | ||||
|  | ||||
| The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is | ||||
| to register stream handlers. As an example, suppose we create a stanza class | ||||
| named ``CustomXEP`` which uses the XML element ``<query xmlns="custom-xep" />``, | ||||
| and has a :attr:`~sleekxmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value | ||||
| and has a :attr:`~slixmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value | ||||
| of ``custom_xep``. | ||||
|  | ||||
| There are two types of incoming :class:`~sleekxmpp.stanza.iq.Iq` requests: | ||||
| There are two types of incoming :class:`~slixmpp.stanza.iq.Iq` requests: | ||||
| ``get`` and ``set``. You can register a handler that will accept both and then | ||||
| filter by type as needed, as so: | ||||
|  | ||||
| @@ -167,7 +167,7 @@ filter by type as needed, as so: | ||||
|  | ||||
| If you want to filter out query types beforehand, you can adjust the matching | ||||
| filter by using ``@type=get`` or ``@type=set`` if you are using the recommended | ||||
| :class:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher. | ||||
| :class:`~slixmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|   | ||||
| @@ -1,27 +1,19 @@ | ||||
| .. _mucbot: | ||||
|  | ||||
| ========================= | ||||
| Mulit-User Chat (MUC) Bot | ||||
| Multi-User Chat (MUC) Bot | ||||
| ========================= | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     If you have any issues working through this quickstart guide | ||||
|     or the other tutorials here, please either send a message to the | ||||
|     `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     or join the chat room at `sleek@conference.jabber.org | ||||
|     <xmpp:sleek@conference.jabber.org?join>`_. | ||||
|     join the chat room at `slixmpp@muc.poez.io | ||||
|     <xmpp:slixmpp@muc.poez.io?join>`_. | ||||
|  | ||||
| If you have not yet installed SleekXMPP, do so now by either checking out a version | ||||
| from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` | ||||
| or ``easy_install``. | ||||
| If you have not yet installed Slixmpp, do so now by either checking out a version | ||||
| from `Git <https://lab.louiz.org/poezio/slixmpp>`_. | ||||
|  | ||||
| .. code-block:: sh | ||||
|  | ||||
|     pip install sleekxmpp  # Or: easy_install sleekxmpp | ||||
|  | ||||
|  | ||||
| Now that you've got the basic gist of using SleekXMPP by following the | ||||
| Now that you've got the basic gist of using Slixmpp by following the | ||||
| echobot example (:ref:`echobot`), we can use one of the bundled plugins | ||||
| to create a very popular XMPP starter project: a `Multi-User Chat`_ | ||||
| (MUC) bot. Our bot will login to an XMPP server, join an MUC chat room | ||||
| @@ -36,7 +28,7 @@ Joining The Room | ||||
|  | ||||
| As usual, our code will be based on the pattern explained in :ref:`echobot`. | ||||
| To start, we create an ``MUCBot`` class based on | ||||
| :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and which accepts | ||||
| :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and which accepts | ||||
| parameters for the JID of the MUC room to join, and the nick that the | ||||
| bot will use inside the chat room.  We also register an | ||||
| :term:`event handler` for the :term:`session_start` event. | ||||
| @@ -44,12 +36,12 @@ bot will use inside the chat room.  We also register an | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import sleekxmpp | ||||
|     import slixmpp | ||||
|  | ||||
|     class MUCBot(sleekxmpp.ClientXMPP): | ||||
|     class MUCBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password, room, nick): | ||||
|             sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|             slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|             self.room = room | ||||
|             self.nick = nick | ||||
| @@ -71,17 +63,17 @@ has been established: | ||||
|     def start(self, event): | ||||
|         self.get_roster() | ||||
|         self.send_presence() | ||||
|         self.plugin['xep_0045'].joinMUC(self.room, | ||||
|                                         self.nick, | ||||
|                                         wait=True) | ||||
|         self.plugin['xep_0045'].join_muc(self.room, | ||||
|                                          self.nick, | ||||
|                                          wait=True) | ||||
|  | ||||
| Note that as in :ref:`echobot`, we need to include send an initial presence and request | ||||
| the roster. Next, we want to join the group chat, so we call the | ||||
| ``joinMUC`` method of the MUC plugin. | ||||
| ``join_muc`` method of the MUC plugin. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     The :attr:`plugin <sleekxmpp.basexmpp.BaseXMPP.plugin>` attribute is | ||||
|     The :attr:`plugin <slixmpp.basexmpp.BaseXMPP.plugin>` attribute is | ||||
|     dictionary that maps to instances of plugins that we have previously | ||||
|     registered, by their names. | ||||
|  | ||||
| @@ -115,7 +107,7 @@ event inside the bot's ``__init__`` function. | ||||
| .. code-block:: python | ||||
|  | ||||
|     def __init__(self, jid, password, room, nick): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.room = room | ||||
|         self.nick = nick | ||||
| @@ -159,7 +151,7 @@ event so it's a good idea to register an event handler for it. | ||||
| .. code-block:: python | ||||
|  | ||||
|     def __init__(self, jid, password, room, nick): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.room = room | ||||
|         self.nick = nick | ||||
|   | ||||
| @@ -5,19 +5,17 @@ Enable HTTP Proxy Support | ||||
| ========================= | ||||
|  | ||||
| .. note:: | ||||
|      | ||||
|  | ||||
|     If you have any issues working through this quickstart guide | ||||
|     or the other tutorials here, please either send a message to the | ||||
|     `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     or join the chat room at `sleek@conference.jabber.org | ||||
|     <xmpp:sleek@conference.jabber.org?join>`_. | ||||
|     join the chat room at `slixmpp@muc.poez.io | ||||
|     <xmpp:slixmpp@muc.poez.io?join>`_. | ||||
|  | ||||
| In some instances, you may wish to route XMPP traffic through | ||||
| an HTTP proxy, probably to get around restrictive firewalls. | ||||
| SleekXMPP provides support for basic HTTP proxying with DIGEST | ||||
| Slixmpp provides support for basic HTTP proxying with DIGEST | ||||
| authentication. | ||||
|  | ||||
| Enabling proxy support is done in two steps. The first is to instruct SleekXMPP | ||||
| Enabling proxy support is done in two steps. The first is to instruct Slixmpp | ||||
| to use a proxy, and the second is to configure the proxy details: | ||||
|  | ||||
| .. code-block:: python | ||||
|   | ||||
| @@ -2,31 +2,29 @@ Sign in, Send a Message, and Disconnect | ||||
| ======================================= | ||||
|  | ||||
| .. note:: | ||||
|      | ||||
|     If you have any issues working through this quickstart guide | ||||
|     or the other tutorials here, please either send a message to the | ||||
|     `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     or join the chat room at `sleek@conference.jabber.org | ||||
|     <xmpp:sleek@conference.jabber.org?join>`_. | ||||
|  | ||||
| A common use case for SleekXMPP is to send one-off messages from | ||||
| time to time. For example, one use case could be sending out a notice when  | ||||
|     If you have any issues working through this quickstart guide | ||||
|     join the chat room at `slixmpp@muc.poez.io | ||||
|     <xmpp:slixmpp@muc.poez.io?join>`_. | ||||
|  | ||||
| A common use case for Slixmpp is to send one-off messages from | ||||
| time to time. For example, one use case could be sending out a notice when | ||||
| a shell script finishes a task. | ||||
|  | ||||
| We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To | ||||
| start, we create a client class based on :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and | ||||
| start, we create a client class based on :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and | ||||
| register a handler for the :term:`session_start` event. We will also accept parameters | ||||
| for the JID that will receive our message, and the string content of the message. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import sleekxmpp | ||||
|     import slixmpp | ||||
|  | ||||
|  | ||||
|     class SendMsgBot(sleekxmpp.ClientXMPP): | ||||
|          | ||||
|     class SendMsgBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password, recipient, msg): | ||||
|             super(SendMsgBot, self).__init__(jid, password) | ||||
|             super().__init__(jid, password) | ||||
|  | ||||
|             self.recipient = recipient | ||||
|             self.msg = msg | ||||
| @@ -38,7 +36,7 @@ for the JID that will receive our message, and the string content of the message | ||||
|             self.get_roster() | ||||
|  | ||||
| Note that as in :ref:`echobot`, we need to include send an initial presence and request | ||||
| the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`. | ||||
| the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
| @@ -48,12 +46,12 @@ the roster. Next, we want to send our message, and to do that we will use :meth: | ||||
|  | ||||
|         self.send_message(mto=self.recipient, mbody=self.msg) | ||||
|  | ||||
| Finally, we need to disconnect the client using :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>`. | ||||
| Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call | ||||
| :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible | ||||
| for the client to disconnect before the send queue is processed and the message is actually | ||||
| sent on the wire. To ensure that our message is processed, we use  | ||||
| :meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`. | ||||
| Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>`. | ||||
| Now, sent stanzas are placed in a queue to pass them to the send thread. | ||||
| :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>` by default will wait for an | ||||
| acknowledgement from the server for at least `2.0` seconds. This time is configurable with | ||||
| the `wait` parameter. If `0.0` is passed for `wait`, :meth:`disconnect | ||||
| <slixmpp.xmlstream.XMLStream.disconnect>` will not close the connection gracefully. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
| @@ -63,12 +61,12 @@ sent on the wire. To ensure that our message is processed, we use | ||||
|  | ||||
|         self.send_message(mto=self.recipient, mbody=self.msg) | ||||
|  | ||||
|         self.disconnect(wait=True) | ||||
|         self.disconnect() | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     If you happen to be adding stanzas to the send queue faster than the send thread | ||||
|     can process them, then :meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>` | ||||
|     can process them, then :meth:`disconnect() <slixmpp.xmlstream.XMLStream.disconnect>` | ||||
|     will block and not disconnect. | ||||
|  | ||||
| Final Product | ||||
|   | ||||
| @@ -9,21 +9,20 @@ Glossary | ||||
|     stream handler | ||||
|         A callback function that accepts stanza objects pulled directly | ||||
|         from the XML stream. A stream handler is encapsulated in a | ||||
|         object that includes a :term:`Matcher` object, and which provides | ||||
|         additional semantics. For example, the ``Waiter`` handler wrapper | ||||
|         blocks thread execution until a matching stanza is received. | ||||
|         object that includes a :class:`Matcher <.MatcherBase>` object, and | ||||
|         which provides additional semantics. For example, the | ||||
|         :class:`.Waiter` handler wrapper blocks thread execution until a | ||||
|         matching stanza is received. | ||||
|  | ||||
|     event handler | ||||
|         A callback function that responds to events raised by | ||||
|         ``XMLStream.event``. An event handler may be marked as | ||||
|         threaded, allowing it to execute outside of the main processing | ||||
|         loop. | ||||
|         :meth:`.XMLStream.event`. | ||||
|  | ||||
|     stanza object | ||||
|         Informally may refer both to classes which extend ``ElementBase`` | ||||
|         or ``StanzaBase``, and to objects of such classes. | ||||
|         Informally may refer both to classes which extend :class:`.ElementBase` | ||||
|         or :class:`.StanzaBase`, and to objects of such classes. | ||||
|  | ||||
|         A stanza object is a wrapper for an XML object which exposes ``dict`` | ||||
|         A stanza object is a wrapper for an XML object which exposes :class:`dict` | ||||
|         like interfaces which may be assigned to, read from, or deleted. | ||||
|  | ||||
|     stanza plugin | ||||
|   | ||||
| @@ -18,7 +18,7 @@ Working with service discovery is about creating and querying these nodes. | ||||
| According to XEP-0030, a node may contain three types of information: | ||||
| identities, features, and items. (Further, extensible, information types are | ||||
| defined in `XEP-0128 <http://xmpp.org/extensions/xep-0128.html>`_, but they are | ||||
| not yet implemented by SleekXMPP.) SleekXMPP provides methods to configure each | ||||
| not yet implemented by Slixmpp.) Slixmpp provides methods to configure each | ||||
| of these node attributes. | ||||
|  | ||||
| Configuring Service Discovery | ||||
| @@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as | ||||
| checking an ACL, etc. | ||||
|  | ||||
| You may find it necessary at some point to revert a particular node or JID to | ||||
| using the default, static handlers. To do so, use the method ``make_static()``. | ||||
| using the default, static handlers. To do so, use the method ``restore_defaults()``. | ||||
| You may also elect to only convert a given set of actions instead. | ||||
|  | ||||
| Creating a Node Handler | ||||
| @@ -119,7 +119,7 @@ the same order as expected using positional arguments. | ||||
|  | ||||
|     xmpp['xep_0030'].add_identity(category='client', | ||||
|                                   itype='bot', | ||||
|                                   name='Sleek', | ||||
|                                   name='Slixmpp', | ||||
|                                   node='foo', | ||||
|                                   jid=xmpp.boundjid.full, | ||||
|                                   lang='no') | ||||
| @@ -159,10 +159,10 @@ item itself, and the JID and node that will own the item. | ||||
| .. note:: | ||||
|  | ||||
|     In this case, the owning JID and node are provided with the | ||||
|     parameters ``ijid`` and ``node``.  | ||||
|     parameters ``ijid`` and ``node``. | ||||
|  | ||||
| Peforming Disco Queries | ||||
| ----------------------- | ||||
| Performing Disco Queries | ||||
| ------------------------ | ||||
| The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs | ||||
| and their nodes for disco information. Since these methods are wrappers for | ||||
| sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()`` | ||||
| @@ -172,11 +172,10 @@ the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     info = self['xep_0030'].get_info(jid='foo@example.com', | ||||
|                                      node='bar', | ||||
|                                      ifrom='baz@mycomponent.example.com', | ||||
|                                      block=True, | ||||
|                                      timeout=30) | ||||
|     info = yield from self['xep_0030'].get_info(jid='foo@example.com', | ||||
|                                                 node='bar', | ||||
|                                                 ifrom='baz@mycomponent.example.com', | ||||
|                                                 timeout=30) | ||||
|  | ||||
|     items = self['xep_0030'].get_info(jid='foo@example.com', | ||||
|                                       node='bar', | ||||
| @@ -197,5 +196,5 @@ a full Iq stanza. | ||||
|  | ||||
|     info = self['xep_0030'].get_info(node='foo', local=True) | ||||
|     items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com', | ||||
|                                        node='bar',  | ||||
|                                        node='bar', | ||||
|                                        local=True) | ||||
|   | ||||
							
								
								
									
										112
									
								
								docs/index.rst
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								docs/index.rst
									
									
									
									
									
								
							| @@ -1,49 +1,36 @@ | ||||
| SleekXMPP | ||||
| Slixmpp | ||||
| ######### | ||||
|  | ||||
| .. sidebar:: Get the Code | ||||
|  | ||||
|     .. code-block:: sh | ||||
|     The latest source code for Slixmpp may be found on the `Git repo | ||||
|     <https://lab.louiz.org/poezio/slixmpp>`_. :: | ||||
|  | ||||
|         pip install sleekxmpp | ||||
|         git clone https://lab.louiz.org/poezio/slixmpp | ||||
|  | ||||
|     The latest source code for SleekXMPP may be found on `Github | ||||
|     <http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the | ||||
|     ``master`` branch, while the latest development version is in the | ||||
|     ``develop`` branch. | ||||
|  | ||||
|     **Latest Stable Release** | ||||
|         - `1.0 <http://github.com/fritzy/SleekXMPP/zipball/1.0>`_ | ||||
|  | ||||
|     **Develop Releases** | ||||
|         - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_ | ||||
|  | ||||
|  | ||||
|     A mailing list and XMPP chat room are available for discussing and getting | ||||
|     help with SleekXMPP. | ||||
|  | ||||
|     **Mailing List** | ||||
|         `SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-discussion>`_ | ||||
|     An XMPP chat room is available for discussing and getting help with slixmpp. | ||||
|  | ||||
|     **Chat** | ||||
|         `sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_ | ||||
|         `slixmpp@muc.poez.io <xmpp:slixmpp@muc.poez.io?join>`_ | ||||
|  | ||||
|     **Reporting bugs** | ||||
|         You can report bugs at http://lab.louiz.org/poezio/slixmpp/issues. | ||||
|  | ||||
| SleekXMPP is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+, | ||||
| and is featured in examples in | ||||
| `XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_  | ||||
| by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived | ||||
| here from reading the Definitive Guide, please see the notes on updating | ||||
| the examples to the latest version of SleekXMPP. | ||||
| .. note:: | ||||
|     slixmpp is a friendly fork of `SleekXMPP <https://github.com/fritzy/SleekXMPP>`_ | ||||
|     which goal is to use asyncio instead of threads to handle networking. See | ||||
|     :ref:`differences`. | ||||
|  | ||||
| SleekXMPP's design goals and philosphy are: | ||||
| Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 3.7+, | ||||
|  | ||||
| Slixmpp's design goals and philosphy are: | ||||
|  | ||||
| **Low number of dependencies** | ||||
|     Installing and using SleekXMPP should be as simple as possible, without | ||||
|     Installing and using Slixmpp should be as simple as possible, without | ||||
|     having to deal with long dependency chains. | ||||
|  | ||||
|     As part of reducing the number of dependencies, some third party | ||||
|     modules are included with SleekXMPP in the ``thirdparty`` directory. | ||||
|     modules are included with Slixmpp in the ``thirdparty`` directory. | ||||
|     Imports from this module first try to import an existing installed | ||||
|     version before loading the packaged version, when possible. | ||||
|  | ||||
| @@ -55,19 +42,20 @@ SleekXMPP's design goals and philosphy are: | ||||
|     XEPs. | ||||
|  | ||||
| **Rewarding to work with** | ||||
|     As much as possible, SleekXMPP should allow things to "just work" using | ||||
|     As much as possible, Slixmpp should allow things to "just work" using | ||||
|     sensible defaults and appropriate abstractions. XML can be ugly to work | ||||
|     with, but it doesn't have to be that way. | ||||
|  | ||||
| Here's your first SleekXMPP Bot: | ||||
|  | ||||
| Here's your first Slixmpp Bot: | ||||
| -------------------------------- | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import asyncio | ||||
|     import logging | ||||
|  | ||||
|     from sleekxmpp import ClientXMPP | ||||
|     from sleekxmpp.exceptions import IqError, IqTimeout | ||||
|     from slixmpp import ClientXMPP | ||||
|  | ||||
|  | ||||
|     class EchoBot(ClientXMPP): | ||||
| @@ -85,27 +73,13 @@ Here's your first SleekXMPP Bot: | ||||
|             # Here's how to access plugins once you've registered them: | ||||
|             # self['xep_0030'].add_feature('echo_demo') | ||||
|  | ||||
|             # If you are working with an OpenFire server, you will | ||||
|             # need to use a different SSL version: | ||||
|             # import ssl | ||||
|             # self.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|         def session_start(self, event): | ||||
|             self.send_presence() | ||||
|             self.get_roster() | ||||
|  | ||||
|             # Most get_*/set_* methods from plugins use Iq stanzas, which | ||||
|             # can generate IqError and IqTimeout exceptions | ||||
|             # | ||||
|             # try: | ||||
|             #     self.get_roster() | ||||
|             # except IqError as err: | ||||
|             #     logging.error('There was an error getting the roster') | ||||
|             #     logging.error(err.iq['error']['condition']) | ||||
|             #     self.disconnect() | ||||
|             # except IqTimeout: | ||||
|             #     logging.error('Server is taking too long to respond') | ||||
|             #     self.disconnect() | ||||
|             # are sent asynchronously. You can almost always provide a | ||||
|             # callback that will be executed when the reply is received. | ||||
|  | ||||
|         def message(self, msg): | ||||
|             if msg['type'] in ('chat', 'normal'): | ||||
| @@ -113,7 +87,7 @@ Here's your first SleekXMPP Bot: | ||||
|  | ||||
|  | ||||
|     if __name__ == '__main__': | ||||
|         # Ideally use optparse or argparse to get JID,  | ||||
|         # Ideally use optparse or argparse to get JID, | ||||
|         # password, and log level. | ||||
|  | ||||
|         logging.basicConfig(level=logging.DEBUG, | ||||
| @@ -121,15 +95,24 @@ Here's your first SleekXMPP Bot: | ||||
|  | ||||
|         xmpp = EchoBot('somejid@example.com', 'use_getpass') | ||||
|         xmpp.connect() | ||||
|         xmpp.process(block=True) | ||||
|         xmpp.process() | ||||
|  | ||||
|  | ||||
| To read if you come from SleekXMPP | ||||
| ---------------------------------- | ||||
|  | ||||
| .. toctree:: | ||||
|     :maxdepth: 1 | ||||
|  | ||||
|     differences | ||||
|     using_asyncio | ||||
|  | ||||
|  | ||||
| Getting Started (with Examples) | ||||
| ------------------------------- | ||||
| .. toctree:: | ||||
|     :maxdepth: 1 | ||||
|      | ||||
|  | ||||
|     getting_started/echobot | ||||
|     getting_started/sendlogout | ||||
|     getting_started/component | ||||
| @@ -144,8 +127,7 @@ Tutorials, FAQs, and How To Guides | ||||
| ---------------------------------- | ||||
| .. toctree:: | ||||
|     :maxdepth: 1 | ||||
|     | ||||
|     faq | ||||
|  | ||||
|     xeps | ||||
|     xmpp_tdg | ||||
|     howto/stanzas | ||||
| @@ -156,12 +138,12 @@ Tutorials, FAQs, and How To Guides | ||||
|  | ||||
| Plugin Guides | ||||
| ~~~~~~~~~~~~~ | ||||
| .. toctree::  | ||||
| .. toctree:: | ||||
|     :maxdepth: 1 | ||||
|  | ||||
|     guide_xep_0030 | ||||
|  | ||||
| SleekXMPP Architecture and Design | ||||
| Slixmpp Architecture and Design | ||||
| --------------------------------- | ||||
| .. toctree:: | ||||
|     :maxdepth: 3 | ||||
| @@ -173,7 +155,7 @@ API Reference | ||||
| ------------- | ||||
| .. toctree:: | ||||
|     :maxdepth: 2 | ||||
|      | ||||
|  | ||||
|     event_index | ||||
|     api/clientxmpp | ||||
|     api/componentxmpp | ||||
| @@ -184,9 +166,7 @@ API Reference | ||||
|     api/xmlstream/handler | ||||
|     api/xmlstream/matcher | ||||
|     api/xmlstream/xmlstream | ||||
|     api/xmlstream/scheduler | ||||
|     api/xmlstream/tostring | ||||
|     api/xmlstream/filesocket | ||||
|  | ||||
| Core Stanzas | ||||
| ~~~~~~~~~~~~ | ||||
| @@ -197,8 +177,6 @@ Core Stanzas | ||||
|     api/stanza/message | ||||
|     api/stanza/presence | ||||
|     api/stanza/iq | ||||
|     api/stanza/error | ||||
|     api/stanza/stream_error | ||||
|  | ||||
| Plugins | ||||
| ~~~~~~~ | ||||
| @@ -220,8 +198,14 @@ Additional Info | ||||
| * :ref:`modindex` | ||||
| * :ref:`search` | ||||
|  | ||||
| Credits | ||||
| ------- | ||||
| SleekXMPP Credits | ||||
| ----------------- | ||||
|  | ||||
| .. note:: | ||||
|     Those people made SleekXMPP, so you should not bother them if | ||||
|     you have an issue with slixmpp. But it’s still fair to credit | ||||
|     them for their work. | ||||
|  | ||||
|  | ||||
| **Main Author:** `Nathan Fritz <http://andyet.net/team/fritzy>`_ | ||||
|      `fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_, | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| .. _license:  | ||||
| .. _license: | ||||
|  | ||||
| License (MIT) | ||||
| ============= | ||||
|   | ||||
| @@ -95,9 +95,9 @@ if "%1" == "qthelp" ( | ||||
| 	echo. | ||||
| 	echo.Build finished; now you can run "qcollectiongenerator" with the ^ | ||||
| .qhcp project file in %BUILDDIR%/qthelp, like this: | ||||
| 	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SleekXMPP.qhcp | ||||
| 	echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Slixmpp.qhcp | ||||
| 	echo.To view the help file: | ||||
| 	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SleekXMPP.ghc | ||||
| 	echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Slixmpp.ghc | ||||
| 	goto end | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										148
									
								
								docs/using_asyncio.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								docs/using_asyncio.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| .. _using_asyncio: | ||||
|  | ||||
| ============= | ||||
| Using asyncio | ||||
| ============= | ||||
|  | ||||
| Block on IQ sending | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| :meth:`.Iq.send` now returns a :class:`~.Future` so you can easily block with: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     result = yield from iq.send() | ||||
|  | ||||
| .. warning:: | ||||
|  | ||||
|     If the reply is an IQ with an ``error`` type, this will raise an | ||||
|     :class:`.IqError`, and if it timeouts, it will raise an | ||||
|     :class:`.IqTimeout`. Don't forget to catch it. | ||||
|  | ||||
| You can still use callbacks instead. | ||||
|  | ||||
| XEP plugin integration | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| The same changes from the SleekXMPP API apply, so you can do: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     iq_info = yield from self.xmpp['xep_0030'].get_info(jid) | ||||
|  | ||||
| But the following will only return a Future: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     iq_info = self.xmpp['xep_0030'].get_info(jid) | ||||
|  | ||||
|  | ||||
| Callbacks, Event Handlers, and Stream Handlers | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| IQ callbacks and :term:`Event Handlers <event handler>` can be coroutine | ||||
| functions; in this case, they will be scheduled in the event loop using | ||||
| :meth:`.asyncio.async` and not ran immediately. | ||||
|  | ||||
| A :class:`.CoroutineCallback` class has been added as well for | ||||
| :term:`Stream Handlers <stream handler>`, which will use | ||||
| :meth:`.asyncio.async` to schedule the callback. | ||||
|  | ||||
| Running the event loop | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| :meth:`.XMLStream.process` is only a thin wrapper on top of | ||||
| ``loop.run_forever()`` (if ``timeout`` is provided then it will | ||||
| only run for this amount of time, and if ``forever`` is False it will | ||||
| run until disconnection). | ||||
|  | ||||
| Therefore you can handle the event loop in any way you like | ||||
| instead of using ``process()``. | ||||
|  | ||||
|  | ||||
| Examples | ||||
| ~~~~~~~~ | ||||
|  | ||||
| Blocking until the session is established | ||||
| ----------------------------------------- | ||||
|  | ||||
| This code blocks until the XMPP session is fully established, which | ||||
| can be useful to make sure external events aren’t triggering XMPP | ||||
| callbacks while everything is not ready. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import asyncio, slixmpp | ||||
|  | ||||
|     client = slixmpp.ClientXMPP('jid@example', 'password') | ||||
|     client.connected_event = asyncio.Event() | ||||
|     callback = lambda _: client.connected_event.set() | ||||
|     client.add_event_handler('session_start', callback) | ||||
|     client.connect() | ||||
|     loop.run_until_complete(event.wait()) | ||||
|     # do some other stuff before running the event loop, e.g. | ||||
|     # loop.run_until_complete(httpserver.init()) | ||||
|     client.process() | ||||
|  | ||||
|  | ||||
| Use with other asyncio-based libraries | ||||
| -------------------------------------- | ||||
|  | ||||
| This code interfaces with aiohttp to retrieve two pages asynchronously | ||||
| when the session is established, and then send the HTML content inside | ||||
| a simple <message>. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import asyncio, aiohttp, slixmpp | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def get_pythonorg(event): | ||||
|         req = yield from aiohttp.request('get', 'http://www.python.org') | ||||
|         text = yield from req.text | ||||
|         client.send_message(mto='jid2@example', mbody=text) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def get_asyncioorg(event): | ||||
|         req = yield from aiohttp.request('get', 'http://www.asyncio.org') | ||||
|         text = yield from req.text | ||||
|         client.send_message(mto='jid3@example', mbody=text) | ||||
|  | ||||
|     client = slixmpp.ClientXMPP('jid@example', 'password') | ||||
|     client.add_event_handler('session_start', get_pythonorg) | ||||
|     client.add_event_handler('session_start', get_asyncioorg) | ||||
|     client.connect() | ||||
|     client.process() | ||||
|  | ||||
|  | ||||
| Blocking Iq | ||||
| ----------- | ||||
|  | ||||
| This client checks (via XEP-0092) the software used by every entity it | ||||
| receives a message from. After this, it sends a message to a specific | ||||
| JID indicating its findings. | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|     import asyncio, slixmpp | ||||
|  | ||||
|     class ExampleClient(slixmpp.ClientXMPP): | ||||
|         def __init__(self, *args, **kwargs): | ||||
|             slixmpp.ClientXMPP.__init__(self, *args, **kwargs) | ||||
|             self.register_plugin('xep_0092') | ||||
|             self.add_event_handler('message', self.on_message) | ||||
|  | ||||
|         @asyncio.coroutine | ||||
|         def on_message(self, event): | ||||
|             # You should probably handle IqError and IqTimeout exceptions here | ||||
|             # but this is an example. | ||||
|             version = yield from self['xep_0092'].get_version(message['from']) | ||||
|             text = "%s sent me a message, he runs %s" % (message['from'], | ||||
|                                                          version['software_version']['name']) | ||||
|             self.send_message(mto='master@example.tld', mbody=text) | ||||
|  | ||||
|     client = ExampleClient('jid@example', 'password') | ||||
|     client.connect() | ||||
|     client.process() | ||||
|  | ||||
|  | ||||
| @@ -4,9 +4,9 @@ Supported XEPS | ||||
| ======= ============================= ================ | ||||
| XEP     Description                   Notes | ||||
| ======= ============================= ================ | ||||
| `0004`_ Data forms                    | ||||
| `0009`_ Jabber RPC                    | ||||
| `0012`_ Last Activity              | ||||
| `0004`_ Data forms | ||||
| `0009`_ Jabber RPC | ||||
| `0012`_ Last Activity | ||||
| `0030`_ Service Discovery | ||||
| `0033`_ Extended Stanza Addressing | ||||
| `0045`_ Multi-User Chat (MUC)         Client-side only | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| Following *XMPP: The Definitive Guide* | ||||
| ====================================== | ||||
|  | ||||
| SleekXMPP was featured in the first edition of the O'Reilly book  | ||||
| Slixmpp was featured in the first edition of the O'Reilly book | ||||
| `XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_ | ||||
| by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code | ||||
| for the book's examples can be found at http://github.com/remko/xmpp-tdg. An | ||||
| updated version of the source code, maintained to stay current with the latest | ||||
| SleekXMPP release, is available at http://github.com/legastero/xmpp-tdg. | ||||
| Slixmpp release, is available at http://github.com/legastero/xmpp-tdg. | ||||
|  | ||||
| However, since publication, SleekXMPP has advanced from version 0.2.1 to version | ||||
| However, since publication, Slixmpp has advanced from version 0.2.1 to version | ||||
| 1.0 and there have been several major API changes. The most notable is the | ||||
| introduction of :term:`stanza objects <stanza object>` which have simplified and | ||||
| standardized interactions with the XMPP XML stream. | ||||
|  | ||||
| What follows is a walk-through of *The Definitive Guide* highlighting the | ||||
| changes needed to make the code examples work with version 1.0 of SleekXMPP. | ||||
| changes needed to make the code examples work with version 1.0 of Slixmpp. | ||||
| These changes have been kept to a minimum to preserve the correlation with | ||||
| the book's explanations, so be aware that some code may not use current best | ||||
| practices. | ||||
| @@ -36,7 +36,7 @@ Updated Code | ||||
| .. code-block:: python | ||||
|  | ||||
|     def handleIncomingMessage(self, message): | ||||
|         self.xmpp.sendMessage(message["from"], message["body"]) | ||||
|         self.xmpp.send_message(message["from"], message["body"]) | ||||
|  | ||||
| `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ | | ||||
| `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ | ||||
| @@ -47,7 +47,7 @@ Example 14-1. (Page 215) | ||||
| **CheshiR IM bot implementation.** | ||||
|  | ||||
| The main event handling method in the Bot class is meant to process both message | ||||
| events and presence update events. With the new changes in SleekXMPP 1.0, | ||||
| events and presence update events. With the new changes in Slixmpp 1.0, | ||||
| extracting a CheshiR status "message" from both types of stanzas | ||||
| requires accessing different attributes. In the case of a message stanza, the | ||||
| ``"body"`` attribute would contain the CheshiR message. For a presence event, | ||||
| @@ -72,21 +72,21 @@ Updated Code | ||||
| .. code-block:: python | ||||
|  | ||||
|   def handleIncomingXMPPEvent(self, event): | ||||
|     msgLocations = {sleekxmpp.stanza.presence.Presence: "status", | ||||
|                     sleekxmpp.stanza.message.Message: "body"} | ||||
|     msgLocations = {slixmpp.stanza.presence.Presence: "status", | ||||
|                     slixmpp.stanza.message.Message: "body"} | ||||
|  | ||||
|     message = event[msgLocations[type(event)]] | ||||
|     user = self.backend.getUserFromJID(event["from"].jid) | ||||
|     if user is not None: | ||||
|       self.backend.addMessageFromUser(message, user) | ||||
|    | ||||
|  | ||||
|   def handleMessageAddedToBackend(self, message) : | ||||
|     body = message.user + ": " + message.text | ||||
|     htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % { | ||||
|       "uri": self.url + "/" + message.user, | ||||
|       "user" : message.user, "message" : message.text } | ||||
|     for subscriberJID in self.backend.getSubscriberJIDs(message.user) : | ||||
|       self.xmpp.sendMessage(subscriberJID, body, mhtml=htmlBody) | ||||
|       self.xmpp.send_message(subscriberJID, body, mhtml=htmlBody) | ||||
|  | ||||
| `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ | | ||||
| `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ | ||||
| @@ -102,7 +102,7 @@ Example 14-3. (Page 217) | ||||
|  | ||||
| The main difference for the configurable IM bot is the handling for the | ||||
| data form in ``handleConfigurationCommand``. The test for equality | ||||
| with the string ``"1"`` is no longer required; SleekXMPP converts | ||||
| with the string ``"1"`` is no longer required; Slixmpp converts | ||||
| boolean data form fields to the values ``True`` and ``False`` | ||||
| automatically. | ||||
|  | ||||
| @@ -145,7 +145,7 @@ Example 14-4. (Page 220) | ||||
|  | ||||
| Like several previous examples, a needed change is to replace | ||||
| ``subscription["from"]`` with ``subscription["from"].jid`` because the | ||||
| ``BaseXMPP`` method ``makePresence`` requires the JID to be a string. | ||||
| ``BaseXMPP`` method ``make_presence`` requires the JID to be a string. | ||||
|  | ||||
| A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was | ||||
| left out of the original implementation; the variable ``user`` is undefined. The | ||||
| @@ -154,7 +154,7 @@ JID of the user can be extracted from the presence stanza's ``from`` attribute. | ||||
| Since this implementation of CheshiR uses an XMPP component, it must | ||||
| include a ``from`` attribute in all messages that it sends. Adding the | ||||
| ``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to | ||||
| ``self.xmpp.sendMessage``. | ||||
| ``self.xmpp.send_message``. | ||||
|  | ||||
| Updated Code | ||||
| ~~~~~~~~~~~~ | ||||
| @@ -162,19 +162,19 @@ Updated Code | ||||
| .. code-block:: python | ||||
|  | ||||
|   def handleXMPPPresenceProbe(self, event) : | ||||
|     self.xmpp.sendPresence(pto = event["from"]) | ||||
|     self.xmpp.send_presence(pto = event["from"]) | ||||
|  | ||||
|   def handleXMPPPresenceSubscription(self, subscription) : | ||||
|     if subscription["type"] == "subscribe" : | ||||
|       userJID = subscription["from"].jid | ||||
|       self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribed") | ||||
|       self.xmpp.sendPresence(pto = userJID) | ||||
|       self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribe") | ||||
|       self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribed") | ||||
|       self.xmpp.send_presence(pto = userJID) | ||||
|       self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribe") | ||||
|  | ||||
|   def handleMessageAddedToBackend(self, message) : | ||||
|     body = message.user + ": " + message.text | ||||
|     for subscriberJID in self.backend.getSubscriberJIDs(message.user) : | ||||
|       self.xmpp.sendMessage(subscriberJID, body, mfrom=self.xmpp.jid) | ||||
|       self.xmpp.send_message(subscriberJID, body, mfrom=self.xmpp.jid) | ||||
|  | ||||
| `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ | | ||||
| `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ | ||||
| @@ -192,7 +192,7 @@ After applying the changes from Example 14-4 above, the registrable component | ||||
| implementation should work correctly. | ||||
|  | ||||
| .. tip:: | ||||
|     To see how to implement in-band registration as a SleekXMPP plugin, | ||||
|     To see how to implement in-band registration as a Slixmpp plugin, | ||||
|     see the tutorial :ref:`tutorial-create-plugin`. | ||||
|  | ||||
| `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ | | ||||
| @@ -203,13 +203,13 @@ Example 14-7. (Page 225) | ||||
| **Extended CheshiR IM server component implementation.** | ||||
|  | ||||
| .. note:: | ||||
|     Since the CheshiR examples build on each other, see previous  | ||||
|     Since the CheshiR examples build on each other, see previous | ||||
|     sections for corrections to code that is not marked as new in the book | ||||
|     example. | ||||
|  | ||||
| While the final code example can look daunting with all of the changes | ||||
| made, it requires very few modifications to work with the latest version of | ||||
| SleekXMPP. Most differences are the result of CheshiR's backend functions | ||||
| Slixmpp. Most differences are the result of CheshiR's backend functions | ||||
| expecting JIDs to be strings so that they can be stripped to bare JIDs. To | ||||
| resolve these, use the ``jid`` attribute of the JID objects. Also, | ||||
| references to ``"message"`` and ``"jid"`` attributes need to | ||||
| @@ -239,11 +239,11 @@ Updated Code | ||||
|       userJID = subscription["from"].jid | ||||
|       user = self.backend.getUserFromJID(userJID) | ||||
|       contactJID = subscription["to"] | ||||
|       self.xmpp.sendPresenceSubscription( | ||||
|       self.xmpp.send_presence_subscription( | ||||
|           pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user) | ||||
|       self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID) | ||||
|       if contactJID == self.componentDomain : | ||||
|         self.sendAllContactSubscriptionRequestsToUser(userJID) | ||||
|  | ||||
| `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ | | ||||
| `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_  | ||||
| `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ | ||||
|   | ||||
							
								
								
									
										182
									
								
								examples/IoT_TestDevice.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										182
									
								
								examples/IoT_TestDevice.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,182 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Implementation of xeps for Internet of Things | ||||
|     http://wiki.xmpp.org/web/Tech_pages/IoT_systems | ||||
|     Copyright (C) 2013 Sustainable Innovation, Joachim.lindborg@sust.se | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from os.path import basename, join as pjoin | ||||
| from argparse import ArgumentParser | ||||
| from urllib import urlopen | ||||
| from getpass import getpass | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.plugins.xep_0323.device import Device | ||||
|  | ||||
| #from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
| class IoT_TestDevice(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple IoT device that can act as server or client | ||||
|     """ | ||||
|     def __init__(self, jid, password): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         self.add_event_handler("session_start", self.session_start) | ||||
|         self.add_event_handler("message", self.message) | ||||
|         self.device=None | ||||
|         self.releaseMe=False | ||||
|         self.beServer=True | ||||
|         self.clientJID=None | ||||
|  | ||||
|     def datacallback(self,from_jid,result,nodeId=None,timestamp=None,fields=None,error_msg=None): | ||||
|         """ | ||||
|         This method will be called when you ask another IoT device for data with the xep_0323 | ||||
|         se script below for the registration of the callback | ||||
|         """ | ||||
|         logging.debug("we got data %s from %s",str(result),from_jid) | ||||
|  | ||||
|     def beClientOrServer(self,server=True,clientJID=None ): | ||||
|         if server: | ||||
|             self.beServer=True | ||||
|             self.clientJID=None | ||||
|         else: | ||||
|             self.beServer=False | ||||
|             self.clientJID=clientJID | ||||
|  | ||||
|     def testForRelease(self): | ||||
|         # todo thread safe | ||||
|         return self.releaseMe | ||||
|  | ||||
|     def doReleaseMe(self): | ||||
|         # todo thread safe | ||||
|         self.releaseMe=True | ||||
|  | ||||
|     def addDevice(self, device): | ||||
|         self.device=device | ||||
|  | ||||
|     def session_start(self, event): | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         # tell your preffered friend that you are alive | ||||
|         self.send_message(mto='jocke@jabber.sust.se', mbody=self.boundjid.bare +' is now online use xep_323 stanza to talk to me') | ||||
|  | ||||
|         if not(self.beServer): | ||||
|             session=self['xep_0323'].request_data(self.boundjid.full,self.clientJID,self.datacallback) | ||||
|  | ||||
|     def message(self, msg): | ||||
|         if msg['type'] in ('chat', 'normal'): | ||||
|             logging.debug("got normal chat message" + str(msg)) | ||||
|             ip=urlopen('http://icanhazip.com').read() | ||||
|             msg.reply("Hi I am " + self.boundjid.full + " and I am on IP " + ip).send() | ||||
|         else: | ||||
|             logging.debug("got unknown message type %s", str(msg['type'])) | ||||
|  | ||||
| class TheDevice(Device): | ||||
|     """ | ||||
|     This is the actual device object that you will use to get information from your real hardware | ||||
|     You will be called in the refresh method when someone is requesting information from you | ||||
|     """ | ||||
|     def __init__(self,nodeId): | ||||
|         Device.__init__(self,nodeId) | ||||
|         self.counter=0 | ||||
|  | ||||
|     def refresh(self,fields): | ||||
|         """ | ||||
|         the implementation of the refresh method | ||||
|         """ | ||||
|         self._set_momentary_timestamp(self._get_timestamp()) | ||||
|         self.counter+=self.counter | ||||
|         self._add_field_momentary_data(self, "Temperature", self.counter) | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|  | ||||
|     # Setup the command line arguments. | ||||
|     # | ||||
|     # This script can act both as | ||||
|     #   "server" an IoT device that can provide sensorinformation | ||||
|     #   python IoT_TestDevice.py -j "serverjid@yourdomain.com" -p "password" -n "TestIoT" --debug | ||||
|     # | ||||
|     #   "client" an IoT device or other party that would like to get data from another device | ||||
|  | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|     parser.add_argument("-t", "--pingto", help="set jid to ping", | ||||
|                         action="store", type="string", dest="pingjid", | ||||
|                         default=None) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # IoT test | ||||
|     parser.add_argument("-c", "--sensorjid", dest="sensorjid", | ||||
|                         help="Another device to call for data on", default=None) | ||||
|     parser.add_argument("-n", "--nodeid", dest="nodeid", | ||||
|                         help="I am a device get ready to be called", default=None) | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|      # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|  | ||||
|     xmpp = IoT_TestDevice(args.jid,args.password) | ||||
|     xmpp.register_plugin('xep_0030') | ||||
|     #xmpp['xep_0030'].add_feature(feature='urn:xmpp:iot:sensordata', | ||||
|     #                             node=None, | ||||
|     #    jid=None) | ||||
|     xmpp.register_plugin('xep_0323') | ||||
|     xmpp.register_plugin('xep_0325') | ||||
|  | ||||
|     if args.nodeid: | ||||
|  | ||||
|         # xmpp['xep_0030'].add_feature(feature='urn:xmpp:sn', | ||||
|         # node=args.nodeid, | ||||
|         # jid=xmpp.boundjid.full) | ||||
|  | ||||
|         myDevice = TheDevice(args.nodeid); | ||||
|         # myDevice._add_field(name="Relay", typename="numeric", unit="Bool"); | ||||
|         myDevice._add_field(name="Temperature", typename="numeric", unit="C") | ||||
|         myDevice._set_momentary_timestamp("2013-03-07T16:24:30") | ||||
|         myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}) | ||||
|  | ||||
|         xmpp['xep_0323'].register_node(nodeId=args.nodeid, device=myDevice, commTimeout=10); | ||||
|         xmpp.beClientOrServer(server=True) | ||||
|         while not(xmpp.testForRelease()): | ||||
|             xmpp.connect() | ||||
|             xmpp.process(block=True) | ||||
|             logging.debug("lost connection") | ||||
|     if args.sensorjid: | ||||
|         logging.debug("will try to call another device for data") | ||||
|         xmpp.beClientOrServer(server=False,clientJID=args.sensorjid) | ||||
|         xmpp.connect() | ||||
|         xmpp.process(block=True) | ||||
|         logging.debug("ready ending") | ||||
|  | ||||
|     else: | ||||
|        print("noopp didn't happen") | ||||
|  | ||||
| @@ -1,41 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class CommandBot(sleekxmpp.ClientXMPP): | ||||
| class CommandBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that provides a basic | ||||
|     A simple Slixmpp bot that provides a basic | ||||
|     adhoc command. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -44,7 +33,7 @@ class CommandBot(sleekxmpp.ClientXMPP): | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -58,7 +47,7 @@ class CommandBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         # We add the command after session_start has fired | ||||
|         # to ensure that the correct full JID is used. | ||||
| @@ -79,7 +68,7 @@ class CommandBot(sleekxmpp.ClientXMPP): | ||||
|                        session. Additional, custom data may be saved | ||||
|                        here to persist across handler callbacks. | ||||
|         """ | ||||
|         form = self['xep_0004'].makeForm('form', 'Greeting') | ||||
|         form = self['xep_0004'].make_form('form', 'Greeting') | ||||
|         form['instructions'] = 'Send a custom greeting to a JID' | ||||
|         form.addField(var='greeting', | ||||
|                       ftype='text-single', | ||||
| @@ -143,62 +132,42 @@ class CommandBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the CommandBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = CommandBot(opts.jid, opts.password) | ||||
|     xmpp = CommandBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0050') # Adhoc Commands | ||||
|     xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15}) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
| @@ -1,41 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class CommandUserBot(sleekxmpp.ClientXMPP): | ||||
| class CommandUserBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that uses the adhoc command | ||||
|     A simple Slixmpp bot that uses the adhoc command | ||||
|     provided by the adhoc_provider.py example. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, other, greeting): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.command_provider = other | ||||
|         self.greeting = greeting | ||||
| @@ -48,7 +37,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP): | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -62,7 +51,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         # We first create a session dictionary containing: | ||||
|         #   'next'  -- the handler to execute on a successful response | ||||
| @@ -105,7 +94,7 @@ class CommandUserBot(sleekxmpp.ClientXMPP): | ||||
|         #          label="Your greeting" /> | ||||
|         # </x> | ||||
|  | ||||
|         form = self['xep_0004'].makeForm(ftype='submit') | ||||
|         form = self['xep_0004'].make_form(ftype='submit') | ||||
|         form.addField(var='greeting', | ||||
|                       value=session['greeting']) | ||||
|  | ||||
| @@ -142,69 +131,49 @@ class CommandUserBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-o", "--other", dest="other", | ||||
|                     help="JID providing commands") | ||||
|     optp.add_option("-g", "--greeting", dest="greeting", | ||||
|                     help="Greeting") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-o", "--other", dest="other", | ||||
|                         help="JID providing commands") | ||||
|     parser.add_argument("-g", "--greeting", dest="greeting", | ||||
|                         help="Greeting") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.other is None: | ||||
|         opts.other = raw_input("JID Providing Commands: ") | ||||
|     if opts.greeting is None: | ||||
|         opts.greeting = raw_input("Greeting: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.other is None: | ||||
|         args.other = input("JID Providing Commands: ") | ||||
|     if args.greeting is None: | ||||
|         args.greeting = input("Greeting: ") | ||||
|  | ||||
|     # Setup the CommandBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = CommandUserBot(opts.jid, opts.password, opts.other, opts.greeting) | ||||
|     xmpp = CommandUserBot(args.jid, args.password, args.other, args.greeting) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0050') # Adhoc Commands | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										147
									
								
								examples/admin_commands.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										147
									
								
								examples/admin_commands.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class AdminCommands(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple Slixmpp bot that uses admin commands to | ||||
|     add a new user to a server. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, command): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.command = command | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         def command_success(iq, session): | ||||
|             print('Command completed') | ||||
|             if iq['command']['form']: | ||||
|                 for var, field in iq['command']['form']['fields'].items(): | ||||
|                     print('%s: %s' % (var, field['value'])) | ||||
|             if iq['command']['notes']: | ||||
|                 print('Command Notes:') | ||||
|                 for note in iq['command']['notes']: | ||||
|                     print('%s: %s' % note) | ||||
|             self.disconnect() | ||||
|  | ||||
|         def command_error(iq, session): | ||||
|             print('Error completing command') | ||||
|             print('%s: %s' % (iq['error']['condition'], | ||||
|                               iq['error']['text'])) | ||||
|             self['xep_0050'].terminate_command(session) | ||||
|             self.disconnect() | ||||
|  | ||||
|         def process_form(iq, session): | ||||
|             form = iq['command']['form'] | ||||
|             answers = {} | ||||
|             for var, field in form['fields'].items(): | ||||
|                 if var != 'FORM_TYPE': | ||||
|                     if field['type'] == 'boolean': | ||||
|                         answers[var] = input('%s (y/n): ' % field['label']) | ||||
|                         if answers[var].lower() in ('1', 'true', 'y', 'yes'): | ||||
|                             answers[var] = '1' | ||||
|                         else: | ||||
|                             answers[var] = '0' | ||||
|                     else: | ||||
|                         answers[var] = input('%s: ' % field['label']) | ||||
|                 else: | ||||
|                     answers['FORM_TYPE'] = field['value'] | ||||
|             form['type'] = 'submit' | ||||
|             form['values'] = answers | ||||
|  | ||||
|             session['next'] = command_success | ||||
|             session['payload'] = form | ||||
|  | ||||
|             self['xep_0050'].complete_command(session) | ||||
|  | ||||
|         session = {'next': process_form, | ||||
|                    'error': command_error} | ||||
|  | ||||
|         command = self.command.replace('-', '_') | ||||
|         handler = getattr(self['xep_0133'], command, None) | ||||
|  | ||||
|         if handler: | ||||
|             handler(session={ | ||||
|                 'next': process_form, | ||||
|                 'error': command_error | ||||
|             }) | ||||
|         else: | ||||
|             print('Invalid command name: %s' % self.command) | ||||
|             self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-c", "--command", dest="command", | ||||
|                         help="admin command to use") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.command is None: | ||||
|         args.command = input("Admin command: ") | ||||
|  | ||||
|     # Setup the CommandBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = AdminCommands(args.jid, args.password, args.command) | ||||
|     xmpp.register_plugin('xep_0133') # Service Administration | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
							
								
								
									
										99
									
								
								examples/confirm_answer.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										99
									
								
								examples/confirm_answer.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015 Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class AnswerConfirm(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client demonstrating how to confirm or deny an HTTP request. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, trusted): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.add_event_handler("http_confirm", self.confirm) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, *args): | ||||
|         self.make_presence().send() | ||||
|  | ||||
|     def prompt(self, stanza): | ||||
|         confirm = stanza['confirm'] | ||||
|         print('Received confirm request %s from %s to access %s using ' | ||||
|                  'method %s' % ( | ||||
|                      confirm['id'], stanza['from'], confirm['url'], | ||||
|                      confirm['method']) | ||||
|                 ) | ||||
|         result = input("Do you accept (y/N)? ") | ||||
|         return 'y' == result.lower() | ||||
|  | ||||
|     def confirm(self, stanza): | ||||
|         if self.prompt(stanza): | ||||
|             reply = stanza.reply() | ||||
|         else: | ||||
|             reply = stanza.reply() | ||||
|             reply.enable('error') | ||||
|             reply['error']['type'] = 'auth' | ||||
|             reply['error']['code'] = '401' | ||||
|             reply['error']['condition'] = 'not-authorized' | ||||
|         reply.append(stanza['confirm']) | ||||
|         reply.send() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options. | ||||
|     parser.add_argument("-t", "--trusted", nargs='*', | ||||
|                         help="List of trusted JIDs") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = AnswerConfirm(args.jid, args.password, args.trusted) | ||||
|     xmpp.register_plugin('xep_0070') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
							
								
								
									
										124
									
								
								examples/confirm_ask.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										124
									
								
								examples/confirm_ask.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015 Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError, IqError | ||||
| from slixmpp import asyncio | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class AskConfirm(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client asking an entity if they confirm the access to an HTTP URL. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, recipient, id, url, method): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.recipient = recipient | ||||
|         self.id = id | ||||
|         self.url = url | ||||
|         self.method = method | ||||
|  | ||||
|         # Will be used to set the proper exit code. | ||||
|         self.confirmed = asyncio.Future() | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("message", self.start) | ||||
|         self.add_event_handler("http_confirm_message", self.confirm) | ||||
|  | ||||
|     def confirm(self, message): | ||||
|         print(message) | ||||
|         if message['confirm']['id'] == self.id: | ||||
|             if message['type'] == 'error': | ||||
|                 self.confirmed.set_result(False) | ||||
|             else: | ||||
|                 self.confirmed.set_result(True) | ||||
|  | ||||
|     async def start(self, event): | ||||
|         log.info('Sending confirm request %s to %s who wants to access %s using ' | ||||
|                  'method %s...' % (self.id, self.recipient, self.url, self.method)) | ||||
|         try: | ||||
|             confirmed = await self['xep_0070'].ask_confirm(self.recipient, | ||||
|                                                                 id=self.id, | ||||
|                                                                 url=self.url, | ||||
|                                                                 method=self.method, | ||||
|                                                                 message='Plz say yes or no for {method} {url} ({id}).') | ||||
|             if isinstance(confirmed, slixmpp.Message): | ||||
|                 confirmed = await self.confirmed | ||||
|             else: | ||||
|                 confirmed = True | ||||
|         except IqError: | ||||
|             confirmed = False | ||||
|         if confirmed: | ||||
|             print('Confirmed') | ||||
|         else: | ||||
|             print('Denied') | ||||
|         self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options. | ||||
|     parser.add_argument("-r", "--recipient", required=True, | ||||
|                         help="Recipient JID") | ||||
|     parser.add_argument("-i", "--id", required=True, | ||||
|                         help="id TODO") | ||||
|     parser.add_argument("-u", "--url", required=True, | ||||
|                         help="URL the user tried to access") | ||||
|     parser.add_argument("-m", "--method", required=True, | ||||
|                         help="HTTP method used") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = AskConfirm(args.jid, args.password, args.recipient, args.id, | ||||
|                       args.url, args.method) | ||||
|     xmpp.register_plugin('xep_0070') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|     sys.exit(0 if xmpp.confirmed else 1) | ||||
| @@ -1,48 +1,37 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| import slixmpp | ||||
|  | ||||
| from sleekxmpp import ClientXMPP, Iq | ||||
| from sleekxmpp.exceptions import IqError, IqTimeout, XMPPError | ||||
| from sleekxmpp.xmlstream import register_stanza_plugin | ||||
| from sleekxmpp.xmlstream.handler import Callback | ||||
| from sleekxmpp.xmlstream.matcher import StanzaPath | ||||
| from slixmpp import ClientXMPP, Iq | ||||
| from slixmpp.exceptions import IqError, IqTimeout, XMPPError | ||||
| from slixmpp.xmlstream import register_stanza_plugin | ||||
| from slixmpp.xmlstream.handler import Callback | ||||
| from slixmpp.xmlstream.matcher import StanzaPath | ||||
| from stanza import Action | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class ActionBot(sleekxmpp.ClientXMPP): | ||||
| class ActionBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that receives a custom stanza | ||||
|     A simple Slixmpp bot that receives a custom stanza | ||||
|     from another client. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -51,18 +40,17 @@ class ActionBot(sleekxmpp.ClientXMPP): | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|         self.registerHandler( | ||||
|         self.register_handler( | ||||
|           Callback('Some custom iq', | ||||
|             StanzaPath('iq@type=set/action'), | ||||
|             self._handle_action)) | ||||
|  | ||||
|         self.add_event_handler('custom_action',  | ||||
|                 self._handle_action_event,  | ||||
|                 threaded=True) | ||||
|         self.add_event_handler('custom_action', | ||||
|                 self._handle_action_event) | ||||
|  | ||||
|         register_stanza_plugin(Iq, Action) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -85,89 +73,68 @@ class ActionBot(sleekxmpp.ClientXMPP): | ||||
|         """ | ||||
|         self.event('custom_action', iq) | ||||
|  | ||||
|     def _handle_action_event(self, iq): | ||||
|     async def _handle_action_event(self, iq): | ||||
|         """ | ||||
|         Respond to the custom action event. | ||||
|  | ||||
|         Since one of the actions is to disconnect, this | ||||
|         event handler needs to be run in threaded mode, by | ||||
|         using `threaded=True` in the `add_event_handler` call. | ||||
|         """ | ||||
|         method = iq['action']['method'] | ||||
|         param = iq['action']['param'] | ||||
|  | ||||
|         if method == 'is_prime' and param == '2': | ||||
|             print("got message: %s" % iq) | ||||
|             iq.reply() | ||||
|             iq['action']['status'] = 'done' | ||||
|             iq.send() | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'done' | ||||
|             await rep.send() | ||||
|         elif method == 'bye': | ||||
|             print("got message: %s" % iq) | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'done' | ||||
|             await rep.send() | ||||
|             self.disconnect() | ||||
|         else: | ||||
|             print("got message: %s" % iq) | ||||
|             iq.reply() | ||||
|             iq['action']['status'] = 'error' | ||||
|             iq.send() | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'error' | ||||
|             await rep.send() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the CommandBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = ActionBot(opts.jid, opts.password) | ||||
|     xmpp = ActionBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0050') # Adhoc Commands | ||||
|     xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency':15}) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
| @@ -1,46 +1,35 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp import Iq | ||||
| from sleekxmpp.exceptions import XMPPError | ||||
| from sleekxmpp.xmlstream import register_stanza_plugin | ||||
| import slixmpp | ||||
| from slixmpp import Iq | ||||
| from slixmpp.exceptions import XMPPError | ||||
| from slixmpp.xmlstream import register_stanza_plugin | ||||
|  | ||||
| from stanza import Action | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class ActionUserBot(sleekxmpp.ClientXMPP): | ||||
| class ActionUserBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that sends a custom action stanza | ||||
|     A simple Slixmpp bot that sends a custom action stanza | ||||
|     to another client. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, other): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.action_provider = other | ||||
|  | ||||
| @@ -49,12 +38,12 @@ class ActionUserBot(sleekxmpp.ClientXMPP): | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|         register_stanza_plugin(Iq, Action) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -68,11 +57,11 @@ class ActionUserBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         self.send_custom_iq() | ||||
|         await self.send_custom_iq() | ||||
|  | ||||
|     def send_custom_iq(self): | ||||
|     async def send_custom_iq(self): | ||||
|         """Create and send two custom actions. | ||||
|  | ||||
|         If the first action was successful, then send | ||||
| @@ -85,18 +74,16 @@ class ActionUserBot(sleekxmpp.ClientXMPP): | ||||
|         iq['action']['param'] = '2' | ||||
|  | ||||
|         try: | ||||
|             resp = iq.send() | ||||
|             resp = await iq.send() | ||||
|             if resp['action']['status'] == 'done': | ||||
|                 #sending bye | ||||
|                 iq2 = self.Iq() | ||||
|                 iq2['to'] = self.action_provider | ||||
|                 iq2['type'] = 'set' | ||||
|                 iq2['action']['method'] = 'bye' | ||||
|                 iq2.send(block=False) | ||||
|              | ||||
|                 # The wait=True delays the disconnect until the queue | ||||
|                 # of stanzas to be sent becomes empty. | ||||
|                 self.disconnect(wait=True) | ||||
|                 await iq2.send() | ||||
|  | ||||
|                 self.disconnect() | ||||
|         except XMPPError: | ||||
|             print('There was an error sending the custom action.') | ||||
|  | ||||
| @@ -111,65 +98,45 @@ class ActionUserBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-o", "--other", dest="other", | ||||
|                     help="JID providing custom stanza") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-o", "--other", dest="other", | ||||
|                         help="JID providing custom stanza") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.other is None: | ||||
|         opts.other = raw_input("JID Providing custom stanza: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.other is None: | ||||
|         args.other = input("JID Providing custom stanza: ") | ||||
|  | ||||
|     # Setup the CommandBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = ActionUserBot(opts.jid, opts.password, opts.other) | ||||
|     xmpp = ActionUserBot(args.jid, args.password, args.other) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0050') # Adhoc Commands | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
| @@ -1,30 +1,30 @@ | ||||
| from sleekxmpp.xmlstream import ElementBase | ||||
| from slixmpp.xmlstream import ElementBase | ||||
|  | ||||
| class Action(ElementBase): | ||||
|  | ||||
|     """ | ||||
|     A stanza class for XML content of the form: | ||||
|  | ||||
|     <action xmlns="sleekxmpp:custom:actions"> | ||||
|     <action xmlns="slixmpp:custom:actions"> | ||||
|       <method>X</method> | ||||
|       <param>X</param> | ||||
|       <status>X</status> | ||||
|     </action> | ||||
|     """ | ||||
|     | ||||
|  | ||||
|     #: The `name` field refers to the basic XML tag name of the | ||||
|     #: stanza. Here, the tag name will be 'action'. | ||||
|     name = 'action' | ||||
|  | ||||
|     #: The namespace of the main XML tag. | ||||
|     namespace = 'sleekxmpp:custom:actions' | ||||
|     namespace = 'slixmpp:custom:actions' | ||||
|  | ||||
|     #: The `plugin_attrib` value is the name that can be used | ||||
|     #: with a parent stanza to access this stanza. For example | ||||
|     #: from an Iq stanza object, accessing: | ||||
|     #:  | ||||
|     #: | ||||
|     #:     iq['action'] | ||||
|     #:  | ||||
|     #: | ||||
|     #: would reference an Action object, and will even create | ||||
|     #: an Action object and append it to the Iq stanza if | ||||
|     #: one doesn't already exist. | ||||
| @@ -41,7 +41,7 @@ class Action(ElementBase): | ||||
|     #:     del action['status'] | ||||
|     #: | ||||
|     #: to set, get, or remove its values. | ||||
|     interfaces = set(('method', 'param', 'status')) | ||||
|     interfaces = {'method', 'param', 'status'} | ||||
|  | ||||
|     #: By default, values in the `interfaces` set are mapped to | ||||
|     #: attribute values. This can be changed such that an interface | ||||
| @@ -49,8 +49,8 @@ class Action(ElementBase): | ||||
|     #: the sub_interfaces set. For example, here all interfaces | ||||
|     #: are marked as sub_interfaces, and so the XML produced will | ||||
|     #: look like: | ||||
|     #:  | ||||
|     #:     <action xmlns="sleekxmpp:custom:actions"> | ||||
|     #: | ||||
|     #:     <action xmlns="slixmpp:custom:actions"> | ||||
|     #:       <method>foo</method> | ||||
|     #:     </action> | ||||
|     sub_interfaces = interfaces | ||||
|   | ||||
| @@ -1,34 +1,23 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class Disco(sleekxmpp.ClientXMPP): | ||||
| class Disco(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A demonstration for using basic service discovery. | ||||
| @@ -41,7 +30,7 @@ class Disco(sleekxmpp.ClientXMPP): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, target_jid, target_node='', get=''): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # Using service discovery requires the XEP-0030 plugin. | ||||
|         self.register_plugin('xep_0030') | ||||
| @@ -62,9 +51,9 @@ class Disco(sleekxmpp.ClientXMPP): | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -80,120 +69,91 @@ class Disco(sleekxmpp.ClientXMPP): | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|         self.send_presence() | ||||
|  | ||||
|         if self.get in self.info_types: | ||||
|             # By using block=True, the result stanza will be | ||||
|             # returned. Execution will block until the reply is | ||||
|             # received. Non-blocking options would be to listen | ||||
|             # for the disco_info event, or passing a handler | ||||
|             # function using the callback parameter. | ||||
|             info = self['xep_0030'].get_info(jid=self.target_jid, | ||||
|                                              node=self.target_node, | ||||
|                                              block=True) | ||||
|         if self.get in self.items_types: | ||||
|             # The same applies from above. Listen for the | ||||
|             # disco_items event or pass a callback function | ||||
|             # if you need to process a non-blocking request. | ||||
|             items = self['xep_0030'].get_items(jid=self.target_jid, | ||||
|                                                node=self.target_node, | ||||
|                                                block=True) | ||||
|         try: | ||||
|             if self.get in self.info_types: | ||||
|                 # function using the callback parameter. | ||||
|                 info = await self['xep_0030'].get_info(jid=self.target_jid, | ||||
|                                                             node=self.target_node) | ||||
|             if self.get in self.items_types: | ||||
|                 # The same applies from above. Listen for the | ||||
|                 # disco_items event or pass a callback function | ||||
|                 # if you need to process a non-blocking request. | ||||
|                 items = await self['xep_0030'].get_items(jid=self.target_jid, | ||||
|                                                               node=self.target_node) | ||||
|             if self.get not in self.info_types and self.get not in self.items_types: | ||||
|                 logging.error("Invalid disco request type.") | ||||
|                 return | ||||
|         except IqError as e: | ||||
|             logging.error("Entity returned an error: %s" % e.iq['error']['condition']) | ||||
|         except IqTimeout: | ||||
|             logging.error("No response received.") | ||||
|         else: | ||||
|             logging.error("Invalid disco request type.") | ||||
|             self.disconnect() | ||||
|             return | ||||
|  | ||||
|         header = 'XMPP Service Discovery: %s' % self.target_jid | ||||
|         print(header) | ||||
|         print('-' * len(header)) | ||||
|         if self.target_node != '': | ||||
|             print('Node: %s' % self.target_node) | ||||
|             header = 'XMPP Service Discovery: %s' % self.target_jid | ||||
|             print(header) | ||||
|             print('-' * len(header)) | ||||
|             if self.target_node != '': | ||||
|                 print('Node: %s' % self.target_node) | ||||
|                 print('-' * len(header)) | ||||
|  | ||||
|         if self.get in self.identity_types: | ||||
|             print('Identities:') | ||||
|             for identity in info['disco_info']['identities']: | ||||
|                 print('  - %s' % str(identity)) | ||||
|             if self.get in self.identity_types: | ||||
|                 print('Identities:') | ||||
|                 for identity in info['disco_info']['identities']: | ||||
|                     print('  - %s' % str(identity)) | ||||
|  | ||||
|         if self.get in self.feature_types: | ||||
|             print('Features:') | ||||
|             for feature in info['disco_info']['features']: | ||||
|                 print('  - %s' % feature) | ||||
|             if self.get in self.feature_types: | ||||
|                 print('Features:') | ||||
|                 for feature in info['disco_info']['features']: | ||||
|                     print('  - %s' % feature) | ||||
|  | ||||
|         if self.get in self.items_types: | ||||
|             print('Items:') | ||||
|             for item in items['disco_items']['items']: | ||||
|                 print('  - %s' % str(item)) | ||||
|  | ||||
|         self.disconnect() | ||||
|             if self.get in self.items_types: | ||||
|                 print('Items:') | ||||
|                 for item in items['disco_items']['items']: | ||||
|                     print('  - %s' % str(item)) | ||||
|         finally: | ||||
|             self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     optp.version = '%%prog 0.1' | ||||
|     optp.usage = "Usage: %%prog [options] %s <jid> [<node>]" % \ | ||||
|                              'all|info|items|identities|features' | ||||
|     parser = ArgumentParser(description=Disco.__doc__) | ||||
|  | ||||
|     optp.add_option('-q','--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.ERROR, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-d','--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.DEBUG, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-v','--verbose', help='set logging to COMM', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=5, | ||||
|                     default=logging.ERROR) | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.ERROR) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.ERROR) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     opts,args = optp.parse_args() | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("query", choices=["all", "info", "items", "identities", "features"]) | ||||
|     parser.add_argument("target_jid") | ||||
|     parser.add_argument("node", nargs='?') | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if len(args) < 2: | ||||
|         optp.print_help() | ||||
|         exit() | ||||
|  | ||||
|     if len(args) == 2: | ||||
|         args = (args[0], args[1], '') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the Disco browser. | ||||
|     xmpp = Disco(opts.jid, opts.password, args[1], args[2], args[0]) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = Disco(args.jid, args.password, args.target_jid, args.node, args.query) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										162
									
								
								examples/download_avatars.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										162
									
								
								examples/download_avatars.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2012  Nathanael C. Fritz | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
| from slixmpp import asyncio | ||||
|  | ||||
|  | ||||
| FILE_TYPES = { | ||||
|     'image/png': 'png', | ||||
|     'image/gif': 'gif', | ||||
|     'image/jpeg': 'jpg' | ||||
| } | ||||
|  | ||||
|  | ||||
| class AvatarDownloader(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic script for downloading the avatars for a user's contacts. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("changed_status", self.wait_for_presences) | ||||
|  | ||||
|         self.add_event_handler('vcard_avatar_update', self.on_vcard_avatar) | ||||
|         self.add_event_handler('avatar_metadata_publish', self.on_avatar) | ||||
|  | ||||
|         self.received = set() | ||||
|         self.presences_received = asyncio.Event() | ||||
|         self.roster_received = asyncio.Event() | ||||
|  | ||||
|     def roster_received_cb(self, event): | ||||
|         self.roster_received.set() | ||||
|         self.presences_received.clear() | ||||
|  | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster(callback=self.roster_received_cb) | ||||
|  | ||||
|         print('Waiting for presence updates...\n') | ||||
|         await self.roster_received.wait() | ||||
|         print('Roster received') | ||||
|         await self.presences_received.wait() | ||||
|         self.disconnect() | ||||
|  | ||||
|     async def on_vcard_avatar(self, pres): | ||||
|         print("Received vCard avatar update from %s" % pres['from'].bare) | ||||
|         try: | ||||
|             result = await self['xep_0054'].get_vcard(pres['from'].bare, cached=True, | ||||
|                                                            timeout=5) | ||||
|         except XMPPError: | ||||
|             print("Error retrieving avatar for %s" % pres['from']) | ||||
|             return | ||||
|         avatar = result['vcard_temp']['PHOTO'] | ||||
|  | ||||
|         filetype = FILE_TYPES.get(avatar['TYPE'], 'png') | ||||
|         filename = 'vcard_avatar_%s_%s.%s' % ( | ||||
|                 pres['from'].bare, | ||||
|                 pres['vcard_temp_update']['photo'], | ||||
|                 filetype) | ||||
|         with open(filename, 'wb+') as img: | ||||
|             img.write(avatar['BINVAL']) | ||||
|  | ||||
|     async def on_avatar(self, msg): | ||||
|         print("Received avatar update from %s" % msg['from']) | ||||
|         metadata = msg['pubsub_event']['items']['item']['avatar_metadata'] | ||||
|         for info in metadata['items']: | ||||
|             if not info['url']: | ||||
|                 try: | ||||
|                     result = await self['xep_0084'].retrieve_avatar(msg['from'].bare, info['id'], | ||||
|                                                                          timeout=5) | ||||
|                 except XMPPError: | ||||
|                     print("Error retrieving avatar for %s" % msg['from']) | ||||
|                     return | ||||
|  | ||||
|                 avatar = result['pubsub']['items']['item']['avatar_data'] | ||||
|  | ||||
|                 filetype = FILE_TYPES.get(metadata['type'], 'png') | ||||
|                 filename = 'avatar_%s_%s.%s' % (msg['from'].bare, info['id'], filetype) | ||||
|                 with open(filename, 'wb+') as img: | ||||
|                     img.write(avatar['value']) | ||||
|             else: | ||||
|                 # We could retrieve the avatar via HTTP, etc here instead. | ||||
|                 pass | ||||
|  | ||||
|     def wait_for_presences(self, pres): | ||||
|         """ | ||||
|         Wait to receive updates from all roster contacts. | ||||
|         """ | ||||
|         self.received.add(pres['from'].bare) | ||||
|         print((len(self.received), len(self.client_roster.keys()))) | ||||
|         if len(self.received) >= len(self.client_roster.keys()): | ||||
|             self.presences_received.set() | ||||
|         else: | ||||
|             self.presences_received.clear() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.ERROR) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.ERROR) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = AvatarDownloader(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0054') | ||||
|     xmpp.register_plugin('xep_0153') | ||||
|     xmpp.register_plugin('xep_0084') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
| @@ -1,41 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class EchoBot(sleekxmpp.ClientXMPP): | ||||
| class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that will echo messages it | ||||
|     A simple Slixmpp bot that will echo messages it | ||||
|     receives, along with a short thank you message. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -49,7 +38,7 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|         # MUC messages and error messages. | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -63,7 +52,7 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
| @@ -83,75 +72,42 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser(description=EchoBot.__doc__) | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = EchoBot(opts.jid, opts.password) | ||||
|     xmpp = EchoBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # If you are connecting to Facebook and wish to use the | ||||
|     # X-FACEBOOK-PLATFORM authentication mechanism, you will need | ||||
|     # your API key and an access token. Then you'll set: | ||||
|     # xmpp.credentials['api_key'] = 'THE_API_KEY' | ||||
|     # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||||
|  | ||||
|     # If you are connecting to MSN, then you will need an | ||||
|     # access token, and it does not matter what JID you | ||||
|     # specify other than that the domain is 'messenger.live.com', | ||||
|     # so '_@messenger.live.com' will work. You can specify | ||||
|     # the access token as so: | ||||
|     # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
| @@ -1,37 +1,26 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.componentxmpp import ComponentXMPP | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
| from slixmpp.componentxmpp import ComponentXMPP | ||||
|  | ||||
|  | ||||
| class EchoComponent(ComponentXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP component that echoes messages. | ||||
|     A simple Slixmpp component that echoes messages. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, secret, server, port): | ||||
| @@ -67,56 +56,50 @@ class EchoComponent(ComponentXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser(description=EchoComponent.__doc__) | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-s", "--server", dest="server", | ||||
|                     help="server to connect to") | ||||
|     optp.add_option("-P", "--port", dest="port", | ||||
|                     help="port to connect to") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-s", "--server", dest="server", | ||||
|                         help="server to connect to") | ||||
|     parser.add_argument("-P", "--port", dest="port", | ||||
|                         help="port to connect to") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Component JID: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.server is None: | ||||
|         opts.server = raw_input("Server: ") | ||||
|     if opts.port is None: | ||||
|         opts.port = int(raw_input("Port: ")) | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Component JID: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.server is None: | ||||
|         args.server = input("Server: ") | ||||
|     if args.port is None: | ||||
|         args.port = int(input("Port: ")) | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     # Setup the EchoComponent and register plugins. Note that while plugins | ||||
|     # may have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = EchoComponent(opts.jid, opts.password, opts.server, opts.port) | ||||
|     xmpp.registerPlugin('xep_0030') # Service Discovery | ||||
|     xmpp.registerPlugin('xep_0004') # Data Forms | ||||
|     xmpp.registerPlugin('xep_0060') # PubSub | ||||
|     xmpp.registerPlugin('xep_0199') # XMPP Ping | ||||
|     xmpp = EchoComponent(args.jid, args.password, args.server, args.port) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
| @@ -1,46 +1,34 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| import slixmpp | ||||
|  | ||||
| import ssl | ||||
| from sleekxmpp.xmlstream import cert | ||||
| from slixmpp.xmlstream import cert | ||||
|  | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class GTalkBot(sleekxmpp.ClientXMPP): | ||||
| class GTalkBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A demonstration of using SleekXMPP with accounts from a Google Apps | ||||
|     A demonstration of using Slixmpp with accounts from a Google Apps | ||||
|     account with a custom domain, because it requires custom certificate | ||||
|     validation. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -67,10 +55,10 @@ class GTalkBot(sleekxmpp.ClientXMPP): | ||||
|             cert.verify('talk.google.com', der_cert) | ||||
|             logging.debug("CERT: Found GTalk certificate") | ||||
|         except cert.CertificateError as err: | ||||
|             log.error(err.message) | ||||
|             self.disconnect(send_close=False) | ||||
|             logging.error(err.message) | ||||
|             self.disconnect() | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -84,7 +72,7 @@ class GTalkBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
| @@ -104,62 +92,42 @@ class GTalkBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the GTalkBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = GTalkBot(opts.jid, opts.password) | ||||
|     xmpp = GTalkBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										97
									
								
								examples/http_over_xmpp.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								examples/http_over_xmpp.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Implementation of HTTP over XMPP transport | ||||
|     http://xmpp.org/extensions/xep-0332.html | ||||
|     Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp import ClientXMPP | ||||
|  | ||||
| from argparse import ArgumentParser | ||||
| import logging | ||||
| import getpass | ||||
|  | ||||
|  | ||||
| class HTTPOverXMPPClient(ClientXMPP): | ||||
|     def __init__(self, jid, password): | ||||
|         ClientXMPP.__init__(self, jid, password) | ||||
|         self.register_plugin('xep_0332')    # HTTP over XMPP Transport | ||||
|         self.add_event_handler( | ||||
|             'session_start', self.session_start | ||||
|         ) | ||||
|         self.add_event_handler('http_request', self.http_request_received) | ||||
|         self.add_event_handler('http_response', self.http_response_received) | ||||
|  | ||||
|     def http_request_received(self, iq): | ||||
|         pass | ||||
|  | ||||
|     def http_response_received(self, iq): | ||||
|         print('HTTP Response Received : %s' % iq) | ||||
|         print('From    : %s' %  iq['from']) | ||||
|         print('To      : %s' % iq['to']) | ||||
|         print('Type    : %s' % iq['type']) | ||||
|         print('Headers : %s' % iq['resp']['headers']) | ||||
|         print('Code    : %s' % iq['resp']['code']) | ||||
|         print('Message : %s' % iq['resp']['message']) | ||||
|         print('Data    : %s' % iq['resp']['data']) | ||||
|  | ||||
|     def session_start(self, event): | ||||
|         # TODO: Fill in the blanks | ||||
|         self['xep_0332'].send_request( | ||||
|             to='?', method='?', resource='?', headers={} | ||||
|         ) | ||||
|         self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|  | ||||
|     # | ||||
|     # NOTE: To run this example, fill up the blanks in session_start() and | ||||
|     #       use the following command. | ||||
|     # | ||||
|     # ./http_over_xmpp.py -J <jid> -P <pwd> -i <ip> -p <port> [-v] | ||||
|     # | ||||
|  | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument( | ||||
|         '-v', '--verbose', help='set logging to DEBUG', action='store_const', | ||||
|         dest='loglevel', const=logging.DEBUG, default=logging.ERROR | ||||
|     ) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument('-J', '--jid', dest='jid', help='JID') | ||||
|     parser.add_argument('-P', '--password', dest='password', help='Password') | ||||
|  | ||||
|     # XMPP server ip and port options. | ||||
|     parser.add_argument( | ||||
|         '-i', '--ipaddr', dest='ipaddr', | ||||
|         help='IP Address of the XMPP server', default=None | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         '-p', '--port', dest='port', | ||||
|         help='Port of the XMPP server', default=None | ||||
|     ) | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input('Username: ') | ||||
|     if args.password is None: | ||||
|         args.password = getpass.getpass('Password: ') | ||||
|  | ||||
|     xmpp = HTTPOverXMPPClient(args.jid, args.password) | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|  | ||||
							
								
								
									
										96
									
								
								examples/http_upload.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										96
									
								
								examples/http_upload.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2018 Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class HttpUpload(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client asking an entity if they confirm the access to an HTTP URL. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, recipient, filename, domain=None): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.recipient = recipient | ||||
|         self.filename = filename | ||||
|         self.domain = domain | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     async def start(self, event): | ||||
|         log.info('Uploading file %s...', self.filename) | ||||
|         def timeout_callback(arg): | ||||
|             raise TimeoutError("could not send message in time") | ||||
|         url = await self['xep_0363'].upload_file( | ||||
|             self.filename, domain=self.domain, timeout=10, timeout_callback=timeout_callback) | ||||
|         log.info('Upload success!') | ||||
|  | ||||
|         log.info('Sending file to %s', self.recipient) | ||||
|         html = '<body xmlns="http://www.w3.org/1999/xhtml"><a href="%s">%s</a></body>' % (url, url) | ||||
|         self.send_message(self.recipient, url, mhtml=html) | ||||
|         self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options. | ||||
|     parser.add_argument("-r", "--recipient", required=True, | ||||
|                         help="Recipient JID") | ||||
|     parser.add_argument("-f", "--file", required=True, | ||||
|                         help="File to send") | ||||
|     parser.add_argument("--domain", | ||||
|                         help="Domain to use for HTTP File Upload (leave out for your own server’s)") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = HttpUpload(args.jid, args.password, args.recipient, args.file, args.domain) | ||||
|     xmpp.register_plugin('xep_0071') | ||||
|     xmpp.register_plugin('xep_0128') | ||||
|     xmpp.register_plugin('xep_0363') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
| @@ -1,45 +1,31 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class IBBReceiver(sleekxmpp.ClientXMPP): | ||||
| class IBBReceiver(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic example of creating and using an in-band bytestream. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|     def __init__(self, jid, password, filename): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.register_plugin('xep_0030') # Service Discovery | ||||
|         self.register_plugin('xep_0047', { | ||||
|             'accept_stream': self.accept_stream | ||||
|         }) # In-band Bytestreams | ||||
|         self.file = open(filename, 'wb') | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -50,6 +36,7 @@ class IBBReceiver(sleekxmpp.ClientXMPP): | ||||
|  | ||||
|         self.add_event_handler("ibb_stream_start", self.stream_opened) | ||||
|         self.add_event_handler("ibb_stream_data", self.stream_data) | ||||
|         self.add_event_handler("ibb_stream_end", self.stream_closed) | ||||
|  | ||||
|     def start(self, event): | ||||
|         """ | ||||
| @@ -67,83 +54,59 @@ class IBBReceiver(sleekxmpp.ClientXMPP): | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|  | ||||
|     def accept_stream(self, iq): | ||||
|         """ | ||||
|         Check that it is ok to accept a stream request.  | ||||
|  | ||||
|         Controlling stream acceptance can be done via either: | ||||
|             - setting 'auto_accept' to False in the plugin | ||||
|               configuration. The default is True. | ||||
|             - setting 'accept_stream' to a function which accepts | ||||
|               an Iq stanza as its argument, like this one. | ||||
|  | ||||
|         The accept_stream function will be used if it exists, and the | ||||
|         auto_accept value will be used otherwise. | ||||
|         """ | ||||
|         return True | ||||
|  | ||||
|     def stream_opened(self, stream): | ||||
|         # NOTE: IBB streams are bi-directional, so the original sender is | ||||
|         # now the opened stream's receiver. | ||||
|         print('Stream opened: %s from ' % (stream.sid, stream.receiver)) | ||||
|         print('Stream opened: %s from %s' % (stream.sid, stream.peer_jid)) | ||||
|  | ||||
|         # You could run a loop reading from the stream using stream.recv(), | ||||
|         # or use the ibb_stream_data event. | ||||
|     def stream_data(self, stream): | ||||
|         self.file.write(stream.read()) | ||||
|  | ||||
|     def stream_data(self, event): | ||||
|         print(event['data']) | ||||
|     def stream_closed(self, stream): | ||||
|         print('Stream closed: %s from %s' % (stream.sid, stream.peer_jid)) | ||||
|         self.file.close() | ||||
|         self.disconnect() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-o", "--out", dest="filename", | ||||
|                         help="file to save to") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.filename is None: | ||||
|         args.filename = input("File path: ") | ||||
|  | ||||
|     xmpp = IBBReceiver(opts.jid, opts.password) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     # Setup the IBBReceiver and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = IBBReceiver(args.jid, args.password, args.filename) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0047', { | ||||
|         'auto_accept': True | ||||
|     }) # In-band Bytestreams | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
| @@ -1,43 +1,35 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
|  | ||||
| class IBBSender(sleekxmpp.ClientXMPP): | ||||
| class IBBSender(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic example of creating and using an in-band bytestream. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, receiver, filename): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|     def __init__(self, jid, password, receiver, filename, use_messages=False): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.receiver = receiver | ||||
|         self.filename = filename | ||||
|  | ||||
|         self.file = open(filename, 'rb') | ||||
|         self.use_messages = use_messages | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -46,7 +38,7 @@ class IBBSender(sleekxmpp.ClientXMPP): | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -62,84 +54,70 @@ class IBBSender(sleekxmpp.ClientXMPP): | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|  | ||||
|         # For the purpose of demonstration, we'll set a very small block | ||||
|         # size. The default block size is 4096. We'll also use a window | ||||
|         # allowing sending multiple blocks at a time; in this case, three | ||||
|         # block transfers may be in progress at any time. | ||||
|         stream = self['xep_0047'].open_stream(self.receiver) | ||||
|         try: | ||||
|             # Open the IBB stream in which to write to. | ||||
|             stream = await self['xep_0047'].open_stream(self.receiver, use_messages=self.use_messages) | ||||
|  | ||||
|         with open(self.filename) as f: | ||||
|             data = f.read() | ||||
|             stream.sendall(data) | ||||
|             # If you want to send in-memory bytes, use stream.sendall() instead. | ||||
|             await stream.sendfile(self.file, timeout=10) | ||||
|  | ||||
|             # And finally close the stream. | ||||
|             await stream.close(timeout=10) | ||||
|         except (IqError, IqTimeout): | ||||
|             print('File transfer errored') | ||||
|         else: | ||||
|             print('File transfer finished') | ||||
|         finally: | ||||
|             self.file.close() | ||||
|             self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-r", "--receiver", dest="receiver", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-f", "--file", dest="filename", | ||||
|                     help="JID to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-r", "--receiver", dest="receiver", | ||||
|                         help="JID of the receiver") | ||||
|     parser.add_argument("-f", "--file", dest="filename", | ||||
|                         help="file to send") | ||||
|     parser.add_argument("-m", "--use-messages", action="store_true", | ||||
|                         help="use messages instead of iqs for file transfer") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.receiver is None: | ||||
|         opts.receiver = raw_input("Receiver: ") | ||||
|     if opts.filename is None: | ||||
|         opts.filename = raw_input("File path: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.receiver is None: | ||||
|         args.receiver = input("Receiver: ") | ||||
|     if args.filename is None: | ||||
|         args.filename = input("File path: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # Setup the IBBSender and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = IBBSender(opts.jid, opts.password, opts.receiver, opts.filename) | ||||
|     xmpp = IBBSender(args.jid, args.password, args.receiver, args.filename, args.use_messages) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0047') # In-band Bytestreams | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										97
									
								
								examples/mam.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										97
									
								
								examples/mam.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2017 Mathieu Pasquet | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class MAM(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client fetching mam archive messages | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, remote_jid, start): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         self.remote_jid = remote_jid | ||||
|         self.start_date = start | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     async def start(self, *args): | ||||
|         """ | ||||
|         Fetch mam results for the specified JID. | ||||
|         Use RSM to paginate the results. | ||||
|         """ | ||||
|         results = self.plugin['xep_0313'].retrieve(jid=self.remote_jid, iterator=True, rsm={'max': 10}, start=self.start_date) | ||||
|         page = 1 | ||||
|         async for rsm in results: | ||||
|             print('Page %d' % page) | ||||
|             for msg in rsm['mam']['results']: | ||||
|                 forwarded = msg['mam_result']['forwarded'] | ||||
|                 timestamp = forwarded['delay']['stamp'] | ||||
|                 message = forwarded['stanza'] | ||||
|                 print('[%s] %s: %s' % (timestamp, message['from'], message['body'])) | ||||
|             page += 1 | ||||
|         self.disconnect() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options | ||||
|     parser.add_argument("-r", "--remote-jid", dest="remote_jid", | ||||
|                         help="Remote JID") | ||||
|     parser.add_argument("--start", help="Start date", default='2017-09-20T12:00:00Z') | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.remote_jid is None: | ||||
|         args.remote_jid = input("Remote JID: ") | ||||
|     if args.start is None: | ||||
|         args.start = input("Start time: ") | ||||
|  | ||||
|     xmpp = MAM(args.jid, args.password, args.remote_jid, args.start) | ||||
|     xmpp.register_plugin('xep_0313') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
							
								
								
									
										120
									
								
								examples/markup.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										120
									
								
								examples/markup.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.plugins.xep_0394 import stanza as markup_stanza | ||||
|  | ||||
|  | ||||
| class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple Slixmpp bot that will echo messages it | ||||
|     receives, along with a short thank you message. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|         # The message event is triggered whenever a message | ||||
|         # stanza is received. Be aware that that includes | ||||
|         # MUC messages and error messages. | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         await self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
|         Process incoming message stanzas. Be aware that this also | ||||
|         includes MUC messages and error messages. It is usually | ||||
|         a good idea to check the messages's type before processing | ||||
|         or sending replies. | ||||
|  | ||||
|         Arguments: | ||||
|             msg -- The received message stanza. See the documentation | ||||
|                    for stanza objects and the Message stanza to see | ||||
|                    how it may be used. | ||||
|         """ | ||||
|         body = msg['body'] | ||||
|         new_body = self['xep_0394'].to_plain_text(body, msg['markup']) | ||||
|         xhtml = self['xep_0394'].to_xhtml_im(body, msg['markup']) | ||||
|         print('Plain text:', new_body) | ||||
|         print('XHTML-IM:', xhtml['body']) | ||||
|         message = msg.reply() | ||||
|         message['body'] = new_body | ||||
|         message['html']['body'] = xhtml['body'] | ||||
|         self.send(message) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser(description=EchoBot.__doc__) | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = EchoBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|     xmpp.register_plugin('xep_0394') # Message Markup | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
							
								
								
									
										107
									
								
								examples/migrate_roster.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										107
									
								
								examples/migrate_roster.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| # Setup the command line arguments. | ||||
| parser = ArgumentParser() | ||||
|  | ||||
| # Output verbosity options. | ||||
| parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                     action="store_const", dest="loglevel", | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
| parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                     action="store_const", dest="loglevel", | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
| # JID and password options. | ||||
| parser.add_argument("--oldjid", dest="old_jid", | ||||
|                     help="JID of the old account") | ||||
| parser.add_argument("--oldpassword", dest="old_password", | ||||
|                     help="password of the old account") | ||||
|  | ||||
| parser.add_argument("--newjid", dest="new_jid", | ||||
|                     help="JID of the old account") | ||||
| parser.add_argument("--newpassword", dest="new_password", | ||||
|                     help="password of the old account") | ||||
|  | ||||
|  | ||||
| args = parser.parse_args() | ||||
|  | ||||
| # Setup logging. | ||||
| logging.basicConfig(level=args.loglevel, | ||||
|                     format='%(levelname)-8s %(message)s') | ||||
|  | ||||
| if args.old_jid is None: | ||||
|     args.old_jid = input("Old JID: ") | ||||
| if args.old_password is None: | ||||
|     args.old_password = getpass("Old Password: ") | ||||
|  | ||||
| if args.new_jid is None: | ||||
|     args.new_jid = input("New JID: ") | ||||
| if args.new_password is None: | ||||
|     args.new_password = getpass("New Password: ") | ||||
|  | ||||
|  | ||||
| old_xmpp = slixmpp.ClientXMPP(args.old_jid, args.old_password) | ||||
|  | ||||
| # If you are connecting to Facebook and wish to use the | ||||
| # X-FACEBOOK-PLATFORM authentication mechanism, you will need | ||||
| # your API key and an access token. Then you'll set: | ||||
| # xmpp.credentials['api_key'] = 'THE_API_KEY' | ||||
| # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||||
|  | ||||
| # If you are connecting to MSN, then you will need an | ||||
| # access token, and it does not matter what JID you | ||||
| # specify other than that the domain is 'messenger.live.com', | ||||
| # so '_@messenger.live.com' will work. You can specify | ||||
| # the access token as so: | ||||
| # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||||
|  | ||||
| # If you are working with an OpenFire server, you may need | ||||
| # to adjust the SSL version used: | ||||
| # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
| # If you want to verify the SSL certificates offered by a server: | ||||
| # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
| roster = [] | ||||
|  | ||||
| def on_session(event): | ||||
|     roster.append(old_xmpp.get_roster()) | ||||
|     old_xmpp.disconnect() | ||||
| old_xmpp.add_event_handler('session_start', on_session) | ||||
|  | ||||
| if old_xmpp.connect(): | ||||
|     old_xmpp.process(block=True) | ||||
|  | ||||
| if not roster: | ||||
|     print('No roster to migrate') | ||||
|     sys.exit() | ||||
|  | ||||
| new_xmpp = slixmpp.ClientXMPP(args.new_jid, args.new_password) | ||||
| def on_session2(event): | ||||
|     new_xmpp.get_roster() | ||||
|     new_xmpp.send_presence() | ||||
|  | ||||
|     logging.info(roster[0]) | ||||
|     data = roster[0]['roster']['items'] | ||||
|     logging.info(data) | ||||
|  | ||||
|     for jid, item in data.items(): | ||||
|         if item['subscription'] != 'none': | ||||
|             new_xmpp.send_presence(ptype='subscribe', pto=jid) | ||||
|         new_xmpp.update_roster(jid, | ||||
|                 name = item['name'], | ||||
|                 groups = item['groups']) | ||||
|     new_xmpp.disconnect() | ||||
| new_xmpp.add_event_handler('session_start', on_session2) | ||||
|  | ||||
| new_xmpp.connect() | ||||
| new_xmpp.process(forever=False) | ||||
							
								
								
									
										112
									
								
								examples/muc.py
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								examples/muc.py
									
									
									
									
									
								
							| @@ -1,42 +1,31 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class MUCBot(sleekxmpp.ClientXMPP): | ||||
| class MUCBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that will greets those | ||||
|     A simple Slixmpp bot that will greets those | ||||
|     who enter the room, and acknowledge any messages | ||||
|     that mentions the bot's nickname. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, room, nick): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.room = room | ||||
|         self.nick = nick | ||||
| @@ -63,7 +52,7 @@ class MUCBot(sleekxmpp.ClientXMPP): | ||||
|                                self.muc_online) | ||||
|  | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -76,13 +65,13 @@ class MUCBot(sleekxmpp.ClientXMPP): | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|         self.send_presence() | ||||
|         self.plugin['xep_0045'].joinMUC(self.room, | ||||
|                                         self.nick, | ||||
|                                         # If a room password is needed, use: | ||||
|                                         # password=the_room_password, | ||||
|                                         wait=True) | ||||
|         self.plugin['xep_0045'].join_muc(self.room, | ||||
|                                          self.nick, | ||||
|                                          # If a room password is needed, use: | ||||
|                                          # password=the_room_password, | ||||
|                                          wait=True) | ||||
|  | ||||
|     def muc_message(self, msg): | ||||
|         """ | ||||
| @@ -132,62 +121,49 @@ class MUCBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-r", "--room", dest="room", | ||||
|                     help="MUC room to join") | ||||
|     optp.add_option("-n", "--nick", dest="nick", | ||||
|                     help="MUC nickname") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-r", "--room", dest="room", | ||||
|                         help="MUC room to join") | ||||
|     parser.add_argument("-n", "--nick", dest="nick", | ||||
|                         help="MUC nickname") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.room is None: | ||||
|         opts.room = raw_input("MUC room: ") | ||||
|     if opts.nick is None: | ||||
|         opts.nick = raw_input("MUC nickname: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.room is None: | ||||
|         args.room = input("MUC room: ") | ||||
|     if args.nick is None: | ||||
|         args.nick = input("MUC nickname: ") | ||||
|  | ||||
|     # Setup the MUCBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = MUCBot(opts.jid, opts.password, opts.room, opts.nick) | ||||
|     xmpp = MUCBot(args.jid, args.password, args.room, args.nick) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0045') # Multi-User Chat | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										125
									
								
								examples/ping.py
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								examples/ping.py
									
									
									
									
									
								
							| @@ -1,43 +1,33 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class PingTest(sleekxmpp.ClientXMPP): | ||||
| class PingTest(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that will send a ping request | ||||
|     A simple Slixmpp bot that will send a ping request | ||||
|     to a given JID. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, pingjid): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         if pingjid is None: | ||||
|             pingjid = self.jid | ||||
|             pingjid = self.boundjid.bare | ||||
|         self.pingjid = pingjid | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
| @@ -45,9 +35,9 @@ class PingTest(sleekxmpp.ClientXMPP): | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -61,81 +51,62 @@ class PingTest(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         result = self['xep_0199'].send_ping(self.pingjid, | ||||
|                                             timeout=10, | ||||
|                                             errorfalse=True) | ||||
|         logging.info("Pinging...") | ||||
|         if result is False: | ||||
|             logging.info("Couldn't ping.") | ||||
|             self.disconnect() | ||||
|             sys.exit(1) | ||||
|         else: | ||||
|             logging.info("Success! RTT: %s", str(result)) | ||||
|         await self.get_roster() | ||||
|  | ||||
|         try: | ||||
|             rtt = await self['xep_0199'].ping(self.pingjid, | ||||
|                                                    timeout=10) | ||||
|             logging.info("Success! RTT: %s", rtt) | ||||
|         except IqError as e: | ||||
|             logging.info("Error pinging %s: %s", | ||||
|                     self.pingjid, | ||||
|                     e.iq['error']['condition']) | ||||
|         except IqTimeout: | ||||
|             logging.info("No response from %s", self.pingjid) | ||||
|         finally: | ||||
|             self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     optp.add_option('-t', '--pingto', help='set jid to ping', | ||||
|                     action='store', type='string', dest='pingjid', | ||||
|                     default=None) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|     parser.add_argument("-t", "--pingto", help="set jid to ping", | ||||
|                         dest="pingjid", default=None) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the PingTest and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = PingTest(opts.jid, opts.password, opts.pingjid) | ||||
|     xmpp = PingTest(args.jid, args.password, args.pingjid) | ||||
|     xmpp.register_plugin('xep_0030')  # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004')  # Data Forms | ||||
|     xmpp.register_plugin('xep_0060')  # PubSub | ||||
|     xmpp.register_plugin('xep_0199')  # XMPP Ping | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
| @@ -1,41 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class EchoBot(sleekxmpp.ClientXMPP): | ||||
| class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that will echo messages it | ||||
|     A simple Slixmpp bot that will echo messages it | ||||
|     receives, along with a short thank you message. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
| @@ -49,7 +38,7 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|         # MUC messages and error messages. | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -63,7 +52,7 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
| @@ -82,87 +71,65 @@ class EchoBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("--phost", dest="proxy_host", | ||||
|                     help="Proxy hostname") | ||||
|     optp.add_option("--pport", dest="proxy_port", | ||||
|                     help="Proxy port") | ||||
|     optp.add_option("--puser", dest="proxy_user", | ||||
|                     help="Proxy username") | ||||
|     optp.add_option("--ppass", dest="proxy_pass", | ||||
|                     help="Proxy password") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("--phost", dest="proxy_host", | ||||
|                         help="Proxy hostname") | ||||
|     parser.add_argument("--pport", dest="proxy_port", | ||||
|                         help="Proxy port") | ||||
|     parser.add_argument("--puser", dest="proxy_user", | ||||
|                         help="Proxy username") | ||||
|     parser.add_argument("--ppass", dest="proxy_pass", | ||||
|                         help="Proxy password") | ||||
|  | ||||
|  | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.proxy_host is None: | ||||
|         opts.proxy_host = raw_input("Proxy host: ") | ||||
|     if opts.proxy_port is None: | ||||
|         opts.proxy_port = raw_input("Proxy port: ") | ||||
|     if opts.proxy_user is None: | ||||
|         opts.proxy_user = raw_input("Proxy username: ") | ||||
|     if opts.proxy_pass is None and opts.proxy_user: | ||||
|         opts.proxy_pass = getpass.getpass("Proxy password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.proxy_host is None: | ||||
|         args.proxy_host = input("Proxy host: ") | ||||
|     if args.proxy_port is None: | ||||
|         args.proxy_port = input("Proxy port: ") | ||||
|     if args.proxy_user is None: | ||||
|         args.proxy_user = input("Proxy username: ") | ||||
|     if args.proxy_pass is None and args.proxy_user: | ||||
|         args.proxy_pass = getpass("Proxy password: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = EchoBot(opts.jid, opts.password) | ||||
|     xmpp = EchoBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     xmpp.use_proxy = True | ||||
|     xmpp.proxy_config = { | ||||
|         'host': opts.proxy_host, | ||||
|         'port': int(opts.proxy_port), | ||||
|         'username': opts.proxy_user, | ||||
|         'password': opts.proxy_pass} | ||||
|         'host': args.proxy_host, | ||||
|         'port': int(args.proxy_port), | ||||
|         'username': args.proxy_user, | ||||
|         'password': args.proxy_pass} | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										243
									
								
								examples/pubsub_client.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										243
									
								
								examples/pubsub_client.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,34 +1,26 @@ | ||||
| import sys | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.xmlstream import ET, tostring | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
| from slixmpp.xmlstream import ET, tostring | ||||
|  | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| class PubsubClient(slixmpp.ClientXMPP): | ||||
|  | ||||
|  | ||||
| class PubsubClient(sleekxmpp.ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password, server,  | ||||
|                        node=None, action='list', data=''): | ||||
|         super(PubsubClient, self).__init__(jid, password) | ||||
|     def __init__(self, jid, password, server, | ||||
|                        node=None, action='nodes', data=''): | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.register_plugin('xep_0030') | ||||
|         self.register_plugin('xep_0059') | ||||
|         self.register_plugin('xep_0060') | ||||
|  | ||||
|         self.actions = ['nodes', 'create', 'delete',  | ||||
|         self.actions = ['nodes', 'create', 'delete', 'get_configure', | ||||
|                         'publish', 'get', 'retract', | ||||
|                         'purge', 'subscribe', 'unsubscribe'] | ||||
|  | ||||
| @@ -37,162 +29,143 @@ class PubsubClient(sleekxmpp.ClientXMPP): | ||||
|         self.data = data | ||||
|         self.pubsub_server = server | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start, threaded=True) | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|         self.get_roster() | ||||
|     async def start(self, event): | ||||
|         await self.get_roster() | ||||
|         self.send_presence() | ||||
|  | ||||
|         try: | ||||
|             getattr(self, self.action)() | ||||
|             await getattr(self, self.action)() | ||||
|         except: | ||||
|             logging.error('Could not execute: %s' % self.action) | ||||
|             logging.exception('Could not execute %s:', self.action) | ||||
|         self.disconnect() | ||||
|  | ||||
|     def nodes(self): | ||||
|     async def nodes(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].get_nodes(self.pubsub_server, self.node) | ||||
|             result = await self['xep_0060'].get_nodes(self.pubsub_server, self.node) | ||||
|             for item in result['disco_items']['items']: | ||||
|                 print('  - %s' % str(item)) | ||||
|         except: | ||||
|             logging.error('Could not retrieve node list.') | ||||
|                 logging.info('  - %s', str(item)) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not retrieve node list: %s', error.format()) | ||||
|  | ||||
|     def create(self): | ||||
|     async def create(self): | ||||
|         try: | ||||
|             self['xep_0060'].create_node(self.pubsub_server, self.node) | ||||
|         except: | ||||
|             logging.error('Could not create node: %s' % self.node) | ||||
|             await self['xep_0060'].create_node(self.pubsub_server, self.node) | ||||
|             logging.info('Created node %s', self.node) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not create node %s: %s', self.node, error.format()) | ||||
|  | ||||
|     def delete(self): | ||||
|     async def delete(self): | ||||
|         try: | ||||
|             self['xep_0060'].delete_node(self.pubsub_server, self.node) | ||||
|             print('Deleted node: %s' % self.node) | ||||
|         except: | ||||
|             logging.error('Could not delete node: %s' % self.node) | ||||
|             await self['xep_0060'].delete_node(self.pubsub_server, self.node) | ||||
|             logging.info('Deleted node %s', self.node) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not delete node %s: %s', self.node, error.format()) | ||||
|  | ||||
|     def publish(self): | ||||
|     async def get_configure(self): | ||||
|         try: | ||||
|             configuration_form = await self['xep_0060'].get_node_config(self.pubsub_server, self.node) | ||||
|             logging.info('Configure form received from node %s: %s', self.node, configuration_form['pubsub_owner']['configure']['form']) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not retrieve configure form from node %s: %s', self.node, error.format()) | ||||
|  | ||||
|     async def publish(self): | ||||
|         payload = ET.fromstring("<test xmlns='test'>%s</test>" % self.data) | ||||
|         try: | ||||
|             result = self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload) | ||||
|             id = result['pubsub']['publish']['item']['id'] | ||||
|             print('Published at item id: %s' % id) | ||||
|         except: | ||||
|             logging.error('Could not publish to: %s' % self.node) | ||||
|             result = await self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload) | ||||
|             logging.info('Published at item id: %s', result['pubsub']['publish']['item']['id']) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not publish to %s: %s', self.node, error.format()) | ||||
|  | ||||
|     def get(self): | ||||
|     async def get(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].get_item(self.pubsub_server, self.node, self.data) | ||||
|             result = await self['xep_0060'].get_item(self.pubsub_server, self.node, self.data) | ||||
|             for item in result['pubsub']['items']['substanzas']: | ||||
|                 print('Retrieved item %s: %s' % (item['id'], tostring(item['payload']))) | ||||
|         except: | ||||
|             logging.error('Could not retrieve item %s from node %s' % (self.data, self.node)) | ||||
|                 logging.info('Retrieved item %s: %s', item['id'], tostring(item['payload'])) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not retrieve item %s from node %s: %s', self.data, self.node, error.format()) | ||||
|  | ||||
|     def retract(self): | ||||
|     async def retract(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].retract(self.pubsub_server, self.node, self.data) | ||||
|             print('Retracted item %s from node %s' % (self.data, self.node)) | ||||
|         except: | ||||
|             logging.error('Could not retract item %s from node %s' % (self.data, self.node)) | ||||
|             await self['xep_0060'].retract(self.pubsub_server, self.node, self.data) | ||||
|             logging.info('Retracted item %s from node %s', self.data, self.node) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not retract item %s from node %s: %s', self.data, self.node, error.format()) | ||||
|  | ||||
|     def purge(self): | ||||
|     async def purge(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].purge(self.pubsub_server, self.node) | ||||
|             print('Purged all items from node %s' % self.node) | ||||
|         except: | ||||
|             logging.error('Could not purge items from node %s' % self.node) | ||||
|             await self['xep_0060'].purge(self.pubsub_server, self.node) | ||||
|             logging.info('Purged all items from node %s', self.node) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not purge items from node %s: %s', self.node, error.format()) | ||||
|  | ||||
|     def subscribe(self): | ||||
|     async def subscribe(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].subscribe(self.pubsub_server, self.node) | ||||
|             print('Subscribed %s to node %s' % (self.boundjid.bare, self.node)) | ||||
|         except: | ||||
|             logging.error('Could not subscribe %s to node %s' % (self.boundjid.bare, self.node)) | ||||
|             iq = await self['xep_0060'].subscribe(self.pubsub_server, self.node) | ||||
|             subscription = iq['pubsub']['subscription'] | ||||
|             logging.info('Subscribed %s to node %s', subscription['jid'], subscription['node']) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not subscribe %s to node %s: %s', self.boundjid.bare, self.node, error.format()) | ||||
|  | ||||
|     def unsubscribe(self): | ||||
|     async def unsubscribe(self): | ||||
|         try: | ||||
|             result = self['xep_0060'].unsubscribe(self.pubsub_server, self.node) | ||||
|             print('Unsubscribed %s from node %s' % (self.boundjid.bare, self.node)) | ||||
|         except: | ||||
|             logging.error('Could not unsubscribe %s from node %s' % (self.boundjid.bare, self.node)) | ||||
|             await self['xep_0060'].unsubscribe(self.pubsub_server, self.node) | ||||
|             logging.info('Unsubscribed %s from node %s', self.boundjid.bare, self.node) | ||||
|         except XMPPError as error: | ||||
|             logging.error('Could not unsubscribe %s from node %s: %s', self.boundjid.bare, self.node, error.format()) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     optp.version = '%%prog 0.1' | ||||
|     optp.usage = "Usage: %%prog [options] <jid> " + \ | ||||
|                              'nodes|create|delete|purge|subscribe|unsubscribe|publish|retract|get' + \ | ||||
|     parser = ArgumentParser() | ||||
|     parser.version = '%%prog 0.1' | ||||
|     parser.usage = "Usage: %%prog [options] <jid> " + \ | ||||
|                              'nodes|create|delete|get_configure|purge|subscribe|unsubscribe|publish|retract|get' + \ | ||||
|                              ' [<node> <data>]' | ||||
|  | ||||
|     optp.add_option('-q','--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.ERROR, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-d','--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.DEBUG, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-v','--verbose', help='set logging to COMM', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=5, | ||||
|                     default=logging.ERROR) | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     opts,args = optp.parse_args() | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     parser.add_argument("server") | ||||
|     parser.add_argument("action", choices=["nodes", "create", "delete", "get_configure", "purge", "subscribe", "unsubscribe", "publish", "retract", "get"]) | ||||
|     parser.add_argument("node", nargs='?') | ||||
|     parser.add_argument("data", nargs='?') | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if len(args) < 2: | ||||
|         optp.print_help() | ||||
|         exit() | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|  | ||||
|     if len(args) == 2: | ||||
|         args = (args[0], args[1], '', '', '') | ||||
|     elif len(args) == 3: | ||||
|         args = (args[0], args[1], args[2], '', '') | ||||
|     elif len(args) == 4: | ||||
|         args = (args[0], args[1], args[2], args[3], '') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the Pubsub client | ||||
|     xmpp = PubsubClient(opts.jid, opts.password, | ||||
|                         server=args[0], | ||||
|                         node=args[2], | ||||
|                         action=args[1], | ||||
|                         data=args[3]) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = PubsubClient(args.jid, args.password, | ||||
|                         server=args.server, | ||||
|                         node=args.node, | ||||
|                         action=args.action, | ||||
|                         data=args.data) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										97
									
								
								examples/pubsub_events.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										97
									
								
								examples/pubsub_events.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,29 +1,20 @@ | ||||
| import sys | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.xmlstream import ET, tostring | ||||
| from sleekxmpp.xmlstream.matcher import StanzaPath | ||||
| from sleekxmpp.xmlstream.handler import Callback | ||||
| import slixmpp | ||||
| from slixmpp.xmlstream import ET, tostring | ||||
| from slixmpp.xmlstream.matcher import StanzaPath | ||||
| from slixmpp.xmlstream.handler import Callback | ||||
|  | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class PubsubEvents(sleekxmpp.ClientXMPP): | ||||
| class PubsubEvents(slixmpp.ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(PubsubEvents, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.register_plugin('xep_0030') | ||||
|         self.register_plugin('xep_0059') | ||||
| @@ -47,8 +38,8 @@ class PubsubEvents(sleekxmpp.ClientXMPP): | ||||
|         # self.add_event_handler('event_prefix_purge', handler) | ||||
|         # self.add_event_handler('event_prefix_delete', handler) | ||||
|  | ||||
|     def start(self, event): | ||||
|         self.get_roster() | ||||
|     async def start(self, event): | ||||
|         await self.get_roster() | ||||
|         self.send_presence() | ||||
|  | ||||
|     def _publish(self, msg): | ||||
| @@ -77,7 +68,7 @@ class PubsubEvents(sleekxmpp.ClientXMPP): | ||||
|         """Handle receiving a node deletion event.""" | ||||
|         print('Deleted node %s' % ( | ||||
|            msg['pubsub_event']['delete']['node'])) | ||||
|   | ||||
|  | ||||
|     def _config(self, msg): | ||||
|         """Handle receiving a node configuration event.""" | ||||
|         print('Configured node %s:' % ( | ||||
| @@ -93,59 +84,39 @@ class PubsubEvents(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     logging.info("Run this in conjunction with the pubsub_client.py " + \ | ||||
|                  "example to watch events happen as you give commands.") | ||||
|  | ||||
|     # Setup the PubsubEvents listener | ||||
|     xmpp = PubsubEvents(opts.jid, opts.password) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = PubsubEvents(args.jid, args.password) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										109
									
								
								examples/register_account.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										109
									
								
								examples/register_account.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,34 +1,23 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
|  | ||||
| class RegisterBot(sleekxmpp.ClientXMPP): | ||||
| class RegisterBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic bot that will attempt to register an account | ||||
| @@ -40,25 +29,25 @@ class RegisterBot(sleekxmpp.ClientXMPP): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|         # The register event provides an Iq result stanza with | ||||
|         # a registration form from the server. This may include | ||||
|         # the basic registration fields, a data form, an  | ||||
|         # the basic registration fields, a data form, an | ||||
|         # out-of-band URL, or any combination. For more advanced | ||||
|         # cases, you will need to examine the fields provided | ||||
|         # and respond accordingly. SleekXMPP provides plugins | ||||
|         # and respond accordingly. Slixmpp provides plugins | ||||
|         # for data forms and OOB links that will make that easier. | ||||
|         self.add_event_handler("register", self.register, threaded=True) | ||||
|         self.add_event_handler("register", self.register) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -72,12 +61,12 @@ class RegisterBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         # We're only concerned about registering, so nothing more to do here. | ||||
|         self.disconnect() | ||||
|  | ||||
|     def register(self, iq): | ||||
|     async def register(self, iq): | ||||
|         """ | ||||
|         Fill out and submit a registration form. | ||||
|  | ||||
| @@ -101,10 +90,10 @@ class RegisterBot(sleekxmpp.ClientXMPP): | ||||
|         resp['register']['password'] = self.password | ||||
|  | ||||
|         try: | ||||
|             resp.send(now=True) | ||||
|             await resp.send() | ||||
|             logging.info("Account created for %s!" % self.boundjid) | ||||
|         except IqError as e: | ||||
|             logging.error("Could not register account: %s" %  | ||||
|             logging.error("Could not register account: %s" % | ||||
|                     e.iq['error']['text']) | ||||
|             self.disconnect() | ||||
|         except IqTimeout: | ||||
| @@ -114,62 +103,46 @@ class RegisterBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     # Setup the RegisterBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = RegisterBot(opts.jid, opts.password) | ||||
|     xmpp = RegisterBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data forms | ||||
|     xmpp.register_plugin('xep_0066') # Out-of-band Data | ||||
|     xmpp.register_plugin('xep_0077') # In-band Registration | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     # Some servers don't advertise support for inband registration, even | ||||
|     # though they allow it. If this applies to your server, use: | ||||
|     xmpp['xep_0077'].force_registration = True | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										119
									
								
								examples/roster_browser.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										119
									
								
								examples/roster_browser.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,36 +1,24 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| import threading | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.exceptions import IqError, IqTimeout | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
| from slixmpp.xmlstream.asyncio import asyncio | ||||
|  | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
|  | ||||
|  | ||||
| class RosterBrowser(sleekxmpp.ClientXMPP): | ||||
| class RosterBrowser(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic script for dumping a client's roster to | ||||
| @@ -38,21 +26,19 @@ class RosterBrowser(sleekxmpp.ClientXMPP): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. We need threaded=True so that the | ||||
|         # session_start handler doesn't block event processing | ||||
|         # while we wait for presence stanzas to arrive. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("changed_status", self.wait_for_presences) | ||||
|  | ||||
|         self.received = set() | ||||
|         self.presences_received = threading.Event() | ||||
|         self.presences_received = asyncio.Event() | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -66,16 +52,16 @@ class RosterBrowser(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         try: | ||||
|             self.get_roster() | ||||
|             await self.get_roster() | ||||
|         except IqError as err: | ||||
|             print('Error: %' % err.iq['error']['condition']) | ||||
|             print('Error: %s' % err.iq['error']['condition']) | ||||
|         except IqTimeout: | ||||
|             print('Error: Request timed out') | ||||
|         self.send_presence() | ||||
|  | ||||
|  | ||||
|         print('Waiting for presence updates...\n') | ||||
|         self.presences_received.wait(5) | ||||
|         await asyncio.sleep(10) | ||||
|  | ||||
|         print('Roster for %s' % self.boundjid.bare) | ||||
|         groups = self.client_roster.groups() | ||||
| @@ -115,58 +101,37 @@ class RosterBrowser(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     optp.add_option('-q','--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.ERROR, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-d','--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=logging.DEBUG, | ||||
|                     default=logging.ERROR) | ||||
|     optp.add_option('-v','--verbose', help='set logging to COMM', | ||||
|                     action='store_const', | ||||
|                     dest='loglevel', | ||||
|                     const=5, | ||||
|                     default=logging.ERROR) | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.ERROR) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.ERROR) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     opts,args = optp.parse_args() | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = RosterBrowser(opts.jid, opts.password) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = RosterBrowser(args.jid, args.password) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|  | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										37
									
								
								examples/rpc_async.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										37
									
								
								examples/rpc_async.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,44 +1,47 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2011  Dann Martens | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
| from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
|     ANY_ALL, Future | ||||
| import time | ||||
|  | ||||
| class Boomerang(Endpoint): | ||||
|      | ||||
|  | ||||
|     def FQN(self): | ||||
|         return 'boomerang' | ||||
|            | ||||
|  | ||||
|     @remote | ||||
|     def throw(self): | ||||
|         print "Duck!" | ||||
|              | ||||
|         print("Duck!") | ||||
|  | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|  | ||||
|     session = Remote.new_session('kangaroo@xmpp.org/rpc', '*****') | ||||
|  | ||||
|     session.new_handler(ANY_ALL, Boomerang)     | ||||
|      | ||||
|     session.new_handler(ANY_ALL, Boomerang) | ||||
|  | ||||
|     boomerang = session.new_proxy('kangaroo@xmpp.org/rpc', Boomerang) | ||||
|          | ||||
|  | ||||
|     callback = Future() | ||||
|          | ||||
|  | ||||
|     boomerang.async(callback).throw() | ||||
|      | ||||
|  | ||||
|     time.sleep(10) | ||||
|      | ||||
|  | ||||
|     session.close() | ||||
|      | ||||
|      | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|      | ||||
|  | ||||
|   | ||||
							
								
								
									
										35
									
								
								examples/rpc_client_side.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										35
									
								
								examples/rpc_client_side.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,29 +1,32 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2011  Dann Martens | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
| from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
|     ANY_ALL | ||||
| import threading | ||||
| import time | ||||
|  | ||||
| class Thermostat(Endpoint): | ||||
|      | ||||
|  | ||||
|     def FQN(self): | ||||
|         return 'thermostat' | ||||
|      | ||||
|  | ||||
|     def __init__(self, initial_temperature): | ||||
|         self._temperature = initial_temperature | ||||
|         self._event = threading.Event()         | ||||
|      | ||||
|         self._event = threading.Event() | ||||
|  | ||||
|     @remote | ||||
|     def set_temperature(self, temperature): | ||||
|         return NotImplemented | ||||
|      | ||||
|  | ||||
|     @remote | ||||
|     def get_temperature(self): | ||||
|         return NotImplemented | ||||
| @@ -31,23 +34,23 @@ class Thermostat(Endpoint): | ||||
|     @remote(False) | ||||
|     def release(self): | ||||
|         return NotImplemented | ||||
|          | ||||
|  | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|  | ||||
|     session = Remote.new_session('operator@xmpp.org/rpc', '*****') | ||||
|      | ||||
|  | ||||
|     thermostat = session.new_proxy('thermostat@xmpp.org/rpc', Thermostat) | ||||
|      | ||||
|  | ||||
|     print("Current temperature is %s" % thermostat.get_temperature()) | ||||
|      | ||||
|  | ||||
|     thermostat.set_temperature(20) | ||||
|      | ||||
|  | ||||
|     time.sleep(10) | ||||
|      | ||||
|  | ||||
|     session.close() | ||||
|      | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|      | ||||
|  | ||||
|   | ||||
							
								
								
									
										37
									
								
								examples/rpc_server_side.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										37
									
								
								examples/rpc_server_side.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,52 +1,55 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2011  Dann Martens | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
| from slixmpp.plugins.xep_0009.remote import Endpoint, remote, Remote, \ | ||||
|     ANY_ALL | ||||
| import threading | ||||
|  | ||||
| class Thermostat(Endpoint): | ||||
|      | ||||
|  | ||||
|     def FQN(self): | ||||
|         return 'thermostat' | ||||
|      | ||||
|  | ||||
|     def __init__(self, initial_temperature): | ||||
|         self._temperature = initial_temperature | ||||
|         self._event = threading.Event()         | ||||
|      | ||||
|         self._event = threading.Event() | ||||
|  | ||||
|     @remote | ||||
|     def set_temperature(self, temperature): | ||||
|         print("Setting temperature to %s" % temperature) | ||||
|         self._temperature = temperature | ||||
|      | ||||
|  | ||||
|     @remote | ||||
|     def get_temperature(self): | ||||
|         return self._temperature | ||||
|  | ||||
|     @remote(False) | ||||
|     def release(self): | ||||
|         self._event.set()  | ||||
|          | ||||
|         self._event.set() | ||||
|  | ||||
|     def wait_for_release(self): | ||||
|         self._event.wait()         | ||||
|      | ||||
|         self._event.wait() | ||||
|  | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|  | ||||
|     session = Remote.new_session('sleek@xmpp.org/rpc', '*****') | ||||
|      | ||||
|  | ||||
|     thermostat = session.new_handler(ANY_ALL, Thermostat, 18) | ||||
|      | ||||
|  | ||||
|     thermostat.wait_for_release() | ||||
|      | ||||
|  | ||||
|     session.close() | ||||
|      | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|      | ||||
|  | ||||
|   | ||||
							
								
								
									
										89
									
								
								examples/s5b_transfer/s5b_receiver.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										89
									
								
								examples/s5b_transfer/s5b_receiver.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015  Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class S5BReceiver(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic example of creating and using a SOCKS5 bytestream. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, filename): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.file = open(filename, 'wb') | ||||
|  | ||||
|         self.add_event_handler("socks5_connected", self.stream_opened) | ||||
|         self.add_event_handler("socks5_data", self.stream_data) | ||||
|         self.add_event_handler("socks5_closed", self.stream_closed) | ||||
|  | ||||
|     def stream_opened(self, sid): | ||||
|         logging.info('Stream opened. %s', sid) | ||||
|  | ||||
|     def stream_data(self, data): | ||||
|         self.file.write(data) | ||||
|  | ||||
|     def stream_closed(self, exception): | ||||
|         logging.info('Stream closed. %s', exception) | ||||
|         self.file.close() | ||||
|         self.disconnect() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-o", "--out", dest="filename", | ||||
|                         help="file to save to") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.filename is None: | ||||
|         args.filename = input("File path: ") | ||||
|  | ||||
|     # Setup the S5BReceiver and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = S5BReceiver(args.jid, args.password, args.filename) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0065', { | ||||
|         'auto_accept': True | ||||
|     }) # SOCKS5 Bytestreams | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
							
								
								
									
										122
									
								
								examples/s5b_transfer/s5b_sender.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										122
									
								
								examples/s5b_transfer/s5b_sender.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015  Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
|  | ||||
| class S5BSender(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic example of creating and using a SOCKS5 bytestream. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, receiver, filename): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.receiver = receiver | ||||
|  | ||||
|         self.file = open(filename, 'rb') | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
|         # and the XML streams are ready for use. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|  | ||||
|         try: | ||||
|             # Open the S5B stream in which to write to. | ||||
|             proxy = await self['xep_0065'].handshake(self.receiver) | ||||
|  | ||||
|             # Send the entire file. | ||||
|             while True: | ||||
|                 data = self.file.read(1048576) | ||||
|                 if not data: | ||||
|                     break | ||||
|                 await proxy.write(data) | ||||
|  | ||||
|             # And finally close the stream. | ||||
|             proxy.transport.write_eof() | ||||
|         except (IqError, IqTimeout): | ||||
|             print('File transfer errored') | ||||
|         else: | ||||
|             print('File transfer finished') | ||||
|         finally: | ||||
|             self.file.close() | ||||
|             self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-r", "--receiver", dest="receiver", | ||||
|                         help="JID of the receiver") | ||||
|     parser.add_argument("-f", "--file", dest="filename", | ||||
|                         help="file to send") | ||||
|     parser.add_argument("-m", "--use-messages", action="store_true", | ||||
|                         help="use messages instead of iqs for file transfer") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.receiver is None: | ||||
|         args.receiver = input("Receiver: ") | ||||
|     if args.filename is None: | ||||
|         args.filename = input("File path: ") | ||||
|  | ||||
|     # Setup the S5BSender and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = S5BSender(args.jid, args.password, args.receiver, args.filename) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0065') # SOCKS5 Bytestreams | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
| @@ -1,41 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import sleekxmpp | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
|  | ||||
|  | ||||
| class SendMsgBot(sleekxmpp.ClientXMPP): | ||||
| class SendMsgBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic SleekXMPP bot that will log in, send a message, | ||||
|     A basic Slixmpp bot that will log in, send a message, | ||||
|     and then log out. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, recipient, message): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The message we wish to send, and the JID that | ||||
|         # will receive it. | ||||
| @@ -47,9 +36,9 @@ class SendMsgBot(sleekxmpp.ClientXMPP): | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start, threaded=True) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -63,81 +52,59 @@ class SendMsgBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         self.send_message(mto=self.recipient, | ||||
|                           mbody=self.msg, | ||||
|                           mtype='chat') | ||||
|  | ||||
|         # Using wait=True ensures that the send queue will be | ||||
|         # emptied before ending the session. | ||||
|         self.disconnect(wait=True) | ||||
|         self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser(description=SendMsgBot.__doc__) | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     optp.add_option("-t", "--to", dest="to", | ||||
|                     help="JID to send the message to") | ||||
|     optp.add_option("-m", "--message", dest="message", | ||||
|                     help="message to send") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-t", "--to", dest="to", | ||||
|                         help="JID to send the message to") | ||||
|     parser.add_argument("-m", "--message", dest="message", | ||||
|                         help="message to send") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if opts.to is None: | ||||
|         opts.to = raw_input("Send To: ") | ||||
|     if opts.message is None: | ||||
|         opts.message = raw_input("Message: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.to is None: | ||||
|         args.to = input("Send To: ") | ||||
|     if args.message is None: | ||||
|         args.message = input("Message: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = SendMsgBot(opts.jid, opts.password, opts.to, opts.message) | ||||
|     xmpp = SendMsgBot(args.jid, args.password, args.to, args.message) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|   | ||||
							
								
								
									
										140
									
								
								examples/set_avatar.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										140
									
								
								examples/set_avatar.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2012  Nathanael C. Fritz | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import os | ||||
| import imghdr | ||||
| import logging | ||||
| from getpass import getpass | ||||
| import threading | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
|  | ||||
| class AvatarSetter(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic script for downloading the avatars for a user's contacts. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, filepath): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|         self.filepath = filepath | ||||
|  | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         avatar_file = None | ||||
|         try: | ||||
|             avatar_file = open(os.path.expanduser(self.filepath), 'rb') | ||||
|         except IOError: | ||||
|             print('Could not find file: %s' % self.filepath) | ||||
|             return self.disconnect() | ||||
|  | ||||
|         avatar = avatar_file.read() | ||||
|  | ||||
|         avatar_type = 'image/%s' % imghdr.what('', avatar) | ||||
|         avatar_id = self['xep_0084'].generate_id(avatar) | ||||
|         avatar_bytes = len(avatar) | ||||
|  | ||||
|         avatar_file.close() | ||||
|  | ||||
|         used_xep84 = False | ||||
|  | ||||
|         print('Publish XEP-0084 avatar data') | ||||
|         result = await self['xep_0084'].publish_avatar(avatar) | ||||
|         if isinstance(result, XMPPError): | ||||
|             print('Could not publish XEP-0084 avatar') | ||||
|         else: | ||||
|             used_xep84 = True | ||||
|  | ||||
|         print('Update vCard with avatar') | ||||
|         result = await self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type) | ||||
|         if isinstance(result, XMPPError): | ||||
|             print('Could not set vCard avatar') | ||||
|  | ||||
|         if used_xep84: | ||||
|             print('Advertise XEP-0084 avatar metadata') | ||||
|             result = await self['xep_0084'].publish_avatar_metadata([ | ||||
|                 {'id': avatar_id, | ||||
|                  'type': avatar_type, | ||||
|                  'bytes': avatar_bytes} | ||||
|                 # We could advertise multiple avatars to provide | ||||
|                 # options in image type, source (HTTP vs pubsub), | ||||
|                 # size, etc. | ||||
|                 # {'id': ....} | ||||
|             ]) | ||||
|             if isinstance(result, XMPPError): | ||||
|                 print('Could not publish XEP-0084 metadata') | ||||
|  | ||||
|         print('Wait for presence updates to propagate...') | ||||
|         self.schedule('end', 5, self.disconnect, kwargs={'wait': True}) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.ERROR) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.ERROR) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|     parser.add_argument("-f", "--file", dest="filepath", | ||||
|                         help="path to the avatar file") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|     if args.filepath is None: | ||||
|         args.filepath = input("Avatar file location: ") | ||||
|  | ||||
|     xmpp = AvatarSetter(args.jid, args.password, args.filepath) | ||||
|     xmpp.register_plugin('xep_0054') | ||||
|     xmpp.register_plugin('xep_0153') | ||||
|     xmpp.register_plugin('xep_0084') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
							
								
								
									
										101
									
								
								examples/thirdparty_auth.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										101
									
								
								examples/thirdparty_auth.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,18 +1,18 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| try: | ||||
|     from httplib import HTTPSConnection | ||||
| @@ -21,24 +21,14 @@ except ImportError: | ||||
|     from urllib.parse import urlencode | ||||
|     from http.client import HTTPSConnection | ||||
|  | ||||
| import sleekxmpp | ||||
| from sleekxmpp.xmlstream import JID | ||||
|  | ||||
| # Python versions before 3.0 do not use UTF-8 encoding | ||||
| # by default. To ensure that Unicode is handled properly | ||||
| # throughout SleekXMPP, we will set the default encoding | ||||
| # ourselves to UTF-8. | ||||
| if sys.version_info < (3, 0): | ||||
|     reload(sys) | ||||
|     sys.setdefaultencoding('utf8') | ||||
| else: | ||||
|     raw_input = input | ||||
| import slixmpp | ||||
| from slixmpp.xmlstream import JID | ||||
|  | ||||
|  | ||||
| class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
| class ThirdPartyAuthBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple SleekXMPP bot that will echo messages it | ||||
|     A simple Slixmpp bot that will echo messages it | ||||
|     receives, along with a short thank you message. | ||||
|  | ||||
|     This version uses a thirdpary service for authentication, | ||||
| @@ -46,7 +36,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The X-GOOGLE-TOKEN mech is ranked lower than PLAIN | ||||
|         # due to Google only allowing a single SASL attempt per | ||||
| @@ -55,7 +45,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
|         # X-GOOGLE-TOKEN with a TLS connection, explicitly select | ||||
|         # it using: | ||||
|         # | ||||
|         # sleekxmpp.ClientXMPP.__init__(self, jid, password, | ||||
|         # slixmpp.ClientXMPP.__init__(self, jid, password, | ||||
|         #                               sasl_mech="X-GOOGLE-TOKEN") | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
| @@ -70,7 +60,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
|         # MUC messages and error messages. | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -84,7 +74,7 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
| @@ -104,37 +94,34 @@ class ThirdPartyAuthBot(sleekxmpp.ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|  | ||||
|      | ||||
|     access_token = None | ||||
|  | ||||
|     # Since documentation on how to work with Google tokens | ||||
| @@ -156,11 +143,11 @@ if __name__ == '__main__': | ||||
|     params = urlencode({ | ||||
|         'accountType': 'GOOGLE', | ||||
|         'service': 'mail', | ||||
|         'Email': JID(opts.jid).bare, | ||||
|         'Passwd': opts.password | ||||
|         'Email': JID(args.jid).bare, | ||||
|         'Passwd': args.password | ||||
|     }) | ||||
|     headers = { | ||||
|         'Content-Type': 'application/x-www-form-urlencoded'  | ||||
|         'Content-Type': 'application/x-www-form-urlencoded' | ||||
|     } | ||||
|     try: | ||||
|         conn.request('POST', '/accounts/ClientLogin', params, headers) | ||||
| @@ -208,12 +195,12 @@ if __name__ == '__main__': | ||||
|     # We're using an access token instead of a password, so we'll use `''` as | ||||
|     # a password argument filler. | ||||
|  | ||||
|     xmpp = ThirdPartyAuthBot(opts.jid, '')   | ||||
|     xmpp = ThirdPartyAuthBot(args.jid, '') | ||||
|     xmpp.credentials['access_token'] = access_token | ||||
|  | ||||
|     # The credentials dictionary is used to provide additional authentication | ||||
|     # information beyond just a password. | ||||
|      | ||||
|  | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0004') # Data Forms | ||||
|     xmpp.register_plugin('xep_0060') # PubSub | ||||
| @@ -231,17 +218,7 @@ if __name__ == '__main__': | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     # Google only allows one SASL attempt per connection, so in order to  | ||||
|     # Google only allows one SASL attempt per connection, so in order to | ||||
|     # enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS. | ||||
|     if xmpp.connect(use_tls=False): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										78
									
								
								examples/user_location.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										78
									
								
								examples/user_location.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,9 +1,9 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| try: | ||||
|     import json | ||||
| @@ -16,16 +16,16 @@ except ImportError: | ||||
|     print('This demo requires the requests package for using HTTP.') | ||||
|     sys.exit() | ||||
|  | ||||
| from sleekxmpp import ClientXMPP | ||||
| from slixmpp import ClientXMPP | ||||
|  | ||||
|  | ||||
| class LocationBot(ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(LocationBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start, threaded=True) | ||||
|         self.add_event_handler('user_location_publish',  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|         self.add_event_handler('user_location_publish', | ||||
|                                self.user_location_publish) | ||||
|  | ||||
|         self.register_plugin('xep_0004') | ||||
| @@ -38,9 +38,9 @@ class LocationBot(ClientXMPP): | ||||
|  | ||||
|         self.current_tune = None | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|         self['xep_0115'].update_caps() | ||||
|  | ||||
|         print("Using freegeoip.net to get geolocation.") | ||||
| @@ -71,55 +71,35 @@ class LocationBot(ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = LocationBot(opts.jid, opts.password) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = LocationBot(args.jid, args.password) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										74
									
								
								examples/user_tune.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										74
									
								
								examples/user_tune.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,9 +1,9 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import getpass | ||||
| from optparse import OptionParser | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| try: | ||||
|     from appscript import * | ||||
| @@ -11,13 +11,13 @@ except ImportError: | ||||
|     print('This demo requires the appscript package to interact with iTunes.') | ||||
|     sys.exit() | ||||
|  | ||||
| from sleekxmpp import ClientXMPP | ||||
| from slixmpp import ClientXMPP | ||||
|  | ||||
|  | ||||
| class TuneBot(ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(TuneBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         # Check for the current song every 5 seconds. | ||||
|         self.schedule('Check Current Tune', 5, self._update_tune, repeat=True) | ||||
| @@ -35,9 +35,9 @@ class TuneBot(ClientXMPP): | ||||
|  | ||||
|         self.current_tune = None | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|         self['xep_0115'].update_caps() | ||||
|  | ||||
|     def _update_tune(self): | ||||
| @@ -83,55 +83,35 @@ class TuneBot(ClientXMPP): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     optp = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.ERROR, default=logging.INFO) | ||||
|     optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=logging.DEBUG, default=logging.INFO) | ||||
|     optp.add_option('-v', '--verbose', help='set logging to COMM', | ||||
|                     action='store_const', dest='loglevel', | ||||
|                     const=5, default=logging.INFO) | ||||
|     parser.add_argument("-q", "--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.ERROR, default=logging.INFO) | ||||
|     parser.add_argument("-d", "--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", dest="loglevel", | ||||
|                         const=logging.DEBUG, default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     optp.add_option("-j", "--jid", dest="jid", | ||||
|                     help="JID to use") | ||||
|     optp.add_option("-p", "--password", dest="password", | ||||
|                     help="password to use") | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     opts, args = optp.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = raw_input("Username: ") | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass("Password: ") | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = TuneBot(opts.jid, opts.password) | ||||
|  | ||||
|     # If you are working with an OpenFire server, you may need | ||||
|     # to adjust the SSL version used: | ||||
|     # xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||||
|  | ||||
|     # If you want to verify the SSL certificates offered by a server: | ||||
|     # xmpp.ca_certs = "path/to/ca/cert" | ||||
|     xmpp = TuneBot(args.jid, args.password) | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     if xmpp.connect(): | ||||
|         # If you do not have the dnspython library installed, you will need | ||||
|         # to manually specify the name of the server if it does not match | ||||
|         # the one in the JID. For example, to use Google Talk you would | ||||
|         # need to use: | ||||
|         # | ||||
|         # if xmpp.connect(('talk.google.com', 5222)): | ||||
|         #     ... | ||||
|         xmpp.process(block=True) | ||||
|         print("Done") | ||||
|     else: | ||||
|         print("Unable to connect.") | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|   | ||||
							
								
								
									
										233
									
								
								ez_setup.py
									
									
									
									
									
								
							
							
						
						
									
										233
									
								
								ez_setup.py
									
									
									
									
									
								
							| @@ -1,233 +0,0 @@ | ||||
| #!python | ||||
| """Bootstrap setuptools installation | ||||
|  | ||||
| If you want to use setuptools in your package's setup.py, just include this | ||||
| file in the same directory with it, and add this to the top of your setup.py:: | ||||
|  | ||||
|     from ez_setup import use_setuptools | ||||
|     use_setuptools() | ||||
|  | ||||
| If you want to require a specific version of setuptools, set a download | ||||
| mirror, or use an alternate download directory, you can do so by supplying | ||||
| the appropriate options to ``use_setuptools()``. | ||||
|  | ||||
| This file can also be run as a script to install or upgrade setuptools. | ||||
| """ | ||||
| import sys | ||||
| DEFAULT_VERSION = "0.6c7" | ||||
| DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] | ||||
|  | ||||
| md5_data = { | ||||
|     'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', | ||||
|     'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', | ||||
|     'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', | ||||
|     'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', | ||||
|     'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', | ||||
|     'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', | ||||
|     'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', | ||||
|     'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', | ||||
|     'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', | ||||
|     'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', | ||||
|     'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', | ||||
|     'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', | ||||
|     'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', | ||||
|     'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', | ||||
|     'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', | ||||
|     'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', | ||||
|     'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', | ||||
|     'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', | ||||
|     'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', | ||||
|     'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', | ||||
|     'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', | ||||
|     'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', | ||||
|     'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', | ||||
|     'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', | ||||
| } | ||||
|  | ||||
| import sys, os | ||||
|  | ||||
| def _validate_md5(egg_name, data): | ||||
|     if egg_name in md5_data: | ||||
|         from md5 import md5 | ||||
|         digest = md5(data).hexdigest() | ||||
|         if digest != md5_data[egg_name]: | ||||
|             print >>sys.stderr, ( | ||||
|                 "md5 validation of %s failed!  (Possible download problem?)" | ||||
|                 % egg_name | ||||
|             ) | ||||
|             sys.exit(2) | ||||
|     return data | ||||
|  | ||||
|  | ||||
| def use_setuptools( | ||||
|     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, min_version=None, | ||||
|     download_delay=15 | ||||
| ): | ||||
|     """Automatically find/download setuptools and make it available on sys.path | ||||
|  | ||||
|     `version` should be a valid setuptools version number that is available | ||||
|     as an egg for download under the `download_base` URL (which should end with | ||||
|     a '/').  `to_dir` is the directory where setuptools will be downloaded, if | ||||
|     it is not already available.  If `download_delay` is specified, it should | ||||
|     be the number of seconds that will be paused before initiating a download, | ||||
|     should one be required.  If an older version of setuptools is installed, | ||||
|     this routine will print a message to ``sys.stderr`` and raise SystemExit in | ||||
|     an attempt to abort the calling script. | ||||
|     """ | ||||
|     try: | ||||
|         import setuptools | ||||
|         if setuptools.__version__ == '0.0.1': | ||||
|             print >>sys.stderr, ( | ||||
|             "You have an obsolete version of setuptools installed.  Please\n" | ||||
|             "remove it from your system entirely before rerunning this script." | ||||
|             ) | ||||
|             sys.exit(2) | ||||
|     except ImportError: | ||||
|         egg = download_setuptools(version, download_base, to_dir, download_delay) | ||||
|         sys.path.insert(0, egg) | ||||
|         import setuptools; setuptools.bootstrap_install_from = egg | ||||
|  | ||||
|     import pkg_resources | ||||
|     try: | ||||
|         if not min_version: | ||||
|             min_version = version | ||||
|         pkg_resources.require("setuptools>="+min_version) | ||||
|  | ||||
|     except pkg_resources.VersionConflict, e: | ||||
|         # XXX could we install in a subprocess here? | ||||
|         print >>sys.stderr, ( | ||||
|             "The required version of setuptools (>=%s) is not available, and\n" | ||||
|             "can't be installed while this script is running. Please install\n" | ||||
|             " a more recent version first.\n\n(Currently using %r)" | ||||
|         ) % (min_version, e.args[0]) | ||||
|         sys.exit(2) | ||||
|  | ||||
| def download_setuptools( | ||||
|     version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, | ||||
|     delay = 15 | ||||
| ): | ||||
|     """Download setuptools from a specified location and return its filename | ||||
|  | ||||
|     `version` should be a valid setuptools version number that is available | ||||
|     as an egg for download under the `download_base` URL (which should end | ||||
|     with a '/'). `to_dir` is the directory where the egg will be downloaded. | ||||
|     `delay` is the number of seconds to pause before an actual download attempt. | ||||
|     """ | ||||
|     import urllib2, shutil | ||||
|     egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) | ||||
|     url = download_base + egg_name | ||||
|     saveto = os.path.join(to_dir, egg_name) | ||||
|     src = dst = None | ||||
|     if not os.path.exists(saveto):  # Avoid repeated downloads | ||||
|         try: | ||||
|             from distutils import log | ||||
|             if delay: | ||||
|                 log.warn(""" | ||||
| --------------------------------------------------------------------------- | ||||
| This script requires setuptools version %s to run (even to display | ||||
| help).  I will attempt to download it for you (from | ||||
| %s), but | ||||
| you may need to enable firewall access for this script first. | ||||
| I will start the download in %d seconds. | ||||
|  | ||||
| (Note: if this machine does not have network access, please obtain the file | ||||
|  | ||||
|    %s | ||||
|  | ||||
| and place it in this directory before rerunning this script.) | ||||
| ---------------------------------------------------------------------------""", | ||||
|                     version, download_base, delay, url | ||||
|                 ); from time import sleep; sleep(delay) | ||||
|             log.warn("Downloading %s", url) | ||||
|             src = urllib2.urlopen(url) | ||||
|             # Read/write all in one block, so we don't create a corrupt file | ||||
|             # if the download is interrupted. | ||||
|             data = _validate_md5(egg_name, src.read()) | ||||
|             dst = open(saveto,"wb"); dst.write(data) | ||||
|         finally: | ||||
|             if src: src.close() | ||||
|             if dst: dst.close() | ||||
|     return os.path.realpath(saveto) | ||||
|  | ||||
| def main(argv, version=DEFAULT_VERSION): | ||||
|     """Install or upgrade setuptools and EasyInstall""" | ||||
|  | ||||
|     try: | ||||
|         import setuptools | ||||
|     except ImportError: | ||||
|         egg = None | ||||
|         try: | ||||
|             egg = download_setuptools(version, delay=0) | ||||
|             sys.path.insert(0,egg) | ||||
|             from setuptools.command.easy_install import main | ||||
|             return main(list(argv)+[egg])   # we're done here | ||||
|         finally: | ||||
|             if egg and os.path.exists(egg): | ||||
|                 os.unlink(egg) | ||||
|     else: | ||||
|         if setuptools.__version__ == '0.0.1': | ||||
|             # tell the user to uninstall obsolete version | ||||
|             use_setuptools(version) | ||||
|  | ||||
|     req = "setuptools>="+version | ||||
|     import pkg_resources | ||||
|     try: | ||||
|         pkg_resources.require(req) | ||||
|     except pkg_resources.VersionConflict: | ||||
|         try: | ||||
|             from setuptools.command.easy_install import main | ||||
|         except ImportError: | ||||
|             from easy_install import main | ||||
|         main(list(argv)+[download_setuptools(delay=0)]) | ||||
|         sys.exit(0) # try to force an exit | ||||
|     else: | ||||
|         if argv: | ||||
|             from setuptools.command.easy_install import main | ||||
|             main(argv) | ||||
|         else: | ||||
|             print "Setuptools version",version,"or greater has been installed." | ||||
|             print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' | ||||
|  | ||||
|  | ||||
|  | ||||
| def update_md5(filenames): | ||||
|     """Update our built-in md5 registry""" | ||||
|  | ||||
|     import re | ||||
|     from md5 import md5 | ||||
|  | ||||
|     for name in filenames: | ||||
|         base = os.path.basename(name) | ||||
|         f = open(name,'rb') | ||||
|         md5_data[base] = md5(f.read()).hexdigest() | ||||
|         f.close() | ||||
|  | ||||
|     data = ["    %r: %r,\n" % it for it in md5_data.items()] | ||||
|     data.sort() | ||||
|     repl = "".join(data) | ||||
|  | ||||
|     import inspect | ||||
|     srcfile = inspect.getsourcefile(sys.modules[__name__]) | ||||
|     f = open(srcfile, 'rb'); src = f.read(); f.close() | ||||
|  | ||||
|     match = re.search("\nmd5_data = {\n([^}]+)}", src) | ||||
|     if not match: | ||||
|         print >>sys.stderr, "Internal error!" | ||||
|         sys.exit(2) | ||||
|  | ||||
|     src = src[:match.start(1)] + repl + src[match.end(1):] | ||||
|     f = open(srcfile,'w') | ||||
|     f.write(src) | ||||
|     f.close() | ||||
|  | ||||
|  | ||||
| if __name__=='__main__': | ||||
|     if len(sys.argv)>2 and sys.argv[1]=='--md5update': | ||||
|         update_md5(sys.argv[2:]) | ||||
|     else: | ||||
|         main(sys.argv[1:]) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										69
									
								
								run_tests.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								run_tests.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import logging | ||||
| import unittest | ||||
|  | ||||
| from argparse import ArgumentParser | ||||
| from distutils.core import Command | ||||
| from importlib import import_module | ||||
| from pathlib import Path | ||||
|  | ||||
|  | ||||
| def run_tests(filenames=None): | ||||
|     """ | ||||
|     Find and run all tests in the tests/ directory. | ||||
|  | ||||
|     Excludes live tests (tests/live_*). | ||||
|     """ | ||||
|     if not filenames: | ||||
|         filenames = [i for i in Path('tests').glob('test_*')] | ||||
|     else: | ||||
|         filenames = [Path(i) for i in filenames] | ||||
|  | ||||
|     modules = ['.'.join(test.parts[:-1] + (test.stem,)) for test in filenames] | ||||
|  | ||||
|     suites = [] | ||||
|     for filename in modules: | ||||
|         module = import_module(filename) | ||||
|         suites.append(module.suite) | ||||
|  | ||||
|     tests = unittest.TestSuite(suites) | ||||
|     runner = unittest.TextTestRunner(verbosity=2) | ||||
|  | ||||
|     # Disable logging output | ||||
|     logging.basicConfig(level=100) | ||||
|     logging.disable(100) | ||||
|  | ||||
|     result = runner.run(tests) | ||||
|     return result | ||||
|  | ||||
|  | ||||
| # Add a 'test' command for setup.py | ||||
|  | ||||
| class TestCommand(Command): | ||||
|  | ||||
|     user_options = [] | ||||
|  | ||||
|     def initialize_options(self): | ||||
|         pass | ||||
|  | ||||
|     def finalize_options(self): | ||||
|         pass | ||||
|  | ||||
|     def run(self): | ||||
|         run_tests() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     parser = ArgumentParser(description='Run unit tests.') | ||||
|     parser.add_argument('tests', metavar='TEST', nargs='*', help='list of tests to run, or nothing to run them all') | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     result = run_tests(args.tests) | ||||
|     print("<tests %s ran='%s' errors='%s' fails='%s' success='%s'/>" % ( | ||||
|         "xmlns='http//andyet.net/protocol/tests'", | ||||
|         result.testsRun, len(result.errors), | ||||
|         len(result.failures), result.wasSuccessful())) | ||||
|  | ||||
|     sys.exit(not result.wasSuccessful()) | ||||
							
								
								
									
										177
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								setup.py
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/env python | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # Copyright (C) 2007-2011 Nathanael C. Fritz | ||||
| @@ -7,117 +7,82 @@ | ||||
| # This software is licensed as described in the README.rst and LICENSE | ||||
| # file, which you should have received as part of this distribution. | ||||
|  | ||||
| import sys | ||||
| import codecs | ||||
| import os | ||||
| from pathlib import Path | ||||
| from subprocess import call, DEVNULL, check_output, CalledProcessError | ||||
| from tempfile import TemporaryFile | ||||
| try: | ||||
|     from setuptools import setup, Command | ||||
|     from setuptools import setup | ||||
| except ImportError: | ||||
|     from distutils.core import setup, Command | ||||
| # from ez_setup import use_setuptools | ||||
|     from distutils.core import setup | ||||
|  | ||||
| from testall import TestCommand | ||||
| from sleekxmpp.version import __version__ | ||||
| # if 'cygwin' in sys.platform.lower(): | ||||
| #     min_version = '0.6c6' | ||||
| # else: | ||||
| #     min_version = '0.6a9' | ||||
| # | ||||
| # try: | ||||
| #     use_setuptools(min_version=min_version) | ||||
| # except TypeError: | ||||
| #     # locally installed ez_setup won't have min_version | ||||
| #     use_setuptools() | ||||
| # | ||||
| # from setuptools import setup, find_packages, Extension, Feature | ||||
| from run_tests import TestCommand | ||||
| from slixmpp.version import __version__ | ||||
|  | ||||
| VERSION          = __version__ | ||||
| DESCRIPTION      = 'SleekXMPP is an elegant Python library for XMPP (aka Jabber, Google Talk, etc).' | ||||
| with codecs.open('README.rst', 'r', encoding='UTF-8') as readme: | ||||
|     LONG_DESCRIPTION = ''.join(readme) | ||||
| VERSION = __version__ | ||||
| DESCRIPTION = ('Slixmpp is an elegant Python library for XMPP (aka Jabber).') | ||||
| with open('README.rst', encoding='utf8') as readme: | ||||
|     LONG_DESCRIPTION = readme.read() | ||||
|  | ||||
| CLASSIFIERS      = [ 'Intended Audience :: Developers', | ||||
|                      'License :: OSI Approved :: MIT License', | ||||
|                      'Programming Language :: Python', | ||||
|                      'Programming Language :: Python :: 2.6', | ||||
|                      'Programming Language :: Python :: 2.7', | ||||
|                      'Programming Language :: Python :: 3.1', | ||||
|                      'Programming Language :: Python :: 3.2', | ||||
|                      'Topic :: Software Development :: Libraries :: Python Modules', | ||||
|                    ] | ||||
| CLASSIFIERS = [ | ||||
|     'Intended Audience :: Developers', | ||||
|     'License :: OSI Approved :: MIT License', | ||||
|     'Programming Language :: Python', | ||||
|     'Programming Language :: Python :: 3.7', | ||||
|     'Programming Language :: Python :: 3.8', | ||||
|     'Topic :: Internet :: XMPP', | ||||
|     'Topic :: Software Development :: Libraries :: Python Modules', | ||||
| ] | ||||
|  | ||||
| packages     = [ 'sleekxmpp', | ||||
|                  'sleekxmpp/stanza', | ||||
|                  'sleekxmpp/test', | ||||
|                  'sleekxmpp/roster', | ||||
|                  'sleekxmpp/xmlstream', | ||||
|                  'sleekxmpp/xmlstream/matcher', | ||||
|                  'sleekxmpp/xmlstream/handler', | ||||
|                  'sleekxmpp/plugins', | ||||
|                  'sleekxmpp/plugins/xep_0004', | ||||
|                  'sleekxmpp/plugins/xep_0004/stanza', | ||||
|                  'sleekxmpp/plugins/xep_0009', | ||||
|                  'sleekxmpp/plugins/xep_0009/stanza', | ||||
|                  'sleekxmpp/plugins/xep_0012', | ||||
|                  'sleekxmpp/plugins/xep_0027', | ||||
|                  'sleekxmpp/plugins/xep_0030', | ||||
|                  'sleekxmpp/plugins/xep_0030/stanza', | ||||
|                  'sleekxmpp/plugins/xep_0033', | ||||
|                  'sleekxmpp/plugins/xep_0047', | ||||
|                  'sleekxmpp/plugins/xep_0050', | ||||
|                  'sleekxmpp/plugins/xep_0054', | ||||
|                  'sleekxmpp/plugins/xep_0059', | ||||
|                  'sleekxmpp/plugins/xep_0060', | ||||
|                  'sleekxmpp/plugins/xep_0060/stanza', | ||||
|                  'sleekxmpp/plugins/xep_0066', | ||||
|                  'sleekxmpp/plugins/xep_0077', | ||||
|                  'sleekxmpp/plugins/xep_0078', | ||||
|                  'sleekxmpp/plugins/xep_0080', | ||||
|                  'sleekxmpp/plugins/xep_0084', | ||||
|                  'sleekxmpp/plugins/xep_0085', | ||||
|                  'sleekxmpp/plugins/xep_0086', | ||||
|                  'sleekxmpp/plugins/xep_0092', | ||||
|                  'sleekxmpp/plugins/xep_0107', | ||||
|                  'sleekxmpp/plugins/xep_0108', | ||||
|                  'sleekxmpp/plugins/xep_0115', | ||||
|                  'sleekxmpp/plugins/xep_0118', | ||||
|                  'sleekxmpp/plugins/xep_0128', | ||||
|                  'sleekxmpp/plugins/xep_0153', | ||||
|                  'sleekxmpp/plugins/xep_0172', | ||||
|                  'sleekxmpp/plugins/xep_0184', | ||||
|                  'sleekxmpp/plugins/xep_0186', | ||||
|                  'sleekxmpp/plugins/xep_0198', | ||||
|                  'sleekxmpp/plugins/xep_0199', | ||||
|                  'sleekxmpp/plugins/xep_0202', | ||||
|                  'sleekxmpp/plugins/xep_0203', | ||||
|                  'sleekxmpp/plugins/xep_0221', | ||||
|                  'sleekxmpp/plugins/xep_0224', | ||||
|                  'sleekxmpp/plugins/xep_0231', | ||||
|                  'sleekxmpp/plugins/xep_0249', | ||||
|                  'sleekxmpp/plugins/xep_0258', | ||||
|                  'sleekxmpp/features', | ||||
|                  'sleekxmpp/features/feature_mechanisms', | ||||
|                  'sleekxmpp/features/feature_mechanisms/stanza', | ||||
|                  'sleekxmpp/features/feature_starttls', | ||||
|                  'sleekxmpp/features/feature_bind', | ||||
|                  'sleekxmpp/features/feature_session', | ||||
|                  'sleekxmpp/features/feature_rosterver', | ||||
|                  'sleekxmpp/thirdparty', | ||||
|                  'sleekxmpp/thirdparty/suelta', | ||||
|                  'sleekxmpp/thirdparty/suelta/mechanisms', | ||||
|                  ] | ||||
| packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')] | ||||
|  | ||||
| def check_include(library_name, header): | ||||
|     command = [os.environ.get('PKG_CONFIG', 'pkg-config'), '--cflags', library_name] | ||||
|     try: | ||||
|         cflags = check_output(command).decode('utf-8').split() | ||||
|     except FileNotFoundError: | ||||
|         print('pkg-config not found.') | ||||
|         return False | ||||
|     except CalledProcessError: | ||||
|         # pkg-config already prints the missing libraries on stderr. | ||||
|         return False | ||||
|     command = [os.environ.get('CC', 'cc')] + cflags + ['-E', '-'] | ||||
|     with TemporaryFile('w+') as c_file: | ||||
|         c_file.write('#include <%s>' % header) | ||||
|         c_file.seek(0) | ||||
|         try: | ||||
|             return call(command, stdin=c_file, stdout=DEVNULL, stderr=DEVNULL) == 0 | ||||
|         except FileNotFoundError: | ||||
|             print('%s headers not found.' % library_name) | ||||
|             return False | ||||
|  | ||||
| HAS_PYTHON_HEADERS = check_include('python3', 'Python.h') | ||||
| HAS_STRINGPREP_HEADERS = check_include('libidn', 'stringprep.h') | ||||
|  | ||||
| ext_modules = None | ||||
| if HAS_PYTHON_HEADERS and HAS_STRINGPREP_HEADERS: | ||||
|     try: | ||||
|         from Cython.Build import cythonize | ||||
|     except ImportError: | ||||
|         print('Cython not found, falling back to the slow stringprep module.') | ||||
|     else: | ||||
|         ext_modules = cythonize('slixmpp/stringprep.pyx') | ||||
| else: | ||||
|     print('Falling back to the slow stringprep module.') | ||||
|  | ||||
| setup( | ||||
|     name             = "sleekxmpp", | ||||
|     version          = VERSION, | ||||
|     description      = DESCRIPTION, | ||||
|     long_description = LONG_DESCRIPTION, | ||||
|     author       = 'Nathanael Fritz', | ||||
|     author_email = 'fritzy [at] netflint.net', | ||||
|     url          = 'http://github.com/fritzy/SleekXMPP', | ||||
|     license      = 'MIT', | ||||
|     platforms    = [ 'any' ], | ||||
|     packages     = packages, | ||||
|     requires     = [ 'dnspython', 'pyasn1', 'pyasn1_modules' ], | ||||
|     classifiers  = CLASSIFIERS, | ||||
|     cmdclass     = {'test': TestCommand} | ||||
|     name="slixmpp", | ||||
|     version=VERSION, | ||||
|     description=DESCRIPTION, | ||||
|     long_description=LONG_DESCRIPTION, | ||||
|     author='Florent Le Coz', | ||||
|     author_email='louiz@louiz.org', | ||||
|     url='https://lab.louiz.org/poezio/slixmpp', | ||||
|     license='MIT', | ||||
|     platforms=['any'], | ||||
|     packages=packages, | ||||
|     ext_modules=ext_modules, | ||||
|     install_requires=['aiodns>=1.0', 'pyasn1', 'pyasn1_modules', 'aiohttp'], | ||||
|     classifiers=CLASSIFIERS, | ||||
|     cmdclass={'test': TestCommand} | ||||
| ) | ||||
|   | ||||
| @@ -1,18 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.basexmpp import BaseXMPP | ||||
| from sleekxmpp.clientxmpp import ClientXMPP | ||||
| from sleekxmpp.componentxmpp import ComponentXMPP | ||||
| from sleekxmpp.stanza import Message, Presence, Iq | ||||
| from sleekxmpp.xmlstream.handler import * | ||||
| from sleekxmpp.xmlstream import XMLStream, RestartStream | ||||
| from sleekxmpp.xmlstream.matcher import * | ||||
| from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET | ||||
|  | ||||
| from sleekxmpp.version import __version__, __version_info__ | ||||
| @@ -1,19 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.base import register_plugin | ||||
|  | ||||
| from sleekxmpp.features.feature_bind.bind import FeatureBind | ||||
| from sleekxmpp.features.feature_bind.stanza import Bind | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureBind) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_bind = FeatureBind | ||||
| @@ -1,63 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from sleekxmpp.stanza import Iq, StreamFeatures | ||||
| from sleekxmpp.features.feature_bind import stanza | ||||
| from sleekxmpp.xmlstream import register_stanza_plugin | ||||
| from sleekxmpp.plugins import BasePlugin, register_plugin | ||||
|  | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class FeatureBind(BasePlugin): | ||||
|  | ||||
|     name = 'feature_bind' | ||||
|     description = 'RFC 6120: Stream Feature: Resource Binding' | ||||
|     dependencies = set() | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|         self.xmpp.register_feature('bind', | ||||
|                 self._handle_bind_resource, | ||||
|                 restart=False, | ||||
|                 order=10000) | ||||
|  | ||||
|         register_stanza_plugin(Iq, stanza.Bind) | ||||
|         register_stanza_plugin(StreamFeatures, stanza.Bind) | ||||
|  | ||||
|     def _handle_bind_resource(self, features): | ||||
|         """ | ||||
|         Handle requesting a specific resource. | ||||
|  | ||||
|         Arguments: | ||||
|             features -- The stream features stanza. | ||||
|         """ | ||||
|         log.debug("Requesting resource: %s", self.xmpp.boundjid.resource) | ||||
|         iq = self.xmpp.Iq() | ||||
|         iq['type'] = 'set' | ||||
|         iq.enable('bind') | ||||
|         if self.xmpp.boundjid.resource: | ||||
|             iq['bind']['resource'] = self.xmpp.boundjid.resource | ||||
|         response = iq.send(now=True) | ||||
|  | ||||
|         self.xmpp.set_jid(response['bind']['jid']) | ||||
|         self.xmpp.bound = True | ||||
|         self.xmpp.event('session_bind', self.xmpp.boundjid, direct=True) | ||||
|  | ||||
|         self.xmpp.features.add('bind') | ||||
|  | ||||
|         log.info("Node set to: %s", self.xmpp.boundjid.full) | ||||
|  | ||||
|         if 'session' not in features['features']: | ||||
|             log.debug("Established Session") | ||||
|             self.xmpp.sessionstarted = True | ||||
|             self.xmpp.session_started_event.set() | ||||
|             self.xmpp.event("session_start") | ||||
| @@ -1,22 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.base import register_plugin | ||||
|  | ||||
| from sleekxmpp.features.feature_mechanisms.mechanisms import FeatureMechanisms | ||||
| from sleekxmpp.features.feature_mechanisms.stanza import Mechanisms | ||||
| from sleekxmpp.features.feature_mechanisms.stanza import Auth | ||||
| from sleekxmpp.features.feature_mechanisms.stanza import Success | ||||
| from sleekxmpp.features.feature_mechanisms.stanza import Failure | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureMechanisms) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_mechanisms = FeatureMechanisms | ||||
| @@ -1,171 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
|  | ||||
| from sleekxmpp.thirdparty import suelta | ||||
| from sleekxmpp.thirdparty.suelta.exceptions import SASLCancelled, SASLError | ||||
| from sleekxmpp.thirdparty.suelta.exceptions import SASLPrepFailure | ||||
|  | ||||
| from sleekxmpp.stanza import StreamFeatures | ||||
| from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin | ||||
| from sleekxmpp.plugins import BasePlugin | ||||
| from sleekxmpp.xmlstream.matcher import MatchXPath | ||||
| from sleekxmpp.xmlstream.handler import Callback | ||||
| from sleekxmpp.features.feature_mechanisms import stanza | ||||
|  | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class FeatureMechanisms(BasePlugin): | ||||
|  | ||||
|     name = 'feature_mechanisms' | ||||
|     description = 'RFC 6120: Stream Feature: SASL' | ||||
|     dependencies = set() | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|         self.use_mech = self.config.get('use_mech', None) | ||||
|  | ||||
|         if not self.use_mech and not self.xmpp.boundjid.user: | ||||
|             self.use_mech = 'ANONYMOUS' | ||||
|  | ||||
|         def tls_active(): | ||||
|             return 'starttls' in self.xmpp.features | ||||
|  | ||||
|         def basic_callback(mech, values): | ||||
|             creds = self.xmpp.credentials | ||||
|             for value in values: | ||||
|                 if value == 'username': | ||||
|                     values['username'] = self.xmpp.boundjid.user | ||||
|                 elif value == 'password': | ||||
|                     values['password'] = creds['password'] | ||||
|                 elif value == 'email': | ||||
|                     jid = self.xmpp.boundjid.bare | ||||
|                     values['email'] = creds.get('email', jid) | ||||
|                 elif value in creds: | ||||
|                     values[value] = creds[value] | ||||
|             mech.fulfill(values) | ||||
|  | ||||
|         sasl_callback = self.config.get('sasl_callback', None) | ||||
|         if sasl_callback is None: | ||||
|             sasl_callback = basic_callback | ||||
|  | ||||
|         self.mech = None | ||||
|         self.sasl = suelta.SASL(self.xmpp.boundjid.domain, 'xmpp', | ||||
|                                 username=self.xmpp.boundjid.user, | ||||
|                                 sec_query=suelta.sec_query_allow, | ||||
|                                 request_values=sasl_callback, | ||||
|                                 tls_active=tls_active, | ||||
|                                 mech=self.use_mech) | ||||
|  | ||||
|         self.mech_list = set() | ||||
|         self.attempted_mechs = set() | ||||
|  | ||||
|         register_stanza_plugin(StreamFeatures, stanza.Mechanisms) | ||||
|  | ||||
|         self.xmpp.register_stanza(stanza.Success) | ||||
|         self.xmpp.register_stanza(stanza.Failure) | ||||
|         self.xmpp.register_stanza(stanza.Auth) | ||||
|         self.xmpp.register_stanza(stanza.Challenge) | ||||
|         self.xmpp.register_stanza(stanza.Response) | ||||
|         self.xmpp.register_stanza(stanza.Abort) | ||||
|  | ||||
|         self.xmpp.register_handler( | ||||
|                 Callback('SASL Success', | ||||
|                          MatchXPath(stanza.Success.tag_name()), | ||||
|                          self._handle_success, | ||||
|                          instream=True)) | ||||
|         self.xmpp.register_handler( | ||||
|                 Callback('SASL Failure', | ||||
|                          MatchXPath(stanza.Failure.tag_name()), | ||||
|                          self._handle_fail, | ||||
|                          instream=True)) | ||||
|         self.xmpp.register_handler( | ||||
|                 Callback('SASL Challenge', | ||||
|                          MatchXPath(stanza.Challenge.tag_name()), | ||||
|                          self._handle_challenge)) | ||||
|  | ||||
|         self.xmpp.register_feature('mechanisms', | ||||
|                 self._handle_sasl_auth, | ||||
|                 restart=True, | ||||
|                 order=self.config.get('order', 100)) | ||||
|  | ||||
|     def _handle_sasl_auth(self, features): | ||||
|         """ | ||||
|         Handle authenticating using SASL. | ||||
|  | ||||
|         Arguments: | ||||
|             features -- The stream features stanza. | ||||
|         """ | ||||
|         if 'mechanisms' in self.xmpp.features: | ||||
|             # SASL authentication has already succeeded, but the | ||||
|             # server has incorrectly offered it again. | ||||
|             return False | ||||
|  | ||||
|         if not self.use_mech: | ||||
|             self.mech_list = set(features['mechanisms']) | ||||
|         else: | ||||
|             self.mech_list = set([self.use_mech]) | ||||
|         return self._send_auth() | ||||
|  | ||||
|     def _send_auth(self): | ||||
|         mech_list = self.mech_list - self.attempted_mechs | ||||
|         self.mech = self.sasl.choose_mechanism(mech_list) | ||||
|  | ||||
|         if mech_list and self.mech is not None: | ||||
|             resp = stanza.Auth(self.xmpp) | ||||
|             resp['mechanism'] = self.mech.name | ||||
|             try: | ||||
|                 resp['value'] = self.mech.process() | ||||
|             except SASLCancelled: | ||||
|                 self.attempted_mechs.add(self.mech.name) | ||||
|                 self._send_auth() | ||||
|             except SASLError: | ||||
|                 self.attempted_mechs.add(self.mech.name) | ||||
|                 self._send_auth() | ||||
|             except SASLPrepFailure: | ||||
|                 log.exception("A credential value did not pass SASLprep.") | ||||
|                 self.xmpp.disconnect() | ||||
|             else: | ||||
|                 resp.send(now=True) | ||||
|         else: | ||||
|             log.error("No appropriate login method.") | ||||
|             self.xmpp.event("no_auth", direct=True) | ||||
|             self.attempted_mechs = set() | ||||
|             self.xmpp.disconnect() | ||||
|         return True | ||||
|  | ||||
|     def _handle_challenge(self, stanza): | ||||
|         """SASL challenge received. Process and send response.""" | ||||
|         resp = self.stanza.Response(self.xmpp) | ||||
|         try: | ||||
|             resp['value'] = self.mech.process(stanza['value']) | ||||
|         except SASLCancelled: | ||||
|             self.stanza.Abort(self.xmpp).send() | ||||
|         except SASLError: | ||||
|             self.stanza.Abort(self.xmpp).send() | ||||
|         else: | ||||
|             resp.send(now=True) | ||||
|  | ||||
|     def _handle_success(self, stanza): | ||||
|         """SASL authentication succeeded. Restart the stream.""" | ||||
|         self.attempted_mechs = set() | ||||
|         self.xmpp.authenticated = True | ||||
|         self.xmpp.features.add('mechanisms') | ||||
|         self.xmpp.event('auth_success', stanza, direct=True) | ||||
|         raise RestartStream() | ||||
|  | ||||
|     def _handle_fail(self, stanza): | ||||
|         """SASL authentication failed. Disconnect and shutdown.""" | ||||
|         self.attempted_mechs.add(self.mech.name) | ||||
|         log.info("Authentication failed: %s", stanza['condition']) | ||||
|         self.xmpp.event("failed_auth", stanza, direct=True) | ||||
|         self._send_auth() | ||||
|         return True | ||||
| @@ -1,16 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
|  | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.mechanisms import Mechanisms | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.auth import Auth | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.success import Success | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.failure import Failure | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.challenge import Challenge | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.response import Response | ||||
| from sleekxmpp.features.feature_mechanisms.stanza.abort import Abort | ||||
| @@ -1,24 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.xmlstream import StanzaBase | ||||
|  | ||||
|  | ||||
| class Success(StanzaBase): | ||||
|  | ||||
|     """ | ||||
|     """ | ||||
|  | ||||
|     name = 'success' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set() | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def setup(self, xml): | ||||
|         StanzaBase.setup(self, xml) | ||||
|         self.xml.tag = self.tag_name() | ||||
| @@ -1,19 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2012  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.base import register_plugin | ||||
|  | ||||
| from sleekxmpp.features.feature_rosterver.rosterver import FeatureRosterVer | ||||
| from sleekxmpp.features.feature_rosterver.stanza import RosterVer | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureRosterVer) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_rosterver = FeatureRosterVer | ||||
| @@ -1,19 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.plugins.base import register_plugin | ||||
|  | ||||
| from sleekxmpp.features.feature_session.session import FeatureSession | ||||
| from sleekxmpp.features.feature_session.stanza import Session | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureSession) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_session = FeatureSession | ||||
| @@ -1,20 +0,0 @@ | ||||
| """ | ||||
|     SleekXMPP: The Sleek XMPP Library | ||||
|     Copyright (C) 2011  Nathanael C. Fritz | ||||
|     This file is part of SleekXMPP. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from sleekxmpp.xmlstream import ElementBase | ||||
|  | ||||
|  | ||||
| class Session(ElementBase): | ||||
|  | ||||
|     """ | ||||
|     """ | ||||
|  | ||||
|     name = 'session' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-session' | ||||
|     interfaces = set() | ||||
|     plugin_attrib = 'session' | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user