mirror of
				https://github.com/Tha14/toxic.git
				synced 2025-11-04 00:36:51 +01:00 
			
		
		
		
	Compare commits
	
		
			1236 Commits
		
	
	
		
			0.3.0
			...
			TokTok-mas
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ae94bc593b | ||
| 
						 | 
					81eb58532e | ||
| 
						 | 
					8464ea9a7a | ||
| 
						 | 
					b77bff35a1 | ||
| 
						 | 
					eb964b64c2 | ||
| 
						 | 
					2ff9d29491 | ||
| 
						 | 
					2640919318 | ||
| 
						 | 
					2fcbc4fa1c | ||
| 
						 | 
					4330bf5867 | ||
| 
						 | 
					3f1b7cdd26 | ||
| 
						 | 
					1e985c1456 | ||
| 
						 | 
					61740bda85 | ||
| 
						 | 
					0d8e6d713e | ||
| 
						 | 
					39e4ff8bd6 | ||
| 
						 | 
					0434ac186a | ||
| 
						 | 
					8d9d51640c | ||
| 
						 | 
					c4c0c0d1f4 | ||
| 
						 | 
					3f2826bd66 | ||
| 
						 | 
					7b7ea0e386 | ||
| 
						 | 
					d35a38735b | ||
| 
						 | 
					f0c4906fdc | ||
| 
						 | 
					56ba61e061 | ||
| 
						 | 
					898d89e95a | ||
| 
						 | 
					1fd1e27bdf | ||
| 
						 | 
					8e84ac58d4 | ||
| 
						 | 
					9d65997871 | ||
| 
						 | 
					da2889f3ab | ||
| 
						 | 
					312b38d253 | ||
| 
						 | 
					0554bf0240 | ||
| 
						 | 
					53a7530e8a | ||
| 
						 | 
					41be04a142 | ||
| 
						 | 
					31f36318a2 | ||
| 
						 | 
					f882fdf608 | ||
| 
						 | 
					7e1e410307 | ||
| 
						 | 
					c135c812c2 | ||
| 
						 | 
					6c239193ab | ||
| 
						 | 
					de7db08352 | ||
| 
						 | 
					ba5ded9bc2 | ||
| 
						 | 
					4581dee4fc | ||
| 
						 | 
					d75d6e8b60 | ||
| 
						 | 
					142ce642f0 | ||
| 
						 | 
					7dead5ec96 | ||
| 
						 | 
					ddcf224db2 | ||
| 
						 | 
					daf794c4a2 | ||
| 
						 | 
					dac0124f0f | ||
| 
						 | 
					15b7a30925 | ||
| 
						 | 
					77ab71f26f | ||
| 
						 | 
					68e1ba312d | ||
| 
						 | 
					752fc6d619 | ||
| 
						 | 
					16bcb27ca7 | ||
| 
						 | 
					71d7d355a6 | ||
| 
						 | 
					4188b392cc | ||
| 
						 | 
					811fbfbb1e | ||
| 
						 | 
					32eb7d3040 | ||
| 
						 | 
					42763905d7 | ||
| 
						 | 
					f64300d1d6 | ||
| 
						 | 
					1a723f0e8e | ||
| 
						 | 
					a86884c40e | ||
| 
						 | 
					3f02e119f4 | ||
| 
						 | 
					1bbd50aac7 | ||
| 
						 | 
					e7a0c32a68 | ||
| 
						 | 
					7560bc9547 | ||
| 
						 | 
					2b43340c90 | ||
| 
						 | 
					ff1620c923 | ||
| 
						 | 
					1303053a27 | ||
| 
						 | 
					91f194c821 | ||
| 
						 | 
					478762f76c | ||
| 
						 | 
					4d96d6a753 | ||
| 
						 | 
					3cdcfbf4e5 | ||
| 
						 | 
					4c302da503 | ||
| 
						 | 
					26b5fe8f9d | ||
| 
						 | 
					22d60232fb | ||
| 
						 | 
					e428879beb | ||
| 
						 | 
					3015138a5a | ||
| 
						 | 
					9c06ad608b | ||
| 
						 | 
					015dbd9a96 | ||
| 
						 | 
					a7466c3142 | ||
| 
						 | 
					f012007cc4 | ||
| 
						 | 
					dcf3baf60f | ||
| 
						 | 
					4bda799a4b | ||
| 
						 | 
					bdeae33d48 | ||
| 
						 | 
					47591d5298 | ||
| 
						 | 
					b5ace27a3e | ||
| 
						 | 
					b334622d36 | ||
| 
						 | 
					4bfb344caa | ||
| 
						 | 
					16d96d6faf | ||
| 
						 | 
					0ab2bad226 | ||
| 
						 | 
					68db926f9f | ||
| 
						 | 
					b270c1e8b7 | ||
| 
						 | 
					e7142e49fd | ||
| 
						 | 
					610906d07f | ||
| 
						 | 
					6f72a191ba | ||
| 
						 | 
					dd5fa236ae | ||
| 
						 | 
					51e1ab94b3 | ||
| 
						 | 
					ddc8c53abf | ||
| 
						 | 
					46513017e3 | ||
| 
						 | 
					98cb7f58c0 | ||
| 
						 | 
					206bf407fd | ||
| 
						 | 
					0a8ac4de3b | ||
| 
						 | 
					87d54acad0 | ||
| 
						 | 
					45ff6d8bac | ||
| 
						 | 
					437dd8baeb | ||
| 
						 | 
					b080236ee5 | ||
| 
						 | 
					116bff8cef | ||
| 
						 | 
					ddeca171a0 | ||
| 
						 | 
					127f9462e0 | ||
| 
						 | 
					4b5a9abbd4 | ||
| 
						 | 
					bb2257973e | ||
| 
						 | 
					12b9cd2386 | ||
| 
						 | 
					2cbe8fa880 | ||
| 
						 | 
					2e39bee05a | ||
| 
						 | 
					05eda76643 | ||
| 
						 | 
					f7b73af9a7 | ||
| 
						 | 
					73aaa44d12 | ||
| 
						 | 
					e4abd8b36b | ||
| 
						 | 
					9e3d4f3889 | ||
| 
						 | 
					b7d67c1d86 | ||
| 
						 | 
					c4a11f8dc7 | ||
| 
						 | 
					d18cc8cbc2 | ||
| 
						 | 
					ce6d4861fb | ||
| 
						 | 
					8f0e6026f0 | ||
| 
						 | 
					258736995d | ||
| 
						 | 
					56e03a3f8b | ||
| 
						 | 
					b6c746b5f5 | ||
| 
						 | 
					03673cbced | ||
| 
						 | 
					0fea930c24 | ||
| 
						 | 
					94d22a8853 | ||
| 
						 | 
					63cc23401a | ||
| 
						 | 
					f90a774470 | ||
| 
						 | 
					e7c5fbc873 | ||
| 
						 | 
					d62902ffb3 | ||
| 
						 | 
					bebff3be0e | ||
| 
						 | 
					2be4847b53 | ||
| 
						 | 
					4557614443 | ||
| 
						 | 
					5b30ecf2e4 | ||
| 
						 | 
					2413ad2b59 | ||
| 
						 | 
					52855b805a | ||
| 
						 | 
					20b5e46850 | ||
| 
						 | 
					f2b796940e | ||
| 
						 | 
					a37bf300f9 | ||
| 
						 | 
					cb524dcbc3 | ||
| 
						 | 
					4144b868ce | ||
| 
						 | 
					af11f16bef | ||
| 
						 | 
					1d27a496ef | ||
| 
						 | 
					32bd9dc1a7 | ||
| 
						 | 
					3cd2bc7e3c | ||
| 
						 | 
					43ca840658 | ||
| 
						 | 
					685837357b | ||
| 
						 | 
					812a13b0fb | ||
| 
						 | 
					641fa471d2 | ||
| 
						 | 
					8d5755f2d8 | ||
| 
						 | 
					af510b6666 | ||
| 
						 | 
					46f646afcf | ||
| 
						 | 
					68ce17a57f | ||
| 
						 | 
					a69fad15c1 | ||
| 
						 | 
					7621fe9a62 | ||
| 
						 | 
					f6d9bc3a74 | ||
| 
						 | 
					29aea0b42c | ||
| 
						 | 
					815c29ee31 | ||
| 
						 | 
					3917f664bf | ||
| 
						 | 
					a223329815 | ||
| 
						 | 
					3fec11d5f9 | ||
| 
						 | 
					221edb0012 | ||
| 
						 | 
					2710ab6034 | ||
| 
						 | 
					bc3ffac0ba | ||
| 
						 | 
					29f55c5277 | ||
| 
						 | 
					a290f0f7f8 | ||
| 
						 | 
					5cd196a769 | ||
| 
						 | 
					b14d983a8c | ||
| 
						 | 
					51f1daeec8 | ||
| 
						 | 
					b799c6a8d7 | ||
| 
						 | 
					b9f9546e2b | ||
| 
						 | 
					846bc4613e | ||
| 
						 | 
					a5a1f6015d | ||
| 
						 | 
					fe6a7074ea | ||
| 
						 | 
					db7c9fe426 | ||
| 
						 | 
					b1d8ab102f | ||
| 
						 | 
					0bd5b4ddee | ||
| 
						 | 
					c387df35f8 | ||
| 
						 | 
					351a50c214 | ||
| 
						 | 
					93175314b5 | ||
| 
						 | 
					b905a1a3c5 | ||
| 
						 | 
					c4386b195f | ||
| 
						 | 
					ed1e617380 | ||
| 
						 | 
					1382adb1f6 | ||
| 
						 | 
					ecf1c317b7 | ||
| 
						 | 
					cf0b99f1e5 | ||
| 
						 | 
					3605a296a9 | ||
| 
						 | 
					9375d220f9 | ||
| 
						 | 
					8f94b0a218 | ||
| 
						 | 
					85a0becbf9 | ||
| 
						 | 
					fec36ad9e6 | ||
| 
						 | 
					ecdf6f01d2 | ||
| 
						 | 
					e1bfa30769 | ||
| 
						 | 
					ebcbc7497b | ||
| 
						 | 
					e844ece28b | ||
| 
						 | 
					8508451ba6 | ||
| 
						 | 
					5cc83a7cb5 | ||
| 
						 | 
					febc725763 | ||
| 
						 | 
					f2c116feb3 | ||
| 
						 | 
					52dd60dc86 | ||
| 
						 | 
					80c0500299 | ||
| 
						 | 
					ab490d28b4 | ||
| 
						 | 
					a9f7f85617 | ||
| 
						 | 
					1bfc1ba371 | ||
| 
						 | 
					2ede39369a | ||
| 
						 | 
					922c184195 | ||
| 
						 | 
					56a9571509 | ||
| 
						 | 
					0136f22076 | ||
| 
						 | 
					c4ace288af | ||
| 
						 | 
					6d3fbfee59 | ||
| 
						 | 
					be5e7906da | ||
| 
						 | 
					369f26932e | ||
| 
						 | 
					22ea522baf | ||
| 
						 | 
					4f60d546e6 | ||
| 
						 | 
					76d1eafdc0 | ||
| 
						 | 
					37912f2d88 | ||
| 
						 | 
					09710327c5 | ||
| 
						 | 
					acee4615f8 | ||
| 
						 | 
					5ed26eda9b | ||
| 
						 | 
					6d2b90ac9f | ||
| 
						 | 
					02ea0fac44 | ||
| 
						 | 
					7d3d129624 | ||
| 
						 | 
					b3ed8bc35c | ||
| 
						 | 
					90210daca7 | ||
| 
						 | 
					0e13a1f1bc | ||
| 
						 | 
					09e2690211 | ||
| 
						 | 
					e65e3af274 | ||
| 
						 | 
					c6c60d018e | ||
| 
						 | 
					451d4ced80 | ||
| 
						 | 
					7a7402ff86 | ||
| 
						 | 
					600e013adc | ||
| 
						 | 
					1d71e2eb18 | ||
| 
						 | 
					f858714edd | ||
| 
						 | 
					4df44a7274 | ||
| 
						 | 
					a26ed9d28f | ||
| 
						 | 
					2bd5083b8f | ||
| 
						 | 
					8805f694b9 | ||
| 
						 | 
					71040355fd | ||
| 
						 | 
					6bc5d8c543 | ||
| 
						 | 
					abb39ea6b5 | ||
| 
						 | 
					15846d2b50 | ||
| 
						 | 
					958df9f2e8 | ||
| 
						 | 
					2fd43aebee | ||
| 
						 | 
					34c29745cc | ||
| 
						 | 
					da6fe41d75 | ||
| 
						 | 
					e17fa89d8f | ||
| 
						 | 
					f056f13329 | ||
| 
						 | 
					3515623159 | ||
| 
						 | 
					2194b9e259 | ||
| 
						 | 
					c24e1bd2b8 | ||
| 
						 | 
					38ec96e96a | ||
| 
						 | 
					d2b572ede1 | ||
| 
						 | 
					703d5419a3 | ||
| 
						 | 
					221d761ff4 | ||
| 
						 | 
					151f5f0c51 | ||
| 
						 | 
					4f6c603543 | ||
| 
						 | 
					a009f11c0c | ||
| 
						 | 
					1f8c11a33a | ||
| 
						 | 
					5e20e6b279 | ||
| 
						 | 
					1f02bb2be5 | ||
| 
						 | 
					98154b3cba | ||
| 
						 | 
					379ad9e116 | ||
| 
						 | 
					cb21672600 | ||
| 
						 | 
					4019395f44 | ||
| 
						 | 
					ee084c572c | ||
| 
						 | 
					41a8401ac5 | ||
| 
						 | 
					d8a3f7de4c | ||
| 
						 | 
					c425aa2f27 | ||
| 
						 | 
					94e026d114 | ||
| 
						 | 
					f89638635a | ||
| 
						 | 
					402b86687f | ||
| 
						 | 
					5b1b420ac0 | ||
| 
						 | 
					62ec514f17 | ||
| 
						 | 
					f893dd755f | ||
| 
						 | 
					9aedcf7753 | ||
| 
						 | 
					d3effa26b5 | ||
| 
						 | 
					2ec180789b | ||
| 
						 | 
					9f74d3a3a8 | ||
| 
						 | 
					9fcbc3bde0 | ||
| 
						 | 
					cf16849b37 | ||
| 
						 | 
					32442b6286 | ||
| 
						 | 
					50f227418b | ||
| 
						 | 
					fc06a625a6 | ||
| 
						 | 
					70bd39eb74 | ||
| 
						 | 
					4e0e322e32 | ||
| 
						 | 
					e73ac9b6a4 | ||
| 
						 | 
					bcda6e476e | ||
| 
						 | 
					5b29ce7132 | ||
| 
						 | 
					f43f644451 | ||
| 
						 | 
					d6fdac9739 | ||
| 
						 | 
					c6a2bb8a90 | ||
| 
						 | 
					04576fea7e | ||
| 
						 | 
					e6f839f9ac | ||
| 
						 | 
					eb02424f8a | ||
| 
						 | 
					2e609c46f6 | ||
| 
						 | 
					a474e3bf39 | ||
| 
						 | 
					93835f0455 | ||
| 
						 | 
					ac6d8ff89c | ||
| 
						 | 
					88e74224ed | ||
| 
						 | 
					deccaec40e | ||
| 
						 | 
					4419be36e8 | ||
| 
						 | 
					b34b51e8c1 | ||
| 
						 | 
					74416b4b58 | ||
| 
						 | 
					675712cea0 | ||
| 
						 | 
					36feebfe8d | ||
| 
						 | 
					3fe9abd84d | ||
| 
						 | 
					fd6432c727 | ||
| 
						 | 
					1feffcc2f0 | ||
| 
						 | 
					6bba3cb9e2 | ||
| 
						 | 
					3cb6db3d60 | ||
| 
						 | 
					77238eeadf | ||
| 
						 | 
					88270827a9 | ||
| 
						 | 
					aade65bfe1 | ||
| 
						 | 
					b24c5d8cf8 | ||
| 
						 | 
					9f0feb7223 | ||
| 
						 | 
					74c1eef1d1 | ||
| 
						 | 
					65c07a57db | ||
| 
						 | 
					ab99c1ac73 | ||
| 
						 | 
					05f5f16af3 | ||
| 
						 | 
					d16be574f3 | ||
| 
						 | 
					7e0b8b4870 | ||
| 
						 | 
					39c4b7ecdd | ||
| 
						 | 
					c5d9aca3e1 | ||
| 
						 | 
					fa0e645a79 | ||
| 
						 | 
					14a8bdb874 | ||
| 
						 | 
					93a73cbef2 | ||
| 
						 | 
					6aab9a79d8 | ||
| 
						 | 
					dfff777283 | ||
| 
						 | 
					a95fc7824c | ||
| 
						 | 
					f707dce2da | ||
| 
						 | 
					0d07d14b13 | ||
| 
						 | 
					6cc1525daa | ||
| 
						 | 
					49f5efaab0 | ||
| 
						 | 
					a5e5e98afc | ||
| 
						 | 
					4ab99c73a0 | ||
| 
						 | 
					e02cf1bb7d | ||
| 
						 | 
					9751cfc407 | ||
| 
						 | 
					36963a5b38 | ||
| 
						 | 
					7cf9c37aef | ||
| 
						 | 
					2b4b8c0289 | ||
| 
						 | 
					368a1465ec | ||
| 
						 | 
					fea317ee24 | ||
| 
						 | 
					8584feab80 | ||
| 
						 | 
					f7e48d294e | ||
| 
						 | 
					928f25bd89 | ||
| 
						 | 
					941ac1d951 | ||
| 
						 | 
					7af9327b37 | ||
| 
						 | 
					6b97df2615 | ||
| 
						 | 
					cea5f1fe04 | ||
| 
						 | 
					abfdbfe468 | ||
| 
						 | 
					462cfca175 | ||
| 
						 | 
					db410cb01e | ||
| 
						 | 
					a920f3edfe | ||
| 
						 | 
					2c3921a9fb | ||
| 
						 | 
					f295352495 | ||
| 
						 | 
					ffcc804efe | ||
| 
						 | 
					69be1bc398 | ||
| 
						 | 
					b4464eda4d | ||
| 
						 | 
					28dd43608d | ||
| 
						 | 
					11701d22a1 | ||
| 
						 | 
					4e2db756be | ||
| 
						 | 
					19cfe3d393 | ||
| 
						 | 
					c546df3917 | ||
| 
						 | 
					ed0a4fb3b8 | ||
| 
						 | 
					271ca08eb2 | ||
| 
						 | 
					0e79b8a076 | ||
| 
						 | 
					1606d01158 | ||
| 
						 | 
					c8a9ac21f3 | ||
| 
						 | 
					e91aaf6c73 | ||
| 
						 | 
					619fdc1098 | ||
| 
						 | 
					b7e613de32 | ||
| 
						 | 
					929fca3de1 | ||
| 
						 | 
					b67792f9f2 | ||
| 
						 | 
					96162bf254 | ||
| 
						 | 
					8a66c3fa4c | ||
| 
						 | 
					2cdcbc07a7 | ||
| 
						 | 
					6e0d19b01d | ||
| 
						 | 
					ad04fa4dcd | ||
| 
						 | 
					c2c612b85a | ||
| 
						 | 
					d359ba6a54 | ||
| 
						 | 
					54e2fe8d6f | ||
| 
						 | 
					53353825e2 | ||
| 
						 | 
					fcdc8e8b67 | ||
| 
						 | 
					9b6efb65de | ||
| 
						 | 
					c8ea02376e | ||
| 
						 | 
					2369b5e9e2 | ||
| 
						 | 
					8f28f1d748 | ||
| 
						 | 
					a33e5f4bec | ||
| 
						 | 
					e0a35a6569 | ||
| 
						 | 
					9863dfc2ae | ||
| 
						 | 
					c755247434 | ||
| 
						 | 
					879b2b236e | ||
| 
						 | 
					c6b9a288b6 | ||
| 
						 | 
					e9e5b5af8d | ||
| 
						 | 
					d175ff2480 | ||
| 
						 | 
					750258adef | ||
| 
						 | 
					60b4d62657 | ||
| 
						 | 
					ea78dca756 | ||
| 
						 | 
					3cb412632b | ||
| 
						 | 
					8301ab1bc2 | ||
| 
						 | 
					b6e90d2ebb | ||
| 
						 | 
					06c268417f | ||
| 
						 | 
					1458a6bbc5 | ||
| 
						 | 
					737d29864b | ||
| 
						 | 
					0a2ad23c15 | ||
| 
						 | 
					a455c80a1f | ||
| 
						 | 
					43bda5f7d9 | ||
| 
						 | 
					f2121fae74 | ||
| 
						 | 
					3241551cfb | ||
| 
						 | 
					6e90072fb8 | ||
| 
						 | 
					ca1fca5aa5 | ||
| 
						 | 
					ef1068b6aa | ||
| 
						 | 
					72982cee97 | ||
| 
						 | 
					9a4eaa8693 | ||
| 
						 | 
					64e7553fb0 | ||
| 
						 | 
					dd8df1df76 | ||
| 
						 | 
					c8d102b02d | ||
| 
						 | 
					a3fa7fd524 | ||
| 
						 | 
					b2ed8c0ead | ||
| 
						 | 
					bbdf4c96b9 | ||
| 
						 | 
					5496890b34 | ||
| 
						 | 
					fd85d8f87b | ||
| 
						 | 
					37e7b4c3d3 | ||
| 
						 | 
					92d76c7f99 | ||
| 
						 | 
					2a787c1097 | ||
| 
						 | 
					327259c4c8 | ||
| 
						 | 
					f173f4275e | ||
| 
						 | 
					48eaf8a14f | ||
| 
						 | 
					083611f18e | ||
| 
						 | 
					48ffae68a9 | ||
| 
						 | 
					c39f8909cd | ||
| 
						 | 
					32e541bd1c | ||
| 
						 | 
					f559bdabfe | ||
| 
						 | 
					0047ba0e9f | ||
| 
						 | 
					ecefc19b23 | ||
| 
						 | 
					e83b397494 | ||
| 
						 | 
					688ea927f8 | ||
| 
						 | 
					904f58c0e8 | ||
| 
						 | 
					035420e5c7 | ||
| 
						 | 
					444d8e7a74 | ||
| 
						 | 
					84a0276668 | ||
| 
						 | 
					312d0c3f42 | ||
| 
						 | 
					d8eca8393c | ||
| 
						 | 
					374b78c763 | ||
| 
						 | 
					409e4ddd96 | ||
| 
						 | 
					1beb35025b | ||
| 
						 | 
					51a1c660b4 | ||
| 
						 | 
					85d3c18ba6 | ||
| 
						 | 
					d0a7ca17d2 | ||
| 
						 | 
					36640224af | ||
| 
						 | 
					231078b6b9 | ||
| 
						 | 
					414f58d896 | ||
| 
						 | 
					4d73f8b241 | ||
| 
						 | 
					82e76a3b5b | ||
| 
						 | 
					0bc610e18d | ||
| 
						 | 
					02e6d2db3c | ||
| 
						 | 
					5a2c341259 | ||
| 
						 | 
					1a7eaeddba | ||
| 
						 | 
					f656d0a722 | ||
| 
						 | 
					09c1ad4566 | ||
| 
						 | 
					8b9e34db75 | ||
| 
						 | 
					dd9186e834 | ||
| 
						 | 
					5ff1517b28 | ||
| 
						 | 
					bbb639c5aa | ||
| 
						 | 
					860db2f612 | ||
| 
						 | 
					523f205646 | ||
| 
						 | 
					e998c8a866 | ||
| 
						 | 
					eaea68c33e | ||
| 
						 | 
					4780cfeafc | ||
| 
						 | 
					bdb0951c84 | ||
| 
						 | 
					e3130c92c0 | ||
| 
						 | 
					12c880ab51 | ||
| 
						 | 
					522aabd4e4 | ||
| 
						 | 
					bf09b3b6c4 | ||
| 
						 | 
					2d3c5c9450 | ||
| 
						 | 
					ae87b2eb2d | ||
| 
						 | 
					c34ecc8dfd | ||
| 
						 | 
					2c2938c647 | ||
| 
						 | 
					22dd883f28 | ||
| 
						 | 
					dfbb1338a5 | ||
| 
						 | 
					f8dc82516e | ||
| 
						 | 
					59b16f7760 | ||
| 
						 | 
					a11289de79 | ||
| 
						 | 
					a64b8cae89 | ||
| 
						 | 
					470eaeb97b | ||
| 
						 | 
					6503349ed3 | ||
| 
						 | 
					ec23cedc3a | ||
| 
						 | 
					ce1ae1d7dc | ||
| 
						 | 
					6669d5632f | ||
| 
						 | 
					59e1114997 | ||
| 
						 | 
					c20510e5aa | ||
| 
						 | 
					2b2e746549 | ||
| 
						 | 
					dc5a8d44e5 | ||
| 
						 | 
					090d3339a0 | ||
| 
						 | 
					442d9e22b4 | ||
| 
						 | 
					0c39e7b158 | ||
| 
						 | 
					3e3f2614b5 | ||
| 
						 | 
					53e4b2c971 | ||
| 
						 | 
					d6c57c7aa3 | ||
| 
						 | 
					3efc984ae9 | ||
| 
						 | 
					7618a0871a | ||
| 
						 | 
					b87f73cc47 | ||
| 
						 | 
					785d39d78f | ||
| 
						 | 
					38a0f6fae4 | ||
| 
						 | 
					710be51cad | ||
| 
						 | 
					50438425e5 | ||
| 
						 | 
					4b4bfe8876 | ||
| 
						 | 
					67da4bdd5b | ||
| 
						 | 
					e230badb47 | ||
| 
						 | 
					d48d9ed4dc | ||
| 
						 | 
					b9fe6bfa10 | ||
| 
						 | 
					5cbbb62ce2 | ||
| 
						 | 
					3369c9d808 | ||
| 
						 | 
					dfc594f949 | ||
| 
						 | 
					d714cda145 | ||
| 
						 | 
					428e1e4100 | ||
| 
						 | 
					2b19f56e63 | ||
| 
						 | 
					4badc983ea | ||
| 
						 | 
					c8a4f88ff3 | ||
| 
						 | 
					eeeaf8d707 | ||
| 
						 | 
					37b3b5a5ed | ||
| 
						 | 
					a561ef8c49 | ||
| 
						 | 
					89f200e870 | ||
| 
						 | 
					2823115a6c | ||
| 
						 | 
					5599d73760 | ||
| 
						 | 
					bac66cb5ad | ||
| 
						 | 
					61c50972e3 | ||
| 
						 | 
					ff0fbbc379 | ||
| 
						 | 
					4a124dea43 | ||
| 
						 | 
					e722b665d1 | ||
| 
						 | 
					4365b8d5ad | ||
| 
						 | 
					e55e5f3f7e | ||
| 
						 | 
					d1036c8538 | ||
| 
						 | 
					9240f62829 | ||
| 
						 | 
					1b89bc9051 | ||
| 
						 | 
					7700ef83e0 | ||
| 
						 | 
					9922b3a4f3 | ||
| 
						 | 
					d561d2e1ac | ||
| 
						 | 
					7865cea284 | ||
| 
						 | 
					424189cad9 | ||
| 
						 | 
					82aa64e8f7 | ||
| 
						 | 
					a0418520a2 | ||
| 
						 | 
					f451d961bc | ||
| 
						 | 
					a4da9fd49e | ||
| 
						 | 
					0a0891fa98 | ||
| 
						 | 
					9464b369a4 | ||
| 
						 | 
					47692edee4 | ||
| 
						 | 
					73c94b25ba | ||
| 
						 | 
					ab2ea5936d | ||
| 
						 | 
					90985af007 | ||
| 
						 | 
					5aad8764b1 | ||
| 
						 | 
					5a175f374a | ||
| 
						 | 
					4acfe84171 | ||
| 
						 | 
					e995a1cb69 | ||
| 
						 | 
					867f041c23 | ||
| 
						 | 
					7e49ba92b2 | ||
| 
						 | 
					2fa53c0531 | ||
| 
						 | 
					673800c947 | ||
| 
						 | 
					835b821b75 | ||
| 
						 | 
					78587ad20b | ||
| 
						 | 
					09bbec79cf | ||
| 
						 | 
					751b5f9943 | ||
| 
						 | 
					4a337ae3cb | ||
| 
						 | 
					1baeb15073 | ||
| 
						 | 
					141b36af04 | ||
| 
						 | 
					4238c20e72 | ||
| 
						 | 
					4e177d60b0 | ||
| 
						 | 
					1bd880708b | ||
| 
						 | 
					76c21c8b34 | ||
| 
						 | 
					dd8c2caac7 | ||
| 
						 | 
					7a7e8a7f8d | ||
| 
						 | 
					43f45d67a4 | ||
| 
						 | 
					adb36a39bb | ||
| 
						 | 
					5a0d9f5e9f | ||
| 
						 | 
					a4e8cb3971 | ||
| 
						 | 
					e22b7a336c | ||
| 
						 | 
					317fa42b20 | ||
| 
						 | 
					884f8dda37 | ||
| 
						 | 
					f5090532fb | ||
| 
						 | 
					ae04dd8fa5 | ||
| 
						 | 
					00e4075937 | ||
| 
						 | 
					d65f3ea58d | ||
| 
						 | 
					008163bf6c | ||
| 
						 | 
					f09002a49a | ||
| 
						 | 
					431290d47a | ||
| 
						 | 
					b66874b7b3 | ||
| 
						 | 
					1b9fd7f936 | ||
| 
						 | 
					0a1457acde | ||
| 
						 | 
					d2008aa92f | ||
| 
						 | 
					e83356faef | ||
| 
						 | 
					fd4161832b | ||
| 
						 | 
					0a132b0eb5 | ||
| 
						 | 
					9c7ac9043a | ||
| 
						 | 
					b86c0d357f | ||
| 
						 | 
					75dd26518f | ||
| 
						 | 
					2cc261c619 | ||
| 
						 | 
					f7d46f1100 | ||
| 
						 | 
					be264528d2 | ||
| 
						 | 
					c825adc1e3 | ||
| 
						 | 
					4e9f125e95 | ||
| 
						 | 
					d26c8fe447 | ||
| 
						 | 
					e42d635195 | ||
| 
						 | 
					a32cd1c19b | ||
| 
						 | 
					14dc02ac83 | ||
| 
						 | 
					e4a28d1839 | ||
| 
						 | 
					0908920b51 | ||
| 
						 | 
					8a882916fb | ||
| 
						 | 
					55ada8ad2f | ||
| 
						 | 
					2094186c0f | ||
| 
						 | 
					d3a489b756 | ||
| 
						 | 
					e6b18231c0 | ||
| 
						 | 
					cc0145d561 | ||
| 
						 | 
					9f0daca5eb | ||
| 
						 | 
					1f2bd44dce | ||
| 
						 | 
					6492bd12f9 | ||
| 
						 | 
					43552161f9 | ||
| 
						 | 
					e5d45fdf1d | ||
| 
						 | 
					bd69c8da18 | ||
| 
						 | 
					8c3e3ebe24 | ||
| 
						 | 
					7eebbd982d | ||
| 
						 | 
					5c66f5c161 | ||
| 
						 | 
					40f70fc1e3 | ||
| 
						 | 
					9cf4427375 | ||
| 
						 | 
					23cf9686cb | ||
| 
						 | 
					70add920fe | ||
| 
						 | 
					c56c6cc219 | ||
| 
						 | 
					e9a0296851 | ||
| 
						 | 
					de30433e26 | ||
| 
						 | 
					fa64fa8b93 | ||
| 
						 | 
					50c7942cb5 | ||
| 
						 | 
					e7697b8fba | ||
| 
						 | 
					b46a77f977 | ||
| 
						 | 
					38909afa89 | ||
| 
						 | 
					5af561c811 | ||
| 
						 | 
					ae984d4f04 | ||
| 
						 | 
					97a8ecd115 | ||
| 
						 | 
					64d782569a | ||
| 
						 | 
					6248baf98b | ||
| 
						 | 
					33cfca7ecc | ||
| 
						 | 
					a01cc35368 | ||
| 
						 | 
					b10eebd77e | ||
| 
						 | 
					05661ca9b6 | ||
| 
						 | 
					784883f773 | ||
| 
						 | 
					a9e5723ca4 | ||
| 
						 | 
					95dfea8d29 | ||
| 
						 | 
					e574af7d68 | ||
| 
						 | 
					2918ca45a2 | ||
| 
						 | 
					6ad744f770 | ||
| 
						 | 
					5b394e6f35 | ||
| 
						 | 
					940af2c711 | ||
| 
						 | 
					544c402f78 | ||
| 
						 | 
					cee9e624b8 | ||
| 
						 | 
					2e65ee3609 | ||
| 
						 | 
					3a176e1cab | ||
| 
						 | 
					00cccad22c | ||
| 
						 | 
					a432d733d7 | ||
| 
						 | 
					893e88294b | ||
| 
						 | 
					b071a9e992 | ||
| 
						 | 
					48cf4ebf02 | ||
| 
						 | 
					773a75b948 | ||
| 
						 | 
					133c0e8d63 | ||
| 
						 | 
					bf54cb36ef | ||
| 
						 | 
					032853b5c9 | ||
| 
						 | 
					650c13ca7a | ||
| 
						 | 
					9d5fe03285 | ||
| 
						 | 
					c3f68b60d3 | ||
| 
						 | 
					1c16467eb9 | ||
| 
						 | 
					3c74385f5c | ||
| 
						 | 
					c07c0028bb | ||
| 
						 | 
					dc3b2e04ab | ||
| 
						 | 
					7fd3aa9164 | ||
| 
						 | 
					4c60312e2d | ||
| 
						 | 
					16e29aa4e0 | ||
| 
						 | 
					bd7b073155 | ||
| 
						 | 
					f25cf870e6 | ||
| 
						 | 
					13291d0365 | ||
| 
						 | 
					9ee7a48910 | ||
| 
						 | 
					daf4614ba6 | ||
| 
						 | 
					919d36369c | ||
| 
						 | 
					618704df76 | ||
| 
						 | 
					9a70dd9651 | ||
| 
						 | 
					e2d310b10f | ||
| 
						 | 
					a1015a366a | ||
| 
						 | 
					913ec7b3fe | ||
| 
						 | 
					4a52b06954 | ||
| 
						 | 
					89f9c07b9e | ||
| 
						 | 
					388d78d11e | ||
| 
						 | 
					a2a23b3932 | ||
| 
						 | 
					f405ae8b42 | ||
| 
						 | 
					cf3f6750eb | ||
| 
						 | 
					4de22d067a | ||
| 
						 | 
					51e274ea38 | ||
| 
						 | 
					0a6ce62363 | ||
| 
						 | 
					13c5de5531 | ||
| 
						 | 
					21f8e7f398 | ||
| 
						 | 
					bcf4a5af90 | ||
| 
						 | 
					09f90d095b | ||
| 
						 | 
					416ebc9ab8 | ||
| 
						 | 
					3ca22aa714 | ||
| 
						 | 
					8dd25e1f0b | ||
| 
						 | 
					5b9bd603ea | ||
| 
						 | 
					3c2c1f15ce | ||
| 
						 | 
					6876df4a45 | ||
| 
						 | 
					1ff97161fb | ||
| 
						 | 
					667410e879 | ||
| 
						 | 
					a862874740 | ||
| 
						 | 
					79bde4e5bf | ||
| 
						 | 
					833b724e9f | ||
| 
						 | 
					96b68058bb | ||
| 
						 | 
					e823233149 | ||
| 
						 | 
					3ac22fafe4 | ||
| 
						 | 
					71f2ac170c | ||
| 
						 | 
					0ef888eea3 | ||
| 
						 | 
					a9b0028a15 | ||
| 
						 | 
					b18e6cff5a | ||
| 
						 | 
					424a1c94d9 | ||
| 
						 | 
					009095af24 | ||
| 
						 | 
					2ce42ab057 | ||
| 
						 | 
					934459dea8 | ||
| 
						 | 
					52bc874675 | ||
| 
						 | 
					511907fbc5 | ||
| 
						 | 
					155e194174 | ||
| 
						 | 
					b1c7e21ca9 | ||
| 
						 | 
					7edcf6cb45 | ||
| 
						 | 
					9581940cfa | ||
| 
						 | 
					f2aa57c4fa | ||
| 
						 | 
					8bf4405fd0 | ||
| 
						 | 
					21ef1788ca | ||
| 
						 | 
					68f1dffba7 | ||
| 
						 | 
					092df2c0e4 | ||
| 
						 | 
					691f94c75c | ||
| 
						 | 
					d6d4476e85 | ||
| 
						 | 
					924e8e0860 | ||
| 
						 | 
					53193e933f | ||
| 
						 | 
					328587ad9c | ||
| 
						 | 
					1a8fdb1b99 | ||
| 
						 | 
					690f0221b5 | ||
| 
						 | 
					e117bd3985 | ||
| 
						 | 
					15cc87bffd | ||
| 
						 | 
					97d4c97c52 | ||
| 
						 | 
					c8b22d7e8a | ||
| 
						 | 
					f48ec4f49b | ||
| 
						 | 
					d4ce697bd9 | ||
| 
						 | 
					bd20513493 | ||
| 
						 | 
					fd3f4eb724 | ||
| 
						 | 
					75e8486061 | ||
| 
						 | 
					bd216709fc | ||
| 
						 | 
					a3a8f7608a | ||
| 
						 | 
					affc88d0a8 | ||
| 
						 | 
					eca4882ce2 | ||
| 
						 | 
					58b0a04019 | ||
| 
						 | 
					b870679f2c | ||
| 
						 | 
					ae83725cb6 | ||
| 
						 | 
					595e42b587 | ||
| 
						 | 
					f5401df2c7 | ||
| 
						 | 
					3e79a5ca8b | ||
| 
						 | 
					327081945e | ||
| 
						 | 
					68ec484a58 | ||
| 
						 | 
					1d6ccf56a8 | ||
| 
						 | 
					67f637a1e1 | ||
| 
						 | 
					5e175d5319 | ||
| 
						 | 
					778db0fece | ||
| 
						 | 
					72010dd2e1 | ||
| 
						 | 
					39556b36f3 | ||
| 
						 | 
					dc9ffa6e56 | ||
| 
						 | 
					1e92bb3c2b | ||
| 
						 | 
					edbdf2966a | ||
| 
						 | 
					3f6fd734d3 | ||
| 
						 | 
					919a06d282 | ||
| 
						 | 
					35cc815cdb | ||
| 
						 | 
					a318bdb034 | ||
| 
						 | 
					d6aaa95b25 | ||
| 
						 | 
					5718ad52db | ||
| 
						 | 
					0f4cffbacc | ||
| 
						 | 
					d9a861331f | ||
| 
						 | 
					2f12a8d429 | ||
| 
						 | 
					e75cf4f3ad | ||
| 
						 | 
					bb85f31bb2 | ||
| 
						 | 
					396d08f0d2 | ||
| 
						 | 
					6ab184e7ce | ||
| 
						 | 
					fd65fbfd0c | ||
| 
						 | 
					637ea0ed55 | ||
| 
						 | 
					dc2d20f4c4 | ||
| 
						 | 
					d712ccc17e | ||
| 
						 | 
					147030e06f | ||
| 
						 | 
					09fd5cb69f | ||
| 
						 | 
					64db9f73a2 | ||
| 
						 | 
					28633be2dd | ||
| 
						 | 
					6fdafceda8 | ||
| 
						 | 
					38ed0c86ad | ||
| 
						 | 
					ad23816096 | ||
| 
						 | 
					bc4a730e76 | ||
| 
						 | 
					79372cc80d | ||
| 
						 | 
					c9e4246ac5 | ||
| 
						 | 
					dcd6a238b6 | ||
| 
						 | 
					c49de7733c | ||
| 
						 | 
					3fc7c90630 | ||
| 
						 | 
					53663a7832 | ||
| 
						 | 
					c14f2a3fcd | ||
| 
						 | 
					3cbe61e111 | ||
| 
						 | 
					fa023c6a99 | ||
| 
						 | 
					f98e6bdcb4 | ||
| 
						 | 
					0884954c84 | ||
| 
						 | 
					43727c6730 | ||
| 
						 | 
					618b731d5a | ||
| 
						 | 
					46975bf38b | ||
| 
						 | 
					8f3989000d | ||
| 
						 | 
					9fe75fbc47 | ||
| 
						 | 
					c455e79604 | ||
| 
						 | 
					a223545853 | ||
| 
						 | 
					b243f7aa62 | ||
| 
						 | 
					899452d7cd | ||
| 
						 | 
					af68fa7ee0 | ||
| 
						 | 
					5da789cc37 | ||
| 
						 | 
					7e5b41c8e0 | ||
| 
						 | 
					0254596c73 | ||
| 
						 | 
					67c02404b7 | ||
| 
						 | 
					0b5ee7e2c7 | ||
| 
						 | 
					fba0732faa | ||
| 
						 | 
					d06086a656 | ||
| 
						 | 
					e74b678739 | ||
| 
						 | 
					b62787ce47 | ||
| 
						 | 
					75708f7600 | ||
| 
						 | 
					476dec46b6 | ||
| 
						 | 
					973f6206ee | ||
| 
						 | 
					cbe47b3660 | ||
| 
						 | 
					1c58c339bb | ||
| 
						 | 
					15e91cfa99 | ||
| 
						 | 
					f4fb6ea4fc | ||
| 
						 | 
					0d2ff2c0a8 | ||
| 
						 | 
					5275da5a6b | ||
| 
						 | 
					e891b1281b | ||
| 
						 | 
					ca7110b37c | ||
| 
						 | 
					8960eb98f4 | ||
| 
						 | 
					18610668b8 | ||
| 
						 | 
					efe61e32e2 | ||
| 
						 | 
					7a7e4f573a | ||
| 
						 | 
					a7e6ab7758 | ||
| 
						 | 
					a0cde4ae8c | ||
| 
						 | 
					7566aa9d26 | ||
| 
						 | 
					d2332a5b77 | ||
| 
						 | 
					94a8ce5aa8 | ||
| 
						 | 
					b18a67d656 | ||
| 
						 | 
					02708534c0 | ||
| 
						 | 
					d5710d80e0 | ||
| 
						 | 
					8dcba3219d | ||
| 
						 | 
					9f01a45b1f | ||
| 
						 | 
					dd2cb93ecc | ||
| 
						 | 
					49538a986c | ||
| 
						 | 
					26c2331d0f | ||
| 
						 | 
					a0758643c2 | ||
| 
						 | 
					77e152ad36 | ||
| 
						 | 
					4834642b80 | ||
| 
						 | 
					18a6f621f0 | ||
| 
						 | 
					3cae1d92cd | ||
| 
						 | 
					02b192d6ee | ||
| 
						 | 
					f630a3e604 | ||
| 
						 | 
					fb5a9bc043 | ||
| 
						 | 
					26ad5a00a3 | ||
| 
						 | 
					18e1f08e31 | ||
| 
						 | 
					b68deef6db | ||
| 
						 | 
					30ec7debba | ||
| 
						 | 
					3a1e23a3ff | ||
| 
						 | 
					0887bb7662 | ||
| 
						 | 
					5a55f738a9 | ||
| 
						 | 
					8d8df585ad | ||
| 
						 | 
					8660047ec1 | ||
| 
						 | 
					9476db02a9 | ||
| 
						 | 
					04fbf5f724 | ||
| 
						 | 
					3cc629cbc1 | ||
| 
						 | 
					50fca4cddf | ||
| 
						 | 
					a047cead05 | ||
| 
						 | 
					1131b73299 | ||
| 
						 | 
					196af10d01 | ||
| 
						 | 
					1e0e93e5c6 | ||
| 
						 | 
					ac01d6d316 | ||
| 
						 | 
					654e404e0e | ||
| 
						 | 
					f0f1138c54 | ||
| 
						 | 
					bc94e08970 | ||
| 
						 | 
					42c3ede963 | ||
| 
						 | 
					174568d769 | ||
| 
						 | 
					4587d8ebbd | ||
| 
						 | 
					98aae242fb | ||
| 
						 | 
					7abd8d5ee5 | ||
| 
						 | 
					98ac4d7983 | ||
| 
						 | 
					933d46553f | ||
| 
						 | 
					7e667a8028 | ||
| 
						 | 
					d4e41d6053 | ||
| 
						 | 
					f30dccf726 | ||
| 
						 | 
					ea3fcd5b79 | ||
| 
						 | 
					e61d070def | ||
| 
						 | 
					b5f34f42a8 | ||
| 
						 | 
					4426eaddd9 | ||
| 
						 | 
					83f0720a39 | ||
| 
						 | 
					ce4f293574 | ||
| 
						 | 
					b23ae5a4c3 | ||
| 
						 | 
					190e1e73e8 | ||
| 
						 | 
					ee67cf0bf1 | ||
| 
						 | 
					aaeb47dc14 | ||
| 
						 | 
					e19b0ed710 | ||
| 
						 | 
					a774121c13 | ||
| 
						 | 
					df676423a7 | ||
| 
						 | 
					cf8dda6b0d | ||
| 
						 | 
					1ce731471d | ||
| 
						 | 
					f98c77432b | ||
| 
						 | 
					9fa5a3fdb6 | ||
| 
						 | 
					5b9fd70f30 | ||
| 
						 | 
					442f68cd31 | ||
| 
						 | 
					e74212cb9e | ||
| 
						 | 
					57b52f35b4 | ||
| 
						 | 
					27a31a8399 | ||
| 
						 | 
					f1a3ed379e | ||
| 
						 | 
					60f9be7234 | ||
| 
						 | 
					dcfb90bc63 | ||
| 
						 | 
					74b84c4252 | ||
| 
						 | 
					00e6546f0c | ||
| 
						 | 
					a009fbf20c | ||
| 
						 | 
					2ed9448b41 | ||
| 
						 | 
					1575a40d61 | ||
| 
						 | 
					a784fdf9d5 | ||
| 
						 | 
					612c0e1131 | ||
| 
						 | 
					16a82e1897 | ||
| 
						 | 
					ad14baf601 | ||
| 
						 | 
					8b6a5813e6 | ||
| 
						 | 
					f4c76e12f4 | ||
| 
						 | 
					3fa8c4be0b | ||
| 
						 | 
					2f904371ae | ||
| 
						 | 
					455eba3bfd | ||
| 
						 | 
					48f6a0cd5e | ||
| 
						 | 
					50a15d2289 | ||
| 
						 | 
					de1e61bd5a | ||
| 
						 | 
					7fba5a59bf | ||
| 
						 | 
					3a86ee923e | ||
| 
						 | 
					65e726a51a | ||
| 
						 | 
					91c4414889 | ||
| 
						 | 
					6754741f37 | ||
| 
						 | 
					10d0e99d72 | ||
| 
						 | 
					9696acc8bd | ||
| 
						 | 
					0f37e50419 | ||
| 
						 | 
					95d09e4b75 | ||
| 
						 | 
					7c71c35797 | ||
| 
						 | 
					893cfaa543 | ||
| 
						 | 
					3e22c9b829 | ||
| 
						 | 
					a968ca2a2e | ||
| 
						 | 
					c271622670 | ||
| 
						 | 
					a126f9c1a6 | ||
| 
						 | 
					44d524134f | ||
| 
						 | 
					7ae807002e | ||
| 
						 | 
					a194f7ad87 | ||
| 
						 | 
					61d3f7e63e | ||
| 
						 | 
					8715e9c41e | ||
| 
						 | 
					5da69e7f56 | ||
| 
						 | 
					ebc5cd9285 | ||
| 
						 | 
					97536d2a72 | ||
| 
						 | 
					a2e6a25fc8 | ||
| 
						 | 
					f8998b5891 | ||
| 
						 | 
					8d4f7fc32b | ||
| 
						 | 
					828b7fb505 | ||
| 
						 | 
					74525bcd14 | ||
| 
						 | 
					33e98fd720 | ||
| 
						 | 
					134e5873a9 | ||
| 
						 | 
					89a95eca16 | ||
| 
						 | 
					d881312e3e | ||
| 
						 | 
					da65ba4e8d | ||
| 
						 | 
					e8a39e1722 | ||
| 
						 | 
					581261afca | ||
| 
						 | 
					8d68b5cc01 | ||
| 
						 | 
					353be3a7a2 | ||
| 
						 | 
					b9af1b3293 | ||
| 
						 | 
					09badaa9ee | ||
| 
						 | 
					587f6518f7 | ||
| 
						 | 
					6c38e72654 | ||
| 
						 | 
					599c2119d5 | ||
| 
						 | 
					dfd89f2b5c | ||
| 
						 | 
					7db3dcbdf6 | ||
| 
						 | 
					5b268a1a6a | ||
| 
						 | 
					43c1140aa2 | ||
| 
						 | 
					0bc9725b98 | ||
| 
						 | 
					ef097757f3 | ||
| 
						 | 
					6490fa598c | ||
| 
						 | 
					c41464c990 | ||
| 
						 | 
					94d7e3199e | ||
| 
						 | 
					140dd5e5d3 | ||
| 
						 | 
					251a81ef43 | ||
| 
						 | 
					76f81c4d33 | ||
| 
						 | 
					b14a1bb7b9 | ||
| 
						 | 
					5f6f021039 | ||
| 
						 | 
					9b69cecfb1 | ||
| 
						 | 
					f75248d177 | ||
| 
						 | 
					97f8d6c074 | ||
| 
						 | 
					c29d5d1ca2 | ||
| 
						 | 
					48c272acf8 | ||
| 
						 | 
					f66b9137e8 | ||
| 
						 | 
					c3dfaa5935 | ||
| 
						 | 
					9a9ae03e41 | ||
| 
						 | 
					2bbc47d3f7 | ||
| 
						 | 
					f12b0ee472 | ||
| 
						 | 
					46e4ddfaf1 | ||
| 
						 | 
					449b6fa5ff | ||
| 
						 | 
					3913adedb0 | ||
| 
						 | 
					4cf545d334 | ||
| 
						 | 
					9225af06b1 | ||
| 
						 | 
					562483823c | ||
| 
						 | 
					57742bcd87 | ||
| 
						 | 
					5066ea637b | ||
| 
						 | 
					7b8cf65218 | ||
| 
						 | 
					7ac7713268 | ||
| 
						 | 
					490c80dae9 | ||
| 
						 | 
					f324d2d34b | ||
| 
						 | 
					f3ee120c48 | ||
| 
						 | 
					63ea6154f4 | ||
| 
						 | 
					eafa660dee | ||
| 
						 | 
					2a6a5b13d7 | ||
| 
						 | 
					47b9648f85 | ||
| 
						 | 
					55c05a4092 | ||
| 
						 | 
					476b056ed0 | ||
| 
						 | 
					c53600b550 | ||
| 
						 | 
					f47991e18e | ||
| 
						 | 
					773a3f4abf | ||
| 
						 | 
					809f472cb4 | ||
| 
						 | 
					e8ee3d694a | ||
| 
						 | 
					fec501801e | ||
| 
						 | 
					c52fe21237 | ||
| 
						 | 
					f00c218e56 | ||
| 
						 | 
					1daa4c5ca6 | ||
| 
						 | 
					717f8986cd | ||
| 
						 | 
					65aba6e77d | ||
| 
						 | 
					9f8a6a8b6b | ||
| 
						 | 
					b0bfb13241 | ||
| 
						 | 
					34102f72a2 | ||
| 
						 | 
					cb93c6ec65 | ||
| 
						 | 
					78af10fa1f | ||
| 
						 | 
					52b7719180 | ||
| 
						 | 
					48361a003e | ||
| 
						 | 
					34bd4a1c7c | ||
| 
						 | 
					94b271da5d | ||
| 
						 | 
					e47f2c05f3 | ||
| 
						 | 
					6b9ef7e6c9 | ||
| 
						 | 
					62239a1fda | ||
| 
						 | 
					bba81ac884 | ||
| 
						 | 
					9f4248b1e1 | ||
| 
						 | 
					e06f0ffb7e | ||
| 
						 | 
					29b283c176 | ||
| 
						 | 
					3e797db16e | ||
| 
						 | 
					034a8f5d8b | ||
| 
						 | 
					eb7d910683 | ||
| 
						 | 
					85af9f55ba | ||
| 
						 | 
					ca98b49813 | ||
| 
						 | 
					0cff881d69 | ||
| 
						 | 
					7eb82a0fe5 | ||
| 
						 | 
					58a131426a | ||
| 
						 | 
					72e9e7d9c4 | ||
| 
						 | 
					fc148be3e2 | ||
| 
						 | 
					bc51714148 | ||
| 
						 | 
					b24325d879 | ||
| 
						 | 
					b480e22a27 | ||
| 
						 | 
					afa4bc86e8 | ||
| 
						 | 
					6cd2411ec0 | ||
| 
						 | 
					6f9ab56493 | ||
| 
						 | 
					485191d185 | ||
| 
						 | 
					1456cef991 | ||
| 
						 | 
					53cb4b0248 | ||
| 
						 | 
					2c4f0d593d | ||
| 
						 | 
					499c66f411 | ||
| 
						 | 
					1b5da956e5 | ||
| 
						 | 
					c76b541cb8 | ||
| 
						 | 
					ce2d371c4b | ||
| 
						 | 
					eefd981572 | ||
| 
						 | 
					9240295724 | ||
| 
						 | 
					a516724760 | ||
| 
						 | 
					a0ef4d752f | ||
| 
						 | 
					65ad64bf42 | ||
| 
						 | 
					b36680d767 | ||
| 
						 | 
					24a85df15f | ||
| 
						 | 
					f10ce94f38 | ||
| 
						 | 
					612c6c95eb | ||
| 
						 | 
					31a2e648c5 | ||
| 
						 | 
					31acdcada3 | ||
| 
						 | 
					12e33a1760 | ||
| 
						 | 
					328e7f8d57 | ||
| 
						 | 
					33000598fc | ||
| 
						 | 
					6a2ef5cc6c | ||
| 
						 | 
					2a63e62aba | ||
| 
						 | 
					935d8f8770 | ||
| 
						 | 
					8c5ac1f77d | ||
| 
						 | 
					bfa266c604 | ||
| 
						 | 
					901ffbc7c0 | ||
| 
						 | 
					97dedd32fb | ||
| 
						 | 
					789c491c1e | ||
| 
						 | 
					4b8dd3ad72 | ||
| 
						 | 
					c2dce960b8 | ||
| 
						 | 
					f9e15cd60b | ||
| 
						 | 
					4d249c5fe3 | ||
| 
						 | 
					7206a9ea73 | ||
| 
						 | 
					848b4e9a4c | ||
| 
						 | 
					d65d0a08aa | ||
| 
						 | 
					7ccf4b6432 | ||
| 
						 | 
					d18ba78d03 | ||
| 
						 | 
					ab1c97fb2b | ||
| 
						 | 
					b0a66706bd | ||
| 
						 | 
					f0962bd060 | ||
| 
						 | 
					083ca2f3b7 | ||
| 
						 | 
					8481b50f97 | ||
| 
						 | 
					a04f7ee661 | ||
| 
						 | 
					10d47d1ac6 | ||
| 
						 | 
					445f5aa1fd | ||
| 
						 | 
					1b49a89c8e | ||
| 
						 | 
					9bf92d1e48 | ||
| 
						 | 
					da308b2253 | ||
| 
						 | 
					0c834b60f5 | ||
| 
						 | 
					2cf5430b85 | ||
| 
						 | 
					30d2a5514e | ||
| 
						 | 
					1d6a6efb81 | ||
| 
						 | 
					af09961875 | ||
| 
						 | 
					a46fe25283 | ||
| 
						 | 
					dfe3f1c4c2 | ||
| 
						 | 
					b969079af5 | ||
| 
						 | 
					2837c5697f | ||
| 
						 | 
					820b619847 | ||
| 
						 | 
					6b72ef0720 | ||
| 
						 | 
					81125be971 | ||
| 
						 | 
					decc585065 | ||
| 
						 | 
					17ad66346e | ||
| 
						 | 
					e0330c984f | ||
| 
						 | 
					3a9056745f | ||
| 
						 | 
					9b997fbf01 | ||
| 
						 | 
					4cac797b40 | ||
| 
						 | 
					7f5dc0a756 | ||
| 
						 | 
					93d77fdeca | ||
| 
						 | 
					5b3acf3f6b | ||
| 
						 | 
					a29136d6b7 | ||
| 
						 | 
					4a8db6f098 | ||
| 
						 | 
					766ae685c2 | ||
| 
						 | 
					e384f87a04 | ||
| 
						 | 
					688564cfc2 | ||
| 
						 | 
					4643996c3a | ||
| 
						 | 
					eef5b4941f | ||
| 
						 | 
					4b83df3652 | ||
| 
						 | 
					f54cd87abc | ||
| 
						 | 
					be8a0de38d | ||
| 
						 | 
					9fbf7bd1c1 | ||
| 
						 | 
					cd0bccfbeb | ||
| 
						 | 
					c1cb367acf | ||
| 
						 | 
					de3a28c6e6 | ||
| 
						 | 
					5976d33fef | ||
| 
						 | 
					e17b62c98b | ||
| 
						 | 
					92948abcf1 | ||
| 
						 | 
					852c3e89d6 | ||
| 
						 | 
					8ce1a3d3e9 | ||
| 
						 | 
					cb9622136c | ||
| 
						 | 
					46b57feb2f | ||
| 
						 | 
					a9bcab4aee | ||
| 
						 | 
					0fdb01ff97 | ||
| 
						 | 
					b9290c8a83 | ||
| 
						 | 
					246a514e88 | ||
| 
						 | 
					20f126e1d8 | ||
| 
						 | 
					82027a5b4f | ||
| 
						 | 
					3b2010200d | ||
| 
						 | 
					24cd6d772f | ||
| 
						 | 
					c46676daa5 | ||
| 
						 | 
					411ae8d0f5 | ||
| 
						 | 
					e419299487 | ||
| 
						 | 
					f3a8ba6ab3 | ||
| 
						 | 
					6d98f38128 | ||
| 
						 | 
					08f57de9e0 | ||
| 
						 | 
					3b7e161149 | ||
| 
						 | 
					15815bf4bb | ||
| 
						 | 
					43a5ee2d4f | ||
| 
						 | 
					bd817e77f0 | ||
| 
						 | 
					f8a4312fdd | ||
| 
						 | 
					cce7892d94 | ||
| 
						 | 
					1420618eb0 | ||
| 
						 | 
					52d6e8431f | ||
| 
						 | 
					1b89af9063 | ||
| 
						 | 
					d873181306 | ||
| 
						 | 
					26640cda14 | ||
| 
						 | 
					21c48bde5c | ||
| 
						 | 
					8c071fb208 | ||
| 
						 | 
					b36a8fd8fa | ||
| 
						 | 
					94e936575e | ||
| 
						 | 
					1b3c40b539 | ||
| 
						 | 
					bd5453002e | ||
| 
						 | 
					c218e104e7 | ||
| 
						 | 
					f6db888808 | ||
| 
						 | 
					3a804fefd1 | ||
| 
						 | 
					e0deda27da | ||
| 
						 | 
					bb97f3e543 | ||
| 
						 | 
					92c0f737ac | ||
| 
						 | 
					29b549e677 | ||
| 
						 | 
					3baa830afb | ||
| 
						 | 
					a5ce17f44e | ||
| 
						 | 
					2f981ecb12 | ||
| 
						 | 
					5e941427d3 | ||
| 
						 | 
					a40b6b1b1b | ||
| 
						 | 
					e5b6e0ad9f | ||
| 
						 | 
					5956c6acaf | ||
| 
						 | 
					58f33fa1d6 | ||
| 
						 | 
					7384440a3d | ||
| 
						 | 
					c1dfb741c9 | ||
| 
						 | 
					25b5545644 | ||
| 
						 | 
					d49e911fe4 | ||
| 
						 | 
					50a37495f8 | ||
| 
						 | 
					8bea44a44c | ||
| 
						 | 
					3ad82cf3b1 | ||
| 
						 | 
					99e36195f7 | ||
| 
						 | 
					d03a661635 | ||
| 
						 | 
					c5c12385ef | ||
| 
						 | 
					705a55d1b5 | ||
| 
						 | 
					77db725822 | ||
| 
						 | 
					e6c68143bd | ||
| 
						 | 
					b5cbd8e410 | ||
| 
						 | 
					8024757e57 | ||
| 
						 | 
					a5a7361370 | ||
| 
						 | 
					7f70345dae | ||
| 
						 | 
					33a4e806e2 | ||
| 
						 | 
					1a9cd4cd2c | ||
| 
						 | 
					c055af7348 | ||
| 
						 | 
					65eb185a9f | ||
| 
						 | 
					a68fc671e5 | ||
| 
						 | 
					79fbf0a31f | ||
| 
						 | 
					d29836845c | ||
| 
						 | 
					c2d417c78b | ||
| 
						 | 
					d8d198c81c | ||
| 
						 | 
					bc8b1f170e | ||
| 
						 | 
					514cf8e460 | ||
| 
						 | 
					ac82961bea | ||
| 
						 | 
					9d52b6ab5d | ||
| 
						 | 
					aeb70262e0 | ||
| 
						 | 
					f6a85518bc | ||
| 
						 | 
					27c5013697 | ||
| 
						 | 
					aa53076e11 | ||
| 
						 | 
					c37311ae36 | ||
| 
						 | 
					ce76896eb3 | ||
| 
						 | 
					5e377639c8 | ||
| 
						 | 
					93fb9611f7 | 
							
								
								
									
										1
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/.github/	@TokTok/admins
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					github: [JFreegman]
 | 
				
			||||||
							
								
								
									
										17
									
								
								.github/settings.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/settings.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					_extends: .github
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					repository:
 | 
				
			||||||
 | 
					  name: toxic
 | 
				
			||||||
 | 
					  description: An ncurses-based Tox client
 | 
				
			||||||
 | 
					  topics: tox, console, chat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					branches:
 | 
				
			||||||
 | 
					  - name: "master"
 | 
				
			||||||
 | 
					    protection:
 | 
				
			||||||
 | 
					      required_status_checks:
 | 
				
			||||||
 | 
					        contexts:
 | 
				
			||||||
 | 
					          - Codacy/PR Quality Review
 | 
				
			||||||
 | 
					          - CodeFactor
 | 
				
			||||||
 | 
					          - Travis CI - Pull Request
 | 
				
			||||||
 | 
					          - code-review/reviewable
 | 
				
			||||||
							
								
								
									
										14
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -9,19 +9,11 @@
 | 
				
			|||||||
*.app
 | 
					*.app
 | 
				
			||||||
*.swp
 | 
					*.swp
 | 
				
			||||||
*.la
 | 
					*.la
 | 
				
			||||||
m4/*
 | 
					 | 
				
			||||||
!m4/pkg.m4
 | 
					 | 
				
			||||||
configure
 | 
					 | 
				
			||||||
configure_aux
 | 
					 | 
				
			||||||
Makefile.in
 | 
					 | 
				
			||||||
aclocal.m4
 | 
					 | 
				
			||||||
config.h*
 | 
					 | 
				
			||||||
config.log
 | 
					 | 
				
			||||||
config.status
 | 
					 | 
				
			||||||
stamp-h1
 | 
					stamp-h1
 | 
				
			||||||
autom4te.cache
 | 
					 | 
				
			||||||
.deps
 | 
					.deps
 | 
				
			||||||
.libs
 | 
					.libs
 | 
				
			||||||
*.orig
 | 
					*.orig
 | 
				
			||||||
build/toxic
 | 
					build/toxic
 | 
				
			||||||
Makefile
 | 
					build/*.o
 | 
				
			||||||
 | 
					build/*.d
 | 
				
			||||||
 | 
					apidoc/python/build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.restyled.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.restyled.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					---
 | 
				
			||||||
 | 
					restylers:
 | 
				
			||||||
 | 
					  - astyle:
 | 
				
			||||||
 | 
					      arguments: ["--options=astylerc"]
 | 
				
			||||||
							
								
								
									
										120
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,64 +1,60 @@
 | 
				
			|||||||
language: c
 | 
					---
 | 
				
			||||||
compiler:
 | 
					language: python
 | 
				
			||||||
  - gcc
 | 
					python: nightly
 | 
				
			||||||
  - clang
 | 
					dist: xenial
 | 
				
			||||||
 | 
					os: linux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
before_script:
 | 
					jobs:
 | 
				
			||||||
  #installing libsodium, needed for Core
 | 
					  include:
 | 
				
			||||||
  - git clone git://github.com/jedisct1/libsodium.git > /dev/null
 | 
					    - env: JOB=linux
 | 
				
			||||||
  - cd libsodium
 | 
					 | 
				
			||||||
  - git checkout tags/0.4.2 > /dev/null
 | 
					 | 
				
			||||||
  - ./autogen.sh > /dev/null
 | 
					 | 
				
			||||||
  - ./configure > /dev/null
 | 
					 | 
				
			||||||
  - make check -j3 > /dev/null
 | 
					 | 
				
			||||||
  - sudo make install >/dev/null
 | 
					 | 
				
			||||||
  - cd ..
 | 
					 | 
				
			||||||
  #installing yasm, needed for compiling vpx
 | 
					 | 
				
			||||||
  - sudo apt-get install yasm > /dev/null
 | 
					 | 
				
			||||||
  #installing libconfig, needed for DHT_bootstrap_daemon
 | 
					 | 
				
			||||||
  - wget http://www.hyperrealm.com/libconfig/libconfig-1.4.9.tar.gz > /dev/null
 | 
					 | 
				
			||||||
  - tar -xvzf libconfig-1.4.9.tar.gz > /dev/null
 | 
					 | 
				
			||||||
  - cd libconfig-1.4.9
 | 
					 | 
				
			||||||
  - ./configure > /dev/null
 | 
					 | 
				
			||||||
  - make -j3 > /dev/null
 | 
					 | 
				
			||||||
  - sudo make install > /dev/null
 | 
					 | 
				
			||||||
  - cd ..
 | 
					 | 
				
			||||||
  #installing libopus, needed for audio encoding/decoding
 | 
					 | 
				
			||||||
  - wget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz > /dev/null
 | 
					 | 
				
			||||||
  - tar xzf opus-1.0.3.tar.gz > /dev/null
 | 
					 | 
				
			||||||
  - cd opus-1.0.3
 | 
					 | 
				
			||||||
  - ./configure > /dev/null
 | 
					 | 
				
			||||||
  - make -j3 > /dev/null
 | 
					 | 
				
			||||||
  - sudo make install > /dev/null
 | 
					 | 
				
			||||||
  - cd ..
 | 
					 | 
				
			||||||
  #installing vpx
 | 
					 | 
				
			||||||
  - git clone http://git.chromium.org/webm/libvpx.git > /dev/null
 | 
					 | 
				
			||||||
  - cd libvpx
 | 
					 | 
				
			||||||
  - ./configure --enable-shared > /dev/null
 | 
					 | 
				
			||||||
  - make -j3 >/dev/null
 | 
					 | 
				
			||||||
  - sudo make install > /dev/null
 | 
					 | 
				
			||||||
  - cd ..
 | 
					 | 
				
			||||||
  #creating libraries links and updating cache
 | 
					 | 
				
			||||||
  - sudo ldconfig > /dev/null
 | 
					 | 
				
			||||||
# creating librarys' links and updating cache
 | 
					 | 
				
			||||||
  - sudo ldconfig
 | 
					 | 
				
			||||||
  - git clone https://github.com/irungentoo/ProjectTox-Core.git toxcore
 | 
					 | 
				
			||||||
  - cd toxcore
 | 
					 | 
				
			||||||
  - autoreconf -i
 | 
					 | 
				
			||||||
  - ./configure --disable-tests --disable-ntox --disable-daemon --enable-av
 | 
					 | 
				
			||||||
  - make -j2
 | 
					 | 
				
			||||||
  - sudo make install
 | 
					 | 
				
			||||||
  - cd ..
 | 
					 | 
				
			||||||
  - sudo apt-get install libopenal-dev -yq
 | 
					 | 
				
			||||||
script:
 | 
					 | 
				
			||||||
  - autoreconf -i
 | 
					 | 
				
			||||||
  - ./configure
 | 
					 | 
				
			||||||
  - make -j2
 | 
					 | 
				
			||||||
notifications:
 | 
					 | 
				
			||||||
  email: false
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  irc: 
 | 
					      addons:
 | 
				
			||||||
    channels:
 | 
					        apt:
 | 
				
			||||||
      - "chat.freenode.net#tox-dev"
 | 
					          packages:
 | 
				
			||||||
    on_success: always
 | 
					            - libalut-dev
 | 
				
			||||||
    on_failure: always
 | 
					            - libconfig-dev
 | 
				
			||||||
 | 
					            - libnotify-dev
 | 
				
			||||||
 | 
					            - libopenal-dev
 | 
				
			||||||
 | 
					            - libopus-dev
 | 
				
			||||||
 | 
					            - libqrencode-dev
 | 
				
			||||||
 | 
					            - libvpx-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      cache:
 | 
				
			||||||
 | 
					        directories:
 | 
				
			||||||
 | 
					          - $HOME/cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      install:
 | 
				
			||||||
 | 
					        # Where to find libraries.
 | 
				
			||||||
 | 
					        - export LD_LIBRARY_PATH=$HOME/cache/usr/lib
 | 
				
			||||||
 | 
					        - export PKG_CONFIG_PATH=$HOME/cache/usr/lib/pkgconfig
 | 
				
			||||||
 | 
					        # c-sodium
 | 
				
			||||||
 | 
					        - git clone --depth=1 --branch=stable https://github.com/jedisct1/libsodium ../libsodium
 | 
				
			||||||
 | 
					        - test -f $HOME/cache/usr/lib/libsodium.so || (cd ../libsodium && ./configure --prefix=$HOME/cache/usr && make install -j$(nproc))
 | 
				
			||||||
 | 
					        # c-toxcore
 | 
				
			||||||
 | 
					        - git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
 | 
				
			||||||
 | 
					        - test -f $HOME/cache/usr/lib/libtoxcore.so || (cd ../c-toxcore && cmake -B_build -H. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/cache/usr && make -C_build install -j$(nproc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      script:
 | 
				
			||||||
 | 
					        - make ENABLE_PYTHON=1 -j$(nproc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - env: JOB=macos
 | 
				
			||||||
 | 
					      os: macos
 | 
				
			||||||
 | 
					      language: c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      cache:
 | 
				
			||||||
 | 
					        directories:
 | 
				
			||||||
 | 
					          - $HOME/cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      install:
 | 
				
			||||||
 | 
					        - brew install
 | 
				
			||||||
 | 
					          freealut
 | 
				
			||||||
 | 
					          libconfig
 | 
				
			||||||
 | 
					          libqrencode
 | 
				
			||||||
 | 
					          libsodium
 | 
				
			||||||
 | 
					          openal-soft
 | 
				
			||||||
 | 
					        - export LDFLAGS="-L/usr/local/Cellar/openal-soft/1.21.0/lib"
 | 
				
			||||||
 | 
					        - git clone --depth=1 https://github.com/TokTok/c-toxcore ../c-toxcore
 | 
				
			||||||
 | 
					        - test -f /usr/local/lib/libtoxcore.dylib || (cd ../c-toxcore && cmake -B_build -H. && make -C_build install -j$(nproc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      script:
 | 
				
			||||||
 | 
					        - make ENABLE_PYTHON=1 DISABLE_DESKTOP_NOTIFY=1 DISABLE_X11=1 DISABLE_AV=1 DISABLE_SOUND_NOTIFY=1 -j$(nproc)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										41
									
								
								BUILD.bazel
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								BUILD.bazel
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					load("@rules_cc//cc:defs.bzl", "cc_binary")
 | 
				
			||||||
 | 
					load("//tools/project:build_defs.bzl", "project")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					project()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cc_binary(
 | 
				
			||||||
 | 
					    name = "toxic",
 | 
				
			||||||
 | 
					    srcs = glob(
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					            "src/*.c",
 | 
				
			||||||
 | 
					            "src/*.h",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        exclude = ["src/video*"],
 | 
				
			||||||
 | 
					    ) + select({
 | 
				
			||||||
 | 
					        "//tools/config:linux": glob(["src/video*"]),
 | 
				
			||||||
 | 
					        "//tools/config:osx": [],
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    copts = [
 | 
				
			||||||
 | 
					        "-std=gnu99",
 | 
				
			||||||
 | 
					        "-DAUDIO",
 | 
				
			||||||
 | 
					        "-DPACKAGE_DATADIR='\"data\"'",
 | 
				
			||||||
 | 
					        "-DPYTHON",
 | 
				
			||||||
 | 
					        "-DQRCODE",
 | 
				
			||||||
 | 
					    ] + select({
 | 
				
			||||||
 | 
					        "//tools/config:linux": ["-DVIDEO"],
 | 
				
			||||||
 | 
					        "//tools/config:osx": [],
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					    deps = [
 | 
				
			||||||
 | 
					        "//c-toxcore",
 | 
				
			||||||
 | 
					        "@curl",
 | 
				
			||||||
 | 
					        "@libconfig",
 | 
				
			||||||
 | 
					        "@libqrencode",
 | 
				
			||||||
 | 
					        "@libvpx",
 | 
				
			||||||
 | 
					        "@ncurses",
 | 
				
			||||||
 | 
					        "@openal",
 | 
				
			||||||
 | 
					        "@python3//:python",
 | 
				
			||||||
 | 
					    ] + select({
 | 
				
			||||||
 | 
					        "//tools/config:linux": ["@x11"],
 | 
				
			||||||
 | 
					        "//tools/config:osx": [],
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										503
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,503 @@
 | 
				
			|||||||
 | 
					# Change Log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [Unreleased](https://github.com/JFreegman/toxic/tree/HEAD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.7.0...HEAD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- How can I copy everything from one computer to another? [\#391](https://github.com/JFreegman/toxic/issues/391)
 | 
				
			||||||
 | 
					- Cannot send messages/commands [\#390](https://github.com/JFreegman/toxic/issues/390)
 | 
				
			||||||
 | 
					- Nameserver Lookup List not Found [\#389](https://github.com/JFreegman/toxic/issues/389)
 | 
				
			||||||
 | 
					- ERROR: toxini file 'tox.ini' not found [\#388](https://github.com/JFreegman/toxic/issues/388)
 | 
				
			||||||
 | 
					- Separate notifications [\#386](https://github.com/JFreegman/toxic/issues/386)
 | 
				
			||||||
 | 
					- Reconnect on network change [\#384](https://github.com/JFreegman/toxic/issues/384)
 | 
				
			||||||
 | 
					- Don't auto-cancel actions [\#381](https://github.com/JFreegman/toxic/issues/381)
 | 
				
			||||||
 | 
					- How to export your profile? [\#377](https://github.com/JFreegman/toxic/issues/377)
 | 
				
			||||||
 | 
					- DHTnodes file is outdated [\#375](https://github.com/JFreegman/toxic/issues/375)
 | 
				
			||||||
 | 
					- Toxic fails to initialize if ~/.config directory doesn't exist [\#372](https://github.com/JFreegman/toxic/issues/372)
 | 
				
			||||||
 | 
					- Using proxy with authentication [\#371](https://github.com/JFreegman/toxic/issues/371)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add multiline support [\#387](https://github.com/JFreegman/toxic/pull/387) ([mphe](https://github.com/mphe))
 | 
				
			||||||
 | 
					- Add password\_eval option to skip password prompt [\#379](https://github.com/JFreegman/toxic/pull/379) ([FreakyPenguin](https://github.com/FreakyPenguin))
 | 
				
			||||||
 | 
					- sleep use tox\_iteration\_interval [\#374](https://github.com/JFreegman/toxic/pull/374) ([quininer](https://github.com/quininer))
 | 
				
			||||||
 | 
					- Fix \#372 - can't start with missing ~/.config [\#373](https://github.com/JFreegman/toxic/pull/373) ([wedge-jarrad](https://github.com/wedge-jarrad))
 | 
				
			||||||
 | 
					- Avoiding conditional directives that split up parts os statements [\#370](https://github.com/JFreegman/toxic/pull/370) ([RomeroMalaquias](https://github.com/RomeroMalaquias))
 | 
				
			||||||
 | 
					- update doc: DATA\_FILE is now `toxic\_profile.tox` [\#369](https://github.com/JFreegman/toxic/pull/369) ([nil0x42](https://github.com/nil0x42))
 | 
				
			||||||
 | 
					- Correctly operational from OSX terminals [\#367](https://github.com/JFreegman/toxic/pull/367) ([landswellsong](https://github.com/landswellsong))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.7.0](https://github.com/JFreegman/toxic/tree/v0.7.0) (2015-11-12)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.1...v0.7.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Implemented enhancements:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- /myid doesn't show qrcode [\#326](https://github.com/JFreegman/toxic/issues/326)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Installation failed on ubuntu 12.04, package missing [\#279](https://github.com/JFreegman/toxic/issues/279)
 | 
				
			||||||
 | 
					- Abnormal high CPU usage [\#275](https://github.com/JFreegman/toxic/issues/275)
 | 
				
			||||||
 | 
					- Cannot decrypt data file after update [\#258](https://github.com/JFreegman/toxic/issues/258)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Compiling video\_device.c on FreeBSD [\#364](https://github.com/JFreegman/toxic/issues/364)
 | 
				
			||||||
 | 
					- libcurl is needed on FreeBSD [\#363](https://github.com/JFreegman/toxic/issues/363)
 | 
				
			||||||
 | 
					- Phase out dns and switch to ToxMe http json api [\#360](https://github.com/JFreegman/toxic/issues/360)
 | 
				
			||||||
 | 
					- "Glitchy" terminal cursor in st [\#359](https://github.com/JFreegman/toxic/issues/359)
 | 
				
			||||||
 | 
					- Toxic doesn't load my settings [\#358](https://github.com/JFreegman/toxic/issues/358)
 | 
				
			||||||
 | 
					- Does Toxic support proxy? [\#355](https://github.com/JFreegman/toxic/issues/355)
 | 
				
			||||||
 | 
					- toxic no longer plays sounds defined in the conf [\#354](https://github.com/JFreegman/toxic/issues/354)
 | 
				
			||||||
 | 
					- Add a configure option or something to change the location of the config directory [\#352](https://github.com/JFreegman/toxic/issues/352)
 | 
				
			||||||
 | 
					- Remove/Replace links to libtoxcore.so [\#349](https://github.com/JFreegman/toxic/issues/349)
 | 
				
			||||||
 | 
					- "No pending friend requests." while"Friend request has already been sent." [\#348](https://github.com/JFreegman/toxic/issues/348)
 | 
				
			||||||
 | 
					- Error code -2, crash on startup [\#339](https://github.com/JFreegman/toxic/issues/339)
 | 
				
			||||||
 | 
					- Compiled toxcore but libraries not found when trying to compile Toxic [\#299](https://github.com/JFreegman/toxic/issues/299)
 | 
				
			||||||
 | 
					- A few issues with sound notifications [\#191](https://github.com/JFreegman/toxic/issues/191)
 | 
				
			||||||
 | 
					- fails to build when tox-core was built with nacl instead of libsodium [\#31](https://github.com/JFreegman/toxic/issues/31)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix spelling mistake BOARDER -\> BORDER [\#362](https://github.com/JFreegman/toxic/pull/362) ([subliun](https://github.com/subliun))
 | 
				
			||||||
 | 
					- Fix compile for DragonFlyBSD [\#351](https://github.com/JFreegman/toxic/pull/351) ([mneumann](https://github.com/mneumann))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.6.1](https://github.com/JFreegman/toxic/tree/v0.6.1) (2015-08-28)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.6.0...v0.6.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- \[Invalid UTF-8\] [\#344](https://github.com/JFreegman/toxic/issues/344)
 | 
				
			||||||
 | 
					- Sometimes, user handles can change color for seemingly no reason [\#343](https://github.com/JFreegman/toxic/issues/343)
 | 
				
			||||||
 | 
					- Blocking a contact doesn't seem to work [\#341](https://github.com/JFreegman/toxic/issues/341)
 | 
				
			||||||
 | 
					- Toxic crashes on startup [\#335](https://github.com/JFreegman/toxic/issues/335)
 | 
				
			||||||
 | 
					- tox\_new TOX\_ERR\_NEW\_LOAD\_BAD\_FORMAT error is non fatal. [\#333](https://github.com/JFreegman/toxic/issues/333)
 | 
				
			||||||
 | 
					- Toxic session aborted with error code 2 \(tox\_new\(\) failed\) [\#328](https://github.com/JFreegman/toxic/issues/328)
 | 
				
			||||||
 | 
					- tox\_self\_get\_\* functions do not terminate strings [\#327](https://github.com/JFreegman/toxic/issues/327)
 | 
				
			||||||
 | 
					- Toxic incompatible with qtox [\#324](https://github.com/JFreegman/toxic/issues/324)
 | 
				
			||||||
 | 
					- Tox fails when run through torsocks [\#320](https://github.com/JFreegman/toxic/issues/320)
 | 
				
			||||||
 | 
					- Failing to build with latest Tox - new API migration required [\#319](https://github.com/JFreegman/toxic/issues/319)
 | 
				
			||||||
 | 
					- Avoid non-posix option in sed. [\#307](https://github.com/JFreegman/toxic/issues/307)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- fix a broken link [\#350](https://github.com/JFreegman/toxic/pull/350) ([vinegret](https://github.com/vinegret))
 | 
				
			||||||
 | 
					- Makefile: allow overriding pkg-config [\#346](https://github.com/JFreegman/toxic/pull/346) ([ony](https://github.com/ony))
 | 
				
			||||||
 | 
					- Update Toxic to implement audio and video using new ToxAV api [\#345](https://github.com/JFreegman/toxic/pull/345) ([cnhenry](https://github.com/cnhenry))
 | 
				
			||||||
 | 
					- travis.yml: update dependencies [\#340](https://github.com/JFreegman/toxic/pull/340) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Add localization system \(gettext\) [\#337](https://github.com/JFreegman/toxic/pull/337) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: try to fix Tox/toxic\#307 [\#323](https://github.com/JFreegman/toxic/pull/323) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: add uninstall target [\#322](https://github.com/JFreegman/toxic/pull/322) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.6.0](https://github.com/JFreegman/toxic/tree/v0.6.0) (2015-03-28)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.2...v0.6.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Please do not force push to tox/toxic master branch. [\#311](https://github.com/JFreegman/toxic/issues/311)
 | 
				
			||||||
 | 
					- Import tox id [\#295](https://github.com/JFreegman/toxic/issues/295)
 | 
				
			||||||
 | 
					- openalut [\#287](https://github.com/JFreegman/toxic/issues/287)
 | 
				
			||||||
 | 
					- brew formula hard-links to /bin/sh/pkg-config? \(OS X\) [\#286](https://github.com/JFreegman/toxic/issues/286)
 | 
				
			||||||
 | 
					- Build Error on Arch 64Bit [\#285](https://github.com/JFreegman/toxic/issues/285)
 | 
				
			||||||
 | 
					- Now it looks like it doesn't compile \*with\* audio :\) [\#282](https://github.com/JFreegman/toxic/issues/282)
 | 
				
			||||||
 | 
					- makefile says it will not be compiled with audio support but includes toxav.h anyway. [\#281](https://github.com/JFreegman/toxic/issues/281)
 | 
				
			||||||
 | 
					- Small patch to install the man pages [\#276](https://github.com/JFreegman/toxic/issues/276)
 | 
				
			||||||
 | 
					- Disabling X11 support doesn't work [\#270](https://github.com/JFreegman/toxic/issues/270)
 | 
				
			||||||
 | 
					- Support arrow keys [\#265](https://github.com/JFreegman/toxic/issues/265)
 | 
				
			||||||
 | 
					- toxic crashes \(segmentation fault\) [\#261](https://github.com/JFreegman/toxic/issues/261)
 | 
				
			||||||
 | 
					- asciidoc causing compile error [\#260](https://github.com/JFreegman/toxic/issues/260)
 | 
				
			||||||
 | 
					- これはセグフォールトですか [\#259](https://github.com/JFreegman/toxic/issues/259)
 | 
				
			||||||
 | 
					- Verify ~/.config/tox permissions on startup [\#245](https://github.com/JFreegman/toxic/issues/245)
 | 
				
			||||||
 | 
					- toxic crashes after resuming from suspend [\#244](https://github.com/JFreegman/toxic/issues/244)
 | 
				
			||||||
 | 
					- Toxic does not compile on osx 10.9.3 [\#145](https://github.com/JFreegman/toxic/issues/145)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- README.md: fix typo [\#318](https://github.com/JFreegman/toxic/pull/318) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: be less aggressive when cleaning [\#316](https://github.com/JFreegman/toxic/pull/316) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Move makefile into root directory [\#315](https://github.com/JFreegman/toxic/pull/315) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fixing couple leaking file descriptors [\#314](https://github.com/JFreegman/toxic/pull/314) ([al42and](https://github.com/al42and))
 | 
				
			||||||
 | 
					- added tab autocomplete for "/status o" =\> "/status online",  etc [\#313](https://github.com/JFreegman/toxic/pull/313) ([hardlyeven](https://github.com/hardlyeven))
 | 
				
			||||||
 | 
					- Some cosmetics changes [\#310](https://github.com/JFreegman/toxic/pull/310) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Openbsd [\#308](https://github.com/JFreegman/toxic/pull/308) ([henriqueleng](https://github.com/henriqueleng))
 | 
				
			||||||
 | 
					- Add support for custom timestamps in chat and logs. [\#303](https://github.com/JFreegman/toxic/pull/303) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- README.md: update download section [\#302](https://github.com/JFreegman/toxic/pull/302) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Add INSTALL.md [\#301](https://github.com/JFreegman/toxic/pull/301) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- travis.yml: use latest libsodium stable [\#298](https://github.com/JFreegman/toxic/pull/298) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Travis should build with Libsodium stable, fix clang [\#297](https://github.com/JFreegman/toxic/pull/297) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Interface [\#296](https://github.com/JFreegman/toxic/pull/296) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- Correct filename comment from main.c to toxic.c [\#293](https://github.com/JFreegman/toxic/pull/293) ([Spagy](https://github.com/Spagy))
 | 
				
			||||||
 | 
					- Update for toxcore API break [\#292](https://github.com/JFreegman/toxic/pull/292) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fix some edge cases when obtaining paths [\#291](https://github.com/JFreegman/toxic/pull/291) ([dantok](https://github.com/dantok))
 | 
				
			||||||
 | 
					- Update DHT nodes again [\#290](https://github.com/JFreegman/toxic/pull/290) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Update DHT node list [\#289](https://github.com/JFreegman/toxic/pull/289) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Make "Last seen" handle year rollover correctly [\#288](https://github.com/JFreegman/toxic/pull/288) ([flussence](https://github.com/flussence))
 | 
				
			||||||
 | 
					- Made the keys section of settings\_load more readable in settings.c [\#284](https://github.com/JFreegman/toxic/pull/284) ([jpoler](https://github.com/jpoler))
 | 
				
			||||||
 | 
					- Destroy AL context before closing dhndl [\#283](https://github.com/JFreegman/toxic/pull/283) ([stal888](https://github.com/stal888))
 | 
				
			||||||
 | 
					- Darwin Build [\#280](https://github.com/JFreegman/toxic/pull/280) ([DomT4](https://github.com/DomT4))
 | 
				
			||||||
 | 
					- Fix Tox/toxic\#276 [\#278](https://github.com/JFreegman/toxic/pull/278) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: revert back to mkdir [\#274](https://github.com/JFreegman/toxic/pull/274) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: add toxic.desktop to install target [\#273](https://github.com/JFreegman/toxic/pull/273) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Toxic.conf.exmaple: fix sound namefile [\#271](https://github.com/JFreegman/toxic/pull/271) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Version: fix revision calculation [\#269](https://github.com/JFreegman/toxic/pull/269) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- fix doc building, dataencrypt api and minor ui tweak [\#267](https://github.com/JFreegman/toxic/pull/267) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- Change action messages indicator [\#264](https://github.com/JFreegman/toxic/pull/264) ([zetok](https://github.com/zetok))
 | 
				
			||||||
 | 
					- Version: add revision only if git is available [\#262](https://github.com/JFreegman/toxic/pull/262) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.5.2](https://github.com/JFreegman/toxic/tree/v0.5.2) (2014-09-29)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.1...v0.5.2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Failed to read log file [\#254](https://github.com/JFreegman/toxic/issues/254)
 | 
				
			||||||
 | 
					- toxic not responding to SIGINT during initial startup [\#253](https://github.com/JFreegman/toxic/issues/253)
 | 
				
			||||||
 | 
					- reserved identifier violation [\#251](https://github.com/JFreegman/toxic/issues/251)
 | 
				
			||||||
 | 
					- Fix signal handler [\#250](https://github.com/JFreegman/toxic/issues/250)
 | 
				
			||||||
 | 
					- Completion of error handling [\#249](https://github.com/JFreegman/toxic/issues/249)
 | 
				
			||||||
 | 
					- How to decline file sends? [\#247](https://github.com/JFreegman/toxic/issues/247)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix "error: unknown type name 'off\_t'" [\#255](https://github.com/JFreegman/toxic/pull/255) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- rm -rf -\> rm -f [\#252](https://github.com/JFreegman/toxic/pull/252) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Update screenshot [\#246](https://github.com/JFreegman/toxic/pull/246) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Makefile: use single quotes also for PACKAGE\_DATADIR [\#243](https://github.com/JFreegman/toxic/pull/243) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.5.1](https://github.com/JFreegman/toxic/tree/v0.5.1) (2014-09-19)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.5.0...v0.5.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Support for faux offline messaging [\#233](https://github.com/JFreegman/toxic/issues/233)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Usage help: add missing comma [\#242](https://github.com/JFreegman/toxic/pull/242) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fix some 'clang --analyze' warnings [\#240](https://github.com/JFreegman/toxic/pull/240) ([s3erios](https://github.com/s3erios))
 | 
				
			||||||
 | 
					- Addition to Tox/toxic\#235 [\#238](https://github.com/JFreegman/toxic/pull/238) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Some code simplification [\#236](https://github.com/JFreegman/toxic/pull/236) ([s3erios](https://github.com/s3erios))
 | 
				
			||||||
 | 
					- Add X11 option [\#235](https://github.com/JFreegman/toxic/pull/235) ([s3erios](https://github.com/s3erios))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.5.0](https://github.com/JFreegman/toxic/tree/v0.5.0) (2014-09-01)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.7...v0.5.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 7edcf6cb45e6917f41bd82e3435e3a898a032b47 segfaults when supplied with a config file [\#232](https://github.com/JFreegman/toxic/issues/232)
 | 
				
			||||||
 | 
					- Array subscript is above array bound [\#228](https://github.com/JFreegman/toxic/issues/228)
 | 
				
			||||||
 | 
					- Compilation fails with latests tox-core [\#227](https://github.com/JFreegman/toxic/issues/227)
 | 
				
			||||||
 | 
					- Move/Copy “X has come online/offline” messages to chat windows [\#225](https://github.com/JFreegman/toxic/issues/225)
 | 
				
			||||||
 | 
					- MANDIR set for Linux [\#222](https://github.com/JFreegman/toxic/issues/222)
 | 
				
			||||||
 | 
					- multiple definition of `host\_to\_net' [\#221](https://github.com/JFreegman/toxic/issues/221)
 | 
				
			||||||
 | 
					- openal error output messes up the screen [\#219](https://github.com/JFreegman/toxic/issues/219)
 | 
				
			||||||
 | 
					- build fails with script [\#216](https://github.com/JFreegman/toxic/issues/216)
 | 
				
			||||||
 | 
					- UTF-8 Support [\#171](https://github.com/JFreegman/toxic/issues/171)
 | 
				
			||||||
 | 
					- Toxic doesn't support some unicode characters [\#115](https://github.com/JFreegman/toxic/issues/115)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Cosmetic fixes [\#234](https://github.com/JFreegman/toxic/pull/234) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Reworked manpage build system [\#231](https://github.com/JFreegman/toxic/pull/231) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Manpage [\#230](https://github.com/JFreegman/toxic/pull/230) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- toxic.conf.example: better formatting [\#229](https://github.com/JFreegman/toxic/pull/229) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fix Tox/toxic\#222 and reorganize cfg dir [\#226](https://github.com/JFreegman/toxic/pull/226) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Add debug flag and update man page. [\#223](https://github.com/JFreegman/toxic/pull/223) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- new tox\_bootstrap\_from\_address\(\) behaviour and a minor ui change [\#220](https://github.com/JFreegman/toxic/pull/220) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					- toxic.conf.5: Remove default config from man page [\#218](https://github.com/JFreegman/toxic/pull/218) ([louipc](https://github.com/louipc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.4.7](https://github.com/JFreegman/toxic/tree/v0.4.7) (2014-08-05)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.6...v0.4.7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Segfault on openSUSE 13.1 [\#106](https://github.com/JFreegman/toxic/issues/106)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- cancel callback doesn't work [\#214](https://github.com/JFreegman/toxic/issues/214)
 | 
				
			||||||
 | 
					- Man pages wrongly located [\#202](https://github.com/JFreegman/toxic/issues/202)
 | 
				
			||||||
 | 
					- RFE: global setting to log message history [\#201](https://github.com/JFreegman/toxic/issues/201)
 | 
				
			||||||
 | 
					- Small typo in menu item [\#197](https://github.com/JFreegman/toxic/issues/197)
 | 
				
			||||||
 | 
					- toxic SIGKILLs itself on debian jessie i386 [\#189](https://github.com/JFreegman/toxic/issues/189)
 | 
				
			||||||
 | 
					- Toxic segfaults [\#144](https://github.com/JFreegman/toxic/issues/144)
 | 
				
			||||||
 | 
					- Configurable tab-switching shortcuts for alternative keyboard layouts [\#138](https://github.com/JFreegman/toxic/issues/138)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix ringing sounds [\#215](https://github.com/JFreegman/toxic/pull/215) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Add missing includes [\#213](https://github.com/JFreegman/toxic/pull/213) ([doughdemon](https://github.com/doughdemon))
 | 
				
			||||||
 | 
					- Fix bug [\#211](https://github.com/JFreegman/toxic/pull/211) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Fresh pack of backdoors [\#210](https://github.com/JFreegman/toxic/pull/210) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Makefile: refactoring and adding desktop notifications support [\#208](https://github.com/JFreegman/toxic/pull/208) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Update toxic.conf manpage [\#207](https://github.com/JFreegman/toxic/pull/207) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Configurable keybindings [\#206](https://github.com/JFreegman/toxic/pull/206) ([gracchus163](https://github.com/gracchus163))
 | 
				
			||||||
 | 
					- Lowered volume of sounds [\#205](https://github.com/JFreegman/toxic/pull/205) ([loadedice](https://github.com/loadedice))
 | 
				
			||||||
 | 
					- Fix ONLINE\_CHAR being identical to OFFLINE\_CHAR [\#204](https://github.com/JFreegman/toxic/pull/204) ([zetok](https://github.com/zetok))
 | 
				
			||||||
 | 
					- Put man pages in right place by default \(\#202\) [\#203](https://github.com/JFreegman/toxic/pull/203) ([zetok](https://github.com/zetok))
 | 
				
			||||||
 | 
					- Popup notifications & core adjustments [\#200](https://github.com/JFreegman/toxic/pull/200) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Fixed sounds not playing [\#199](https://github.com/JFreegman/toxic/pull/199) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- README.md: add precompiled binaries [\#198](https://github.com/JFreegman/toxic/pull/198) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.4.6](https://github.com/JFreegman/toxic/tree/v0.4.6) (2014-07-23)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/v0.4.5...v0.4.6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Implemented enhancements:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "Officially Deprecated" build for 32-bit? [\#192](https://github.com/JFreegman/toxic/issues/192)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Please create me a wiki account [\#196](https://github.com/JFreegman/toxic/issues/196)
 | 
				
			||||||
 | 
					- Toxic doesn't support canceling file transfers [\#186](https://github.com/JFreegman/toxic/issues/186)
 | 
				
			||||||
 | 
					- hashes of binaries? [\#185](https://github.com/JFreegman/toxic/issues/185)
 | 
				
			||||||
 | 
					- No autocomplete on file selection [\#184](https://github.com/JFreegman/toxic/issues/184)
 | 
				
			||||||
 | 
					- valgrind [\#178](https://github.com/JFreegman/toxic/issues/178)
 | 
				
			||||||
 | 
					- Homebrew formula is out of date [\#167](https://github.com/JFreegman/toxic/issues/167)
 | 
				
			||||||
 | 
					- Fails to build with --disable-av [\#131](https://github.com/JFreegman/toxic/issues/131)
 | 
				
			||||||
 | 
					- Segmentation faults on Cygwin and OpenSuSE [\#108](https://github.com/JFreegman/toxic/issues/108)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add hardcoded path for sound notifications [\#195](https://github.com/JFreegman/toxic/pull/195) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Makefile: little refactoring [\#193](https://github.com/JFreegman/toxic/pull/193) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fixed some build errors [\#190](https://github.com/JFreegman/toxic/pull/190) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Makefile fix [\#188](https://github.com/JFreegman/toxic/pull/188) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Added sound notifications, libconfig support, and more... [\#187](https://github.com/JFreegman/toxic/pull/187) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [v0.4.5](https://github.com/JFreegman/toxic/tree/v0.4.5) (2014-07-14)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.1...v0.4.5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- building on freebsd [\#177](https://github.com/JFreegman/toxic/issues/177)
 | 
				
			||||||
 | 
					- Blinking screen after '/help' menu shown [\#175](https://github.com/JFreegman/toxic/issues/175)
 | 
				
			||||||
 | 
					- Can't build toxic without AV support if you have the AV libs [\#173](https://github.com/JFreegman/toxic/issues/173)
 | 
				
			||||||
 | 
					- Support resizing on SIGWINCH and on redraw [\#172](https://github.com/JFreegman/toxic/issues/172)
 | 
				
			||||||
 | 
					- Broken backspace [\#163](https://github.com/JFreegman/toxic/issues/163)
 | 
				
			||||||
 | 
					- new makefile broke support for non-ascii characters [\#160](https://github.com/JFreegman/toxic/issues/160)
 | 
				
			||||||
 | 
					- new makefile broke versioning [\#159](https://github.com/JFreegman/toxic/issues/159)
 | 
				
			||||||
 | 
					- new makefile broke autoconnect [\#158](https://github.com/JFreegman/toxic/issues/158)
 | 
				
			||||||
 | 
					- Compilation error [\#143](https://github.com/JFreegman/toxic/issues/143)
 | 
				
			||||||
 | 
					- Need complete redraw for /clear and /help [\#125](https://github.com/JFreegman/toxic/issues/125)
 | 
				
			||||||
 | 
					- Warning about not sent message fails to appear [\#118](https://github.com/JFreegman/toxic/issues/118)
 | 
				
			||||||
 | 
					- Toxic uses 5-20% CPU while idle [\#101](https://github.com/JFreegman/toxic/issues/101)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixes problems with upstream changes [\#183](https://github.com/JFreegman/toxic/pull/183) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Use long int instead uint64\_t [\#181](https://github.com/JFreegman/toxic/pull/181) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Forgot about help [\#180](https://github.com/JFreegman/toxic/pull/180) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Add option to disable audio support [\#179](https://github.com/JFreegman/toxic/pull/179) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Make closing window end call [\#174](https://github.com/JFreegman/toxic/pull/174) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Manpage fix [\#170](https://github.com/JFreegman/toxic/pull/170) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Add help target and toxic.conf manpage [\#169](https://github.com/JFreegman/toxic/pull/169) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Fixed setting buffer to half of the size [\#165](https://github.com/JFreegman/toxic/pull/165) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Add manpage [\#164](https://github.com/JFreegman/toxic/pull/164) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Try to fix autoconnect [\#161](https://github.com/JFreegman/toxic/pull/161) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Wide characters support [\#157](https://github.com/JFreegman/toxic/pull/157) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Polishing README.md [\#155](https://github.com/JFreegman/toxic/pull/155) ([theGeekPirate](https://github.com/theGeekPirate))
 | 
				
			||||||
 | 
					- README.md: add build status [\#153](https://github.com/JFreegman/toxic/pull/153) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Update readme instructions [\#152](https://github.com/JFreegman/toxic/pull/152) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Forgot to set index in some callbacks [\#151](https://github.com/JFreegman/toxic/pull/151) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Reverse call\_idx and enable running call when devices fail to load [\#150](https://github.com/JFreegman/toxic/pull/150) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Remove autotools dependency [\#149](https://github.com/JFreegman/toxic/pull/149) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Cast localtime [\#147](https://github.com/JFreegman/toxic/pull/147) ([Ansa89](https://github.com/Ansa89))
 | 
				
			||||||
 | 
					- Changed code a bit and added new features [\#146](https://github.com/JFreegman/toxic/pull/146) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.4.1](https://github.com/JFreegman/toxic/tree/0.4.1) (2014-06-19)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.4.0...0.4.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Toxic does not complie with audio on OSX [\#140](https://github.com/JFreegman/toxic/issues/140)
 | 
				
			||||||
 | 
					- compiling error [\#139](https://github.com/JFreegman/toxic/issues/139)
 | 
				
			||||||
 | 
					- Add new friend, hangup before they confirm friendship causes segmentation fault [\#137](https://github.com/JFreegman/toxic/issues/137)
 | 
				
			||||||
 | 
					- build fail [\#124](https://github.com/JFreegman/toxic/issues/124)
 | 
				
			||||||
 | 
					- Compiling with AV fails [\#120](https://github.com/JFreegman/toxic/issues/120)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add libresolv [\#142](https://github.com/JFreegman/toxic/pull/142) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Search for OpenAL framework on OSX [\#141](https://github.com/JFreegman/toxic/pull/141) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.4.0](https://github.com/JFreegman/toxic/tree/0.4.0) (2014-06-01)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0.1...0.4.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Implemented enhancements:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Are there any keybinding to scroll chat/groupchat view up and down? [\#74](https://github.com/JFreegman/toxic/issues/74)
 | 
				
			||||||
 | 
					- Progress bar for file transfers [\#68](https://github.com/JFreegman/toxic/issues/68)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Toxic does not support certain characters [\#84](https://github.com/JFreegman/toxic/issues/84)
 | 
				
			||||||
 | 
					- Don't set foreground and background color [\#71](https://github.com/JFreegman/toxic/issues/71)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Toxic misbehaves and is killed [\#136](https://github.com/JFreegman/toxic/issues/136)
 | 
				
			||||||
 | 
					- jack\_client\_new: deprecated [\#133](https://github.com/JFreegman/toxic/issues/133)
 | 
				
			||||||
 | 
					- build error on os x 10.9 [\#129](https://github.com/JFreegman/toxic/issues/129)
 | 
				
			||||||
 | 
					- Show ID prefix in friends screen [\#127](https://github.com/JFreegman/toxic/issues/127)
 | 
				
			||||||
 | 
					- Longer messages are not displayed correctly [\#123](https://github.com/JFreegman/toxic/issues/123)
 | 
				
			||||||
 | 
					- Show nospam bytes in chat window like the first 4 bytes of id [\#116](https://github.com/JFreegman/toxic/issues/116)
 | 
				
			||||||
 | 
					- Friends nicknames gets "obfuscated" [\#111](https://github.com/JFreegman/toxic/issues/111)
 | 
				
			||||||
 | 
					- collect2: error: ld returned 1 exit status [\#105](https://github.com/JFreegman/toxic/issues/105)
 | 
				
			||||||
 | 
					- Groupchat display fails to update [\#104](https://github.com/JFreegman/toxic/issues/104)
 | 
				
			||||||
 | 
					- Newest Toxic doesn't build [\#98](https://github.com/JFreegman/toxic/issues/98)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Update README.md [\#134](https://github.com/JFreegman/toxic/pull/134) ([zetok](https://github.com/zetok))
 | 
				
			||||||
 | 
					- Update audio\_call.c [\#132](https://github.com/JFreegman/toxic/pull/132) ([Impyy](https://github.com/Impyy))
 | 
				
			||||||
 | 
					- Not done yet. [\#130](https://github.com/JFreegman/toxic/pull/130) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Fix file sender null terminator. [\#128](https://github.com/JFreegman/toxic/pull/128) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- Drop typedef redeclarations [\#122](https://github.com/JFreegman/toxic/pull/122) ([czarkoff](https://github.com/czarkoff))
 | 
				
			||||||
 | 
					- Include "pthread.h" [\#121](https://github.com/JFreegman/toxic/pull/121) ([czarkoff](https://github.com/czarkoff))
 | 
				
			||||||
 | 
					- Wow [\#119](https://github.com/JFreegman/toxic/pull/119) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Use default terminal fg/bg colors when we can. [\#117](https://github.com/JFreegman/toxic/pull/117) ([ooesili](https://github.com/ooesili))
 | 
				
			||||||
 | 
					- Fixed support for wide characters [\#113](https://github.com/JFreegman/toxic/pull/113) ([graboy](https://github.com/graboy))
 | 
				
			||||||
 | 
					- Mention av [\#110](https://github.com/JFreegman/toxic/pull/110) ([stqism](https://github.com/stqism))
 | 
				
			||||||
 | 
					- allow history scrolling [\#109](https://github.com/JFreegman/toxic/pull/109) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Only those who appreciate small things [\#107](https://github.com/JFreegman/toxic/pull/107) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Open devices when call starts instead of keeping them opened all the time [\#103](https://github.com/JFreegman/toxic/pull/103) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Incorrectly handled error check for widechars [\#102](https://github.com/JFreegman/toxic/pull/102) ([graboy](https://github.com/graboy))
 | 
				
			||||||
 | 
					- Fix toxic build when toxav is not available [\#100](https://github.com/JFreegman/toxic/pull/100) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Add checks for pthreads to the build system [\#99](https://github.com/JFreegman/toxic/pull/99) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Fixes and stuff... [\#97](https://github.com/JFreegman/toxic/pull/97) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.3.0.1](https://github.com/JFreegman/toxic/tree/0.3.0.1) (2014-03-12)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.3.0...0.3.0.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- SPELLING IS FOR FOOLS [\#94](https://github.com/JFreegman/toxic/pull/94) ([lehitoskin](https://github.com/lehitoskin))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.3.0](https://github.com/JFreegman/toxic/tree/0.3.0) (2014-03-12)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.7...0.3.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- SIGSEVG upon friend hanging up [\#89](https://github.com/JFreegman/toxic/issues/89)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fixed segfault [\#92](https://github.com/JFreegman/toxic/pull/92) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- This should fix segfault and remove one-line comments [\#91](https://github.com/JFreegman/toxic/pull/91) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Fixed another clang issue with bools that broek file sending. [\#90](https://github.com/JFreegman/toxic/pull/90) ([Jman012](https://github.com/Jman012))
 | 
				
			||||||
 | 
					- Toxic audio support [\#88](https://github.com/JFreegman/toxic/pull/88) ([ghost](https://github.com/ghost))
 | 
				
			||||||
 | 
					- Fixed clang error, disabling the execute module. [\#87](https://github.com/JFreegman/toxic/pull/87) ([Jman012](https://github.com/Jman012))
 | 
				
			||||||
 | 
					- Issue \#84 fixed [\#86](https://github.com/JFreegman/toxic/pull/86) ([thevar1able](https://github.com/thevar1able))
 | 
				
			||||||
 | 
					- Fixing fall-back from IPv6 to IPv4 [\#85](https://github.com/JFreegman/toxic/pull/85) ([micrictor](https://github.com/micrictor))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.2.7](https://github.com/JFreegman/toxic/tree/0.2.7) (2014-03-01)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6.1...0.2.7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Toxic segfault when window is closed [\#81](https://github.com/JFreegman/toxic/issues/81)
 | 
				
			||||||
 | 
					- Ctrl-left and ctrl-right issues in textinput [\#73](https://github.com/JFreegman/toxic/issues/73)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- down arrow returns empty string if at end of history [\#82](https://github.com/JFreegman/toxic/pull/82) ([kl4ng](https://github.com/kl4ng))
 | 
				
			||||||
 | 
					- Fallback to loading /usr/share/toxic/DHTservers. [\#80](https://github.com/JFreegman/toxic/pull/80) ([viric](https://github.com/viric))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.2.6.1](https://github.com/JFreegman/toxic/tree/0.2.6.1) (2014-02-23)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.6...0.2.6.1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.2.6](https://github.com/JFreegman/toxic/tree/0.2.6) (2014-02-23)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/0.2.5...0.2.6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [0.2.5](https://github.com/JFreegman/toxic/tree/0.2.5) (2014-02-22)
 | 
				
			||||||
 | 
					[Full Changelog](https://github.com/JFreegman/toxic/compare/prealpha_win32_r8...0.2.5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Back space leaves ć character [\#44](https://github.com/JFreegman/toxic/issues/44)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Closed issues:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Remember groupchats [\#76](https://github.com/JFreegman/toxic/issues/76)
 | 
				
			||||||
 | 
					- Segfault [\#75](https://github.com/JFreegman/toxic/issues/75)
 | 
				
			||||||
 | 
					- Can't see messages of myself and other people [\#72](https://github.com/JFreegman/toxic/issues/72)
 | 
				
			||||||
 | 
					- binary blob in source [\#66](https://github.com/JFreegman/toxic/issues/66)
 | 
				
			||||||
 | 
					- symbol lookup error [\#54](https://github.com/JFreegman/toxic/issues/54)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ncurses libraries README note  [\#78](https://github.com/JFreegman/toxic/pull/78) ([kl4ng](https://github.com/kl4ng))
 | 
				
			||||||
 | 
					- umask such that stored files are u+rw only [\#77](https://github.com/JFreegman/toxic/pull/77) ([alevy](https://github.com/alevy))
 | 
				
			||||||
 | 
					- Fix groupchat cursor movement. [\#63](https://github.com/JFreegman/toxic/pull/63) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- Fix wchar cursor movement. [\#62](https://github.com/JFreegman/toxic/pull/62) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- api update [\#61](https://github.com/JFreegman/toxic/pull/61) ([naxuroqa](https://github.com/naxuroqa))
 | 
				
			||||||
 | 
					- Add option to switch off ipv6. [\#60](https://github.com/JFreegman/toxic/pull/60) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- Fix partial fix: A slash in pos 0 still led to read access to pathname\[-1\]. [\#59](https://github.com/JFreegman/toxic/pull/59) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- Fix corresponding API name changes in toxcore. [\#58](https://github.com/JFreegman/toxic/pull/58) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- Fix API ret code changes of ToxCore [\#57](https://github.com/JFreegman/toxic/pull/57) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [prealpha_win32_r8](https://github.com/JFreegman/toxic/tree/prealpha_win32_r8) (2013-11-28)
 | 
				
			||||||
 | 
					**Implemented enhancements:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Added groupchats [\#40](https://github.com/JFreegman/toxic/pull/40) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Adapted to ipv6-enabled tox [\#38](https://github.com/JFreegman/toxic/pull/38) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- if tox\_new\(\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- truncate friends' notes if they're too long [\#30](https://github.com/JFreegman/toxic/pull/30) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Added status bar to prompt, made it beep/blink on friend request, and bug fixes [\#29](https://github.com/JFreegman/toxic/pull/29) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Added a statusbar to chat windows and removed spammy messages [\#28](https://github.com/JFreegman/toxic/pull/28) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- implemented status and connectionstatus callbacks [\#26](https://github.com/JFreegman/toxic/pull/26) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Show offline friends names and some cosmetic changes [\#25](https://github.com/JFreegman/toxic/pull/25) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- refactor command argument parsing [\#23](https://github.com/JFreegman/toxic/pull/23) ([lukechampine](https://github.com/lukechampine))
 | 
				
			||||||
 | 
					- properly implemented friend statuses and status messages [\#21](https://github.com/JFreegman/toxic/pull/21) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- implemented friend deletion [\#15](https://github.com/JFreegman/toxic/pull/15) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Add check for setlocale\(\) [\#10](https://github.com/JFreegman/toxic/pull/10) ([manuel-arguelles](https://github.com/manuel-arguelles))
 | 
				
			||||||
 | 
					- Update build system [\#7](https://github.com/JFreegman/toxic/pull/7) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Added travis integration [\#6](https://github.com/JFreegman/toxic/pull/6) ([stqism](https://github.com/stqism))
 | 
				
			||||||
 | 
					- Use new public api [\#5](https://github.com/JFreegman/toxic/pull/5) ([fhahn](https://github.com/fhahn))
 | 
				
			||||||
 | 
					- Add widechar checks [\#2](https://github.com/JFreegman/toxic/pull/2) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Fixed bugs:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Let windows.c actually get the tox \*m. [\#41](https://github.com/JFreegman/toxic/pull/41) ([Jman012](https://github.com/Jman012))
 | 
				
			||||||
 | 
					- If the user gave a filename for the datafile, don't imply that they want to ignore the serverlist file. [\#37](https://github.com/JFreegman/toxic/pull/37) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- Client specific max name length / status messages now dynamically resize [\#36](https://github.com/JFreegman/toxic/pull/36) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Merged pr6 [\#34](https://github.com/JFreegman/toxic/pull/34) ([stqism](https://github.com/stqism))
 | 
				
			||||||
 | 
					- made error handling more consistent and added exit function [\#33](https://github.com/JFreegman/toxic/pull/33) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- if tox\\_new\\(\\) fails, don't crash and leave the terminal in a broken state [\#32](https://github.com/JFreegman/toxic/pull/32) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- Changed statusmsg command to note & segfault fixes [\#24](https://github.com/JFreegman/toxic/pull/24) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- fix buffer overflows and format issues [\#20](https://github.com/JFreegman/toxic/pull/20) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Fix blocking while waiting for key [\#17](https://github.com/JFreegman/toxic/pull/17) ([manuel-arguelles](https://github.com/manuel-arguelles))
 | 
				
			||||||
 | 
					- fixed "free\(\): invalid pointer" when XDG\_CONFIG\_HOME is set [\#16](https://github.com/JFreegman/toxic/pull/16) ([gs93](https://github.com/gs93))
 | 
				
			||||||
 | 
					- Make sure toxic compiles on MinGW/Win32 again [\#14](https://github.com/JFreegman/toxic/pull/14) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Fix for the "bad character" when doing backspace in chat window [\#12](https://github.com/JFreegman/toxic/pull/12) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Fix configure for Free BSD [\#11](https://github.com/JFreegman/toxic/pull/11) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- Fix configure script for ncurses without ncursesw [\#9](https://github.com/JFreegman/toxic/pull/9) ([manuel-arguelles](https://github.com/manuel-arguelles))
 | 
				
			||||||
 | 
					- Fix configure script for mingw32 [\#8](https://github.com/JFreegman/toxic/pull/8) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					- warning: comparison of integers of different signs: 'int' and 'unsigned long' [\#3](https://github.com/JFreegman/toxic/pull/3) ([1100110](https://github.com/1100110))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Merged pull requests:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Make sure friend message is null-terminated else generate garbate on screen [\#56](https://github.com/JFreegman/toxic/pull/56) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- Fix trailing slashes which leads to segfault. [\#55](https://github.com/JFreegman/toxic/pull/55) ([aitjcize](https://github.com/aitjcize))
 | 
				
			||||||
 | 
					- fix cflags [\#53](https://github.com/JFreegman/toxic/pull/53) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Fix 93ab16c [\#52](https://github.com/JFreegman/toxic/pull/52) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Offer solution for "error while loading shared libraries: libtoxcore.so.... [\#51](https://github.com/JFreegman/toxic/pull/51) ([urras](https://github.com/urras))
 | 
				
			||||||
 | 
					- Implemented file transfers [\#50](https://github.com/JFreegman/toxic/pull/50) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Fix check for toxcore by linking sodium in the correct place [\#47](https://github.com/JFreegman/toxic/pull/47) ([devurandom](https://github.com/devurandom))
 | 
				
			||||||
 | 
					- Changed order of servers [\#46](https://github.com/JFreegman/toxic/pull/46) ([grimd34th](https://github.com/grimd34th))
 | 
				
			||||||
 | 
					- set friendnames properly and some fixes [\#45](https://github.com/JFreegman/toxic/pull/45) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- moved misc helper functions to separate file and removed redundant includes [\#43](https://github.com/JFreegman/toxic/pull/43) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Refactored prompt command parser to work with all window types and moved command stuff to separate files [\#42](https://github.com/JFreegman/toxic/pull/42) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Ipv6.init connection [\#39](https://github.com/JFreegman/toxic/pull/39) ([FullName](https://github.com/FullName))
 | 
				
			||||||
 | 
					- Remove DHT window [\#13](https://github.com/JFreegman/toxic/pull/13) ([JFreegman](https://github.com/JFreegman))
 | 
				
			||||||
 | 
					- Update README.md [\#4](https://github.com/JFreegman/toxic/pull/4) ([notadecent](https://github.com/notadecent))
 | 
				
			||||||
 | 
					- Toxic standalone [\#1](https://github.com/JFreegman/toxic/pull/1) ([jin-eld](https://github.com/jin-eld))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
 | 
				
			||||||
							
								
								
									
										365
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										365
									
								
								INSTALL
									
									
									
									
									
								
							@@ -1,365 +0,0 @@
 | 
				
			|||||||
Installation Instructions
 | 
					 | 
				
			||||||
*************************
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
 | 
					 | 
				
			||||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Copying and distribution of this file, with or without modification,
 | 
					 | 
				
			||||||
are permitted in any medium without royalty provided the copyright
 | 
					 | 
				
			||||||
notice and this notice are preserved.  This file is offered as-is,
 | 
					 | 
				
			||||||
without warranty of any kind.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Basic Installation
 | 
					 | 
				
			||||||
==================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Briefly, the shell commands `./configure; make; make install' should
 | 
					 | 
				
			||||||
configure, build, and install this package.  The following
 | 
					 | 
				
			||||||
more-detailed instructions are generic; see the `README' file for
 | 
					 | 
				
			||||||
instructions specific to this package.  Some packages provide this
 | 
					 | 
				
			||||||
`INSTALL' file but do not implement all of the features documented
 | 
					 | 
				
			||||||
below.  The lack of an optional feature in a given package is not
 | 
					 | 
				
			||||||
necessarily a bug.  More recommendations for GNU packages can be found
 | 
					 | 
				
			||||||
in *note Makefile Conventions: (standards)Makefile Conventions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The `configure' shell script attempts to guess correct values for
 | 
					 | 
				
			||||||
various system-dependent variables used during compilation.  It uses
 | 
					 | 
				
			||||||
those values to create a `Makefile' in each directory of the package.
 | 
					 | 
				
			||||||
It may also create one or more `.h' files containing system-dependent
 | 
					 | 
				
			||||||
definitions.  Finally, it creates a shell script `config.status' that
 | 
					 | 
				
			||||||
you can run in the future to recreate the current configuration, and a
 | 
					 | 
				
			||||||
file `config.log' containing compiler output (useful mainly for
 | 
					 | 
				
			||||||
debugging `configure').
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   It can also use an optional file (typically called `config.cache'
 | 
					 | 
				
			||||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
 | 
					 | 
				
			||||||
the results of its tests to speed up reconfiguring.  Caching is
 | 
					 | 
				
			||||||
disabled by default to prevent problems with accidental use of stale
 | 
					 | 
				
			||||||
cache files.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   If you need to do unusual things to compile the package, please try
 | 
					 | 
				
			||||||
to figure out how `configure' could check whether to do them, and mail
 | 
					 | 
				
			||||||
diffs or instructions to the address given in the `README' so they can
 | 
					 | 
				
			||||||
be considered for the next release.  If you are using the cache, and at
 | 
					 | 
				
			||||||
some point `config.cache' contains results you don't want to keep, you
 | 
					 | 
				
			||||||
may remove or edit it.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The file `configure.ac' (or `configure.in') is used to create
 | 
					 | 
				
			||||||
`configure' by a program called `autoconf'.  You need `configure.ac' if
 | 
					 | 
				
			||||||
you want to change it or regenerate `configure' using a newer version
 | 
					 | 
				
			||||||
of `autoconf'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The simplest way to compile this package is:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  1. `cd' to the directory containing the package's source code and type
 | 
					 | 
				
			||||||
     `./configure' to configure the package for your system.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     Running `configure' might take a while.  While running, it prints
 | 
					 | 
				
			||||||
     some messages telling which features it is checking for.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  2. Type `make' to compile the package.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  3. Optionally, type `make check' to run any self-tests that come with
 | 
					 | 
				
			||||||
     the package, generally using the just-built uninstalled binaries.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  4. Type `make install' to install the programs and any data files and
 | 
					 | 
				
			||||||
     documentation.  When installing into a prefix owned by root, it is
 | 
					 | 
				
			||||||
     recommended that the package be configured and built as a regular
 | 
					 | 
				
			||||||
     user, and only the `make install' phase executed with root
 | 
					 | 
				
			||||||
     privileges.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  5. Optionally, type `make installcheck' to repeat any self-tests, but
 | 
					 | 
				
			||||||
     this time using the binaries in their final installed location.
 | 
					 | 
				
			||||||
     This target does not install anything.  Running this target as a
 | 
					 | 
				
			||||||
     regular user, particularly if the prior `make install' required
 | 
					 | 
				
			||||||
     root privileges, verifies that the installation completed
 | 
					 | 
				
			||||||
     correctly.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  6. You can remove the program binaries and object files from the
 | 
					 | 
				
			||||||
     source code directory by typing `make clean'.  To also remove the
 | 
					 | 
				
			||||||
     files that `configure' created (so you can compile the package for
 | 
					 | 
				
			||||||
     a different kind of computer), type `make distclean'.  There is
 | 
					 | 
				
			||||||
     also a `make maintainer-clean' target, but that is intended mainly
 | 
					 | 
				
			||||||
     for the package's developers.  If you use it, you may have to get
 | 
					 | 
				
			||||||
     all sorts of other programs in order to regenerate files that came
 | 
					 | 
				
			||||||
     with the distribution.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  7. Often, you can also type `make uninstall' to remove the installed
 | 
					 | 
				
			||||||
     files again.  In practice, not all packages have tested that
 | 
					 | 
				
			||||||
     uninstallation works correctly, even though it is required by the
 | 
					 | 
				
			||||||
     GNU Coding Standards.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  8. Some packages, particularly those that use Automake, provide `make
 | 
					 | 
				
			||||||
     distcheck', which can by used by developers to test that all other
 | 
					 | 
				
			||||||
     targets like `make install' and `make uninstall' work correctly.
 | 
					 | 
				
			||||||
     This target is generally not run by end users.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Compilers and Options
 | 
					 | 
				
			||||||
=====================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Some systems require unusual options for compilation or linking that
 | 
					 | 
				
			||||||
the `configure' script does not know about.  Run `./configure --help'
 | 
					 | 
				
			||||||
for details on some of the pertinent environment variables.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   You can give `configure' initial values for configuration parameters
 | 
					 | 
				
			||||||
by setting variables in the command line or in the environment.  Here
 | 
					 | 
				
			||||||
is an example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   *Note Defining Variables::, for more details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Compiling For Multiple Architectures
 | 
					 | 
				
			||||||
====================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   You can compile the package for more than one kind of computer at the
 | 
					 | 
				
			||||||
same time, by placing the object files for each architecture in their
 | 
					 | 
				
			||||||
own directory.  To do this, you can use GNU `make'.  `cd' to the
 | 
					 | 
				
			||||||
directory where you want the object files and executables to go and run
 | 
					 | 
				
			||||||
the `configure' script.  `configure' automatically checks for the
 | 
					 | 
				
			||||||
source code in the directory that `configure' is in and in `..'.  This
 | 
					 | 
				
			||||||
is known as a "VPATH" build.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   With a non-GNU `make', it is safer to compile the package for one
 | 
					 | 
				
			||||||
architecture at a time in the source code directory.  After you have
 | 
					 | 
				
			||||||
installed the package for one architecture, use `make distclean' before
 | 
					 | 
				
			||||||
reconfiguring for another architecture.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   On MacOS X 10.5 and later systems, you can create libraries and
 | 
					 | 
				
			||||||
executables that work on multiple system types--known as "fat" or
 | 
					 | 
				
			||||||
"universal" binaries--by specifying multiple `-arch' options to the
 | 
					 | 
				
			||||||
compiler but only a single `-arch' option to the preprocessor.  Like
 | 
					 | 
				
			||||||
this:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
 | 
					 | 
				
			||||||
                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
 | 
					 | 
				
			||||||
                 CPP="gcc -E" CXXCPP="g++ -E"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   This is not guaranteed to produce working output in all cases, you
 | 
					 | 
				
			||||||
may have to build one architecture at a time and combine the results
 | 
					 | 
				
			||||||
using the `lipo' tool if you have problems.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Installation Names
 | 
					 | 
				
			||||||
==================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   By default, `make install' installs the package's commands under
 | 
					 | 
				
			||||||
`/usr/local/bin', include files under `/usr/local/include', etc.  You
 | 
					 | 
				
			||||||
can specify an installation prefix other than `/usr/local' by giving
 | 
					 | 
				
			||||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
 | 
					 | 
				
			||||||
absolute file name.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   You can specify separate installation prefixes for
 | 
					 | 
				
			||||||
architecture-specific files and architecture-independent files.  If you
 | 
					 | 
				
			||||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
 | 
					 | 
				
			||||||
PREFIX as the prefix for installing programs and libraries.
 | 
					 | 
				
			||||||
Documentation and other data files still use the regular prefix.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   In addition, if you use an unusual directory layout you can give
 | 
					 | 
				
			||||||
options like `--bindir=DIR' to specify different values for particular
 | 
					 | 
				
			||||||
kinds of files.  Run `configure --help' for a list of the directories
 | 
					 | 
				
			||||||
you can set and what kinds of files go in them.  In general, the
 | 
					 | 
				
			||||||
default for these options is expressed in terms of `${prefix}', so that
 | 
					 | 
				
			||||||
specifying just `--prefix' will affect all of the other directory
 | 
					 | 
				
			||||||
specifications that were not explicitly provided.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The most portable way to affect installation locations is to pass the
 | 
					 | 
				
			||||||
correct locations to `configure'; however, many packages provide one or
 | 
					 | 
				
			||||||
both of the following shortcuts of passing variable assignments to the
 | 
					 | 
				
			||||||
`make install' command line to change installation locations without
 | 
					 | 
				
			||||||
having to reconfigure or recompile.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The first method involves providing an override variable for each
 | 
					 | 
				
			||||||
affected directory.  For example, `make install
 | 
					 | 
				
			||||||
prefix=/alternate/directory' will choose an alternate location for all
 | 
					 | 
				
			||||||
directory configuration variables that were expressed in terms of
 | 
					 | 
				
			||||||
`${prefix}'.  Any directories that were specified during `configure',
 | 
					 | 
				
			||||||
but not in terms of `${prefix}', must each be overridden at install
 | 
					 | 
				
			||||||
time for the entire installation to be relocated.  The approach of
 | 
					 | 
				
			||||||
makefile variable overrides for each directory variable is required by
 | 
					 | 
				
			||||||
the GNU Coding Standards, and ideally causes no recompilation.
 | 
					 | 
				
			||||||
However, some platforms have known limitations with the semantics of
 | 
					 | 
				
			||||||
shared libraries that end up requiring recompilation when using this
 | 
					 | 
				
			||||||
method, particularly noticeable in packages that use GNU Libtool.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The second method involves providing the `DESTDIR' variable.  For
 | 
					 | 
				
			||||||
example, `make install DESTDIR=/alternate/directory' will prepend
 | 
					 | 
				
			||||||
`/alternate/directory' before all installation names.  The approach of
 | 
					 | 
				
			||||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
 | 
					 | 
				
			||||||
does not work on platforms that have drive letters.  On the other hand,
 | 
					 | 
				
			||||||
it does better at avoiding recompilation issues, and works well even
 | 
					 | 
				
			||||||
when some directory options were not specified in terms of `${prefix}'
 | 
					 | 
				
			||||||
at `configure' time.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Optional Features
 | 
					 | 
				
			||||||
=================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   If the package supports it, you can cause programs to be installed
 | 
					 | 
				
			||||||
with an extra prefix or suffix on their names by giving `configure' the
 | 
					 | 
				
			||||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Some packages pay attention to `--enable-FEATURE' options to
 | 
					 | 
				
			||||||
`configure', where FEATURE indicates an optional part of the package.
 | 
					 | 
				
			||||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
 | 
					 | 
				
			||||||
is something like `gnu-as' or `x' (for the X Window System).  The
 | 
					 | 
				
			||||||
`README' should mention any `--enable-' and `--with-' options that the
 | 
					 | 
				
			||||||
package recognizes.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   For packages that use the X Window System, `configure' can usually
 | 
					 | 
				
			||||||
find the X include and library files automatically, but if it doesn't,
 | 
					 | 
				
			||||||
you can use the `configure' options `--x-includes=DIR' and
 | 
					 | 
				
			||||||
`--x-libraries=DIR' to specify their locations.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Some packages offer the ability to configure how verbose the
 | 
					 | 
				
			||||||
execution of `make' will be.  For these packages, running `./configure
 | 
					 | 
				
			||||||
--enable-silent-rules' sets the default to minimal output, which can be
 | 
					 | 
				
			||||||
overridden with `make V=1'; while running `./configure
 | 
					 | 
				
			||||||
--disable-silent-rules' sets the default to verbose, which can be
 | 
					 | 
				
			||||||
overridden with `make V=0'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Particular systems
 | 
					 | 
				
			||||||
==================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
 | 
					 | 
				
			||||||
CC is not installed, it is recommended to use the following options in
 | 
					 | 
				
			||||||
order to use an ANSI C compiler:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
 | 
					 | 
				
			||||||
parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
 | 
					 | 
				
			||||||
a workaround.  If GNU CC is not installed, it is therefore recommended
 | 
					 | 
				
			||||||
to try
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC="cc"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
and if that doesn't work, try
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC="cc -nodtk"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
 | 
					 | 
				
			||||||
directory contains several dysfunctional programs; working variants of
 | 
					 | 
				
			||||||
these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
 | 
					 | 
				
			||||||
in your `PATH', put it _after_ `/usr/bin'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   On Haiku, software installed for all users goes in `/boot/common',
 | 
					 | 
				
			||||||
not `/usr/local'.  It is recommended to use the following options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure --prefix=/boot/common
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Specifying the System Type
 | 
					 | 
				
			||||||
==========================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   There may be some features `configure' cannot figure out
 | 
					 | 
				
			||||||
automatically, but needs to determine by the type of machine the package
 | 
					 | 
				
			||||||
will run on.  Usually, assuming the package is built to be run on the
 | 
					 | 
				
			||||||
_same_ architectures, `configure' can figure that out, but if it prints
 | 
					 | 
				
			||||||
a message saying it cannot guess the machine type, give it the
 | 
					 | 
				
			||||||
`--build=TYPE' option.  TYPE can either be a short name for the system
 | 
					 | 
				
			||||||
type, such as `sun4', or a canonical name which has the form:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     CPU-COMPANY-SYSTEM
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
where SYSTEM can have one of these forms:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     OS
 | 
					 | 
				
			||||||
     KERNEL-OS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   See the file `config.sub' for the possible values of each field.  If
 | 
					 | 
				
			||||||
`config.sub' isn't included in this package, then this package doesn't
 | 
					 | 
				
			||||||
need to know the machine type.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   If you are _building_ compiler tools for cross-compiling, you should
 | 
					 | 
				
			||||||
use the option `--target=TYPE' to select the type of system they will
 | 
					 | 
				
			||||||
produce code for.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   If you want to _use_ a cross compiler, that generates code for a
 | 
					 | 
				
			||||||
platform different from the build platform, you should specify the
 | 
					 | 
				
			||||||
"host" platform (i.e., that on which the generated programs will
 | 
					 | 
				
			||||||
eventually be run) with `--host=TYPE'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Sharing Defaults
 | 
					 | 
				
			||||||
================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   If you want to set default values for `configure' scripts to share,
 | 
					 | 
				
			||||||
you can create a site shell script called `config.site' that gives
 | 
					 | 
				
			||||||
default values for variables like `CC', `cache_file', and `prefix'.
 | 
					 | 
				
			||||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
 | 
					 | 
				
			||||||
`PREFIX/etc/config.site' if it exists.  Or, you can set the
 | 
					 | 
				
			||||||
`CONFIG_SITE' environment variable to the location of the site script.
 | 
					 | 
				
			||||||
A warning: not all `configure' scripts look for a site script.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Defining Variables
 | 
					 | 
				
			||||||
==================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Variables not defined in a site shell script can be set in the
 | 
					 | 
				
			||||||
environment passed to `configure'.  However, some packages may run
 | 
					 | 
				
			||||||
configure again during the build, and the customized values of these
 | 
					 | 
				
			||||||
variables may be lost.  In order to avoid this problem, you should set
 | 
					 | 
				
			||||||
them in the `configure' command line, using `VAR=value'.  For example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     ./configure CC=/usr/local2/bin/gcc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
causes the specified `gcc' to be used as the C compiler (unless it is
 | 
					 | 
				
			||||||
overridden in the site shell script).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
 | 
					 | 
				
			||||||
an Autoconf bug.  Until the bug is fixed you can use this workaround:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`configure' Invocation
 | 
					 | 
				
			||||||
======================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   `configure' recognizes the following options to control how it
 | 
					 | 
				
			||||||
operates.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--help'
 | 
					 | 
				
			||||||
`-h'
 | 
					 | 
				
			||||||
     Print a summary of all of the options to `configure', and exit.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--help=short'
 | 
					 | 
				
			||||||
`--help=recursive'
 | 
					 | 
				
			||||||
     Print a summary of the options unique to this package's
 | 
					 | 
				
			||||||
     `configure', and exit.  The `short' variant lists options used
 | 
					 | 
				
			||||||
     only in the top level, while the `recursive' variant lists options
 | 
					 | 
				
			||||||
     also present in any nested packages.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--version'
 | 
					 | 
				
			||||||
`-V'
 | 
					 | 
				
			||||||
     Print the version of Autoconf used to generate the `configure'
 | 
					 | 
				
			||||||
     script, and exit.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--cache-file=FILE'
 | 
					 | 
				
			||||||
     Enable the cache: use and save the results of the tests in FILE,
 | 
					 | 
				
			||||||
     traditionally `config.cache'.  FILE defaults to `/dev/null' to
 | 
					 | 
				
			||||||
     disable caching.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--config-cache'
 | 
					 | 
				
			||||||
`-C'
 | 
					 | 
				
			||||||
     Alias for `--cache-file=config.cache'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--quiet'
 | 
					 | 
				
			||||||
`--silent'
 | 
					 | 
				
			||||||
`-q'
 | 
					 | 
				
			||||||
     Do not print messages saying which checks are being made.  To
 | 
					 | 
				
			||||||
     suppress all normal output, redirect it to `/dev/null' (any error
 | 
					 | 
				
			||||||
     messages will still be shown).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--srcdir=DIR'
 | 
					 | 
				
			||||||
     Look for the package's source code in directory DIR.  Usually
 | 
					 | 
				
			||||||
     `configure' can determine that directory automatically.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--prefix=DIR'
 | 
					 | 
				
			||||||
     Use DIR as the installation prefix.  *note Installation Names::
 | 
					 | 
				
			||||||
     for more details, including other options available for fine-tuning
 | 
					 | 
				
			||||||
     the installation locations.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`--no-create'
 | 
					 | 
				
			||||||
`-n'
 | 
					 | 
				
			||||||
     Run the configure checks, but stop before creating any output
 | 
					 | 
				
			||||||
     files.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
`configure' also accepts some other, not widely useful, options.  Run
 | 
					 | 
				
			||||||
`configure --help' for more details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										70
									
								
								INSTALL.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								INSTALL.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					# Installation
 | 
				
			||||||
 | 
					* [Dependencies](#dependencies)
 | 
				
			||||||
 | 
					  * [OS X Notes](#os-x-notes)
 | 
				
			||||||
 | 
					* [Compiling](#compiling)
 | 
				
			||||||
 | 
					  * [Documentation](#documentation)
 | 
				
			||||||
 | 
					* [Notes](#notes)
 | 
				
			||||||
 | 
					  * [Compilation variables](#compilation-variables)
 | 
				
			||||||
 | 
					  * [Environment variables](#environment-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Dependencies
 | 
				
			||||||
 | 
					| Name                                                 | Needed by                  | Debian package      |
 | 
				
			||||||
 | 
					|------------------------------------------------------|----------------------------|---------------------|
 | 
				
			||||||
 | 
					| [Tox Core](https://github.com/toktok/c-toxcore)      | BASE                       | *None*              |
 | 
				
			||||||
 | 
					| [NCurses](https://www.gnu.org/software/ncurses)      | BASE                       | libncursesw5-dev    |
 | 
				
			||||||
 | 
					| [LibConfig](http://www.hyperrealm.com/libconfig)     | BASE                       | libconfig-dev       |
 | 
				
			||||||
 | 
					| [GNUmake](https://www.gnu.org/software/make)         | BASE                       | make                |
 | 
				
			||||||
 | 
					| [libcurl](http://curl.haxx.se/)                      | BASE                       | libcurl4-openssl-dev|
 | 
				
			||||||
 | 
					| [libqrencode](https://fukuchi.org/works/qrencode/)   | QRCODE                     | libqrencode-dev     |
 | 
				
			||||||
 | 
					| [OpenAL](http://openal.org)                          | AUDIO, SOUND NOTIFICATIONS | libopenal-dev       |
 | 
				
			||||||
 | 
					| [OpenALUT](http://openal.org)                        | SOUND NOTIFICATIONS        | libalut-dev         |
 | 
				
			||||||
 | 
					| [LibNotify](https://developer.gnome.org/libnotify)   | DESKTOP NOTIFICATIONS      | libnotify-dev       |
 | 
				
			||||||
 | 
					| [Python 3](http://www.python.org/)                   | PYTHON                     | python3-dev         |
 | 
				
			||||||
 | 
					| [AsciiDoc](http://asciidoc.org/index.html)           | DOCUMENTATION<sup>1</sup>  | asciidoc            |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<sup>1</sup>: see [Documentation](#documentation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### OS X Notes
 | 
				
			||||||
 | 
					Using [Homebrew](http://brew.sh):
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					brew install curl qrencode openal-soft freealut libconfig libpng
 | 
				
			||||||
 | 
					brew install --HEAD https://raw.githubusercontent.com/Tox/homebrew-tox/master/Formula/libtoxcore.rb
 | 
				
			||||||
 | 
					brew install libnotify
 | 
				
			||||||
 | 
					export PKG_CONFIG_PATH=/usr/local/opt/openal-soft/lib/pkgconfig
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can omit `libnotify` if you intend to build without desktop notifications enabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Compiling
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					make
 | 
				
			||||||
 | 
					sudo make install
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Documentation
 | 
				
			||||||
 | 
					Run `make doc` in the build directory after editing the asciidoc files to regenerate the manpages.<br />
 | 
				
			||||||
 | 
					**Note for developers**: asciidoc files and generated manpages will need to be committed together.<br />
 | 
				
			||||||
 | 
					**Note for everyone**: [asciidoc](http://asciidoc.org/index.html) (and this step) is only required for regenerating manpages when you modify them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Notes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Compilation variables
 | 
				
			||||||
 | 
					* You can add specific flags to the Makefile with `USER_CFLAGS=""` and `USER_LDFLAGS=""` passed as arguments to make, or as environment variables
 | 
				
			||||||
 | 
					* Default compile options can be overridden by using special variables:
 | 
				
			||||||
 | 
					  * `DISABLE_X11=1` → Disable X11 support (needed for focus tracking)
 | 
				
			||||||
 | 
					  * `DISABLE_AV=1` → Disable audio call support
 | 
				
			||||||
 | 
					  * `DISABLE_SOUND_NOTIFY=1` → Disable sound notifications support
 | 
				
			||||||
 | 
					  * `DISABLE_QRCODE` → Disable QR exporting support
 | 
				
			||||||
 | 
					  * `DISABLE_QRPNG` → Disable support for exporting QR as PNG
 | 
				
			||||||
 | 
					  * `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
 | 
				
			||||||
 | 
					  * `ENABLE_PYTHON=1` → Build toxic with Python scripting support
 | 
				
			||||||
 | 
					  * `ENABLE_RELEASE=1` → Build toxic without debug symbols and with full compiler optimizations
 | 
				
			||||||
 | 
					  * `ENABLE_ASAN=1` → Build toxic with LLVM Address Sanitizer enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Environment variables
 | 
				
			||||||
 | 
					* You can use the `CFLAGS` and `LDFLAGS` environment variables to add specific flags to the Makefile
 | 
				
			||||||
 | 
					* The `PREFIX` environment variable specifies a base install directory for binaries and data files. This is interchangeable with the `DESTDIR` variable, and is generally used by systems that have the `PREFIX` environment variable set by default.<br />
 | 
				
			||||||
 | 
					**Note**: `sudo` does not preserve user environment variables by default on some systems. See the `sudoers` manual for more information.
 | 
				
			||||||
@@ -672,3 +672,4 @@ may consider it more useful to permit linking proprietary applications with
 | 
				
			|||||||
the library.  If this is what you want to do, use the GNU Lesser General
 | 
					the library.  If this is what you want to do, use the GNU Lesser General
 | 
				
			||||||
Public License instead of this License.  But first, please read
 | 
					Public License instead of this License.  But first, please read
 | 
				
			||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
 | 
					<http://www.gnu.org/philosophy/why-not-lgpl.html>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										97
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					BASE_DIR = $(shell pwd -P)
 | 
				
			||||||
 | 
					CFG_DIR = $(BASE_DIR)/cfg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-include $(CFG_DIR)/global_vars.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS = toxcore ncursesw libconfig libcurl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS ?= -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wno-missing-braces
 | 
				
			||||||
 | 
					CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
 | 
				
			||||||
 | 
					CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
 | 
				
			||||||
 | 
					CFLAGS += ${USER_CFLAGS}
 | 
				
			||||||
 | 
					LDFLAGS ?=
 | 
				
			||||||
 | 
					LDFLAGS += ${USER_LDFLAGS}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OBJ = autocomplete.o avatars.o bootstrap.o chat.o chat_commands.o configdir.o curl_util.o execute.o
 | 
				
			||||||
 | 
					OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o conference.o help.o input.o
 | 
				
			||||||
 | 
					OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
 | 
				
			||||||
 | 
					OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if debug build is enabled
 | 
				
			||||||
 | 
					RELEASE := $(shell if [ -z "$(ENABLE_RELEASE)" ] || [ "$(ENABLE_RELEASE)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(RELEASE), enabled)
 | 
				
			||||||
 | 
						CFLAGS += -O0 -g -DDEBUG
 | 
				
			||||||
 | 
						LDFLAGS += -O0
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						CFLAGS += -O2 -flto
 | 
				
			||||||
 | 
						LDFLAGS += -O2 -flto
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if LLVM Address Sanitizer is enabled
 | 
				
			||||||
 | 
					ENABLE_ASAN := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(ENABLE_ASAN), disabled)
 | 
				
			||||||
 | 
						CFLAGS += -fsanitize=address -fno-omit-frame-pointer
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check on wich system we are running
 | 
				
			||||||
 | 
					UNAME_S = $(shell uname -s)
 | 
				
			||||||
 | 
					ifeq ($(UNAME_S), Linux)
 | 
				
			||||||
 | 
					LDFLAGS += -ldl -lrt
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifeq ($(UNAME_S), OpenBSD)
 | 
				
			||||||
 | 
					LIBS := $(filter-out ncursesw, $(LIBS))
 | 
				
			||||||
 | 
					LDFLAGS += -lncursesw
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifeq ($(UNAME_S), NetBSD)
 | 
				
			||||||
 | 
					LIBS := $(filter-out ncursesw, $(LIBS))
 | 
				
			||||||
 | 
					LDFLAGS += -lncursesw
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifeq ($(UNAME_S), Darwin)
 | 
				
			||||||
 | 
					    -include $(CFG_DIR)/systems/Darwin.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check on which platform we are running
 | 
				
			||||||
 | 
					UNAME_M = $(shell uname -m)
 | 
				
			||||||
 | 
					ifeq ($(UNAME_M), x86_64)
 | 
				
			||||||
 | 
					    -include $(CFG_DIR)/platforms/x86_64.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifneq ($(filter %86, $(UNAME_M)),)
 | 
				
			||||||
 | 
					    -include $(CFG_DIR)/platforms/x86.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifneq ($(filter arm%, $(UNAME_M)),)
 | 
				
			||||||
 | 
					    -include $(CFG_DIR)/platforms/arm.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Include all needed checks
 | 
				
			||||||
 | 
					-include $(CFG_DIR)/checks/check_features.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Fix path for object files
 | 
				
			||||||
 | 
					OBJ := $(addprefix $(BUILD_DIR)/, $(OBJ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Targets
 | 
				
			||||||
 | 
					all: $(BUILD_DIR)/toxic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BUILD_DIR)/toxic: $(OBJ)
 | 
				
			||||||
 | 
						@echo "  LD    $(@:$(BUILD_DIR)/%=%)"
 | 
				
			||||||
 | 
						@$(CC) $(CFLAGS) -o $(BUILD_DIR)/toxic $(OBJ) $(LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BUILD_DIR)/osx_video.o: $(SRC_DIR)/$(OSX_VIDEO)
 | 
				
			||||||
 | 
						@echo "  CC    $(@:$(BUILD_DIR)/)osx_video.o"
 | 
				
			||||||
 | 
						@$(CC) $(CFLAGS) -o $(BUILD_DIR)/osx_video.o -c $(SRC_DIR)/$(OSX_VIDEO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
 | 
				
			||||||
 | 
						@if [ ! -e $(BUILD_DIR) ]; then \
 | 
				
			||||||
 | 
							mkdir -p $(BUILD_DIR) ;\
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						@echo "  CC    $(@:$(BUILD_DIR)/%=%)"
 | 
				
			||||||
 | 
						@$(CC) $(CFLAGS) -o $(BUILD_DIR)/$*.o -c $(SRC_DIR)/$*.c
 | 
				
			||||||
 | 
						@$(CC) -MM $(CFLAGS) $(SRC_DIR)/$*.c >$(BUILD_DIR)/$*.d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o $(BUILD_DIR)/toxic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-include $(BUILD_DIR)/$(OBJ:.o=.d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-include $(CFG_DIR)/targets/*.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: clean all
 | 
				
			||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
SUBDIRS = build misc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ACLOCAL_AMFLAGS = -I m4
 | 
					 | 
				
			||||||
							
								
								
									
										32
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								README.md
									
									
									
									
									
								
							@@ -1,21 +1,27 @@
 | 
				
			|||||||
# Toxic
 | 
					<a href="https://scan.coverity.com/projects/toxic-tox">
 | 
				
			||||||
 | 
					  <img alt="Coverity Scan Build Status"
 | 
				
			||||||
 | 
					       src="https://scan.coverity.com/projects/4975/badge.svg"/>
 | 
				
			||||||
 | 
					</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[](https://i.imgur.com/TwYA8L0.png)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Toxic is an ncurses based instant messaging client for [Tox](http://tox.im) which formerly resided in the [Tox core repository](https://github.com/irungentoo/ProjectTox-Core) and is now available as a standalone program. It looks like [this](http://i.imgur.com/hL7WhVl.png).
 | 
					 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
* Generate the configure script by running the ```autoreconf -i``` command.
 | 
					[See the install instructions](/INSTALL.md)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Execute the configure script with ```./configure``` (you may need to pass it the location of your dependency libraries, i.e.):
 | 
					## Settings
 | 
				
			||||||
```./configure --prefix=/where/to/install --with-libtoxcore-headers=/path/to/ProjectTox-Core/toxcore --with-libtoxcore-libs=/path/to/ProjectTox-Core/build/toxcore --with-libsodium-headers=/path/to/libsodium/include/ --with-libsodium-libs=/path/to/sodiumtest/lib/ ```
 | 
					Running Toxic for the first time creates an empty file called toxic.conf in your home configuration directory ("~/.config/tox" for Linux users). Adding options to this file allows you to enable auto-logging, change the time format (12/24 hour), and much more.
 | 
				
			||||||
 | 
					You can view our example config file [here](misc/toxic.conf.example).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Compile and install the program with ```make && sudo make install```
 | 
					## Troubleshooting
 | 
				
			||||||
 | 
					If your default prefix is "/usr/local" and you receive the following:
 | 
				
			||||||
#### Notes
 | 
					```
 | 
				
			||||||
If your default prefix is /usr/local and you get the error: "error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory", then you can try running ```sudo ldconfig```. If that doesn't fix it, run:
 | 
					error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					you can attempt to correct it by running `sudo ldconfig`. If that doesn't work, run:
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
 | 
					echo '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf
 | 
				
			||||||
sudo ldconfig
 | 
					sudo ldconfig
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
If you dont already have them, you may need to install the ncurses libraries. For Debian based systems:
 | 
					
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
sudo apt-get install libncurses5-dev libncursesw5-dev
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								apidoc/python/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								apidoc/python/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# Minimal makefile for Sphinx documentation
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# You can set these variables from the command line.
 | 
				
			||||||
 | 
					SPHINXOPTS    =
 | 
				
			||||||
 | 
					SPHINXBUILD   = sphinx-build
 | 
				
			||||||
 | 
					SPHINXPROJ    = toxic_api
 | 
				
			||||||
 | 
					SOURCEDIR     = source
 | 
				
			||||||
 | 
					BUILDDIR      = build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Put it first so that "make" without argument is like "make help".
 | 
				
			||||||
 | 
					help:
 | 
				
			||||||
 | 
						@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: help Makefile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Catch-all target: route all unknown targets to Sphinx using the new
 | 
				
			||||||
 | 
					# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
 | 
				
			||||||
 | 
					%: Makefile
 | 
				
			||||||
 | 
						@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
 | 
				
			||||||
							
								
								
									
										157
									
								
								apidoc/python/source/conf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								apidoc/python/source/conf.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# toxic_api documentation build configuration file, created by
 | 
				
			||||||
 | 
					# sphinx-quickstart on Tue May 16 08:58:24 2017.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is execfile()d with the current directory set to its
 | 
				
			||||||
 | 
					# containing dir.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Note that not all possible configuration values are present in this
 | 
				
			||||||
 | 
					# autogenerated file.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# All configuration values have a default; values that are commented out
 | 
				
			||||||
 | 
					# serve to show the default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# import os
 | 
				
			||||||
 | 
					# import sys
 | 
				
			||||||
 | 
					# sys.path.insert(0, os.path.abspath('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- General configuration ------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If your documentation needs a minimal Sphinx version, state it here.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# needs_sphinx = '1.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add any Sphinx extension module names here, as strings. They can be
 | 
				
			||||||
 | 
					# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 | 
				
			||||||
 | 
					# ones.
 | 
				
			||||||
 | 
					extensions = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add any paths that contain templates here, relative to this directory.
 | 
				
			||||||
 | 
					templates_path = ['_templates']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The suffix(es) of source filenames.
 | 
				
			||||||
 | 
					# You can specify multiple suffix as a list of string:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# source_suffix = ['.rst', '.md']
 | 
				
			||||||
 | 
					source_suffix = '.rst'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The master toctree document.
 | 
				
			||||||
 | 
					master_doc = 'index'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# General information about the project.
 | 
				
			||||||
 | 
					project = 'toxic_api'
 | 
				
			||||||
 | 
					copyright = '2017, Jakob Kreuze'
 | 
				
			||||||
 | 
					author = 'Jakob Kreuze'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The short X.Y version.
 | 
				
			||||||
 | 
					version = '0.10.0'
 | 
				
			||||||
 | 
					# The full version, including alpha/beta/rc tags.
 | 
				
			||||||
 | 
					release = '0.10.0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The language for content autogenerated by Sphinx. Refer to documentation
 | 
				
			||||||
 | 
					# for a list of supported languages.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This is also used if you do content translation via gettext catalogs.
 | 
				
			||||||
 | 
					# Usually you set "language" from the command line for these cases.
 | 
				
			||||||
 | 
					language = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# List of patterns, relative to source directory, that match files and
 | 
				
			||||||
 | 
					# directories to ignore when looking for source files.
 | 
				
			||||||
 | 
					# This patterns also effect to html_static_path and html_extra_path
 | 
				
			||||||
 | 
					exclude_patterns = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The name of the Pygments (syntax highlighting) style to use.
 | 
				
			||||||
 | 
					pygments_style = 'sphinx'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If true, `todo` and `todoList` produce output, else they produce nothing.
 | 
				
			||||||
 | 
					todo_include_todos = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- Options for HTML output ----------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The theme to use for HTML and HTML Help pages.  See the documentation for
 | 
				
			||||||
 | 
					# a list of builtin themes.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					html_theme = 'alabaster'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Theme options are theme-specific and customize the look and feel of a theme
 | 
				
			||||||
 | 
					# further.  For a list of options available for each theme, see the
 | 
				
			||||||
 | 
					# documentation.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# html_theme_options = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Add any paths that contain custom static files (such as style sheets) here,
 | 
				
			||||||
 | 
					# relative to this directory. They are copied after the builtin static files,
 | 
				
			||||||
 | 
					# so a file named "default.css" will overwrite the builtin "default.css".
 | 
				
			||||||
 | 
					html_static_path = ['_static']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- Options for HTMLHelp output ------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Output file base name for HTML help builder.
 | 
				
			||||||
 | 
					htmlhelp_basename = 'toxic_apidoc'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- Options for LaTeX output ---------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					latex_elements = {
 | 
				
			||||||
 | 
					    # The paper size ('letterpaper' or 'a4paper').
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # 'papersize': 'letterpaper',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The font size ('10pt', '11pt' or '12pt').
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # 'pointsize': '10pt',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Additional stuff for the LaTeX preamble.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # 'preamble': '',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Latex figure (float) alignment
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # 'figure_align': 'htbp',
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Grouping the document tree into LaTeX files. List of tuples
 | 
				
			||||||
 | 
					# (source start file, target name, title,
 | 
				
			||||||
 | 
					#  author, documentclass [howto, manual, or own class]).
 | 
				
			||||||
 | 
					latex_documents = [
 | 
				
			||||||
 | 
					    (master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
 | 
				
			||||||
 | 
					     'Jakob Kreuze', 'manual'),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- Options for manual page output ---------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# One entry per manual page. List of tuples
 | 
				
			||||||
 | 
					# (source start file, name, description, authors, manual section).
 | 
				
			||||||
 | 
					man_pages = [
 | 
				
			||||||
 | 
					    (master_doc, 'toxic_api', 'toxic_api Documentation',
 | 
				
			||||||
 | 
					     [author], 1)
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -- Options for Texinfo output -------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Grouping the document tree into Texinfo files. List of tuples
 | 
				
			||||||
 | 
					# (source start file, target name, title, author,
 | 
				
			||||||
 | 
					#  dir menu entry, description, category)
 | 
				
			||||||
 | 
					texinfo_documents = [
 | 
				
			||||||
 | 
					    (master_doc, 'toxic_api', 'toxic_api Documentation',
 | 
				
			||||||
 | 
					     author, 'toxic_api', 'One line description of project.',
 | 
				
			||||||
 | 
					     'Miscellaneous'),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								apidoc/python/source/examples.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								apidoc/python/source/examples.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					============
 | 
				
			||||||
 | 
					API Examples
 | 
				
			||||||
 | 
					============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Fortune
 | 
				
			||||||
 | 
					=======
 | 
				
			||||||
 | 
					.. literalinclude:: fortune.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
							
								
								
									
										37
									
								
								apidoc/python/source/fortune.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								apidoc/python/source/fortune.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import toxic_api
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FORTUNES = [
 | 
				
			||||||
 | 
					    "A bug in the code is worth two in the documentation.",
 | 
				
			||||||
 | 
					    "A bug in the hand is better than one as yet undetected.",
 | 
				
			||||||
 | 
					    "\"A debugged program is one for which you have not yet found the "
 | 
				
			||||||
 | 
					    "conditions that make it fail.\" -- Jerry Ogdin"
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_fortune(args):
 | 
				
			||||||
 | 
					    """Callback function that sends the contact of the current window a
 | 
				
			||||||
 | 
					    given number of random fortunes.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    if len(args) != 1:
 | 
				
			||||||
 | 
					        toxic_api.display("Only one argument allowed!")
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        count = int(args[0])
 | 
				
			||||||
 | 
					    except ValueError:
 | 
				
			||||||
 | 
					        toxic_api.display("Argument must be a number!")
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if count < 0 or count > 20:
 | 
				
			||||||
 | 
					        toxic_api.display("Argument is too large!")
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = toxic_api.get_nick()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
 | 
				
			||||||
 | 
					    for _ in range(count):
 | 
				
			||||||
 | 
					        toxic_api.send(random.choice(FORTUNES))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					toxic_api.register("/fortune", "Send a fortune to the contact of the current "
 | 
				
			||||||
 | 
					                   "window", send_fortune)
 | 
				
			||||||
							
								
								
									
										9
									
								
								apidoc/python/source/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apidoc/python/source/index.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					Toxic Scripting Interface Documentation
 | 
				
			||||||
 | 
					=======================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. toctree::
 | 
				
			||||||
 | 
					   :maxdepth: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   intro
 | 
				
			||||||
 | 
					   reference
 | 
				
			||||||
 | 
					   examples
 | 
				
			||||||
							
								
								
									
										12
									
								
								apidoc/python/source/intro.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								apidoc/python/source/intro.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					=========================
 | 
				
			||||||
 | 
					Toxic Scripting Interface
 | 
				
			||||||
 | 
					=========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Getting Started
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.
 | 
				
			||||||
							
								
								
									
										73
									
								
								apidoc/python/source/reference.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								apidoc/python/source/reference.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					=============
 | 
				
			||||||
 | 
					API Reference
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Messages
 | 
				
			||||||
 | 
					========
 | 
				
			||||||
 | 
					.. function:: display(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Display a message to the user through the current window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :param msg: The message to display.
 | 
				
			||||||
 | 
					   :type msg: string
 | 
				
			||||||
 | 
					   :rtype: none
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: send(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Send a message to the user specified by the currently open conversation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :param msg: The message to display.
 | 
				
			||||||
 | 
					   :type msg: string
 | 
				
			||||||
 | 
					   :rtype: none
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					State
 | 
				
			||||||
 | 
					=====
 | 
				
			||||||
 | 
					.. function:: get_nick()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Return the user's current nickname.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :rtype: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: get_status()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Return a string representing the user's current status. Can be either "online", "away", or "busy".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :rtype: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: get_status_message()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Return the user's current status message.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :rtype: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: get_all_friends()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Return a list of all the user's friends.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :rtype: list of (string, string) tuples containing the nickname followed by their public key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commands
 | 
				
			||||||
 | 
					========
 | 
				
			||||||
 | 
					.. function:: execute(command, class)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :param command: The command to execute.
 | 
				
			||||||
 | 
					   :type command: string
 | 
				
			||||||
 | 
					   :param class: The class of the command.
 | 
				
			||||||
 | 
					   :type class: int
 | 
				
			||||||
 | 
					   :rtype: none
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. function:: register(command, help, callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :param command: The command to listen for.
 | 
				
			||||||
 | 
					   :type command: string
 | 
				
			||||||
 | 
					   :param help: A description of the command to be shown in the help menu.
 | 
				
			||||||
 | 
					   :type help: string
 | 
				
			||||||
 | 
					   :param callback: The function to be called.
 | 
				
			||||||
 | 
					   :type callback: callable
 | 
				
			||||||
 | 
					   :rtype: none
 | 
				
			||||||
							
								
								
									
										26
									
								
								astylerc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								astylerc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# Bracket Style Options
 | 
				
			||||||
 | 
					--style=kr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tab Options
 | 
				
			||||||
 | 
					--indent=spaces=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Indentation Options
 | 
				
			||||||
 | 
					--indent-switches
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Padding Options
 | 
				
			||||||
 | 
					--pad-header
 | 
				
			||||||
 | 
					--break-blocks
 | 
				
			||||||
 | 
					--pad-oper
 | 
				
			||||||
 | 
					--unpad-paren
 | 
				
			||||||
 | 
					--align-pointer=name
 | 
				
			||||||
 | 
					--align-reference=name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Formatting Options
 | 
				
			||||||
 | 
					--add-brackets
 | 
				
			||||||
 | 
					--convert-tabs
 | 
				
			||||||
 | 
					--max-code-length=120
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Other Options
 | 
				
			||||||
 | 
					--preserve-date
 | 
				
			||||||
 | 
					--formatted
 | 
				
			||||||
 | 
					--lineend=linux
 | 
				
			||||||
@@ -1,60 +0,0 @@
 | 
				
			|||||||
#Don't change this unless needed, else you'll break stuff
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bin_PROGRAMS = toxic
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_SOURCES = $(top_srcdir)/src/main.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/chat.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/chat.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/configdir.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/configdir.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/prompt.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/prompt.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/friendlist.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/friendlist.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/toxic_windows.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/windows.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/groupchat.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/groupchat.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/global_commands.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/global_commands.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/chat_commands.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/chat_commands.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/execute.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/execute.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/misc_tools.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/misc_tools.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/toxic_strings.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/toxic_strings.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/log.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/log.h \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/file_senders.c \
 | 
					 | 
				
			||||||
                $(top_srcdir)/src/file_senders.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_CFLAGS =                 -I$(top_srcdir) \
 | 
					 | 
				
			||||||
				$(NCURSES_CFLAGS) \
 | 
					 | 
				
			||||||
				$(LIBSODIUM_CFLAGS) \
 | 
					 | 
				
			||||||
				$(LIBTOXCORE_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_CPPFLAGS = '-DTOXICVER="$(TOXIC_VERSION)"'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_LDADD =	$(LIBTOXCORE_LDFLAGS) \
 | 
					 | 
				
			||||||
				$(LIBSODIUM_LDFLAGS) \
 | 
					 | 
				
			||||||
				$(NCURSES_LIBS) \
 | 
					 | 
				
			||||||
				$(LIBTOXCORE_LIBS) \
 | 
					 | 
				
			||||||
				$(LIBSODIUM_LIBS) \
 | 
					 | 
				
			||||||
                $(WINSOCK2_LIBS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# For audio support
 | 
					 | 
				
			||||||
if BUILD_AV
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_SOURCES += $(top_srcdir)/src/audio_call.c \
 | 
					 | 
				
			||||||
                 $(top_srcdir)/src/audio_call.h
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
toxic_CFLAGS += $(LIBTOXAV_CFLAGS) \
 | 
					 | 
				
			||||||
		$(OPENAL_CFLAGS)
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
toxic_LDADD += $(LIBTOXAV_LIBS) \
 | 
					 | 
				
			||||||
	       $(OPENAL_LIBS) 
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
							
								
								
									
										22
									
								
								cfg/checks/audio.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								cfg/checks/audio.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					# Variables for audio call support
 | 
				
			||||||
 | 
					AUDIO_LIBS = openal
 | 
				
			||||||
 | 
					AUDIO_CFLAGS = -DAUDIO
 | 
				
			||||||
 | 
					ifneq (, $(findstring audio_device.o, $(OBJ)))
 | 
				
			||||||
 | 
					    AUDIO_OBJ = audio_call.o
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    AUDIO_OBJ = audio_call.o audio_device.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build audio support
 | 
				
			||||||
 | 
					CHECK_AUDIO_LIBS := $(shell $(PKG_CONFIG) --exists $(AUDIO_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_AUDIO_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(AUDIO_LIBS)
 | 
				
			||||||
 | 
					    LDFLAGS += -lm
 | 
				
			||||||
 | 
					    CFLAGS += $(AUDIO_CFLAGS)
 | 
				
			||||||
 | 
					    OBJ += $(AUDIO_OBJ)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_AUDIO_LIBS := $(shell for lib in $(AUDIO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without audio support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for audio support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_AUDIO_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										66
									
								
								cfg/checks/check_features.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								cfg/checks/check_features.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					CHECKS_DIR = $(CFG_DIR)/checks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build X11 support
 | 
				
			||||||
 | 
					X11 := $(shell if [ -z "$(DISABLE_X11)" ] || [ "$(DISABLE_X11)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(X11), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/x11.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build audio support
 | 
				
			||||||
 | 
					AUDIO := $(shell if [ -z "$(DISABLE_AV)" ] || [ "$(DISABLE_AV)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(AUDIO), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/audio.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build video support
 | 
				
			||||||
 | 
					VIDEO := $(shell if [ -z "$(DISABLE_VI)" ] || [ "$(DISABLE_VI)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(X11), disabled)
 | 
				
			||||||
 | 
					ifneq ($(AUDIO), disabled)
 | 
				
			||||||
 | 
					ifneq ($(VIDEO), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/video.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build sound notifications support
 | 
				
			||||||
 | 
					SND_NOTIFY := $(shell if [ -z "$(DISABLE_SOUND_NOTIFY)" ] || [ "$(DISABLE_SOUND_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(SND_NOTIFY), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/sound_notifications.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build desktop notifications support
 | 
				
			||||||
 | 
					DESK_NOTIFY := $(shell if [ -z "$(DISABLE_DESKTOP_NOTIFY)" ] || [ "$(DISABLE_DESKTOP_NOTIFY)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(DESK_NOTIFY), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/desktop_notifications.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build QR export support
 | 
				
			||||||
 | 
					QR_CODE := $(shell if [ -z "$(DISABLE_QRCODE)" ] || [ "$(DISABLE_QRCODE)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(QR_CODE), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/qr.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build QR exported as PNG support
 | 
				
			||||||
 | 
					QR_PNG := $(shell if [ -z "$(DISABLE_QRPNG)" ] || [ "$(DISABLE_QRPNG)" = "0" ] ; then echo enabled ; else echo disabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(QR_PNG), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/qr_png.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we want build Python scripting support
 | 
				
			||||||
 | 
					PYTHON := $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
 | 
				
			||||||
 | 
					ifneq ($(PYTHON), disabled)
 | 
				
			||||||
 | 
					    -include $(CHECKS_DIR)/python.mk
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build Toxic
 | 
				
			||||||
 | 
					CHECK_LIBS := $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_LIBS), error)
 | 
				
			||||||
 | 
					    CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBS))
 | 
				
			||||||
 | 
					    LDFLAGS += $(shell $(PKG_CONFIG) --libs $(LIBS))
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_LIBS := $(shell for lib in $(LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning ERROR -- Cannot compile Toxic)
 | 
				
			||||||
 | 
					    $(warning ERROR -- You need these libraries)
 | 
				
			||||||
 | 
					    $(warning ERROR -- $(MISSING_LIBS))
 | 
				
			||||||
 | 
					    $(error ERROR)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										15
									
								
								cfg/checks/desktop_notifications.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cfg/checks/desktop_notifications.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					# Variables for desktop notifications support
 | 
				
			||||||
 | 
					DESK_NOTIFY_LIBS = libnotify
 | 
				
			||||||
 | 
					DESK_NOTIFY_CFLAGS = -DBOX_NOTIFY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build desktop notifications support
 | 
				
			||||||
 | 
					CHECK_DESK_NOTIFY_LIBS := $(shell $(PKG_CONFIG) --exists $(DESK_NOTIFY_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_DESK_NOTIFY_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(DESK_NOTIFY_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(DESK_NOTIFY_CFLAGS)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_DESK_NOTIFY_LIBS := $(shell for lib in $(DESK_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without desktop notifications support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for desktop notifications support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_DESK_NOTIFY_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										15
									
								
								cfg/checks/python.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cfg/checks/python.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					# Variables for Python scripting support
 | 
				
			||||||
 | 
					PYTHON3_LIBS = python3
 | 
				
			||||||
 | 
					PYTHON_CFLAGS = -DPYTHON
 | 
				
			||||||
 | 
					PYTHON_OBJ = api.o python_api.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build Python scripting support
 | 
				
			||||||
 | 
					CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_PYTHON3_LIBS), error)
 | 
				
			||||||
 | 
					    LDFLAGS += $(shell python3-config --ldflags)
 | 
				
			||||||
 | 
					    CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
 | 
				
			||||||
 | 
					    OBJ += $(PYTHON_OBJ)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without Python scripting support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need python3 installed for Python scripting support)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										15
									
								
								cfg/checks/qr.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cfg/checks/qr.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					# Variables for QR export support
 | 
				
			||||||
 | 
					QR_LIBS = libqrencode
 | 
				
			||||||
 | 
					QR_CFLAGS = -DQRCODE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build QR export support
 | 
				
			||||||
 | 
					CHECK_QR_LIBS = $(shell pkg-config --exists $(QR_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_QR_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(QR_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(QR_CFLAGS)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_QR_LIBS = $(shell for lib in $(QR_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without QR export support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for QR export support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_QR_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										15
									
								
								cfg/checks/qr_png.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cfg/checks/qr_png.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					# Variables for QR exported as PNG support
 | 
				
			||||||
 | 
					PNG_LIBS = libpng
 | 
				
			||||||
 | 
					PNG_CFLAGS = -DQRPNG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build QR exported as PNG support
 | 
				
			||||||
 | 
					CHECK_PNG_LIBS = $(shell pkg-config --exists $(PNG_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_PNG_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(PNG_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(PNG_CFLAGS)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_PNG_LIBS = $(shell for lib in $(PNG_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without QR exported as PNG support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for QR exported as PNG support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_PNG_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										21
									
								
								cfg/checks/sound_notifications.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								cfg/checks/sound_notifications.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# Variables for sound notifications support
 | 
				
			||||||
 | 
					SND_NOTIFY_LIBS = openal freealut
 | 
				
			||||||
 | 
					SND_NOTIFY_CFLAGS = -DSOUND_NOTIFY
 | 
				
			||||||
 | 
					ifneq (, $(findstring audio_device.o, $(OBJ)))
 | 
				
			||||||
 | 
					    SND_NOTIFY_OBJ =
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    SND_NOTIFY_OBJ = audio_device.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build sound notifications support
 | 
				
			||||||
 | 
					CHECK_SND_NOTIFY_LIBS = $(shell $(PKG_CONFIG) --exists $(SND_NOTIFY_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_SND_NOTIFY_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(SND_NOTIFY_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(SND_NOTIFY_CFLAGS)
 | 
				
			||||||
 | 
					    OBJ += $(SND_NOTIFY_OBJ)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_SND_NOTIFY_LIBS = $(shell for lib in $(SND_NOTIFY_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without sound notifications support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for sound notifications support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_SND_NOTIFY_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										21
									
								
								cfg/checks/video.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								cfg/checks/video.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# Variables for video call support
 | 
				
			||||||
 | 
					VIDEO_LIBS = openal vpx x11
 | 
				
			||||||
 | 
					VIDEO_CFLAGS = -DVIDEO
 | 
				
			||||||
 | 
					ifneq (, $(findstring video_device.o, $(OBJ)))
 | 
				
			||||||
 | 
					    VIDEO_OBJ = video_call.o
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    VIDEO_OBJ = video_call.o video_device.o
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build video support
 | 
				
			||||||
 | 
					CHECK_VIDEO_LIBS = $(shell $(PKG_CONFIG) --exists $(VIDEO_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_VIDEO_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(VIDEO_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(VIDEO_CFLAGS)
 | 
				
			||||||
 | 
					    OBJ += $(VIDEO_OBJ)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_VIDEO_LIBS = $(shell for lib in $(VIDEO_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without video support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- You will need these libraries for video support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_VIDEO_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										17
									
								
								cfg/checks/x11.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cfg/checks/x11.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# Variables for X11 support
 | 
				
			||||||
 | 
					X11_LIBS = x11
 | 
				
			||||||
 | 
					X11_CFLAGS = -DX11
 | 
				
			||||||
 | 
					X11_OBJ = x11focus.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if we can build X11 support
 | 
				
			||||||
 | 
					CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
 | 
				
			||||||
 | 
					ifneq ($(CHECK_X11_LIBS), error)
 | 
				
			||||||
 | 
					    LIBS += $(X11_LIBS)
 | 
				
			||||||
 | 
					    CFLAGS += $(X11_CFLAGS)
 | 
				
			||||||
 | 
					    OBJ += $(X11_OBJ)
 | 
				
			||||||
 | 
					else ifneq ($(MAKECMDGOALS), clean)
 | 
				
			||||||
 | 
					    MISSING_X11_LIBS = $(shell for lib in $(X11_LIBS) ; do if ! $(PKG_CONFIG) --exists $$lib ; then echo $$lib ; fi ; done)
 | 
				
			||||||
 | 
					    $(warning WARNING -- Toxic will be compiled without x11 support (needed for focus tracking and drag&drop support))
 | 
				
			||||||
 | 
					    $(warning WARNING -- You need these libraries for x11 support)
 | 
				
			||||||
 | 
					    $(warning WARNING -- $(MISSING_X11_LIBS))
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										33
									
								
								cfg/global_vars.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								cfg/global_vars.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					# Version
 | 
				
			||||||
 | 
					TOXIC_VERSION = 0.10.0
 | 
				
			||||||
 | 
					REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
 | 
				
			||||||
 | 
					ifneq (, $(findstring error, $(REV)))
 | 
				
			||||||
 | 
					    VERSION = $(TOXIC_VERSION)
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    VERSION = $(TOXIC_VERSION)_r$(REV)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Project directories
 | 
				
			||||||
 | 
					BUILD_DIR = $(BASE_DIR)/build
 | 
				
			||||||
 | 
					DOC_DIR = $(BASE_DIR)/doc
 | 
				
			||||||
 | 
					SRC_DIR = $(BASE_DIR)/src
 | 
				
			||||||
 | 
					SND_DIR = $(BASE_DIR)/sounds
 | 
				
			||||||
 | 
					MISC_DIR = $(BASE_DIR)/misc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Project files
 | 
				
			||||||
 | 
					MANFILES = toxic.1 toxic.conf.5
 | 
				
			||||||
 | 
					DATAFILES = nameservers toxic.conf.example
 | 
				
			||||||
 | 
					DESKFILE = toxic.desktop
 | 
				
			||||||
 | 
					SNDFILES = ToxicContactOnline.wav ToxicContactOffline.wav ToxicError.wav
 | 
				
			||||||
 | 
					SNDFILES += ToxicRecvMessage.wav ToxicOutgoingCall.wav ToxicIncomingCall.wav
 | 
				
			||||||
 | 
					SNDFILES += ToxicTransferComplete.wav ToxicTransferStart.wav
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Install directories
 | 
				
			||||||
 | 
					PREFIX ?= /usr/local
 | 
				
			||||||
 | 
					BINDIR = $(PREFIX)/bin
 | 
				
			||||||
 | 
					DATADIR = $(PREFIX)/share/toxic
 | 
				
			||||||
 | 
					MANDIR ?= $(PREFIX)/share/man
 | 
				
			||||||
 | 
					APPDIR = $(PREFIX)/share/applications
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Platform tools
 | 
				
			||||||
 | 
					PKG_CONFIG = pkg-config
 | 
				
			||||||
							
								
								
									
										4
									
								
								cfg/platforms/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								cfg/platforms/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					# Ignore everything in this directory
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					# Except this file
 | 
				
			||||||
 | 
					!.gitignore
 | 
				
			||||||
							
								
								
									
										18
									
								
								cfg/systems/Darwin.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								cfg/systems/Darwin.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Special options for OS X
 | 
				
			||||||
 | 
					# This assumes the use of Homebrew. Change the paths if using MacPorts or Fink.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PKG_CONFIG_PATH = $(shell export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/opt/libconfig/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LIBS := $(filter-out ncursesw, $(LIBS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# OS X ships a usable, recent version of ncurses, but calls it ncurses not ncursesw.
 | 
				
			||||||
 | 
					LDFLAGS += -lncurses -lalut -ltoxcore -lcurl -lconfig -lqrencode -lpng -lopenal -g
 | 
				
			||||||
 | 
					CFLAGS += -I/usr/local/opt/freealut/include/AL -I/usr/local/opt/glib/include/glib-2.0 -g
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OSX_LIBRARIES = -lobjc -lresolv
 | 
				
			||||||
 | 
					OSX_FRAMEWORKS = -framework Foundation -framework CoreFoundation -framework AVFoundation \
 | 
				
			||||||
 | 
						-framework QuartzCore -framework CoreMedia
 | 
				
			||||||
 | 
					OSX_VIDEO = osx_video.m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LDFLAGS += $(OSX_LIBRARIES) $(OSX_FRAMEWORKS)
 | 
				
			||||||
 | 
					OBJ += osx_video.o
 | 
				
			||||||
							
								
								
									
										10
									
								
								cfg/targets/doc.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								cfg/targets/doc.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					# Doc target
 | 
				
			||||||
 | 
					doc: $(MANFILES:%=$(DOC_DIR)/%)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(DOC_DIR)/%: $(DOC_DIR)/%.asc
 | 
				
			||||||
 | 
						@echo "  MAN   $(@F)"
 | 
				
			||||||
 | 
						@a2x -f manpage -a revdate=$(shell git log -1 --date=short --format="%ad" $<) \
 | 
				
			||||||
 | 
							-a manmanual="Toxic Manual" -a mansource=toxic \
 | 
				
			||||||
 | 
							-a manversion=__VERSION__ -a datadir=__DATADIR__ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: doc
 | 
				
			||||||
							
								
								
									
										37
									
								
								cfg/targets/help.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								cfg/targets/help.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					# Help target
 | 
				
			||||||
 | 
					help:
 | 
				
			||||||
 | 
						@echo "-- Targets --"
 | 
				
			||||||
 | 
						@echo "  all:       Build toxic and documentation [DEFAULT]"
 | 
				
			||||||
 | 
						@echo "  toxic:     Build toxic"
 | 
				
			||||||
 | 
						@echo "  doc:       Build documentation"
 | 
				
			||||||
 | 
						@echo "  install:   Build toxic and install it in PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
 | 
				
			||||||
 | 
						@echo "  uninstall: Remove toxic from PREFIX (default PREFIX is \"$(abspath $(PREFIX))\")"
 | 
				
			||||||
 | 
						@echo "  clean:     Remove built files"
 | 
				
			||||||
 | 
						@echo "  help:      This help"
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						@echo "-- Variables --"
 | 
				
			||||||
 | 
						@echo "  DISABLE_X11:            Set to \"1\" to force building without X11 support"
 | 
				
			||||||
 | 
						@echo "  DISABLE_AV:             Set to \"1\" to force building without audio call support"
 | 
				
			||||||
 | 
						@echo "  DISABLE_SOUND_NOTIFY:   Set to \"1\" to force building without sound notification support"
 | 
				
			||||||
 | 
						@echo "  DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
 | 
				
			||||||
 | 
						@echo "  DISABLE_QRCODE:         Set to \"1\" to force building without QR export support"
 | 
				
			||||||
 | 
						@echo "  DISABLE_QRPNG:          Set to \"1\" to force building without QR exported as PNG support"
 | 
				
			||||||
 | 
						@echo "  ENABLE_PYTHON:          Set to \"1\" to enable building with Python scripting support"
 | 
				
			||||||
 | 
						@echo "  ENABLE_RELEASE:         Set to \"1\" to build without debug symbols and with full compiler optimizations"
 | 
				
			||||||
 | 
						@echo "  ENABLE_ASAN:            Set to \"1\" to build with LLVM address sanitizer enabled.
 | 
				
			||||||
 | 
						@echo "  USER_CFLAGS:            Add custom flags to default CFLAGS"
 | 
				
			||||||
 | 
						@echo "  USER_LDFLAGS:           Add custom flags to default LDFLAGS"
 | 
				
			||||||
 | 
						@echo "  PREFIX:                 Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
 | 
				
			||||||
 | 
						@echo "  DESTDIR:                Specify a directory where to store installed files (mainly for packaging purpose)"
 | 
				
			||||||
 | 
						@echo "  MANDIR:                 Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
 | 
				
			||||||
 | 
						@echo
 | 
				
			||||||
 | 
						@echo "-- Environment Variables --"
 | 
				
			||||||
 | 
						@echo "  CFLAGS:                 Add custom flags to default CFLAGS"
 | 
				
			||||||
 | 
						@echo "  LDFLAGS:                Add custom flags to default LDFLAGS"
 | 
				
			||||||
 | 
						@echo "  USER_CFLAGS:            Add custom flags to default CFLAGS"
 | 
				
			||||||
 | 
						@echo "  USER_LDFLAGS:           Add custom flags to default LDFLAGS"
 | 
				
			||||||
 | 
						@echo "  PREFIX:                 Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
 | 
				
			||||||
 | 
						@echo "  DESTDIR:                Specify a directory where to store installed files (mainly for packaging purpose)"
 | 
				
			||||||
 | 
						@echo "  MANDIR:                 Specify a directory where to store man pages (default is \"$(abspath $(PREFIX)/share/man)\")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: help
 | 
				
			||||||
							
								
								
									
										41
									
								
								cfg/targets/install.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								cfg/targets/install.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					# Install target
 | 
				
			||||||
 | 
					install: $(BUILD_DIR)/toxic
 | 
				
			||||||
 | 
						@echo "Installing toxic executable"
 | 
				
			||||||
 | 
						@mkdir -p $(abspath $(DESTDIR)/$(BINDIR))
 | 
				
			||||||
 | 
						@install -m 0755 $(BUILD_DIR)/toxic $(abspath $(DESTDIR)/$(BINDIR)/toxic)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Installing desktop file"
 | 
				
			||||||
 | 
						@mkdir -p $(abspath $(DESTDIR)/$(APPDIR))
 | 
				
			||||||
 | 
						@install -m 0644 $(MISC_DIR)/$(DESKFILE) $(abspath $(DESTDIR)/$(APPDIR)/$(DESKFILE))
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Installing data files"
 | 
				
			||||||
 | 
						@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))
 | 
				
			||||||
 | 
						@for f in $(DATAFILES) ; do \
 | 
				
			||||||
 | 
							install -m 0644 $(MISC_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
 | 
				
			||||||
 | 
							file=$(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
 | 
				
			||||||
 | 
							sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
 | 
				
			||||||
 | 
							mv temp_file $$file ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
						@mkdir -p $(abspath $(DESTDIR)/$(DATADIR))/sounds
 | 
				
			||||||
 | 
						@for f in $(SNDFILES) ; do \
 | 
				
			||||||
 | 
							install -m 0644 $(SND_DIR)/$$f $(abspath $(DESTDIR)/$(DATADIR)/sounds/$$f) ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Installing man pages"
 | 
				
			||||||
 | 
						@mkdir -p $(abspath $(DESTDIR)/$(MANDIR))
 | 
				
			||||||
 | 
						@for f in $(MANFILES) ; do \
 | 
				
			||||||
 | 
							if [ ! -e "$(DOC_DIR)/$$f" ]; then \
 | 
				
			||||||
 | 
								continue ;\
 | 
				
			||||||
 | 
							fi ;\
 | 
				
			||||||
 | 
							section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
 | 
				
			||||||
 | 
							file=$$section/$$f ;\
 | 
				
			||||||
 | 
							mkdir -p $$section ;\
 | 
				
			||||||
 | 
							install -m 0644 $(DOC_DIR)/$$f $$file ;\
 | 
				
			||||||
 | 
							sed -e 's:__VERSION__:'$(VERSION)':g' $$file > temp_file && \
 | 
				
			||||||
 | 
							mv temp_file $$file ;\
 | 
				
			||||||
 | 
							sed -e 's:__DATADIR__:'$(abspath $(DATADIR))':g' $$file > temp_file && \
 | 
				
			||||||
 | 
							mv temp_file $$file ;\
 | 
				
			||||||
 | 
							gzip -f -n -9 $$file ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: install
 | 
				
			||||||
							
								
								
									
										24
									
								
								cfg/targets/uninstall.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								cfg/targets/uninstall.mk
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					# Uninstall target
 | 
				
			||||||
 | 
					uninstall:
 | 
				
			||||||
 | 
						@echo "Removing toxic executable"
 | 
				
			||||||
 | 
						@rm -f $(abspath $(DESTDIR)/$(BINDIR)/toxic)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Removing desktop file"
 | 
				
			||||||
 | 
						@rm -f $(abspath $(DESTDIR)/$(APPDIR)/$(DESKFILE))
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Removing data files"
 | 
				
			||||||
 | 
						@for f in $(DATAFILES) ; do \
 | 
				
			||||||
 | 
							rm -f $(abspath $(DESTDIR)/$(DATADIR)/$$f) ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
						@for f in $(SNDFILES) ; do \
 | 
				
			||||||
 | 
							rm -f $(abspath $(DESTDIR)/$(DATADIR)/sounds/$$f) ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@echo "Removing man pages"
 | 
				
			||||||
 | 
						@for f in $(MANFILES) ; do \
 | 
				
			||||||
 | 
							section=$(abspath $(DESTDIR)/$(MANDIR))/man`echo $${f##*.}` ;\
 | 
				
			||||||
 | 
							file=$$section/$$f ;\
 | 
				
			||||||
 | 
							rm -f $$file $$file.gz ;\
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: uninstall
 | 
				
			||||||
							
								
								
									
										473
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										473
									
								
								configure.ac
									
									
									
									
									
								
							@@ -1,473 +0,0 @@
 | 
				
			|||||||
#                                               -*- Autoconf -*-
 | 
					 | 
				
			||||||
# Process this file with autoconf to produce a configure script.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_PREREQ([2.65])
 | 
					 | 
				
			||||||
AC_INIT([toxic], [0.3.0], [https://tox.im/])
 | 
					 | 
				
			||||||
AC_CONFIG_AUX_DIR(configure_aux)
 | 
					 | 
				
			||||||
AC_CONFIG_SRCDIR([src/main.c])
 | 
					 | 
				
			||||||
AC_CONFIG_HEADERS([config.h])
 | 
					 | 
				
			||||||
AM_INIT_AUTOMAKE([1.10 -Wall])
 | 
					 | 
				
			||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
					 | 
				
			||||||
AC_CONFIG_MACRO_DIR([m4])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x${prefix}" = "xNONE"; then
 | 
					 | 
				
			||||||
    prefix="${ac_default_prefix}"
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEPSEARCH=
 | 
					 | 
				
			||||||
LIBTOXCORE_SEARCH_HEADERS=
 | 
					 | 
				
			||||||
LIBTOXCORE_SEARCH_LIBS=
 | 
					 | 
				
			||||||
LIBSODIUM_SEARCH_HEADERS=
 | 
					 | 
				
			||||||
LIBSODIUM_SEARCH_LIBS=
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LIBTOXCORE_FOUND="no"
 | 
					 | 
				
			||||||
NCURSES_FOUND="no"
 | 
					 | 
				
			||||||
NCURSES_WIDECHAR_SUPPORT="no"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(dependency-search,
 | 
					 | 
				
			||||||
    AC_HELP_STRING([--with-dependency-search=DIR],
 | 
					 | 
				
			||||||
                   [search for dependencies in DIR, i.e. look for libraries in
 | 
					 | 
				
			||||||
                    DIR/lib and for headers in DIR/include]),
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        DEPSEARCH="$withval"
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test -n "$DEPSEARCH"; then
 | 
					 | 
				
			||||||
    CFLAGS="$CFLAGS -I$DEPSEARCH/include"
 | 
					 | 
				
			||||||
    CPPFLAGS="$CPPFLAGS -I$DEPSEARCH/include"
 | 
					 | 
				
			||||||
    LDFLAGS="$LDFLAGS -L$DEPSEARCH/lib"
 | 
					 | 
				
			||||||
    export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(libtoxcore-headers,
 | 
					 | 
				
			||||||
        AC_HELP_STRING([--with-libtoxcore-headers=DIR],
 | 
					 | 
				
			||||||
                       [search for libtoxcore header files in DIR/tox]),
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            LIBTOXCORE_SEARCH_HEADERS="$withval"
 | 
					 | 
				
			||||||
            AC_MSG_NOTICE([Will search for libtoxcore header files in $withval])
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(libtoxcore-libs,
 | 
					 | 
				
			||||||
        AC_HELP_STRING([--with-libtoxcore-libs=DIR],
 | 
					 | 
				
			||||||
                       [search for libtoxcore libraries in DIR]),
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            LIBTOXCORE_SEARCH_LIBS="$withval"
 | 
					 | 
				
			||||||
            AC_MSG_NOTICE([Will search for libtoxcore libraries in $withval])
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(libsodium-headers,
 | 
					 | 
				
			||||||
        AC_HELP_STRING([--with-libsodium-headers=DIR],
 | 
					 | 
				
			||||||
                       [search for libsodium header files in DIR]),
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            LIBSODIUM_SEARCH_HEADERS="$withval"
 | 
					 | 
				
			||||||
            AC_MSG_NOTICE([Will search for libsodium header files in $withval])
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(libsodium-libs,
 | 
					 | 
				
			||||||
        AC_HELP_STRING([--with-libsodium-libs=DIR],
 | 
					 | 
				
			||||||
                       [search for libsodium libraries in DIR]),
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            LIBSODIUM_SEARCH_LIBS="$withval"
 | 
					 | 
				
			||||||
            AC_MSG_NOTICE([Will search for libsodium libraries in $withval])
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WIN32=no
 | 
					 | 
				
			||||||
AC_CANONICAL_HOST
 | 
					 | 
				
			||||||
case $host_os in
 | 
					 | 
				
			||||||
    *mingw*)
 | 
					 | 
				
			||||||
        WIN32="yes"
 | 
					 | 
				
			||||||
    ;;
 | 
					 | 
				
			||||||
    *freebsd*)
 | 
					 | 
				
			||||||
        LDFLAGS="$LDFLAGS -L/usr/local/lib"
 | 
					 | 
				
			||||||
        CFLAGS="$CFLAGS -I/usr/local/include"
 | 
					 | 
				
			||||||
        CPPFLAGS="$CPPFLAGS -I/usr/local/include"
 | 
					 | 
				
			||||||
    ;;
 | 
					 | 
				
			||||||
esac
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Checks for programs.
 | 
					 | 
				
			||||||
AC_PROG_CC
 | 
					 | 
				
			||||||
AM_PROG_CC_C_O
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_CHECK_HEADERS(
 | 
					 | 
				
			||||||
    [limits.h locale.h stdint.h stdlib.h string.h unistd.h wchar.h wctype.h],
 | 
					 | 
				
			||||||
    [],
 | 
					 | 
				
			||||||
    [ AC_MSG_ERROR([required header is missing on your system]) ])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Checks for typedefs, structures, and compiler characteristics.
 | 
					 | 
				
			||||||
AC_HEADER_STDBOOL
 | 
					 | 
				
			||||||
AC_TYPE_SIZE_T
 | 
					 | 
				
			||||||
AC_TYPE_UINT16_T
 | 
					 | 
				
			||||||
AC_TYPE_UINT32_T
 | 
					 | 
				
			||||||
AC_TYPE_UINT64_T
 | 
					 | 
				
			||||||
AC_TYPE_UINT8_T
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Checks for library functions.
 | 
					 | 
				
			||||||
AC_FUNC_MALLOC
 | 
					 | 
				
			||||||
AC_CHECK_FUNCS(
 | 
					 | 
				
			||||||
    [iswprint memmove memset mkdir setlocale strchr strdup],
 | 
					 | 
				
			||||||
    [],
 | 
					 | 
				
			||||||
    [ AC_MSG_ERROR([required library function is missing on your system])])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# pkg-config based tests
 | 
					 | 
				
			||||||
PKG_PROG_PKG_CONFIG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test -n "$PKG_CONFIG"; then
 | 
					 | 
				
			||||||
    if test "x$WIN32" != "xyes"; then
 | 
					 | 
				
			||||||
        PKG_CHECK_MODULES([NCURSES], [ncursesw],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
                NCURSES_WIDECHAR_SUPPORT="yes"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                NCURSES_WIDECHAR_SUPPORT="no"
 | 
					 | 
				
			||||||
                PKG_CHECK_MODULES([NCURSES], [ncurses],
 | 
					 | 
				
			||||||
                    [
 | 
					 | 
				
			||||||
                        NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                    [
 | 
					 | 
				
			||||||
                        AC_MSG_WARN([$NCURSES_PKG_ERRORS])
 | 
					 | 
				
			||||||
                    ])
 | 
					 | 
				
			||||||
            ])
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
    AC_MSG_WARN([pkg-config was not found on your sytem])
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
 | 
					 | 
				
			||||||
    AC_PATH_PROG([CURSES_CONFIG], [ncursesw5-config], [no])
 | 
					 | 
				
			||||||
    if test "x$CURSES_CONFIG" != "xno"; then
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses cflags)
 | 
					 | 
				
			||||||
        NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses libraries)
 | 
					 | 
				
			||||||
        NCURSES_LIBS=`${CURSES_CONFIG} --libs`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_LIBS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_LIBS)
 | 
					 | 
				
			||||||
        NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
        NCURSES_WIDECHAR_SUPPORT="yes"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
 | 
					 | 
				
			||||||
    unset ac_cv_path_CURSES_CONFIG
 | 
					 | 
				
			||||||
    AC_PATH_PROG([CURSES_CONFIG], [ncursesw5.4-config], [no])
 | 
					 | 
				
			||||||
    if test "x$CURSES_CONFIG" != "xno"; then
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses cflags)
 | 
					 | 
				
			||||||
        NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses libraries)
 | 
					 | 
				
			||||||
        NCURSES_LIBS=`${CURSES_CONFIG} --libs`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_LIBS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_LIBS)
 | 
					 | 
				
			||||||
        NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
        NCURSES_WIDECHAR_SUPPORT="yes"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
 | 
					 | 
				
			||||||
    unset ac_cv_path_CURSES_CONFIG
 | 
					 | 
				
			||||||
    AC_PATH_PROG([CURSES_CONFIG], [ncurses5-config], [no])
 | 
					 | 
				
			||||||
    if test "x$CURSES_CONFIG" != "xno"; then
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses cflags)
 | 
					 | 
				
			||||||
        NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses libraries)
 | 
					 | 
				
			||||||
        NCURSES_LIBS=`${CURSES_CONFIG} --libs`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_LIBS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_LIBS)
 | 
					 | 
				
			||||||
        NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (test "x$NCURSES_FOUND" = "xno") && (test "x$WIN32" != "xyes"); then
 | 
					 | 
				
			||||||
    unset ac_cv_path_CURSES_CONFIG
 | 
					 | 
				
			||||||
    AC_PATH_PROG([CURSES_CONFIG], [ncurses5.4-config], [no])
 | 
					 | 
				
			||||||
    if test "x$CURSES_CONFIG" != "xno"; then
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses cflags)
 | 
					 | 
				
			||||||
        NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_MSG_CHECKING(ncurses libraries)
 | 
					 | 
				
			||||||
        NCURSES_LIBS=`${CURSES_CONFIG} --libs`
 | 
					 | 
				
			||||||
        AC_MSG_RESULT($NCURSES_LIBS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_CFLAGS)
 | 
					 | 
				
			||||||
        AC_SUBST(NCURSES_LIBS)
 | 
					 | 
				
			||||||
        NCURSES_FOUND="yes"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x$NCURSES_FOUND" = "xno"; then
 | 
					 | 
				
			||||||
    AC_CHECK_HEADER([curses.h],
 | 
					 | 
				
			||||||
        [],
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            AC_MSG_ERROR([headers for the ncurses library were not found on your system])
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if test "x$WIN32" = "xyes"; then
 | 
					 | 
				
			||||||
        dnl Check if pdcurses provides wide char support
 | 
					 | 
				
			||||||
        NCURSES_WIDECHAR_SUPPORT="no"
 | 
					 | 
				
			||||||
        AC_CHECK_LIB([pdcurses], [clear],
 | 
					 | 
				
			||||||
            [],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library pdcurses was not found on your system])
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        AC_CHECK_LIB(ws2_32, main,
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                WINSOCK2_LIBS="-lws2_32"
 | 
					 | 
				
			||||||
                AC_SUBST(WINSOCK2_LIBS)
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library winsock2 was not found on the system, please check your MinGW installation])
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        AC_DEFINE([_WIN32_WINNT], [0x501],
 | 
					 | 
				
			||||||
                  [enable getaddrinfo/freeaddrinfo on XP and higher])
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        AC_CHECK_LIB([ncursesw], [wget_wch],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                NCURSES_WIDECHAR_SUPPORT="yes"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                unset ac_cv_lib_ncursesw_wget_wch
 | 
					 | 
				
			||||||
                AC_CHECK_LIB([ncursesw], [wget_wch],
 | 
					 | 
				
			||||||
                    [
 | 
					 | 
				
			||||||
                        NCURSES_WIDECHAR_SUPPORT="yes"
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                    [
 | 
					 | 
				
			||||||
                        NCURSES_WIDECHAR_SUPPORT="no"
 | 
					 | 
				
			||||||
                        AC_CHECK_LIB([ncurses], [clear],
 | 
					 | 
				
			||||||
                            [],
 | 
					 | 
				
			||||||
                            [
 | 
					 | 
				
			||||||
                                unset ac_cv_lib_ncurses_clear
 | 
					 | 
				
			||||||
                                AC_CHECK_LIB([ncurses], [clear],
 | 
					 | 
				
			||||||
                                    [],
 | 
					 | 
				
			||||||
                                    [
 | 
					 | 
				
			||||||
                                        AC_MSG_ERROR([required library ncurses was not found on your system])
 | 
					 | 
				
			||||||
                                    ],
 | 
					 | 
				
			||||||
                                    [
 | 
					 | 
				
			||||||
                                        -ltinfo
 | 
					 | 
				
			||||||
                                    ]
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                            ]
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                    [
 | 
					 | 
				
			||||||
                        -ltinfo
 | 
					 | 
				
			||||||
                    ]
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test -n "$PKG_CONFIG"; then
 | 
					 | 
				
			||||||
    PKG_CHECK_MODULES(LIBTOXCORE, [libtoxcore],
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            LIBTOXCORE_FOUND="yes"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            AC_MSG_WARN([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
 | 
					 | 
				
			||||||
        ])
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x$LIBTOXCORE_FOUND" = "xno"; then
 | 
					 | 
				
			||||||
    LIBSODIUM_LIBS=
 | 
					 | 
				
			||||||
    LIBSODIUM_LDFLAGS=
 | 
					 | 
				
			||||||
    LDFLAGS_SAVE="$LDFLAGS"
 | 
					 | 
				
			||||||
    if test -n "$LIBSODIUM_SEARCH_LIBS"; then
 | 
					 | 
				
			||||||
        LDFLAGS="$LDFLAGS -L$LIBSODIUM_SEARCH_LIBS"
 | 
					 | 
				
			||||||
        AC_CHECK_LIB(sodium, randombytes_random,
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                LIBSODIUM_LDFLAGS="-L$LIBSODIUM_SEARCH_LIBS"
 | 
					 | 
				
			||||||
                LIBSODIUM_LIBS="-lsodium"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS])
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        AC_CHECK_LIB(sodium, randombytes_random,
 | 
					 | 
				
			||||||
            [],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LDFLAGS="$LDFLAGS_SAVE"
 | 
					 | 
				
			||||||
    AC_SUBST(LIBSODIUM_LIBS)
 | 
					 | 
				
			||||||
    AC_SUBST(LIBSODIUM_LDFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LIBTOXCORE_CFLAGS=
 | 
					 | 
				
			||||||
    CFLAGS_SAVE="$CFLAGS"
 | 
					 | 
				
			||||||
    CPPFLAGS_SAVE="$CPPFLAGS"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if test -n "$LIBTOXCORE_SEARCH_HEADERS"; then
 | 
					 | 
				
			||||||
        CFLAGS="$CFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
 | 
					 | 
				
			||||||
        CPPFLAGS="$CPPFLAGS -I$LIBTOXCORE_SEARCH_HEADERS"
 | 
					 | 
				
			||||||
        AC_CHECK_HEADER([tox/tox.h],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                LIBTOXCORE_CFLAGS="-I$LIBTOXCORE_SEARCH_HEADERS"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([headers for the toxcore library were not found on your system])
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        AC_CHECK_HEADER([tox/tox.h],
 | 
					 | 
				
			||||||
            [],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([headers for the toxcore library were not found on your system])
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    CFLAGS="$CFLAGS_SAVE"
 | 
					 | 
				
			||||||
    CPPFLAGS="$CPPFLAGS_SAVE"
 | 
					 | 
				
			||||||
    AC_SUBST(LIBTOXCORE_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    LIBTOXCORE_LIBS=
 | 
					 | 
				
			||||||
    LIBTOXCORE_LDFLAGS=
 | 
					 | 
				
			||||||
    LDFLAGS_SAVE="$LDFLAGS"
 | 
					 | 
				
			||||||
    if test -n "$LIBTOXCORE_SEARCH_LIBS"; then
 | 
					 | 
				
			||||||
        LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS -L$LIBTOXCORE_SEARCH_LIBS"
 | 
					 | 
				
			||||||
        AC_CHECK_LIB([toxcore], [tox_new],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                LIBTOXCORE_LDFLAGS="-L$LIBTOXCORE_SEARCH_LIBS"
 | 
					 | 
				
			||||||
                LIBTOXCORE_LIBS="-ltoxcore"
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library toxcore was not found on your system])
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                $WINSOCK2_LIBS
 | 
					 | 
				
			||||||
                $LIBSODIUM_LIBS
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        LDFLAGS="$LDFLAGS $LIBSODIUM_LDFLAGS"
 | 
					 | 
				
			||||||
        AC_CHECK_LIB([toxcore], [tox_new],
 | 
					 | 
				
			||||||
            [],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_ERROR([required library toxcore was not found on your system])
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                $WINSOCK2_LIBS
 | 
					 | 
				
			||||||
                $LIBSODIUM_LIBS
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
    LDFLAGS="$LDFLAGS_SAVE"
 | 
					 | 
				
			||||||
    AC_SUBST(LIBTOXCORE_LIBS)
 | 
					 | 
				
			||||||
    AC_SUBST(LIBTOXCORE_LDFLAGS)
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
####
 | 
					 | 
				
			||||||
#### A/V Stuff
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AV_SEARCH_DIR=
 | 
					 | 
				
			||||||
BUILD_AV="yes"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AC_ARG_WITH(libtoxav-prefix,
 | 
					 | 
				
			||||||
    AC_HELP_STRING([--with-libtoxav-prefix=DIR],
 | 
					 | 
				
			||||||
                   [search for libtoxav in DIR, i.e. look for libraries in
 | 
					 | 
				
			||||||
                    DIR/lib and for headers in DIR/include]),
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        AV_SEARCH_DIR="$withval"
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test -n "$AV_SEARCH_DIR"; then
 | 
					 | 
				
			||||||
    CFLAGS="$CFLAGS -I$AV_SEARCH_DIR/include"
 | 
					 | 
				
			||||||
    CPPFLAGS="$CPPFLAGS -I$AV_SEARCH_DIR/include"
 | 
					 | 
				
			||||||
    LDFLAGS="$LDFLAGS -L$AV_SEARCH_DIR/lib"
 | 
					 | 
				
			||||||
    export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$AV_SEARCH_DIR/lib/pkgconfig
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Check if specified enable
 | 
					 | 
				
			||||||
AC_ARG_ENABLE([av],
 | 
					 | 
				
			||||||
    [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        if test "x$enableval" = "xno"; then
 | 
					 | 
				
			||||||
            BUILD_AV="no"
 | 
					 | 
				
			||||||
        elif test "x$enableval" = "xyes"; then
 | 
					 | 
				
			||||||
            BUILD_AV="yes"
 | 
					 | 
				
			||||||
        fi
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Check for A/V library
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x$BUILD_AV" = "xyes"; then
 | 
					 | 
				
			||||||
    PKG_CHECK_MODULES([OPENAL], [openal],
 | 
					 | 
				
			||||||
    [        
 | 
					 | 
				
			||||||
        export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PKG_CHECK_MODULES([LIBTOXAV], [libtoxav], 
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            AC_CHECK_HEADER([tox/toxav.h],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                # Place define for audio support
 | 
					 | 
				
			||||||
                AC_DEFINE([_SUPPORT_AUDIO], [], [Is audio supported])
 | 
					 | 
				
			||||||
                AC_MSG_NOTICE([Building with audio support])
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                AC_MSG_NOTICE([No A/V headers; disabling A/V support])
 | 
					 | 
				
			||||||
                BUILD_AV="no"
 | 
					 | 
				
			||||||
            ],)
 | 
					 | 
				
			||||||
        ], 
 | 
					 | 
				
			||||||
        [
 | 
					 | 
				
			||||||
            AC_MSG_NOTICE([No A/V library; disabling A/V support])
 | 
					 | 
				
			||||||
        ])
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    [
 | 
					 | 
				
			||||||
        AC_MSG_NOTICE([No openal library; disabling A/V support])
 | 
					 | 
				
			||||||
    ])
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AM_CONDITIONAL(BUILD_AV, test "x$BUILD_AV" = "xyes")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TOXIC_VERSION="$PACKAGE_VERSION"
 | 
					 | 
				
			||||||
AC_PATH_PROG([GIT], [git], [no])
 | 
					 | 
				
			||||||
if test "x$GIT" != "xno"; then
 | 
					 | 
				
			||||||
    if test -d ${srcdir}/.git; then
 | 
					 | 
				
			||||||
        TOXIC_VERSION="${TOXIC_VERSION}_r`${GIT} rev-list HEAD --count`"
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
AC_SUBST(TOXIC_VERSION)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
eval PACKAGE_DATADIR="${datadir}/${PACKAGE}"
 | 
					 | 
				
			||||||
eval PACKAGE_DATADIR="${PACKAGE_DATADIR}"
 | 
					 | 
				
			||||||
AC_DEFINE_UNQUOTED(PACKAGE_DATADIR, "$PACKAGE_DATADIR", [toxic data directory])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x$NCURSES_WIDECHAR_SUPPORT" = "xyes"; then
 | 
					 | 
				
			||||||
    AC_DEFINE([HAVE_WIDECHAR], [1], [ncurses wide char support available])
 | 
					 | 
				
			||||||
    AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1],
 | 
					 | 
				
			||||||
              [enable X/Open Portability Guide functionality])
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
AC_CONFIG_FILES([Makefile
 | 
					 | 
				
			||||||
                 misc/Makefile
 | 
					 | 
				
			||||||
                 build/Makefile])
 | 
					 | 
				
			||||||
AC_OUTPUT
 | 
					 | 
				
			||||||
							
								
								
									
										169
									
								
								doc/toxic.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								doc/toxic.1
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					'\" t
 | 
				
			||||||
 | 
					.\"     Title: toxic
 | 
				
			||||||
 | 
					.\"    Author: [see the "AUTHORS" section]
 | 
				
			||||||
 | 
					.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
 | 
				
			||||||
 | 
					.\"      Date: 2020-05-04
 | 
				
			||||||
 | 
					.\"    Manual: Toxic Manual
 | 
				
			||||||
 | 
					.\"    Source: toxic __VERSION__
 | 
				
			||||||
 | 
					.\"  Language: English
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.TH "TOXIC" "1" "2020\-05\-04" "toxic __VERSION__" "Toxic Manual"
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * Define some portability stuff
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					.\" http://bugs.debian.org/507673
 | 
				
			||||||
 | 
					.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
 | 
				
			||||||
 | 
					.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					.ie \n(.g .ds Aq \(aq
 | 
				
			||||||
 | 
					.el       .ds Aq '
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * set default formatting
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" disable hyphenation
 | 
				
			||||||
 | 
					.nh
 | 
				
			||||||
 | 
					.\" disable justification (adjust text to left margin only)
 | 
				
			||||||
 | 
					.ad l
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * MAIN CONTENT STARTS HERE *
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.SH "NAME"
 | 
				
			||||||
 | 
					toxic \- CLI client for Tox
 | 
				
			||||||
 | 
					.SH "SYNOPSIS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\fBtoxic\fR [\-f \fIdata\-file\fR] [\-x] [\-4] [\-c \fIconfig\-file\fR] [\-n \fInodes\-file\fR] [\-h]
 | 
				
			||||||
 | 
					.SH "DESCRIPTION"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					toxic is an ncurses\-based instant messaging client for Tox which formerly resided in the Tox core repository, and is now available as a standalone application\&.
 | 
				
			||||||
 | 
					.SH "OPTIONS"
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-4, \-\-ipv4
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Force IPv4 connection
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-b, \-\-debug
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable stderr for debugging\&. Redirect output to avoid breaking the curses interface and better capture messages\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-c, \-\-config config\-file
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use specified
 | 
				
			||||||
 | 
					\fIconfig\-file\fR
 | 
				
			||||||
 | 
					instead of
 | 
				
			||||||
 | 
					\fI~/\&.config/tox/toxic\&.conf\fR
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-d, \-\-default\-locale
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use default locale
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-e, \-\-encrypt\-data
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Encrypt an unencrypted data file\&. An error will occur if this option is used with an encrypted data file\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-f, \-\-file data\-file
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use specified
 | 
				
			||||||
 | 
					\fIdata\-file\fR
 | 
				
			||||||
 | 
					instead of
 | 
				
			||||||
 | 
					\fI~/\&.config/tox/toxic_profile\&.tox\fR
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-h, \-\-help
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Show help message
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-l, \-\-logging
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable toxcore logging to stderr
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-n, \-\-nodes nodes\-file
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use specified
 | 
				
			||||||
 | 
					\fInodes\-file\fR
 | 
				
			||||||
 | 
					for DHT bootstrap nodes instead of
 | 
				
			||||||
 | 
					\fI~/\&.config/tox/DHTnodes\&.json\fR
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-o, \-\-noconnect
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Do not connect to the DHT network
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-p, \-\-SOCKS5\-proxy
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use a SOCKS5 proxy: Requires [IP] [port]
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-P, \-\-HTTP\-proxy
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use a HTTP proxy: Requires [IP] [port]
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-r, \-\-namelist
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Use specified nameservers list
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-t, \-\-force\-tcp
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Force TCP connection (use this with proxies)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-T, \-\-tcp\-relay
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Act as a TCP relay server for the network (Note: this uses significantly more bandwidth)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\-u, \-\-unencrypt\-data
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Unencrypt a data file\&. A warning will appear if this option is used with a data file that is already unencrypted\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.SH "FILES"
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					~/\&.config/tox/DHTnodes\&.json
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Default location for list of DHT bootstrap nodes (list obtained from
 | 
				
			||||||
 | 
					https://nodes\&.tox\&.chat)\&. This list is automatically updated\&. See
 | 
				
			||||||
 | 
					\fBtoxic\&.conf\fR(5) for details on controlling the update frequency\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					~/\&.config/tox/toxic_profile\&.tox
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Savestate which contains your personal info (nickname, Tox ID, contacts, etc)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					~/\&.config/tox/toxic\&.conf
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration file\&. See
 | 
				
			||||||
 | 
					\fBtoxic\&.conf\fR(5) for more details\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					__DATADIR__/toxic\&.conf\&.example
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration example\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.SH "BUGS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\-Unicode characters with a width larger than 1 column may cause strange behaviour\&.
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\-Text occasionally fails to auto\-scroll to the bottom\&.
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\-Screen flickering sometimes occurs on certain terminals\&.
 | 
				
			||||||
 | 
					.SH "AUTHORS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					JFreegman <JFreegman@gmail\&.com>
 | 
				
			||||||
 | 
					.SH "SEE ALSO"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\fBtoxic\&.conf\fR(5)
 | 
				
			||||||
 | 
					.SH "LINKS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					Project page: https://github\&.com/JFreegman/toxic
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					IRC channel: chat\&.freenode\&.net#tox
 | 
				
			||||||
							
								
								
									
										108
									
								
								doc/toxic.1.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								doc/toxic.1.asc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					toxic(1)
 | 
				
			||||||
 | 
					========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NAME
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					toxic - CLI client for Tox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYNOPSIS
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					*toxic* [-f 'data-file'] [-x] [-4] [-c 'config-file'] [-n 'nodes-file'] [-h]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DESCRIPTION
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					toxic is an ncurses-based instant messaging client for Tox which formerly
 | 
				
			||||||
 | 
					resided in the Tox core repository, and is now available as a standalone
 | 
				
			||||||
 | 
					application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OPTIONS
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					-4, --ipv4::
 | 
				
			||||||
 | 
					    Force IPv4 connection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-b, --debug::
 | 
				
			||||||
 | 
					    Enable stderr for debugging. Redirect output to
 | 
				
			||||||
 | 
					    avoid breaking the curses interface and better capture messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-c, --config config-file::
 | 
				
			||||||
 | 
					    Use specified 'config-file' instead of '~/.config/tox/toxic.conf'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-d, --default-locale::
 | 
				
			||||||
 | 
					    Use default locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-e, --encrypt-data::
 | 
				
			||||||
 | 
					    Encrypt an unencrypted data file. An error will occur if this option
 | 
				
			||||||
 | 
					    is used with an encrypted data file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-f, --file data-file::
 | 
				
			||||||
 | 
					    Use specified 'data-file' instead of '~/.config/tox/toxic_profile.tox'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-h, --help::
 | 
				
			||||||
 | 
					    Show help message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-l, --logging::
 | 
				
			||||||
 | 
					    Enable toxcore logging to stderr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-n, --nodes nodes-file::
 | 
				
			||||||
 | 
					    Use specified 'nodes-file' for DHT bootstrap nodes instead of '~/.config/tox/DHTnodes.json'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-o, --noconnect::
 | 
				
			||||||
 | 
					    Do not connect to the DHT network
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-p, --SOCKS5-proxy::
 | 
				
			||||||
 | 
					    Use a SOCKS5 proxy: Requires [IP] [port]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-P, --HTTP-proxy::
 | 
				
			||||||
 | 
					    Use a HTTP proxy: Requires [IP] [port]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-r, --namelist::
 | 
				
			||||||
 | 
					    Use specified nameservers list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-t, --force-tcp::
 | 
				
			||||||
 | 
					    Force TCP connection (use this with proxies)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-T, --tcp-relay::
 | 
				
			||||||
 | 
					    Act as a TCP relay server for the network (Note: this uses significantly more bandwidth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-u, --unencrypt-data::
 | 
				
			||||||
 | 
					    Unencrypt a data file. A warning will appear if this option is used
 | 
				
			||||||
 | 
					    with a data file that is already unencrypted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FILES
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					~/.config/tox/DHTnodes.json::
 | 
				
			||||||
 | 
					    Default location for list of DHT bootstrap nodes (list obtained from https://nodes.tox.chat).
 | 
				
			||||||
 | 
					    This list is automatically updated. See *toxic.conf*(5) for details on controlling the update frequency.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					~/.config/tox/toxic_profile.tox::
 | 
				
			||||||
 | 
					    Savestate which contains your personal info (nickname, Tox ID, contacts,
 | 
				
			||||||
 | 
					    etc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					~/.config/tox/toxic.conf::
 | 
				
			||||||
 | 
					    Configuration file. See *toxic.conf*(5) for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{datadir}/toxic.conf.example::
 | 
				
			||||||
 | 
					    Configuration example.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUGS
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					-Unicode characters with a width larger than 1 column may cause strange
 | 
				
			||||||
 | 
					behaviour.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-Text occasionally fails to auto-scroll to the bottom.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-Screen flickering sometimes occurs on certain terminals.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTHORS
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					JFreegman <JFreegman@gmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SEE ALSO
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					*toxic.conf*(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LINKS
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					Project page: <https://github.com/JFreegman/toxic>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IRC channel: chat.freenode.net#tox
 | 
				
			||||||
							
								
								
									
										420
									
								
								doc/toxic.conf.5
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								doc/toxic.conf.5
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,420 @@
 | 
				
			|||||||
 | 
					'\" t
 | 
				
			||||||
 | 
					.\"     Title: toxic.conf
 | 
				
			||||||
 | 
					.\"    Author: [see the "AUTHORS" section]
 | 
				
			||||||
 | 
					.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
 | 
				
			||||||
 | 
					.\"      Date: 2020-11-18
 | 
				
			||||||
 | 
					.\"    Manual: Toxic Manual
 | 
				
			||||||
 | 
					.\"    Source: toxic __VERSION__
 | 
				
			||||||
 | 
					.\"  Language: English
 | 
				
			||||||
 | 
					.\"
 | 
				
			||||||
 | 
					.TH "TOXIC\&.CONF" "5" "2020\-11\-18" "toxic __VERSION__" "Toxic Manual"
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * Define some portability stuff
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					.\" http://bugs.debian.org/507673
 | 
				
			||||||
 | 
					.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
 | 
				
			||||||
 | 
					.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					.ie \n(.g .ds Aq \(aq
 | 
				
			||||||
 | 
					.el       .ds Aq '
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * set default formatting
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" disable hyphenation
 | 
				
			||||||
 | 
					.nh
 | 
				
			||||||
 | 
					.\" disable justification (adjust text to left margin only)
 | 
				
			||||||
 | 
					.ad l
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.\" * MAIN CONTENT STARTS HERE *
 | 
				
			||||||
 | 
					.\" -----------------------------------------------------------------
 | 
				
			||||||
 | 
					.SH "NAME"
 | 
				
			||||||
 | 
					toxic.conf \- Configuration file for toxic
 | 
				
			||||||
 | 
					.SH "SYNOPSIS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					~/\&.config/tox/toxic\&.conf
 | 
				
			||||||
 | 
					.SH "DESCRIPTION"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					The \fItoxic\&.conf\fR file is the main configuration file for \fBtoxic\fR(1) client\&. It uses syntax accepted by \fBlibconfig\fR\&. Lines starting with "//" are comments and will be ignored\&.
 | 
				
			||||||
 | 
					.SH "EXAMPLE"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					.if n \{\
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					.\}
 | 
				
			||||||
 | 
					.nf
 | 
				
			||||||
 | 
					// Configuration for interface
 | 
				
			||||||
 | 
					ui = {
 | 
				
			||||||
 | 
					    timestamps = true;
 | 
				
			||||||
 | 
					    alerts = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Configuration for audio
 | 
				
			||||||
 | 
					audio = {
 | 
				
			||||||
 | 
					    input_device = 1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					.fi
 | 
				
			||||||
 | 
					.if n \{\
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.\}
 | 
				
			||||||
 | 
					.SH "OPTIONS"
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBui\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration related to interface elements\&.
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtimestamps\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable or disable timestamps\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtime_format\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Select between 24 and 12 hour time\&. Specify 24 or 12\&. Setting timestamp_format and log_timestamp_format will override this setting\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtimestamp_format\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Time format string for the interface enclosed by double quotes\&. See
 | 
				
			||||||
 | 
					\fBdate\fR(1)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBlog_timestamp_format\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Time format string for logging enclosed by double quotes\&. See
 | 
				
			||||||
 | 
					\fBdate\fR(1)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBalerts\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable or disable acoustic alerts on events\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBnative_colors\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Select between native terminal colors and toxic color theme\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_bg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set background color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_fg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground (text) color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_accent\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground accent color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcolor_bar_notify\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					set foreground notify (and typing) color in chat status bar\&. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBautolog\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable or disable autologging\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBshow_typing_other\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Show when others are typing in a 1\-on\-1 chat\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBshow_typing_self\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Show others when you\(cqre typing in a 1\-on\-1 chat\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBshow_welcome_msg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Show welcome message on startup\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBshow_connection_msg\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable friend connection change notifications\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBnodelist_update_freq\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					How often in days to update the DHT nodes list\&. (integer; 0 to disable)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBautosave_freq\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					How often in seconds to auto\-save the Tox data file\&. (integer; 0 to disable)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBhistory_size\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Maximum lines for chat window history\&. Integer value\&. (for example: 700)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBnotification_timeout\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Time in milliseconds to display a notification\&. Integer value\&. (for example: 3000)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBline_join\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Indicator for when someone connects or joins a group\&. Three characters max for line_ settings\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBline_quit\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Indicator for when someone disconnects or leaves a group\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBline_alert\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Indicator for alert messages\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBline_normal\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Indicator for normal messages\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBmplex_away\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Set user status when attaching and detaching from GNU screen or tmux\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBmplex_away_note\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Status message to set when status is set to away due to screen/tmux detach\&. When attaching, the status message is set back to the original value\&.
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					.if n \{\
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					.\}
 | 
				
			||||||
 | 
					.nf
 | 
				
			||||||
 | 
					The following options control whether to output a terminal bell on certain events\&.
 | 
				
			||||||
 | 
					Some terminals mark the window as urgent when a bell is received\&. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window\&.
 | 
				
			||||||
 | 
					These options don\*(Aqt affect the "alerts" option\&.
 | 
				
			||||||
 | 
					.fi
 | 
				
			||||||
 | 
					.if n \{\
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.\}
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBbell_on_message\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable the terminal bell when receiving a message\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBbell_on_filetrans\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable the terminal bell when receiving a filetransfer\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBbell_on_filetrans_accept\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable the terminal bell when a filetransfer was accepted\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBbell_on_invite\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable the terminal bell when receiving a group/call invite\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBaudio\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration related to audio devices\&.
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBinput_device\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Audio input device\&. Integer value\&. Number corresponds to
 | 
				
			||||||
 | 
					/lsdev in
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBoutput_device\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Audio output device\&. Integer value\&. Number corresponds to
 | 
				
			||||||
 | 
					/lsdev out
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBVAD_threshold\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBconference_audio_channels\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBchat_audio_channels\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBpush_to_talk\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtox\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration related to paths\&.
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBdownload_path\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Default path for downloads\&. String value\&. Absolute path for downloaded files\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBavatar_path\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBautorun_path\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Path for any scripts that should be run on startup
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBchatlogs_path\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBpassword_eval\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Replace password prompt by running this command and using its output as the password\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBsounds\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration related to notification sounds\&. Special value "silent" can be used to disable a specific notification\&.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each value is a string which corresponds to the absolute path of a wav sound file\&.
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBnotif_error\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when an error occurs\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBself_log_in\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when you log in\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBself_log_out\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when you log out\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBuser_log_in\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when a contact become online\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBuser_log_out\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when a contact become offline\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcall_incoming\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when you receive an incoming call\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBcall_outgoing\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when you start a call\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBgeneric_message\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when an event occurs\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtransfer_pending\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when you receive a file transfer request\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtransfer_completed\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Sound to play when a file transfer is completed\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBkeys\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration related to user interface interaction\&. Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN\&.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each value is a string which corresponds to a key combination\&.
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBnext_tab\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to switch next tab\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBprev_tab\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to switch previous tab\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBscroll_line_up\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to scroll one line up\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBscroll_line_down\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to scroll one line down\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBhalf_page_up\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to scroll half page up\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBhalf_page_down\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to scroll half page down\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBpage_bottom\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Key combination to scroll to page bottom\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtoggle_peerlist\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Toggle the peer list on and off\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					\fBtoggle_paste_mode\fR
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Toggle treating linebreaks as enter key press\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.SH "FILES"
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					~/\&.config/tox/toxic\&.conf
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Main configuration file\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.PP
 | 
				
			||||||
 | 
					__DATADIR__/toxic\&.conf\&.example
 | 
				
			||||||
 | 
					.RS 4
 | 
				
			||||||
 | 
					Configuration example\&.
 | 
				
			||||||
 | 
					.RE
 | 
				
			||||||
 | 
					.SH "SEE ALSO"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					\fBtoxic\fR(1)
 | 
				
			||||||
 | 
					.SH "RESOURCES"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					Project page: https://github\&.com/JFreegman/toxic
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					IRC channel: chat\&.freenode\&.net#tox
 | 
				
			||||||
 | 
					.SH "AUTHORS"
 | 
				
			||||||
 | 
					.sp
 | 
				
			||||||
 | 
					JFreegman <JFreegman@gmail\&.com>
 | 
				
			||||||
							
								
								
									
										275
									
								
								doc/toxic.conf.5.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								doc/toxic.conf.5.asc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,275 @@
 | 
				
			|||||||
 | 
					toxic.conf(5)
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NAME
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					toxic.conf - Configuration file for toxic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SYNOPSIS
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					~/.config/tox/toxic.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DESCRIPTION
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					The 'toxic.conf' file is the main configuration file for *toxic*(1) client.
 | 
				
			||||||
 | 
					It uses syntax accepted by *libconfig*.
 | 
				
			||||||
 | 
					Lines starting with "//" are comments and will be ignored.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXAMPLE
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					// Configuration for interface
 | 
				
			||||||
 | 
					ui = {
 | 
				
			||||||
 | 
					    timestamps = true;
 | 
				
			||||||
 | 
					    alerts = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Configuration for audio
 | 
				
			||||||
 | 
					audio = {
 | 
				
			||||||
 | 
					    input_device = 1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OPTIONS
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					*ui*::
 | 
				
			||||||
 | 
					    Configuration related to interface elements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *timestamps*;;
 | 
				
			||||||
 | 
					        Enable or disable timestamps. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *time_format*;;
 | 
				
			||||||
 | 
						Select between 24 and 12 hour time. Specify 24 or 12. Setting
 | 
				
			||||||
 | 
					        timestamp_format and log_timestamp_format will override this setting.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *timestamp_format*;;
 | 
				
			||||||
 | 
					        Time format string for the interface enclosed by double quotes.
 | 
				
			||||||
 | 
					        See *date*(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *log_timestamp_format*;;
 | 
				
			||||||
 | 
					        Time format string for logging enclosed by double quotes.
 | 
				
			||||||
 | 
					        See *date*(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *alerts*;;
 | 
				
			||||||
 | 
					        Enable or disable acoustic alerts on events. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *native_colors*;;
 | 
				
			||||||
 | 
					        Select between native terminal colors and toxic color theme. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_bg*;;
 | 
				
			||||||
 | 
					        set background color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_fg*;;
 | 
				
			||||||
 | 
					        set foreground (text) color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_accent*;;
 | 
				
			||||||
 | 
					        set foreground accent color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *color_bar_notify*;;
 | 
				
			||||||
 | 
					        set foreground notify (and typing) color in chat status bar. (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *autolog*;;
 | 
				
			||||||
 | 
					        Enable or disable autologging. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *show_typing_other*;;
 | 
				
			||||||
 | 
					        Show when others are typing in a 1-on-1 chat. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *show_typing_self*;;
 | 
				
			||||||
 | 
					        Show others when you're typing in a 1-on-1 chat. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *show_welcome_msg*;;
 | 
				
			||||||
 | 
					        Show welcome message on startup. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *show_connection_msg*;;
 | 
				
			||||||
 | 
					        Enable friend connection change notifications. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *nodelist_update_freq*;;
 | 
				
			||||||
 | 
					        How often in days to update the DHT nodes list. (integer; 0 to disable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *autosave_freq*;;
 | 
				
			||||||
 | 
					        How often in seconds to auto-save the Tox data file. (integer; 0 to disable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *history_size*;;
 | 
				
			||||||
 | 
					        Maximum lines for chat window history. Integer value. (for example: 700)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *notification_timeout*;;
 | 
				
			||||||
 | 
					        Time in milliseconds to display a notification. Integer value. (for example: 3000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *line_join*;;
 | 
				
			||||||
 | 
					        Indicator for when someone connects or joins a group.
 | 
				
			||||||
 | 
					        Three characters max for line_ settings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *line_quit*;;
 | 
				
			||||||
 | 
					        Indicator for when someone disconnects or leaves a group.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *line_alert*;;
 | 
				
			||||||
 | 
					        Indicator for alert messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *line_normal*;;
 | 
				
			||||||
 | 
					        Indicator for normal messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *mplex_away*;;
 | 
				
			||||||
 | 
					        Set user status when attaching and detaching from GNU screen or tmux.
 | 
				
			||||||
 | 
					        true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *mplex_away_note*;;
 | 
				
			||||||
 | 
					        Status message to set when status is set to away due to screen/tmux
 | 
				
			||||||
 | 
					        detach. When attaching, the status message is set back to the original
 | 
				
			||||||
 | 
					        value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The following options control whether to output a terminal bell on certain events.
 | 
				
			||||||
 | 
					    Some terminals mark the window as urgent when a bell is received. Urgent windows are usually highlighted in the taskbar and some window managers even provide shortcuts to jump to the next urgent window.
 | 
				
			||||||
 | 
					    These options don't affect the "alerts" option.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *bell_on_message*;;
 | 
				
			||||||
 | 
					        Enable/Disable the terminal bell when receiving a message. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *bell_on_filetrans*;;
 | 
				
			||||||
 | 
					        Enable/Disable the terminal bell when receiving a filetransfer. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *bell_on_filetrans_accept*;;
 | 
				
			||||||
 | 
					        Enable/Disable the terminal bell when a filetransfer was accepted. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *bell_on_invite*;;
 | 
				
			||||||
 | 
					        Enable/Disable the terminal bell when receiving a group/call invite. true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*audio*::
 | 
				
			||||||
 | 
					    Configuration related to audio devices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *input_device*;;
 | 
				
			||||||
 | 
					        Audio input device. Integer value. Number corresponds to `/lsdev in`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *output_device*;;
 | 
				
			||||||
 | 
					        Audio output device. Integer value. Number corresponds to `/lsdev out`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *VAD_threshold*;;
 | 
				
			||||||
 | 
					        Voice Activity Detection threshold.  Float value. Recommended values are
 | 
				
			||||||
 | 
					        1.0-40.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *conference_audio_channels*;;
 | 
				
			||||||
 | 
					        Number of channels for conference audio broadcast. Integer value. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *chat_audio_channels*;;
 | 
				
			||||||
 | 
					        Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *push_to_talk*;;
 | 
				
			||||||
 | 
					        Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*tox*::
 | 
				
			||||||
 | 
					    Configuration related to paths.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *download_path*;;
 | 
				
			||||||
 | 
					        Default path for downloads. String value. Absolute path for downloaded
 | 
				
			||||||
 | 
					        files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *avatar_path*;;
 | 
				
			||||||
 | 
					        Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *autorun_path*;;
 | 
				
			||||||
 | 
					        Path for any scripts that should be run on startup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *chatlogs_path*;;
 | 
				
			||||||
 | 
					        Default path for chatlogs. String value. Absolute path for chatlog files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *password_eval*;;
 | 
				
			||||||
 | 
					        Replace password prompt by running this command and using its output as
 | 
				
			||||||
 | 
						the password.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*sounds*::
 | 
				
			||||||
 | 
					    Configuration related to notification sounds.
 | 
				
			||||||
 | 
					    Special value "silent" can be used to disable a specific notification. +
 | 
				
			||||||
 | 
					    Each value is a string which corresponds to the absolute path of a wav
 | 
				
			||||||
 | 
					    sound file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *notif_error*;;
 | 
				
			||||||
 | 
					        Sound to play when an error occurs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *self_log_in*;;
 | 
				
			||||||
 | 
					        Sound to play when you log in.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *self_log_out*;;
 | 
				
			||||||
 | 
					        Sound to play when you log out.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *user_log_in*;;
 | 
				
			||||||
 | 
					        Sound to play when a contact become online.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *user_log_out*;;
 | 
				
			||||||
 | 
					        Sound to play when a contact become offline.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *call_incoming*;;
 | 
				
			||||||
 | 
					        Sound to play when you receive an incoming call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *call_outgoing*;;
 | 
				
			||||||
 | 
					        Sound to play when you start a call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *generic_message*;;
 | 
				
			||||||
 | 
					        Sound to play when an event occurs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *transfer_pending*;;
 | 
				
			||||||
 | 
					        Sound to play when you receive a file transfer request.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *transfer_completed*;;
 | 
				
			||||||
 | 
					        Sound to play when a file transfer is completed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*keys*::
 | 
				
			||||||
 | 
					    Configuration related to user interface interaction.
 | 
				
			||||||
 | 
					    Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN. +
 | 
				
			||||||
 | 
					    Each value is a string which corresponds to a key combination.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *next_tab*;;
 | 
				
			||||||
 | 
					        Key combination to switch next tab.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *prev_tab*;;
 | 
				
			||||||
 | 
					        Key combination to switch previous tab.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *scroll_line_up*;;
 | 
				
			||||||
 | 
					        Key combination to scroll one line up.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *scroll_line_down*;;
 | 
				
			||||||
 | 
					        Key combination to scroll one line down.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *half_page_up*;;
 | 
				
			||||||
 | 
					        Key combination to scroll half page up.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *half_page_down*;;
 | 
				
			||||||
 | 
					        Key combination to scroll half page down.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *page_bottom*;;
 | 
				
			||||||
 | 
					        Key combination to scroll to page bottom.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *toggle_peerlist*;;
 | 
				
			||||||
 | 
					        Toggle the peer list on and off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *toggle_paste_mode*;;
 | 
				
			||||||
 | 
					        Toggle treating linebreaks as enter key press.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FILES
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					~/.config/tox/toxic.conf::
 | 
				
			||||||
 | 
					    Main configuration file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{datadir}/toxic.conf.example::
 | 
				
			||||||
 | 
					    Configuration example.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SEE ALSO
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					*toxic*(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RESOURCES
 | 
				
			||||||
 | 
					---------
 | 
				
			||||||
 | 
					Project page: <https://github.com/JFreegman/toxic>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IRC channel:  chat.freenode.net#tox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTHORS
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					JFreegman <JFreegman@gmail.com>
 | 
				
			||||||
							
								
								
									
										199
									
								
								m4/pkg.m4
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								m4/pkg.m4
									
									
									
									
									
								
							@@ -1,199 +0,0 @@
 | 
				
			|||||||
# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
 | 
					 | 
				
			||||||
# serial 1 (pkg-config-0.24)
 | 
					 | 
				
			||||||
# 
 | 
					 | 
				
			||||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
# it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
# the Free Software Foundation; either version 2 of the License, or
 | 
					 | 
				
			||||||
# (at your option) any later version.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# This program is distributed in the hope that it will be useful, but
 | 
					 | 
				
			||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
					 | 
				
			||||||
# General Public License for more details.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
# along with this program; if not, write to the Free Software
 | 
					 | 
				
			||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# As a special exception to the GNU General Public License, if you
 | 
					 | 
				
			||||||
# distribute this file as part of a program that contains a
 | 
					 | 
				
			||||||
# configuration script generated by Autoconf, you may include it under
 | 
					 | 
				
			||||||
# the same distribution terms that you use for the rest of that program.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
 | 
					 | 
				
			||||||
# ----------------------------------
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
 | 
					 | 
				
			||||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 | 
					 | 
				
			||||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
 | 
					 | 
				
			||||||
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
 | 
					 | 
				
			||||||
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
 | 
					 | 
				
			||||||
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
 | 
					 | 
				
			||||||
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
 | 
					 | 
				
			||||||
	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
if test -n "$PKG_CONFIG"; then
 | 
					 | 
				
			||||||
	_pkg_min_version=m4_default([$1], [0.9.0])
 | 
					 | 
				
			||||||
	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
 | 
					 | 
				
			||||||
	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
 | 
					 | 
				
			||||||
		AC_MSG_RESULT([yes])
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		AC_MSG_RESULT([no])
 | 
					 | 
				
			||||||
		PKG_CONFIG=""
 | 
					 | 
				
			||||||
	fi
 | 
					 | 
				
			||||||
fi[]dnl
 | 
					 | 
				
			||||||
])# PKG_PROG_PKG_CONFIG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Check to see whether a particular set of modules exists.  Similar
 | 
					 | 
				
			||||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
					 | 
				
			||||||
# only at the first occurence in configure.ac, so if the first place
 | 
					 | 
				
			||||||
# it's called might be skipped (such as if it is within an "if", you
 | 
					 | 
				
			||||||
# have to call PKG_CHECK_EXISTS manually
 | 
					 | 
				
			||||||
# --------------------------------------------------------------
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_CHECK_EXISTS],
 | 
					 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					 | 
				
			||||||
if test -n "$PKG_CONFIG" && \
 | 
					 | 
				
			||||||
    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
 | 
					 | 
				
			||||||
  m4_default([$2], [:])
 | 
					 | 
				
			||||||
m4_ifvaln([$3], [else
 | 
					 | 
				
			||||||
  $3])dnl
 | 
					 | 
				
			||||||
fi])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
 | 
					 | 
				
			||||||
# ---------------------------------------------
 | 
					 | 
				
			||||||
m4_define([_PKG_CONFIG],
 | 
					 | 
				
			||||||
[if test -n "$$1"; then
 | 
					 | 
				
			||||||
    pkg_cv_[]$1="$$1"
 | 
					 | 
				
			||||||
 elif test -n "$PKG_CONFIG"; then
 | 
					 | 
				
			||||||
    PKG_CHECK_EXISTS([$3],
 | 
					 | 
				
			||||||
                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
 | 
					 | 
				
			||||||
		      test "x$?" != "x0" && pkg_failed=yes ],
 | 
					 | 
				
			||||||
		     [pkg_failed=yes])
 | 
					 | 
				
			||||||
 else
 | 
					 | 
				
			||||||
    pkg_failed=untried
 | 
					 | 
				
			||||||
fi[]dnl
 | 
					 | 
				
			||||||
])# _PKG_CONFIG
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# _PKG_SHORT_ERRORS_SUPPORTED
 | 
					 | 
				
			||||||
# -----------------------------
 | 
					 | 
				
			||||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 | 
					 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 | 
					 | 
				
			||||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 | 
					 | 
				
			||||||
        _pkg_short_errors_supported=yes
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
        _pkg_short_errors_supported=no
 | 
					 | 
				
			||||||
fi[]dnl
 | 
					 | 
				
			||||||
])# _PKG_SHORT_ERRORS_SUPPORTED
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
 | 
					 | 
				
			||||||
# [ACTION-IF-NOT-FOUND])
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Note that if there is a possibility the first call to
 | 
					 | 
				
			||||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
 | 
					 | 
				
			||||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# --------------------------------------------------------------
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_CHECK_MODULES],
 | 
					 | 
				
			||||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 | 
					 | 
				
			||||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
 | 
					 | 
				
			||||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pkg_failed=no
 | 
					 | 
				
			||||||
AC_MSG_CHECKING([for $1])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
 | 
					 | 
				
			||||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
 | 
					 | 
				
			||||||
and $1[]_LIBS to avoid the need to call pkg-config.
 | 
					 | 
				
			||||||
See the pkg-config man page for more details.])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if test $pkg_failed = yes; then
 | 
					 | 
				
			||||||
   	AC_MSG_RESULT([no])
 | 
					 | 
				
			||||||
        _PKG_SHORT_ERRORS_SUPPORTED
 | 
					 | 
				
			||||||
        if test $_pkg_short_errors_supported = yes; then
 | 
					 | 
				
			||||||
	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
 | 
					 | 
				
			||||||
        else 
 | 
					 | 
				
			||||||
	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
 | 
					 | 
				
			||||||
        fi
 | 
					 | 
				
			||||||
	# Put the nasty error message in config.log where it belongs
 | 
					 | 
				
			||||||
	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m4_default([$4], [AC_MSG_ERROR(
 | 
					 | 
				
			||||||
[Package requirements ($2) were not met:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
$$1_PKG_ERRORS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
 | 
					 | 
				
			||||||
installed software in a non-standard prefix.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_PKG_TEXT])[]dnl
 | 
					 | 
				
			||||||
        ])
 | 
					 | 
				
			||||||
elif test $pkg_failed = untried; then
 | 
					 | 
				
			||||||
     	AC_MSG_RESULT([no])
 | 
					 | 
				
			||||||
	m4_default([$4], [AC_MSG_FAILURE(
 | 
					 | 
				
			||||||
[The pkg-config script could not be found or is too old.  Make sure it
 | 
					 | 
				
			||||||
is in your PATH or set the PKG_CONFIG environment variable to the full
 | 
					 | 
				
			||||||
path to pkg-config.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_PKG_TEXT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
 | 
					 | 
				
			||||||
        ])
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
 | 
					 | 
				
			||||||
	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
 | 
					 | 
				
			||||||
        AC_MSG_RESULT([yes])
 | 
					 | 
				
			||||||
	$3
 | 
					 | 
				
			||||||
fi[]dnl
 | 
					 | 
				
			||||||
])# PKG_CHECK_MODULES
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# PKG_INSTALLDIR(DIRECTORY)
 | 
					 | 
				
			||||||
# -------------------------
 | 
					 | 
				
			||||||
# Substitutes the variable pkgconfigdir as the location where a module
 | 
					 | 
				
			||||||
# should install pkg-config .pc files. By default the directory is
 | 
					 | 
				
			||||||
# $libdir/pkgconfig, but the default can be changed by passing
 | 
					 | 
				
			||||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
 | 
					 | 
				
			||||||
# parameter.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_INSTALLDIR],
 | 
					 | 
				
			||||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
 | 
					 | 
				
			||||||
m4_pushdef([pkg_description],
 | 
					 | 
				
			||||||
    [pkg-config installation directory @<:@]pkg_default[@:>@])
 | 
					 | 
				
			||||||
AC_ARG_WITH([pkgconfigdir],
 | 
					 | 
				
			||||||
    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
 | 
					 | 
				
			||||||
    [with_pkgconfigdir=]pkg_default)
 | 
					 | 
				
			||||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
 | 
					 | 
				
			||||||
m4_popdef([pkg_default])
 | 
					 | 
				
			||||||
m4_popdef([pkg_description])
 | 
					 | 
				
			||||||
]) dnl PKG_INSTALLDIR
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
 | 
					 | 
				
			||||||
# -------------------------
 | 
					 | 
				
			||||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
 | 
					 | 
				
			||||||
# module should install arch-independent pkg-config .pc files. By
 | 
					 | 
				
			||||||
# default the directory is $datadir/pkgconfig, but the default can be
 | 
					 | 
				
			||||||
# changed by passing DIRECTORY. The user can override through the
 | 
					 | 
				
			||||||
# --with-noarch-pkgconfigdir parameter.
 | 
					 | 
				
			||||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
 | 
					 | 
				
			||||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
 | 
					 | 
				
			||||||
m4_pushdef([pkg_description],
 | 
					 | 
				
			||||||
    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
 | 
					 | 
				
			||||||
AC_ARG_WITH([noarch-pkgconfigdir],
 | 
					 | 
				
			||||||
    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
 | 
					 | 
				
			||||||
    [with_noarch_pkgconfigdir=]pkg_default)
 | 
					 | 
				
			||||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
 | 
					 | 
				
			||||||
m4_popdef([pkg_default])
 | 
					 | 
				
			||||||
m4_popdef([pkg_description])
 | 
					 | 
				
			||||||
]) dnl PKG_NOARCH_INSTALLDIR
 | 
					 | 
				
			||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
192.254.75.98 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B
 | 
					 | 
				
			||||||
2607:5600:284::2 33445 FE3914F4616E227F29B2103450D6B55A836AD4BD23F97144E2C4ABE8D504FE1B
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
dist_pkgdata_DATA = DHTnodes
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								misc/nameservers
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								misc/nameservers
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					toxme.io 1A39E7A5D5FA9CF155C751570A32E625698A60A55F6D88028F949F66144F4F25
 | 
				
			||||||
							
								
								
									
										148
									
								
								misc/toxic.conf.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								misc/toxic.conf.example
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					// SAMPLE TOXIC CONFIGURATION
 | 
				
			||||||
 | 
					// USES LIBCONFIG-ACCEPTED SYNTAX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ui = {
 | 
				
			||||||
 | 
					  // true to enable timestamps, false to disable
 | 
				
			||||||
 | 
					  timestamps=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to enable acoustic alerts on messages, false to disable
 | 
				
			||||||
 | 
					  alerts=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output a bell when receiving a message (see manpage)
 | 
				
			||||||
 | 
					  bell_on_message=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output a bell when receiving a filetransfer (see manpage)
 | 
				
			||||||
 | 
					  bell_on_filetrans=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Don't output a bell when a filetransfer was accepted (see manpage)
 | 
				
			||||||
 | 
					  bell_on_filetrans_accept=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Output a bell when receiving a group/call invite (see manpage)
 | 
				
			||||||
 | 
					  bell_on_invite=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to use native terminal colours, false to use toxic default colour theme
 | 
				
			||||||
 | 
					  native_colors=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set background color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_bg="blue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground (text) color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_fg="white";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground accent color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_accent="cyan";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set foreground notify (and typing) color in chat status bar (black, white, red, green, blue, cyan, yellow, magenta)
 | 
				
			||||||
 | 
					  color_bar_notify="yellow";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to enable autologging, false to disable
 | 
				
			||||||
 | 
					  autolog=false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 24 or 12 hour time
 | 
				
			||||||
 | 
					  time_format=24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Timestamp format string according to date/strftime format. Overrides time_format setting
 | 
				
			||||||
 | 
					  timestamp_format="%H:%M";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to show you when others are typing a message in 1-on-1 chats
 | 
				
			||||||
 | 
					  show_typing_other=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to show others when you're typing a message in 1-on-1 chats
 | 
				
			||||||
 | 
					  show_typing_self=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to show the welcome message on startup
 | 
				
			||||||
 | 
					  show_welcome_msg=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to show friend connection change messages on the home screen
 | 
				
			||||||
 | 
					  show_connection_msg=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // How often in days to update the DHT nodes list. (0 to disable updates)
 | 
				
			||||||
 | 
					  nodeslist_update_freq=7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // How often in seconds to auto-save the Tox data file. (0 to disable periodic auto-saves)
 | 
				
			||||||
 | 
					  autosave_freq=600;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // maximum lines for chat window history
 | 
				
			||||||
 | 
					  history_size=700;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // time in milliseconds to display a notification
 | 
				
			||||||
 | 
					  notification_timeout=6000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Indicator for display when someone connects or joins a group
 | 
				
			||||||
 | 
					  line_join="-->";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Indicator for display when someone disconnects or leaves a group
 | 
				
			||||||
 | 
					  line_quit="<--";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Indicator for alert messages.
 | 
				
			||||||
 | 
					  line_alert="-!-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Indicator for normal messages.
 | 
				
			||||||
 | 
					  line_normal="-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // true to change status based on screen/tmux attach/detach, false to disable
 | 
				
			||||||
 | 
					  mplex_away=true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Status message to use when status set to away due to screen/tmux detach
 | 
				
			||||||
 | 
					  mplex_away_note="Away from keyboard, be back soon!"
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					audio = {
 | 
				
			||||||
 | 
					  // preferred audio input device; numbers correspond to /lsdev in
 | 
				
			||||||
 | 
					  input_device=2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // preferred audio output device; numbers correspond to /lsdev out
 | 
				
			||||||
 | 
					  output_device=0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // default VAD threshold; float (recommended values are 1.0-40.0)
 | 
				
			||||||
 | 
					  VAD_threshold=5.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Number of channels to use for conference audio broadcasts; 1 for mono, 2 for stereo.
 | 
				
			||||||
 | 
					  conference_audio_channels=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
 | 
				
			||||||
 | 
					  chat_audio_channels=2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // toggle conference push-to-talk
 | 
				
			||||||
 | 
					  push_to_talk=false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tox = {
 | 
				
			||||||
 | 
					  // Path for downloaded files
 | 
				
			||||||
 | 
					  // download_path="/home/USERNAME/Downloads/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Path for your avatar (file must be a .png and cannot exceed 64 KiB)
 | 
				
			||||||
 | 
					  // avatar_path="/home/USERNAME/Pictures/youravatar.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Path for scripts that should be run on startup
 | 
				
			||||||
 | 
					  // autorun_path="/home/USERNAME/toxic_scripts/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Path for chatlogs
 | 
				
			||||||
 | 
					  // chatlogs_path="/home/USERNAME/toxic_chatlogs/";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// To disable a sound set the path to "silent"
 | 
				
			||||||
 | 
					sounds = {
 | 
				
			||||||
 | 
					  error="__DATADIR__/sounds/ToxicError.wav";
 | 
				
			||||||
 | 
					  user_log_in="__DATADIR__/sounds/ToxicContactOnline.wav";
 | 
				
			||||||
 | 
					  user_log_out="__DATADIR__/sounds/ToxicContactOffline.wav";
 | 
				
			||||||
 | 
					  call_incoming="__DATADIR__/sounds/ToxicIncomingCall.wav";
 | 
				
			||||||
 | 
					  call_outgoing="__DATADIR__/sounds/ToxicOutgoingCall.wav";
 | 
				
			||||||
 | 
					  generic_message="__DATADIR__/sounds/ToxicRecvMessage.wav";
 | 
				
			||||||
 | 
					  transfer_pending="__DATADIR__/sounds/ToxicTransferStart.wav";
 | 
				
			||||||
 | 
					  transfer_completed="__DATADIR__/sounds/ToxicTransferComplete.wav";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Currently supported: Ctrl modified keys, Tab, PAGEUP and PAGEDOWN (case insensitive)
 | 
				
			||||||
 | 
					// Note: Ctrl+M does not work
 | 
				
			||||||
 | 
					keys = {
 | 
				
			||||||
 | 
					  next_tab="Ctrl+P";
 | 
				
			||||||
 | 
					  prev_tab="Ctrl+O";
 | 
				
			||||||
 | 
					  scroll_line_up="PAGEUP";
 | 
				
			||||||
 | 
					  scroll_line_down="PAGEDOWN";
 | 
				
			||||||
 | 
					  half_page_up="Ctrl+F";
 | 
				
			||||||
 | 
					  half_page_down="Ctrl+V";
 | 
				
			||||||
 | 
					  page_bottom="Ctrl+H";
 | 
				
			||||||
 | 
					  toggle_peerlist="Ctrl+B";
 | 
				
			||||||
 | 
					  toggle_paste_mode="Ctrl+T";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										11
									
								
								misc/toxic.desktop
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								misc/toxic.desktop
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					[Desktop Entry]
 | 
				
			||||||
 | 
					Version=1.0
 | 
				
			||||||
 | 
					Type=Application
 | 
				
			||||||
 | 
					Name=Toxic
 | 
				
			||||||
 | 
					Comment=A CLI based Tox client
 | 
				
			||||||
 | 
					TryExec=toxic
 | 
				
			||||||
 | 
					Exec=toxic
 | 
				
			||||||
 | 
					Icon=utilities-terminal
 | 
				
			||||||
 | 
					Categories=InstantMessaging;AudioVideo;Network;
 | 
				
			||||||
 | 
					Terminal=true
 | 
				
			||||||
 | 
					MimeType=x-scheme-handler/tox;
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicContactOffline.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicContactOffline.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicContactOnline.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicContactOnline.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicError.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicError.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicIncomingCall.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicIncomingCall.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicOutgoingCall.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicOutgoingCall.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicRecvMessage.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicRecvMessage.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicTransferComplete.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicTransferComplete.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/ToxicTransferStart.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/ToxicTransferStart.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								sounds/license
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								sounds/license
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					ToxicError.wav, ToxicRecvMessage.wav, ToxicContactOffline.wav, ToxicIncomingCall.wav, ToxicTransferComplete.wav, ToxicContactOnline.wav, ToxicOutgoingCall.wav and ToxicTransferStart.wav
 | 
				
			||||||
 | 
					are licensed under the "Creative Commons Attribution 3.0 Unported". All credit attributed to Jfreegman.
 | 
				
			||||||
							
								
								
									
										217
									
								
								src/api.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/api.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,217 @@
 | 
				
			|||||||
 | 
					/*  api.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <dirent.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <tox/tox.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "execute.h"
 | 
				
			||||||
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "message_queue.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "settings.h"
 | 
				
			||||||
 | 
					#include "toxic_strings.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					#include "python_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tox              *user_tox;
 | 
				
			||||||
 | 
					static WINDOW    *cur_window;
 | 
				
			||||||
 | 
					static ToxWindow *self_window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern FriendsList Friends;
 | 
				
			||||||
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void api_display(const char *const msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (msg == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self_window = get_active_window();
 | 
				
			||||||
 | 
					    line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FriendsList api_get_friendslist(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return Friends;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *api_get_nick(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t   len  = tox_self_get_name_size(user_tox);
 | 
				
			||||||
 | 
					    uint8_t *name = malloc(len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (name == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tox_self_get_name(user_tox, name);
 | 
				
			||||||
 | 
					    name[len] = '\0';
 | 
				
			||||||
 | 
					    return (char *) name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tox_User_Status api_get_status(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return tox_self_get_status(user_tox);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *api_get_status_message(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t   len    = tox_self_get_status_message_size(user_tox);
 | 
				
			||||||
 | 
					    uint8_t *status = malloc(len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (status == NULL) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tox_self_get_status_message(user_tox, status);
 | 
				
			||||||
 | 
					    status[len] = '\0';
 | 
				
			||||||
 | 
					    return (char *) status;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void api_send(const char *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (msg == NULL || self_window->chatwin->cqueue == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *name = api_get_nick();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (name == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self_window = get_active_window();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
 | 
				
			||||||
 | 
					    add_line_to_hist(self_window->chatwin);
 | 
				
			||||||
 | 
					    int id = line_info_add(self_window, true, name, NULL, OUT_MSG, 0, 0, "%s", msg);
 | 
				
			||||||
 | 
					    cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
 | 
				
			||||||
 | 
					    free(name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void api_execute(const char *input, int mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    self_window = get_active_window();
 | 
				
			||||||
 | 
					    execute(cur_window, self_window, user_tox, input, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return do_python_command(num_args, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int num_registered_handlers(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return python_num_registered_handlers();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int help_max_width(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return python_help_max_width();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void draw_handler_help(WINDOW *win)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    python_draw_handler_help(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FILE       *fp;
 | 
				
			||||||
 | 
					    const char *error_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cur_window  = window;
 | 
				
			||||||
 | 
					    self_window = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc != 1) {
 | 
				
			||||||
 | 
					        if (argc < 1) {
 | 
				
			||||||
 | 
					            error_str = "Path must be specified.";
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            error_str = "Only one argument allowed.";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fp = fopen(argv[1], "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fp == NULL) {
 | 
				
			||||||
 | 
					        error_str = "Path does not exist.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    run_python(fp, argv[1]);
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void invoke_autoruns(WINDOW *window, ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char abspath_buf[PATH_MAX + 256];
 | 
				
			||||||
 | 
					    char err_buf[PATH_MAX + 128];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (user_settings->autorun_path[0] == '\0') {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DIR *d = opendir(user_settings->autorun_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (d == NULL) {
 | 
				
			||||||
 | 
					        snprintf(err_buf, sizeof(err_buf), "Autorun path does not exist: %s", user_settings->autorun_path);
 | 
				
			||||||
 | 
					        api_display(err_buf);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct dirent *dir = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cur_window  = window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self_window = self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while ((dir = readdir(d)) != NULL) {
 | 
				
			||||||
 | 
					        size_t path_len = strlen(dir->d_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!strcmp(dir->d_name + path_len - 3, ".py")) {
 | 
				
			||||||
 | 
					            snprintf(abspath_buf, sizeof(abspath_buf), "%s%s", user_settings->autorun_path, dir->d_name);
 | 
				
			||||||
 | 
					            FILE *fp = fopen(abspath_buf, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (fp == NULL) {
 | 
				
			||||||
 | 
					                snprintf(err_buf, sizeof(err_buf), "Invalid path: %s", abspath_buf);
 | 
				
			||||||
 | 
					                api_display(err_buf);
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            run_python(fp, abspath_buf);
 | 
				
			||||||
 | 
					            fclose(fp);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closedir(d);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/api.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/api.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					/*  api.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef API_H
 | 
				
			||||||
 | 
					#define API_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void api_display(const char *const msg);
 | 
				
			||||||
 | 
					FriendsList api_get_friendslist(void);
 | 
				
			||||||
 | 
					char *api_get_nick(void);
 | 
				
			||||||
 | 
					Tox_User_Status api_get_status(void);
 | 
				
			||||||
 | 
					char *api_get_status_message(void);
 | 
				
			||||||
 | 
					void api_send(const char *msg);
 | 
				
			||||||
 | 
					void api_execute(const char *input, int mode);
 | 
				
			||||||
 | 
					int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					int num_registered_handlers(void);
 | 
				
			||||||
 | 
					int help_max_width(void);
 | 
				
			||||||
 | 
					void draw_handler_help(WINDOW *win);
 | 
				
			||||||
 | 
					void invoke_autoruns(WINDOW *w, ToxWindow *self);
 | 
				
			||||||
 | 
					void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* API_H */
 | 
				
			||||||
							
								
								
									
										1225
									
								
								src/audio_call.c
									
									
									
									
									
								
							
							
						
						
									
										1225
									
								
								src/audio_call.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										115
									
								
								src/audio_call.h
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								src/audio_call.h
									
									
									
									
									
								
							@@ -1,30 +1,109 @@
 | 
				
			|||||||
/*
 | 
					/*  audio_call.h
 | 
				
			||||||
 * Toxic -- Tox Curses Client
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef _audio_h
 | 
					#ifndef AUDIO_CALL_H
 | 
				
			||||||
#define _audio_h
 | 
					#define AUDIO_CALL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <tox/toxav.h>
 | 
					#include <tox/toxav.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct ToxWindow ToxWindow;
 | 
					#include "audio_device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum _AudioError
 | 
					typedef enum AudioError {
 | 
				
			||||||
{
 | 
					    ae_None = 0,
 | 
				
			||||||
    NoError = 0,
 | 
					    ae_StartingCaptureDevice = 1 << 0,
 | 
				
			||||||
    ErrorStartingCaptureDevice = 1 << 0,
 | 
					    ae_StartingOutputDevice = 1 << 1,
 | 
				
			||||||
    ErrorStartingOutputDevice = 1 << 1,
 | 
					    ae_StartingCoreAudio = 1 << 2
 | 
				
			||||||
    ErrorStartingCoreAudio = 1 << 2
 | 
					 | 
				
			||||||
} AudioError;
 | 
					} AudioError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* You will have to pass pointer to first member of 'windows' 
 | 
					#ifdef VIDEO
 | 
				
			||||||
 * declared in windows.c otherwise undefined behaviour will 
 | 
					typedef enum VideoError {
 | 
				
			||||||
 | 
					    ve_None = 0,
 | 
				
			||||||
 | 
					    ve_StartingCaptureDevice = 1 << 0,
 | 
				
			||||||
 | 
					    ve_StartingOutputDevice = 1 << 1,
 | 
				
			||||||
 | 
					    ve_StartingCoreVideo = 1 << 2
 | 
				
			||||||
 | 
					} VideoError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Status transitions:
 | 
				
			||||||
 | 
					 * None -> Pending (call invitation made or received);
 | 
				
			||||||
 | 
					 * Pending -> None (invitation rejected or failed);
 | 
				
			||||||
 | 
					 * Pending -> Active (call starts);
 | 
				
			||||||
 | 
					 * Active -> None (call ends).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ToxAv* init_audio(ToxWindow* window, Tox* tox);
 | 
					typedef enum CallStatus {
 | 
				
			||||||
void terminate_audio();
 | 
					    cs_None = 0,
 | 
				
			||||||
 | 
					    cs_Pending,
 | 
				
			||||||
 | 
					    cs_Active
 | 
				
			||||||
 | 
					} CallStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int errors();
 | 
					typedef struct Call {
 | 
				
			||||||
 | 
					    CallStatus status;
 | 
				
			||||||
 | 
					    uint32_t state; /* ToxAV call state, valid when `status == cs_Active` */
 | 
				
			||||||
 | 
					    uint32_t in_idx, out_idx; /* Audio device index, or -1 if not open */
 | 
				
			||||||
 | 
					    uint32_t audio_bit_rate; /* Bit rate for sending audio */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int start_transmission();
 | 
					    uint32_t vin_idx, vout_idx; /* Video device index, or -1 if not open */
 | 
				
			||||||
 | 
					    uint32_t video_width, video_height;
 | 
				
			||||||
 | 
					    uint32_t video_bit_rate; /* Bit rate for sending video; 0 for no video */
 | 
				
			||||||
 | 
					} Call;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _audio_h */
 | 
					struct CallControl {
 | 
				
			||||||
 | 
					    AudioError audio_errors;
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					    VideoError video_errors;
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ToxAV *av;
 | 
				
			||||||
 | 
					    ToxWindow *prompt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Call *calls;
 | 
				
			||||||
 | 
					    uint32_t max_calls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool audio_enabled;
 | 
				
			||||||
 | 
					    bool video_enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int32_t audio_frame_duration;
 | 
				
			||||||
 | 
					    uint32_t audio_sample_rate;
 | 
				
			||||||
 | 
					    uint8_t audio_channels;
 | 
				
			||||||
 | 
					    uint32_t default_audio_bit_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int32_t video_frame_duration;
 | 
				
			||||||
 | 
					    uint32_t default_video_width, default_video_height;
 | 
				
			||||||
 | 
					    uint32_t default_video_bit_rate;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct CallControl CallControl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* You will have to pass pointer to first member of 'windows' declared in windows.c */
 | 
				
			||||||
 | 
					ToxAV *init_audio(ToxWindow *self, Tox *tox);
 | 
				
			||||||
 | 
					void terminate_audio(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool init_call(Call *call);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void place_call(ToxWindow *self);
 | 
				
			||||||
 | 
					void stop_current_call(ToxWindow *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void init_friend_AV(uint32_t index);
 | 
				
			||||||
 | 
					void del_friend_AV(uint32_t index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* AUDIO_CALL_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										790
									
								
								src/audio_device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										790
									
								
								src/audio_device.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,790 @@
 | 
				
			|||||||
 | 
					/*  audio_device.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "audio_device.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "settings.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <AL/al.h>
 | 
				
			||||||
 | 
					#include <AL/alc.h>
 | 
				
			||||||
 | 
					/* compatibility with older versions of OpenAL */
 | 
				
			||||||
 | 
					#ifndef ALC_ALL_DEVICES_SPECIFIER
 | 
				
			||||||
 | 
					#include <AL/alext.h>
 | 
				
			||||||
 | 
					#endif /* ALC_ALL_DEVICES_SPECIFIER */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
 | 
					extern struct Winthread Winthread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct FrameInfo {
 | 
				
			||||||
 | 
					    uint32_t samples_per_frame;
 | 
				
			||||||
 | 
					    uint32_t sample_rate;
 | 
				
			||||||
 | 
					    bool stereo;
 | 
				
			||||||
 | 
					} FrameInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A virtual input/output device, abstracting the currently selected openal
 | 
				
			||||||
 | 
					 * device (which may change during the lifetime of the virtual device).
 | 
				
			||||||
 | 
					 * We refer to a virtual device as a "device", and refer to an underlying
 | 
				
			||||||
 | 
					 * openal device as an "al_device".
 | 
				
			||||||
 | 
					 * Multiple virtual devices may be open at once; the callback of each virtual
 | 
				
			||||||
 | 
					 * input device has data captured from the input al_device passed to it, and
 | 
				
			||||||
 | 
					 * each virtual output device acts as a source for the output al_device.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct Device {
 | 
				
			||||||
 | 
					    bool active;
 | 
				
			||||||
 | 
					    bool muted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FrameInfo frame_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // used only by input devices:
 | 
				
			||||||
 | 
					    DataHandleCallback cb;
 | 
				
			||||||
 | 
					    void *cb_data;
 | 
				
			||||||
 | 
					    float VAD_threshold;
 | 
				
			||||||
 | 
					    uint32_t VAD_samples_remaining;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // used only by output devices:
 | 
				
			||||||
 | 
					    uint32_t source;
 | 
				
			||||||
 | 
					    uint32_t buffers[OPENAL_BUFS];
 | 
				
			||||||
 | 
					    bool source_open;
 | 
				
			||||||
 | 
					} Device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct AudioState {
 | 
				
			||||||
 | 
					    ALCdevice *al_device[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device devices[2][MAX_DEVICES];
 | 
				
			||||||
 | 
					    uint32_t num_devices[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FrameInfo capture_frame_info;
 | 
				
			||||||
 | 
					    float input_volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // mutexes to prevent changes to input resp. output devices and al_devices
 | 
				
			||||||
 | 
					    // during poll_input iterations resp. calls to write_out;
 | 
				
			||||||
 | 
					    // mutex[input] also used to lock input_volume which poll_input writes to.
 | 
				
			||||||
 | 
					    pthread_mutex_t mutex[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: unused
 | 
				
			||||||
 | 
					    const char *default_al_device_name[2];              /* Default devices */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *al_device_names[2][MAX_OPENAL_DEVICES]; /* Available devices */
 | 
				
			||||||
 | 
					    uint32_t num_al_devices[2];
 | 
				
			||||||
 | 
					    char *current_al_device_name[2];
 | 
				
			||||||
 | 
					} AudioState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static AudioState *audio_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lock(DeviceType type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&audio_state->mutex[type]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void unlock(DeviceType type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&audio_state->mutex[type]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool thread_running = true,
 | 
				
			||||||
 | 
					            thread_paused = true;               /* Thread control */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					static void *poll_input(void *);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t sound_mode(bool stereo)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return stereo ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t sample_size(bool stereo)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return stereo ? 4 : 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError init_devices(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    audio_state = calloc(1, sizeof(AudioState));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state == NULL) {
 | 
				
			||||||
 | 
					        return de_InternalError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get_al_device_names();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (DeviceType type = input; type <= output; ++type) {
 | 
				
			||||||
 | 
					        audio_state->al_device[type] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pthread_mutex_init(&audio_state->mutex[type], NULL) != 0) {
 | 
				
			||||||
 | 
					            return de_InternalError;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    // Start poll thread
 | 
				
			||||||
 | 
					    pthread_t thread_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pthread_create(&thread_id, NULL, poll_input, NULL) != 0
 | 
				
			||||||
 | 
					            || pthread_detach(thread_id) != 0) {
 | 
				
			||||||
 | 
					        return de_InternalError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError terminate_devices(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    lock(input);
 | 
				
			||||||
 | 
					    thread_running = false;
 | 
				
			||||||
 | 
					    unlock(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sleep_thread(20000L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (DeviceType type = input; type <= output; ++type) {
 | 
				
			||||||
 | 
					        if (pthread_mutex_destroy(&audio_state->mutex[type]) != 0) {
 | 
				
			||||||
 | 
					            return de_InternalError;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (audio_state->current_al_device_name[type] != NULL) {
 | 
				
			||||||
 | 
					            free(audio_state->current_al_device_name[type]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(audio_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void get_al_device_names(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *stringed_device_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (DeviceType type = input; type <= output; ++type) {
 | 
				
			||||||
 | 
					        audio_state->num_al_devices[type] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (type == input) {
 | 
				
			||||||
 | 
					            stringed_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE) {
 | 
				
			||||||
 | 
					                stringed_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                stringed_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (stringed_device_list != NULL) {
 | 
				
			||||||
 | 
					            audio_state->default_al_device_name[type] = alcGetString(NULL,
 | 
				
			||||||
 | 
					                    type == input ? ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER : ALC_DEFAULT_DEVICE_SPECIFIER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (; *stringed_device_list != '\0'
 | 
				
			||||||
 | 
					                    && audio_state->num_al_devices[type] < MAX_OPENAL_DEVICES; ++audio_state->num_al_devices[type]) {
 | 
				
			||||||
 | 
					                audio_state->al_device_names[type][audio_state->num_al_devices[type]] = stringed_device_list;
 | 
				
			||||||
 | 
					                stringed_device_list += strlen(stringed_device_list) + 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError device_mute(DeviceType type, uint32_t device_idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[type][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return de_DeviceNotActive;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device->muted = !device->muted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(type);
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool device_is_muted(DeviceType type, uint32_t device_idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[type][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return device->muted;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError device_set_VAD_threshold(uint32_t device_idx, float value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[input][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return de_DeviceNotActive;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value <= 0.0f) {
 | 
				
			||||||
 | 
					        value = 0.0f;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device->VAD_threshold = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(input);
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float device_get_VAD_threshold(uint32_t device_idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return 0.0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[input][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return 0.0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return device->VAD_threshold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError set_source_position(uint32_t device_idx, float x, float y, float z)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[output][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return de_DeviceNotActive;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alSource3f(device->source, AL_POSITION, x, y, z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!audio_state->al_device[output] || alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        return de_AlError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DeviceError close_al_device(DeviceType type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (audio_state->al_device[type] == NULL) {
 | 
				
			||||||
 | 
					        return de_None;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == input) {
 | 
				
			||||||
 | 
					        if (!alcCaptureCloseDevice(audio_state->al_device[type])) {
 | 
				
			||||||
 | 
					            return de_AlError;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread_paused = true;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ALCcontext *context = alcGetCurrentContext();
 | 
				
			||||||
 | 
					        alcMakeContextCurrent(NULL);
 | 
				
			||||||
 | 
					        alcDestroyContext(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!alcCloseDevice(audio_state->al_device[type])) {
 | 
				
			||||||
 | 
					            return de_AlError;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    audio_state->al_device[type] = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DeviceError open_al_device(DeviceType type, FrameInfo frame_info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    audio_state->al_device[type] = type == input
 | 
				
			||||||
 | 
					                                   ? alcCaptureOpenDevice(audio_state->current_al_device_name[type],
 | 
				
			||||||
 | 
					                                           frame_info.sample_rate, sound_mode(frame_info.stereo), frame_info.samples_per_frame * 2)
 | 
				
			||||||
 | 
					                                   : alcOpenDevice(audio_state->current_al_device_name[type]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->al_device[type] == NULL) {
 | 
				
			||||||
 | 
					        return de_FailedStart;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == input) {
 | 
				
			||||||
 | 
					        alcCaptureStart(audio_state->al_device[type]);
 | 
				
			||||||
 | 
					        thread_paused = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        audio_state->capture_frame_info = frame_info;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        alcMakeContextCurrent(alcCreateContext(audio_state->al_device[type], NULL));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (alcGetError(audio_state->al_device[type]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        close_al_device(type);
 | 
				
			||||||
 | 
					        return de_AlError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void close_source(Device *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device->source_open) {
 | 
				
			||||||
 | 
					        alDeleteSources(1, &device->source);
 | 
				
			||||||
 | 
					        alDeleteBuffers(OPENAL_BUFS, device->buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        device->source_open = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DeviceError open_source(Device *device)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    alGenBuffers(OPENAL_BUFS, device->buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        return de_FailedStart;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alGenSources((uint32_t)1, &device->source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        alDeleteBuffers(OPENAL_BUFS, device->buffers);
 | 
				
			||||||
 | 
					        return de_FailedStart;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device->source_open = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alSourcei(device->source, AL_LOOPING, AL_FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
 | 
				
			||||||
 | 
					    size_t zeros_size = frame_size * sizeof(uint16_t);
 | 
				
			||||||
 | 
					    uint16_t *zeros = calloc(1, zeros_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (zeros == NULL) {
 | 
				
			||||||
 | 
					        close_source(device);
 | 
				
			||||||
 | 
					        return de_FailedStart;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < OPENAL_BUFS; ++i) {
 | 
				
			||||||
 | 
					        alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
 | 
				
			||||||
 | 
					                     zeros_size, device->frame_info.sample_rate);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(zeros);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alSourceQueueBuffers(device->source, OPENAL_BUFS, device->buffers);
 | 
				
			||||||
 | 
					    alSourcePlay(device->source);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        close_source(device);
 | 
				
			||||||
 | 
					        return de_FailedStart;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError set_al_device(DeviceType type, int32_t selection)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (audio_state->num_al_devices[type] <= selection || selection < 0) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *name = audio_state->al_device_names[type][selection];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char **cur_name = &audio_state->current_al_device_name[type];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*cur_name != NULL) {
 | 
				
			||||||
 | 
					        free(*cur_name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *cur_name = malloc(strlen(name) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*cur_name == NULL) {
 | 
				
			||||||
 | 
					        return de_InternalError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(*cur_name, name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->num_devices[type] > 0) {
 | 
				
			||||||
 | 
					        // close any existing al_device and try to open new one, reopening existing sources
 | 
				
			||||||
 | 
					        lock(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (type == output) {
 | 
				
			||||||
 | 
					            for (int i = 0; i < MAX_DEVICES; i++) {
 | 
				
			||||||
 | 
					                Device *device = &audio_state->devices[type][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (device->active) {
 | 
				
			||||||
 | 
					                    close_source(device);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        close_al_device(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DeviceError err = open_al_device(type, audio_state->capture_frame_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != de_None) {
 | 
				
			||||||
 | 
					            unlock(type);
 | 
				
			||||||
 | 
					            return err;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (type == output) {
 | 
				
			||||||
 | 
					            for (int i = 0; i < MAX_DEVICES; i++) {
 | 
				
			||||||
 | 
					                Device *device = &audio_state->devices[type][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (device->active) {
 | 
				
			||||||
 | 
					                    open_source(device);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unlock(type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DeviceError open_device(DeviceType type, uint32_t *device_idx,
 | 
				
			||||||
 | 
					                               DataHandleCallback cb, void *cb_data, bool enable_VAD,
 | 
				
			||||||
 | 
					                               uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (channels != 1 && channels != 2) {
 | 
				
			||||||
 | 
					        return de_UnsupportedMode;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const uint32_t samples_per_frame = (sample_rate * frame_duration / 1000);
 | 
				
			||||||
 | 
					    FrameInfo frame_info = {samples_per_frame, sample_rate, channels == 2};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < MAX_DEVICES && audio_state->devices[type][i].active; ++i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (i == MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_AllDevicesBusy;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *device_idx = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->al_device[type] == NULL) {
 | 
				
			||||||
 | 
					        DeviceError err = open_al_device(type, frame_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != de_None) {
 | 
				
			||||||
 | 
					            unlock(type);
 | 
				
			||||||
 | 
					            return err;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (type == input) {
 | 
				
			||||||
 | 
					        // Use previously set frame info on existing capture device
 | 
				
			||||||
 | 
					        frame_info = audio_state->capture_frame_info;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[type][i];
 | 
				
			||||||
 | 
					    device->active = true;
 | 
				
			||||||
 | 
					    ++audio_state->num_devices[type];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device->muted = false;
 | 
				
			||||||
 | 
					    device->frame_info = frame_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == input) {
 | 
				
			||||||
 | 
					        device->cb = cb;
 | 
				
			||||||
 | 
					        device->cb_data = cb_data;
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					        device->VAD_threshold = enable_VAD ? user_settings->VAD_threshold : 0.0f;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        device->VAD_threshold = 0.0f;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        if (open_source(device) != de_None) {
 | 
				
			||||||
 | 
					            device->active = false;
 | 
				
			||||||
 | 
					            --audio_state->num_devices[type];
 | 
				
			||||||
 | 
					            unlock(type);
 | 
				
			||||||
 | 
					            return de_FailedStart;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(type);
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError open_input_device(uint32_t *device_idx,
 | 
				
			||||||
 | 
					                              DataHandleCallback cb, void *cb_data, bool enable_VAD,
 | 
				
			||||||
 | 
					                              uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return open_device(input, device_idx,
 | 
				
			||||||
 | 
					                       cb, cb_data, enable_VAD,
 | 
				
			||||||
 | 
					                       sample_rate, frame_duration, channels);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError open_output_device(uint32_t *device_idx,
 | 
				
			||||||
 | 
					                               uint32_t sample_rate, uint32_t frame_duration, uint8_t channels)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return open_device(output, device_idx,
 | 
				
			||||||
 | 
					                       0, 0, 0,
 | 
				
			||||||
 | 
					                       sample_rate, frame_duration, channels);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError close_device(DeviceType type, uint32_t device_idx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[type][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active) {
 | 
				
			||||||
 | 
					        return de_DeviceNotActive;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == output) {
 | 
				
			||||||
 | 
					        close_source(device);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    device->active = false;
 | 
				
			||||||
 | 
					    --audio_state->num_devices[type];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DeviceError err = de_None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->num_devices[type] == 0) {
 | 
				
			||||||
 | 
					        err = close_al_device(type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(type);
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t sample_count, uint8_t channels,
 | 
				
			||||||
 | 
					                      uint32_t sample_rate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (device_idx >= MAX_DEVICES) {
 | 
				
			||||||
 | 
					        return de_InvalidSelection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lock(output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Device *device = &audio_state->devices[output][device_idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!device->active || device->muted) {
 | 
				
			||||||
 | 
					        unlock(output);
 | 
				
			||||||
 | 
					        return de_DeviceNotActive;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ALuint bufid;
 | 
				
			||||||
 | 
					    ALint processed, queued;
 | 
				
			||||||
 | 
					    alGetSourcei(device->source, AL_BUFFERS_PROCESSED, &processed);
 | 
				
			||||||
 | 
					    alGetSourcei(device->source, AL_BUFFERS_QUEUED, &queued);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->al_device[output] == NULL || alcGetError(audio_state->al_device[output]) != AL_NO_ERROR) {
 | 
				
			||||||
 | 
					        unlock(output);
 | 
				
			||||||
 | 
					        return de_AlError;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (processed) {
 | 
				
			||||||
 | 
					        ALuint *bufids = malloc(processed * sizeof(ALuint));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (bufids == NULL) {
 | 
				
			||||||
 | 
					            unlock(output);
 | 
				
			||||||
 | 
					            return de_InternalError;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        alSourceUnqueueBuffers(device->source, processed, bufids);
 | 
				
			||||||
 | 
					        alDeleteBuffers(processed - 1, bufids + 1);
 | 
				
			||||||
 | 
					        bufid = bufids[0];
 | 
				
			||||||
 | 
					        free(bufids);
 | 
				
			||||||
 | 
					    } else if (queued < 16) {
 | 
				
			||||||
 | 
					        alGenBuffers(1, &bufid);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        unlock(output);
 | 
				
			||||||
 | 
					        return de_Busy;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const bool stereo = channels == 2;
 | 
				
			||||||
 | 
					    alBufferData(bufid, sound_mode(stereo), data,
 | 
				
			||||||
 | 
					                 sample_count * sample_size(stereo),
 | 
				
			||||||
 | 
					                 sample_rate);
 | 
				
			||||||
 | 
					    alSourceQueueBuffers(device->source, 1, &bufid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ALint state;
 | 
				
			||||||
 | 
					    alGetSourcei(device->source, AL_SOURCE_STATE, &state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state != AL_PLAYING) {
 | 
				
			||||||
 | 
					        alSourcePlay(device->source);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unlock(output);
 | 
				
			||||||
 | 
					    return de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					/* Adapted from qtox,
 | 
				
			||||||
 | 
					 * Copyright © 2014-2019 by The qTox Project Contributors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * return normalized volume of buffer in range 0.0-100.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					float volume(int16_t *frame, uint32_t samples)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    float sum_of_squares = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (uint32_t i = 0; i < samples; i++) {
 | 
				
			||||||
 | 
					        const float sample = (float)(frame[i]) / INT16_MAX;
 | 
				
			||||||
 | 
					        sum_of_squares += powf(sample, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const float root_mean_square = sqrtf(sum_of_squares / samples);
 | 
				
			||||||
 | 
					    const float root_two = 1.414213562;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // normalizedVolume == 1.0 corresponds to a sine wave of maximal amplitude
 | 
				
			||||||
 | 
					    const float normalized_volume = root_mean_square * root_two;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 100.0f * fminf(1.0f, normalized_volume);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Time in ms for which we continue to capture audio after VAD is triggered:
 | 
				
			||||||
 | 
					#define VAD_TIME 250
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FRAME_BUF_SIZE 16000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *poll_input(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int16_t *frame_buf = malloc(FRAME_BUF_SIZE * sizeof(int16_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (frame_buf == NULL) {
 | 
				
			||||||
 | 
					        exit_toxic_err("failed in thread_poll", FATALERR_MEMORY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (1) {
 | 
				
			||||||
 | 
					        lock(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!thread_running) {
 | 
				
			||||||
 | 
					            free(frame_buf);
 | 
				
			||||||
 | 
					            unlock(input);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (thread_paused) {
 | 
				
			||||||
 | 
					            unlock(input);
 | 
				
			||||||
 | 
					            sleep_thread(10000L);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (audio_state->al_device[input] != NULL) {
 | 
				
			||||||
 | 
					            int32_t available_samples;
 | 
				
			||||||
 | 
					            alcGetIntegerv(audio_state->al_device[input], ALC_CAPTURE_SAMPLES, sizeof(int32_t), &available_samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const uint32_t f_size = audio_state->capture_frame_info.samples_per_frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (available_samples >= f_size && f_size <= FRAME_BUF_SIZE) {
 | 
				
			||||||
 | 
					                alcCaptureSamples(audio_state->al_device[input], frame_buf, f_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                unlock(input);
 | 
				
			||||||
 | 
					                pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
 | 
					                lock(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                float frame_volume = volume(frame_buf, f_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                audio_state->input_volume = frame_volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (int i = 0; i < MAX_DEVICES; i++) {
 | 
				
			||||||
 | 
					                    Device *device = &audio_state->devices[input][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (device->VAD_threshold != 0.0f) {
 | 
				
			||||||
 | 
					                        if (frame_volume >= device->VAD_threshold) {
 | 
				
			||||||
 | 
					                            device->VAD_samples_remaining = VAD_TIME * (audio_state->capture_frame_info.sample_rate / 1000);
 | 
				
			||||||
 | 
					                        } else if (device->VAD_samples_remaining < f_size) {
 | 
				
			||||||
 | 
					                            continue;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            device->VAD_samples_remaining -= f_size;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (device->active && !device->muted && device->cb) {
 | 
				
			||||||
 | 
					                        device->cb(frame_buf, f_size, device->cb_data);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unlock(input);
 | 
				
			||||||
 | 
					        sleep_thread(5000L);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_exit(NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float get_input_volume(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    float ret = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (audio_state->al_device[input] != NULL) {
 | 
				
			||||||
 | 
					        lock(input);
 | 
				
			||||||
 | 
					        ret = audio_state->input_volume;
 | 
				
			||||||
 | 
					        unlock(input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_al_devices(ToxWindow *self, DeviceType type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (int i = 0; i < audio_state->num_al_devices[type]; ++i) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG,
 | 
				
			||||||
 | 
					                      audio_state->current_al_device_name[type]
 | 
				
			||||||
 | 
					                      && strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0,
 | 
				
			||||||
 | 
					                      0, "%d: %s", i, audio_state->al_device_names[type][i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError selection_valid(DeviceType type, int32_t selection)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return (audio_state->num_al_devices[type] <= selection || selection < 0) ? de_InvalidSelection : de_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										97
									
								
								src/audio_device.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/audio_device.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					/*  audio_device.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * You can have multiple sources (Input devices) but only one output device.
 | 
				
			||||||
 | 
					 * Pass buffers to output device via write();
 | 
				
			||||||
 | 
					 * Read from running input device(s) via select()/callback combo.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef AUDIO_DEVICE_H
 | 
				
			||||||
 | 
					#define AUDIO_DEVICE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OPENAL_BUFS 5
 | 
				
			||||||
 | 
					#define MAX_OPENAL_DEVICES 32
 | 
				
			||||||
 | 
					#define MAX_DEVICES 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum DeviceType {
 | 
				
			||||||
 | 
					    input,
 | 
				
			||||||
 | 
					    output,
 | 
				
			||||||
 | 
					} DeviceType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum DeviceError {
 | 
				
			||||||
 | 
					    de_None,
 | 
				
			||||||
 | 
					    de_InternalError = -1,
 | 
				
			||||||
 | 
					    de_InvalidSelection = -2,
 | 
				
			||||||
 | 
					    de_FailedStart = -3,
 | 
				
			||||||
 | 
					    de_Busy = -4,
 | 
				
			||||||
 | 
					    de_AllDevicesBusy = -5,
 | 
				
			||||||
 | 
					    de_DeviceNotActive = -6,
 | 
				
			||||||
 | 
					    de_BufferError = -7,
 | 
				
			||||||
 | 
					    de_UnsupportedMode = -8,
 | 
				
			||||||
 | 
					    de_AlError = -9,
 | 
				
			||||||
 | 
					} DeviceError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef void (*DataHandleCallback)(const int16_t *, uint32_t size, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError init_devices(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void get_al_device_names(void);
 | 
				
			||||||
 | 
					DeviceError terminate_devices(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* toggle device mute */
 | 
				
			||||||
 | 
					DeviceError device_mute(DeviceType type, uint32_t device_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool device_is_muted(DeviceType type, uint32_t device_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError device_set_VAD_threshold(uint32_t device_idx, float value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float device_get_VAD_threshold(uint32_t device_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError set_source_position(uint32_t device_idx, float x, float y, float z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError set_al_device(DeviceType type, int32_t selection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Start device */
 | 
				
			||||||
 | 
					DeviceError open_input_device(uint32_t *device_idx,
 | 
				
			||||||
 | 
					                              DataHandleCallback cb, void *cb_data, bool enable_VAD,
 | 
				
			||||||
 | 
					                              uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
 | 
				
			||||||
 | 
					DeviceError open_output_device(uint32_t *device_idx,
 | 
				
			||||||
 | 
					                               uint32_t sample_rate, uint32_t frame_duration, uint8_t channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Stop device */
 | 
				
			||||||
 | 
					DeviceError close_device(DeviceType type, uint32_t device_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Write data to output device */
 | 
				
			||||||
 | 
					DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_t length, uint8_t channels,
 | 
				
			||||||
 | 
					                      uint32_t sample_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* return current input volume as float in range 0.0-100.0 */
 | 
				
			||||||
 | 
					float get_input_volume(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void print_al_devices(ToxWindow *self, DeviceType type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DeviceError selection_valid(DeviceType type, int32_t selection);
 | 
				
			||||||
 | 
					#endif /* AUDIO_DEVICE_H */
 | 
				
			||||||
							
								
								
									
										393
									
								
								src/autocomplete.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								src/autocomplete.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,393 @@
 | 
				
			|||||||
 | 
					/*  autocomplete.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __APPLE__
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/dir.h>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <dirent.h>
 | 
				
			||||||
 | 
					#endif /* __APPLE__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "configdir.h"
 | 
				
			||||||
 | 
					#include "execute.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matches)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (m) {
 | 
				
			||||||
 | 
					        execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < n_matches; ++i) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* puts match in match buffer. if more than one match, add first n chars that are identical.
 | 
				
			||||||
 | 
					 * e.g. if matches contains: [foo, foobar, foe] we put fo in match.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the length of the match.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, const char **matches, size_t n_items,
 | 
				
			||||||
 | 
					                            size_t max_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (n_items == 1) {
 | 
				
			||||||
 | 
					        return snprintf(match, match_sz, "%s", matches[0]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < max_size; ++i) {
 | 
				
			||||||
 | 
					        char ch1 = matches[0][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (size_t j = 0; j < n_items; ++j) {
 | 
				
			||||||
 | 
					            char ch2 = matches[j][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (ch1 != ch2 || !ch1) {
 | 
				
			||||||
 | 
					                snprintf(match, match_sz, "%s", matches[0]);
 | 
				
			||||||
 | 
					                match[i] = '\0';
 | 
				
			||||||
 | 
					                return i;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return snprintf(match, match_sz, "%s", matches[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Looks for all instances in list that begin with the last entered word in line according to pos,
 | 
				
			||||||
 | 
					 * then fills line with the complete word. e.g. "Hello jo" would complete the line
 | 
				
			||||||
 | 
					 * with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * dir_search should be true if the line being completed is a file path.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the difference between the old len and new len of line on success.
 | 
				
			||||||
 | 
					 * Returns -1 on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: This function should not be called directly. Use complete_line() and complete_path() instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int complete_line_helper(ToxWindow *self, const char **list, const size_t n_items, bool dir_search)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos <= 0 || ctx->len <= 0 || ctx->pos > ctx->len) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->len >= MAX_STR_SIZE) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *endchrs = " ";
 | 
				
			||||||
 | 
					    char ubuf[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* work with multibyte string copy of buf for simplicity */
 | 
				
			||||||
 | 
					    if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* isolate substring from space behind pos to pos */
 | 
				
			||||||
 | 
					    char tmp[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    memcpy(tmp, ubuf, ctx->pos);
 | 
				
			||||||
 | 
					    tmp[ctx->pos] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
 | 
				
			||||||
 | 
					    char *sub = calloc(1, strlen(ubuf) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (sub == NULL) {
 | 
				
			||||||
 | 
					        exit_toxic_err("failed in complete_line_helper", FATALERR_MEMORY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!s && !dir_search) {
 | 
				
			||||||
 | 
					        strcpy(sub, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (sub[0] != '/') {
 | 
				
			||||||
 | 
					            endchrs = ": ";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (s) {
 | 
				
			||||||
 | 
					        strcpy(sub, &s[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (dir_search) {
 | 
				
			||||||
 | 
					            int sub_len = strlen(sub);
 | 
				
			||||||
 | 
					            int si = char_rfind(sub, '/', sub_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (si || *sub == '/') {
 | 
				
			||||||
 | 
					                memmove(sub, &sub[si + 1], sub_len - si);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!sub[0] && !(dir_search && n_items == 1)) {
 | 
				
			||||||
 | 
					        free(sub);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int s_len = strlen(sub);
 | 
				
			||||||
 | 
					    size_t n_matches = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (matches == NULL) {
 | 
				
			||||||
 | 
					        free(sub);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* put all list matches in matches array */
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < n_items; ++i) {
 | 
				
			||||||
 | 
					        if (strncasecmp(list[i], sub, s_len) == 0) {
 | 
				
			||||||
 | 
					            snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(sub);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!n_matches) {
 | 
				
			||||||
 | 
					        free_ptr_array((void **) matches);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!dir_search && n_matches > 1) {
 | 
				
			||||||
 | 
					        print_ac_matches(self, NULL, matches, n_matches);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char match[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    size_t match_len = get_str_match(self, match, sizeof(match), (const char **) matches, n_matches, MAX_STR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_ptr_array((void **) matches);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (match_len == 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dir_search) {
 | 
				
			||||||
 | 
					        if (n_matches == 1) {
 | 
				
			||||||
 | 
					            endchrs = char_rfind(match, '.', match_len) ? "" : "/";
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            endchrs = "";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (n_matches > 1) {
 | 
				
			||||||
 | 
					        endchrs = "";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* put match in correct spot in buf and append endchars */
 | 
				
			||||||
 | 
					    int n_endchrs = strlen(endchrs);
 | 
				
			||||||
 | 
					    int strt = ctx->pos - s_len;
 | 
				
			||||||
 | 
					    int diff = match_len - s_len + n_endchrs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->len + diff >= MAX_STR_SIZE) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char tmpend[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    snprintf(tmpend, sizeof(tmpend), "%s", &ubuf[ctx->pos]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (match_len + n_endchrs + strlen(tmpend) >= sizeof(ubuf)) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(&ubuf[strt], match);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If path points to a file with no extension don't append a forward slash */
 | 
				
			||||||
 | 
					    if (dir_search && *endchrs == '/') {
 | 
				
			||||||
 | 
					        const char *path_start = strchr(ubuf + 1, '/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!path_start) {
 | 
				
			||||||
 | 
					            path_start = strchr(ubuf + 1, ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!path_start) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (strlen(path_start) < 2) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ++path_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (file_type(path_start) == FILE_TYPE_REGULAR) {
 | 
				
			||||||
 | 
					            endchrs = "";
 | 
				
			||||||
 | 
					            diff -= n_endchrs;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(&ubuf[strt + match_len], endchrs);
 | 
				
			||||||
 | 
					    strcpy(&ubuf[strt + match_len + n_endchrs], tmpend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* convert to widechar and copy back to original buf */
 | 
				
			||||||
 | 
					    wchar_t newbuf[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mbs_to_wcs_buf(newbuf, ubuf, sizeof(newbuf) / sizeof(wchar_t)) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wcscpy(ctx->line, newbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ctx->len += diff;
 | 
				
			||||||
 | 
					    ctx->pos += diff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return diff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int complete_line(ToxWindow *self, const char **list, size_t n_items)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return complete_line_helper(self, list, n_items, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int complete_path(ToxWindow *self, const char **list, const size_t n_items)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return complete_line_helper(self, list, n_items, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
 | 
				
			||||||
 | 
					static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char homedir[MAX_STR_SIZE] = {0};
 | 
				
			||||||
 | 
					    get_home_dir(homedir, sizeof(homedir));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char newline[MAX_STR_SIZE + 1];
 | 
				
			||||||
 | 
					    snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1);
 | 
				
			||||||
 | 
					    snprintf(path, pathsize, "%s", &newline[cmdlen - 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wchar_t wline[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mbs_to_wcs_buf(wline, newline, sizeof(wline) / sizeof(wchar_t)) == -1) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int newlen = wcslen(wline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->len + newlen >= MAX_STR_SIZE) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmemcpy(ctx->line, wline, newlen + 1);
 | 
				
			||||||
 | 
					    ctx->pos = newlen;
 | 
				
			||||||
 | 
					    ctx->len = ctx->pos;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Return true if the first `p_len` chars in `s` are equal to `p` and `s` is a valid directory name.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool is_partial_match(const char *s, const char *p, size_t p_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (s == NULL || p == NULL) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return strncmp(s, p, p_len) == 0 && strcmp(".", s) != 0 && strcmp("..", s) != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Attempts to match /command "<incomplete-dir>" line to matching directories.
 | 
				
			||||||
 | 
					 * If there is only one match the line is auto-completed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the diff between old len and new len of ctx->line on success.
 | 
				
			||||||
 | 
					 * Returns -1 if no matches or more than one match.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MAX_DIRS 75
 | 
				
			||||||
 | 
					int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char b_path[MAX_STR_SIZE + 1];
 | 
				
			||||||
 | 
					    char b_name[MAX_STR_SIZE + 1];
 | 
				
			||||||
 | 
					    char b_cmd[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    const wchar_t *tmpline = &line[wcslen(cmd) + 1];   /* start after "/command " */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path) - 1) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wcs_to_mbs_buf(b_cmd, cmd, sizeof(b_cmd)) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (b_path[0] == '~') {
 | 
				
			||||||
 | 
					        complete_home_dir(self, b_path, sizeof(b_path) - 1, b_cmd, strlen(b_cmd) + 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int si = char_rfind(b_path, '/', strlen(b_path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!b_path[0]) {    /* list everything in pwd */
 | 
				
			||||||
 | 
					        b_path[0] = '.';
 | 
				
			||||||
 | 
					        b_path[1] = '\0';
 | 
				
			||||||
 | 
					    } else if (!si && b_path[0] != '/') {    /* look for matches in pwd */
 | 
				
			||||||
 | 
					        memmove(b_path + 1, b_path, sizeof(b_path) - 1);
 | 
				
			||||||
 | 
					        b_path[0] = '.';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(b_name, sizeof(b_name), "%s", &b_path[si + 1]);
 | 
				
			||||||
 | 
					    b_path[si + 1] = '\0';
 | 
				
			||||||
 | 
					    size_t b_name_len = strlen(b_name);
 | 
				
			||||||
 | 
					    DIR *dp = opendir(b_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dp == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char **dirnames = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dirnames == NULL) {
 | 
				
			||||||
 | 
					        closedir(dp);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct dirent *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int dircount = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
 | 
				
			||||||
 | 
					        if (is_partial_match(entry->d_name, b_name, b_name_len)) {
 | 
				
			||||||
 | 
					            snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
 | 
				
			||||||
 | 
					            ++dircount;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closedir(dp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dircount == 0) {
 | 
				
			||||||
 | 
					        free_ptr_array((void **) dirnames);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dircount > 1) {
 | 
				
			||||||
 | 
					        qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
 | 
				
			||||||
 | 
					        print_ac_matches(self, m, dirnames, dircount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = complete_path(self, (const char **) dirnames, dircount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free_ptr_array((void **) dirnames);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								src/autocomplete.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/autocomplete.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					/*  autocomplete.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef AUTOCOMPLETE_H
 | 
				
			||||||
 | 
					#define AUTOCOMPLETE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Looks for all instances in list that begin with the last entered word in line according to pos,
 | 
				
			||||||
 | 
					 * then fills line with the complete word. e.g. "Hello jo" would complete the line
 | 
				
			||||||
 | 
					 * with "Hello john". If multiple matches, prints out all the matches and semi-completes line.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					* `list` is a pointer to `n_items` strings.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * dir_search should be true if the line being completed is a file path.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the difference between the old len and new len of line on success.
 | 
				
			||||||
 | 
					 * Returns -1 on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: This function should not be called directly. Use complete_line() and complete_path() instead.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int complete_line(ToxWindow *self, const char **list, size_t n_items);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Attempts to match /command "<incomplete-dir>" line to matching directories.
 | 
				
			||||||
 | 
					 * If there is only one match the line is auto-completed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the diff between old len and new len of ctx->line on success.
 | 
				
			||||||
 | 
					 * Returns -1 if no matches or more than one match.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* AUTOCOMPLETE_H */
 | 
				
			||||||
							
								
								
									
										262
									
								
								src/avatars.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/avatars.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
				
			|||||||
 | 
					/*  avatars.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2015 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "avatars.h"
 | 
				
			||||||
 | 
					#include "file_transfers.h"
 | 
				
			||||||
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern FriendsList Friends;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct Avatar {
 | 
				
			||||||
 | 
					    char name[TOX_MAX_FILENAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    size_t name_len;
 | 
				
			||||||
 | 
					    char path[PATH_MAX + 1];
 | 
				
			||||||
 | 
					    size_t path_len;
 | 
				
			||||||
 | 
					    off_t size;
 | 
				
			||||||
 | 
					} Avatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Compares the first size bytes of fp to signature.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 if they are the same
 | 
				
			||||||
 | 
					 * Returns 1 if they differ
 | 
				
			||||||
 | 
					 * Returns -1 on error.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * On success this function will seek back to the beginning of fp.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int check_file_signature(const unsigned char *signature, size_t size, FILE *fp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *buf = malloc(size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (buf == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fread(buf, size, 1, fp) != 1) {
 | 
				
			||||||
 | 
					        free(buf);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = memcmp(signature, buf, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fseek(fp, 0L, SEEK_SET) == -1) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ret == 0 ? 0 : 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void avatar_clear(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Avatar = (struct Avatar) {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sends avatar to friendnumber.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int avatar_send(Tox *m, uint32_t friendnumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Tox_Err_File_Send err;
 | 
				
			||||||
 | 
					    uint32_t filenumber = tox_file_send(m, friendnumber, TOX_FILE_KIND_AVATAR, (size_t) Avatar.size,
 | 
				
			||||||
 | 
					                                        NULL, (uint8_t *) Avatar.name, Avatar.name_len, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (Avatar.size == 0) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err != TOX_ERR_FILE_SEND_OK) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "tox_file_send failed for friendnumber %u (error %d)\n", friendnumber, err);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct FileTransfer *ft = new_file_transfer(NULL, friendnumber, filenumber, FILE_TRANSFER_SEND, TOX_FILE_KIND_AVATAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!ft) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ft->file = fopen(Avatar.path, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ft->file == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(ft->file_name, sizeof(ft->file_name), "%s", Avatar.name);
 | 
				
			||||||
 | 
					    ft->file_size = Avatar.size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sends avatar to all friends */
 | 
				
			||||||
 | 
					static void avatar_send_all(Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < Friends.max_idx; ++i) {
 | 
				
			||||||
 | 
					        if (Friends.list[i].connection_status != TOX_CONNECTION_NONE) {
 | 
				
			||||||
 | 
					            avatar_send(m, Friends.list[i].num);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sets avatar to path and sends it to all online contacts.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int avatar_set(Tox *m, const char *path, size_t path_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (path_len == 0 || path_len >= sizeof(Avatar.path)) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE *fp = fopen(path, "rb");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fp == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned char PNG_signature[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (check_file_signature(PNG_signature, sizeof(PNG_signature), fp) != 0) {
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    off_t size = file_size(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (size == 0 || size > MAX_AVATAR_FILE_SIZE) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get_file_name(Avatar.name, sizeof(Avatar.name), path);
 | 
				
			||||||
 | 
					    Avatar.name_len = strlen(Avatar.name);
 | 
				
			||||||
 | 
					    snprintf(Avatar.path, sizeof(Avatar.path), "%s", path);
 | 
				
			||||||
 | 
					    Avatar.path_len = path_len;
 | 
				
			||||||
 | 
					    Avatar.size = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    avatar_send_all(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Unsets avatar and sends to all online contacts.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void avatar_unset(Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    avatar_clear();
 | 
				
			||||||
 | 
					    avatar_send_all(m);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (connection_status == TOX_CONNECTION_NONE) {
 | 
				
			||||||
 | 
					        kill_avatar_file_transfers_friend(m, friendnumber);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (control) {
 | 
				
			||||||
 | 
					        case TOX_FILE_CONTROL_RESUME:
 | 
				
			||||||
 | 
					            if (ft->state == FILE_TRANSFER_PENDING) {
 | 
				
			||||||
 | 
					                ft->state = FILE_TRANSFER_STARTED;
 | 
				
			||||||
 | 
					            } else if (ft->state == FILE_TRANSFER_PAUSED) {
 | 
				
			||||||
 | 
					                ft->state = FILE_TRANSFER_STARTED;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_FILE_CONTROL_PAUSE:
 | 
				
			||||||
 | 
					            ft->state = FILE_TRANSFER_PAUSED;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_FILE_CONTROL_CANCEL:
 | 
				
			||||||
 | 
					            close_file_transfer(NULL, m, ft, -1, NULL, silent);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ft->state != FILE_TRANSFER_STARTED) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (length == 0) {
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, ft, -1, NULL, silent);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ft->file == NULL) {
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ft->position != position) {
 | 
				
			||||||
 | 
					        if (fseek(ft->file, position, SEEK_SET) == -1) {
 | 
				
			||||||
 | 
					            close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ft->position = position;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t *send_data = malloc(length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (send_data == NULL) {
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t send_length = fread(send_data, 1, length, ft->file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (send_length != length) {
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					        free(send_data);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Tox_Err_File_Send_Chunk err;
 | 
				
			||||||
 | 
					    tox_file_send_chunk(m, ft->friendnumber, ft->filenumber, position, send_data, send_length, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(send_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err != TOX_ERR_FILE_SEND_CHUNK_OK) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "tox_file_send_chunk failed in avatar callback (error %d)\n", err);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ft->position += send_length;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/avatars.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/avatars.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					/*  avatars.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2015 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef AVATARS_H
 | 
				
			||||||
 | 
					#define AVATARS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "file_transfers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_AVATAR_FILE_SIZE 65536
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sends avatar to friendnum.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int avatar_send(Tox *m, uint32_t friendnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sets avatar to path and sends it to all online contacts.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int avatar_set(Tox *m, const char *path, size_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Unsets avatar and sends to all online contacts.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void avatar_unset(Tox *m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void on_avatar_chunk_request(Tox *m, struct FileTransfer *ft, uint64_t position, size_t length);
 | 
				
			||||||
 | 
					void on_avatar_file_control(Tox *m, struct FileTransfer *ft, Tox_File_Control control);
 | 
				
			||||||
 | 
					void on_avatar_friend_connection_status(Tox *m, uint32_t friendnumber, Tox_Connection connection_status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* AVATARS_H */
 | 
				
			||||||
							
								
								
									
										635
									
								
								src/bootstrap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										635
									
								
								src/bootstrap.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,635 @@
 | 
				
			|||||||
 | 
					/*  bootstrap.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2016 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <curl/curl.h>
 | 
				
			||||||
 | 
					#include <tox/tox.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "configdir.h"
 | 
				
			||||||
 | 
					#include "curl_util.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "prompt.h"
 | 
				
			||||||
 | 
					#include "settings.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct arg_opts arg_opts;
 | 
				
			||||||
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
 | 
					extern struct Winthread Winthread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* URL that we get the JSON encoded nodes list from. */
 | 
				
			||||||
 | 
					#define NODES_LIST_URL "https://nodes.tox.chat/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_NODES_FILENAME "DHTnodes.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Time to wait between bootstrap attempts */
 | 
				
			||||||
 | 
					#define TRY_BOOTSTRAP_INTERVAL 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Number of nodes to bootstrap to per try */
 | 
				
			||||||
 | 
					#define NUM_BOOTSTRAP_NODES 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Number of seconds since last successful ping before we consider a node offline */
 | 
				
			||||||
 | 
					#define NODE_OFFLINE_TIMOUT (60*60*24*2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IP_MAX_SIZE 45
 | 
				
			||||||
 | 
					#define IP_MIN_SIZE 7
 | 
				
			||||||
 | 
					#define PORT_MAX_SIZE 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LAST_SCAN_JSON_KEY "\"last_scan\":"
 | 
				
			||||||
 | 
					#define LAST_SCAN_JSON_KEY_LEN (sizeof(LAST_SCAN_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IPV4_JSON_KEY "\"ipv4\":\""
 | 
				
			||||||
 | 
					#define IPV4_JSON_KEY_LEN (sizeof(IPV4_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IPV6_JSON_KEY "\"ipv6\":\""
 | 
				
			||||||
 | 
					#define IPV6_JSON_KEY_LEN (sizeof(IPV6_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PORT_JSON_KEY "\"port\":"
 | 
				
			||||||
 | 
					#define PORT_JSON_KEY_LEN (sizeof(PORT_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PK_JSON_KEY "\"public_key\":\""
 | 
				
			||||||
 | 
					#define PK_JSON_KEY_LEN (sizeof(PK_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LAST_PING_JSON_KEY "\"last_ping\":"
 | 
				
			||||||
 | 
					#define LAST_PING_JSON_KEY_LEN (sizeof(LAST_PING_JSON_KEY) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Maximum allowable size of the nodes list */
 | 
				
			||||||
 | 
					#define MAX_NODELIST_SIZE (MAX_RECV_CURL_DATA_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct Thread_Data {
 | 
				
			||||||
 | 
					    pthread_t tid;
 | 
				
			||||||
 | 
					    pthread_attr_t attr;
 | 
				
			||||||
 | 
					    pthread_mutex_t lock;
 | 
				
			||||||
 | 
					    volatile bool active;
 | 
				
			||||||
 | 
					} thread_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_NODES 50
 | 
				
			||||||
 | 
					struct Node {
 | 
				
			||||||
 | 
					    char ip4[IP_MAX_SIZE + 1];
 | 
				
			||||||
 | 
					    bool have_ip4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char ip6[IP_MAX_SIZE + 1];
 | 
				
			||||||
 | 
					    bool have_ip6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char key[TOX_PUBLIC_KEY_SIZE];
 | 
				
			||||||
 | 
					    uint16_t port;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct DHT_Nodes {
 | 
				
			||||||
 | 
					    struct Node list[MAX_NODES];
 | 
				
			||||||
 | 
					    size_t count;
 | 
				
			||||||
 | 
					    time_t last_updated;
 | 
				
			||||||
 | 
					} Nodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if address appears to be a valid ipv4 address. */
 | 
				
			||||||
 | 
					static bool is_ip4_address(const char *address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct sockaddr_in s_addr;
 | 
				
			||||||
 | 
					    return inet_pton(AF_INET, address, &(s_addr.sin_addr)) != 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if address roughly appears to be a valid ipv6 address.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TODO: Improve this function (inet_pton behaves strangely with ipv6).
 | 
				
			||||||
 | 
					 * for now the only guarantee is that it won't return true if the
 | 
				
			||||||
 | 
					 * address is a domain or ipv4 address, and should only be used if you're
 | 
				
			||||||
 | 
					 * reasonably sure that the address is one of the three (ipv4, ipv6 or a domain).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool is_ip6_address(const char *address)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    size_t num_colons = 0;
 | 
				
			||||||
 | 
					    char ch = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; (ch = address[i]); ++i) {
 | 
				
			||||||
 | 
					        if (ch == '.') {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ch == ':') {
 | 
				
			||||||
 | 
					            ++num_colons;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return num_colons > 1 && num_colons < 8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Determine if a node is offline by comparing the age of the nodeslist
 | 
				
			||||||
 | 
					 * to the last time the node was successfully pinged.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool node_is_offline(unsigned long long int last_ping)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return last_ping + NODE_OFFLINE_TIMOUT <= last_ping;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if nodeslist pointed to by fp needs to be updated.
 | 
				
			||||||
 | 
					 * This will be the case if the file is empty, has an invalid format,
 | 
				
			||||||
 | 
					 * or if the file is older than the given timeout.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool nodeslist_needs_update(const char *nodes_path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (user_settings->nodeslist_update_freq <= 0) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE *fp = fopen(nodes_path, "r+");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fp == NULL) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* last_scan value should be at beginning of file */
 | 
				
			||||||
 | 
					    char line[LAST_SCAN_JSON_KEY_LEN + 32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fgets(line, sizeof(line), fp) == NULL) {
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *last_scan_val = strstr(line, LAST_SCAN_JSON_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (last_scan_val == NULL) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long long int last_scan = strtoll(last_scan_val + LAST_SCAN_JSON_KEY_LEN, NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&thread_data.lock);
 | 
				
			||||||
 | 
					    Nodes.last_updated = last_scan;
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&thread_data.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&Winthread.lock);
 | 
				
			||||||
 | 
					    bool is_timeout = timed_out(last_scan, user_settings->nodeslist_update_freq * 24 * 60 * 60);
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&Winthread.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (is_timeout) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Fetches the JSON encoded DHT nodeslist from NODES_LIST_URL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int curl_fetch_nodes_JSON(struct Recv_Curl_Data *recv_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CURL *c_handle = curl_easy_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (c_handle == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int err = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct curl_slist *headers = NULL;
 | 
				
			||||||
 | 
					    headers = curl_slist_append(headers, "Content-Type: application/json");
 | 
				
			||||||
 | 
					    headers = curl_slist_append(headers, "charsets: utf-8");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_HTTPHEADER, headers);
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_URL, NODES_LIST_URL);
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_WRITEFUNCTION, curl_cb_write_data);
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_WRITEDATA, recv_data);
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
 | 
				
			||||||
 | 
					    curl_easy_setopt(c_handle, CURLOPT_HTTPGET, 1L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int proxy_ret = set_curl_proxy(c_handle, arg_opts.proxy_address, arg_opts.proxy_port, arg_opts.proxy_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (proxy_ret != 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "set_curl_proxy() failed with error %d\n", proxy_ret);
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = curl_easy_setopt(c_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "TLSv1.2 could not be set (libcurl error %d)", ret);
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, TLS_CIPHER_SUITE_LIST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Failed to set TLS cipher list (libcurl error %d)", ret);
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = curl_easy_perform(c_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        /* If system doesn't support any of the specified ciphers suites, fall back to default */
 | 
				
			||||||
 | 
					        if (ret == CURLE_SSL_CIPHER) {
 | 
				
			||||||
 | 
					            curl_easy_setopt(c_handle, CURLOPT_SSL_CIPHER_LIST, NULL);
 | 
				
			||||||
 | 
					            ret = curl_easy_perform(c_handle);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "HTTPS lookup error (libcurl error %d)\n", ret);
 | 
				
			||||||
 | 
					            goto on_exit;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on_exit:
 | 
				
			||||||
 | 
					    curl_slist_free_all(headers);
 | 
				
			||||||
 | 
					    curl_easy_cleanup(c_handle);
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Attempts to update the DHT nodeslist.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 1 if list was updated successfully.
 | 
				
			||||||
 | 
					 * Return 0 if list does not need to be updated.
 | 
				
			||||||
 | 
					 * Return -1 if file cannot be opened.
 | 
				
			||||||
 | 
					 * Return -2 if http lookup failed.
 | 
				
			||||||
 | 
					 * Return -3 if http reponse was empty.
 | 
				
			||||||
 | 
					 * Return -4 if data could not be written to disk.
 | 
				
			||||||
 | 
					 * Return -5 if memory allocation fails.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int update_DHT_nodeslist(const char *nodes_path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!nodeslist_needs_update(nodes_path)) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE *fp = fopen(nodes_path, "r+");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fp == NULL) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Recv_Curl_Data *recv_data = calloc(1, sizeof(struct Recv_Curl_Data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (recv_data == NULL) {
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -5;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (curl_fetch_nodes_JSON(recv_data) == -1) {
 | 
				
			||||||
 | 
					        free(recv_data);
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (recv_data->length == 0) {
 | 
				
			||||||
 | 
					        free(recv_data);
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -3;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fwrite(recv_data->data, recv_data->length, 1, fp) != 1) {
 | 
				
			||||||
 | 
					        free(recv_data);
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        return -4;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(recv_data);
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_nodeslist_path(char *buf, size_t buf_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *config_dir = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (arg_opts.nodes_path[0]) {
 | 
				
			||||||
 | 
					        snprintf(buf, buf_size, "%s", arg_opts.nodes_path);
 | 
				
			||||||
 | 
					    } else if ((config_dir = get_user_config_dir()) != NULL) {
 | 
				
			||||||
 | 
					        snprintf(buf, buf_size, "%s%s%s", config_dir, CONFIGDIR, DEFAULT_NODES_FILENAME);
 | 
				
			||||||
 | 
					        free(config_dir);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        snprintf(buf, buf_size, "%s", DEFAULT_NODES_FILENAME);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return true if json encoded string s contains a valid IP address and puts address in ip_buf.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ip_type should be set to 1 for ipv4 address, or 0 for ipv6 addresses.
 | 
				
			||||||
 | 
					 * ip_buf must have room for at least IP_MAX_SIZE + 1 bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static bool extract_val_ip(const char *s, char *ip_buf, unsigned short int ip_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int ip_len = char_find(0, s, '"');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ip_len < IP_MIN_SIZE || ip_len > IP_MAX_SIZE) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(ip_buf, s, ip_len);
 | 
				
			||||||
 | 
					    ip_buf[ip_len] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (ip_type == 1) ? is_ip4_address(ip_buf) : is_ip6_address(ip_buf);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extracts the port from json encoded string s.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return port number on success.
 | 
				
			||||||
 | 
					 * Return 0 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static uint16_t extract_val_port(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    long int port = strtol(s, NULL, 10);
 | 
				
			||||||
 | 
					    return (port > 0 && port <= MAX_PORT_RANGE) ? port : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extracts the last pinged value from json encoded string s.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return timestamp on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static long long int extract_val_last_pinged(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    long long int last_pinged = strtoll(s, NULL, 10);
 | 
				
			||||||
 | 
					    return (last_pinged <= 0) ? -1 : last_pinged;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extracts DHT public key from json encoded string s and puts key in key_buf.
 | 
				
			||||||
 | 
					 * key_buf must have room for at least TOX_PUBLIC_KEY_SIZE * 2 + 1 bytes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return number of bytes copied to key_buf on success.
 | 
				
			||||||
 | 
					 * Return -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int extract_val_pk(const char *s, char *key_buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int key_len = char_find(0, s, '"');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (key_len != TOX_PUBLIC_KEY_SIZE * 2) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(key_buf, s, key_len);
 | 
				
			||||||
 | 
					    key_buf[key_len] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return key_len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Extracts values from json formatted string, validats them, and puts them in node.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 if line is empty.
 | 
				
			||||||
 | 
					 * Return -2 if line does not appear to be a valid nodes list entry.
 | 
				
			||||||
 | 
					 * Return -3 if node appears to be offline.
 | 
				
			||||||
 | 
					 * Return -4 if entry does not contain either a valid ipv4 or ipv6 address.
 | 
				
			||||||
 | 
					 * Return -5 if port value is invalid.
 | 
				
			||||||
 | 
					 * Return -6 if public key is invalid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int extract_node(const char *line, struct Node *node)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!line) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *ip4_start = strstr(line, IPV4_JSON_KEY);
 | 
				
			||||||
 | 
					    const char *ip6_start = strstr(line, IPV6_JSON_KEY);
 | 
				
			||||||
 | 
					    const char *port_start = strstr(line, PORT_JSON_KEY);
 | 
				
			||||||
 | 
					    const char *key_start = strstr(line, PK_JSON_KEY);
 | 
				
			||||||
 | 
					    const char *last_pinged_str = strstr(line, LAST_PING_JSON_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!ip4_start || !ip6_start || !port_start || !key_start || !last_pinged_str) {
 | 
				
			||||||
 | 
					        return -2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long long int last_pinged = extract_val_last_pinged(last_pinged_str + LAST_PING_JSON_KEY_LEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (last_pinged <= 0 || node_is_offline(last_pinged)) {
 | 
				
			||||||
 | 
					        return -3;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char ip4_string[IP_MAX_SIZE + 1];
 | 
				
			||||||
 | 
					    bool have_ip4 = extract_val_ip(ip4_start + IPV4_JSON_KEY_LEN, ip4_string, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char ip6_string[IP_MAX_SIZE + 1];
 | 
				
			||||||
 | 
					    bool have_ip6 = extract_val_ip(ip6_start + IPV6_JSON_KEY_LEN, ip6_string, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!have_ip6 && !have_ip4) {
 | 
				
			||||||
 | 
					        return -4;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t port = extract_val_port(port_start + PORT_JSON_KEY_LEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (port == 0) {
 | 
				
			||||||
 | 
					        return -5;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char key_string[TOX_PUBLIC_KEY_SIZE * 2 + 1];
 | 
				
			||||||
 | 
					    int key_len = extract_val_pk(key_start + PK_JSON_KEY_LEN, key_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (key_len == -1) {
 | 
				
			||||||
 | 
					        return -6;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (hex_string_to_bin(key_string, key_len, node->key, TOX_PUBLIC_KEY_SIZE) == -1) {
 | 
				
			||||||
 | 
					        return -6;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (have_ip4) {
 | 
				
			||||||
 | 
					        snprintf(node->ip4, sizeof(node->ip4), "%s", ip4_string);
 | 
				
			||||||
 | 
					        node->have_ip4 = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (have_ip6) {
 | 
				
			||||||
 | 
					        snprintf(node->ip6, sizeof(node->ip6), "%s", ip6_string);
 | 
				
			||||||
 | 
					        node->have_ip6 = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    node->port = port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Loads the DHT nodeslist to memory from json encoded nodes file. */
 | 
				
			||||||
 | 
					void *load_nodeslist_thread(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char nodes_path[PATH_MAX];
 | 
				
			||||||
 | 
					    get_nodeslist_path(nodes_path, sizeof(nodes_path));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE *fp = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!file_exists(nodes_path)) {
 | 
				
			||||||
 | 
					        if ((fp = fopen(nodes_path, "w+")) == NULL) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "nodeslist load error: failed to create file '%s'\n", nodes_path);
 | 
				
			||||||
 | 
					            goto on_exit;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if ((fp = fopen(nodes_path, "r+")) == NULL) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "nodeslist load error: failed to open file '%s'\n", nodes_path);
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int update_err = update_DHT_nodeslist(nodes_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (update_err < 0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "update_DHT_nodeslist() failed with error %d\n", update_err);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char line[MAX_NODELIST_SIZE + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fgets(line, sizeof(line), fp) == NULL) {
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        fprintf(stderr, "nodeslist load error: file empty.\n");
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t idx = 0;
 | 
				
			||||||
 | 
					    const char *line_start = line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while ((line_start = strstr(line_start + 1, IPV4_JSON_KEY))) {
 | 
				
			||||||
 | 
					        pthread_mutex_lock(&thread_data.lock);
 | 
				
			||||||
 | 
					        idx = Nodes.count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (idx >= MAX_NODES) {
 | 
				
			||||||
 | 
					            pthread_mutex_unlock(&thread_data.lock);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (extract_node(line_start, &Nodes.list[idx]) == 0) {
 | 
				
			||||||
 | 
					            ++Nodes.count;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pthread_mutex_unlock(&thread_data.lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If nodeslist does not contain any valid entries we set the last_scan value
 | 
				
			||||||
 | 
					     * to 0 so that it will fetch a new list the next time this function is called.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    if (Nodes.count == 0) {
 | 
				
			||||||
 | 
					        const char *s = "{\"last_scan\":0}";
 | 
				
			||||||
 | 
					        rewind(fp);
 | 
				
			||||||
 | 
					        fwrite(s, strlen(s), 1, fp);  // Not much we can do if it fails
 | 
				
			||||||
 | 
					        fclose(fp);
 | 
				
			||||||
 | 
					        fprintf(stderr, "nodeslist load error: List did not contain any valid entries.\n");
 | 
				
			||||||
 | 
					        goto on_exit;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on_exit:
 | 
				
			||||||
 | 
					    thread_data.active = false;
 | 
				
			||||||
 | 
					    pthread_attr_destroy(&thread_data.attr);
 | 
				
			||||||
 | 
					    pthread_exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Creates a new thread that will load the DHT nodeslist to memory
 | 
				
			||||||
 | 
					 * from json encoded nodes file obtained at NODES_LIST_URL. Only one
 | 
				
			||||||
 | 
					 * thread may run at a time.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 if a thread is already active.
 | 
				
			||||||
 | 
					 * Return -2 if mutex fails to init.
 | 
				
			||||||
 | 
					 * Return -3 if pthread attribute fails to init.
 | 
				
			||||||
 | 
					 * Return -4 if pthread fails to set detached state.
 | 
				
			||||||
 | 
					 * Return -5 if thread creation fails.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int load_DHT_nodeslist(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (thread_data.active) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pthread_mutex_init(&thread_data.lock, NULL) != 0) {
 | 
				
			||||||
 | 
					        return -2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pthread_attr_init(&thread_data.attr) != 0) {
 | 
				
			||||||
 | 
					        return -3;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pthread_attr_setdetachstate(&thread_data.attr, PTHREAD_CREATE_DETACHED) != 0) {
 | 
				
			||||||
 | 
					        return -4;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    thread_data.active = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pthread_create(&thread_data.tid, &thread_data.attr, load_nodeslist_thread, NULL) != 0) {
 | 
				
			||||||
 | 
					        thread_data.active = false;
 | 
				
			||||||
 | 
					        return -5;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Connects to NUM_BOOTSTRAP_NODES random DHT nodes listed in the DHTnodes file. */
 | 
				
			||||||
 | 
					static void DHT_bootstrap(Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&thread_data.lock);
 | 
				
			||||||
 | 
					    size_t num_nodes = Nodes.count;
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&thread_data.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (num_nodes == 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_mutex_lock(&thread_data.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NUM_BOOTSTRAP_NODES; ++i) {
 | 
				
			||||||
 | 
					        struct Node *node = &Nodes.list[rand() % Nodes.count];
 | 
				
			||||||
 | 
					        const char *addr = node->have_ip4 ? node->ip4 : node->ip6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!addr) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Tox_Err_Bootstrap err;
 | 
				
			||||||
 | 
					        tox_bootstrap(m, addr, node->port, (uint8_t *) node->key, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != TOX_ERR_BOOTSTRAP_OK) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Failed to bootstrap %s:%d\n", addr, node->port);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tox_add_tcp_relay(m, addr, node->port, (uint8_t *) node->key, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != TOX_ERR_BOOTSTRAP_OK) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Failed to add TCP relay %s:%d\n", addr, node->port);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pthread_mutex_unlock(&thread_data.lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Manages connection to the Tox DHT network. */
 | 
				
			||||||
 | 
					void do_tox_connection(Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static time_t last_bootstrap_time = 0;
 | 
				
			||||||
 | 
					    bool connected = prompt_selfConnectionStatus() != TOX_CONNECTION_NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!connected && timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL)) {
 | 
				
			||||||
 | 
					        DHT_bootstrap(m);
 | 
				
			||||||
 | 
					        last_bootstrap_time = get_unix_time();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/bootstrap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/bootstrap.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					/*  bootstrap.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2016 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef BOOTSTRAP_H
 | 
				
			||||||
 | 
					#define BOOTSTRAP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Manages connection to the Tox DHT network. */
 | 
				
			||||||
 | 
					void do_tox_connection(Tox *m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Creates a new thread that will load the DHT nodeslist to memory
 | 
				
			||||||
 | 
					 * from json encoded nodes file obtained at NODES_LIST_URL. Only one
 | 
				
			||||||
 | 
					 * thread may run at a time.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return 0 on success.
 | 
				
			||||||
 | 
					 * Return -1 if a thread is already active.
 | 
				
			||||||
 | 
					 * Return -2 if mutex fails to init.
 | 
				
			||||||
 | 
					 * Return -3 if pthread attribute fails to init.
 | 
				
			||||||
 | 
					 * Return -4 if pthread fails to set detached state.
 | 
				
			||||||
 | 
					 * Return -5 if thread creation fails.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int load_DHT_nodeslist(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* BOOTSTRAP_H */
 | 
				
			||||||
							
								
								
									
										1878
									
								
								src/chat.c
									
									
									
									
									
								
							
							
						
						
									
										1878
									
								
								src/chat.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										16
									
								
								src/chat.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/chat.h
									
									
									
									
									
								
							@@ -20,12 +20,16 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CHAT_H_6489PZ13
 | 
					#ifndef CHAT_H
 | 
				
			||||||
#define CHAT_H_6489PZ13
 | 
					#define CHAT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "toxic_windows.h"
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void kill_chat_window(ToxWindow *self);
 | 
					/* set CTRL to -1 if we don't want to send a control signal.
 | 
				
			||||||
ToxWindow new_chat(Tox *m, int friendnum);
 | 
					   set msg to NULL if we don't want to display a message */
 | 
				
			||||||
 | 
					void chat_close_file_receiver(Tox *m, int filenum, int friendnum, int CTRL);
 | 
				
			||||||
 | 
					void kill_chat_window(ToxWindow *self, Tox *m);
 | 
				
			||||||
 | 
					ToxWindow *new_chat(Tox *m, int32_t friendnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* end of include guard: CHAT_H_6489PZ13 */
 | 
					#endif /* end of include guard: CHAT_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,217 +20,325 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "toxic_windows.h"
 | 
					#include "chat.h"
 | 
				
			||||||
#include "misc_tools.h"
 | 
					#include "conference.h"
 | 
				
			||||||
#include "friendlist.h"
 | 
					 | 
				
			||||||
#include "execute.h"
 | 
					#include "execute.h"
 | 
				
			||||||
 | 
					#include "file_transfers.h"
 | 
				
			||||||
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern ToxWindow *prompt;
 | 
					extern ToxWindow *prompt;
 | 
				
			||||||
 | 
					extern FriendsList Friends;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern ToxicFriend friends[MAX_FRIENDS_NUM];
 | 
					void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					 | 
				
			||||||
extern FileSender file_senders[MAX_FILES];
 | 
					 | 
				
			||||||
extern uint8_t max_file_senders_index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void cmd_chat_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (argc == 1) {
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
        if (!strcmp(argv[1], "global")) {
 | 
					
 | 
				
			||||||
            execute(window, self, m, "/help", GLOBAL_COMMAND_MODE);
 | 
					    if (argc < 2) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char msg[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    const char *inoutstr = argv[1];
 | 
				
			||||||
 | 
					    long int idx = strtol(argv[2], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					    struct FileTransfer *ft = NULL;
 | 
				
			||||||
    wprintw(window, "Chat commands:\n");
 | 
					 | 
				
			||||||
    wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					    /* cancel an incoming file transfer */
 | 
				
			||||||
 | 
					    if (strcasecmp(inoutstr, "in") == 0) {
 | 
				
			||||||
 | 
					        ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
 | 
				
			||||||
 | 
					    } else if (strcasecmp(inoutstr, "out") == 0) {
 | 
				
			||||||
 | 
					        ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "    /call                      : Audio call\n");
 | 
					    if (!ft) {
 | 
				
			||||||
    wprintw(window, "    /cancel                    : Cancel call\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
    wprintw(window, "    /answer                    : Answer incomming call\n");
 | 
					        return;
 | 
				
			||||||
    wprintw(window, "    /hangup                    : Hangup active call\n");
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					    if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "    /invite <n>                : Invite friend to a group chat\n");
 | 
					    snprintf(msg, sizeof(msg), "File transfer for '%s' aborted.", ft->file_name);
 | 
				
			||||||
    wprintw(window, "    /join                      : Join a pending group chat\n");
 | 
					    close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, silent);
 | 
				
			||||||
    wprintw(window, "    /log <on> or <off>         : Enable/disable logging\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /sendfile <filepath>       : Send a file\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /savefile <n>              : Receive a file\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /close                     : Close the current chat window\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /help                      : Print this message again\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /help global               : Show a list of global commands\n");
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(window, " * Argument messages must be enclosed in quotation marks.\n\n");
 | 
					 | 
				
			||||||
    wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_groupinvite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
      wprintw(window, "Invalid syntax.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int groupnum = atoi(argv[1]);
 | 
					    long int conferencenum = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (groupnum == 0 && strcmp(argv[1], "0")) {    /* atoi returns 0 value on invalid input */
 | 
					    if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
 | 
				
			||||||
        wprintw(window, "Invalid syntax.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (tox_invite_friend(m, self->num, groupnum) == -1) {
 | 
					    Tox_Err_Conference_Invite err;
 | 
				
			||||||
        wprintw(window, "Failed to invite friend.\n");
 | 
					
 | 
				
			||||||
 | 
					    if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "Invited friend to group chat %d.\n", groupnum);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_join_group(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
					    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
				
			||||||
        wattron(window, COLOR_PAIR(RED));
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
 | 
				
			||||||
        wprintw(window, " * Warning: Too many windows are open.\n");
 | 
					 | 
				
			||||||
        wattron(window, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *groupkey = friends[self->num].pending_groupchat;
 | 
					    const char *conferencekey = Friends.list[self->num].conference_invite.key;
 | 
				
			||||||
 | 
					    uint16_t length = Friends.list[self->num].conference_invite.length;
 | 
				
			||||||
 | 
					    uint8_t type = Friends.list[self->num].conference_invite.type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (groupkey[0] == '\0') {
 | 
					    if (!Friends.list[self->num].conference_invite.pending) {
 | 
				
			||||||
        wprintw(window, "No pending group chat invite.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int groupnum = tox_join_groupchat(m, self->num, groupkey);
 | 
					    uint32_t conferencenum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (groupnum == -1) {
 | 
					    if (type == TOX_CONFERENCE_TYPE_TEXT) {
 | 
				
			||||||
        wprintw(window, "Group chat instance failed to initialize.\n");
 | 
					        Tox_Err_Conference_Join err;
 | 
				
			||||||
 | 
					        conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					        conferencenum = toxav_join_av_groupchat(m, self->num, (const uint8_t *) conferencekey, length,
 | 
				
			||||||
 | 
					                                                audio_conference_callback, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (conferencenum == (uint32_t) -1) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_groupchat_win(prompt, m, groupnum) == -1) {
 | 
					#else
 | 
				
			||||||
        wprintw(window, "Group chat window failed to initialize.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
				
			||||||
        tox_del_groupchat(m, groupnum);
 | 
					        return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
				
			||||||
 | 
					        tox_conference_delete(m, conferencenum, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
 | 
					        if (!init_conference_audio_input(m, conferencenum)) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (argc != 1) {
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
      wprintw(window, "Invalid syntax.\n");
 | 
					
 | 
				
			||||||
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t filenum = atoi(argv[1]);
 | 
					    long int idx = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((filenum == 0 && strcmp(argv[1], "0")) || filenum >= MAX_FILES) {
 | 
					    if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) {
 | 
				
			||||||
        wprintw(window, "No pending file transfers with that number.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!friends[self->num].file_receiver.pending[filenum]) {
 | 
					    struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
 | 
				
			||||||
        wprintw(window, "No pending file transfers with that number.\n");
 | 
					
 | 
				
			||||||
 | 
					    if (!ft) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *filename = friends[self->num].file_receiver.filenames[filenum];
 | 
					    if (ft->state != FILE_TRANSFER_PENDING) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
 | 
				
			||||||
    if (tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_ACCEPT, 0, 0) == 0) {
 | 
					        return;
 | 
				
			||||||
        wprintw(window, "Accepted file transfer %u. Saving file as: '%s'\n", filenum, filename);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ((friends[self->num].file_receiver.files[filenum] = fopen(filename, "a")) == NULL) {
 | 
					 | 
				
			||||||
            wattron(window, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
            wprintw(window, "* Error writing to file.\n");
 | 
					 | 
				
			||||||
            wattroff(window, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
            tox_file_send_control(m, self->num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        wprintw(window, "File transfer failed.\n");
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    friends[self->num].file_receiver.pending[filenum] = false;
 | 
					    if ((ft->file = fopen(ft->file_path, "a")) == NULL) {
 | 
				
			||||||
 | 
					        const char *msg =  "File transfer failed: Invalid download path.";
 | 
				
			||||||
 | 
					        close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Tox_Err_File_Control err;
 | 
				
			||||||
 | 
					    tox_file_control(m, self->num, ft->filenumber, TOX_FILE_CONTROL_RESUME, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (err != TOX_ERR_FILE_CONTROL_OK) {
 | 
				
			||||||
 | 
					        goto on_recv_error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* prep progress bar line */
 | 
				
			||||||
 | 
					    char progline[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    init_progress_bar(progline);
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ft->line_id = self->chatwin->hst->line_end->id + 2;
 | 
				
			||||||
 | 
					    ft->state = FILE_TRANSFER_STARTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on_recv_error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (err) {
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_CONTROL_NOT_FOUND:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_CONTROL_SENDQ:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (max_file_senders_index >= (MAX_FILES-1)) {
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
        wprintw(window,"Please wait for some of your outgoing file transfers to complete.\n");
 | 
					
 | 
				
			||||||
        return;
 | 
					    const char *errmsg = NULL;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
      wprintw(window, "Invalid syntax.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *path = argv[1];
 | 
					    char path[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    snprintf(path, sizeof(path), "%s", argv[1]);
 | 
				
			||||||
    if (path[0] != '\"') {
 | 
					 | 
				
			||||||
        wprintw(window, "File path must be enclosed in quotes.\n");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    path[strlen(++path)-1] = L'\0';
 | 
					 | 
				
			||||||
    int path_len = strlen(path);
 | 
					    int path_len = strlen(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (path_len > MAX_STR_SIZE) {
 | 
					    if (path_len >= MAX_STR_SIZE) {
 | 
				
			||||||
        wprintw(window, "File path exceeds character limit.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FILE *file_to_send = fopen(path, "r");
 | 
					    FILE *file_to_send = fopen(path, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (file_to_send == NULL) {
 | 
					    if (file_to_send == NULL) {
 | 
				
			||||||
        wprintw(window, "File '%s' not found.\n", path);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fseek(file_to_send, 0, SEEK_END);
 | 
					    off_t filesize = file_size(path);
 | 
				
			||||||
    uint64_t filesize = ftell(file_to_send);
 | 
					 | 
				
			||||||
    fseek(file_to_send, 0, SEEK_SET);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t filename[MAX_STR_SIZE];
 | 
					    if (filesize == 0) {
 | 
				
			||||||
    get_file_name(path, filename);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
 | 
				
			||||||
    int filenum = tox_new_file_sender(m, self->num, filesize, filename, strlen(filename) + 1);
 | 
					        fclose(file_to_send);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (filenum == -1) {
 | 
					 | 
				
			||||||
        wprintw(window, "Error sending file.\n");
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i;
 | 
					    char file_name[TOX_MAX_FILENAME_LENGTH];
 | 
				
			||||||
 | 
					    size_t namelen = get_file_name(file_name, sizeof(file_name), path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < MAX_FILES; ++i) {
 | 
					    Tox_Err_File_Send err;
 | 
				
			||||||
        if (!file_senders[i].active) {
 | 
					    uint32_t filenum = tox_file_send(m, self->num, TOX_FILE_KIND_DATA, (uint64_t) filesize, NULL,
 | 
				
			||||||
            memcpy(file_senders[i].pathname, path, path_len + 1);
 | 
					                                     (uint8_t *) file_name, namelen, &err);
 | 
				
			||||||
            file_senders[i].active = true;
 | 
					 | 
				
			||||||
            file_senders[i].toxwin = self;
 | 
					 | 
				
			||||||
            file_senders[i].file = file_to_send;
 | 
					 | 
				
			||||||
            file_senders[i].filenum = (uint8_t) filenum;
 | 
					 | 
				
			||||||
            file_senders[i].friendnum = self->num;
 | 
					 | 
				
			||||||
            file_senders[i].timestamp = (uint64_t) time(NULL);
 | 
					 | 
				
			||||||
            file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
 | 
					 | 
				
			||||||
                                             tox_file_data_size(m, self->num), file_to_send);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            wprintw(window, "Sending file: '%s'\n", path);
 | 
					    if (err != TOX_ERR_FILE_SEND_OK) {
 | 
				
			||||||
 | 
					        goto on_send_error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (i == max_file_senders_index)
 | 
					    struct FileTransfer *ft = new_file_transfer(self, self->num, filenum, FILE_TRANSFER_SEND, TOX_FILE_KIND_DATA);
 | 
				
			||||||
                ++max_file_senders_index;
 | 
					
 | 
				
			||||||
 | 
					    if (!ft) {
 | 
				
			||||||
 | 
					        err = TOX_ERR_FILE_SEND_TOO_MANY;
 | 
				
			||||||
 | 
					        goto on_send_error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(ft->file_name, file_name, namelen + 1);
 | 
				
			||||||
 | 
					    ft->file = file_to_send;
 | 
				
			||||||
 | 
					    ft->file_size = filesize;
 | 
				
			||||||
 | 
					    tox_file_get_file_id(m, self->num, filenum, ft->file_id, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char sizestr[32];
 | 
				
			||||||
 | 
					    bytes_convert_str(sizestr, sizeof(sizestr), filesize);
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on_send_error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (err) {
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND:
 | 
				
			||||||
 | 
					            errmsg = "File transfer failed: Invalid friend.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
 | 
				
			||||||
 | 
					            errmsg = "File transfer failed: Friend is offline.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_SEND_NAME_TOO_LONG:
 | 
				
			||||||
 | 
					            errmsg = "File transfer failed: Filename is too long.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FILE_SEND_TOO_MANY:
 | 
				
			||||||
 | 
					            errmsg = "File transfer failed: Too many concurrent file transfers.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            errmsg = "File transfer failed.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } 
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
 | 
				
			||||||
 | 
					    tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
 | 
				
			||||||
 | 
					    fclose(file_to_send);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,16 +20,34 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_chat_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					#ifndef CHAT_COMMANDS_H
 | 
				
			||||||
void cmd_groupinvite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					#define CHAT_COMMANDS_H
 | 
				
			||||||
void cmd_join_group(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_invite(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_join(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_savefile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_sendfile(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					 | 
				
			||||||
void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_call(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_answer(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_reject(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_hangup(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_cancel(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					void cmd_ccur_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_mute(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_sense(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_bitrate(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					void cmd_vcall(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_video(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_res(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CHAT_COMMANDS_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1418
									
								
								src/conference.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1418
									
								
								src/conference.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										118
									
								
								src/conference.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/conference.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					/*  conference.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFERENCE_H
 | 
				
			||||||
 | 
					#define CONFERENCE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
 | 
				
			||||||
 | 
					#define SIDEBAR_WIDTH 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct ConferencePeer {
 | 
				
			||||||
 | 
					    bool       active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t    pubkey[TOX_PUBLIC_KEY_SIZE];
 | 
				
			||||||
 | 
					    uint32_t   peernum;    /* index in chat->peer_list */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char       name[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					    size_t     name_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool       sending_audio;
 | 
				
			||||||
 | 
					    uint32_t   audio_out_idx;
 | 
				
			||||||
 | 
					    time_t     last_audio_time;
 | 
				
			||||||
 | 
					} ConferencePeer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct AudioInputCallbackData {
 | 
				
			||||||
 | 
					    Tox *tox;
 | 
				
			||||||
 | 
					    uint32_t conferencenum;
 | 
				
			||||||
 | 
					} AudioInputCallbackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PUBKEY_STRING_SIZE (2 * TOX_PUBLIC_KEY_SIZE + 1)
 | 
				
			||||||
 | 
					typedef struct NameListEntry {
 | 
				
			||||||
 | 
					    char name[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					    char pubkey_str[PUBKEY_STRING_SIZE];
 | 
				
			||||||
 | 
					    uint32_t peernum;
 | 
				
			||||||
 | 
					} NameListEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    int chatwin;
 | 
				
			||||||
 | 
					    bool active;
 | 
				
			||||||
 | 
					    uint8_t type;
 | 
				
			||||||
 | 
					    int side_pos;    /* current position of the sidebar - used for scrolling up and down */
 | 
				
			||||||
 | 
					    time_t start_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
 | 
				
			||||||
 | 
					    size_t title_length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ConferencePeer *peer_list;
 | 
				
			||||||
 | 
					    uint32_t max_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NameListEntry *name_list;
 | 
				
			||||||
 | 
					    uint32_t num_peers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool push_to_talk_enabled;
 | 
				
			||||||
 | 
					    time_t ptt_last_pushed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool audio_enabled;
 | 
				
			||||||
 | 
					    time_t last_sent_audio;
 | 
				
			||||||
 | 
					    uint32_t audio_in_idx;
 | 
				
			||||||
 | 
					    AudioInputCallbackData audio_input_callback_data;
 | 
				
			||||||
 | 
					} ConferenceChat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
 | 
				
			||||||
 | 
					void free_conference(ToxWindow *self, uint32_t conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* destroys and re-creates conference window with or without the peerlist */
 | 
				
			||||||
 | 
					void redraw_conference_win(ToxWindow *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length);
 | 
				
			||||||
 | 
					void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title);
 | 
				
			||||||
 | 
					int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
 | 
				
			||||||
 | 
					 * of `maxpeers`.
 | 
				
			||||||
 | 
					 * Maches each peer whose name or pubkey begins with `prefix`.
 | 
				
			||||||
 | 
					 * If `prefix` is exactly the pubkey of a peer, matches only that peer.
 | 
				
			||||||
 | 
					 * return number of entries placed in `entries`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *prefix, NameListEntry **entries,
 | 
				
			||||||
 | 
					        uint32_t maxpeers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
 | 
					bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
 | 
					bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
 | 
				
			||||||
 | 
					bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
 | 
				
			||||||
 | 
					void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
 | 
				
			||||||
 | 
					                               const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
 | 
				
			||||||
 | 
					                               sample_rate, void *userdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool conference_mute_self(uint32_t conferencenum);
 | 
				
			||||||
 | 
					bool conference_mute_peer(const Tox *m, uint32_t conferencenum, uint32_t peernum);
 | 
				
			||||||
 | 
					bool conference_set_VAD_threshold(uint32_t conferencenum, float threshold);
 | 
				
			||||||
 | 
					float conference_get_VAD_threshold(uint32_t conferencenum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFERENCE_H */
 | 
				
			||||||
							
								
								
									
										210
									
								
								src/conference_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/conference_commands.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
				
			|||||||
 | 
					/*  conference_commands.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "conference.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_err(ToxWindow *self, const char *error_str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Tox_Err_Conference_Title err;
 | 
				
			||||||
 | 
					    char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        size_t tlen = tox_conference_get_title_size(m, self->num, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != TOX_ERR_CONFERENCE_TITLE_OK || tlen >= sizeof(title)) {
 | 
				
			||||||
 | 
					            print_err(self, "Title is not set");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!tox_conference_get_title(m, self->num, (uint8_t *) title, &err)) {
 | 
				
			||||||
 | 
					            print_err(self, "Title is not set");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        title[tlen] = '\0';
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t len = strlen(argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (len >= sizeof(title)) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(title, sizeof(title), "%s", argv[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_rename_log_path(m, self->num, title);  // must be called first
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    conference_set_title(self, self->num, title, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char selfnick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					    tox_self_get_name(m, (uint8_t *) selfnick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t sn_len = tox_self_get_name_size(m);
 | 
				
			||||||
 | 
					    selfnick[sn_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, true, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char tmp_event[MAX_STR_SIZE + 20];
 | 
				
			||||||
 | 
					    snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
 | 
				
			||||||
 | 
					    write_to_log(tmp_event, selfnick, self->chatwin->log, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc == 1 && !strcasecmp(argv[1], "on")) {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					    } else if (argc == 1 && !strcasecmp(argv[1], "off")) {
 | 
				
			||||||
 | 
					        enable = false;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        print_err(self, "Please specify: on | off");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
 | 
				
			||||||
 | 
					        print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
 | 
				
			||||||
 | 
					                  : "Disabled conference audio");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        if (conference_mute_self(self->num)) {
 | 
				
			||||||
 | 
					            print_err(self, "Toggled self audio mute status");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            print_err(self, "No audio input to mute");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        NameListEntry *entries[16];
 | 
				
			||||||
 | 
					        uint32_t n = get_name_list_entries_by_prefix(self->num, argv[1], entries, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (n == 0) {
 | 
				
			||||||
 | 
					            print_err(self, "No such peer");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (n > 1) {
 | 
				
			||||||
 | 
					            print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (uint32_t i = 0; i < n; ++i) {
 | 
				
			||||||
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            print_err(self, "Peer is not on the call");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc == 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
 | 
				
			||||||
 | 
					                      (double) conference_get_VAD_threshold(self->num));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc > 1) {
 | 
				
			||||||
 | 
					        print_err(self, "Only one argument allowed.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *end;
 | 
				
			||||||
 | 
					    float value = strtof(argv[1], &end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*end) {
 | 
				
			||||||
 | 
					        print_err(self, "Invalid input");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (conference_set_VAD_threshold(self->num, value)) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        print_err(self, "Failed to set conference audio input sensitivity.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc == 1 && !strcasecmp(argv[1], "on")) {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					    } else if (argc == 1 && !strcasecmp(argv[1], "off")) {
 | 
				
			||||||
 | 
					        enable = false;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        print_err(self, "Please specify: on | off");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!toggle_conference_push_to_talk(self->num, enable)) {
 | 
				
			||||||
 | 
					        print_err(self, "Failed to toggle push to talk.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/conference_commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/conference_commands.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*  conference_commands.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CONFERENCE_COMMANDS_H
 | 
				
			||||||
 | 
					#define CONFERENCE_COMMANDS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFERENCE_COMMANDS_H */
 | 
				
			||||||
							
								
								
									
										163
									
								
								src/configdir.c
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								src/configdir.c
									
									
									
									
									
								
							@@ -20,83 +20,59 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <sys/types.h>
 | 
					 | 
				
			||||||
#include <sys/stat.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
#include <shlobj.h>
 | 
					 | 
				
			||||||
#include <direct.h>
 | 
					 | 
				
			||||||
#else /* WIN32 */
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <pwd.h>
 | 
					#include <pwd.h>
 | 
				
			||||||
#endif /* WIN32 */
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "configdir.h"
 | 
					#include "configdir.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* get the user's home directory. */
 | 
				
			||||||
 | 
					void get_home_dir(char *home, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct passwd pwd;
 | 
				
			||||||
 | 
					    struct passwd *pwdbuf;
 | 
				
			||||||
 | 
					    const char *hmstr;
 | 
				
			||||||
 | 
					    char buf[NSS_BUFLEN_PASSWD];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (rc == 0) {
 | 
				
			||||||
 | 
					        hmstr = pwd.pw_dir;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        hmstr = getenv("HOME");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (hmstr == NULL) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        snprintf(buf, sizeof(buf), "%s", hmstr);
 | 
				
			||||||
 | 
					        hmstr = buf;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(home, size, "%s", hmstr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Get the users config directory.
 | 
					 * @brief Get the user's config directory.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This is without a trailing slash.
 | 
					 * This is without a trailing slash. Resulting string must be freed.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @return The users config dir or NULL on error.
 | 
					 * @return The users config dir or NULL on error.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
char *get_user_config_dir(void)
 | 
					char *get_user_config_dir(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char *user_config_dir;
 | 
					    char home[NSS_BUFLEN_PASSWD] = {0};
 | 
				
			||||||
#ifdef _WIN32
 | 
					    get_home_dir(home, sizeof(home));
 | 
				
			||||||
#warning Please fix configdir for Win32
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
    char appdata[MAX_PATH];
 | 
					 | 
				
			||||||
    BOOL ok;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ok = SHGetSpecialFolderPathA(NULL, appdata, CSIDL_PROFILE, TRUE);
 | 
					    char *user_config_dir = NULL;
 | 
				
			||||||
 | 
					    size_t len = 0;
 | 
				
			||||||
    if (!ok) {
 | 
					 | 
				
			||||||
        return NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    user_config_dir = strdup(appdata);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return user_config_dir;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else /* WIN32 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef NSS_BUFLEN_PASSWD
 | 
					 | 
				
			||||||
#define NSS_BUFLEN_PASSWD 4096
 | 
					 | 
				
			||||||
#endif /* NSS_BUFLEN_PASSWD */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct passwd pwd;
 | 
					 | 
				
			||||||
    struct passwd *pwdbuf;
 | 
					 | 
				
			||||||
    const char *home;
 | 
					 | 
				
			||||||
    char buf[NSS_BUFLEN_PASSWD];
 | 
					 | 
				
			||||||
    size_t len;
 | 
					 | 
				
			||||||
    int rc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (rc == 0) {
 | 
					 | 
				
			||||||
        home = pwd.pw_dir;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        home = getenv("HOME");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (home == NULL) {
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* env variables can be tainted */
 | 
					 | 
				
			||||||
        snprintf(buf, sizeof(buf), "%s", home);
 | 
					 | 
				
			||||||
        home = buf;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# if defined(__APPLE__)
 | 
					# if defined(__APPLE__)
 | 
				
			||||||
    len = strlen(home) + strlen("/Library/Application Support") + 1;
 | 
					    len = strlen(home) + strlen("/Library/Application Support") + 1;
 | 
				
			||||||
@@ -109,8 +85,9 @@ char *get_user_config_dir(void)
 | 
				
			|||||||
    snprintf(user_config_dir, len, "%s/Library/Application Support", home);
 | 
					    snprintf(user_config_dir, len, "%s/Library/Application Support", home);
 | 
				
			||||||
# else /* __APPLE__ */
 | 
					# else /* __APPLE__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const char *tmp;
 | 
					    const char *tmp = getenv("XDG_CONFIG_HOME");
 | 
				
			||||||
    if (!(tmp = getenv("XDG_CONFIG_HOME"))) {
 | 
					
 | 
				
			||||||
 | 
					    if (tmp == NULL) {
 | 
				
			||||||
        len = strlen(home) + strlen("/.config") + 1;
 | 
					        len = strlen(home) + strlen("/.config") + 1;
 | 
				
			||||||
        user_config_dir = malloc(len);
 | 
					        user_config_dir = malloc(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -126,56 +103,52 @@ char *get_user_config_dir(void)
 | 
				
			|||||||
# endif /* __APPLE__ */
 | 
					# endif /* __APPLE__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return user_config_dir;
 | 
					    return user_config_dir;
 | 
				
			||||||
#undef NSS_BUFLEN_PASSWD
 | 
					 | 
				
			||||||
#endif /* WIN32 */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/* Creates the config and chatlog directories.
 | 
				
			||||||
 * Creates the config directory.
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int create_user_config_dir(char *path)
 | 
					int create_user_config_dirs(char *path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
#warning Please fix configdir for Win32
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
    char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
 | 
					 | 
				
			||||||
    strcpy(fullpath, path);
 | 
					 | 
				
			||||||
    strcat(fullpath, CONFIGDIR);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mkdir_err = _mkdir(fullpath);
 | 
					 | 
				
			||||||
    struct __stat64 buf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (mkdir_err && (errno != EEXIST || _wstat64(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
					 | 
				
			||||||
        free(fullpath);
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    free(fullpath);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    int mkdir_err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mkdir_err = mkdir(path, 0700);
 | 
					 | 
				
			||||||
    struct stat buf;
 | 
					    struct stat buf;
 | 
				
			||||||
 | 
					    int mkdir_err = mkdir(path, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
					    if (mkdir_err && (errno != EEXIST || stat(path, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
 | 
					    char *fullpath = malloc(strlen(path) + strlen(CONFIGDIR) + 1);
 | 
				
			||||||
 | 
					    char *logpath = malloc(strlen(path) + strlen(LOGDIR) + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fullpath == NULL || logpath == NULL) {
 | 
				
			||||||
 | 
					        exit_toxic_err("failed in load_data_structures", FATALERR_MEMORY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    strcpy(fullpath, path);
 | 
					    strcpy(fullpath, path);
 | 
				
			||||||
    strcat(fullpath, CONFIGDIR);
 | 
					    strcat(fullpath, CONFIGDIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcpy(logpath, path);
 | 
				
			||||||
 | 
					    strcat(logpath, LOGDIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mkdir_err = mkdir(fullpath, 0700);
 | 
					    mkdir_err = mkdir(fullpath, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mkdir_err && (errno != EEXIST || stat(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
					    if (mkdir_err && (errno != EEXIST || stat(fullpath, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
				
			||||||
        free(fullpath);
 | 
					        free(fullpath);
 | 
				
			||||||
 | 
					        free(logpath);
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkdir_err = mkdir(logpath, 0700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mkdir_err && (errno != EEXIST || stat(logpath, &buf) || !S_ISDIR(buf.st_mode))) {
 | 
				
			||||||
 | 
					        free(fullpath);
 | 
				
			||||||
 | 
					        free(logpath);
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(logpath);
 | 
				
			||||||
    free(fullpath);
 | 
					    free(fullpath);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,16 +20,37 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _win32
 | 
					#ifndef CONFIGDIR_H
 | 
				
			||||||
#define CONFIGDIR "\\tox\\"
 | 
					#define CONFIGDIR_H
 | 
				
			||||||
#else
 | 
					
 | 
				
			||||||
#define CONFIGDIR "/tox/"
 | 
					#ifndef NSS_BUFLEN_PASSWD
 | 
				
			||||||
 | 
					#define NSS_BUFLEN_PASSWD 4096
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CONFIGDIR "/tox/"
 | 
				
			||||||
 | 
					#define LOGDIR "/tox/chatlogs/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef S_ISDIR
 | 
					#ifndef S_ISDIR
 | 
				
			||||||
#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
 | 
					#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Get the user's config directory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is without a trailing slash. Resulting string must be freed.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return The users config dir or NULL on error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
char *get_user_config_dir(void);
 | 
					char *get_user_config_dir(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int create_user_config_dir(char *path);
 | 
					/* get the user's home directory. */
 | 
				
			||||||
 | 
					void get_home_dir(char *home, int size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Creates the config and chatlog directories.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success.
 | 
				
			||||||
 | 
					 * Returns -1 on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int create_user_config_dirs(char *path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFIGDIR_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										94
									
								
								src/curl_util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/curl_util.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					/*  curl_util.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2016 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <curl/curl.h>
 | 
				
			||||||
 | 
					#include <tox/tox.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "curl_util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sets proxy info for given CURL handler.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success or if no proxy is set by the client.
 | 
				
			||||||
 | 
					 * Returns -1 if proxy info is invalid.
 | 
				
			||||||
 | 
					 * Returns an int > 0 on curl error (see: https://curl.haxx.se/libcurl/c/libcurl-errors.html)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (proxy_type == TOX_PROXY_TYPE_NONE) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (proxy_address == NULL || port == 0) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ret = curl_easy_setopt(c_handle, CURLOPT_PROXYPORT, (long) port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long int type = proxy_type == TOX_PROXY_TYPE_SOCKS5 ? CURLPROXY_SOCKS5_HOSTNAME : CURLPROXY_HTTP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = curl_easy_setopt(c_handle, CURLOPT_PROXYTYPE, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = curl_easy_setopt(c_handle, CURLOPT_PROXY, proxy_address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ret != CURLE_OK) {
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback function for CURL to write received data.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will append data from an http request to the data buffer
 | 
				
			||||||
 | 
					 * until the request is complete or the buffer is full. Buffer will be null terminated.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns number of bytes received from http request on success (don't change this).
 | 
				
			||||||
 | 
					 * Returns 0 if data exceeds buffer size.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Recv_Curl_Data *recv_data = (struct Recv_Curl_Data *) user_pointer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t length = size * nmemb;
 | 
				
			||||||
 | 
					    size_t total_size = length + recv_data->length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (total_size > MAX_RECV_CURL_DATA_SIZE) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(recv_data->data + recv_data->length, data, length);
 | 
				
			||||||
 | 
					    recv_data->data[total_size] = '\0';
 | 
				
			||||||
 | 
					    recv_data->length += length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return length;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								src/curl_util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/curl_util.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					/*  curl_util.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2016 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CURL_UTIL_H
 | 
				
			||||||
 | 
					#define CURL_UTIL_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* List based on Mozilla's recommended configurations for modern browsers */
 | 
				
			||||||
 | 
					#define TLS_CIPHER_SUITE_LIST "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Max size of an http response that we can store in Recv_Data */
 | 
				
			||||||
 | 
					#define MAX_RECV_CURL_DATA_SIZE 32767
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Holds data received from curl lookup */
 | 
				
			||||||
 | 
					struct Recv_Curl_Data {
 | 
				
			||||||
 | 
					    char data[MAX_RECV_CURL_DATA_SIZE + 1];   /* Data received from curl write data callback */
 | 
				
			||||||
 | 
					    size_t length;  /* Total number of bytes written to data buffer (doesn't include null) */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Sets proxy info for given CURL handler.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 on success or if no proxy is set by the client.
 | 
				
			||||||
 | 
					 * Returns -1 if proxy info is invalid.
 | 
				
			||||||
 | 
					 * Returns an int > 0 on curl error (see: https://curl.haxx.se/libcurl/c/libcurl-errors.html)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int set_curl_proxy(CURL *c_handle, const char *proxy_address, uint16_t port, uint8_t proxy_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback function for CURL to write received data.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function will append data from an http request to the data buffer
 | 
				
			||||||
 | 
					 * until the request is complete or the buffer is full. Buffer will be null terminated.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns size of bytes written to the data buffer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					size_t curl_cb_write_data(void *data, size_t size, size_t nmemb, void *user_pointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CURL_UTIL_H */
 | 
				
			||||||
							
								
								
									
										232
									
								
								src/execute.c
									
									
									
									
									
								
							
							
						
						
									
										232
									
								
								src/execute.c
									
									
									
									
									
								
							@@ -20,18 +20,20 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					#include <assert.h>
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "toxic_windows.h"
 | 
					#include "api.h"
 | 
				
			||||||
#include "execute.h"
 | 
					 | 
				
			||||||
#include "chat_commands.h"
 | 
					#include "chat_commands.h"
 | 
				
			||||||
 | 
					#include "execute.h"
 | 
				
			||||||
#include "global_commands.h"
 | 
					#include "global_commands.h"
 | 
				
			||||||
 | 
					#include "conference_commands.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "notify.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_func {
 | 
					struct cmd_func {
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
@@ -41,83 +43,181 @@ struct cmd_func {
 | 
				
			|||||||
static struct cmd_func global_commands[] = {
 | 
					static struct cmd_func global_commands[] = {
 | 
				
			||||||
    { "/accept",    cmd_accept        },
 | 
					    { "/accept",    cmd_accept        },
 | 
				
			||||||
    { "/add",       cmd_add           },
 | 
					    { "/add",       cmd_add           },
 | 
				
			||||||
 | 
					    { "/avatar",    cmd_avatar        },
 | 
				
			||||||
    { "/clear",     cmd_clear         },
 | 
					    { "/clear",     cmd_clear         },
 | 
				
			||||||
    { "/connect",   cmd_connect       },
 | 
					    { "/connect",   cmd_connect       },
 | 
				
			||||||
 | 
					    { "/decline",   cmd_decline       },
 | 
				
			||||||
    { "/exit",      cmd_quit          },
 | 
					    { "/exit",      cmd_quit          },
 | 
				
			||||||
    { "/groupchat", cmd_groupchat     },
 | 
					    { "/conference", cmd_conference    },
 | 
				
			||||||
    { "/help",      cmd_prompt_help   },
 | 
					    { "/help",      cmd_prompt_help   },
 | 
				
			||||||
    { "/log",       cmd_log           },
 | 
					    { "/log",       cmd_log           },
 | 
				
			||||||
    { "/myid",      cmd_myid          },
 | 
					    { "/myid",      cmd_myid          },
 | 
				
			||||||
 | 
					#ifdef QRCODE
 | 
				
			||||||
 | 
					    { "/myqr",      cmd_myqr          },
 | 
				
			||||||
 | 
					#endif /* QRCODE */
 | 
				
			||||||
    { "/nick",      cmd_nick          },
 | 
					    { "/nick",      cmd_nick          },
 | 
				
			||||||
    { "/note",      cmd_note          },
 | 
					    { "/note",      cmd_note          },
 | 
				
			||||||
 | 
					    { "/nospam",    cmd_nospam        },
 | 
				
			||||||
    { "/q",         cmd_quit          },
 | 
					    { "/q",         cmd_quit          },
 | 
				
			||||||
    { "/quit",      cmd_quit          },
 | 
					    { "/quit",      cmd_quit          },
 | 
				
			||||||
 | 
					    { "/requests",  cmd_requests      },
 | 
				
			||||||
    { "/status",    cmd_status        },
 | 
					    { "/status",    cmd_status        },
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					#ifdef AUDIO
 | 
				
			||||||
    { "/lsdev",     cmd_list_devices  },
 | 
					    { "/lsdev",     cmd_list_devices  },
 | 
				
			||||||
    { "/sdev",      cmd_change_device },
 | 
					    { "/sdev",      cmd_change_device },
 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					    { "/lsvdev",    cmd_list_video_devices  },
 | 
				
			||||||
 | 
					    { "/svdev",     cmd_change_video_device },
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					    { "/run",       cmd_run           },
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					    { NULL,         NULL              },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cmd_func chat_commands[] = {
 | 
					static struct cmd_func chat_commands[] = {
 | 
				
			||||||
    { "/help",      cmd_chat_help   },
 | 
					    { "/cancel",    cmd_cancelfile        },
 | 
				
			||||||
    { "/invite",    cmd_groupinvite },
 | 
					    { "/invite",    cmd_conference_invite },
 | 
				
			||||||
    { "/join",      cmd_join_group  },
 | 
					    { "/join",      cmd_conference_join   },
 | 
				
			||||||
    { "/savefile",  cmd_savefile          },
 | 
					    { "/savefile",  cmd_savefile          },
 | 
				
			||||||
    { "/sendfile",  cmd_sendfile          },
 | 
					    { "/sendfile",  cmd_sendfile          },
 | 
				
			||||||
    
 | 
					#ifdef AUDIO
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					 | 
				
			||||||
    { "/call",      cmd_call              },
 | 
					    { "/call",      cmd_call              },
 | 
				
			||||||
    { "/cancel",    cmd_cancel      },
 | 
					 | 
				
			||||||
    { "/answer",    cmd_answer            },
 | 
					    { "/answer",    cmd_answer            },
 | 
				
			||||||
 | 
					    { "/reject",    cmd_reject            },
 | 
				
			||||||
    { "/hangup",    cmd_hangup            },
 | 
					    { "/hangup",    cmd_hangup            },
 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					    { "/mute",      cmd_mute              },
 | 
				
			||||||
 | 
					    { "/sense",     cmd_sense             },
 | 
				
			||||||
 | 
					    { "/bitrate",   cmd_bitrate           },
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					    { "/vcall",     cmd_vcall             },
 | 
				
			||||||
 | 
					    { "/video",     cmd_video             },
 | 
				
			||||||
 | 
					    { "/res",       cmd_res               },
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					    { NULL,         NULL                  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Parses input command and puts args into arg array. 
 | 
					static struct cmd_func conference_commands[] = {
 | 
				
			||||||
   Returns number of arguments on success, -1 on failure. */
 | 
					    { "/title",     cmd_conference_set_title },
 | 
				
			||||||
static int parse_command(WINDOW *w, char *cmd, char (*args)[MAX_STR_SIZE])
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    { "/audio",     cmd_enable_audio },
 | 
				
			||||||
 | 
					    { "/mute",      cmd_conference_mute   },
 | 
				
			||||||
 | 
					    { "/ptt",       cmd_conference_push_to_talk },
 | 
				
			||||||
 | 
					    { "/sense",     cmd_conference_sense  },
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					    { NULL,         NULL             },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					#define SPECIAL_COMMANDS 7
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define SPECIAL_COMMANDS 6
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Special commands are commands that only take one argument even if it contains spaces */
 | 
				
			||||||
 | 
					static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = {
 | 
				
			||||||
 | 
					    "/avatar",
 | 
				
			||||||
 | 
					    "/nick",
 | 
				
			||||||
 | 
					    "/note",
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					    "/run",
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					    "/sendfile",
 | 
				
			||||||
 | 
					    "/title",
 | 
				
			||||||
 | 
					    "/mute",
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns true if input command is in the special_commands array. */
 | 
				
			||||||
 | 
					static bool is_special_command(const char *input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    const int s = char_find(0, input, ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < SPECIAL_COMMANDS; ++i) {
 | 
				
			||||||
 | 
					        if (strncmp(input, special_commands[i], s) == 0) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parses commands in the special_commands array. Unlike parse_command, this function
 | 
				
			||||||
 | 
					 * does not split the input string at spaces.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the number of arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int parse_special_command(const char *input, char (*args)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int len = strlen(input);
 | 
				
			||||||
 | 
					    int s = char_find(0, input, ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(args[0], input, s);
 | 
				
			||||||
 | 
					    args[0][s++] = '\0';    // increment to remove space after "/command "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s >= len) {
 | 
				
			||||||
 | 
					        return 1;  // No additional args
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(args[1], input + s, len - s);
 | 
				
			||||||
 | 
					    args[1][len - s] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Parses input command and puts args into arg array.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns the number of arguments.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int parse_command(const char *input, char (*args)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (is_special_command(input)) {
 | 
				
			||||||
 | 
					        return parse_special_command(input, args);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *cmd = strdup(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cmd == NULL) {
 | 
				
			||||||
 | 
					        exit_toxic_err("failed in parse_command", FATALERR_MEMORY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int num_args = 0;
 | 
					    int num_args = 0;
 | 
				
			||||||
    bool cmd_end = false;    /* flags when we get to the end of cmd */
 | 
					 | 
				
			||||||
    char *end;               /* points to the end of the current arg */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* characters wrapped in double quotes count as one arg */
 | 
					    /* characters wrapped in double quotes count as one arg */
 | 
				
			||||||
    while (!cmd_end && num_args < MAX_NUM_ARGS) {
 | 
					    while (num_args < MAX_NUM_ARGS) {
 | 
				
			||||||
        if (*cmd == '\"') {
 | 
					        int i = char_find(0, cmd, ' ');    // index of last char in an argument
 | 
				
			||||||
            end = strchr(cmd+1, '\"');
 | 
					        memcpy(args[num_args], cmd, i);
 | 
				
			||||||
 | 
					        args[num_args++][i] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (end++ == NULL) {    /* Increment past the end quote */
 | 
					        if (cmd[i] == '\0') {  // no more args
 | 
				
			||||||
                wprintw(w, "Invalid argument. Did you forget a closing \"?\n");
 | 
					            break;
 | 
				
			||||||
                return -1;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            cmd_end = *end == '\0';
 | 
					        char tmp[MAX_STR_SIZE];
 | 
				
			||||||
        } else {
 | 
					        snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]);
 | 
				
			||||||
            end = strchr(cmd, ' ');
 | 
					        strcpy(cmd, tmp);    // tmp will always fit inside cmd
 | 
				
			||||||
            cmd_end = end == NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!cmd_end)
 | 
					 | 
				
			||||||
            *end++ = '\0';    /* mark end of current argument */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Copy from start of current arg to where we just inserted the null byte */
 | 
					 | 
				
			||||||
        strcpy(args[num_args++], cmd);
 | 
					 | 
				
			||||||
        cmd = end;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(cmd);
 | 
				
			||||||
    return num_args;
 | 
					    return num_args;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Matches command to respective function. Returns 0 on match, 1 on no match */
 | 
					/* Matches command to respective function.
 | 
				
			||||||
static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_cmds,
 | 
					 *
 | 
				
			||||||
                      struct cmd_func *commands, char (*args)[MAX_STR_SIZE])
 | 
					 * Returns 0 on match.
 | 
				
			||||||
 | 
					 * Returns 1 on no match
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands,
 | 
				
			||||||
 | 
					                      char (*args)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < num_cmds; ++i) {
 | 
					    for (i = 0; commands[i].name != NULL; ++i) {
 | 
				
			||||||
        if (strcmp(args[0], commands[i].name) == 0) {
 | 
					        if (strcmp(args[0], commands[i].name) == 0) {
 | 
				
			||||||
            (commands[i].func)(w, self, m, num_args-1, args);
 | 
					            (commands[i].func)(w, self, m, num_args - 1, args);
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -125,33 +225,51 @@ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, int num_
 | 
				
			|||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void execute(WINDOW* w, ToxWindow *self, Tox *m, char *cmd, int mode)
 | 
					void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (string_is_empty(cmd))
 | 
					    if (string_is_empty(input)) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char args[MAX_NUM_ARGS][MAX_STR_SIZE] = {0};
 | 
					    char args[MAX_NUM_ARGS][MAX_STR_SIZE];
 | 
				
			||||||
    int num_args = parse_command(w, cmd, args);
 | 
					    int num_args = parse_command(input, args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (num_args == -1)
 | 
					    if (num_args <= 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Try to match input command to command functions. If non-global command mode is specified,
 | 
					    /* Try to match input command to command functions. If non-global command mode is specified,
 | 
				
			||||||
       try specified mode's commands first, then upon failure try global commands. 
 | 
					     * try specified mode's commands first, then upon failure try global commands.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
       Note: Global commands must come last in case of duplicate command names */
 | 
					     * Note: Global commands must come last in case of duplicate command names
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    switch (mode) {
 | 
					    switch (mode) {
 | 
				
			||||||
        case CHAT_COMMAND_MODE:
 | 
					        case CHAT_COMMAND_MODE:
 | 
				
			||||||
        if (do_command(w, self, m, num_args, CHAT_NUM_COMMANDS, chat_commands, args) == 0)
 | 
					            if (do_command(w, self, m, num_args, chat_commands, args) == 0) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case GROUPCHAT_COMMAND_MODE:
 | 
					        case CONFERENCE_COMMAND_MODE:
 | 
				
			||||||
 | 
					            if (do_command(w, self, m, num_args, conference_commands, args) == 0) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (do_command(w, self, m, num_args, GLOBAL_NUM_COMMANDS, global_commands, args) == 0)
 | 
					    if (do_command(w, self, m, num_args, global_commands, args) == 0) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(w, "Invalid command.\n");
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (do_plugin_command(num_args, args) == 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,20 +20,20 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_NUM_ARGS 4     /* Includes command */
 | 
					#ifndef EXECUTE_H
 | 
				
			||||||
 | 
					#define EXECUTE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO 
 | 
					#include "toxic.h"
 | 
				
			||||||
    #define GLOBAL_NUM_COMMANDS 16
 | 
					#include "windows.h"
 | 
				
			||||||
    #define CHAT_NUM_COMMANDS 9
 | 
					
 | 
				
			||||||
#else 
 | 
					#define MAX_NUM_ARGS 4     /* Includes command */
 | 
				
			||||||
    #define GLOBAL_NUM_COMMANDS 14
 | 
					 | 
				
			||||||
    #define CHAT_NUM_COMMANDS 5
 | 
					 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    GLOBAL_COMMAND_MODE,
 | 
					    GLOBAL_COMMAND_MODE,
 | 
				
			||||||
    CHAT_COMMAND_MODE,
 | 
					    CHAT_COMMAND_MODE,
 | 
				
			||||||
    GROUPCHAT_COMMAND_MODE,
 | 
					    CONFERENCE_COMMAND_MODE,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void execute(WINDOW *w, ToxWindow *self, Tox *m, char *cmd, int mode);
 | 
					void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* EXECUTE_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,113 +0,0 @@
 | 
				
			|||||||
/*  file_senders.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  This file is part of Toxic.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 *  it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
 *  the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 *  (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 *  GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "toxic_windows.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FileSender file_senders[MAX_FILES];
 | 
					 | 
				
			||||||
uint8_t max_file_senders_index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void close_file_sender(int i)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    fclose(file_senders[i].file);
 | 
					 | 
				
			||||||
    memset(&file_senders[i], 0, sizeof(FileSender));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int j;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (j = max_file_senders_index; j > 0; --j) {
 | 
					 | 
				
			||||||
        if (file_senders[j-1].active)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    max_file_senders_index = j;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Should only be called on exit */
 | 
					 | 
				
			||||||
void close_all_file_senders(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < max_file_senders_index; ++i) {
 | 
					 | 
				
			||||||
        if (file_senders[i].active)
 | 
					 | 
				
			||||||
            fclose(file_senders[i].file);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void do_file_senders(Tox *m)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < max_file_senders_index; ++i) {
 | 
					 | 
				
			||||||
        if (!file_senders[i].active)
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint8_t *pathname = file_senders[i].pathname;
 | 
					 | 
				
			||||||
        uint8_t filenum = file_senders[i].filenum;
 | 
					 | 
				
			||||||
        int friendnum = file_senders[i].friendnum;
 | 
					 | 
				
			||||||
        FILE *fp = file_senders[i].file;
 | 
					 | 
				
			||||||
        uint64_t current_time = (uint64_t) time(NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* If file transfer has timed out kill transfer and send kill control */
 | 
					 | 
				
			||||||
        if (timed_out(file_senders[i].timestamp, current_time, TIMEOUT_FILESENDER)) {
 | 
					 | 
				
			||||||
            ChatContext *ctx = file_senders[i].toxwin->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (ctx != NULL) {
 | 
					 | 
				
			||||||
                wprintw(ctx->history, "File transfer for '%s' timed out.\n", pathname);
 | 
					 | 
				
			||||||
                alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_KILL, 0, 0);
 | 
					 | 
				
			||||||
            close_file_sender(i);
 | 
					 | 
				
			||||||
            continue;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (true) {
 | 
					 | 
				
			||||||
            if (tox_file_send_data(m, friendnum, filenum, file_senders[i].nextpiece, 
 | 
					 | 
				
			||||||
                                   file_senders[i].piecelen) == -1)
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            file_senders[i].timestamp = current_time;
 | 
					 | 
				
			||||||
            file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1, 
 | 
					 | 
				
			||||||
                                             tox_file_data_size(m, friendnum), fp);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (file_senders[i].piecelen == 0) {
 | 
					 | 
				
			||||||
                ChatContext *ctx = file_senders[i].toxwin->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (ctx != NULL) {
 | 
					 | 
				
			||||||
                    wprintw(ctx->history, "File '%s' successfuly sent.\n", pathname);
 | 
					 | 
				
			||||||
                    alert_window(file_senders[i].toxwin, WINDOW_ALERT_2, true);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
 | 
					 | 
				
			||||||
                close_file_sender(i);
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										309
									
								
								src/file_transfers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								src/file_transfers.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,309 @@
 | 
				
			|||||||
 | 
					/*  file_transfers.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "file_transfers.h"
 | 
				
			||||||
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "notify.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern FriendsList Friends;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
 | 
				
			||||||
 | 
					#define NUM_PROG_MARKS 50
 | 
				
			||||||
 | 
					#define STR_BUF_SIZE 30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* creates initial progress line that will be updated during file transfer.
 | 
				
			||||||
 | 
					   Assumes progline has room for at least MAX_STR_SIZE bytes */
 | 
				
			||||||
 | 
					void init_progress_bar(char *progline)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    strcpy(progline, "0% [");
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < NUM_PROG_MARKS; ++i) {
 | 
				
			||||||
 | 
					        strcat(progline, "-");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    strcat(progline, "] 0.0 B/s");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* prints a progress bar for file transfers. */
 | 
				
			||||||
 | 
					void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t line_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (bps < 0 || pct_done < 0 || pct_done > 100) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char pct_str[STR_BUF_SIZE];
 | 
				
			||||||
 | 
					    snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char bps_str[STR_BUF_SIZE];
 | 
				
			||||||
 | 
					    bytes_convert_str(bps_str, sizeof(bps_str), bps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char prog_line[NUM_PROG_MARKS + 1];
 | 
				
			||||||
 | 
					    prog_line[0] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int n = pct_done / (100 / NUM_PROG_MARKS);
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < n; ++i) {
 | 
				
			||||||
 | 
					        strcat(prog_line, "=");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pct_done < 100) {
 | 
				
			||||||
 | 
					        strcpy(prog_line + n, ">");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (j = i; j < NUM_PROG_MARKS - 1; ++j) {
 | 
				
			||||||
 | 
					        strcat(prog_line, "-");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t line_buf_size = strlen(pct_str) + NUM_PROG_MARKS + strlen(bps_str) + 7;
 | 
				
			||||||
 | 
					    char *full_line = malloc(line_buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (full_line == NULL) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    snprintf(full_line, line_buf_size, "%s [%s] %s/s", pct_str, prog_line, bps_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_set(self, line_id, full_line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(full_line);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void refresh_progress_helper(ToxWindow *self, struct FileTransfer *ft)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Timeout must be set to 1 second to show correct bytes per second */
 | 
				
			||||||
 | 
					    if (!timed_out(ft->last_line_progress, 1)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    double remain = ft->file_size - ft->position;
 | 
				
			||||||
 | 
					    double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
 | 
				
			||||||
 | 
					    print_progress_bar(self, ft->bps, pct_done, ft->line_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ft->bps = 0;
 | 
				
			||||||
 | 
					    ft->last_line_progress = get_unix_time();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* refreshes active file transfer status bars. */
 | 
				
			||||||
 | 
					void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        refresh_progress_helper(self, &Friends.list[friendnumber].file_receiver[i]);
 | 
				
			||||||
 | 
					        refresh_progress_helper(self, &Friends.list[friendnumber].file_sender[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void clear_file_transfer(struct FileTransfer *ft)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    *ft = (struct FileTransfer) {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
 | 
				
			||||||
 | 
					 * Returns NULL if filenumber is invalid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        struct FileTransfer *ft_send = &Friends.list[friendnumber].file_sender[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft_send->state != FILE_TRANSFER_INACTIVE && ft_send->filenumber == filenumber) {
 | 
				
			||||||
 | 
					            return ft_send;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        struct FileTransfer *ft_recv = &Friends.list[friendnumber].file_receiver[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft_recv->state != FILE_TRANSFER_INACTIVE && ft_recv->filenumber == filenumber) {
 | 
				
			||||||
 | 
					            return ft_recv;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
 | 
				
			||||||
 | 
					 * Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
 | 
				
			||||||
 | 
					        FILE_TRANSFER_DIRECTION direction)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (direction != FILE_TRANSFER_RECV && direction != FILE_TRANSFER_SEND) {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        struct FileTransfer *ft = direction == FILE_TRANSFER_SEND ?
 | 
				
			||||||
 | 
					                                      &Friends.list[friendnumber].file_sender[i] :
 | 
				
			||||||
 | 
					                                      &Friends.list[friendnumber].file_receiver[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft->state != FILE_TRANSFER_INACTIVE && ft->index == index) {
 | 
				
			||||||
 | 
					            return ft;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to an unused file sender.
 | 
				
			||||||
 | 
					 * Returns NULL if all file senders are in use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct FileTransfer *new_file_sender(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber, uint8_t type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
 | 
					            clear_file_transfer(ft);
 | 
				
			||||||
 | 
					            ft->window = window;
 | 
				
			||||||
 | 
					            ft->index = i;
 | 
				
			||||||
 | 
					            ft->friendnumber = friendnumber;
 | 
				
			||||||
 | 
					            ft->filenumber = filenumber;
 | 
				
			||||||
 | 
					            ft->file_type = type;
 | 
				
			||||||
 | 
					            ft->state = FILE_TRANSFER_PENDING;
 | 
				
			||||||
 | 
					            return ft;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to an unused file receiver.
 | 
				
			||||||
 | 
					 * Returns NULL if all file receivers are in use.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
 | 
				
			||||||
 | 
					        uint8_t type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        struct FileTransfer *ft = &Friends.list[friendnumber].file_receiver[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
 | 
					            clear_file_transfer(ft);
 | 
				
			||||||
 | 
					            ft->window = window;
 | 
				
			||||||
 | 
					            ft->index = i;
 | 
				
			||||||
 | 
					            ft->friendnumber = friendnumber;
 | 
				
			||||||
 | 
					            ft->filenumber = filenumber;
 | 
				
			||||||
 | 
					            ft->file_type = type;
 | 
				
			||||||
 | 
					            ft->state = FILE_TRANSFER_PENDING;
 | 
				
			||||||
 | 
					            return ft;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Initializes an unused file transfer and returns its pointer.
 | 
				
			||||||
 | 
					 * Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
 | 
				
			||||||
 | 
					                                       FILE_TRANSFER_DIRECTION direction, uint8_t type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (direction == FILE_TRANSFER_RECV) {
 | 
				
			||||||
 | 
					        return new_file_receiver(window, friendnumber, filenumber, type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (direction == FILE_TRANSFER_SEND) {
 | 
				
			||||||
 | 
					        return new_file_sender(window, friendnumber, filenumber, type);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Closes file transfer ft.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Set CTRL to -1 if we don't want to send a control signal.
 | 
				
			||||||
 | 
					 * Set message or self to NULL if we don't want to display a message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
 | 
				
			||||||
 | 
					                         Notification sound_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!ft) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ft->state == FILE_TRANSFER_INACTIVE) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ft->file) {
 | 
				
			||||||
 | 
					        fclose(ft->file);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (CTRL >= 0) {
 | 
				
			||||||
 | 
					        tox_file_control(m, ft->friendnumber, ft->filenumber, (Tox_File_Control) CTRL, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (message && self) {
 | 
				
			||||||
 | 
					        if (self->active_box != -1 && sound_type != silent) {
 | 
				
			||||||
 | 
					            box_notify2(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", message);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clear_file_transfer(ft);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Kills active outgoing avatar file transfers for friendnumber */
 | 
				
			||||||
 | 
					void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        struct FileTransfer *ft = &Friends.list[friendnumber].file_sender[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ft->file_type == TOX_FILE_KIND_AVATAR) {
 | 
				
			||||||
 | 
					            close_file_transfer(NULL, m, ft, TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Kills all active file transfers for friendnumber */
 | 
				
			||||||
 | 
					void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < MAX_FILES; ++i) {
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, &Friends.list[friendnumber].file_sender[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					        close_file_transfer(NULL, m, &Friends.list[friendnumber].file_receiver[i], TOX_FILE_CONTROL_CANCEL, NULL, silent);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kill_all_file_transfers(Tox *m)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < Friends.max_idx; ++i) {
 | 
				
			||||||
 | 
					        kill_all_file_transfers_friend(m, Friends.list[i].num);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/file_transfers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/file_transfers.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					/*  file_transfers.h
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FILE_TRANSFERS_H
 | 
				
			||||||
 | 
					#define FILE_TRANSFERS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "notify.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define KiB 1024
 | 
				
			||||||
 | 
					#define MiB 1048576       /* 1024^2 */
 | 
				
			||||||
 | 
					#define GiB 1073741824    /* 1024^3 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_FILES 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum FILE_TRANSFER_STATE {
 | 
				
			||||||
 | 
					    FILE_TRANSFER_INACTIVE,
 | 
				
			||||||
 | 
					    FILE_TRANSFER_PAUSED,
 | 
				
			||||||
 | 
					    FILE_TRANSFER_PENDING,
 | 
				
			||||||
 | 
					    FILE_TRANSFER_STARTED,
 | 
				
			||||||
 | 
					} FILE_TRANSFER_STATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum FILE_TRANSFER_DIRECTION {
 | 
				
			||||||
 | 
					    FILE_TRANSFER_SEND,
 | 
				
			||||||
 | 
					    FILE_TRANSFER_RECV
 | 
				
			||||||
 | 
					} FILE_TRANSFER_DIRECTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct FileTransfer {
 | 
				
			||||||
 | 
					    ToxWindow *window;
 | 
				
			||||||
 | 
					    FILE *file;
 | 
				
			||||||
 | 
					    FILE_TRANSFER_STATE state;
 | 
				
			||||||
 | 
					    uint8_t file_type;
 | 
				
			||||||
 | 
					    char file_name[TOX_MAX_FILENAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    char file_path[PATH_MAX + 1];    /* Not used by senders */
 | 
				
			||||||
 | 
					    double   bps;
 | 
				
			||||||
 | 
					    uint32_t filenumber;
 | 
				
			||||||
 | 
					    uint32_t friendnumber;
 | 
				
			||||||
 | 
					    size_t   index;
 | 
				
			||||||
 | 
					    uint64_t file_size;
 | 
				
			||||||
 | 
					    uint64_t position;
 | 
				
			||||||
 | 
					    time_t   last_line_progress;   /* The last time we updated the progress bar */
 | 
				
			||||||
 | 
					    uint32_t line_id;
 | 
				
			||||||
 | 
					    uint8_t  file_id[TOX_FILE_ID_LENGTH];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* creates initial progress line that will be updated during file transfer.
 | 
				
			||||||
 | 
					   progline must be at lesat MAX_STR_SIZE bytes */
 | 
				
			||||||
 | 
					void init_progress_bar(char *progline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* prints a progress bar for file transfers */
 | 
				
			||||||
 | 
					void print_progress_bar(ToxWindow *self, double pct_done, double bps, uint32_t line_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* refreshes active file transfer status bars. */
 | 
				
			||||||
 | 
					void refresh_file_transfer_progress(ToxWindow *self, uint32_t friendnumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to friendnumber's FileTransfer struct associated with filenumber.
 | 
				
			||||||
 | 
					 * Returns NULL if filenumber is invalid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *get_file_transfer_struct(uint32_t friendnumber, uint32_t filenumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns a pointer to the FileTransfer struct associated with index with the direction specified.
 | 
				
			||||||
 | 
					 * Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *get_file_transfer_struct_index(uint32_t friendnumber, uint32_t index,
 | 
				
			||||||
 | 
					        FILE_TRANSFER_DIRECTION direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Initializes an unused file transfer and returns its pointer.
 | 
				
			||||||
 | 
					 * Returns NULL on failure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct FileTransfer *new_file_transfer(ToxWindow *window, uint32_t friendnumber, uint32_t filenumber,
 | 
				
			||||||
 | 
					                                       FILE_TRANSFER_DIRECTION direction, uint8_t type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Closes file transfer ft.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Set CTRL to -1 if we don't want to send a control signal.
 | 
				
			||||||
 | 
					 * Set message or self to NULL if we don't want to display a message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int CTRL, const char *message,
 | 
				
			||||||
 | 
					                         Notification sound_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Kills active outgoing avatar file transfers for friendnumber */
 | 
				
			||||||
 | 
					void kill_avatar_file_transfers_friend(Tox *m, uint32_t friendnumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Kills all active file transfers for friendnumber */
 | 
				
			||||||
 | 
					void kill_all_file_transfers_friend(Tox *m, uint32_t friendnumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void kill_all_file_transfers(Tox *m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* FILE_TRANSFERS_H */
 | 
				
			||||||
							
								
								
									
										1488
									
								
								src/friendlist.c
									
									
									
									
									
								
							
							
						
						
									
										1488
									
								
								src/friendlist.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -20,40 +20,85 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef FRIENDLIST_H_53I41IM
 | 
					#ifndef FRIENDLIST_H
 | 
				
			||||||
#define FRIENDLIST_H_53I41IM
 | 
					#define FRIENDLIST_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "toxic_windows.h"
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "file_transfers.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct LastOnline {
 | 
				
			||||||
 | 
					    uint64_t last_on;
 | 
				
			||||||
 | 
					    struct tm tm;
 | 
				
			||||||
 | 
					    char hour_min_str[TIME_STR_SIZE];    /* holds 12/24-hour time string e.g. "10:43 PM" */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ConferenceInvite {
 | 
				
			||||||
 | 
					    char *key;
 | 
				
			||||||
 | 
					    uint16_t length;
 | 
				
			||||||
 | 
					    uint8_t type;
 | 
				
			||||||
 | 
					    bool pending;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    uint8_t name[TOX_MAX_NAME_LENGTH];
 | 
					    char name[TOXIC_MAX_NAME_LENGTH + 1];
 | 
				
			||||||
    uint16_t namelength;
 | 
					    uint16_t namelength;
 | 
				
			||||||
    uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];
 | 
					    char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH + 1];
 | 
				
			||||||
    uint16_t statusmsg_len;
 | 
					    size_t statusmsg_len;
 | 
				
			||||||
    uint8_t pending_groupchat[TOX_CLIENT_ID_SIZE];
 | 
					    char pub_key[TOX_PUBLIC_KEY_SIZE];
 | 
				
			||||||
    uint8_t pub_key[TOX_CLIENT_ID_SIZE];
 | 
					    uint32_t num;
 | 
				
			||||||
    int num;
 | 
					 | 
				
			||||||
    int chatwin;
 | 
					    int chatwin;
 | 
				
			||||||
    bool active;
 | 
					    bool active;
 | 
				
			||||||
    bool online;
 | 
					    Tox_Connection connection_status;
 | 
				
			||||||
    bool is_typing;
 | 
					    bool is_typing;
 | 
				
			||||||
    bool logging_on;    /* saves preference for friend irrespective of chat windows */
 | 
					    bool logging_on;    /* saves preference for friend irrespective of global settings */
 | 
				
			||||||
    TOX_USERSTATUS status;
 | 
					    Tox_User_Status status;
 | 
				
			||||||
    struct FileReceiver file_receiver;
 | 
					
 | 
				
			||||||
 | 
					    struct LastOnline last_online;
 | 
				
			||||||
 | 
					    struct ConferenceInvite conference_invite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct FileTransfer file_receiver[MAX_FILES];
 | 
				
			||||||
 | 
					    struct FileTransfer file_sender[MAX_FILES];
 | 
				
			||||||
} ToxicFriend;
 | 
					} ToxicFriend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    int num;
 | 
					    char name[TOXIC_MAX_NAME_LENGTH + 1];
 | 
				
			||||||
 | 
					    uint16_t namelength;
 | 
				
			||||||
 | 
					    char pub_key[TOX_PUBLIC_KEY_SIZE];
 | 
				
			||||||
 | 
					    uint32_t num;
 | 
				
			||||||
    bool active;
 | 
					    bool active;
 | 
				
			||||||
} PendingDel;
 | 
					    uint64_t last_on;
 | 
				
			||||||
 | 
					} BlockedFriend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ToxWindow new_friendlist(void);
 | 
					typedef struct {
 | 
				
			||||||
void disable_chatwin(int f_num);
 | 
					    int num_selected;
 | 
				
			||||||
 | 
					    size_t num_friends;
 | 
				
			||||||
 | 
					    size_t num_online;
 | 
				
			||||||
 | 
					    size_t max_idx;    /* 1 + the index of the last friend in list */
 | 
				
			||||||
 | 
					    uint32_t *index;
 | 
				
			||||||
 | 
					    ToxicFriend *list;
 | 
				
			||||||
 | 
					} FriendsList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToxWindow *new_friendlist(void);
 | 
				
			||||||
 | 
					void friendlist_onInit(ToxWindow *self, Tox *m);
 | 
				
			||||||
 | 
					void disable_chatwin(uint32_t f_num);
 | 
				
			||||||
int get_friendnum(uint8_t *name);
 | 
					int get_friendnum(uint8_t *name);
 | 
				
			||||||
 | 
					int load_blocklist(char *data);
 | 
				
			||||||
void friendlist_onFriendAdded(ToxWindow *self, Tox *m, int num, bool sort);
 | 
					void kill_friendlist(ToxWindow *self);
 | 
				
			||||||
 | 
					void friendlist_onFriendAdded(ToxWindow *self, Tox *m, uint32_t num, bool sort);
 | 
				
			||||||
 | 
					Tox_User_Status get_friend_status(uint32_t friendnumber);
 | 
				
			||||||
 | 
					Tox_Connection get_friend_connection_status(uint32_t friendnumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* sorts friendlist_index first by connection status then alphabetically */
 | 
					/* sorts friendlist_index first by connection status then alphabetically */
 | 
				
			||||||
void sort_friendlist_index(Tox *m);
 | 
					void sort_friendlist_index(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* end of include guard: FRIENDLIST_H_53I41IM */
 | 
					/*
 | 
				
			||||||
 | 
					 * Returns true if friend associated with `public_key` is in the block list.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `public_key` must be at least TOX_PUBLIC_KEY_SIZE bytes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool friend_is_blocked(const char *public_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* end of include guard: FRIENDLIST_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,424 +20,705 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "toxic_windows.h"
 | 
					#include "avatars.h"
 | 
				
			||||||
#include "misc_tools.h"
 | 
					#include "conference.h"
 | 
				
			||||||
#include "friendlist.h"
 | 
					#include "friendlist.h"
 | 
				
			||||||
 | 
					#include "help.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "name_lookup.h"
 | 
				
			||||||
 | 
					#include "prompt.h"
 | 
				
			||||||
 | 
					#include "qr_code.h"
 | 
				
			||||||
 | 
					#include "term_mplex.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "toxic_strings.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern char *DATA_FILE;
 | 
					extern char *DATA_FILE;
 | 
				
			||||||
extern ToxWindow *prompt;
 | 
					extern ToxWindow *prompt;
 | 
				
			||||||
 | 
					extern FriendsList Friends;
 | 
				
			||||||
extern ToxicFriend friends[MAX_FRIENDS_NUM];
 | 
					extern FriendRequests FrndRequests;
 | 
				
			||||||
 | 
					 | 
				
			||||||
extern uint8_t pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
 | 
					 | 
				
			||||||
extern uint8_t num_frnd_requests;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* command functions */
 | 
					/* command functions */
 | 
				
			||||||
void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* check arguments */
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
    if (argc != 1) {
 | 
					
 | 
				
			||||||
      wprintw(window, "Invalid syntax.\n");
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int req = atoi(argv[1]);
 | 
					    long int req = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((req == 0 && strcmp(argv[1], "0"))|| req >= MAX_FRIENDS_NUM) {
 | 
					    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
				
			||||||
        wprintw(window, "No pending friend request with that number.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!strlen(pending_frnd_requests[req])) {
 | 
					    if (!FrndRequests.request[req].active) {
 | 
				
			||||||
        wprintw(window, "No pending friend request with that number.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int friendnum = tox_add_friend_norequest(m, pending_frnd_requests[req]);
 | 
					    Tox_Err_Friend_Add err;
 | 
				
			||||||
 | 
					    uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (friendnum == -1)
 | 
					    if (err != TOX_ERR_FRIEND_ADD_OK) {
 | 
				
			||||||
        wprintw(window, "Failed to add friend.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
 | 
				
			||||||
    else {
 | 
					        return;
 | 
				
			||||||
        wprintw(window, "Friend request accepted.\n");
 | 
					    } else {
 | 
				
			||||||
        on_friendadded(m, friendnum, true);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
 | 
				
			||||||
 | 
					        on_friend_added(m, friendnum, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    memset(&pending_frnd_requests[req], 0, TOX_CLIENT_ID_SIZE);
 | 
					    FrndRequests.request[req] = (struct friend_request) {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = num_frnd_requests; i > 0; --i) {
 | 
					    for (i = FrndRequests.max_idx; i > 0; --i) {
 | 
				
			||||||
        if (!strlen(pending_frnd_requests[i-1]))
 | 
					        if (FrndRequests.request[i - 1].active) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FrndRequests.max_idx = i;
 | 
				
			||||||
 | 
					    --FrndRequests.num_requests;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char *errmsg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Tox_Err_Friend_Add err;
 | 
				
			||||||
 | 
					    uint32_t f_num = tox_friend_add(m, (const uint8_t *) id_bin, (const uint8_t *) msg, strlen(msg), &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (err) {
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_TOO_LONG:
 | 
				
			||||||
 | 
					            errmsg = "Message is too long.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_NO_MESSAGE:
 | 
				
			||||||
 | 
					            errmsg = "Please add a message to your request.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_OWN_KEY:
 | 
				
			||||||
 | 
					            errmsg = "That appears to be your own ID.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_ALREADY_SENT:
 | 
				
			||||||
 | 
					            errmsg = "Friend request has already been sent.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:
 | 
				
			||||||
 | 
					            errmsg = "Bad checksum in address.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:
 | 
				
			||||||
 | 
					            errmsg = "Nospam was different.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_MALLOC:
 | 
				
			||||||
 | 
					            errmsg = "Core memory allocation failed.";
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_OK:
 | 
				
			||||||
 | 
					            errmsg = "Friend request sent.";
 | 
				
			||||||
 | 
					            on_friend_added(m, f_num, true);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_FRIEND_ADD_NULL:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* fallthrough */
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            errmsg = "Failed to add friend: Unknown error.";
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    num_frnd_requests = i;
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        wprintw(window, "Invalid syntax.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *id = argv[1];
 | 
					    const char *id = argv[1];
 | 
				
			||||||
    uint8_t msg[MAX_STR_SIZE];
 | 
					    char msg[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc > 1) {
 | 
					    if (argc > 1) {
 | 
				
			||||||
        uint8_t *temp = argv[2];
 | 
					        if (argv[2][0] != '\"') {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
 | 
				
			||||||
        if (temp[0] != '\"') {
 | 
					 | 
				
			||||||
            wprintw(window, "Message must be enclosed in quotes.\n");
 | 
					 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        temp[strlen(++temp)-1] = L'\0';
 | 
					        /* remove opening and closing quotes */
 | 
				
			||||||
        snprintf(msg, sizeof(msg), "%s", temp);
 | 
					        char tmp[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					        snprintf(tmp, sizeof(tmp), "%s", &argv[2][1]);
 | 
				
			||||||
 | 
					        int len = strlen(tmp) - 1;
 | 
				
			||||||
 | 
					        tmp[len] = '\0';
 | 
				
			||||||
 | 
					        snprintf(msg, sizeof(msg), "%s", tmp);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        uint8_t selfname[TOX_MAX_NAME_LENGTH];
 | 
					        char selfname[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
        tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH);
 | 
					        tox_self_get_name(m, (uint8_t *) selfname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t n_len = tox_self_get_name_size(m);
 | 
				
			||||||
 | 
					        selfname[n_len] = '\0';
 | 
				
			||||||
        snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
 | 
					        snprintf(msg, sizeof(msg), "Hello, my name is %s. Care to Tox?", selfname);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (strlen(id) != 2 * TOX_FRIEND_ADDRESS_SIZE) {
 | 
					    char id_bin[TOX_ADDRESS_SIZE] = {0};
 | 
				
			||||||
        wprintw(window, "Invalid ID length.\n");
 | 
					    uint16_t id_len = (uint16_t) strlen(id);
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* try to add tox ID */
 | 
				
			||||||
 | 
					    if (id_len == 2 * TOX_ADDRESS_SIZE) {
 | 
				
			||||||
        size_t i;
 | 
					        size_t i;
 | 
				
			||||||
        char xx[3];
 | 
					        char xx[3];
 | 
				
			||||||
        uint32_t x;
 | 
					        uint32_t x;
 | 
				
			||||||
    uint8_t id_bin[TOX_FRIEND_ADDRESS_SIZE];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
 | 
					        for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {
 | 
				
			||||||
            xx[0] = id[2 * i];
 | 
					            xx[0] = id[2 * i];
 | 
				
			||||||
            xx[1] = id[2 * i + 1];
 | 
					            xx[1] = id[2 * i + 1];
 | 
				
			||||||
            xx[2] = '\0';
 | 
					            xx[2] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (sscanf(xx, "%02x", &x) != 1) {
 | 
					            if (sscanf(xx, "%02x", &x) != 1) {
 | 
				
			||||||
            wprintw(window, "Invalid ID.\n");
 | 
					                line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            id_bin[i] = x;
 | 
					            id_bin[i] = x;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
 | 
					        if (friend_is_blocked(id_bin)) {
 | 
				
			||||||
        id[i] = toupper(id[i]);
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int f_num = tox_add_friend(m, id_bin, msg, strlen(msg) + 1);
 | 
					        cmd_add_helper(self, m, id_bin, msg);
 | 
				
			||||||
 | 
					    } else {    /* assume id is a username@domain address and do http name server lookup */
 | 
				
			||||||
    switch (f_num) {
 | 
					        name_lookup(self, m, id_bin, id, msg);
 | 
				
			||||||
    case TOX_FAERR_TOOLONG:
 | 
					 | 
				
			||||||
        wprintw(window, "Message is too long.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_NOMESSAGE:
 | 
					 | 
				
			||||||
        wprintw(window, "Please add a message to your request.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_OWNKEY:
 | 
					 | 
				
			||||||
        wprintw(window, "That appears to be your own ID.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_ALREADYSENT:
 | 
					 | 
				
			||||||
        wprintw(window, "Friend request has already been sent.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_UNKNOWN:
 | 
					 | 
				
			||||||
        wprintw(window, "Undefined error when adding friend.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_BADCHECKSUM:
 | 
					 | 
				
			||||||
        wprintw(window, "Bad checksum in address.\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case TOX_FAERR_SETNEWNOSPAM:
 | 
					 | 
				
			||||||
        wprintw(window, "Nospam was different (is this contact already added?)\n");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
        wprintw(window, "Friend request sent.\n");
 | 
					 | 
				
			||||||
        on_friendadded(m, f_num, true);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc != 1 || strlen(argv[1]) < 3) {
 | 
				
			||||||
 | 
					        avatar_unset(m);
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char path[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    snprintf(path, sizeof(path), "%s", argv[1]);
 | 
				
			||||||
 | 
					    int len = strlen(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (len <= 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    path[len] = '\0';
 | 
				
			||||||
 | 
					    char filename[MAX_STR_SIZE];
 | 
				
			||||||
 | 
					    get_file_name(filename, sizeof(filename), path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (avatar_set(m, path, len) == -1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
 | 
					                      "Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.",
 | 
				
			||||||
 | 
					                      MAX_AVATAR_FILE_SIZE);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    wclear(window);
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
    wprintw(window, "\n\n");
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_clear(self->chatwin->hst);
 | 
				
			||||||
 | 
					    force_refresh(window);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* check arguments */
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc != 3) {
 | 
					    if (argc != 3) {
 | 
				
			||||||
      wprintw(window, "Invalid syntax.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tox_IP_Port dht;
 | 
					    const char *ip = argv[1];
 | 
				
			||||||
    char *ip = argv[1];
 | 
					    const char *port_str = argv[2];
 | 
				
			||||||
    char *port = argv[2];
 | 
					    const char *ascii_key = argv[3];
 | 
				
			||||||
    char *key = argv[3];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (atoi(port) == 0) {
 | 
					    long int port = strtol(port_str, NULL, 10);
 | 
				
			||||||
        wprintw(window, "Invalid syntax.\n");
 | 
					
 | 
				
			||||||
 | 
					    if (port <= 0 || port > MAX_PORT_RANGE) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *binary_string = hex_string_to_bin(key);
 | 
					    char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
 | 
				
			||||||
    tox_bootstrap_from_address(m, ip, TOX_ENABLE_IPV6_DEFAULT,
 | 
					
 | 
				
			||||||
                               htons(atoi(port)), binary_string);
 | 
					    if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
 | 
				
			||||||
    free(binary_string);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Tox_Err_Bootstrap err;
 | 
				
			||||||
 | 
					    tox_bootstrap(m, ip, port, (uint8_t *) key_binary, &err);
 | 
				
			||||||
 | 
					    tox_add_tcp_relay(m, ip, port, (uint8_t *) key_binary, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (err) {
 | 
				
			||||||
 | 
					        case TOX_ERR_BOOTSTRAP_BAD_HOST:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_BOOTSTRAP_BAD_PORT:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case TOX_ERR_BOOTSTRAP_NULL:
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_groupchat(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long int req = strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!FrndRequests.request[req].active) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FrndRequests.request[req] = (struct friend_request) {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = FrndRequests.max_idx; i > 0; --i) {
 | 
				
			||||||
 | 
					        if (FrndRequests.request[i - 1].active) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FrndRequests.max_idx = i;
 | 
				
			||||||
 | 
					    --FrndRequests.num_requests;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
					    if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
 | 
				
			||||||
        wattron(window, COLOR_PAIR(RED));
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
 | 
				
			||||||
        wprintw(window, " * Warning: Too many windows are open.\n");
 | 
					 | 
				
			||||||
        wattron(window, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int groupnum = tox_add_groupchat(m);
 | 
					    if (argc < 1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
 | 
				
			||||||
    if (groupnum == -1) {
 | 
					 | 
				
			||||||
        wprintw(window, "Group chat instance failed to initialize.\n");
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init_groupchat_win(prompt, m, groupnum) == -1) {
 | 
					    uint8_t type;
 | 
				
			||||||
        wprintw(window, "Group chat window failed to initialize.\n");
 | 
					
 | 
				
			||||||
        tox_del_groupchat(m, groupnum);
 | 
					    if (!strcasecmp(argv[1], "audio")) {
 | 
				
			||||||
 | 
					        type = TOX_CONFERENCE_TYPE_AV;
 | 
				
			||||||
 | 
					    } else if (!strcasecmp(argv[1], "text")) {
 | 
				
			||||||
 | 
					        type = TOX_CONFERENCE_TYPE_TEXT;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "Group chat created as %d.\n", groupnum);
 | 
					    uint32_t conferencenum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == TOX_CONFERENCE_TYPE_TEXT) {
 | 
				
			||||||
 | 
					        Tox_Err_Conference_New err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        conferencenum = tox_conference_new(m, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err != TOX_ERR_CONFERENCE_NEW_OK) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					        conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (conferencenum == (uint32_t) -1) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
 | 
				
			||||||
 | 
					        tox_conference_delete(m, conferencenum, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type == TOX_CONFERENCE_TYPE_AV) {
 | 
				
			||||||
 | 
					        if (!init_conference_audio_input(m, conferencenum)) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *msg;
 | 
				
			||||||
 | 
					    struct chatlog *log = self->chatwin->log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc == 0) {
 | 
					    if (argc == 0) {
 | 
				
			||||||
        bool on;
 | 
					        if (log->log_on) {
 | 
				
			||||||
 | 
					            msg = "Logging for this window is ON; type \"/log off\" to disable. (Logs are not encrypted)";
 | 
				
			||||||
        if (self->is_chat || self->is_groupchat)
 | 
					 | 
				
			||||||
            on = self->chatwin->log->log_on;
 | 
					 | 
				
			||||||
        else if (self->is_prompt)
 | 
					 | 
				
			||||||
            on = self->promptbuf->log->log_on;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (on) {
 | 
					 | 
				
			||||||
            wprintw(window, "Logging for this window is ");
 | 
					 | 
				
			||||||
            wattron(window, COLOR_PAIR(GREEN) | A_BOLD);
 | 
					 | 
				
			||||||
            wprintw(window, "[on]");
 | 
					 | 
				
			||||||
            wattroff(window, COLOR_PAIR(GREEN) | A_BOLD);
 | 
					 | 
				
			||||||
            wprintw(window, ". Type \"/log off\" to disable.\n");
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            wprintw(window, "Logging for this window is ");
 | 
					            msg = "Logging for this window is OFF; type \"/log on\" to enable.";
 | 
				
			||||||
            wattron(window, COLOR_PAIR(RED) | A_BOLD);
 | 
					 | 
				
			||||||
            wprintw(window, "[off]");
 | 
					 | 
				
			||||||
            wattroff(window, COLOR_PAIR(RED) | A_BOLD);
 | 
					 | 
				
			||||||
            wprintw(window, ". Type \"/log on\" to enable.\n");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *swch = argv[1];
 | 
					    const char *swch = argv[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
 | 
					    if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
 | 
				
			||||||
 | 
					        msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
 | 
				
			||||||
        if (self->is_chat) {
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
            friends[self->num].logging_on = true;
 | 
					 | 
				
			||||||
            log_enable(self->name, friends[self->num].pub_key, self->chatwin->log);
 | 
					 | 
				
			||||||
        } else if (self->is_prompt) {
 | 
					 | 
				
			||||||
            uint8_t myid[TOX_FRIEND_ADDRESS_SIZE];
 | 
					 | 
				
			||||||
            tox_get_address(m, myid);
 | 
					 | 
				
			||||||
            log_enable(self->name, &myid, self->promptbuf->log);
 | 
					 | 
				
			||||||
        } else if (self->is_groupchat) {
 | 
					 | 
				
			||||||
            log_enable(self->name, NULL, self->chatwin->log);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wprintw(window, "Logging ");
 | 
					 | 
				
			||||||
        wattron(window, COLOR_PAIR(GREEN) | A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(window, "[on]\n");
 | 
					 | 
				
			||||||
        wattroff(window, COLOR_PAIR(GREEN) | A_BOLD);
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
 | 
					    } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
 | 
				
			||||||
        if (self->is_chat) {
 | 
					        if (self->type == WINDOW_TYPE_CHAT) {
 | 
				
			||||||
            friends[self->num].logging_on = false;
 | 
					            Friends.list[self->num].logging_on = false;
 | 
				
			||||||
            log_disable(self->chatwin->log);
 | 
					 | 
				
			||||||
        } else if (self->is_prompt) {
 | 
					 | 
				
			||||||
            log_disable(self->promptbuf->log);
 | 
					 | 
				
			||||||
        } else if (self->is_groupchat) {
 | 
					 | 
				
			||||||
            log_disable(self->chatwin->log);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wprintw(window, "Logging ");
 | 
					        log_disable(log);
 | 
				
			||||||
        wattron(window, COLOR_PAIR(RED) | A_BOLD);
 | 
					
 | 
				
			||||||
        wprintw(window, "[off]\n");
 | 
					        msg = "Logging disabled.";
 | 
				
			||||||
        wattroff(window, COLOR_PAIR(RED) | A_BOLD);
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.\n");
 | 
					    msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    char id[TOX_FRIEND_ADDRESS_SIZE * 2 + 1] = {0};
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
    uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
    tox_get_address(m, address);
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t i;
 | 
					    char id_string[TOX_ADDRESS_SIZE * 2 + 1];
 | 
				
			||||||
 | 
					    char bin_id[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; ++i) {
 | 
					    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
				
			||||||
        char xx[3];
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID.");
 | 
				
			||||||
        snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff);
 | 
					        return;
 | 
				
			||||||
        strcat(id, xx);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "%s\n", id);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QRCODE
 | 
				
			||||||
 | 
					void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char id_string[TOX_ADDRESS_SIZE * 2 + 1];
 | 
				
			||||||
 | 
					    char bin_id[TOX_ADDRESS_SIZE];
 | 
				
			||||||
 | 
					    tox_self_get_address(m, (uint8_t *) bin_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char nick[TOX_MAX_NAME_LENGTH];
 | 
				
			||||||
 | 
					    tox_self_get_name(m, (uint8_t *) nick);
 | 
				
			||||||
 | 
					    size_t nick_len = tox_self_get_name_size(m);
 | 
				
			||||||
 | 
					    nick[nick_len] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t data_file_len = strlen(DATA_FILE);
 | 
				
			||||||
 | 
					    char *dir = malloc(data_file_len + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dir == NULL) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t dir_len = get_base_dir(DATA_FILE, data_file_len, dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QRPNG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc == 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
 | 
				
			||||||
 | 
					        free(dir);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (!strcmp(argv[1], "txt")) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QRPNG */
 | 
				
			||||||
 | 
					        size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT);
 | 
				
			||||||
 | 
					        char *qr_path = malloc(qr_path_buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (qr_path == NULL) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
				
			||||||
 | 
					            free(dir);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
 | 
					            free(dir);
 | 
				
			||||||
 | 
					            free(qr_path);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        free(qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef QRPNG
 | 
				
			||||||
 | 
					    } else if (!strcmp(argv[1], "png")) {
 | 
				
			||||||
 | 
					        size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG);
 | 
				
			||||||
 | 
					        char *qr_path = malloc(qr_path_buf_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (qr_path == NULL) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
 | 
				
			||||||
 | 
					            free(dir);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ID_to_QRcode_png(id_string, qr_path) == -1) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
 | 
				
			||||||
 | 
					            free(dir);
 | 
				
			||||||
 | 
					            free(qr_path);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        free(qr_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
 | 
				
			||||||
 | 
					        free(dir);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* QRPNG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(dir);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* QRCODE */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* check arguments */
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
      wprintw(window, "Invalid name.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *nick = argv[1];
 | 
					    char nick[MAX_STR_SIZE];
 | 
				
			||||||
    int len = strlen(nick);
 | 
					    snprintf(nick, sizeof(nick), "%s", argv[1]);
 | 
				
			||||||
 | 
					    size_t len = strlen(nick);
 | 
				
			||||||
    if (nick[0] == '\"') {
 | 
					 | 
				
			||||||
        ++nick;
 | 
					 | 
				
			||||||
        len -= 2;
 | 
					 | 
				
			||||||
        nick[len] = L'\0';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!valid_nick(nick)) {
 | 
					    if (!valid_nick(nick)) {
 | 
				
			||||||
        wprintw(window, "Invalid name.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (len > TOXIC_MAX_NAME_LENGTH) {
 | 
					    len = MIN(len, TOXIC_MAX_NAME_LENGTH - 1);
 | 
				
			||||||
        nick[TOXIC_MAX_NAME_LENGTH] = L'\0';
 | 
					    nick[len] = '\0';
 | 
				
			||||||
        len = TOXIC_MAX_NAME_LENGTH;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tox_set_name(m, nick, len+1);
 | 
					    tox_self_set_name(m, (uint8_t *) nick, len, NULL);
 | 
				
			||||||
    prompt_update_nick(prompt, nick, len+1);
 | 
					    prompt_update_nick(prompt, nick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    store_data(m, DATA_FILE);
 | 
					    store_data(m, DATA_FILE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc < 1) {
 | 
					    if (argc < 1) {
 | 
				
			||||||
        wprintw(window, "Wrong number of arguments.\n");
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t *msg = argv[1];
 | 
					    prompt_update_statusmessage(prompt, m, argv[1]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (msg[0] != '\"') {
 | 
					void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
        wprintw(window, "Note must be enclosed in quotes.\n");
 | 
					{
 | 
				
			||||||
 | 
					    long int nospam = rand();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (argc > 0) {
 | 
				
			||||||
 | 
					        nospam = strtol(argv[1], NULL, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value.");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    msg[strlen(++msg)-1] = L'\0';
 | 
					    uint32_t old_nospam = tox_self_get_nospam(m);
 | 
				
			||||||
    uint16_t len = strlen(msg) + 1;
 | 
					    tox_self_set_nospam(m, (uint32_t) nospam);
 | 
				
			||||||
    tox_set_status_message(m, msg, len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    prompt_update_statusmessage(prompt, msg, len);
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
 | 
				
			||||||
 | 
					    cmd_myid(window, self, m, 0, NULL);
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
 | 
				
			||||||
 | 
					                  "Any services that relied on your old ID will need to be updated manually.");
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
 | 
				
			||||||
 | 
					                  old_nospam);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_prompt_help(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    wclear(window);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
    wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
    wprintw(window, "\n\nGlobal commands:\n");
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
    wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wprintw(window, "    /add <id> <msg>            : Add friend with optional message\n");
 | 
					    help_init_menu(self);
 | 
				
			||||||
    wprintw(window, "    /accept <n>                : Accept friend request\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /connect <ip> <port> <key> : Manually connect to a DHT node\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /status <type> <msg>       : Set status with optional note\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /note <msg>                : Set a personal note\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /nick <nick>               : Set your nickname\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /log <on> or <off>         : Enable/disable logging\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /groupchat                 : Create a group chat\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /myid                      : Print your ID\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /help                      : Print this message again\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /clear                     : Clear the window\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /quit or /exit             : Exit Toxic\n");
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					 | 
				
			||||||
    wprintw(window, "    /lsdev <type>              : List devices where type: in|out\n");
 | 
					 | 
				
			||||||
    wprintw(window, "    /sdev <type> <id>          : Set active device\n");
 | 
					 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    wattron(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(window, " * Argument messages must be enclosed in quotation marks.\n");
 | 
					 | 
				
			||||||
    wprintw(window, " * Use ctrl-o and ctrl-p to navigate through the tabs.\n\n");
 | 
					 | 
				
			||||||
    wattroff(window, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_quit(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    exit_toxic(m);
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					    UNUSED_VAR(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exit_toxic_success(m);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					    UNUSED_VAR(m);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argc);
 | 
				
			||||||
 | 
					    UNUSED_VAR(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (FrndRequests.num_requests == 0) {
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int i, j;
 | 
				
			||||||
 | 
					    int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < FrndRequests.max_idx; ++i) {
 | 
				
			||||||
 | 
					        if (!FrndRequests.request[i].active) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        char id[TOX_PUBLIC_KEY_SIZE * 2 + 1] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (j = 0; j < TOX_PUBLIC_KEY_SIZE; ++j) {
 | 
				
			||||||
 | 
					            char d[3];
 | 
				
			||||||
 | 
					            snprintf(d, sizeof(d), "%02X", FrndRequests.request[i].key[j] & 0xff);
 | 
				
			||||||
 | 
					            strcat(id, d);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
 | 
				
			||||||
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (++count < FrndRequests.num_requests) {
 | 
				
			||||||
 | 
					            line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
					void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t *msg = NULL;
 | 
					    UNUSED_VAR(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (argc >= 2) {
 | 
					    const char *errmsg;
 | 
				
			||||||
        msg = argv[2];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (msg[0] != '\"') {
 | 
					    lock_status();
 | 
				
			||||||
            wprintw(window, "Note must be enclosed in quotes.\n");
 | 
					
 | 
				
			||||||
            return;
 | 
					    if (argc < 1) {
 | 
				
			||||||
        }
 | 
					        errmsg = "Require a status. Statuses are: online, busy and away.";
 | 
				
			||||||
    } else if (argc != 1) {
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
        wprintw(window, "Wrong number of arguments.\n");
 | 
					        goto finish;
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    char *status = argv[1];
 | 
					    const char *status_str = argv[1];
 | 
				
			||||||
    int len = strlen(status);
 | 
					    Tox_User_Status status;
 | 
				
			||||||
    char l_status[len+1];
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i <= len; ++i)
 | 
					    if (!strcasecmp(status_str, "online")) {
 | 
				
			||||||
        l_status[i] = tolower(status[i]);
 | 
					        status = TOX_USER_STATUS_NONE;
 | 
				
			||||||
 | 
					    } else if (!strcasecmp(status_str, "away")) {
 | 
				
			||||||
    TOX_USERSTATUS status_kind;
 | 
					        status = TOX_USER_STATUS_AWAY;
 | 
				
			||||||
 | 
					    } else if (!strcasecmp(status_str, "busy")) {
 | 
				
			||||||
    if (!strcmp(l_status, "online"))
 | 
					        status = TOX_USER_STATUS_BUSY;
 | 
				
			||||||
        status_kind = TOX_USERSTATUS_NONE;
 | 
					    } else {
 | 
				
			||||||
    else if (!strcmp(l_status, "away"))
 | 
					        errmsg = "Invalid status. Valid statuses are: online, busy and away.";
 | 
				
			||||||
        status_kind = TOX_USERSTATUS_AWAY;
 | 
					        line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
 | 
				
			||||||
    else if (!strcmp(l_status, "busy"))
 | 
					        goto finish;
 | 
				
			||||||
        status_kind = TOX_USERSTATUS_BUSY;
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
        wprintw(window, "Invalid status. Valid statuses are: online, busy and away.\n");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tox_set_user_status(m, status_kind);
 | 
					    tox_self_set_status(m, status);
 | 
				
			||||||
    prompt_update_status(prompt, status_kind);
 | 
					    prompt_update_status(prompt, status);
 | 
				
			||||||
 | 
					    line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (msg != NULL) {
 | 
					
 | 
				
			||||||
        msg[strlen(++msg)-1] = L'\0';   /* remove opening and closing quotes */
 | 
					finish:
 | 
				
			||||||
        uint16_t len = strlen(msg) + 1;
 | 
					    unlock_status();
 | 
				
			||||||
        tox_set_status_message(m, msg, len);
 | 
					 | 
				
			||||||
        prompt_update_statusmessage(prompt, msg, len);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,20 +20,46 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef GLOBAL_COMMANDS_H
 | 
				
			||||||
 | 
					#define GLOBAL_COMMANDS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_accept(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_add(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_clear(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_connect(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_groupchat(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_conference(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_log(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_myid(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#ifdef QRCODE
 | 
				
			||||||
 | 
					void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#endif /* QRCODE */
 | 
				
			||||||
void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_nick(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_note(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_prompt_help(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_quit(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_requests(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_status(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _SUPPORT_AUDIO
 | 
					void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_list_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
					void cmd_change_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
#endif /* _SUPPORT_AUDIO */
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					void cmd_list_video_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* GLOBAL_COMMANDS_H */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										655
									
								
								src/groupchat.c
									
									
									
									
									
								
							
							
						
						
									
										655
									
								
								src/groupchat.c
									
									
									
									
									
								
							@@ -1,655 +0,0 @@
 | 
				
			|||||||
/*  groupchat.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  This file is part of Toxic.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 *  it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
 *  the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
 *  (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Toxic is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 *  GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "toxic_windows.h"
 | 
					 | 
				
			||||||
#include "execute.h"
 | 
					 | 
				
			||||||
#include "misc_tools.h"
 | 
					 | 
				
			||||||
#include "groupchat.h"
 | 
					 | 
				
			||||||
#include "prompt.h"
 | 
					 | 
				
			||||||
#include "toxic_strings.h"
 | 
					 | 
				
			||||||
#include "log.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern char *DATA_FILE;
 | 
					 | 
				
			||||||
extern int store_data(Tox *m, char *path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GroupChat groupchats[MAX_WINDOWS_NUM];
 | 
					 | 
				
			||||||
static int max_groupchat_index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* temporary until group chats have unique commands */
 | 
					 | 
				
			||||||
extern const uint8_t glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i <= max_groupchat_index; ++i) {
 | 
					 | 
				
			||||||
        if (!groupchats[i].active) {
 | 
					 | 
				
			||||||
            groupchats[i].chatwin = add_window(m, new_group_chat(m, groupnum));
 | 
					 | 
				
			||||||
            groupchats[i].active = true;
 | 
					 | 
				
			||||||
            groupchats[i].num_peers = 0;
 | 
					 | 
				
			||||||
            groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
            groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /* temp fix */
 | 
					 | 
				
			||||||
            memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            set_active_window(groupchats[i].chatwin);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (i == max_groupchat_index)
 | 
					 | 
				
			||||||
                ++max_groupchat_index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void kill_groupchat_window(ToxWindow *self)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    log_disable(ctx->log);
 | 
					 | 
				
			||||||
    delwin(ctx->linewin);
 | 
					 | 
				
			||||||
    del_window(self);
 | 
					 | 
				
			||||||
    free(ctx->log);
 | 
					 | 
				
			||||||
    free(ctx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void close_groupchat(ToxWindow *self, Tox *m, int groupnum)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    set_active_window(0);
 | 
					 | 
				
			||||||
    tox_del_groupchat(m, groupnum);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    free(groupchats[groupnum].peer_names);
 | 
					 | 
				
			||||||
    free(groupchats[groupnum].oldpeer_names);
 | 
					 | 
				
			||||||
    memset(&groupchats[groupnum], 0, sizeof(GroupChat));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = max_groupchat_index; i > 0; --i) {
 | 
					 | 
				
			||||||
        if (groupchats[i-1].active)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    max_groupchat_index = i;
 | 
					 | 
				
			||||||
    kill_groupchat_window(self);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void print_groupchat_help(ChatContext *ctx)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    wattron(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "Group chat commands:\n");
 | 
					 | 
				
			||||||
    wattroff(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /add <id> <msg>     : Add friend with optional message\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /status <type> <msg>: Set your status with optional note\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /note <msg>         : Set a personal note\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /nick <nick>        : Set your nickname\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /groupchat          : Create a group chat\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /log <on> or <off>  : Enable/disable logging\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /close              : Close the current group chat\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /help               : Print this message again\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    /help global        : Show a list of global commands\n");
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    wattron(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(ctx->history, " * Argument messages must be enclosed in quotation marks.\n");
 | 
					 | 
				
			||||||
    wprintw(ctx->history, " * Scroll peer list with the Page Up/Page Down keys.\n\n");
 | 
					 | 
				
			||||||
    wattroff(ctx->history, COLOR_PAIR(CYAN) | A_BOLD);
 | 
					 | 
				
			||||||
    wattron(ctx->history, COLOR_PAIR(WHITE) | A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "    Notice, some friends will be missing names while finding peers\n\n");
 | 
					 | 
				
			||||||
    wattroff(ctx->history, COLOR_PAIR(WHITE) | A_BOLD);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onGroupMessage(ToxWindow *self, Tox *m, int groupnum, int peernum,
 | 
					 | 
				
			||||||
                                     uint8_t *msg, uint16_t len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->num != groupnum)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
 | 
					 | 
				
			||||||
    tox_group_peername(m, groupnum, peernum, nick);
 | 
					 | 
				
			||||||
    nick[TOXIC_MAX_NAME_LENGTH] = '\0';    /* enforce client max name length */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* check if message contains own name and alert appropriately */
 | 
					 | 
				
			||||||
    int alert_type = WINDOW_ALERT_1;
 | 
					 | 
				
			||||||
    bool beep = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t selfnick[TOX_MAX_NAME_LENGTH] = {'\0'};
 | 
					 | 
				
			||||||
    tox_get_self_name(m, selfnick, TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
    int nick_clr = strcmp(nick, selfnick) == 0 ? GREEN : CYAN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool nick_match = strcasestr(msg, selfnick) && strncmp(selfnick, nick, TOXIC_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (nick_match) {
 | 
					 | 
				
			||||||
        alert_type = WINDOW_ALERT_0;
 | 
					 | 
				
			||||||
        beep = true;
 | 
					 | 
				
			||||||
        nick_clr = RED;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    alert_window(self, alert_type, beep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    print_time(ctx->history);
 | 
					 | 
				
			||||||
    wattron(ctx->history, COLOR_PAIR(nick_clr));
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "%s: ", nick);
 | 
					 | 
				
			||||||
    wattroff(ctx->history, COLOR_PAIR(nick_clr));
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if (msg[0] == '>') {
 | 
					 | 
				
			||||||
        wattron(ctx->history, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "%s\n", msg);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "%s\n", msg);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    write_to_log(msg, nick, ctx->log, false);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onGroupAction(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t *action,
 | 
					 | 
				
			||||||
                                    uint16_t len)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->num != groupnum)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* check if message contains own name and alert appropriately */
 | 
					 | 
				
			||||||
    int alert_type = WINDOW_ALERT_1;
 | 
					 | 
				
			||||||
    bool beep = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t selfnick[TOX_MAX_NAME_LENGTH] = {'\0'};
 | 
					 | 
				
			||||||
    tox_get_self_name(m, selfnick, TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool nick_match = strcasestr(action, selfnick);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (nick_match) {
 | 
					 | 
				
			||||||
        alert_type = WINDOW_ALERT_0;
 | 
					 | 
				
			||||||
        beep = true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    alert_window(self, alert_type, beep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t nick[TOX_MAX_NAME_LENGTH] = {'\0'};
 | 
					 | 
				
			||||||
    tox_group_peername(m, groupnum, peernum, nick);
 | 
					 | 
				
			||||||
    nick[TOXIC_MAX_NAME_LENGTH] = '\0';    /* enforce client max name length */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    print_time(ctx->history);
 | 
					 | 
				
			||||||
    wattron(ctx->history, COLOR_PAIR(YELLOW));
 | 
					 | 
				
			||||||
    wprintw(ctx->history, "* %s %s\n", nick, action);
 | 
					 | 
				
			||||||
    wattroff(ctx->history, COLOR_PAIR(YELLOW));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    write_to_log(action, nick, ctx->log, true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Puts two copies of peerlist in chat instance */
 | 
					 | 
				
			||||||
static void copy_peernames(int gnum, int npeers, uint8_t tmp_peerlist[][TOX_MAX_NAME_LENGTH])
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Assumes these are initiated in init_groupchat_win */
 | 
					 | 
				
			||||||
    free(groupchats[gnum].peer_names);
 | 
					 | 
				
			||||||
    free(groupchats[gnum].oldpeer_names);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int N = TOX_MAX_NAME_LENGTH;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    groupchats[gnum].peer_names = malloc(sizeof(uint8_t) * npeers * N);
 | 
					 | 
				
			||||||
    groupchats[gnum].oldpeer_names = malloc(sizeof(uint8_t) * npeers * N);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (groupchats[gnum].peer_names == NULL || groupchats[gnum].oldpeer_names == NULL) {
 | 
					 | 
				
			||||||
        endwin();
 | 
					 | 
				
			||||||
        fprintf(stderr, "malloc() failed. Aborting...\n");
 | 
					 | 
				
			||||||
        exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < npeers; ++i) {
 | 
					 | 
				
			||||||
        if (string_is_empty(tmp_peerlist[i])) {
 | 
					 | 
				
			||||||
            memcpy(&groupchats[gnum].peer_names[i*N], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            memcpy(&groupchats[gnum].peer_names[i*N], tmp_peerlist[i], N);
 | 
					 | 
				
			||||||
            groupchats[gnum].peer_names[i*N+TOXIC_MAX_NAME_LENGTH] = '\0';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy(groupchats[gnum].oldpeer_names, groupchats[gnum].peer_names, N*npeers);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum,
 | 
					 | 
				
			||||||
                                            uint8_t change)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (self->num != groupnum)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
 | 
					 | 
				
			||||||
    int num_peers = groupchats[groupnum].num_peers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* get old peer name before updating name list */
 | 
					 | 
				
			||||||
    uint8_t oldpeername[TOX_MAX_NAME_LENGTH] = {0};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (change != TOX_CHAT_CHANGE_PEER_ADD)
 | 
					 | 
				
			||||||
        memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum*TOX_MAX_NAME_LENGTH], 
 | 
					 | 
				
			||||||
               sizeof(oldpeername));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Update name lists */
 | 
					 | 
				
			||||||
    uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
 | 
					 | 
				
			||||||
    tox_group_get_names(m, groupnum, tmp_peerlist, num_peers);
 | 
					 | 
				
			||||||
    copy_peernames(groupnum, num_peers, tmp_peerlist);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* get current peername then sort namelist */
 | 
					 | 
				
			||||||
    uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};
 | 
					 | 
				
			||||||
    memcpy(peername, &groupchats[groupnum].peer_names[peernum*TOX_MAX_NAME_LENGTH], sizeof(peername));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    qsort(groupchats[groupnum].peer_names, groupchats[groupnum].num_peers, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
    print_time(ctx->history);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint8_t *event;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (change) {
 | 
					 | 
				
			||||||
    case TOX_CHAT_CHANGE_PEER_ADD:
 | 
					 | 
				
			||||||
        event = "has joined the room";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wattron(ctx->history, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
        wattron(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "* %s", peername);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, " %s\n", event);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, COLOR_PAIR(GREEN));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        write_to_log(event, peername, ctx->log, true);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case TOX_CHAT_CHANGE_PEER_DEL:
 | 
					 | 
				
			||||||
        event = "has left the room";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wattron(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "* %s", oldpeername);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, " %s\n", event);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (groupchats[self->num].side_pos > 0)
 | 
					 | 
				
			||||||
            --groupchats[self->num].side_pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        write_to_log(event, oldpeername, ctx->log, true);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case TOX_CHAT_CHANGE_PEER_NAME:
 | 
					 | 
				
			||||||
        wattron(ctx->history, COLOR_PAIR(MAGENTA));
 | 
					 | 
				
			||||||
        wattron(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "* %s", oldpeername);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wprintw(ctx->history, " is now known as ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wattron(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "%s\n", peername);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, A_BOLD);
 | 
					 | 
				
			||||||
        wattroff(ctx->history, COLOR_PAIR(MAGENTA));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        uint8_t tmp_event[TOXIC_MAX_NAME_LENGTH + 32];
 | 
					 | 
				
			||||||
        snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", peername);
 | 
					 | 
				
			||||||
        write_to_log(tmp_event, oldpeername, ctx->log, true);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    alert_window(self, WINDOW_ALERT_2, false);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void send_group_action(ToxWindow *self, ChatContext *ctx, Tox *m, uint8_t *action) {
 | 
					 | 
				
			||||||
    if (action == NULL) {
 | 
					 | 
				
			||||||
        wprintw(ctx->history, "Invalid syntax.\n");
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* uint8_t selfname[TOX_MAX_NAME_LENGTH];
 | 
					 | 
				
			||||||
       tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
       print_time(ctx->history);
 | 
					 | 
				
			||||||
       wattron(ctx->history, COLOR_PAIR(YELLOW));
 | 
					 | 
				
			||||||
       wprintw(ctx->history, "* %s %s\n", selfname, action);
 | 
					 | 
				
			||||||
       wattroff(ctx->history, COLOR_PAIR(YELLOW)); */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (tox_group_action_send(m, self->num, action, strlen(action) + 1) == -1) {
 | 
					 | 
				
			||||||
        wattron(ctx->history, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
        wprintw(ctx->history, " * Failed to send action\n");
 | 
					 | 
				
			||||||
        wattroff(ctx->history, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int x, y, y2, x2;
 | 
					 | 
				
			||||||
    getyx(self->window, y, x);
 | 
					 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					 | 
				
			||||||
    int cur_len = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (key == 0x107 || key == 0x8 || key == 0x7f) {  /* BACKSPACE key: Remove character behind pos */
 | 
					 | 
				
			||||||
        if (ctx->pos > 0) {
 | 
					 | 
				
			||||||
            cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1]));
 | 
					 | 
				
			||||||
            del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (x == 0)
 | 
					 | 
				
			||||||
                wmove(self->window, y-1, x2 - cur_len);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                wmove(self->window, y, x - cur_len);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_DC) {      /* DEL key: Remove character at pos */
 | 
					 | 
				
			||||||
        if (ctx->pos != ctx->len)
 | 
					 | 
				
			||||||
            del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == T_KEY_DISCARD) {    /* CTRL-U: Delete entire line behind pos */
 | 
					 | 
				
			||||||
        if (ctx->pos > 0) {
 | 
					 | 
				
			||||||
            discard_buf(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
            wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == T_KEY_KILL) {    /* CTRL-K: Delete entire line in front of pos */
 | 
					 | 
				
			||||||
        if (ctx->pos != ctx->len)
 | 
					 | 
				
			||||||
            kill_buf(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_HOME || key == T_KEY_C_A) {  /* HOME/C-a key: Move cursor to start of line */
 | 
					 | 
				
			||||||
        if (ctx->pos > 0) {
 | 
					 | 
				
			||||||
            ctx->pos = 0;
 | 
					 | 
				
			||||||
            wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_END || key == T_KEY_C_E) {  /* END/C-e key: move cursor to end of line */
 | 
					 | 
				
			||||||
        if (ctx->pos != ctx->len) {
 | 
					 | 
				
			||||||
            ctx->pos = ctx->len;
 | 
					 | 
				
			||||||
            mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, (CHATBOX_HEIGHT-1)*x2)), y2, x2);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_LEFT) {
 | 
					 | 
				
			||||||
        if (ctx->pos > 0) {
 | 
					 | 
				
			||||||
            --ctx->pos;
 | 
					 | 
				
			||||||
            cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (x == 0)
 | 
					 | 
				
			||||||
                wmove(self->window, y-1, x2 - cur_len);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                wmove(self->window, y, x - cur_len);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_RIGHT) {
 | 
					 | 
				
			||||||
        if (ctx->pos < ctx->len) {
 | 
					 | 
				
			||||||
            cur_len = MAX(1, wcwidth(ctx->line[ctx->pos]));
 | 
					 | 
				
			||||||
            ++ctx->pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (x == x2-1)
 | 
					 | 
				
			||||||
                wmove(self->window, y+1, 0);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                wmove(self->window, y, x + cur_len);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_UP) {    /* fetches previous item in history */
 | 
					 | 
				
			||||||
        fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
 | 
					 | 
				
			||||||
                        &ctx->hst_pos, LN_HIST_MV_UP);
 | 
					 | 
				
			||||||
        mv_curs_end(self->window, ctx->len, y2, x2);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_DOWN) {    /* fetches next item in history */
 | 
					 | 
				
			||||||
        fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot,
 | 
					 | 
				
			||||||
                        &ctx->hst_pos, LN_HIST_MV_DWN);
 | 
					 | 
				
			||||||
        mv_curs_end(self->window, ctx->len, y2, x2);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == '\t') {    /* TAB key: completes peer name */
 | 
					 | 
				
			||||||
        if (ctx->len > 0) {
 | 
					 | 
				
			||||||
            int diff;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e'))
 | 
					 | 
				
			||||||
                diff = complete_line(ctx->line, &ctx->pos, &ctx->len, groupchats[self->num].peer_names, 
 | 
					 | 
				
			||||||
                                     groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                diff = complete_line(ctx->line, &ctx->pos, &ctx->len, glob_cmd_list, AC_NUM_GLOB_COMMANDS,
 | 
					 | 
				
			||||||
                                     MAX_CMDNAME_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (diff != -1) {
 | 
					 | 
				
			||||||
                if (x + diff > x2 - 1) {
 | 
					 | 
				
			||||||
                    int ofst = (x + diff - 1) - (x2 - 1);
 | 
					 | 
				
			||||||
                    wmove(self->window, y+1, ofst);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    wmove(self->window, y, x+diff);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                beep();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            beep();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Scroll peerlist up and down one position if list overflows window */
 | 
					 | 
				
			||||||
    else if (key == KEY_NPAGE) {
 | 
					 | 
				
			||||||
        int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
 | 
					 | 
				
			||||||
            ++groupchats[self->num].side_pos;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else if (key == KEY_PPAGE) {
 | 
					 | 
				
			||||||
        if (groupchats[self->num].side_pos > 0)
 | 
					 | 
				
			||||||
            --groupchats[self->num].side_pos;
 | 
					 | 
				
			||||||
    } 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
#if HAVE_WIDECHAR
 | 
					 | 
				
			||||||
    if (iswprint(key))
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    if (isprint(key))
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    {   /* prevents buffer overflows and strange behaviour when cursor goes past the window */
 | 
					 | 
				
			||||||
        if ( (ctx->len < MAX_STR_SIZE-1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1)-1)) ) {
 | 
					 | 
				
			||||||
            add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (x == x2-1)
 | 
					 | 
				
			||||||
                wmove(self->window, y+1, 0);
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                wmove(self->window, y, x + MAX(1, wcwidth(key)));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* RETURN key: Execute command or print line */
 | 
					 | 
				
			||||||
    else if (key == '\n') {
 | 
					 | 
				
			||||||
        uint8_t line[MAX_STR_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
 | 
					 | 
				
			||||||
            memset(&line, 0, sizeof(line));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wclear(ctx->linewin);
 | 
					 | 
				
			||||||
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					 | 
				
			||||||
        wclrtobot(self->window);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!string_is_empty(line))
 | 
					 | 
				
			||||||
            add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (line[0] == '/') {
 | 
					 | 
				
			||||||
            if (strcmp(line, "/close") == 0) {
 | 
					 | 
				
			||||||
                close_groupchat(self, m, self->num);
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            } else if (strcmp(line, "/help") == 0) {
 | 
					 | 
				
			||||||
                if (strcmp(line, "help global") == 0)
 | 
					 | 
				
			||||||
                    execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE);
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                    print_groupchat_help(ctx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
 | 
					 | 
				
			||||||
                send_group_action(self, ctx, m, line + strlen("/me "));
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if (!string_is_empty(line)) {
 | 
					 | 
				
			||||||
            if (tox_group_message_send(m, self->num, line, strlen(line) + 1) == -1) {
 | 
					 | 
				
			||||||
                wattron(ctx->history, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
                wprintw(ctx->history, " * Failed to send message.\n");
 | 
					 | 
				
			||||||
                wattroff(ctx->history, COLOR_PAIR(RED));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        reset_buf(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onDraw(ToxWindow *self, Tox *m)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    curs_set(1);
 | 
					 | 
				
			||||||
    int x2, y2;
 | 
					 | 
				
			||||||
    getmaxyx(self->window, y2, x2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    wclear(ctx->linewin);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (ctx->len > 0) {
 | 
					 | 
				
			||||||
        uint8_t line[MAX_STR_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
 | 
					 | 
				
			||||||
            reset_buf(ctx->line, &ctx->pos, &ctx->len);
 | 
					 | 
				
			||||||
            wmove(self->window, y2 - CURS_Y_OFFSET, 0);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            mvwprintw(ctx->linewin, 1, 0, "%s", line);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    wclear(ctx->sidebar);
 | 
					 | 
				
			||||||
    mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2);
 | 
					 | 
				
			||||||
    mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2-CHATBOX_HEIGHT);
 | 
					 | 
				
			||||||
    mvwaddch(ctx->sidebar, y2-CHATBOX_HEIGHT, 0, ACS_BTEE);  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int num_peers = groupchats[self->num].num_peers;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    wmove(ctx->sidebar, 0, 1);
 | 
					 | 
				
			||||||
    wattron(ctx->sidebar, A_BOLD);
 | 
					 | 
				
			||||||
    wprintw(ctx->sidebar, "Peers: %d\n", num_peers);
 | 
					 | 
				
			||||||
    wattroff(ctx->sidebar, A_BOLD);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mvwaddch(ctx->sidebar, 1, 0, ACS_LTEE);
 | 
					 | 
				
			||||||
    mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH-1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int N = TOX_MAX_NAME_LENGTH;
 | 
					 | 
				
			||||||
    int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < num_peers && i < maxlines; ++i) {
 | 
					 | 
				
			||||||
        wmove(ctx->sidebar, i+2, 1);
 | 
					 | 
				
			||||||
        int peer = i + groupchats[self->num].side_pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* truncate nick to fit in side panel without modifying list */
 | 
					 | 
				
			||||||
        uint8_t tmpnck[TOX_MAX_NAME_LENGTH];
 | 
					 | 
				
			||||||
        memcpy(tmpnck, &groupchats[self->num].peer_names[peer*N], SIDEBAR_WIDTH-2);
 | 
					 | 
				
			||||||
        tmpnck[SIDEBAR_WIDTH-2] = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        wprintw(ctx->sidebar, "%s\n", tmpnck);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void groupchat_onInit(ToxWindow *self, Tox *m)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int x, y;
 | 
					 | 
				
			||||||
    getmaxyx(self->window, y, x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *ctx = self->chatwin;
 | 
					 | 
				
			||||||
    ctx->history = subwin(self->window, y-CHATBOX_HEIGHT+1, x-SIDEBAR_WIDTH-1, 0, 0);
 | 
					 | 
				
			||||||
    scrollok(ctx->history, 1);
 | 
					 | 
				
			||||||
    ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x, y-CHATBOX_HEIGHT, 0);
 | 
					 | 
				
			||||||
    ctx->sidebar = subwin(self->window, y-CHATBOX_HEIGHT+1, SIDEBAR_WIDTH, 0, x-SIDEBAR_WIDTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ctx->log = malloc(sizeof(struct chatlog));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (ctx->log == NULL) {
 | 
					 | 
				
			||||||
        endwin();
 | 
					 | 
				
			||||||
        fprintf(stderr, "malloc() failed. Aborting...\n");
 | 
					 | 
				
			||||||
        exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memset(ctx->log, 0, sizeof(struct chatlog));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    print_groupchat_help(ctx);
 | 
					 | 
				
			||||||
    execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    wmove(self->window, y-CURS_Y_OFFSET, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ToxWindow new_group_chat(Tox *m, int groupnum)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    ToxWindow ret;
 | 
					 | 
				
			||||||
    memset(&ret, 0, sizeof(ret));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret.active = true;
 | 
					 | 
				
			||||||
    ret.is_groupchat = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret.onKey = &groupchat_onKey;
 | 
					 | 
				
			||||||
    ret.onDraw = &groupchat_onDraw;
 | 
					 | 
				
			||||||
    ret.onInit = &groupchat_onInit;
 | 
					 | 
				
			||||||
    ret.onGroupMessage = &groupchat_onGroupMessage;
 | 
					 | 
				
			||||||
    ret.onGroupNamelistChange = &groupchat_onGroupNamelistChange;
 | 
					 | 
				
			||||||
    ret.onGroupAction = &groupchat_onGroupAction;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    snprintf(ret.name, sizeof(ret.name), "Room #%d", groupnum);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ChatContext *chatwin = calloc(1, sizeof(ChatContext));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (chatwin != NULL)
 | 
					 | 
				
			||||||
        ret.chatwin = chatwin;
 | 
					 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
        endwin();
 | 
					 | 
				
			||||||
        fprintf(stderr, "calloc() failed. Aborting...\n");
 | 
					 | 
				
			||||||
        exit(EXIT_FAILURE);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret.num = groupnum;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										472
									
								
								src/help.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										472
									
								
								src/help.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,472 @@
 | 
				
			|||||||
 | 
					/*  help.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "help.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					#include "api.h"
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					#define HELP_MENU_HEIGHT 10
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define HELP_MENU_HEIGHT 9
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					#define HELP_MENU_WIDTH 26
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void help_init_menu(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->help->win) {
 | 
				
			||||||
 | 
					        delwin(self->help->win);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int y2, x2;
 | 
				
			||||||
 | 
					    getmaxyx(self->window, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (y2 < HELP_MENU_HEIGHT || x2 < HELP_MENU_WIDTH) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->help->win = newwin(HELP_MENU_HEIGHT, HELP_MENU_WIDTH, 3, 3);
 | 
				
			||||||
 | 
					    self->help->active = true;
 | 
				
			||||||
 | 
					    self->help->type = HELP_MENU;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_exit(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    delwin(self->help->win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *(self->help) = (struct Help) {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_init_window(ToxWindow *self, int height, int width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (self->help->win) {
 | 
				
			||||||
 | 
					        delwin(self->help->win);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int y2, x2;
 | 
				
			||||||
 | 
					    getmaxyx(stdscr, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (y2 <= 0 || x2 <= 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    height = MIN(height, y2);
 | 
				
			||||||
 | 
					    width = MIN(width, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->help->win = newwin(height, width, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_menu(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "       Help Menu\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " g");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "lobal commands\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " c");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "hat commands\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, " c");
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "o");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "nference commands\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " p");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "lugin commands\n");
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " f");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "riendlist controls\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " k");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "ey bindings\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, " e");
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "x");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "it menu\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_bottom_menu(WINDOW *win)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int y2, x2;
 | 
				
			||||||
 | 
					    getmaxyx(win, y2, x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UNUSED_VAR(x2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, y2 - 2, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, " m");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "ain menu |");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, " e");
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "x");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
 | 
				
			||||||
 | 
					    wprintw(win, "it");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_global(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Global Commands:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /add <addr> <msg>          : Add contact with optional message\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /accept <id>               : Accept friend request\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /avatar <path>             : Set an avatar (leave path empty to unset)\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /decline <id>              : Decline friend request\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /requests                  : List pending friend requests\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /connect <ip> <port> <key> : Manually connect to a DHT node\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /status <type> <msg>       : Set status with optional note\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /note <msg>                : Set a personal note\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /nick <nick>               : Set your nickname\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /nospam <value>            : Change part of your Tox ID to stop spam\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /log <on> or <off>         : Enable/disable logging\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /conference <type>         : Create a conference where type: text | audio\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /myid                      : Print your Tox ID\n");
 | 
				
			||||||
 | 
					#ifdef QRCODE
 | 
				
			||||||
 | 
					#ifdef QRPNG
 | 
				
			||||||
 | 
					    wprintw(win, "  /myqr <txt> or <png>       : Print your Tox ID's QR code to a file.\n");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    wprintw(win, "  /myqr                      : Print your Tox ID's QR code to a file.\n");
 | 
				
			||||||
 | 
					#endif /* QRPNG */
 | 
				
			||||||
 | 
					#endif /* QRCODE */
 | 
				
			||||||
 | 
					    wprintw(win, "  /clear                     : Clear window history\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /close                     : Close the current chat window\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /quit or /exit             : Exit Toxic\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Audio:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /lsdev <type>              : List devices where type: in|out\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /sdev <type> <id>          : Set active device\n");
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Video:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /lsvdev <type>             : List video devices where type: in|out\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /svdev <type> <id>         : Set active video device\n");
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Scripting:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /run <path>                : Load and run the script at path\n");
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_chat(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Chat Commands:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /invite <n>                : Invite contact to a conference \n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /join                      : Join a pending conference\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /sendfile <path>           : Send a file\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /savefile <id>             : Receive a file\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /cancel <type> <id>        : Cancel file transfer where type: in|out\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Audio:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /call                      : Audio call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /answer                    : Answer incoming call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /reject                    : Reject incoming call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /hangup                    : Hangup active call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /sdev <type> <id>          : Change active device\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /mute <type>               : Mute active device if in call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /sense <n>                 : VAD sensitivity threshold\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /bitrate <n>               : Set the audio encoding bitrate\n");
 | 
				
			||||||
 | 
					#endif /* AUDIO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Video:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "  /res <width> <height>      : Set video resolution\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /vcall                     : Video call\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /video                     : Toggle video in call\n");
 | 
				
			||||||
 | 
					#endif /* VIDEO */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_keys(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Key bindings:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+O and Ctrl+P         : Navigate through the tabs\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Page Up and Page Down     : Scroll window history one line\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+F and Ctrl+V         : Scroll window history half a page\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+H                    : Move to the bottom of window history\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+up and Ctrl+down     : Scroll peer list in conference\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+B                    : Toggle the conference peerlist\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+J                    : Insert new line\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Ctrl+T                    : Toggle paste mode\n\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  (Note: Custom keybindings override these defaults.)\n\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_conference(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Conference commands:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  /title <msg>               : Show/set conference title\n");
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "\n Audio:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD);
 | 
				
			||||||
 | 
					    wprintw(win, "  /audio <on> or <off>       : Enable/disable audio in an audio conference\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /mute                      : Toggle self audio mute status\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /mute <nick> or <pubkey>   : Toggle peer audio mute status\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /ptt <on> or <off>         : Toggle audio input Push-To-Talk (F2 to activate)\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  /sense <n>                 : VAD sensitivity threshold\n\n");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					static void help_draw_plugin(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Plugin commands:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    draw_handler_help(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void help_draw_contacts(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    WINDOW *win = self->help->win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wmove(win, 1, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wattron(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					    wprintw(win, "Friendlist controls:\n");
 | 
				
			||||||
 | 
					    wattroff(win, A_BOLD | COLOR_PAIR(RED));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wprintw(win, "  Up and Down arrows            : Scroll through list\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Right and Left arrows         : Switch between friendlist and blocked list\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Enter                         : Open a chat window with selected contact\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  Delete                        : Permanently delete a contact\n");
 | 
				
			||||||
 | 
					    wprintw(win, "  B                             : Block or unblock a contact\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_draw_bottom_menu(win);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    box(win, ACS_VLINE, ACS_HLINE);
 | 
				
			||||||
 | 
					    wnoutrefresh(win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void help_onKey(ToxWindow *self, wint_t key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (key) {
 | 
				
			||||||
 | 
					        case L'x':
 | 
				
			||||||
 | 
					        case T_KEY_ESC:
 | 
				
			||||||
 | 
					            help_exit(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'c':
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					            help_init_window(self, 25, 80);
 | 
				
			||||||
 | 
					#elif AUDIO
 | 
				
			||||||
 | 
					            help_init_window(self, 20, 80);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					            help_init_window(self, 10, 80);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            self->help->type = HELP_CHAT;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'g':
 | 
				
			||||||
 | 
					            height = 22;
 | 
				
			||||||
 | 
					#ifdef VIDEO
 | 
				
			||||||
 | 
					            height += 8;
 | 
				
			||||||
 | 
					#elif AUDIO
 | 
				
			||||||
 | 
					            height += 4;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					            height += 2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            help_init_window(self, height, 80);
 | 
				
			||||||
 | 
					            self->help->type = HELP_GLOBAL;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'o':
 | 
				
			||||||
 | 
					            height = 6;
 | 
				
			||||||
 | 
					#ifdef AUDIO
 | 
				
			||||||
 | 
					            height += 7;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            help_init_window(self, height, 80);
 | 
				
			||||||
 | 
					            self->help->type = HELP_CONFERENCE;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'p':
 | 
				
			||||||
 | 
					            help_init_window(self, 4 + num_registered_handlers(), help_max_width());
 | 
				
			||||||
 | 
					            self->help->type = HELP_PLUGIN;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'f':
 | 
				
			||||||
 | 
					            help_init_window(self, 10, 80);
 | 
				
			||||||
 | 
					            self->help->type = HELP_CONTACTS;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'k':
 | 
				
			||||||
 | 
					            help_init_window(self, 15, 80);
 | 
				
			||||||
 | 
					            self->help->type = HELP_KEYS;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case L'm':
 | 
				
			||||||
 | 
					            help_init_menu(self);
 | 
				
			||||||
 | 
					            self->help->type = HELP_MENU;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void help_onDraw(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (self->help->type) {
 | 
				
			||||||
 | 
					        case HELP_MENU:
 | 
				
			||||||
 | 
					            help_draw_menu(self);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_CHAT:
 | 
				
			||||||
 | 
					            help_draw_chat(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_GLOBAL:
 | 
				
			||||||
 | 
					            help_draw_global(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_KEYS:
 | 
				
			||||||
 | 
					            help_draw_keys(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_CONTACTS:
 | 
				
			||||||
 | 
					            help_draw_contacts(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_CONFERENCE:
 | 
				
			||||||
 | 
					            help_draw_conference(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case HELP_PLUGIN:
 | 
				
			||||||
 | 
					            help_draw_plugin(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					#endif /* PYTHON */
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
/*  groupchat.h
 | 
					/*  help.h
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
@@ -20,18 +20,26 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SIDEBAR_WIDTH 16
 | 
					#ifndef HELP_H
 | 
				
			||||||
#define SDBAR_OFST 2    /* Offset for the peer number box at the top of the statusbar */
 | 
					#define HELP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					#include "toxic.h"
 | 
				
			||||||
    int chatwin;
 | 
					#include "windows.h"
 | 
				
			||||||
    bool active;
 | 
					 | 
				
			||||||
    int num_peers;
 | 
					 | 
				
			||||||
    int side_pos;    /* current position of the sidebar - used for scrolling up and down */
 | 
					 | 
				
			||||||
    uint8_t *peer_names;
 | 
					 | 
				
			||||||
    uint8_t *oldpeer_names;
 | 
					 | 
				
			||||||
} GroupChat;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void kill_groupchat_window(ToxWindow *self);
 | 
					typedef enum {
 | 
				
			||||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum);
 | 
					    HELP_MENU,
 | 
				
			||||||
ToxWindow new_group_chat(Tox *m, int groupnum);
 | 
					    HELP_GLOBAL,
 | 
				
			||||||
 | 
					    HELP_CHAT,
 | 
				
			||||||
 | 
					    HELP_CONFERENCE,
 | 
				
			||||||
 | 
					    HELP_KEYS,
 | 
				
			||||||
 | 
					    HELP_CONTACTS,
 | 
				
			||||||
 | 
					#ifdef PYTHON
 | 
				
			||||||
 | 
					    HELP_PLUGIN,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					} HELP_TYPES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void help_onDraw(ToxWindow *self);
 | 
				
			||||||
 | 
					void help_init_menu(ToxWindow *self);
 | 
				
			||||||
 | 
					void help_onKey(ToxWindow *self, wint_t key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* HELP_H */
 | 
				
			||||||
							
								
								
									
										350
									
								
								src/input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								src/input.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,350 @@
 | 
				
			|||||||
 | 
					/*  input.c
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Copyright (C) 2014 Toxic All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This file is part of Toxic.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *  it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 *  the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 *  (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Toxic is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *  GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 *  along with Toxic.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _GNU_SOURCE
 | 
				
			||||||
 | 
					#define _GNU_SOURCE    /* needed for wcwidth() */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <wchar.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "conference.h"
 | 
				
			||||||
 | 
					#include "line_info.h"
 | 
				
			||||||
 | 
					#include "misc_tools.h"
 | 
				
			||||||
 | 
					#include "notify.h"
 | 
				
			||||||
 | 
					#include "settings.h"
 | 
				
			||||||
 | 
					#include "toxic.h"
 | 
				
			||||||
 | 
					#include "toxic_strings.h"
 | 
				
			||||||
 | 
					#include "windows.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct user_settings *user_settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* add a char to input field and buffer */
 | 
				
			||||||
 | 
					void input_new_char(ToxWindow *self, wint_t key, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* this is the only place we need to do this check */
 | 
				
			||||||
 | 
					    if (key == '\n') {
 | 
				
			||||||
 | 
					        key = L'¶';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int cur_len = wcwidth(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cur_len == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (add_char_to_buf(ctx, key) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (x + cur_len >= mx_x) {
 | 
				
			||||||
 | 
					        int s_len = wcwidth(ctx->line[ctx->start]);
 | 
				
			||||||
 | 
					        ctx->start += 1 + MAX(0, cur_len - s_len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* delete a char via backspace key from input field and buffer */
 | 
				
			||||||
 | 
					static void input_backspace(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (del_char_buf_bck(ctx) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
 | 
				
			||||||
 | 
					    int s_len = ctx->start > 0 ? wcwidth(ctx->line[ctx->start - 1]) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->start && (x >= mx_x - cur_len)) {
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
 | 
				
			||||||
 | 
					    } else if (ctx->start) {
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - cur_len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* delete a char via delete key from input field and buffer */
 | 
				
			||||||
 | 
					static void input_delete(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (del_char_buf_frnt(self->chatwin) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* delete last typed word */
 | 
				
			||||||
 | 
					static void input_del_word(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (del_word_buf(ctx) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* deletes entire line before cursor from input field and buffer */
 | 
				
			||||||
 | 
					static void input_discard(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (discard_buf(self->chatwin) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* deletes entire line after cursor from input field and buffer */
 | 
				
			||||||
 | 
					static void input_kill(ChatContext *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (kill_buf(ctx) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void input_yank(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (yank_buf(ctx) == -1) {
 | 
				
			||||||
 | 
					        sound_notify(self, notif_error, 0, NULL);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int yank_cols = MAX(0, wcswidth(ctx->yank, ctx->yank_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (x + yank_cols >= mx_x) {
 | 
				
			||||||
 | 
					        int rmdr = MAX(0, (x + yank_cols) - mx_x);
 | 
				
			||||||
 | 
					        int s_len = MAX(0, wcswidth(&ctx->line[ctx->start], rmdr));
 | 
				
			||||||
 | 
					        ctx->start += s_len + 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves cursor/line position to end of line in input field and buffer */
 | 
				
			||||||
 | 
					static void input_mv_end(ToxWindow *self, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ctx->pos = ctx->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
 | 
				
			||||||
 | 
					    ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves cursor/line position to start of line in input field and buffer */
 | 
				
			||||||
 | 
					static void input_mv_home(ToxWindow *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos <= 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ctx->pos = 0;
 | 
				
			||||||
 | 
					    ctx->start = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves cursor/line position left in input field and buffer */
 | 
				
			||||||
 | 
					static void input_mv_left(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos <= 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int cur_len = ctx->pos > 0 ? wcwidth(ctx->line[ctx->pos - 1]) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    --ctx->pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->start > 0 && (x >= mx_x - cur_len)) {
 | 
				
			||||||
 | 
					        int s_len = wcwidth(ctx->line[ctx->start - 1]);
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - 1 + (s_len - cur_len));
 | 
				
			||||||
 | 
					    } else if (ctx->start > 0) {
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - cur_len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves the cursor to the beginning of the previous word in input field and buffer */
 | 
				
			||||||
 | 
					static void input_skip_left(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos <= 0) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        --ctx->pos;
 | 
				
			||||||
 | 
					        count += wcwidth(ctx->line[ctx->pos]);
 | 
				
			||||||
 | 
					    } while (ctx->pos > 0 && (ctx->line[ctx->pos - 1] != L' ' || ctx->line[ctx->pos] == L' '));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->start > 0 && (x >= mx_x - count)) {
 | 
				
			||||||
 | 
					        int s_len = wcwidth(ctx->line[ctx->start - 1]);
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - 1 + (s_len - count));
 | 
				
			||||||
 | 
					    } else if (ctx->start > 0) {
 | 
				
			||||||
 | 
					        ctx->start = MAX(0, ctx->start - count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves cursor/line position right in input field and buffer */
 | 
				
			||||||
 | 
					static void input_mv_right(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos >= ctx->len) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ++ctx->pos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int cur_len = wcwidth(ctx->line[ctx->pos - 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (x + cur_len >= mx_x) {
 | 
				
			||||||
 | 
					        int s_len = wcwidth(ctx->line[ctx->start]);
 | 
				
			||||||
 | 
					        ctx->start += 1 + MAX(0, cur_len - s_len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* moves the cursor to the end of the next word in input field and buffer */
 | 
				
			||||||
 | 
					static void input_skip_right(ToxWindow *self, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ctx->pos >= ctx->len) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        count += wcwidth(ctx->line[ctx->pos]);
 | 
				
			||||||
 | 
					        ++ctx->pos;
 | 
				
			||||||
 | 
					    } while (ctx->pos < ctx->len && !(ctx->line[ctx->pos] == L' ' && ctx->line[ctx->pos - 1] != L' '));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int newpos = x + count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (newpos >= mx_x) {
 | 
				
			||||||
 | 
					        ctx->start += (1 + (newpos - mx_x));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* puts a line history item in input field and buffer */
 | 
				
			||||||
 | 
					static void input_history(ToxWindow *self, wint_t key, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ChatContext *ctx = self->chatwin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fetch_hist_item(ctx, key);
 | 
				
			||||||
 | 
					    int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
 | 
				
			||||||
 | 
					    ctx->start = wlen < mx_x ? 0 : wlen - mx_x + 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handles non-printable input keys that behave the same for all types of chat windows.
 | 
				
			||||||
 | 
					   return true if key matches a function, false otherwise */
 | 
				
			||||||
 | 
					bool input_handle(ToxWindow *self, wint_t key, int x, int mx_x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    bool match = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (key) {
 | 
				
			||||||
 | 
					        case 0x7f:
 | 
				
			||||||
 | 
					        case KEY_BACKSPACE:
 | 
				
			||||||
 | 
					            input_backspace(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_DC:
 | 
				
			||||||
 | 
					            input_delete(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_DISCARD:
 | 
				
			||||||
 | 
					            input_discard(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_KILL:
 | 
				
			||||||
 | 
					            input_kill(self->chatwin);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_C_Y:
 | 
				
			||||||
 | 
					            input_yank(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_C_W:
 | 
				
			||||||
 | 
					            input_del_word(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_HOME:
 | 
				
			||||||
 | 
					        case T_KEY_C_A:
 | 
				
			||||||
 | 
					            input_mv_home(self);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_END:
 | 
				
			||||||
 | 
					        case T_KEY_C_E:
 | 
				
			||||||
 | 
					            input_mv_end(self, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_LEFT:
 | 
				
			||||||
 | 
					            input_mv_left(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_RIGHT:
 | 
				
			||||||
 | 
					            input_mv_right(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case KEY_UP:
 | 
				
			||||||
 | 
					        case KEY_DOWN:
 | 
				
			||||||
 | 
					            input_history(self, key, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_C_L:
 | 
				
			||||||
 | 
					            force_refresh(self->chatwin->history);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_C_LEFT:
 | 
				
			||||||
 | 
					            input_skip_left(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case T_KEY_C_RIGHT:
 | 
				
			||||||
 | 
					            input_skip_right(self, x, mx_x);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            match = false;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* TODO: this special case is ugly.
 | 
				
			||||||
 | 
					       maybe convert entire function to if/else and make them all customizable keys? */
 | 
				
			||||||
 | 
					    if (!match) {
 | 
				
			||||||
 | 
					        if (key == user_settings->key_toggle_peerlist) {
 | 
				
			||||||
 | 
					            if (self->type == WINDOW_TYPE_CONFERENCE) {
 | 
				
			||||||
 | 
					                self->show_peerlist ^= 1;
 | 
				
			||||||
 | 
					                redraw_conference_win(self);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            match = true;
 | 
				
			||||||
 | 
					        } else if (key == user_settings->key_toggle_pastemode) {
 | 
				
			||||||
 | 
					            self->chatwin->pastemode ^= 1;
 | 
				
			||||||
 | 
					            match = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return match;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user