Compare commits

...
Sign in to create a new pull request.

781 commits

Author SHA1 Message Date
Philipp Hörist
519d86444a Refactor conditions to determine connected state
GUI code must not be aware of what integers map to connection states
2019-05-20 21:33:42 +02:00
Philipp Hörist
2485227701 Move ConnectionSocks5Bytestream code to module 2019-05-19 22:33:20 +02:00
Philipp Hörist
275e719da3 Move ConnectionJingle code to module 2019-05-19 22:33:20 +02:00
Yuki
1675161095 Add paste-image-from-clipboard functionality 2019-05-19 16:56:48 +02:00
Philipp Hörist
4394bb1174 Fix disabling Zeroconf account 2019-05-19 16:49:34 +02:00
Philipp Hörist
fdfc9c90a1 Move IBB code to new IBB module 2019-05-19 16:10:27 +02:00
Philipp Hörist
7ec93f89a2 Remove support for XEP-0096 (SI File Transfer) 2019-05-19 16:10:23 +02:00
Philipp Hörist
e1bcbd2f1f Move _compute_resource() into helper module 2019-05-19 16:10:14 +02:00
Philipp Hörist
02915163dc Remove getRoster() helper method 2019-05-18 20:51:01 +02:00
Philipp Hörist
2e50ac5205 Remove unused code 2019-05-18 01:31:09 +02:00
Philipp Hörist
22b3388554 Move roster methods into Roster module 2019-05-18 01:30:37 +02:00
Philipp Hörist
f601ca0d7b Add dedicated announce/motd module 2019-05-18 01:04:11 +02:00
Philipp Hörist
9dbac0f098 Remove custom status per contact feature 2019-05-17 23:38:06 +02:00
Philipp Hörist
9f8492ae69 AdHoc: Show error page if no commands are available
- Remove some unused code

Fixes #9704
2019-05-16 23:34:15 +02:00
Daniel Brötzmann
c823ef6ceb Unify display of URLs in status messages
Status messages in group chats and private chats are now displayed
in the same way as status messages in single chat windows. This
avoids trailing brackets to be appended to a possible hyperlink inside
the status message. Fixes #8470
2019-05-15 23:23:46 +02:00
Philipp Hörist
ac4bde0447 MAM: Always reset state on reconnect
It was not reset if the previous MAM query was interrupted because of a disconnect
2019-05-15 20:12:41 +02:00
Philipp Hörist
03917eda66 Fix pylint errors 2019-05-09 17:54:33 +02:00
Philipp Hörist
bc5e754172 Settings: Determine activateable via func 2019-05-09 17:51:53 +02:00
Daniel Brötzmann
b59d5434f2 Shortcuts: Add shortcuts to move tab left or right 2019-04-30 22:51:01 +02:00
Daniel Brötzmann
9e25930106 ServerInfo: Simplify code around feature creation
- Fix traceback when httpupload is not available
- Improve copy to clipboard text
2019-04-30 19:32:00 +02:00
Daniel Brötzmann
7ed770d7c8 Treat incoming messages as 'chat' by default
Incomming messages of type 'normal' have to be acknowledged one by one,
which can be time consuming when many messages are received.
2019-04-30 17:33:12 +02:00
Daniel Brötzmann
606b5e8a2b SingleMessageWindow: Do not translate placeholder labels 2019-04-30 08:13:30 +02:00
Daniel Brötzmann
5fb231876d Use native GTK icons for audio and video 2019-04-29 21:35:54 +02:00
Daniel Brötzmann
ba1f88a006 RosterWindow: Remove blocked contacts from contact list if not in roster
When blocking a contact which is not in the roster, the contact is
removed and the ChatControl is closed (if any).
2019-04-27 14:04:19 +02:00
Philipp Hörist
a50cedaa6b Move log message 2019-04-27 12:39:34 +02:00
Philipp Hörist
2eb2039a3f Remove Google as default search engine 2019-04-27 12:30:56 +02:00
Philipp Hörist
b9b5690bc4 Use https instead of http 2019-04-27 12:30:56 +02:00
Philipp Hörist
423cfb9fdc Add method to generate map links 2019-04-27 12:30:56 +02:00
Philipp Hörist
dd7496d7a7 Add dedicated method for parsing and opening URIs 2019-04-27 12:30:56 +02:00
Markus Wintermann
6c6c4bdcfe Fix installation of dependencies
Install precis-i18n before the other dependencies, because it is needed by
python-nbxmpp
2019-04-26 21:41:38 +02:00
Daniel Brötzmann
2f5f32257d Add max file size (http_upload) to tooltip and server info 2019-04-26 20:15:31 +02:00
Philipp Hörist
a8bd8abe11 Add test for CertificateDialog 2019-04-26 19:53:10 +02:00
Daniel Brötzmann
6e9b605c00 Certificate dialog: Add copy info button 2019-04-26 19:53:10 +02:00
Daniel Brötzmann
5d795b4c1e MessageWindow: Open new tab relative to the current one 2019-04-26 17:11:59 +02:00
Daniel Brötzmann
f6c3d03261 Rework SingleMessageWindow 2019-04-26 17:09:18 +02:00
Daniel Brötzmann
87bbf4738a MessageWindow: When grouped by type, show contact's name if only one conversation
When chat windows are grouped by type, the window title is either Chats or Group Chats.
If there is only one conversation of either type, the window's title now shows the
contact's or group chat's name.
2019-04-26 16:45:16 +02:00
Daniel Brötzmann
b262d5add9 Disable contact sign-in notification by default 2019-04-26 10:04:02 +02:00
Daniel Brötzmann
eb6762a461 Display server in remote-server-not-found error dialog 2019-04-24 22:56:06 +02:00
Daniel Brötzmann
04717274b3 GroupchatControl: Switch encrypted symbol to symbolic 2019-04-24 16:07:24 +02:00
Daniel Brötzmann
245cecf1a9 Rework PassphraseDialog 2019-04-23 23:11:25 +02:00
Daniel Brötzmann
a9499386be Use symbolic icon in RemoveAccountWindow 2019-04-23 14:07:21 +02:00
Philipp Hörist
185d249e0f ServerInfo: Make dialog scrollable 2019-04-22 15:58:03 +02:00
Philipp Hörist
30997fa1e4 Remove some useless settings 2019-04-22 15:36:28 +02:00
Philipp Hörist
b306a7e05f Rework Accounts Window
- Every account row has now a submenu
- Moved Remove, Back and Pages into the submenu
2019-04-22 12:48:01 +02:00
Philipp Hörist
8c03d37217 Fix undefined var error 2019-04-20 20:18:54 +02:00
Philipp Hörist
657050ad52 Add default chatstate setting 2019-04-20 19:54:48 +02:00
Philipp Hörist
5f84dffca6 Add chatstate setting per contact 2019-04-20 17:43:54 +02:00
Philipp Hörist
df13aa4b22 Make setting description smaller 2019-04-20 17:03:23 +02:00
Philipp Hörist
b134fccf94 Move account specific settings
Move some settings from Prefrences to Accounts
2019-04-20 16:57:56 +02:00
Philipp Hörist
e34886ae47 Add custom MaxWidthComboBoxText 2019-04-20 14:58:22 +02:00
Philipp Hörist
e495617d3d Settings: Add ComboSetting 2019-04-20 14:19:22 +02:00
Philipp Hörist
c343746430 Refactor OptionsDialog
- Rename Option to Setting, it fits better
- Settings inherit from Gtk.ListBoxRow
2019-04-20 13:18:25 +02:00
Philipp Hörist
cc3750711d Add copy menu to Search dialog 2019-04-20 09:47:34 +02:00
Philipp Hörist
6e7f53df48 Remove unused code 2019-04-20 08:37:48 +02:00
Philipp Hörist
cbb1918bce Update CONTRIBUTING.md 2019-04-20 08:13:56 +02:00
Philipp Hörist
eb6d324ec5 Remove unused glade file 2019-04-20 00:26:41 +02:00
Philipp Hörist
a27599c63b Rework Search dialog
- Make it a proper Gtk.Assistant
2019-04-19 23:57:55 +02:00
Philipp Hörist
8bfe90c5fe Refactor FakeDataFormWidget
- Add test
- Support oob redirect url
2019-04-19 19:36:43 +02:00
Philipp Hörist
9f4adbdd1c Fix deprecation warning 2019-04-19 19:36:43 +02:00
Daniel Brötzmann
bd75c78b82 Revert destructive-action on SubRequest deny 2019-04-19 17:04:16 +02:00
Daniel Brötzmann
24352b57c7 Disable resizing in GroupchatInvitationReceived 2019-04-19 16:58:47 +02:00
Philipp Hörist
b2b249c60b Refator DataFormDialog 2019-04-19 16:57:12 +02:00
Philipp Hörist
731aaab633 Improve module imports
Import modules only on demand instead all on first module import
2019-04-19 16:57:12 +02:00
Sebastiaan Lokhorst
e999b74a5b zeroconf_bonjour: switch from DNSServiceQueryRecord to DNSServiceGetAddrInfo for IPv6 compatibility 2019-04-17 19:26:28 +02:00
Philipp Hörist
8f3604016f Update README.md 2019-04-16 23:34:04 +02:00
Philipp Hörist
df71c623e0 Update README.md 2019-04-16 23:30:00 +02:00
Philipp Hörist
9d75c77982 Remove GPG code from Gajim
Code moved into plugin
2019-04-16 23:24:40 +02:00
Alexander Bogdanov
64bac1d910 Implementing error type=modify handling for XEP-0077 2019-04-16 18:47:39 +02:00
Daniel Brötzmann
2f9b716ab0 Add speller to ChangeStatus dialog 2019-04-15 18:23:55 +02:00
Daniel Brötzmann
ef1d7771fb ChatControl: Switch encrypted symbol to symbolic 2019-04-15 11:14:49 +02:00
Philipp Hörist
53880edd96 Add delay execution decorator 2019-04-14 22:32:47 +02:00
Daniel Brötzmann
b32b0f4411 HTTPUpload: Display filename and transfer speed
Fixes #9661
2019-04-14 20:39:44 +02:00
Philipp Hörist
3312ca6c29 Add plugin extension point "send-presence"
This lets plugins modify the presence
2019-04-14 20:25:55 +02:00
Philipp Hörist
ecdf1526fb Fix mypy error 2019-04-14 10:44:08 +02:00
Philipp Hörist
d8beb0183c Refactor Singleton class 2019-04-14 01:58:45 +02:00
Daniel Brötzmann
d83f725578 XMLConsole: Add Paste Last Input button 2019-04-11 19:54:24 +02:00
Daniel Brötzmann
a717ec931e Bookmarks: Add tooltips, connect mnemonics, rename autojoin 2019-04-11 19:39:56 +02:00
Daniel Brötzmann
1e47cfaa57 Bookmarks: Adapt to _ui scheme 2019-04-11 19:39:52 +02:00
Daniel Brötzmann
7b329e9657 Bookmarks: Dont unselect all bookmarks after clicking Remove 2019-04-11 19:39:44 +02:00
Philipp Hörist
0dbcac4efe Connect gpg agent action correctly
Fixes #9660
2019-04-09 22:26:03 +02:00
Daniel Brötzmann
de790f5e4c Add profile button to add contact dialog
This lets the user query the VCard of the contact before adding
2019-04-09 21:53:34 +02:00
Marcin Mielniczuk
64d1401307 Add the possibility to paste as quote 2019-04-09 18:47:12 +02:00
Philipp Hörist
4ac532c3fa Fix memory leak with spell checker
- Dont shadow widgets destroy()
- Dont bind spell checker to class attribute, this prevents its finalize

Fixes #8822
2019-04-08 22:45:26 +02:00
Philipp Hörist
24d939ce41 Disable some pylint checks
Gtk Objects like a TreeModel is not detected correctly

- E0611 no-name-in-module
- E1133 not-an-iterable
- E1136 unsubscriptable-object
2019-04-07 23:34:43 +02:00
Philipp Hörist
3808c85cbd Enable more pylint checks
- E0611 no-name-in-module
- E0710 raising-non-exception
- E0712 catching-non-exception
- E1133 not-an-iterable
- E1136 unsubscriptable-object
2019-04-07 23:07:59 +02:00
Philipp Hörist
b54aba4d3e Fix access-member-before-definition pylint errors 2019-04-07 21:50:33 +02:00
Philipp Hörist
b91b64997e Fix no-callable pylint errors 2019-04-07 21:47:00 +02:00
Philipp Hörist
33f62cecf9 Fix bad-indentation pylint errors 2019-04-07 21:44:42 +02:00
Philipp Hörist
b8d70abdb0 Enable wildcard-import pylint check 2019-04-07 21:32:55 +02:00
Philipp Hörist
7ef066b181 Fix ungrouped-imports pylint errors 2019-04-07 21:29:45 +02:00
Philipp Hörist
cf40a2a8ef Fix wrong-import-order pylint errors 2019-04-07 21:20:21 +02:00
Philipp Hörist
3b3c2af97b Fix wrong-import-position pylint errors 2019-04-07 21:15:39 +02:00
Philipp Hörist
d55cb97dd2 Update pylintrc
- Ignore some pylint errors only in CI, not locally
- Set max line length to 80
2019-04-07 20:41:27 +02:00
Philipp Hörist
f62f922733 Fix unused-wildcard-import pylint errors 2019-04-07 20:27:07 +02:00
Philipp Hörist
1c39d66d21 Fix assignment-from-none pylint errors 2019-04-07 20:13:55 +02:00
Philipp Hörist
ee38f76004 Fix chained-comparison pylint errors 2019-04-07 19:50:15 +02:00
Philipp Hörist
20d3e981b9 Fix consider-using-ternary pylint errors 2019-04-07 19:48:09 +02:00
Philipp Hörist
dc3910ce4c Fix useless-return pylint errors 2019-04-07 19:07:16 +02:00
Philipp Hörist
8ca9c1d6e3 Add description for some pylint errors 2019-04-07 19:04:21 +02:00
Philipp Hörist
5471980a8c Update pylint to 2.3.1 2019-04-07 18:49:27 +02:00
Philipp Hörist
0dbb3eb1d5 Fix comparison-with-callable pylint errors 2019-04-07 18:48:51 +02:00
Philipp Hörist
c8815a9230 Fix no-else-raise pylint errors 2019-04-07 18:40:32 +02:00
Philipp Hörist
30f850b567 Fix no-else-return pylint errors 2019-04-07 18:26:29 +02:00
Philipp Hörist
b09f94dabd Fix simplifiable-if-expression pylint errors 2019-04-07 18:22:45 +02:00
Philipp Hörist
47dae61e21 Fix unnecessary-pass pylint errors 2019-04-07 18:20:15 +02:00
Philipp Hörist
3b2211776c Fix unused-import pylint errors 2019-04-07 18:14:54 +02:00
Philipp Hörist
45ac229fb1 Fix pylint errors 2019-04-07 17:35:19 +02:00
Philipp Hörist
32168c60f5 Fix license header 2019-04-07 17:11:30 +02:00
Philipp Hörist
797a9518ea Remove unused variable 2019-04-07 00:27:13 +02:00
Philipp Hörist
ed011da59e Add new Ad-Hoc Command dialog 2019-04-07 00:06:56 +02:00
Philipp Hörist
06848eaeaf Add option to make DataFormWidget read-only 2019-04-06 23:20:30 +02:00
Philipp Hörist
ac6eae8965 Fix import 2019-04-05 22:56:13 +02:00
Philipp Hörist
f1642e5327 Iterate safely over dict
Fixes #9633
2019-04-05 21:57:18 +02:00
Philipp Hörist
0b9aeb0100 Windows: Fix version comparison
Fixes #9643
2019-04-05 21:49:49 +02:00
Philipp Hörist
03cc3379d5 CertificateDialog: Dont fail on None values
Some attributes of the certificate can yield None
2019-04-05 21:38:32 +02:00
Daniel Brötzmann
318ae4e9d4 Rework InvitationReceivedDialog 2019-04-05 20:08:00 +02:00
Philipp Hörist
239ab1455b Refactor Software Version
- Simplify modules because nbxmpp handles more stuff
2019-04-05 19:44:30 +02:00
Philipp Hörist
471d9ca043 Windows: Dont override format region settings 2019-04-05 19:43:01 +02:00
Philipp Hörist
0678272774 Dont send invalid presence show value 2019-04-05 19:40:14 +02:00
Daniel Brötzmann
4d43eacfd0 Rework Certificate dialog 2019-04-05 17:19:35 +02:00
Daniel Brötzmann
a48610632e Only show avatar Save As menu if sha not None 2019-04-03 09:08:53 +02:00
Daniel Brötzmann
e83a246703 Rework SubscriptionRequestWindow 2019-04-02 19:49:57 +02:00
Philipp Hörist
139156ba5e FeaturesDialog: Replace python-dbus for avahi 2019-03-31 21:52:22 +02:00
André Apitzsch
16bbe31df6 Update dependency check for avahi support 2019-03-31 19:17:34 +02:00
Daniel Brötzmann
a7bc6dc530 Add monospace formatted fingerprint to encryption tooltip 2019-03-28 20:54:04 +01:00
Philipp Hörist
ae29c937ba ChatControl: Use NewConfirmationDialog 2019-03-27 23:36:55 +01:00
Philipp Hörist
f838c2faa2 MUC: Use NewConfirmationDialog for file transfer 2019-03-27 23:36:55 +01:00
Daniel Brötzmann
2080495efc Ask whether to disconnect when disabling account
Fixes #8938
2019-03-27 22:24:46 +01:00
Daniel Brötzmann
74ed71f57e Rework HTTPUpload dialog 2019-03-27 00:40:46 +01:00
Philipp Hörist
760b94f27f Add NewConfirmationCheckDialog 2019-03-27 00:14:00 +01:00
Philipp Hörist
4c062bf93d Call show() on new dialogs
- run() was removed from the dialog because it blocks
2019-03-26 23:53:12 +01:00
Philipp Hörist
bbada2ecd4 Improve NewConfirmationDialog
- Add setting for modal/non-modal
- Add default transient
- Dont call run() it only returns after response
2019-03-26 23:49:45 +01:00
Philipp Hörist
ca037665ca Remove unused imports 2019-03-26 21:55:51 +01:00
Philipp Hörist
acd9f67d92 HistoryManager: Use NewConfirmationDialog 2019-03-26 21:47:18 +01:00
Philipp Hörist
21aa352a34 Refactor NewConfirmationDialog 2019-03-26 20:19:50 +01:00
Philipp Hörist
1551ffa0b4 Correctly get the total screen geometry
get_root_window() does not work on Wayland

Fixes #9637
2019-03-25 23:09:06 +01:00
Philipp Hörist
8201688684 Move imports to the top 2019-03-25 22:26:55 +01:00
Philipp Hörist
7a5d791beb Refactor restoring roster position 2019-03-25 22:20:19 +01:00
Philipp Hörist
a9efde136b Refactor saving roster position
- Dont save roster position on Wayland
2019-03-25 22:20:19 +01:00
Daniel Brötzmann
b6e7f5c6d2 Format OMEMO fingerprint in tooltip 2019-03-25 21:00:40 +01:00
Philipp Hörist
4acf36c97b Add method to determine window manager 2019-03-25 20:11:53 +01:00
Daniel Brötzmann
f6e113c0b6 Update look of Remove account dialog 2019-03-25 20:11:33 +01:00
Daniel Brötzmann
52111cd1b3 Improve dark theme colors 2019-03-24 15:33:37 +01:00
Daniel Brötzmann
a988d2e250 Flatpak: Disable install from ZIP 2019-03-24 15:33:03 +01:00
Dominion
0de04b1ae9 Add server blabber.im to servers.json 2019-03-22 10:09:46 +01:00
André Apitzsch
fd46fcab64 Flatpak: Update runtime version to 3.32 2019-03-21 00:29:45 +01:00
André Apitzsch
c2be5372bd Flatpak: Fix cryptography build 2019-03-21 00:29:00 +01:00
Malte Leip
ae4c98cbb2
Show trust level for incoming encrypted messages 2019-03-20 20:50:49 +01:00
André Apitzsch
5af7fbd428 Flatpak: Update dependencies 2019-03-17 00:12:00 +01:00
André Apitzsch
ab6623d7bd Flatpak: Fix access to GnuPG keys
Fixes gajim/gajim-plugins#386
2019-03-17 00:11:33 +01:00
Philipp Hörist
6ef3b8e01b Windows: Dont steal focus on notification 2019-03-16 16:06:00 +01:00
Philipp Hörist
05dc004448 Notifications: Check if DBus is available 2019-03-16 15:51:12 +01:00
Philipp Hörist
c17b744465 Generate account label correctly 2019-03-16 15:33:58 +01:00
Philipp Hörist
196d856a54 Remove password before config values 2019-03-16 14:47:42 +01:00
Philipp Hörist
be26f50120 Fix nbxmpp method calls
features_nb was renamed
2019-03-16 14:01:49 +01:00
Philipp Hörist
fa464d4333 Fix error while quitting
Fixes #9622
2019-03-16 13:55:15 +01:00
Philipp Hörist
979c7d2553 Dont leak DNS query if we connect via proxy
Fixes #9573
2019-03-16 13:22:05 +01:00
Philipp Hörist
11ae4fac6a HistoryWindow: Center top widgets vertically 2019-03-12 18:58:52 +01:00
Philipp Hörist
62d12f4355 Themes: Better visibility of scrollbar 2019-03-12 18:52:05 +01:00
Philipp Hörist
4b3a5b7704 Use Consistent Color Generation for MUC nicknames 2019-03-12 18:44:20 +01:00
Philipp Hörist
348a8551fe Remove datetime parsing from Gajim
Use nbxmpp's datetime parsing
2019-03-11 23:13:11 +01:00
Philipp Hörist
da46bdda1f Remove delay parsing from Gajim
Use nbxmpp's delay parsing
2019-03-11 23:13:11 +01:00
Philipp Hörist
f5fe4fd8de Better dedupe MUC history messages 2019-03-11 23:13:11 +01:00
Philipp Hörist
851a7ee929 Depend on nbxmpp delay parsing 2019-03-11 23:13:00 +01:00
Philipp Hörist
b80bbaf2b3 Improve log message format 2019-03-10 10:07:12 +01:00
Philipp Hörist
0eb75eb73d Modules: Use LogAdapter
- Make all modules inherit from BaseModule
- Use LogAdapter in BaseModule
2019-03-10 10:06:45 +01:00
Philipp Hörist
6e672c9911 Add LogAdapter
This adds the account to all log messages issues in module code
2019-03-08 20:31:05 +01:00
Philipp Hörist
b704e27abc Write correct show values to database
Since the refactor we wrote accidentally string instead of int
2019-03-06 23:03:45 +01:00
Philipp Hörist
5e97d805d9 HistoryManager: Display show value correctly 2019-03-06 22:14:57 +01:00
Philipp Hörist
872ee3d675 Fix presence subscription
Fixes #9612
2019-03-06 22:11:35 +01:00
Philipp Hörist
1827249653 Fix imports
transports_nb was renamed in nbxmpp
2019-03-04 13:49:03 +01:00
André Apitzsch
74c5f3d0e9 Avahi: don't fail if avahi gir is not installed
Fixes #9610
2019-03-04 08:20:01 +01:00
André Apitzsch
ee6f65f404 Port Avahi to GDBus
fixes #9147
2019-03-03 19:41:55 +01:00
Philipp Hörist
94eef409db Fix imports
dispatcher_nb was renamed in nbxmpp
2019-03-03 19:40:39 +01:00
Philipp Hörist
c58c7cc4a0 Make passwords module more resilient
- Catch more exceptions
- Add more log output
2019-03-02 19:59:27 +01:00
Philipp Hörist
1f479e5ba4 Use pathlib replace() for saving config
This makes it hopefully more resilient on Windows
2019-03-02 10:43:14 +01:00
Philipp Hörist
d61ca3ae6d Fix typo 2019-03-02 09:32:08 +01:00
Philipp Hörist
e023c33268 Use a UUID4 as item id for pubsub posts 2019-03-01 22:57:44 +01:00
Philipp Hörist
553436332b StartChatDialog: Add Muclumbus search 2019-03-01 21:45:50 +01:00
Philipp Hörist
6c06d2c497 1.1.92 2019-02-24 20:23:55 +01:00
Philipp Hörist
3bf755943f Raise nbxmpp version 2019-02-24 20:20:28 +01:00
Philipp Hörist
e3f8f050c0 Zeroconf: Fix missing attrs 2019-02-20 00:31:28 +01:00
Philipp Hörist
0963f44443 Use nbxmpp's parsed EME data 2019-02-20 00:31:24 +01:00
Philipp Hörist
12d909d636 LastActivity: Use BaseModule and StanzaHandler 2019-02-19 20:38:57 +01:00
Philipp Hörist
12389f4097 Remove unused code 2019-02-19 20:38:57 +01:00
Philipp Hörist
72fc96ae63 Refactor Annotations
- Simplify modules because nbxmpp handles more stuff
2019-02-18 23:02:14 +01:00
Philipp Hörist
11c5fd29e5 Remove not used PEP module code 2019-02-18 23:02:05 +01:00
Philipp Hörist
54a9992696 Remove atom modules 2019-02-18 19:46:47 +01:00
André Apitzsch
67ddbf73cd Flatpak: switch to nbxmpp master 2019-02-17 15:22:10 +01:00
André Apitzsch
7530b231b1 Flatpak: update dependencies 2019-02-17 15:13:45 +01:00
Philipp Hörist
0573d42d29 Notifications: Catch all DBus errors 2019-02-16 20:08:00 +01:00
Philipp Hörist
7cd781e921 Get module instance after checking for zeroconf 2019-02-16 13:04:14 +01:00
Philipp Hörist
4c3110c27d Redirect some print statments to stderr
Otherwise they errors will not show up if the console output is
redirected to a file
2019-02-16 10:36:27 +01:00
Philipp Hörist
a944e7e6e1 Determine windows version reliably
Fixes #9578
2019-02-15 17:02:40 +01:00
Philipp Hörist
8455a0fa40 Fix filetransfer tooltip 2019-02-15 15:49:47 +01:00
Philipp Hörist
53d6b1dc32 Dont advertise urn:xmpp:hashes:1
Fixes #9514
2019-02-15 15:04:50 +01:00
Philipp Hörist
7fe03dcb45 XTLS: Fix endless loop on write error 2019-02-15 14:58:56 +01:00
Philipp Hörist
bc7e0e1ee4 Fix depreaction warning
set_cipher_list wants bytes
2019-02-15 14:58:11 +01:00
Philipp Hörist
1f5be6cb0f Add mobile phone indicator
Shows a mobile phone icon if the last message was received by a client
which identifies as phone
2019-02-12 21:40:43 +01:00
Philipp Hörist
c2038b0ffe Adapt to BlockingListResult changes in nbxmpp 2019-02-11 22:24:20 +01:00
Philipp Hörist
dede4ba4f2 Adapt to MucConfigResult changes in nbxmpp 2019-02-11 21:41:39 +01:00
Philipp Hörist
94160d830f Adapt to AffiliationResult changes in nbxmpp 2019-02-11 21:05:20 +01:00
Philipp Hörist
f8373012a2 Fix typo 2019-02-11 20:58:42 +01:00
Philipp Hörist
4a2c23b893 Correctly remove bookmark after MUC was destroyed 2019-02-11 20:32:41 +01:00
Philipp Hörist
6f61f05377 MAM: Detect nbxmpp supported encryptions 2019-02-11 20:29:20 +01:00
Philipp Hörist
1256372d36 Handle nbxmpp error results 2019-02-10 00:39:10 +01:00
Philipp Hörist
5059f72373 Windows: Add pygments to build 2019-02-09 22:05:17 +01:00
Philipp Hörist
4442db5461 Remove unused import 2019-02-09 21:45:18 +01:00
Philipp Hörist
fc8c056eff Detect nbxmpp supported encryptions
- Better handle logging for gnupg
2019-02-09 21:39:14 +01:00
Philipp Hörist
fa71052464 Remove unused import 2019-02-06 20:46:53 +01:00
Philipp Hörist
959be5b8ee Remove unused code 2019-02-06 20:42:26 +01:00
André Apitzsch
36a0083942 Clean up OpenSSL code 2019-02-06 20:25:55 +01:00
streaps
a3c316abaa AMR codec added 2019-02-06 20:18:58 +01:00
Philipp Hörist
a89bec0b9d Refactor Bookmarks
- Simplify modules because nbxmpp handles more stuff
2019-02-04 21:59:33 +01:00
Philipp Hörist
fa7f6f2b8c Add modules to store publish list 2019-02-03 00:15:28 +01:00
Philipp Hörist
cef5b04d82 Refactor UserAvatar
- Simplify modules because nbxmpp handles more stuff
2019-02-03 00:08:28 +01:00
Philipp Hörist
15dc059bf3 Use css value for message input placeholder 2019-02-02 19:12:06 +01:00
Philipp Hörist
dfc3749a4f Remove unused import 2019-02-02 18:03:57 +01:00
Philipp Hörist
3f03e6e0a4 Better handle disable notifitcations 2019-02-02 12:55:07 +01:00
Philipp Hörist
59b39b049a Refactor UserLocation
- Simplify modules because nbxmpp handles more stuff
2019-02-02 12:51:28 +01:00
Philipp Hörist
d37b95e45e Refactor UserTune
- Simplify modules because nbxmpp handles more stuff
2019-02-02 12:51:24 +01:00
Philipp Hörist
18c422d843 Move print for debug message 2019-02-01 17:24:33 +01:00
Philipp Hörist
0b6fac44dc Dont fail on malformed pubsub events 2019-02-01 17:03:46 +01:00
Philipp Hörist
b9b9dae6a0 Refactor UserActivity
- Use IconTheme for mood icons
- Simplify modules because nbxmpp handles more stuff
2019-01-31 22:57:15 +01:00
Philipp Hörist
be95b04007 Refactor UserNickname and UserMood
- Use IconTheme for mood icons
- Simplify modules because nbxmpp handles more stuff
2019-01-30 23:36:01 +01:00
Philipp Hörist
8e336311cc Add annotations 2019-01-26 21:57:22 +01:00
Philipp Hörist
d6b7916f2b Prevent callbacks on destroyed objects
Fixes #9560
2019-01-26 21:25:33 +01:00
Philipp Hörist
e994b8f402 Count MUC members correctly
- Pass Affiliation enum to get_uf_affiliation
- Pass Role enum to get_uf_role
2019-01-26 20:40:07 +01:00
Philipp Hörist
80e5934bb5 Dont skip extension point
- If the contact has no avatar the tooltip extension point was not executed
2019-01-26 20:04:43 +01:00
Philipp Hörist
ce0abb991c Add BaseModule 2019-01-26 14:34:58 +01:00
Philipp Hörist
dad99f85fc Accounts: Update proxy combobox correctly 2019-01-22 22:00:20 +01:00
Philipp Hörist
1a7d930fc4 Add blocking list dialog 2019-01-21 22:45:19 +01:00
Philipp Hörist
b0742377f0 Roster: remove asserts 2019-01-20 14:29:48 +01:00
Philipp Hörist
4670760668 Fix destroying a MUC
- Only close the tab if we initiated the destruction
2019-01-19 23:05:36 +01:00
Philipp Hörist
31d9b39744 Deal with stanza-id not added by a mam archive
Fixes #9550
2019-01-19 21:35:58 +01:00
Philipp Hörist
3e362874be Detect invalid user activity 2019-01-19 21:21:20 +01:00
Philipp Hörist
7c7df9d4a4 Detect invalid user mood
Fixes #9546, #9547
2019-01-19 21:21:16 +01:00
Philipp Hörist
cf8eafffb2 Detect full language code
Previously we only used short language codes (en, de, fr)

- Add conversion method to rfc5646 format
2019-01-19 20:40:06 +01:00
Philipp Hörist
a9994b791b Windows: Fix language detection 2019-01-19 19:41:52 +01:00
Philipp Hörist
72be14a04d Jingle Audio: Add more log output 2019-01-11 21:53:34 +01:00
Philipp Hörist
b22f1baca5 Propagate presences further
Other modules like avatars and entity caps come after the base presence handlers
2019-01-11 20:45:11 +01:00
Philipp Hörist
4f2f2195aa DiscoveryWindow: Fix bookmarking a group chat
Fixes #9537
2019-01-10 23:40:08 +01:00
streaps
88439091b0 Jingle Audio: Update codecs
Fixes #9535
2019-01-10 22:28:00 +01:00
Philipp Hörist
911674d580 Fix status tray notification
Clicking on a new message notification in the status tray didnt open the chat
2019-01-10 22:08:11 +01:00
Philipp Hörist
5b1f8bcc48 Make sure args are always str 2019-01-10 22:07:52 +01:00
Philipp Hörist
418459b634 DBus: Add some logging 2019-01-10 21:50:49 +01:00
Philipp Hörist
247ee81334 Remove unused vars 2019-01-10 21:37:47 +01:00
Philipp Hörist
b84054b58c DBus: Correctly raise NewMessage signal 2019-01-10 21:34:17 +01:00
Philipp Hörist
de25b57ad8 Windows: Downgrade to Gtk 3.24.1 2019-01-08 22:09:06 +01:00
Philipp Hörist
dad671c1c7 Remove unused import 2019-01-07 23:52:51 +01:00
Philipp Hörist
fc64bee08c Raise nbxmpp version 2019-01-07 23:45:11 +01:00
Philipp Hörist
4f3e4d2242 Pass xml:lang to nbxmpp 2019-01-07 23:44:51 +01:00
Sebastiaan Lokhorst
84b2392fcc Add tool to create macOS .icns icon and .app bundle 2019-01-07 22:26:42 +01:00
Philipp Hörist
9879722d42 Update CONTRIBUTING.md 2019-01-07 22:23:37 +01:00
Philipp Hörist
a917ea18e2 Update CONTRIBUTING.md 2019-01-07 22:22:39 +01:00
Philipp Hörist
ab1a64b352 Update CONTRIBUTING.md 2019-01-07 22:20:37 +01:00
Philipp Hörist
de8b5cb7a6 Update README.md
Fixes #9531
2019-01-07 20:59:28 +01:00
Philipp Hörist
5776d3de48 Chatstates: Add more log output 2019-01-06 11:23:30 +01:00
Philipp Hörist
6a958c5725 Pass contact instead of string
Fixes #9529
2019-01-06 11:10:07 +01:00
Philipp Hörist
a64d986c7f Fix pylint error 2019-01-06 02:15:17 +01:00
Philipp Hörist
eb99291d44 Add chat state setting per room
- Add menu option to the group chat menu for setting the chat state
- Up the paused timer to 10 seconds
- Default for group chats is composing only
2019-01-06 02:01:12 +01:00
Philipp Hörist
777b8d72e4 Remove print statement 2019-01-06 00:58:07 +01:00
Philipp Hörist
e308d7a210 Remove unused vars 2019-01-06 00:32:59 +01:00
Philipp Hörist
eebccaf07d Remove unused import 2019-01-06 00:05:12 +01:00
Philipp Hörist
55694b60bf Dont save Gajim settings in bookmarks
- Remove print status from bookmarks
- Remove minimize on join from bookmarks
- Add options to the groupchat menu for both settings

Fixes #9463
2019-01-06 00:00:42 +01:00
Philipp Hörist
4c17b55a91 Fix pylint error 2019-01-05 20:17:20 +01:00
Philipp Hörist
4aa265451d MUC: Use default value when printing the status 2019-01-05 20:10:08 +01:00
Philipp Hörist
7b558d692c MUC: Update menu after preference change
- Simplify action lookup
2019-01-05 19:43:11 +01:00
Philipp Hörist
19c45510a0 MUC: Fix printing status/show
- rename config values to something more appropriate
2019-01-05 19:17:34 +01:00
Philipp Hörist
633795b7f4 Dont fail on users leaving a group chat
Fixes #9527
2019-01-05 19:17:34 +01:00
Sebastiaan Lokhorst
a91f5f2c49 Fix Bonjour (pybonjour) on macOS 2019-01-05 18:37:09 +01:00
André Apitzsch
468d8bd472 Bump copyright year 2019-01-05 17:35:00 +01:00
André Apitzsch
58d7096aca Remove obsolete dbus plugin 2019-01-05 16:46:36 +01:00
Philipp Hörist
d200e94fba Better determine language cross platform 2019-01-05 16:27:11 +01:00
Philipp Hörist
4aca2eeae2 Dont send chatstates when cycling MUC nicks
- Add ability to enable/disable the whole module so it doesnt try to send chatstates when we are offline
2019-01-04 15:21:55 +01:00
Philipp Hörist
4bd14bc51d Use custom link handler in AboutDialog
Fixes #9525
2019-01-04 11:56:23 +01:00
Philipp Hörist
67318a49e5 Preferences: Add some default options
- Option to set default sync threshold
- Option to set default show join/leave
- Option to set default show status message change
2019-01-04 09:00:12 +01:00
Philipp Hörist
5fd1e7b4bf Remove ping timeout on disconnect handler 2019-01-04 00:49:59 +01:00
Philipp Hörist
b600328639 Refactor message handlers
- Adapt to nbxmpp now unwraping MAM messages
- Use nbxmpp properties
- Save message-id to database
2019-01-04 00:11:28 +01:00
Philipp Hörist
cdb37828e4 Move message error handler into message module 2019-01-03 11:52:26 +01:00
Philipp Hörist
c0fb645309 Move MUC message logging into message module 2019-01-03 11:25:45 +01:00
Philipp Hörist
4631f50372 Remove unused code 2019-01-03 10:46:31 +01:00
Philipp Hörist
eb9f340a03 Remove star imports 2019-01-03 10:41:22 +01:00
Philipp Hörist
b05f0e1458 Move methods into Connection class 2019-01-03 10:19:53 +01:00
Philipp Hörist
0441ccd4e9 Move 'agent-removed' handler into Gateway module 2019-01-03 10:19:29 +01:00
Philipp Hörist
f3d5babc65 Register handlers in CommonConnection class 2019-01-03 10:19:25 +01:00
Philipp Hörist
1399c41d59 Remove old dbus module
We now use Gio DBus
2019-01-03 09:06:49 +01:00
Philipp Hörist
371756c2a5 Remove unnecessary event classes 2019-01-03 09:06:44 +01:00
Philipp Hörist
fcb33a10e7 Add missing get_instance() for Gateway/IQ module 2019-01-03 01:00:31 +01:00
Philipp Hörist
d1ccfd515a MUC: Dont check for unique room id support
This feature was remove from XEP-0045 in Version 1.25 (2012-02-08). We simply now use an uuid instead.
2019-01-03 00:50:22 +01:00
Philipp Hörist
d622439a44 Remove unused code 2019-01-03 00:50:00 +01:00
Philipp Hörist
9ae6654dd3 Add IQ and Gateway module 2019-01-03 00:19:23 +01:00
Philipp Hörist
d93fe8b1ea HTTPAuth: Use nbxmpp handlers 2019-01-02 16:53:06 +01:00
Philipp Hörist
d121bbf4ab Refactor Zeroconf presence 2019-01-02 16:10:30 +01:00
Philipp Hörist
b37c578504 Fix tests
- Fix more pylint errors
- Move caps test for now to broken
2019-01-02 02:27:38 +01:00
Philipp Hörist
0fcf90f8d5 Fix pylint errors 2019-01-02 02:16:42 +01:00
Philipp Hörist
f2beea0df3 Refactor Caps module 2019-01-02 02:04:54 +01:00
Philipp Hörist
a289ad5f60 Refactor Presence
- Remove option to hide self contacts for now. This makes the code less
complicated.
- Move as much code as possible into the presence module
- Use nbxmpp properties
2019-01-02 02:04:42 +01:00
Philipp Hörist
608607b721 Remove old PEP code 2018-12-31 10:54:51 +01:00
Philipp Hörist
a7aea4cac1 Raise version to 1.1.91.1 2018-12-31 02:03:31 +01:00
Philipp Hörist
735e72c965 Plugins: Unregister StanzaHandler correctly 2018-12-31 01:58:03 +01:00
Philipp Hörist
73f3e01bdf Update actions after affiliation/role change 2018-12-30 21:27:07 +01:00
Philipp Hörist
d06b73d7c6 Rename some muc events 2018-12-30 21:18:17 +01:00
Philipp Hörist
e1c17d752e Fix tests 2018-12-30 20:51:10 +01:00
Philipp Hörist
d203d36f07 Remove debug code 2018-12-30 20:44:59 +01:00
Philipp Hörist
0ad369dc97 Refactor MUC Presence
- Use nbxmpp properties
- Split into multiple events
- Add new options in the group chat menu for print settings
2018-12-30 20:06:59 +01:00
Philipp Hörist
ed4a81fead Windows: Fix build
Seems we cant set an install order for pip requirements, so install precis-18n alone
2018-12-30 01:37:10 +01:00
Philipp Hörist
5a148f1657 Preferences: Connect two missing signals 2018-12-29 23:05:29 +01:00
Philipp Hörist
79684d90d5 Simplify vcard avatar code
- Use nbxmpp properties
2018-12-28 13:38:15 +01:00
Philipp Hörist
34306921ed Correctly parse delay in groupchats 2018-12-28 11:54:54 +01:00
Philipp Hörist
8094cadbea Refactor MUC module
- nbxmpp provides now most of the MUC code
2018-12-27 22:13:35 +01:00
Philipp Hörist
c63e32634a Adapt Zeroconf to nbxmpp changes
Fixes #9503
2018-12-23 22:33:10 +01:00
Philipp Hörist
b548b90a6c Windows: Fix build
nbxmpp now requires precis-i18n
2018-12-22 14:21:25 +01:00
Philipp Hörist
94479dd7f6 Check if event was not consumed
Fixes #9096
2018-12-21 23:13:34 +01:00
Philipp Hörist
43f210bbaa Remove unused code 2018-12-21 19:33:34 +01:00
Philipp Hörist
0e6011c088 Ignore bookmark updates from other jids
Because we use +notify to subscribe to the bookmarks node, we get notifications from contacts that have an open access bookmarks node
2018-12-21 19:10:18 +01:00
Philipp Hörist
4503f466d6 Simplify gc-message-received event 2018-12-21 18:36:09 +01:00
Philipp Hörist
40fc727156 Remove unused code 2018-12-21 14:13:08 +01:00
Philipp Hörist
85e79e7b27 Use nbxmpp properties for HTTPAuth
nbxmpp implements HTTPAuth now, so we dont need to parse it anymore
2018-12-21 12:23:26 +01:00
Philipp Hörist
42c1909d3b Remove carbon processing
nbxmpp does that now for us
2018-12-20 23:18:23 +01:00
Philipp Hörist
1f975df8a4 Remove incorrect comment 2018-12-19 23:24:49 +01:00
Philipp Hörist
c614ac69df Refactor voice approval 2018-12-19 23:24:44 +01:00
Philipp Hörist
8b5adb06da Allow setting handler priority 2018-12-19 23:24:39 +01:00
Philipp Hörist
56d2c6bc7e Raise nbxmpp version 2018-12-19 23:24:38 +01:00
Philipp Hörist
ce6839957d Catch mediated invites only if type is normal
https://xmpp.org/extensions/xep-0045.html#invite-mediated
2018-12-19 23:00:56 +01:00
Philipp Hörist
5f555193c7 Send active instead of gone as last chatstate
- Also attempt to fix #9446
2018-12-19 23:00:56 +01:00
Philipp Hörist
e9f4c5050e Refactor MUC captcha challenge code 2018-12-19 23:00:50 +01:00
Philipp Hörist
1fec6681cd Move MUC config change handling into MUC module
- Remove status conditions code, since the XEP made a namespace bump to :1 and is now backwards compatible its useless
- XEP-0045 mentions status code 100 can be in messages but there is no case given where this would ever happen, so its removed from message handling
2018-12-19 23:00:09 +01:00
Philipp Hörist
b935ce7096 Add more log output when calling handlers 2018-12-19 02:18:12 +01:00
Philipp Hörist
99cfb8f629 Cleanup Gajims disco features 2018-12-19 00:11:24 +01:00
Philipp Hörist
de4cd80b83 Make namedtuple local 2018-12-18 22:52:29 +01:00
Philipp Hörist
ced387e719 Remove legacy code 2018-12-18 22:49:07 +01:00
Philipp Hörist
7286f4286f Add feature-discovered event
This lets us move more GUI code out of the common module
2018-12-18 22:41:06 +01:00
Philipp Hörist
89d9940933 Roster: Register our-show with lower priority
This event is used to shutdown the roster if we quit, it destroys all windows.

This should be run last because other objects like the ChatControl need a reference to the window to shutdown properly
2018-12-18 14:40:38 +01:00
Philipp Hörist
0ac52a390e Allow handlers list to be modifed while iterating 2018-12-18 14:08:27 +01:00
Philipp Hörist
a6b8ecf6f5 Fix error when opening sign-in/out notification 2018-12-17 15:02:40 +01:00
Philipp Hörist
b449567600 Make copying text work with different layouts
This makes it possible so text can be copied from the conversation textview with other keyboard layouts than english
2018-12-17 14:49:50 +01:00
Philipp Hörist
841f12f75b Fix mypy errors 2018-12-17 00:41:46 +01:00
Philipp Hörist
96edd79963 Handle PEP bookmarks notifications
- Handle PEP bookmark notifications
- On new bookmarks with the auto join flag set, join the MUC
- Dont merge private and pubsub bookmarks
- Only use pubsub if the conversion feature is announced
2018-12-17 00:36:45 +01:00
Philipp Hörist
19b0e73f44 Fix error on key press
Fixes #9471
2018-12-16 01:01:44 +01:00
Philipp Hörist
674ec48fa2 DBus: Show correct unread message number
Fixes #8362
2018-12-15 23:59:27 +01:00
Philipp Hörist
760645f5c3 Improve MUC notifications
- Play sound for received messages, if notify for all messages is activated
- Send system notifications on MUC messages
- Make notify for all the default in private MUCs

Fixes #9383
2018-12-15 23:37:44 +01:00
Philipp Hörist
dac5370780 Dont draw contact after selection change
This seems to be an old codepath, currently there is no need to redraw a contact on selection change

Fixes #9496
2018-12-14 21:39:58 +01:00
Philipp Hörist
5843827abc Fix start chat menu action
Fixes #8275
2018-12-12 23:35:36 +01:00
Philipp Hörist
be420d44fc Implement XEP-0411 Bookmarks Conversion
If bookmarks conversion is announced by the server:

- Dont merge bookmarks
- Only push to either private storage or pubsub
2018-12-10 22:30:45 +01:00
Philipp Hörist
4e814dabcf Fix disabled join groupchat menu
When there are no bookmarks on the server the join groupchat menu
was disabled, preventing the user to open the join groupchat dialog
2018-12-10 22:30:37 +01:00
Philipp Hörist
6e30d3af64 Adapt to nbxmpp API changes
- Remove support for OAUTH2
- Remove insecure password dialog, its impossible now that a user can connect plain by mistake
- Refactor requesting the password
- Add possibility to delete passwords
2018-12-09 18:48:44 +01:00
Philipp Hörist
b8863e82be MUC: Identify subject change correctly
Fixes #9491
2018-12-09 00:29:20 +01:00
Philipp Hörist
293156f670 Find correct contact on private message
get_contact() returns also a contact if only the bare jid matches,
which for private messages is the groupchat contact object.
2018-12-09 00:01:18 +01:00
Philipp Hörist
d129f5559a DataFormWidget: Fix some UI issues
- Textview: Wrap text, set padding
- ListMultiTreeView: Align checkboxes to the right
- Add a adjustment element that sets default sizes on the columns
- Allow two new options 'form-width' and 'left-width' to customize sizes
2018-12-06 23:06:10 +01:00
Philipp Hörist
31417ffbc7 Use virtualenv for CI tests 2018-12-05 21:41:44 +01:00
Philipp Hörist
ace1113d02 Fix pylint errors 2018-12-05 21:40:12 +01:00
Philipp Hörist
a979874fa1 Sort imports 2018-12-05 17:05:29 +01:00
Philipp Hörist
e419f75217 Remove unused imports 2018-12-05 17:05:10 +01:00
Philipp Hörist
4968fe39e2 Correctly remove ping timeout
Fixes #9481
2018-12-05 17:03:34 +01:00
Philipp Hörist
62253c804a Discover the bookmarks conversion server feature 2018-12-04 20:41:44 +01:00
Philipp Hörist
c2e2dd9a87 Fix MUC nick change 2018-12-04 19:43:55 +01:00
Philipp Hörist
86bbdd21fd Encode resource with correct profile
Fixes #9465
2018-12-04 19:43:13 +01:00
Philipp Hörist
932377f533 Remove unused event 2018-12-04 19:32:13 +01:00
Philipp Hörist
700666b820 Refactor send timeouts
Fixes #9459
2018-12-04 19:29:32 +01:00
Philipp Hörist
78f439c611 Refactor disconnect code
Fixes #9467
2018-12-04 19:28:50 +01:00
Philipp Hörist
59855a6c8d Determine delay timestamp correctly
- Check the from attr on the delay node to determine if its a user timestamp or from the server
- Dont use user timestamp for sorting
- Record the user timestamp in additional data so its saved to the database

Fixes #9444
2018-12-04 12:18:17 +01:00
Philipp Hörist
fd6dec1208 Handle presence without from attr correctly
Fixes #9472
2018-12-03 15:40:43 +01:00
Philipp Hörist
1d11e06647 Fix error when creating MUC
Fixes #9473
2018-12-03 14:17:46 +01:00
Philipp Hörist
3f2e3c6bb2 Better handle not available keyring backends 2018-12-01 21:46:58 +01:00
Philipp Hörist
432a4edbc1 Use custom dict for additional data
This makes it easier to retrive and store values
2018-11-30 23:05:15 +01:00
Philipp Hörist
91ebe37359 AccountsWindow: Fix back button 2018-11-27 21:04:13 +01:00
Philipp Hörist
f1ab9fb683 Fix connection resume
Fixes #9458
2018-11-27 19:23:34 +01:00
Andrey Gursky
f942e2c70f Fix receipts for chat
This is a regression from e3050697
2018-11-27 02:17:25 +01:00
André Apitzsch
e70ea74f0d CI: Fix test and build 2018-11-25 23:02:10 +01:00
Philipp Hörist
5fa56684c7 Adapt to nbxmpp API changes 2018-11-25 20:02:20 +01:00
Philipp Hörist
cb05671254 Dont fail when importing plugin_i18n for tests 2018-11-21 21:44:19 +01:00
Philipp Hörist
1196e1df0d Unittest: Add more caps hash examples 2018-11-21 20:02:44 +01:00
Philipp Hörist
35b5a4d7a9 Satisfy pylint/mypy 2018-11-20 23:06:27 +01:00
Philipp Hörist
6327679461 Refactor set_unset_urgency_hint() 2018-11-20 22:59:02 +01:00
Philipp Hörist
c97fddf0f8 Move PrivateChatControl into own module 2018-11-20 22:41:43 +01:00
Philipp Hörist
fa0f35da01 Fix opening links in MUC subject
The default GTK link handler does not work on Windows and Mac

Fixes #9453
2018-11-20 18:44:58 +01:00
Philipp Hörist
c8b5eb94a9 Remove unused imports 2018-11-20 16:16:30 +01:00
Philipp Hörist
8f9c596a0c Windows: Remove cryptography fix
The package has been fixed in the mingw repos
2018-11-20 16:10:11 +01:00
Philipp Hörist
15c3de2b4d Add option to show chatstate in roster
- Preferences: Add options for display in banner, tab, roster
- This makes the chatstate Plugin obsolete
2018-11-20 15:32:01 +01:00
Philipp Hörist
b74468b9c3 Move chatstate css to default theme
This is needed so we can query the current chatstate colors in cellrenderers
2018-11-20 15:32:01 +01:00
Philipp Hörist
c61bd65607 Simplify PEP module inits 2018-11-20 15:32:01 +01:00
Marcin Mielniczuk
9d8b56bc0f Refactor groupchat nick auto completion 2018-11-20 10:37:12 +01:00
Philipp Hörist
a00e8e3abb Dont use deprecated GLib.glib_version 2018-11-20 00:04:41 +01:00
Philipp Hörist
e305069798 Fix receipts for MUC-PMs 2018-11-19 19:33:28 +01:00
Philipp Hörist
b5bd5f15f0 Dont check mam:2 compliance for error messages 2018-11-19 18:04:32 +01:00
Philipp Hörist
1504805575 Dont answer groupchat receipt requests 2018-11-19 17:51:18 +01:00
Philipp Hörist
596f268f14 Fix missing default arg 2018-11-19 15:04:04 +01:00
Philipp Hörist
b98f0a3f76 Remove all usage of get_gtk_builder() 2018-11-18 22:24:34 +01:00
Philipp Hörist
3c32d51174 Fix deprecated init 2018-11-18 22:24:33 +01:00
Philipp Hörist
dffa54f7d3 Refactor Windows Notifications
- Only show one notification at a time
- Fix pylint errors
2018-11-18 22:24:33 +01:00
Philipp Hörist
fedc00eb83 Move notify to gtk folder
- Rename notify to notification
- Move get_show_in_roster() to gtk.util
- Move get_show_in_systray() to gtk.util
2018-11-18 22:24:33 +01:00
Philipp Hörist
2ece342de2 Notification: Use load_icon() 2018-11-18 22:24:33 +01:00
Philipp Hörist
1179333fa0 Refactor loading user supplied iconsets 2018-11-18 22:24:33 +01:00
Philipp Hörist
aca34d5c35 Remove old icons 2018-11-18 22:24:33 +01:00
Philipp Hörist
3ba34fa396 Remove old iconset code 2018-11-18 22:24:32 +01:00
Philipp Hörist
619793a085 Groupchat: Use icons from IconTheme 2018-11-18 22:24:32 +01:00
Philipp Hörist
acc89ad622 Roster: Use icons from IconTheme for Roster
With this Gajim loses the ability to draw animated GIFs in the Roster

GIFs have numerous drawbacks:

- We cant add them to the IconTheme, which means we need a different interface to load them
- The IconTheme scales all icons we load for the current scale (HiDPI)
- The animation causes many updates to the Roster, and causes high cpu usage

Fixes #8814, #8655
2018-11-18 22:24:10 +01:00
Philipp Hörist
8be5562b92 Dont fail when IconTheme is not available
This is needed for tests to work
2018-11-18 12:52:24 +01:00
Philipp Hörist
d13baed80f Improve Entity Time parsing
- Use parse_datetime()
- Improve tzo node validation
2018-11-18 10:35:13 +01:00
Philipp Hörist
f40f171ecd Refactor parse_datetime and add unit test 2018-11-18 10:35:13 +01:00
Philipp Hörist
b5b3820328 Remove unused methods 2018-11-18 10:35:13 +01:00
Philipp Hörist
431d8075a6 Use get_cursor from gtk.util 2018-11-18 10:35:13 +01:00
Philipp Hörist
cee63aa0d8 Move htmltextview into gtk module 2018-11-18 10:35:13 +01:00
André Apitzsch
a1b798b8fc Remove useless comment 2018-11-17 11:25:24 +01:00
André Apitzsch
dd0b7260b4 CI: Make test verbose 2018-11-17 11:25:24 +01:00
André Apitzsch
5c0ff1de9f Test: Fix KeyError
The added account causes an issue with test_gui_interface,
so the account needs to be removed again
2018-11-17 11:23:38 +01:00
Philipp Hörist
fb5cee69cb Dont use deprecated begins_tag() 2018-11-16 21:44:20 +01:00
Philipp Hörist
80954e9534 HtmlTextView: minor refactoring
- Move updating tags into HtmlTextView
- Rename some vars
- Remove legacy GTK code
2018-11-16 21:39:45 +01:00
Philipp Hörist
eedd0c2a72 HtmlTextView: Fix pylint errors and minor refactoring 2018-11-16 21:39:19 +01:00
Philipp Hörist
97310a059a HtmlTextView: Remove some unnecessary methods 2018-11-16 21:36:04 +01:00
Philipp Hörist
63ff9478bd XHTML: Fix parsing font-size
Remove checking for font_scale, Gtk.TextIter.get_attributes() seems buggy at
the moment, and we dont need to check the current scale to apply a new scale

Fixes #9067
2018-11-16 16:23:42 +01:00
Philipp Hörist
77d64267c7 Windows: Fix build
data is now a str
2018-11-16 15:26:38 +01:00
Philipp Hörist
7f1dfe5a8c New DataFormWidget: Add Captcha support 2018-11-15 21:02:09 +01:00
Bronko
4be4998704 fix typos in config.py 2018-11-14 22:44:41 +01:00
Philipp Hörist
9e24c72ba5 Fix incorrect contact status on tabs 2018-11-13 23:47:54 +01:00
Philipp Hörist
8f6dfad44e Windows: Get objdump output as string
Otherwise we have to guess the encoding of the host system
2018-11-13 20:59:55 +01:00
Philipp Hörist
9c5de3bf25 Correctly remove placeholder on focus in
This is a regression from e281fb68

Fixes #9440
2018-11-12 17:47:04 +01:00
Philipp Hörist
f26db88424 Refactor htmltextview test 2018-11-11 22:54:43 +01:00
Andrey Gursky
e281fb6839 Fix clipboard paste in inactive window
Fixes #9427
2018-11-11 17:20:36 +01:00
André Apitzsch
989926a680 Restructure test 2018-11-11 16:50:59 +01:00
André Apitzsch
522eec007d Test: caps cache: use mock from unittest 2018-11-11 16:50:59 +01:00
André Apitzsch
49758ab30e Test: remove unused imports 2018-11-11 16:50:59 +01:00
Philipp Hörist
5ecdfbee5c Windows: Remove old ssl fix 2018-11-11 16:40:08 +01:00
Philipp Hörist
ac5bfe2d7c Windows: Fix build
Fixes #9438
2018-11-11 15:37:30 +01:00
Philipp Hörist
e509a68139 Determine absolut path for custom config folder
When a relative custom config path is passed via commandline, the logic
which decides if a plugin can be deleted from the plugin manager fails
2018-11-11 15:15:10 +01:00
Philipp Hörist
62b210a9e5 Pass account to plugins when encrypting a file 2018-11-11 10:40:48 +01:00
Philipp Hörist
30a20e16d2 Enforce min and max version for plugin manifest
This reduces problems with old plugins without max version
2018-11-11 10:21:46 +01:00
Philipp Hörist
e4a9ffe1ca Dont test for sys.platform == 'linux'
This excludes other unix systems which was not intended
2018-11-10 19:30:19 +01:00
Philipp Hörist
02a9615b94 Dont test if precis_i18n is available
Its listed as dependency
2018-11-10 19:30:19 +01:00
Philipp Hörist
a7cc815ca4 Move imports into function 2018-11-10 19:30:18 +01:00
Philipp Hörist
5152611ad7 Try to play sound on all unix systems
sys.platform == 'linux' excludeds other unix systems, for example FreeBSD
2018-11-10 19:30:18 +01:00
Philipp Hörist
0d70352460 Dont test if winsound is available
Its a standard library which will be always available in our builds
2018-11-10 19:30:13 +01:00
Philipp Hörist
1f31ab04f2 Remove unused code
Code is also not cross-platform compatible
2018-11-10 19:30:13 +01:00
Philipp Hörist
8d95eb9b99 Better determine soundplayer on unix systems
- sys.platform == 'linux', excludes many other unix systems
- use shutil.which() to test if a command is available
2018-11-10 19:30:12 +01:00
André Apitzsch
ac2a75db48 Flatpak: use X11 access only if a X11 session is running
Requires flatpak 1.0 or newer
2018-11-09 23:21:57 +01:00
André Apitzsch
09cded2ff3 Flatpak: update dependencies and use pip to install modules 2018-11-09 23:16:31 +01:00
Philipp Hörist
62cfd7293a Remove unused import 2018-11-07 23:49:29 +01:00
Philipp Hörist
4534f3dbac Do not use own window for RosterTooltip 2018-11-07 23:44:16 +01:00
Daniel Brötzmann
13c82ae777 Update look on GCTooltip and RosterTooltip 2018-11-07 23:07:26 +01:00
Daniel Brötzmann
bd7e32187d Update History Manager GUI 2018-11-07 22:52:23 +01:00
André Apitzsch
fd97d64205 Test: Remove unused xmpp_mocks 2018-11-07 22:36:54 +01:00
Daniel Brötzmann
02f16d53f4 Remove None from list, rename None to No Proxy in combobox 2018-11-07 21:22:25 +01:00
Daniel Brötzmann
56f948f56b Remove unnecessary .destroy 2018-11-07 17:07:24 +01:00
Daniel Brötzmann
43f07c19e5 Merge destroy handlers, connect ESC key, remove transient 2018-11-07 17:07:24 +01:00
Daniel Brötzmann
d106c0d316 ManageProxies GUI update 2018-11-07 17:07:24 +01:00
Philipp Hörist
ea2f76f24e Show correct icon in roster tooltip 2018-11-06 21:31:43 +01:00
Philipp Hörist
f5a19c24a9 Cast messages from a bare muc jid to groupchat 2018-11-05 21:08:34 +01:00
Emmanuel Gil Peyrot
b4d34bf7f6 Move XEP-0231 into its own module 2018-11-05 19:58:49 +01:00
André
2ec1baa7bd Roster: Improve contact filter look 2018-11-04 22:59:56 +01:00
Philipp Hörist
b6c4fcfb54 Use always an action to open the history window
- Make all menus and shortcuts use the 'app.browse-history' action
- HistoryWindow: Inherit from Gtk.ApplicationWindow
2018-11-04 22:50:21 +01:00
Philipp Hörist
3e387f5215 GroupchatConfig: Valid form before sending 2018-11-04 17:45:27 +01:00
Philipp Hörist
4753e6015e ServiceRegistration: Validate form before sending 2018-11-04 01:01:39 +01:00
Philipp Hörist
6b65a23371 DataForms: Make validation possible
- Show orange warning icon if a field is required
- Show red error icon if validation of the field failed
- Set validation error text as tooltip of the icon
- DataFormWidget emits a signal 'is-valid' on every change
2018-11-04 00:58:34 +01:00
Philipp Hörist
44d56ac2fa Tests: Add a DataFormWidget test window 2018-11-03 23:09:12 +01:00
André Apitzsch
09f0835fbd Fix some PyGObject deprecation warnings
like
The "flags" argument for dialog construction is deprecated. Please use initializer keywords: modal=True and/or destroy_with_parent=True.
or
Using positional arguments with the GObject constructor has been deprecated. Please specify keyword(s) for "title, transient_for, flags" or use a class specific constructor.

See: https://wiki.gnome.org/PyGObject/InitializerDeprecations
2018-11-03 13:58:11 +01:00
André Apitzsch
4e0295fcd9 gui_menu_builder: remove unused variable 2018-11-03 13:47:03 +01:00
Philipp Hörist
6e41699297 GroupchatConfig: Tidy up some rough edges 2018-11-03 13:44:50 +01:00
Philipp Hörist
5d5d686408 DataFormWidget: Color required fields red 2018-11-03 13:44:36 +01:00
André Apitzsch
21656ebfe8 Move flake8 config to setup.cfg 2018-11-03 12:02:45 +01:00
Philipp Hörist
bf9e01ee31 Fix displaying PEP icons
- Rename get_pep_as_pixbuf to get_pep_icon
2018-11-02 22:51:57 +01:00
Philipp Hörist
61a791d67c Rewrite GroupchatConfig dialog
- Complete rewrite of the dialog
- Use new DataFormWidget
2018-11-02 22:24:28 +01:00
Philipp Hörist
e615a8e2e3 Add possibility to get windows by jid
This also makes it possible to get windows by an account/jid combination
2018-11-02 22:21:15 +01:00
Philipp Hörist
0662374c14 Set active window as transient for dialogs 2018-11-02 22:17:08 +01:00
Philipp Hörist
32e736aa32 Remove unused shortcut 2018-11-02 21:01:26 +01:00
Daniel Brötzmann
7cae880920 ManageSounds GUI Update 2018-11-02 17:09:28 +01:00
Philipp Hörist
55eef51887 Update win/README.md 2018-11-01 14:57:30 +01:00
Philipp Hörist
110da0172f Remove all non-ascii chars from setup.cfg
https://github.com/pypa/setuptools/issues/1062
2018-11-01 08:40:57 +01:00
Philipp Hörist
7d5f1fba50 Windows: Fix dev_env.sh 2018-11-01 08:28:20 +01:00
Philipp Hörist
1aba2b2d76 Windows: Update dev_env.sh 2018-11-01 08:23:04 +01:00
Philipp Hörist
c2521a41d6 Add margin to DataFormWidget 2018-11-01 08:23:04 +01:00
Philipp Hörist
f46fdee464 Make DataFormWidget configurable
- A option dict can be passed which controls how the DataForfWidget looks
- Analyse the field label lengths and adjust the label justification (left/right)
2018-11-01 08:23:04 +01:00
Daniel Brötzmann
4736f518d6 Scroll history window to bottom when day changed or selected 2018-11-01 00:29:40 +01:00
André Apitzsch
3eeed7d2b4 Setup: move configuration to setup.cfg to improve readability 2018-10-31 22:47:33 +01:00
Philipp Hörist
985fced940 Roster: Use icon names instead of pixbufs
- Use icon names for Tune and Location notifications
- Use None instead of an empty pixbuf when there is no data
2018-10-29 00:12:48 +01:00
Philipp Hörist
7a070a583e Use get_image_button() from gtk.util 2018-10-29 00:12:48 +01:00
Philipp Hörist
3ae03a24b1 Remove unused method 2018-10-29 00:12:44 +01:00
Philipp Hörist
a6d9b2c193 Set the Window icon correctly
Set the default list after the first window has been initialized. Only
set icons on Windows that are different from the default.
2018-10-28 23:01:09 +01:00
Philipp Hörist
e958755a24 HistoryManager: Refactor code
- Use get_builder
- Add get_app_icon_list() to gtk.util
2018-10-28 22:42:02 +01:00
Philipp Hörist
0e3b74da16 Fix pylint errors 2018-10-28 22:04:29 +01:00
Philipp Hörist
ac3bc74952 Remove unused methods 2018-10-28 21:58:30 +01:00
Philipp Hörist
5769ca1e29 Remove dead servers from servers list
All removed servers did not answer to a IBR request
2018-10-28 21:45:04 +01:00
Philipp Hörist
2a0d6dc1ad Use json format for the servers list 2018-10-28 21:26:25 +01:00
Philipp Hörist
69309d283d AccountWizard: Use icon name instead of filename 2018-10-28 20:58:32 +01:00
Philipp Hörist
95e67ab7c1 AdHocCommands: move to gtk module 2018-10-28 20:43:36 +01:00
Philipp Hörist
cdeb902fda FiletransferWindow: Move to gtk module 2018-10-28 20:20:49 +01:00
Philipp Hörist
9ae63b6f70 FiletransferWindow: Use icon name instead of pixbufs 2018-10-28 20:18:33 +01:00
Philipp Hörist
dcfaba09b9 PluginsWindow: Refactor code
- Use get_builder
- Sort imports
- Use load_icon instead of get_icon_pixmap
2018-10-28 20:17:59 +01:00
Philipp Hörist
f4a7e2a353 Move AtomWindow to gtk folder 2018-10-28 19:45:10 +01:00
Philipp Hörist
59ccac4831 Move ServiceDiscoveryWindow to gtk folder 2018-10-28 19:41:19 +01:00
Philipp Hörist
cb58fc86f0 Move GroupsPostWindow into disco module 2018-10-28 19:38:35 +01:00
Philipp Hörist
efbd22723c DiscoveryWindow: Use icon name instead of pixbufs 2018-10-28 19:34:46 +01:00
Philipp Hörist
88f30f92f7 Move SearchWindow to gtk folder 2018-10-28 17:29:12 +01:00
Philipp Hörist
39dfe41af5 Remove print statement 2018-10-28 17:15:38 +01:00
Philipp Hörist
b5441b6169 Move ManageSounds into own module 2018-10-28 17:15:34 +01:00
Philipp Hörist
9af4b4f016 Move GroupchatConfig into own module 2018-10-28 15:36:43 +01:00
Philipp Hörist
4e2f00e569 Move ManageProxies into own module 2018-10-28 15:36:11 +01:00
Philipp Hörist
c109db6eeb Switch some calls to gtk.util helper methods 2018-10-28 15:00:04 +01:00
Philipp Hörist
6b5d559d7a Fix error with some foreign keyboard layouts 2018-10-28 14:37:19 +01:00
Philipp Hörist
960008a69a Use get_icon_name() instead of get_iconset_name_for() 2018-10-28 14:32:54 +01:00
Philipp Hörist
9734e7bdea Preferences: Use icons from icontheme 2018-10-28 14:19:03 +01:00
Philipp Hörist
e86c619379 Rename and extend get_iconset_name_for() 2018-10-28 14:17:04 +01:00
Philipp Hörist
a4077502d5 Tooltips: Use icons from icontheme 2018-10-28 10:44:05 +01:00
Philipp Hörist
7faebf2be5 Tooltips: Refactor code
- Use get_builder
- Fix pylint errors
- Move fill_table_with_accounts() to StatusTable class
2018-10-28 10:20:59 +01:00
Philipp Hörist
5c97f0a91c Move tooltips module into gtk folder 2018-10-28 09:33:40 +01:00
André Apitzsch
a1701301f7 Flatpak: remove modules provided by the runtime 2018-10-28 01:34:11 +02:00
Daniel Brötzmann
a75c0cbd48 Remove obsolete glade file for features window 2018-10-27 18:04:27 +02:00
Daniel Brötzmann
bed18c9067 Add clipboard button to copy server infos 2018-10-27 15:35:37 +02:00
Daniel Brötzmann
5fb6032420 Update Features Dialog Design 2018-10-27 14:54:57 +02:00
Matthew W. S. Bell
2a62209e1e Obtain sleep inhibitor again after every sleep
- There is a PrepareForSleep signal before and after every sleep event.
The expectation is that before sleep, gajim cleans up and then releases
the sleep inhibitor. Accordingly, we must reacquire the inhibitor after
sleeping, which can helpfully be done with the other signal.

- Moved module to the dbus folder

- Embed logic in a LogindListener object so we can import the module
without listening to dbus
2018-10-26 12:57:13 +02:00
Philipp Hörist
54fe4dacf2 Fix import 2018-10-26 01:49:15 +02:00
Philipp Hörist
e5beff266a Guard GeoClue import
- So we dont have to check on module import if GeoClue is installed
2018-10-26 01:45:43 +02:00
Philipp Hörist
ef167349f8 Fix imports 2018-10-26 01:31:49 +02:00
Philipp Hörist
df7f0324a3 Move dbus modules into own folder
- light refactor of the screensaver module
2018-10-26 01:19:47 +02:00
Philipp Hörist
d98ba45f97 Dont use deprecated const 2018-10-26 00:47:36 +02:00
Daniel Brötzmann
5d2e83394b Rework Preferences Window 2018-10-26 00:18:06 +02:00
Daniel Brötzmann
b5416f0e97 Rework ACE 2018-10-26 00:06:27 +02:00
Philipp Hörist
08fe232695 Fix error when plugin cant be loaded
Fixes #9403
2018-10-25 21:20:38 +02:00
Daniel Brötzmann
3dcd6323d2 Update feature list in appdata.xml 2018-10-25 11:59:41 +02:00
Philipp Hörist
d7ea69f36c Refactor StatusIcon
- Move to gtk folder
- Rename some handlers
- Use get_builder
2018-10-25 00:12:28 +02:00
Philipp Hörist
c1cc8c5714 Fix pylint error 2018-10-25 00:06:45 +02:00
Philipp Hörist
c08f752d89 Refactor "Save as" menu 2018-10-24 23:42:07 +02:00
Philipp Hörist
2c6b2e0bb4 Use keyword init for Labels
keyword-less init is deprecated
2018-10-24 23:04:14 +02:00
Philipp Hörist
974b351338 Fix pylint error 2018-10-24 21:16:13 +02:00
Philipp Hörist
0e2a9c724f Improve ExceptionDialog
- Move to gtk module
- Use get_builder() so translation works
- Add GLib version
- Remove standalone testing code
2018-10-24 21:14:54 +02:00
Daniel Brötzmann
79a37f6992 Update ExceptionDialog GUI 2018-10-24 20:41:16 +02:00
Philipp Hörist
9184c66eae Fix Windows build
Appveyor adds ssl libs to the system folder which trips pythons ssl module

see https://github.com/appveyor/ci/issues/2571
2018-10-23 23:27:02 +02:00
Philipp Hörist
fe21ae6086 Windows: Add folder to DLL search
This makes python look into the `bin` folder when searching for DLLs before
it trys C:\Windows or C:\Windows\system32 and potentially finds other versions of DLLs

Fixes #8968
2018-10-23 22:58:49 +02:00
Philipp Hörist
9665376247 Update ChangeLog 2018-10-22 19:52:47 +02:00
Philipp Hörist
dc59801d93 Make var global 2018-10-22 19:04:37 +02:00
Yann Leboulanger
286f820f77 fix regression from [e265514d]: gupnp object is keept globally. Fixes #9398 2018-10-22 13:38:40 +02:00
Daniel Brötzmann
4f28720db0 Remove ESessions leftovers 2018-10-21 23:17:42 +02:00
Philipp Hörist
7397cc8af6 Remove idna as dependency
We use the python inbuilt idna module
2018-10-21 09:36:36 +02:00
André Apitzsch
af88c4cbc6 Flatpak: package new required dependency 2018-10-20 16:24:51 +02:00
Philipp Hörist
3a97d44e3e Fix flickering tooltips in 3.24.1 2018-10-20 09:55:48 +02:00
Philipp Hörist
c2d03dbf24 Prepare for nbxmpp API change 2018-10-19 23:35:57 +02:00
Philipp Hörist
0d4ba65434 Make idna and precis-18n required dependencys 2018-10-19 23:30:56 +02:00
Philipp Hörist
2c01883fc0 Fix missing declaration
Fixes #9322
2018-10-19 22:30:35 +02:00
Philipp Hörist
e44cedf094 Use parse_delay also for presences 2018-10-19 20:43:04 +02:00
Philipp Hörist
abf1909360 Remove support for XEP-0091 2018-10-19 20:38:44 +02:00
Philipp Hörist
53ec34a955 Use parse_datetime for parsing idle time
Fixes #9393
2018-10-19 20:37:18 +02:00
Philipp Hörist
dbd3165c00 DiscoveryWindow: Add default identity
Fixes #9386
2018-10-19 17:52:00 +02:00
Philipp Hörist
8487bdb83e Make bookmark parsing more resilient
Fixes #9385
2018-10-19 15:59:04 +02:00
Philipp Hörist
ba2618d035 Set password correctly on MUC join 2018-10-14 21:42:51 +02:00
Philipp Hörist
c34ce28f56 Add a dedicated folder for plugin data 2018-10-14 17:09:39 +02:00
Philipp Hörist
c58ea13379 Default to showing offline contacts
Many messengers dont show the status anymore, its not evident to new
users that most of their roster is hidden per default and they have to
show it to access the contacts
2018-10-13 16:21:44 +02:00
Philipp Hörist
7113760b03 Windows: Add precis-i18n to the build 2018-10-13 15:41:05 +02:00
Philipp Hörist
2b7006e883 Catch exceptions when loading plugins 2018-10-13 14:13:38 +02:00
Philipp Hörist
683e7aa4c7 Bind textomain also for plugins 2018-10-13 13:27:33 +02:00
Philipp Hörist
6c43c0f408 Allow to load multiple widgets with get_builder() 2018-10-13 00:33:33 +02:00
Philipp Hörist
c43714e4c2 Dont monkey patch _() into plugins
Plugins can import _() from plugins_i18n
2018-10-12 23:42:38 +02:00
Philipp Hörist
e5fe30cb5b Add get_builder() for plugins 2018-10-12 23:42:38 +02:00
Yann Leboulanger
00c8e5c01d Ability to update plugins on startup from a download folder 2018-10-12 22:17:34 +02:00
Philipp Hörist
ff0e02685a Windows: Add correct plugin_installer 2018-10-12 20:17:10 +02:00
Philipp Hörist
528f758287 Raise Gajim version 2018-10-12 17:38:32 +02:00
André Apitzsch
8a0ed4af5b Fix missing UI translations on flatpak 2018-10-11 23:21:46 +02:00
Philipp Hörist
f5337c6890 Raise nbxmpp version 2018-10-11 21:11:06 +02:00
Philipp Hörist
c81711fdf0 Reset chatstate correctly if contact goes offline 2018-10-11 00:11:03 +02:00
Philipp Hörist
bae95858aa Dont overwrite user plugins with base plugins
- Dont load plugins without short_name
- Check with the short_name if a plugin is already loaded
2018-10-10 21:25:54 +02:00
Daniel Brötzmann
491237b41d polish-change-status-dialog 2018-10-09 20:11:01 +02:00
Philipp Hörist
f565928890 Fix a few things regarding chatstates
- Fix wrong chatstates issued because of textview changed signal
- Fix chatstates in PMs
2018-10-09 00:01:35 +02:00
Philipp Hörist
7e007a4210 Add property to distinguish pm contacts 2018-10-07 22:35:27 +02:00
Philipp Hörist
84276aed43 Raise min nbxmpp version 2018-10-07 20:51:51 +02:00
Philipp Hörist
a60b54e46e GajimRemote: pass combined chatstate 2018-10-07 20:48:24 +02:00
André Apitzsch
0c0d852afe Flatpak: Update dependencies
and switch to yaml format to improve readability
2018-10-07 19:26:50 +02:00
Philipp Hörist
084e5d6ca7 Better fix for aa50da05 2018-10-07 18:19:57 +02:00
Philipp Hörist
99972dacf7 GajimRemote: Fix chatstate-received callback 2018-10-07 13:49:55 +02:00
Philipp Hörist
aa50da05d3 Fix gettext not supporting Pathlib yet 2018-10-07 12:49:50 +02:00
Philipp Hörist
f10f7d27ad Bring back lost --version command 2018-10-07 02:05:35 +02:00
Philipp Hörist
cf7ba8d790 Update ChangeLog 2018-10-07 00:13:08 +02:00
Philipp Hörist
cea5231c79 Dont show joined message on status change 2018-10-06 23:08:53 +02:00
Philipp Hörist
a26c4f164d Update .pylintrc 2018-10-06 23:06:22 +02:00
Philipp Hörist
74bb8cec3f Fix pylint error 2018-10-06 23:06:07 +02:00
Philipp Hörist
ca46742117 Fix missing imports 2018-10-06 23:04:28 +02:00
Philipp Hörist
ad4e1258d3 Improve finding locale dir
- Dont install _() globally, although its elegant mypy cant deal with it
- If gettext cant find the translation itself, iter through all dirs and search for it
2018-10-06 22:44:26 +02:00
Philipp Hörist
bf87ad5ac8 Import _() instead of using builtin namespace
- Prepare for removing the global installed _() method in builtins
- Sort some imports along the way
2018-10-06 22:38:55 +02:00
Philipp Hörist
990a35f9d8 MUC: Add option for showing the subject on join 2018-10-06 00:35:24 +02:00
Philipp Hörist
fd232ce616 MUC: Show info message that we joined the room 2018-10-06 00:01:07 +02:00
Philipp Hörist
259f5e3674 MUC: Show timestamp also for info messages 2018-10-05 23:57:54 +02:00
Philipp Hörist
dbd25c590d Fix textview sorting 2018-10-05 23:47:59 +02:00
Philipp Hörist
1e933c2681 Dont show MUC subject on rejoin
- We only show it, if it changed
2018-10-05 23:21:50 +02:00
Philipp Hörist
e8c5ad64a7 Better determine when we fully joined a muc 2018-10-05 22:42:36 +02:00
Philipp Hörist
b049746418 MUC: Make print_status affect the 333 status code 2018-10-05 22:34:06 +02:00
Philipp Hörist
4f1a3a32c5 Fix resume after sm timeout
Fixes #9364
2018-10-05 21:25:15 +02:00
Philipp Hörist
84ba852a97 Dont return None on has_mam()
Fixes #9368
2018-10-05 15:05:06 +02:00
Philipp Hörist
34553b6ca7 Add a configurable threshold for MAM in MUC 2018-10-04 21:42:06 +02:00
Philipp Hörist
5173ca415a Pull correct security catalog for private messages 2018-10-04 14:27:45 +02:00
Philipp Hörist
e664185845 Add debug commandline options
To easier simulate connectivity loss
2018-10-03 12:28:11 +02:00
Philipp Hörist
8b7aae564b MUC: Set active chatstate on messages 2018-10-03 09:56:56 +02:00
Philipp Hörist
b6c43c9066 Fix the fix 2018-10-03 08:08:32 +02:00
Marcin Mielniczuk
237abf742b Pylint CI improvements
* Move the pylint CI configuration to a separate script
* Update pylint in CI to 2.1.1
* Add pycurl to pylint whitelist
2018-10-03 07:58:54 +02:00
Philipp Hörist
ef3cc504d2 Pass correct show state 2018-10-03 07:53:30 +02:00
Philipp Hörist
ff424b5084 Fix passing wrong type 2018-10-01 21:25:10 +02:00
Philipp Hörist
4858bb46f2 Fix wrong argument 2018-10-01 07:50:48 +02:00
Philipp Hörist
460d390795 Refactor Chat State Notifications
- Move code into chatstate module
- Refactor most of the code, make it much simpler
2018-09-30 22:58:38 +02:00
Daniel Brötzmann
07b175d541 Add desktop actions start-chat and show-next-pending-event 2018-09-30 15:35:18 +02:00
Philipp Hörist
5be73fa824 Fix typo 2018-09-30 15:34:59 +02:00
Daniel Brötzmann
1f3bb5667d Fix more strings from #7470 2018-09-30 10:37:16 +02:00
Daniel Brötzmann
ef4c63ba3e Fix #9045, desync'ed 2018-09-30 10:37:16 +02:00
Daniel Brötzmann
6975ffdf94 Unify Emoticon and Emoji strings 2018-09-30 10:37:16 +02:00
Philipp Hörist
acf79ffe8a MAM: Up the requested page size 2018-09-30 10:01:42 +02:00
Philipp Hörist
bdd243d045 Remove unused import 2018-09-30 00:22:22 +02:00
Philipp Hörist
a8c0567bd0 Request security catalog from the barejid
- Some Code/UI cleanup
2018-09-30 00:15:00 +02:00
Philipp Hörist
24e771266b Fix Windows build 2018-09-29 21:55:29 +02:00
Philipp Hörist
8ff3e55f33 Fix security labels 2018-09-29 18:29:59 +02:00
Philipp Hörist
cc891be187 Fix mnemonics and change some strings 2018-09-27 22:04:15 +02:00
Philipp Hörist
58796d223e Preferences: Update layout and some options
- Add a 'convert ascii emoji' checkbutton
- Remove 'Disabled' from Emoji theme
- Change the layout of the style tab
2018-09-27 21:38:23 +02:00
Marcin Mielniczuk
34e93bba17 Add .vscode to .gitignore
This is where the workspace settings are stored.
2018-09-27 14:53:23 +02:00
Philipp Hörist
e9e0b7fbb9 Move AccountsWindow to gtk module 2018-09-27 00:12:55 +02:00
Philipp Hörist
6bf94f15d7 Move AdvancedConfig to gtk module 2018-09-27 00:03:50 +02:00
Philipp Hörist
075069d37a Fix Dark Theme switch
- Move css_config to gtk module
- Add Combobox for overriding the current session setting
- Move theme methods to css_config
2018-09-26 20:17:13 +02:00
Philipp Hörist
f89347516f Only use absolute imports from gtk module
- This reduces import cycles
2018-09-26 19:06:47 +02:00
Philipp Hörist
b2a7c9495d GroupchatControl: Add a is_connected property 2018-09-25 00:29:05 +02:00
Philipp Hörist
429a176712 Check if path is None 2018-09-25 00:29:05 +02:00
Yann Leboulanger
8e0a60911a fix displaying HTML content. Fixes #9210 2018-09-24 09:37:06 +02:00
Yann Leboulanger
5aa41c7f63 handle error message from MUC correctly. Fixes #9280 2018-09-23 22:45:05 +02:00
Philipp Hörist
7cacb4c09e Add annotations 2018-09-23 15:33:31 +02:00
Philipp Hörist
0e0bb9e190 Add dark theme switch in preferences 2018-09-23 15:00:32 +02:00
Philipp Hörist
26b8125446 configpaths: Add get_plugin_dirs() method
This helps with mypy because otherwise get() has multiple return types

This reduces our usage of cast()
2018-09-23 14:41:44 +02:00
Philipp Hörist
39f5803651 Windows: Add debug logging switch in preferences
If debug logging is enabled verbose output is redirected to a file
in the user dir
2018-09-23 14:41:26 +02:00
Philipp Hörist
d29f6b2ca9 Dont parse our own nick on sent carbons
Fixes #9051
2018-09-22 15:35:45 +02:00
Philipp Hörist
06302cdc4d Refactor link context menu
- Move hyperlink handling into HtmlTextView
- Use actions on the menuitems
2018-09-22 13:35:07 +02:00
Philipp Hörist
4077e0d6d6 Update mypy.ini 2018-09-22 13:20:09 +02:00
Philipp Hörist
1483020cf4 Dont show encryption status for status messages
Fixes #9353
2018-09-22 08:07:46 +02:00
Philipp Hörist
011d14e44b Add python3-cairo to CI 2018-09-22 00:05:27 +02:00
Philipp Hörist
0f730d1958 Update CI
- Run mypy on the full gajim folder
2018-09-21 23:56:56 +02:00
Philipp Hörist
6b2aa24d6e Fix rest of mypy errors
- This allows us to run mypy on the full gajim folder
2018-09-21 23:55:57 +02:00
Philipp Hörist
d722a8558b Fix pylint errors in ipython_view 2018-09-21 23:53:50 +02:00
Philipp Hörist
b70549dd59 Add __init__.py to gajim/dev 2018-09-21 23:53:16 +02:00
Philipp Hörist
74b66837fa Add annotations
- Remove some unused vars from app
2018-09-21 15:46:52 +02:00
Philipp Hörist
f7a2ac9d90 Add annotations
- Add a gtk/types modules
- Add a gtk/const module to prevent circular imports
2018-09-21 15:46:52 +02:00
Philipp Hörist
4d4d002342 Extend stubs for emoji_data 2018-09-21 15:46:52 +02:00
Philipp Hörist
3f2f51c169 Add license header to emoji_data.py 2018-09-21 15:46:52 +02:00
Philipp Hörist
5a906c1454 Move HtmlTextView test into test folder 2018-09-21 15:46:52 +02:00
André Apitzsch
efca9cd9c7 Remove epydoc.conf
it doesn't work with Python 3 and epydoc is no longer under development
2018-09-20 00:16:55 +02:00
Philipp Hörist
0a66b6d9ad remove icon 2018-09-19 22:22:52 +02:00
Philipp Hörist
94b17b1fbc Fix colors and icons 2018-09-19 22:22:52 +02:00
Philipp Hörist
fa65653adc ConvTextview: Rework display of encryption 2018-09-19 22:22:52 +02:00
Philipp Hörist
cb692ae4eb Make SQL INSERT querys more resilient
Specify the column in which we insert otherwise downgrading Gajim is
not possible anymore because the query breaks if we modified the column
count in future
2018-09-19 20:12:24 +02:00
André Apitzsch
c7c74998f2 Remote control: Better handle unknown types
there is no corresponding GLib.Variant for None,
use conversion to string as workaround
2018-09-18 22:23:58 +02:00
Philipp Hörist
46ed4757fd Update pre-push-tests.sh 2018-09-18 19:03:14 +02:00
Philipp Hörist
5b23d4879a Fix undefined-loop-variable pylint error 2018-09-18 19:02:48 +02:00
Philipp Hörist
7fcd85f026 Update pylint error list
- Check for W0631 undefined-loop-variable
- Check for W0640 cell-var-from-loop
- Check for W1401 anomalous-backslash-in-string
- Check for W1505 deprecated-method
2018-09-18 18:53:13 +02:00
Philipp Hörist
422cd12991 Fix pylint errors
- deprecated-method
- anomalous-backslash-in-string
- cell-var-from-loop
- undefined-loop-variable
2018-09-18 18:45:16 +02:00
Philipp Hörist
6c80473ebe pylint W0143 is not available on pylint < 2.0 2018-09-18 17:39:35 +02:00
Philipp Hörist
803ff3de45 Update pylint error list
- Check for W0109 duplicate-key
- Check for W0123 eval-used
- Check for W0143 comparison-with-callable
2018-09-18 17:21:53 +02:00
Philipp Hörist
385ef2e456 Fix pylint errors
- duplicate-key
- eval-used
- comparison-with-callable
2018-09-18 17:02:14 +02:00
Philipp Hörist
457faf3806 Update pylint error list
- Check for W0104 pointless-statement
- Check for W0105 pointless-string-statement
- Check for W0108 unnecessary-lambda
2018-09-18 16:46:20 +02:00
Philipp Hörist
81387ada51 Fix pylint errors
- pointless-statement
- pointless-string-statement
- unnecessary-lambda
2018-09-18 16:44:23 +02:00
Philipp Hörist
c2828231bd Update pylint error list
- Check for E0601 used-before-assignment
- Check for E0704 misplaced-bare-raise
- Check for W0101 unreachable
2018-09-18 16:32:31 +02:00
Philipp Hörist
c3e897bdb4 Fix pylint errors
- used-before-assignment
- misplaced-bare-raise
2018-09-18 16:29:26 +02:00
Philipp Hörist
6b54863157 Dont move window between virtual desktops
Its the job of the window manager to restore a window to the correct
location
2018-09-18 16:28:33 +02:00
Philipp Hörist
31a500245f Fix unneeded-not pylint errors 2018-09-18 16:03:35 +02:00
Philipp Hörist
8fad65ccbf Update pylint error list
- Check for C0113 unneeded-not
- Check for C0123 unidiomatic-typecheck
- Check for C0203 bad-mcs-method-argument
- Check for C0200 consider-using-enumerate
- Check for C0305 trailing-newlines
- Check for E0213 no-self-argument
2018-09-18 15:57:34 +02:00
Philipp Hörist
13a88533da Fix pylint errors
- bad-mcs-method-argument
- trailing-newlines
- no-self-argument
2018-09-18 15:45:39 +02:00
Philipp Hörist
1680c3bb38 Fix pylint errors
- consider-using-enumerate
- unneeded-not
- unidiomatic-typecheck
2018-09-18 15:24:40 +02:00
Philipp Hörist
251dbae5d6 Update pylint error list
Specify from now on the errors that are disabled instead of enabled,
because we have now more checks enabled than disabled
2018-09-18 14:46:35 +02:00
Philipp Hörist
2512c2b484 Update pylint error list
- Check for R1714 consider-using-in
- Check for W0107 unnecessary-pass
- Check for W0235 useless-super-delegation
2018-09-18 14:14:26 +02:00
Philipp Hörist
55aab55b9b Fix consider-using-in pylint errors 2018-09-18 14:10:38 +02:00
Philipp Hörist
a77804f475 Fix useless-super-delegation pylint errors 2018-09-18 14:06:16 +02:00
Philipp Hörist
8483ba503f Fix unnecessary-pass pylint errors 2018-09-18 14:03:58 +02:00
Philipp Hörist
376fff7871 Update pylint error list
- Check for W0622 redefined-builtin
- Check for C0303 trailing-whitespace
- Check for C0326 bad-whitespace
2018-09-18 14:00:50 +02:00
Philipp Hörist
df88cc5e15 Fix redefined-builtin pylint errors 2018-09-18 13:54:25 +02:00
Philipp Hörist
29647ea693 Fix trailing-whitespace pylint errors 2018-09-18 13:38:22 +02:00
Philipp Hörist
ccc06a04ab Fix bad-whitespace pylint errors 2018-09-18 12:06:01 +02:00
Philipp Hörist
2acfcfd9f9 Update pylint error list
- Check for C0121 singleton-comparison
- Check for C0321 multiple-statements
2018-09-18 10:33:31 +02:00
Philipp Hörist
dea1464832 Fix multiple-statements pylint errors 2018-09-18 10:30:33 +02:00
Philipp Hörist
6237bfae41 Fix singleton-comparison pylint errors 2018-09-18 10:26:27 +02:00
Philipp Hörist
66c8c26bbc Update pylint error list
- Check for R1704 redefined-argument-from-local
- Check for R1705 no-else-return
2018-09-18 10:18:12 +02:00
Philipp Hörist
ff6ca57033 Fix no-else-return pylint errors 2018-09-18 10:16:54 +02:00
Philipp Hörist
d6f0242655 Fix redefined-argument-from-local pylint errors 2018-09-18 08:37:18 +02:00
Philipp Hörist
cbe335b291 keys() doesnt return list() in python3 2018-09-18 07:20:49 +02:00
Philipp Hörist
206b87d7b7 Update pylint error list
Check for R1707 trailing-comma-tuple
2018-09-17 23:42:23 +02:00
Philipp Hörist
04b70bf220 Fix trailing-comma-tuple pylint errors 2018-09-17 23:38:52 +02:00
Philipp Hörist
67bb5a57c3 Update pylint error list
- Check for R0123 literal-comparison
- Check for R1703 simplifiable-if-statement
2018-09-17 23:26:52 +02:00
Philipp Hörist
01694c6a06 Fix simplifiable-if-statement pylint errors 2018-09-17 23:25:55 +02:00
Philipp Hörist
158d013a86 Fix literal-comparison pylint errors 2018-09-17 23:03:45 +02:00
Philipp Hörist
76333ec73a Use keys() iteration if we modify the dict 2018-09-17 22:51:42 +02:00
Philipp Hörist
55febc4963 Update pylint error list
Check for C0201 consider-iterating-dictionary
2018-09-17 22:35:39 +02:00
Philipp Hörist
793184e7be Fix consider-iterating-dictionary pylint errors 2018-09-17 22:34:15 +02:00
Philipp Hörist
0b8b4f75c3 Fix pylint errors 2018-09-17 22:20:19 +02:00
Philipp Hörist
71feb0b2d2 Update pylint error list
Check for W0612 unused-variable
2018-09-17 21:16:24 +02:00
Philipp Hörist
e8ac644440 Fix unused-variable pylint errors 2018-09-17 21:16:19 +02:00
Philipp Hörist
c6e2335bf0 Update pylint error list
Check for W1202 logging-format-interpolation
2018-09-17 19:15:51 +02:00
Philipp Hörist
7bdad5f4e2 Update pylint error list
Check for W1201 logging-not-lazy
2018-09-17 18:57:52 +02:00
Philipp Hörist
d638087c26 Fix logging-not-lazy pylint errors 2018-09-17 18:57:00 +02:00
Philipp Hörist
9bab139bb5 Update pylint error list
Check for W0702 bare-except
2018-09-16 23:46:16 +02:00
Philipp Hörist
7bb6f8b22e Fix bare-except pylint errors 2018-09-16 23:45:01 +02:00
Philipp Hörist
b8bbcf2be0 Fix missing time attribute
This was removed by accident
2018-09-16 23:33:09 +02:00
Philipp Hörist
aaaa3bc9bd Update .pylintrc 2018-09-16 18:09:24 +02:00
Philipp Hörist
f6144bff30 Update pylint error list
Check for W0621 redefined-outer-name
2018-09-16 18:04:21 +02:00
Philipp Hörist
d53b95218a Fix redefined-outer-name pylint errors 2018-09-16 18:04:15 +02:00
Philipp Hörist
adc94bdcc6 Update pylint error list
Check for C0325 superfluous-parens
2018-09-16 14:44:09 +02:00
Philipp Hörist
c6547b6d30 Fix superfluous-parens pylint errors 2018-09-16 14:42:18 +02:00
Philipp Hörist
328d250f4c Fix evaluation for subject change 2018-09-16 14:36:54 +02:00
Philipp Hörist
b4ac6db9b9 Update pre-push-tests.sh 2018-09-16 14:19:48 +02:00
Philipp Hörist
d19ca8113a Add a pre-push script
Run this before every push to simulate the CI regarding mypy and pylint
2018-09-16 14:15:38 +02:00
Philipp Hörist
7018d5be0e Dont retract pep items on UserXEPs
This leads to multiple problems

1. We cant assume only items with id='current' are stored in the node
which would lead to retracting 'current' but another item would become
the last published and sent to users

2. Even if we have a SingletonNode retracting the only item means the Node
would be empty and offline clients would not receive the last published item
on coming online, because there is no item anymore

Instead we always publish an empty item from now on
2018-09-16 13:35:55 +02:00
Philipp Hörist
e85bc52c8b Fix sending empty pep data 2018-09-16 12:58:37 +02:00
Philipp Hörist
1462f89229 Update pylint error list
Check for R0205 useless-object-inheritance
2018-09-16 11:57:36 +02:00
Philipp Hörist
bb545d546a Fix useless-object-inheritance pylint errors 2018-09-16 11:56:56 +02:00
Philipp Hörist
9e51ed8c7f Update pylint error list
Check for W0611 unused-import
2018-09-16 11:38:50 +02:00
Philipp Hörist
de0c0a9c08 Fix unsued-import pylint errors 2018-09-16 11:37:38 +02:00
Philipp Hörist
50e44543f3 Fix len-as-condition pylint error 2018-09-16 01:19:09 +02:00
Philipp Hörist
8d9fe9e2e1 Update pylint error list
Check for C1801 len-as-condition
2018-09-16 01:12:10 +02:00
Philipp Hörist
49ca238252 Fix len-as-condition pylint errors 2018-09-16 01:10:04 +02:00
Philipp Hörist
f7a139eac2 Zeroconf: Store time of outgoing messages 2018-09-15 12:00:32 +02:00
Philipp Hörist
97ee8082fe HistoryManager: Load css config in standalone 2018-09-15 11:44:09 +02:00
Philipp Hörist
eca69e399b Fix Windows build
- Downgrade to glib2 2.56.2 because higher is broken on Windows 7
- Dont abort build if depchecker fails on some files
2018-09-15 02:01:40 +02:00
Philipp Hörist
3b5b4574ba Update .gitignore 2018-09-14 23:35:38 +02:00
Philipp Hörist
64840cd0b0 Update win/dev_env.sh 2018-09-14 23:17:16 +02:00
Philipp Hörist
d54d4bc232 Add annotations and fix pylint/mypy errors 2018-09-13 23:56:12 +02:00
Philipp Hörist
a62f348a21 Add stubs file for emoji_data
Otherwise mypy hangs because the file is to big
2018-09-13 23:54:29 +02:00
Philipp Hörist
58a3b83083 Update mypy.ini 2018-09-13 19:59:03 +02:00
Philipp Hörist
62c54525d8 fuzzyclock: Fix pylint errors 2018-09-13 00:33:54 +02:00
Philipp Hörist
64aec8adce Add annotations 2018-09-12 21:08:37 +02:00
Philipp Hörist
ee254d25d2 Fix pylint errors 2018-09-12 21:08:37 +02:00
Yann Leboulanger
6b221e7059 fix running pylint 2018-09-12 08:42:23 +02:00
Philipp Hörist
b99632ab03 Fix pylint errors 2018-09-12 00:01:54 +02:00
Philipp Hörist
691678b06a Update pylintrc 2018-09-11 23:49:59 +02:00
Philipp Hörist
c9455de4bd Add mypy test to CI 2018-09-11 22:46:57 +02:00
Philipp Hörist
09c5183575 Fix pylint errors in common/modules 2018-09-11 22:25:55 +02:00
Philipp Hörist
3080946ea1 Update pylintrc 2018-09-11 22:24:08 +02:00
Philipp Hörist
4ad38d5398 Make some vars private 2018-09-11 20:00:34 +02:00
Philipp Hörist
dad7def794 Catch error if no translation is found 2018-09-11 19:37:48 +02:00
Philipp Hörist
a34bf54c46 Fix mypy error regarding _() 2018-09-11 19:29:08 +02:00
Philipp Hörist
21672fadee Refactor i18n
- Make _() available, so other modules can import it from i18n, we need
this because mypy cant handle _() in the builtins namespace
2018-09-11 19:27:10 +02:00
Philipp Hörist
2649b3d01e Add annotations to modules/util.py 2018-09-11 00:47:59 +02:00
Philipp Hörist
ca9b4cb596 Add annotations for modules/__init__.py 2018-09-11 00:47:54 +02:00
Philipp Hörist
bcf2a3770d Remove unnecessary code
NetworkIncomingEvent defines base_network_events and generate() already
2018-09-11 00:37:00 +02:00
Philipp Hörist
7140c2d2a1 Add mypy.ini 2018-09-11 00:36:54 +02:00
Philipp Hörist
6ac31ba5b6 Update .gitignore 2018-09-11 00:03:12 +02:00
Philipp Hörist
0fba2b8a58 Add debug output for NetworkMonitor 2018-09-10 20:27:22 +02:00
Philipp Hörist
f82cd95f2c Fix subscribing to contact
Fixes #9321
2018-09-09 17:43:17 +02:00
Philipp Hörist
432704005d Request blocking list on connect 2018-09-09 16:50:55 +02:00
Philipp Hörist
a497051965 Add Builder class 2018-09-09 15:29:55 +02:00
Philipp Hörist
0a20cb5997 Fix fallback for bookmark name 2018-09-08 23:55:31 +02:00
Philipp Hörist
27dd36cca3 Improve speed of groupchat roster
- Save reference to contact in a dict instead of iterating the whole model
- Sort roster only once after all contacts have been added to the roster
- Speed up get_gc_contact()

Fixes #9334
2018-09-08 20:49:26 +02:00
Philipp Hörist
52e09cf526 Windows: Fix translation
Fixes #9324
2018-09-08 08:40:42 +02:00
Philipp Hörist
c8b31dffbb Remove verbose logging of idle time 2018-09-06 21:44:31 +02:00
Philipp Hörist
bba88cf609 Windows: Improve locked screen detection
UAC prompts count as locked screens, so only trigger extended away
when the screen is more than 10 seconds locked

Fixes #9117
2018-09-06 21:41:38 +02:00
Philipp Hörist
3a16ccb4d4 Revert "Windows: Remove locked screen detection"
This reverts commit 05307bd609
2018-09-06 21:38:41 +02:00
Philipp Hörist
05307bd609 Windows: Remove locked screen detection
This does not reliably tell us when the screen is locked.
For example this triggers when a UAC prompt is active.
From the Windows documentation there is no way to determine
if a workstation is locked

Fixes #9117
2018-09-06 21:17:05 +02:00
Philipp Hörist
a4a136566f Fix license comment format
every linter flags this as an error
2018-09-05 02:59:34 +02:00
Philipp Hörist
856a874dd5 Fix pyflakes/pycodestyle errors 2018-09-05 02:34:36 +02:00
pitchum
f91408fbaf Bugfix: list index out of range when opening service discovery
Fixes #9301
2018-09-05 02:29:04 +02:00
Philipp Hörist
9dd747dfe5 Windows: Fix IPV6 for Windows 10+
Fixes #9326
2018-09-05 02:14:51 +02:00
Philipp Hörist
a6631398f7 Fix pyflakes/pycodestyle errors 2018-09-05 00:33:08 +02:00
Philipp Hörist
27f7580688 Light refactring of bookmark code
- Convert xs:boolean values in bookmark module
- Use python booleans for minimize and autojoin in other parts of Gajim
- Use add_bookmark() instead of manipulating the bookmarks dict
2018-09-05 00:06:59 +02:00
Philipp Hörist
b62335eaf5 Add a bookmark sorting method 2018-09-04 23:22:57 +02:00
Philipp Hörist
a9a115d359 Fix highlight on messages without time 2018-09-02 23:31:42 +02:00
André Apitzsch
b8444fec64 music_track_listener: recognize playing song
when listener is enabled
2018-09-02 18:58:28 +02:00
André Apitzsch
b56f9c6fac music_track_listener: don't hard code media players
inspired by 0ba346b750/js/ui/mpris.js
2018-09-02 00:46:37 +02:00
Philipp Hörist
be6c2d4f7a Add XEP-0398 optimizations
- If the server implements XEP-0398 we dont need to add the avatar sha
anymore, the server adds it for us.
- It also means we dont have to query our own avatar from vcard at start
because the server tells us the avatar sha that is published with the inital
presence reflection
2018-09-01 20:40:20 +02:00
Philipp Hörist
c68f4f1041 Send all presence through the presence module 2018-09-01 18:06:21 +02:00
Philipp Hörist
7d723d7b98 Fix contact not beeing found after room destroy 2018-09-01 12:44:45 +02:00
Philipp Hörist
be96422a14 Disco the room after it has been created 2018-09-01 00:03:24 +02:00
Philipp Hörist
527762f726 Fix missing attribute 2018-08-31 06:37:53 +02:00
Sophie Herold
7743c11a50 Unify to use app.get_account_label() 2018-08-30 19:27:40 +02:00
Philipp Hörist
dd8dda9b32 Fix displaying MUC subjects with delay tag
Dont print it as "old" conversation, instead add the delay timestamp
at the end of the subject
2018-08-30 19:19:47 +02:00
Philipp Hörist
8a34261137 Parse delay after decryption
Delay could be encrypted with full stanza encryption
2018-08-30 19:19:47 +02:00
Yann Leboulanger
08d0cde95d improve string for translators 2018-08-30 14:57:33 +02:00
Yann Leboulanger
7d4a9b91c8 better fix for joining groupchats with uppercase letters. Fixes #9198 2018-08-30 12:21:43 +02:00
Philipp Hörist
931e3f60ba Register modules defined by plugins 2018-08-28 23:03:00 +02:00
Sophie Herold
3c492e92da Show avatar in new message notifications 2018-08-28 22:33:12 +02:00
Philipp Hörist
d57bfcbcad ServerInfo: Fix empty version result
Fixes #9311
2018-08-26 10:39:29 +02:00
Philipp Hörist
e665ee1fbe Fix MUC invite notification
Fixes #9309
2018-08-24 22:03:33 +02:00
Philipp Hörist
bf64d04046 Appveyor: add cssutils dependency 2018-08-23 19:48:36 +02:00
Philipp Hörist
a087486e45 Windows: Fix gstreamer/farstream plugin paths 2018-08-21 19:21:07 +02:00
Philipp Hörist
fb4c5a2351 Call link() on correct object 2018-08-21 18:48:20 +02:00
Philipp Hörist
fef8cff254 Display only emojis the font supports
Fixes #9299
2018-08-20 19:18:07 +02:00
Philipp Hörist
2a4e59654f HistoryManager: Convert RGB to hex 2018-08-19 23:48:44 +02:00
André Apitzsch
5d853e902a Time: use classes from standard library 2018-08-19 23:29:05 +02:00
Philipp Hörist
e128a3f676 Fix emoji theme fallback 2018-08-19 21:38:11 +02:00
Philipp Hörist
8ab607629b Update Gajim version to 1.0.99 2018-08-19 18:08:00 +02:00
Philipp Hörist
1c69b92d85 Move filechoosers into gtk module 2018-08-19 17:47:17 +02:00
Philipp Hörist
f3dd55de3e Add reason to MUC service-error kick 2018-08-19 17:02:10 +02:00
Philipp Hörist
9e3e6f80bb Add JID to VcardReceivedEvent 2018-08-19 16:43:59 +02:00
Philipp Hörist
854f8512a4 Remove not used liststore entrys 2018-08-19 13:51:06 +02:00
André Apitzsch
a592fe5b6a Flatpak: update nbxmpp 2018-08-19 13:28:54 +02:00
Philipp Hörist
732ed0a162 Fix theming option names 2018-08-19 12:15:07 +02:00
817 changed files with 29412 additions and 29540 deletions

View file

@ -1,5 +0,0 @@
[flake8]
ignore =
exclude = .git,__pycache__,.gitlab
max-complexity = 15
builtins=_

3
.gitignore vendored
View file

@ -7,6 +7,7 @@ syntax: glob
*.pyc
*.pyo
*~
*#
autom4te.cache
data/org.gajim.Gajim.appdata.xml
data/org.gajim.Gajim.desktop
@ -19,11 +20,13 @@ po/stamp-it
stamp-h1
Makefile
__pycache__/
.mypy_cache/
build/
dist/
gajim.egg-info/
src/gtk/
win/_build_root
.vscode
syntax: regexp
^config\.*

View file

@ -1,20 +1,30 @@
before_script:
- sudo apt-get update -qq && sudo apt-get install -y -qq libtool pkg-config python3-openssl gir1.2-gtk-3.0 python3-gi python3-nbxmpp-nightly pylint3
- sudo apt-get update -qq && sudo apt-get install -y -qq libtool pkg-config gir1.2-gtk-3.0 python3-gi python3-cairo
- sudo apt-get build-dep -y -qq gajim-default-nightly
stages:
- test
- build
run-test:
run-tests:
stage: test
script:
- python3 setup.py test_nogui
- rm -rf civenv-master
- virtualenv --system-site-packages civenv
- . ./civenv/bin/activate
- pip3 install mypy
- pip3 install git+https://dev.gajim.org/gajim/python-nbxmpp.git@master
- pip3 install pylint==2.3.1
- mypy gajim
- scripts/dev/pylint-ci.sh --jobs=2 gajim
- python3 setup.py test -s test.no_gui
- deactivate
- rm -rf civenv-master
run-pylint:
run-appdata:
stage: test
script:
- pylint3 --additional-builtins=_ --disable=all --enable=E0001,E0011,E0012,E0100,E0101,E0102,E0103,E0104,E0105,E0106,E0107,E0108,E0202,E0221,E0222,E0235,E0501,E0502,E0503,E0602,E0603,E0604,E0701,E0702,E1001,E1002,E1003,E1004,E1111,E1120,E1121,E1122,E1123,E1124,E1125,E1200,E1201,E1205,E1206,E1300,E1301,E1302,E1303,E1304,E1305,E1306,E1310,E1700,E1701,W0102 gajim
- appstream-util validate data/org.gajim.Gajim.appdata.xml.in
run-build:
stage: build
@ -44,4 +54,4 @@ run-build:
name: "gajim-default-$CI_COMMIT_REF_NAME-$CI_COMMIT_SHA"
expire_in: 1 week
paths:
- gajim-default-2???-??-??.tar.gz
- gajim-default-$CI_COMMIT_SHA.tar.gz

View file

@ -1,6 +1,11 @@
If you want to create a fork and use an external account (Github, Google) drop us a message at the Gajim support [group chat](xmpp:gajim@conference.gajim.org?join) so we can give you the necessary rights
- master - Development branch
- gajim_1.1 - Stable Gajim 1.1.x branch
- gajim_1.0 - Stable Gajim 1.0.x branch
- gajim_0.16 - Stable Gajim 0.16.x branch
If you are not familiar with Git please read the [HowTo](https://dev.gajim.org/gajim/gajim/wikis/howtogit)
If you are not familiar with Git please read the [HowTo](https://dev.gajim.org/gajim/gajim/wikis/development/howtogit)
A good article regarding [good commit messages](https://chris.beams.io/posts/git-commit/)

View file

@ -1,3 +1,44 @@
Gajim 1.1.0 (TBA)
New
* Remove support for XEP-0091
Bug fixes
* 9322 Error when adding contact
* 9385 Ignore invalid bookmarks
* 9386 Discovery: Browsing nodes without identity
* 9393 Error when parsing invalid timestamps
* 9398 Error on jingle file transfer
Gajim 1.0.99.1 (07 October 2018)
New
* Implement XEP-0398
* MUC: Set Threshold for requesting history
* Show icon for unencrypted messages
* Support more media players for broadcasting the current tune
* Windows: Add a debug logging switch in preferences
* Preferences: enable/disable dark theme
* Preferences: enable/disable the MUC subject beeing shown on join
* Preferences: enable/disable ascii emoji conversion
Bug fixes
* 9198 Creating new MUCs with captial letters is not possible
* 9210 Error when clicking on new message indicator
* 9280 Inviting users to a MUC causes error
* 9301 Error when opening service discovery window
* 9309 Error when clicking on a groupchat invite notification
* 9311 Error when requesting server info
* 9117 Windows UAC changes status not available
* 9324 No menus/dialogs on Win7
* 9326 IPV6 Connection problem on Win10
* 9334 Joining big MUCs takes very long
* 9339 Error caused by remote_control
Gajim 1.0.99 (19 August 2018)
New

View file

@ -7,17 +7,16 @@
- python3-gi
- python3-gi-cairo
- gir1.2-gtk-3.0 (>=3.22)
- python3-nbxmpp
- python3-openssl (>=0.14)
- python3-nbxmpp (>=0.9.90.4)
- python3-openssl (>=16.2)
- python3-cssutils (>=1.0.2)
- python3-keyring
- python3-precis-i18n
### Optional Runtime Requirements
- python3-pil (pillow) for support of webp avatars
- python3-gnupg to enable GPG encryption
- For zeroconf (bonjour) you need python3-dbus
- gir1.2-avahi-0.6 for zeroconf on Linux or [pybonjour](https://dev.gajim.org/lovetox/pybonjour-python3) on Windows/macOS
- gir1.2-gspell-1 and hunspell-LANG where lang is your locale eg. en, fr etc
- gir1.2-secret-1 for GNOME Keyring or KDE support as password storage
- D-Bus running to have gajim-remote working
@ -25,7 +24,6 @@
- gir1.2-gupnpigd-1.0 for better NAT traversing
- gir1.2-networkmanager-1.0 for network lose detection
- gir1.2-geoclue-2.0 for sharing your location
- python3-idna and python3-precis-i18n for correctly parsing JIDs
### Compile-time Requirements
@ -37,7 +35,7 @@
#### Packages
- [Arch](https://aur.archlinux.org/packages/gajim-git/)
- [Debian](https://packages.debian.org/source/experimental/gajim) (tested with Debian ``testing`` and ``unstable``)
- [Debian](https://packages.debian.org/stretch-backports/gajim)
#### Snapshots
@ -87,7 +85,7 @@ Execute gajim with --verbose
That is all, **enjoy**!
(C) 2003-2018
(C) 2003-2019
The Gajim Team
[https://gajim.org](https://gajim.org)

View file

@ -18,8 +18,9 @@ clone_depth: 1
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
build_script:
- C:\msys64\usr\bin\pacman -Syu --needed --noconfirm --ask=20
- C:\msys64\usr\bin\pacman -Su --needed --noconfirm
- del C:\Windows\System32\libssl-*.dll C:\Windows\system32\libcrypto-*.dll
- del C:\Windows\SysWOW64\libssl-*.dll C:\Windows\SysWOW64\libcrypto-*.dll
- C:\msys64\usr\bin\pacman -Syuu --needed --noconfirm --noprogressbar --overwrite \\*
- ps: |
$env:TIME_STRING=(get-date -UFormat "%Y-%m-%d").ToString()
$env:BUILDROOT="C:\msys64\home\appveyor\gajim\win\_build_root"

View file

@ -46,7 +46,7 @@ and
.Pa THANKS ,
for a complete list.
.Sh COPYRIGHT
Copyright (C) 2003-2018 Gajim Team
Copyright (C) 2003-2019 Gajim Team
.Pp
.Nm
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; version 3 only.

View file

@ -89,7 +89,7 @@ and
.Pa THANKS ,
for a complete list.
.Sh COPYRIGHT
Copyright (C) 2003-2018 Gajim Team
Copyright (C) 2003-2019 Gajim Team
.Pp
.Nm
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; version 3 only.

View file

@ -93,7 +93,7 @@ and
with contributions and patches merged from many individuals around the world.
See the About Dialog for a complete list.
.Sh COPYRIGHT
Copyright (C) 2003-2018 Gajim Team
Copyright (C) 2003-2019 Gajim Team
.Pp
.Nm
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; version 3 only.

View file

@ -7,32 +7,37 @@
<metadata_license>CC-BY-SA-3.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>Gajim</name>
<summary>A GTK+ Jabber client</summary>
<summary>A GTK+ XMPP client</summary>
<description>
<p>Gajim is a chat client to be used with Jabber.org, Live Journal Talk,
Nimbuzz, Ovi, Talkonaut, and thousands of other services
run by companies and ISPs, and volunteers around the world.
<p>Gajim aims to be an easy to use and fully-featured XMPP client.
With Gajim you can chat through various XMPP services of your choice
(e.g. Jabber.org) as well as transports (e.g. Facebook, IRC).
</p>
<p>If you have a few accounts on different servers, if you want to be in
contact with your friends and family all the time, then Gajim is for you.
<p>Just chat with your friends or family, easily share pictures and
thoughts or discuss the news with your groups.
</p>
<p>Gajim integrates well with your other devices: just chat and see what's
been said on your mobile device.
</p>
<p>Features:</p>
<ul>
<li>Tabbed chat window and single window modes</li>
<li>Group chat support (with Multi-User Chat protocol), invitation, chat to group chat transformation</li>
<li>Emoticons, avatars, PEP (user activity, mood and tune)</li>
<li>Audio / video conferences</li>
<li>File transfer, room bookmarks</li>
<li>Metacontacts support</li>
<li>Trayicon, speller, extended chat history functionalities</li>
<li>TLS, GPG and End-To-End encryption support</li>
<li>Transport registration support</li>
<li>Service discovery including nodes, user search</li>
<li>Wikipedia, dictionary and search engine lookup</li>
<li>Multiple accounts support</li>
<li>XML console interface</li>
<li>Link local (bonjour / zeroconf), BOSH</li>
<li>Other features via plugins </li>
<li>Never miss a message, keep all your chat clients synchronized</li>
<li>Invite friends to group chats or join one</li>
<li>Easily send pictures, videos or other files to friends and groups</li>
<li>Chat securely with End-to-End encryption via OMEMO or PGP</li>
<li>Use your favorite emoticons, set your own profile picture</li>
<li>Keep and manage all your chat history</li>
<li>Organize your chats with tabs</li>
<li>Automatic spell-checking for your messages</li>
<li>Connect to other Messengers via Transports (Facebook, IRC, ...)</li>
<li>Lookup things on Wikipedia, dictionaries or other search engines directly from the chat window</li>
<li>Set your activity, tune, and mood to show your friends how you are feeling</li>
<li>Support for multiple accounts</li>
<li>Group multiple contacts from one friend to a single Meta-Contact</li>
<li>XML console to see what's happening on the protocol layer</li>
<li>Serverless messaging (Bonjour/Zeroconf), BOSH</li>
<li>Support for service discovery including nodes and search for users</li>
<li>Even more features via plugins</li>
</ul>
</description>
<categories>
@ -43,7 +48,7 @@
</categories>
<screenshots>
<screenshot type="default">
<image>https://gajim.org/imgs/gajim_roster.png</image>
<image>https://gajim.org/imgs/gajim_single_window_mode.png</image>
<caption>Roster, list of contacts</caption>
</screenshot>
<screenshot>
@ -69,7 +74,7 @@
<url type="homepage">https://gajim.org/</url>
<url type="bugtracker">https://dev.gajim.org/gajim/gajim</url>
<url type="faq">https://dev.gajim.org/gajim/gajim/wikis/help/gajimfaq</url>
<url type="help">https://dev.gajim.org/gajim/gajim/wikis/help/home</url>
<url type="help">https://dev.gajim.org/gajim/gajim/wikis/help/Help</url>
<url type="donation">https://gajim.org/dev.php#donate</url>
<url type="translate">https://dev.gajim.org/gajim/gajim/wikis/development/DevTranslate</url>
<translation type="gettext">gajim</translation>

View file

@ -13,3 +13,14 @@ StartupWMClass=Gajim
Terminal=false
Type=Application
MimeType=x-scheme-handler/xmpp;
Actions=StartChat;ShowNextPendingEvent;
[Desktop Action StartChat]
Exec=gajim --start-chat
Name=Start a new chat
Icon=org.gajim.Gajim
[Desktop Action ShowNextPendingEvent]
Exec=gajim --show-next-pending-event
Name=Show next pending event
Icon=org.gajim.Gajim

View file

@ -1,29 +0,0 @@
[epydoc]
# Information about the project.
name: Gajim
url: http://gajim.org
verbosity: 3
imports: yes
redundant-details: yes
docformat: restructuredtext
# top: gajim
# The list of modules to document. Modules can be named using
# dotted names, module filenames, or package directory names.
# This option may be repeated.
modules: gajim/* test/*
# Write html output to the directory "apidocs"
#output: pdf
output: html
target: doc/apidocs/
# Include all automatically generated graphs. These graphs are
# generated using Graphviz dot.
graph: all
dotpath: /usr/bin/dot
graph-font: Sans
graph-font-size: 10

View file

@ -23,9 +23,9 @@ Replace install path `~/Gajim/gajim_flatpak` with an install path of your choice
*Note: Remove `--user` if you want a system-wide installation.*
1. `flatpak --user remote-add --from gnome https://sdk.gnome.org/gnome.flatpakrepo`
2. `flatpak --user install gnome org.gnome.Platform//3.28`
3. `flatpak --user install gnome org.gnome.Sdk//3.28`
4. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/org.gajim.Gajim.json`
2. `flatpak --user install gnome org.gnome.Platform//3.30`
3. `flatpak --user install gnome org.gnome.Sdk//3.30`
4. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/flatpak/org.gajim.Gajim.yaml`
5. `flatpak --user remote-add --no-gpg-verify gajim_flatpak_repo gajim_flatpak_repo`
6. `flatpak --user install gajim_flatpak_repo org.gajim.Gajim`
7. `flatpak run org.gajim.Gajim`
@ -51,7 +51,7 @@ In this example, we use `git` to update the repository. You can also download th
### Install and update Gajim
1. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/org.gajim.Gajim.json`
1. `flatpak-builder --repo=gajim_flatpak_repo ~/Gajim/gajim_flatpak ~/Gajim/flatpak/org.gajim.Gajim.yaml`
2. `flatpak --user update`
3. `flatpak run org.gajim.Gajim`

View file

@ -0,0 +1,199 @@
app-id: org.gajim.Gajim
runtime: org.gnome.Platform
runtime-version: 3.32
sdk: org.gnome.Sdk
command: gajim
tags: nightly
desktop-file-name-prefix: '(Nightly) '
finish-args:
- --share=ipc
- --share=network
- --socket=fallback-x11
- --socket=wayland
- --socket=pulseaudio
- --system-talk-name=org.freedesktop.GeoClue2
- --system-talk-name=org.freedesktop.login1
- --talk-name=org.freedesktop.Notifications
- --talk-name=org.gnome.ScreenSaver
- --talk-name=org.mpris.MediaPlayer2.*
# Keyring
- --talk-name=org.freedesktop.secrets
# dconf
- --filesystem=xdg-run/dconf
- --filesystem=~/.config/dconf:ro
- --talk-name=ca.desrt.dconf
- --env=DCONF_USER_CONFIG_DIR=.config/dconf
# GnuPG
- --filesystem=~/.gnupg
# extensions
- --env=PYTHONPATH=/app/plugins/lib/python3.7/site-packages
add-extensions:
org.gajim.Gajim.Plugin:
directory: plugins
merge-dirs: lib/python3.7/site-packages
subdirectories: true
no-autodownload: true
autodelete: true
cleanup:
- '/bin/easy*'
- /include
- /lib/debug
- /lib/pkgconfig
- /lib/python2.7
- /share/aclocal
- /share/doc
- /share/gtk-doc
- /share/man
- '*.a'
- '*.la'
modules:
- name: python3-pycparser
buildsystem: simple
build-commands:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz
sha256: a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3
- name: python3-cffi
buildsystem: simple
build-commands:
- pip3 install --prefix=/app .
sources:
- type: archive
url: https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz
sha256: e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7
- name: python3-asn1crypto
buildsystem: simple
build-commands:
- pip3 install --prefix=/app asn1crypto-0.24.0-py2.py3-none-any.whl
sources:
- type: file
url: https://pypi.python.org/packages/ea/cd/35485615f45f30a510576f1a56d1e0a7ad7bd8ab5ed7cdc600ef7cd06222/asn1crypto-0.24.0-py2.py3-none-any.whl
sha256: 2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87
- name: python3-idna
buildsystem: simple
build-commands:
- pip3 install --prefix=/app idna-2.8-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/14/2c/cd551d81dbe15200be1cf41cd03869a46fe7226e7450af7a6545bfc474c9/idna-2.8-py2.py3-none-any.whl
sha256: ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c
- name: python3-cryptography
buildsystem: simple
build-commands:
- python3 setup.py install --prefix=/app
sources:
- type: archive
url: https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz
sha256: 26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6
- name: python3-pyopenssl
buildsystem: simple
build-commands:
- pip3 install --prefix=/app pyOpenSSL-19.0.0-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/01/c8/ceb170d81bd3941cbeb9940fc6cc2ef2ca4288d0ca8929ea4db5905d904d/pyOpenSSL-19.0.0-py2.py3-none-any.whl
sha256: c727930ad54b10fc157015014b666f2d8b41f70c0d03e83ab67624fd3dd5d1e6
- name: python3-dbus-python
build-options:
env:
PYTHON_VERSION: '3'
sources:
- type: archive
url: https://files.pythonhosted.org/packages/3f/e7/4edb582d1ffd5ac3c84188deea32e960b5c8c0fe1da56ce70224f85ce542/dbus-python-1.2.8.tar.gz
sha256: abf12bbb765e300bf8e2a1b2f32f85949eab06998dbda127952c31cb63957b6f
- name: python3-jeepney
buildsystem: simple
build-commands:
- pip3 install --prefix=/app jeepney-0.4-py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/2b/f7/ff23b9b59534f501d47c327576aadda59da5b83d76ff837e6075bc325b9f/jeepney-0.4-py3-none-any.whl
sha256: f6f8b1428403b4afad04b6b82f9ab9fc426c253d7504c9031c41712a2c01dc74
- name: python3-secretstorage
buildsystem: simple
build-commands:
- pip3 install --prefix=/app SecretStorage-3.1.1-py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/82/59/cb226752e20d83598d7fdcabd7819570b0329a61db07cfbdd21b2ef546e3/SecretStorage-3.1.1-py3-none-any.whl
sha256: 7a119fb52a88e398dbb22a4b3eb39b779bfbace7e4153b7bc6e5954d86282a8a
- name: python3-entrypoints
buildsystem: simple
build-commands:
- pip3 install --prefix=/app entrypoints-0.3-py2.py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/ac/c6/44694103f8c221443ee6b0041f69e2740d89a25641e62fb4f2ee568f2f9c/entrypoints-0.3-py2.py3-none-any.whl
sha256: 589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19
- name: python3-keyring
buildsystem: simple
build-commands:
- pip3 install --prefix=/app keyring-18.0.0-py2.py3-none-any.whl
cleanup:
- /bin
sources:
- type: file
url: https://files.pythonhosted.org/packages/a1/28/0058032477bfdf2003e605d175629963759220661615443e20711446bfa7/keyring-18.0.0-py2.py3-none-any.whl
sha256: ca33f5ccc542b9ffaa196ee9a33488069e5e7eac77d5b81969f8a3ce74d0230c
- name: python3-cssutils
buildsystem: simple
build-commands:
- pip3 install --prefix=/app cssutils-1.0.2-py3-none-any.whl
cleanup:
- /bin
sources:
- type: file
url: https://files.pythonhosted.org/packages/6b/15/a9fb9010f58d1c55dd0b7779db2334feb9a572d407024f39a60f44293861/cssutils-1.0.2-py3-none-any.whl
sha256: c74dbe19c92f5052774eadb15136263548dd013250f1ed1027988e7fef125c8d
- name: python3-precis_i18n
buildsystem: simple
build-commands:
- pip3 install --prefix=/app precis_i18n-1.0.0-py3-none-any.whl
sources:
- type: file
url: https://files.pythonhosted.org/packages/08/9d/d32f1b7c6d280c82a786b629ba89bd9e3e8409b9e23a7309f76a78e46971/precis_i18n-1.0.0-py3-none-any.whl
sha256: f6942bbffec698d0d7e30c42f589f3f6da13e723d047997d0761a41facf2986f
- name: gspell
cleanup:
- /bin
sources:
- type: archive
url: https://download.gnome.org/sources/gspell/1.8/gspell-1.8.1.tar.xz
sha256: 819a1d23c7603000e73f5e738bdd284342e0cd345fb0c7650999c31ec741bbe5
- name: python3-nbxmpp
buildsystem: simple
build-commands:
- pip3 install --prefix=/app .
sources:
- type: git
url: https://dev.gajim.org/gajim/python-nbxmpp.git
- name: gajim
buildsystem: simple
build-commands:
- pip3 install --prefix=/app .
- touch /app/share/run-as-flatpak
sources:
- type: git
url: https://dev.gajim.org/gajim/gajim.git
post-install:
- install -d /app/plugins

View file

@ -1,7 +1,7 @@
import os
import subprocess
__version__ = "1.0.3"
__version__ = "1.1.92"
IS_FLATPAK = False
if os.path.exists('/app/share/run-as-flatpak'):

View file

@ -1,793 +0,0 @@
from functools import partial
from gi.repository import Gtk, GLib, Gdk
from gajim.common import app
from gajim import gtkgui_helpers
from gajim import gui_menu_builder
from gajim.common import passwords
from gajim import config
from gajim.common import helpers
from gajim.common import ged
from gajim.common.connection import Connection
from gajim.common.zeroconf.connection_zeroconf import ConnectionZeroconf
from gajim.options_dialog import OptionsDialog, OptionsBox
from gajim.common.const import Option, OptionKind, OptionType
from gajim.gtk import ConfirmationDialog
from gajim.gtk import YesNoDialog
class AccountsWindow(Gtk.ApplicationWindow):
def __init__(self):
Gtk.ApplicationWindow.__init__(self)
self.set_application(app.app)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_show_menubar(False)
self.set_name('AccountsWindow')
self.set_default_size(700, 550)
self.set_resizable(False)
self.set_title(_('Accounts'))
self.need_relogin = {}
glade_objects = ['stack', 'box', 'account_list']
self.builder = gtkgui_helpers.get_gtk_builder('accounts_window.ui')
for obj in glade_objects:
setattr(self, obj, self.builder.get_object(obj))
self.account_list.add(Preferences(self))
account_item = AddAccount()
self.account_list.add(account_item)
account_item.set_activatable()
accounts = app.config.get_per('accounts')
accounts.sort()
for account in accounts:
self.need_relogin[account] = self.get_relogin_options(account)
account_item = Account(account, self)
self.account_list.add(account_item)
account_item.set_activatable()
self.add(self.box)
self.builder.connect_signals(self)
self.connect('destroy', self.on_destroy)
self.connect('key-press-event', self.on_key_press)
self._activate_preferences_page()
self.show_all()
app.ged.register_event_handler(
'our-show', ged.GUI2, self._nec_our_status)
def _nec_our_status(self, event):
self.update_accounts()
def _activate_preferences_page(self):
row = self.account_list.get_row_at_index(0)
self.account_list.select_row(row)
self.account_list.emit('row-activated', row)
def on_key_press(self, widget, event):
if event.keyval == Gdk.KEY_Escape:
self.destroy()
def on_destroy(self, *args):
self.check_relogin()
app.ged.remove_event_handler(
'our-show', ged.GUI2, self._nec_our_status)
def on_child_visible(self, stack, *args):
page = stack.get_visible_child_name()
if page is None:
return
if page == 'account':
self.check_relogin()
def update_accounts(self):
for row in self.account_list.get_children():
row.get_child().update()
@staticmethod
def on_row_activated(listbox, row):
row.get_child().on_row_activated()
def remove_all_pages(self):
for page in self.stack.get_children():
self.stack.remove(page)
def set_page(self, page, name):
self.remove_all_pages()
self.stack.add_named(page, name)
page.update()
page.show_all()
self.stack.set_visible_child(page)
def update_proxy_list(self):
page = self.stack.get_child_by_name('connection')
if page is None:
return
page.listbox.get_option('proxy').update_values()
def check_relogin(self):
for account in self.need_relogin:
options = self.get_relogin_options(account)
active = app.config.get_per('accounts', account, 'active')
if options != self.need_relogin[account]:
self.need_relogin[account] = options
if active:
self.relog(account)
break
def relog(self, account):
if app.connections[account].connected == 0:
return
if account == app.ZEROCONF_ACC_NAME:
app.connections[app.ZEROCONF_ACC_NAME].update_details()
return
def login(account, show_before, status_before):
"""
Login with previous status
"""
# first make sure connection is really closed,
# 0.5 may not be enough
app.connections[account].disconnect(True)
app.interface.roster.send_status(
account, show_before, status_before)
def relog(account):
show_before = app.SHOW_LIST[app.connections[account].connected]
status_before = app.connections[account].status
app.interface.roster.send_status(
account, 'offline', _('Be right back.'))
GLib.timeout_add(500, login, account, show_before, status_before)
YesNoDialog(
_('Relogin now?'),
_('If you want all the changes to apply instantly, '
'you must relogin.'),
transient_for=self,
on_response_yes=lambda *args: relog(account))
@staticmethod
def get_relogin_options(account):
if account == app.ZEROCONF_ACC_NAME:
options = ['zeroconf_first_name', 'zeroconf_last_name',
'zeroconf_jabber_id', 'zeroconf_email', 'keyid']
else:
options = ['client_cert', 'proxy', 'resource',
'use_custom_host', 'custom_host', 'custom_port',
'keyid']
values = []
for option in options:
values.append(app.config.get_per('accounts', account, option))
return values
def on_remove_account(self, button, account):
if app.events.get_events(account):
app.interface.raise_dialog('unread-events-on-remove-account')
return
if app.config.get_per('accounts', account, 'is_zeroconf'):
# Should never happen as button is insensitive
return
win_opened = False
if app.interface.msg_win_mgr.get_controls(acct=account):
win_opened = True
elif account in app.interface.instances:
for key in app.interface.instances[account]:
if (app.interface.instances[account][key] and
key != 'remove_account'):
win_opened = True
break
# Detect if we have opened windows for this account
def remove(account):
if (account in app.interface.instances and
'remove_account' in app.interface.instances[account]):
dialog = app.interface.instances[account]['remove_account']
dialog.window.present()
else:
if account not in app.interface.instances:
app.interface.instances[account] = {}
app.interface.instances[account]['remove_account'] = \
config.RemoveAccountWindow(account)
if win_opened:
ConfirmationDialog(
_('You have opened chat in account %s') % account,
_('All chat and groupchat windows will be closed. '
'Do you want to continue?'),
on_response_ok=(remove, account),
transient_for=self)
else:
remove(account)
def remove_account(self, account):
for row in self.account_list.get_children():
if row.get_child().account == account:
self.account_list.remove(row)
del self.need_relogin[account]
break
self._activate_preferences_page()
def add_account(self, account):
account_item = Account(account, self)
self.account_list.add(account_item)
account_item.set_activatable()
self.account_list.show_all()
self.stack.show_all()
self.need_relogin[account] = self.get_relogin_options(account)
def select_account(self, account):
for row in self.account_list.get_children():
if row.get_child().account == account:
self.account_list.select_row(row)
self.account_list.emit('row-activated', row)
break
@staticmethod
def enable_account(account):
if account == app.ZEROCONF_ACC_NAME:
app.connections[account] = ConnectionZeroconf(account)
else:
app.connections[account] = Connection(account)
# update variables
app.interface.instances[account] = {
'infos': {}, 'disco': {}, 'gc_config': {}, 'search': {},
'online_dialog': {}, 'sub_request': {}}
app.interface.minimized_controls[account] = {}
app.connections[account].connected = 0
app.groups[account] = {}
app.contacts.add_account(account)
app.gc_connected[account] = {}
app.automatic_rooms[account] = {}
app.newly_added[account] = []
app.to_be_removed[account] = []
if account == app.ZEROCONF_ACC_NAME:
app.nicks[account] = app.ZEROCONF_ACC_NAME
else:
app.nicks[account] = app.config.get_per(
'accounts', account, 'name')
app.block_signed_in_notifications[account] = True
app.sleeper_state[account] = 'off'
app.encrypted_chats[account] = []
app.last_message_time[account] = {}
app.status_before_autoaway[account] = ''
app.transport_avatar[account] = {}
app.gajim_optional_features[account] = []
app.caps_hash[account] = ''
helpers.update_optional_features(account)
# refresh roster
if len(app.connections) >= 2:
# Do not merge accounts if only one exists
app.interface.roster.regroup = app.config.get('mergeaccounts')
else:
app.interface.roster.regroup = False
app.interface.roster.setup_and_draw_roster()
gui_menu_builder.build_accounts_menu()
@staticmethod
def disable_account(account):
app.interface.roster.close_all(account)
if account == app.ZEROCONF_ACC_NAME:
app.connections[account].disable_account()
app.connections[account].cleanup()
del app.connections[account]
del app.interface.instances[account]
del app.interface.minimized_controls[account]
del app.nicks[account]
del app.block_signed_in_notifications[account]
del app.groups[account]
app.contacts.remove_account(account)
del app.gc_connected[account]
del app.automatic_rooms[account]
del app.to_be_removed[account]
del app.newly_added[account]
del app.sleeper_state[account]
del app.encrypted_chats[account]
del app.last_message_time[account]
del app.status_before_autoaway[account]
del app.transport_avatar[account]
del app.gajim_optional_features[account]
del app.caps_hash[account]
if len(app.connections) >= 2:
# Do not merge accounts if only one exists
app.interface.roster.regroup = app.config.get('mergeaccounts')
else:
app.interface.roster.regroup = False
app.config.set_per(
'accounts', account, 'roster_version', '')
app.interface.roster.setup_and_draw_roster()
gui_menu_builder.build_accounts_menu()
class AddAccount(Gtk.Box):
def __init__(self):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
spacing=12)
self.account = None
self.label = Gtk.Label(label=_('Add Account…'))
self.label.set_halign(Gtk.Align.START)
self.label.set_hexpand(True)
self.image = Gtk.Image.new_from_icon_name(
'list-add-symbolic', Gtk.IconSize.MENU)
self.add(self.image)
self.add(self.label)
def set_activatable(self):
self.get_parent().set_selectable(False)
def on_row_activated(self):
app.app.activate_action('add-account')
def update(self):
pass
class Preferences(Gtk.Box):
def __init__(self, parent):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
spacing=12)
self.options = PreferencesPage()
self.parent = parent
self.account = None
self.label = Gtk.Label(label=_('Preferences'))
self.label.set_halign(Gtk.Align.START)
self.label.set_hexpand(True)
self.image = Gtk.Image.new_from_icon_name(
'system-run-symbolic', Gtk.IconSize.MENU)
self.add(self.image)
self.add(self.label)
def set_activatable(self):
pass
def on_row_activated(self):
self.options.update_states()
self.parent.set_page(self.options, 'pref')
def update(self):
pass
class Account(Gtk.Box):
def __init__(self, account, parent):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL,
spacing=12)
self.account = account
if account == app.ZEROCONF_ACC_NAME:
self.options = ZeroConfPage(account, parent)
else:
self.options = AccountPage(account, parent)
self.parent = parent
account_label = app.config.get_per('accounts', account, 'account_label')
self.label = Gtk.Label(label=account_label or account)
self.label.set_halign(Gtk.Align.START)
self.label.set_hexpand(True)
self.image = Gtk.Image()
self._update_image()
self.add(self.image)
self.add(self.label)
def set_activatable(self):
if self.account == app.ZEROCONF_ACC_NAME:
zeroconf = app.is_installed('ZEROCONF')
self.get_parent().set_activatable(zeroconf)
self.get_parent().set_sensitive(zeroconf)
if not zeroconf:
self.get_parent().set_tooltip_text(
_('Please check if Avahi or Bonjour is installed.'))
def on_row_activated(self):
self.options.update_states()
self.parent.set_page(self.options, 'account')
def update(self):
account_label = app.config.get_per(
'accounts', self.account, 'account_label')
self.label.set_text(account_label or self.account)
self._update_image()
def _update_image(self):
show = helpers.get_current_show(self.account)
icon = gtkgui_helpers.get_iconset_name_for(show)
self.image.set_from_icon_name(icon, Gtk.IconSize.MENU)
class GenericOptionPage(Gtk.Box):
def __init__(self, account, parent, options):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=12)
self.account = account
self.parent = parent
button = Gtk.Button.new_from_icon_name(
'go-previous-symbolic', Gtk.IconSize.MENU)
button.set_halign(Gtk.Align.START)
button.connect('clicked', self._on_back_button)
if not isinstance(self, (AccountPage, PreferencesPage, ZeroConfPage)):
self.pack_start(button, False, True, 0)
self.listbox = OptionsBox(account)
self.listbox.set_selection_mode(Gtk.SelectionMode.NONE)
self.listbox.set_vexpand(False)
self.listbox.set_valign(Gtk.Align.END)
for option in options:
self.listbox.add_option(option)
self.listbox.update_states()
self.pack_end(self.listbox, True, True, 0)
self.listbox.connect('row-activated', self.on_row_activated)
def _on_back_button(self, *args):
account_window = self.get_toplevel()
child = account_window.stack.get_visible_child()
account_window.remove_all_pages()
account_window.stack.add_named(child.parent, 'account')
account_window.stack.set_visible_child_name('account')
def update_states(self):
self.listbox.update_states()
def on_row_activated(self, listbox, row):
row.get_child().on_row_activated()
def set_entry_text(self, toggle, update=False):
account_label = app.config.get_per(
'accounts', self.account, 'account_label')
if update:
self.entry.set_text(account_label or self.account)
return
if toggle.get_active():
self.entry.set_sensitive(True)
self.entry.grab_focus()
else:
self.entry.set_sensitive(False)
value = self.entry.get_text()
if not value:
value = account_label or self.account
app.config.set_per('accounts', self.account,
'account_label', value or self.account)
if app.config.get_per('accounts', self.account, 'active'):
app.interface.roster.draw_account(self.account)
gui_menu_builder.build_accounts_menu()
def update(self):
pass
def set_page(self, options, name):
options.update_states()
self.get_toplevel().set_page(options, name)
def _add_top_buttons(self, parent):
# This adds the Account enable switch and the back button
box = Gtk.Box()
box.set_hexpand(True)
box.set_halign(Gtk.Align.FILL)
switch = Gtk.Switch()
switch.set_active(app.config.get_per('accounts', self.account, 'active'))
switch.set_vexpand(False)
switch.set_valign(Gtk.Align.CENTER)
switch.set_halign(Gtk.Align.END)
if self.account == app.ZEROCONF_ACC_NAME and not app.is_installed('ZEROCONF'):
switch.set_sensitive(False)
switch.set_active(False)
switch.connect('notify::active', self._on_enable_switch, self.account)
box.pack_start(switch, False, False, 0)
if self.account != app.ZEROCONF_ACC_NAME:
button = Gtk.Button(label=_('Remove'))
button.connect(
'clicked', parent.on_remove_account, self.account)
button.get_style_context().add_class('destructive-action')
button.set_halign(Gtk.Align.END)
switch.set_vexpand(False)
box.pack_end(button, False, False, 0)
self.pack_start(box, True, True, 0)
def _on_enable_switch(self, switch, param, account):
old_state = app.config.get_per('accounts', account, 'active')
state = switch.get_active()
if old_state == state:
return
if (account in app.connections and
app.connections[account].connected > 0):
# connecting or connected
app.interface.raise_dialog('connected-on-disable-account')
switch.set_active(not state)
return
if state:
self.parent.enable_account(account)
else:
self.parent.disable_account(account)
app.config.set_per('accounts', account, 'active', state)
class PreferencesPage(GenericOptionPage):
def __init__(self):
options = [
Option(OptionKind.SWITCH, _('Merge Accounts'),
OptionType.ACTION, 'merge'),
Option(OptionKind.SWITCH, _('Use PGP Agent'),
OptionType.ACTION, 'agent'),
]
GenericOptionPage.__init__(self, None, None, options)
class AccountPage(GenericOptionPage):
def __init__(self, account, parent=None):
general = partial(
self.set_page, GeneralPage(account, self), 'general')
connection = partial(
self.set_page, ConnectionPage(account, self), 'connection')
options = [
Option(OptionKind.ENTRY, _('Label'),
OptionType.ACCOUNT_CONFIG, 'account_label',
callback=self._on_account_name_change),
Option(OptionKind.LOGIN, _('Login'), OptionType.DIALOG,
props={'dialog': LoginDialog}),
Option(OptionKind.ACTION, _('Profile'), OptionType.ACTION,
'-profile', props={'action_args': account}),
Option(OptionKind.CALLBACK, _('General'),
name='general', props={'callback': general}),
Option(OptionKind.CALLBACK, _('Connection'),
name='connection', props={'callback': connection}),
Option(OptionKind.ACTION, _('Import Contacts'), OptionType.ACTION,
'-import-contacts', props={'action_args': account}),
Option(OptionKind.DIALOG, _('Client Certificate'),
OptionType.DIALOG, props={'dialog': CertificateDialog}),
Option(OptionKind.GPG, _('OpenPGP Key'), OptionType.DIALOG,
props={'dialog': None}),
]
GenericOptionPage.__init__(self, account, parent, options)
self._add_top_buttons(parent)
def _on_account_name_change(self, account_name, *args):
self.parent.update_accounts()
class GeneralPage(GenericOptionPage):
def __init__(self, account, parent=None):
options = [
Option(OptionKind.SWITCH, _('Connect on startup'),
OptionType.ACCOUNT_CONFIG, 'autoconnect'),
Option(OptionKind.SWITCH, _('Reconnect when connection is lost'),
OptionType.ACCOUNT_CONFIG, 'autoreconnect'),
Option(OptionKind.SWITCH, _('Save conversations for all contacts'),
OptionType.ACCOUNT_CONFIG, 'no_log_for',
desc=_('Store conversations on the harddrive')),
Option(OptionKind.SWITCH, _('Server Message Archive'),
OptionType.ACCOUNT_CONFIG, 'sync_logs_with_server',
desc=_('Messages get stored on the server.\n'
'The archive is used to sync messages\n'
'between multiple devices.\n'
'XEP-0313')),
Option(OptionKind.SWITCH, _('Global Status'),
OptionType.ACCOUNT_CONFIG, 'sync_with_global_status',
desc=_('Synchronise the status of all accounts')),
Option(OptionKind.SWITCH, _('Message Carbons'),
OptionType.ACCOUNT_CONFIG, 'enable_message_carbons',
desc=_('All your other online devices get copies\n'
'of sent and received messages.\n'
'XEP-0280')),
Option(OptionKind.SWITCH, _('Use file transfer proxies'),
OptionType.ACCOUNT_CONFIG, 'use_ft_proxies'),
]
GenericOptionPage.__init__(self, account, parent, options)
class ConnectionPage(GenericOptionPage):
def __init__(self, account, parent=None):
options = [
Option(OptionKind.SWITCH, 'HTTP_PROXY',
OptionType.ACCOUNT_CONFIG, 'use_env_http_proxy',
desc=_('Use environment variable')),
Option(OptionKind.PROXY, _('Proxy'),
OptionType.ACCOUNT_CONFIG, 'proxy', name='proxy'),
Option(OptionKind.SWITCH, _('Warn on insecure connection'),
OptionType.ACCOUNT_CONFIG,
'warn_when_insecure_ssl_connection'),
Option(OptionKind.SWITCH, _('Send keep-alive packets'),
OptionType.ACCOUNT_CONFIG, 'keep_alives_enabled'),
Option(OptionKind.HOSTNAME, _('Hostname'), OptionType.DIALOG,
desc=_('Manually set the hostname for the server'),
props={'dialog': CutstomHostnameDialog}),
Option(OptionKind.ENTRY, _('Resource'),
OptionType.ACCOUNT_CONFIG, 'resource'),
Option(OptionKind.PRIORITY, _('Priority'),
OptionType.DIALOG, props={'dialog': PriorityDialog}),
]
GenericOptionPage.__init__(self, account, parent, options)
class ZeroConfPage(GenericOptionPage):
def __init__(self, account, parent=None):
options = [
Option(OptionKind.DIALOG, _('Profile'),
OptionType.DIALOG, props={'dialog': ZeroconfProfileDialog}),
Option(OptionKind.SWITCH, _('Connect on startup'),
OptionType.ACCOUNT_CONFIG, 'autoconnect',
desc=_('Use environment variable')),
Option(OptionKind.SWITCH, _('Save conversations for all contacts'),
OptionType.ACCOUNT_CONFIG, 'no_log_for',
desc=_('Store conversations on the harddrive')),
Option(OptionKind.SWITCH, _('Global Status'),
OptionType.ACCOUNT_CONFIG, 'sync_with_global_status',
desc=_('Synchronize the status of all accounts')),
Option(OptionKind.GPG, _('OpenPGP Key'),
OptionType.DIALOG, props={'dialog': None}),
]
GenericOptionPage.__init__(self, account, parent, options)
self._add_top_buttons(None)
class ZeroconfProfileDialog(OptionsDialog):
def __init__(self, account, parent):
options = [
Option(OptionKind.ENTRY, _('First Name'),
OptionType.ACCOUNT_CONFIG, 'zeroconf_first_name'),
Option(OptionKind.ENTRY, _('Last Name'),
OptionType.ACCOUNT_CONFIG, 'zeroconf_last_name'),
Option(OptionKind.ENTRY, _('Jabber ID'),
OptionType.ACCOUNT_CONFIG, 'zeroconf_jabber_id'),
Option(OptionKind.ENTRY, _('Email'),
OptionType.ACCOUNT_CONFIG, 'zeroconf_email'),
]
OptionsDialog.__init__(self, parent, _('Profile'),
Gtk.DialogFlags.MODAL, options, account)
class PriorityDialog(OptionsDialog):
def __init__(self, account, parent):
neg_priority = app.config.get('enable_negative_priority')
if neg_priority:
range_ = (-128, 127)
else:
range_ = (0, 127)
options = [
Option(OptionKind.SWITCH, _('Adjust to status'),
OptionType.ACCOUNT_CONFIG, 'adjust_priority_with_status',
'adjust'),
Option(OptionKind.SPIN, _('Priority'),
OptionType.ACCOUNT_CONFIG, 'priority',
enabledif=('adjust', False), props={'range_': range_}),
]
OptionsDialog.__init__(self, parent, _('Priority'),
Gtk.DialogFlags.MODAL, options, account)
self.connect('destroy', self.on_destroy)
def on_destroy(self, *args):
# Update priority
if self.account not in app.connections:
return
show = app.SHOW_LIST[app.connections[self.account].connected]
status = app.connections[self.account].status
app.connections[self.account].change_status(show, status)
class CutstomHostnameDialog(OptionsDialog):
def __init__(self, account, parent):
options = [
Option(OptionKind.SWITCH, _('Enable'),
OptionType.ACCOUNT_CONFIG, 'use_custom_host', name='custom'),
Option(OptionKind.ENTRY, _('Hostname'),
OptionType.ACCOUNT_CONFIG, 'custom_host',
enabledif=('custom', True)),
Option(OptionKind.ENTRY, _('Port'),
OptionType.ACCOUNT_CONFIG, 'custom_port',
enabledif=('custom', True)),
]
OptionsDialog.__init__(self, parent, _('Connection Options'),
Gtk.DialogFlags.MODAL, options, account)
class CertificateDialog(OptionsDialog):
def __init__(self, account, parent):
options = [
Option(OptionKind.FILECHOOSER, _('Client Certificate'),
OptionType.ACCOUNT_CONFIG, 'client_cert',
props={'filefilter': (_('PKCS12 Files'), '*.p12')}),
Option(OptionKind.SWITCH, _('Encrypted Certificate'),
OptionType.ACCOUNT_CONFIG, 'client_cert_encrypted'),
]
OptionsDialog.__init__(self, parent, _('Certificate Options'),
Gtk.DialogFlags.MODAL, options, account)
class LoginDialog(OptionsDialog):
def __init__(self, account, parent):
options = [
Option(OptionKind.ENTRY, _('Password'),
OptionType.ACCOUNT_CONFIG, 'password', name='password',
enabledif=('savepass', True)),
Option(OptionKind.SWITCH, _('Save Password'),
OptionType.ACCOUNT_CONFIG, 'savepass', name='savepass'),
Option(OptionKind.CHANGEPASSWORD, _('Change Password'),
OptionType.DIALOG, callback=self.on_password_change,
props={'dialog': None}),
]
OptionsDialog.__init__(self, parent, _('Login Options'),
Gtk.DialogFlags.MODAL, options, account)
self.connect('destroy', self.on_destroy)
def on_password_change(self, new_password, data):
passwords.save_password(self.account, new_password)
def on_destroy(self, *args):
savepass = app.config.get_per('accounts', self.account, 'savepass')
if not savepass:
passwords.save_password(self.account, '')

View file

@ -1,558 +0,0 @@
# -*- coding: utf-8 -*-
## src/adhoc_commands.py
##
## Copyright (C) 2006 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## Stephan Erb <steve-e AT h3c.de>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
# FIXME: think if we need caching command list. it may be wrong if there will
# be entities that often change the list, it may be slow to fetch it every time
from gi.repository import Gtk
import nbxmpp
from gajim.common import app
from gajim.common.modules import dataforms
from gajim.common import ged
from gajim import gtkgui_helpers
from gajim.gtk import HigDialog
from gajim import dataforms_widget
class CommandWindow:
"""
Class for a window for single ad-hoc commands session
Note, that there might be more than one for one account/jid pair in one
moment.
TODO: Maybe put this window into MessageWindow? consider this when it will
be possible to manage more than one window of one.
TODO: Account/jid pair in MessageWindowMgr.
TODO: GTK 2.10 has a special wizard-widget, consider using it...
"""
def __init__(self, account, jid, commandnode=None):
"""
Create new window
"""
# an account object
self._con = app.connections[account]
self.jid = jid
self.commandnode = commandnode
self.data_form_widget = None
self.stage_finish_cb = None
self.stage_back_button_cb = None
self.stage_forward_button_cb = None
self.stage_execute_button_cb = None
self.stage_close_button_cb = None
self.stage_restart_button_cb = None
self.stage_window_delete_cb = None
# retrieving widgets from xml
self.xml = gtkgui_helpers.get_gtk_builder('adhoc_commands_window.ui')
self.window = self.xml.get_object('adhoc_commands_window')
self.window.connect('delete-event',
self.on_adhoc_commands_window_delete_event)
for name in ('restart_button', 'back_button', 'forward_button',
'execute_button', 'finish_button', 'close_button', 'stages_notebook',
'retrieving_commands_stage_vbox', 'retrieving_commands_spinner',
'command_list_stage_vbox', 'command_treeview',
'sending_form_stage_vbox', 'sending_form_spinner',
'notes_label', 'no_commands_stage_vbox',
'error_stage_vbox', 'error_description_label'):
setattr(self, name, self.xml.get_object(name))
self.command_store = Gtk.ListStore(str, str)
self.command_treeview.set_model(self.command_store)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Command", renderer, text=0)
self.command_treeview.append_column(column)
app.ged.register_event_handler(
'adhoc-command-error', ged.CORE, self._on_command_error)
app.ged.register_event_handler(
'adhoc-command-list', ged.CORE, self._on_command_list)
app.ged.register_event_handler('adhoc-command-action-response',
ged.CORE,
self._on_action_response)
self.initiate()
def initiate(self):
self.commandlist = None # a list of (commandname, commanddescription)
# command's data
self.sessionid = None
self.dataform = None
self.allow_stage3_close = False
# creating data forms widget
if self.data_form_widget:
self.sending_form_stage_vbox.remove(self.data_form_widget)
self.data_form_widget.destroy()
self.data_form_widget = dataforms_widget.DataFormWidget()
self.data_form_widget.show()
self.sending_form_stage_vbox.pack_start(self.data_form_widget, True, True, 0)
if self.commandnode:
# Execute command
self.stage3()
else:
# setting initial stage
self.stage1()
# displaying the window
self.window.set_title(_('Ad-hoc Commands - Gajim'))
self.xml.connect_signals(self)
self.window.show_all()
self.restart_button.set_sensitive(False)
# These functions are set up by appropriate stageX methods.
def stage_finish(self, *anything):
if self.stage_finish_cb:
self.stage_finish_cb(*anything)
# Widget callbacks...
def on_back_button_clicked(self, *anything):
if self.stage_back_button_cb:
return self.stage_back_button_cb(*anything)
return False
def on_forward_button_clicked(self, *anything):
if self.stage_forward_button_cb:
return self.stage_forward_button_cb(*anything)
return False
def on_execute_button_clicked(self, *anything):
if self.stage_execute_button_cb:
return self.stage_execute_button_cb(*anything)
return False
def on_finish_button_clicked(self, *anything):
if self.stage_finish_button_cb:
return self.stage_finish_button_cb(*anything)
return False
def on_close_button_clicked(self, *anything):
if self.stage_close_button_cb:
return self.stage_close_button_cb(*anything)
return False
def on_restart_button_clicked(self, *anything):
if self.stage_restart_button_cb:
return self.stage_restart_button_cb(*anything)
return False
def on_adhoc_commands_window_destroy(self, *anything):
app.ged.remove_event_handler(
'adhoc-command-error', ged.CORE, self._on_command_error)
app.ged.remove_event_handler(
'adhoc-command-list', ged.CORE, self._on_command_list)
app.ged.remove_event_handler('adhoc-command-action-response',
ged.CORE,
self._on_action_response)
def on_adhoc_commands_window_delete_event(self, *anything):
if self.stage_window_delete_cb:
return self.stage_window_delete_cb(self.window)
return False
def __del__(self):
print('Object has been deleted.')
# stage 1: waiting for command list
def stage1(self):
"""
Prepare the first stage. Request command list, set appropriate state of
widgets
"""
# close old stage...
self.stage_finish()
# show the stage
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(
self.retrieving_commands_stage_vbox))
# set widgets' state
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(False)
self.finish_button.set_sensitive(False)
# request command list
self._con.get_module('AdHocCommands').request_command_list(self.jid)
self.retrieving_commands_spinner.start()
# setup the callbacks
self.stage_finish_cb = self.stage1_finish
self.stage_close_button_cb = self.stage1_close_button_clicked
self.stage_restart_button_cb = self.stage1_restart_button_clicked
self.stage_window_delete_cb = \
self.stage1_adhoc_commands_window_delete_event
def stage1_finish(self):
self.retrieving_commands_spinner.stop()
def stage1_close_button_clicked(self, widget):
# cancelling in this stage is not critical, so we don't
# show any popups to user
self.stage_finish()
self.window.destroy()
def stage1_restart_button_clicked(self, widget):
self.stage_finish()
self.restart()
def stage1_adhoc_commands_window_delete_event(self, widget):
self.stage1_finish()
return True
# stage 2: choosing the command to execute
def stage2(self):
"""
Populate the command list
"""
# close old stage
self.stage_finish()
assert len(self.commandlist)>0
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(self.command_list_stage_vbox))
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(True)
self.execute_button.set_sensitive(False)
self.finish_button.set_sensitive(False)
# build the commands list
self.command_store.clear()
for (commandnode, commandname) in self.commandlist:
self.command_store.append([commandname, commandnode])
self.command_treeview.get_selection().select_iter(self.command_store.get_iter_first())
self.stage_finish_cb = self.stage2_finish
self.stage_close_button_cb = self.stage2_close_button_clicked
self.stage_restart_button_cb = self.stage2_restart_button_clicked
self.stage_forward_button_cb = self.stage2_forward_button_clicked
self.stage_window_delete_cb = None
def stage2_finish(self):
"""
Save selected command to self.commandnode
"""
model, treeiter = self.command_treeview.get_selection().get_selected()
self.commandnode = model[treeiter][1]
def stage2_close_button_clicked(self, widget):
self.stage_finish()
self.window.destroy()
def stage2_restart_button_clicked(self, widget):
self.stage_finish()
self.restart()
def stage2_forward_button_clicked(self, widget):
self.stage3()
def on_check_commands_1_button_clicked(self, widget):
self.stage1()
# stage 3: command invocation
def stage3(self):
# close old stage
self.stage_finish()
self.form_status = None
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(
self.sending_form_stage_vbox))
self.restart_button.set_sensitive(True)
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(False)
self.finish_button.set_sensitive(False)
self.stage3_submit_form()
self.stage_finish_cb = None
self.stage_back_button_cb = self.stage3_back_button_clicked
self.stage_forward_button_cb = self.stage3_forward_button_clicked
self.stage_execute_button_cb = self.stage3_execute_button_clicked
self.stage_finish_button_cb = self.stage3_finish_button_clicked
self.stage_close_button_cb = self.stage3_close_button_clicked
self.stage_restart_button_cb = self.stage3_restart_button_clicked
self.stage_window_delete_cb = self.stage3_close_button_clicked
def stage3_can_close(self, cb):
if self.form_status == 'completed':
cb()
return
def on_yes(button):
self._con.get_module('AdHocCommands').send_cancel(
self.jid, self.commandnode, self.sessionid)
dialog.destroy()
cb()
dialog = HigDialog(self.window, Gtk.MessageType.WARNING,
Gtk.ButtonsType.YES_NO, _('Cancel confirmation'),
_('You are in process of executing command. Do you really want to '
'cancel it?'), on_response_yes=on_yes)
dialog.popup()
def stage3_close_button_clicked(self, widget):
"""
We are in the middle of executing command. Ask user if he really want to
cancel the process, then cancel it
"""
# this works also as a handler for window_delete_event, so we have to
# return appropriate values
if self.allow_stage3_close:
return False
def on_ok():
self.allow_stage3_close = True
self.window.destroy()
self.stage3_can_close(on_ok)
return True # Block event, don't close window
def stage3_restart_button_clicked(self, widget):
def on_ok():
self.restart()
self.stage3_can_close(on_ok)
def stage3_back_button_clicked(self, widget):
self.stage3_submit_form('prev')
def stage3_forward_button_clicked(self, widget):
self.stage3_submit_form('next')
def stage3_execute_button_clicked(self, widget):
self.stage3_submit_form('execute')
def stage3_finish_button_clicked(self, widget):
self.stage3_submit_form('complete')
def stage3_submit_form(self, action='execute'):
self.data_form_widget.set_sensitive(False)
if self.data_form_widget.get_data_form():
df = self.data_form_widget.get_data_form()
if not df.is_valid():
app.interface.raise_dialog(
'invalid-form', transient_for=self.window)
self.data_form_widget.set_sensitive(True)
return
self.data_form_widget.data_form.type_ = 'submit'
else:
self.data_form_widget.hide()
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(False)
self.finish_button.set_sensitive(False)
self.sending_form_spinner.start()
self._con.get_module('AdHocCommands').send_command(
self.jid, self.commandnode, self.sessionid,
self.data_form_widget.data_form, action)
def stage3_next_form(self, command):
if not isinstance(command, nbxmpp.Node):
self.stage5(error=_('Service sent malformed data'), senderror=True)
return
self.sending_form_spinner.stop()
if not self.sessionid:
self.sessionid = command.getAttr('sessionid')
elif self.sessionid != command.getAttr('sessionid'):
self.stage5(error=_('Service changed the session identifier.'),
senderror=True)
return
self.form_status = command.getAttr('status')
self.commandnode = command.getAttr('node')
if command.getTag('x'):
self.dataform = dataforms.ExtendForm(node=command.getTag('x'))
self.data_form_widget.set_sensitive(True)
try:
self.data_form_widget.selectable = True
self.data_form_widget.data_form = self.dataform
except dataforms.Error:
self.stage5(error=_('Service sent malformed data'),
senderror=True)
return
self.data_form_widget.show()
if self.data_form_widget.title:
self.window.set_title(_('%s - Ad-hoc Commands - Gajim') % \
self.data_form_widget.title)
else:
self.data_form_widget.hide()
actions = command.getTag('actions')
if actions:
# actions, actions, actions...
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(actions.getTag('prev') is not None)
self.forward_button.set_sensitive(
actions.getTag('next') is not None)
self.execute_button.set_sensitive(True)
self.finish_button.set_sensitive(actions.getTag('complete') is not \
None)
else:
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(True)
self.finish_button.set_sensitive(False)
if self.form_status == 'completed':
self.close_button.set_sensitive(True)
self.back_button.hide()
self.forward_button.hide()
self.execute_button.hide()
self.finish_button.hide()
self.close_button.show()
self.stage_window_delete_cb = self.stage3_close_button_clicked
note = command.getTag('note')
if note:
self.notes_label.set_text(note.getData())
self.notes_label.set_no_show_all(False)
self.notes_label.show()
else:
self.notes_label.set_no_show_all(True)
self.notes_label.hide()
def restart(self):
self.commandnode = None
self.initiate()
# stage 4: no commands are exposed
def stage4(self):
"""
Display the message. Wait for user to close the window
"""
# close old stage
self.stage_finish()
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(self.no_commands_stage_vbox))
self.close_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(False)
self.finish_button.set_sensitive(False)
self.stage_finish_cb = None
self.stage_close_button_cb = self.stage4_close_button_clicked
self.stage_restart_button_cb = self.stage4_restart_button_clicked
self.stage_window_delete_cb = None
def stage4_close_button_clicked(self, widget):
self.window.destroy()
def stage4_restart_button_clicked(self, widget):
self.restart()
def on_check_commands_2_button_clicked(self, widget):
self.stage1()
# stage 5: an error has occurred
def stage5(self, error=None, errorid=None, senderror=False):
"""
Display the error message. Wait for user to close the window
"""
# FIXME: sending error to responder
# close old stage
self.stage_finish()
assert errorid or error
if errorid:
# we've got error code, display appropriate message
try:
errorname = nbxmpp.NS_STANZAS + ' ' + str(errorid)
errordesc = nbxmpp.ERRORS[errorname][2]
error = errordesc
del errorname, errordesc
except KeyError: # when stanza doesn't have error description
error = _('Service returned an error.')
elif error:
# we've got error message
pass
else:
# we don't know what's that, bailing out
assert False
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(self.error_stage_vbox))
self.close_button.set_sensitive(True)
self.back_button.hide()
self.forward_button.hide()
self.execute_button.hide()
self.finish_button.hide()
self.error_description_label.set_text(error)
self.stage_finish_cb = None
self.stage_close_button_cb = self.stage5_close_button_clicked
self.stage_restart_button_cb = self.stage5_restart_button_clicked
self.stage_window_delete_cb = None
def stage5_close_button_clicked(self, widget):
self.window.destroy()
def stage5_restart_button_clicked(self, widget):
self.restart()
def _on_command_error(self, obj):
self.stage5(errorid=obj.error)
def _on_command_list(self, obj):
self.commandlist = obj.commandlist
if not self.commandlist:
self.stage4()
else:
self.stage2()
def _on_action_response(self, obj):
self.stage3_next_form(obj.command)

View file

@ -1,4 +1,3 @@
#
# Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
@ -15,31 +14,37 @@
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
from gi.repository import Gtk
from gi.repository import Gdk
from gajim.common import app
from gajim.common import helpers
from gajim.common.app import interface
from gajim.common.exceptions import GajimGeneralException
from gajim import config
from gajim import dialogs
from gajim.gtk import shortcuts_window
from gajim.accounts_window import AccountsWindow
import gajim.plugins.gui
from gajim import disco
from gajim.gtk.dialogs import ShortcutsWindow
from gajim.gtk.history_sync import HistorySyncAssistant
from gajim.gtk.server_info import ServerInfoDialog
from gajim.gtk.mam_preferences import MamPreferences
from gajim.gtk.preferences import Preferences
from gajim.gtk import JoinGroupchatWindow
from gajim.gtk import StartChatDialog
from gajim.gtk import AddNewContactWindow
from gajim.gtk import SingleMessageWindow
from gajim.gtk import XMLConsoleWindow
from gajim.gtk import AboutDialog
from gajim.gtk import PrivacyListsWindow
from gajim.gtk import ManageBookmarksWindow
from gajim.gtk import FeaturesDialog
from gajim.gtk import AccountCreationWizard
from gajim.gtk import HistoryWindow
from gajim.gtk.join_groupchat import JoinGroupchatWindow
from gajim.gtk.start_chat import StartChatDialog
from gajim.gtk.add_contact import AddNewContactWindow
from gajim.gtk.single_message import SingleMessageWindow
from gajim.gtk.xml_console import XMLConsoleWindow
from gajim.gtk.about import AboutDialog
from gajim.gtk.privacy_list import PrivacyListsWindow
from gajim.gtk.bookmarks import ManageBookmarksWindow
from gajim.gtk.features import FeaturesDialog
from gajim.gtk.account_wizard import AccountCreationWizard
from gajim.gtk.history import HistoryWindow
from gajim.gtk.accounts import AccountsWindow
from gajim.gtk.proxies import ManageProxies
from gajim.gtk.discovery import ServiceDiscoveryWindow
from gajim.gtk.blocking import BlockingList
# General Actions
@ -126,29 +131,34 @@ def on_service_disco(action, param):
else:
try:
# Object will add itself to the window dict
disco.ServiceDiscoveryWindow(account, address_entry=True)
ServiceDiscoveryWindow(account, address_entry=True)
except GajimGeneralException:
pass
def on_join_gc(action, param):
account = None
def on_join_gc(_action, param):
account, jid = None, None
if param is None:
if not app.get_connected_accounts():
return
else:
account = param.get_string()
account, jid = param.get_strv()
if not jid:
jid = None
window = app.get_app_window(JoinGroupchatWindow)
if window is None:
JoinGroupchatWindow(account, None)
JoinGroupchatWindow(account, jid)
else:
window.present()
def on_add_contact(action, param):
window = app.get_app_window(AddNewContactWindow)
def on_add_contact(_action, param):
account, jid = param.get_strv()
if not jid:
jid = None
window = app.get_app_window(AddNewContactWindow, account)
if window is None:
AddNewContactWindow(param.get_string())
AddNewContactWindow(account, jid)
else:
window.present()
@ -169,11 +179,6 @@ def on_merge_accounts(action, param):
app.interface.roster.setup_and_draw_roster()
def on_use_pgp_agent(action, param):
action.set_state(param)
app.config.set('use_gpg_agent', param.get_boolean())
def on_add_account(action, param):
if 'account_creation_wizard' in app.interface.instances:
app.interface.instances['account_creation_wizard'].window.present()
@ -202,6 +207,15 @@ def on_mam_preferences(action, param):
window.present()
def on_blocking_list(action, param):
account = param.get_string()
window = app.get_app_window(MamPreferences, account)
if window is None:
BlockingList(account)
else:
window.present()
def on_history_sync(action, param):
account = param.get_string()
if 'history_sync' in interface.instances[account]:
@ -242,8 +256,7 @@ def on_manage_proxies(action, param):
if 'manage_proxies' in app.interface.instances:
app.interface.instances['manage_proxies'].window.present()
else:
app.interface.instances['manage_proxies'] = \
config.ManageProxiesWindow(interface.roster.window)
app.interface.instances['manage_proxies'] = ManageProxies()
# Admin Actions
@ -264,25 +277,21 @@ def on_update_motd(action, param):
def on_delete_motd(action, param):
account = param.get_string()
server = app.config.get_per('accounts', account, 'hostname')
server += '/announce/motd/delete'
app.connections[account].send_motd(server)
app.connections[account].get_module('Announce').delete_motd()
# Help Actions
def on_contents(action, param):
helpers.launch_browser_mailer(
'url', 'https://dev.gajim.org/gajim/gajim/wikis')
helpers.open_uri('https://dev.gajim.org/gajim/gajim/wikis')
def on_faq(action, param):
helpers.launch_browser_mailer(
'url', 'https://dev.gajim.org/gajim/gajim/wikis/help/gajimfaq')
helpers.open_uri('https://dev.gajim.org/gajim/gajim/wikis/help/gajimfaq')
def on_keyboard_shortcuts(action, param):
shortcuts_window.show(app.app.get_active_window())
ShortcutsWindow()
def on_features(action, param):
@ -304,10 +313,7 @@ def on_file_transfers(action, param):
def on_history(action, param):
if 'logs' in interface.instances:
interface.instances['logs'].window.present()
else:
interface.instances['logs'] = HistoryWindow()
on_browse_history(action, param)
def on_open_event(action, param):
@ -338,3 +344,41 @@ def show_next_pending_event(action, param):
if not event:
return
app.interface.handle_event(account, jid, event.type_)
def open_link(_action, param):
uri = param.get_string()
helpers.open_uri(uri)
def copy_text(_action, param):
text = param.get_string()
clip = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
clip.set_text(text, -1)
def start_chat(_action, param):
account, jid = param.get_strv()
app.interface.new_chat_from_jid(account, jid)
def join_groupchat(_action, param):
account, jid = param.get_strv()
room_jid = jid.split('?')[0]
app.interface.join_gc_minimal(account, room_jid)
def on_browse_history(_action, param):
jid, account = None, None
if param is not None:
dict_ = param.unpack()
jid = dict_.get('jid')
account = dict_.get('account')
window = app.get_app_window(HistoryWindow)
if window is None:
HistoryWindow(jid, account)
else:
window.present()
if jid is not None and account is not None:
window.open_history(jid, account)

View file

@ -1,102 +1,163 @@
# -*- coding:utf-8 -*-
## src/gajim.py
##
## Copyright (C) 2003-2017 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005 Alex Podaras <bigpod AT gmail.com>
## Norman Rasmussen <norman AT rasmussen.co.za>
## Stéphan Kochen <stephan AT kochen.nl>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
## Alex Mauer <hawke AT hawkesnest.net>
## Copyright (C) 2005-2007 Travis Shirk <travis AT pobox.com>
## Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Junglecow J <junglecow AT gmail.com>
## Stefan Bethge <stefan AT lanpartei.de>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## James Newton <redshodan AT gmail.com>
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
## Julien Pivotto <roidelapluie AT gmail.com>
## Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
## Copyright (C) 2016-2017 Emmanuel Gil Peyrot <linkmauve AT linkmauve.fr>
## Philipp Hörist <philipp AT hoerist.com>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
# Copyright (C) 2003-2017 Yann Leboulanger <asterix AT lagaule.org>
# Copyright (C) 2004-2005 Vincent Hanquez <tab AT snarc.org>
# Copyright (C) 2005 Alex Podaras <bigpod AT gmail.com>
# Norman Rasmussen <norman AT rasmussen.co.za>
# Stéphan Kochen <stephan AT kochen.nl>
# Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
# Alex Mauer <hawke AT hawkesnest.net>
# Copyright (C) 2005-2007 Travis Shirk <travis AT pobox.com>
# Nikos Kouremenos <kourem AT gmail.com>
# Copyright (C) 2006 Junglecow J <junglecow AT gmail.com>
# Stefan Bethge <stefan AT lanpartei.de>
# Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
# Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
# James Newton <redshodan AT gmail.com>
# Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
# Julien Pivotto <roidelapluie AT gmail.com>
# Stephan Erb <steve-e AT h3c.de>
# Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
# Copyright (C) 2016-2017 Emmanuel Gil Peyrot <linkmauve AT linkmauve.fr>
# Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
from datetime import datetime
from pathlib import Path
from urllib.parse import unquote
from gi.repository import GLib, Gio, Gtk
import nbxmpp
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import Gtk
import gajim
from gajim.common import app
from gajim.common import i18n
from gajim.common import ged
from gajim.common import configpaths
from gajim.common import logging_helpers
from gajim.common import exceptions
from gajim.common import caps_cache
from gajim.common import logger
from gajim.common.i18n import _
class GajimApplication(Gtk.Application):
'''Main class handling activation and command line.'''
def __init__(self):
Gtk.Application.__init__(self, application_id='org.gajim.Gajim',
flags=(
Gio.ApplicationFlags.HANDLES_COMMAND_LINE |
Gio.ApplicationFlags.HANDLES_OPEN))
flags = (Gio.ApplicationFlags.HANDLES_COMMAND_LINE |
Gio.ApplicationFlags.HANDLES_OPEN)
Gtk.Application.__init__(self,
application_id='org.gajim.Gajim',
flags=flags)
self.add_main_option(
'version',
ord('V'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show the application\'s version'))
self.add_main_option(
'quiet',
ord('q'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show only critical errors'))
self.add_main_option(
'separate',
ord('s'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Separate profile files completely '
'(even history database and plugins)'))
self.add_main_option(
'verbose',
ord('v'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Print XML stanzas and other debug information'))
self.add_main_option(
'profile',
ord('p'),
GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Use defined profile in configuration directory'),
'NAME')
self.add_main_option(
'config-path',
ord('c'),
GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Set configuration directory'),
'PATH')
self.add_main_option(
'loglevel',
ord('l'),
GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Configure logging system'),
'LEVEL')
self.add_main_option(
'warnings',
ord('w'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show all warnings'))
self.add_main_option(
'ipython',
ord('i'),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Open IPython shell'))
self.add_main_option(
'show-next-pending-event',
0,
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Pops up a window with the next pending event'))
self.add_main_option(
'start-chat', 0,
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Start a new chat'))
self.add_main_option(
'simulate-network-lost',
0,
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Simulate loss of connectivity'))
self.add_main_option(
'simulate-network-connected',
0,
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Simulate regaining connectivity'))
self.add_main_option('version', ord('V'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show the application\'s version'))
self.add_main_option('quiet', ord('q'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show only critical errors'))
self.add_main_option('separate', ord('s'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Separate profile files completely (even '
'history database and plugins)'))
self.add_main_option('verbose', ord('v'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Print XML stanzas and other debug '
'information'))
self.add_main_option('profile', ord('p'), GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Use defined profile in configuration '
'directory'), 'NAME')
self.add_main_option('config-path', ord('c'), GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Set configuration directory'), 'PATH')
self.add_main_option('loglevel', ord('l'), GLib.OptionFlags.NONE,
GLib.OptionArg.STRING,
_('Configure logging system'), 'LEVEL')
self.add_main_option('warnings', ord('w'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Show all warnings'))
self.add_main_option('ipython', ord('i'), GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Open IPython shell'))
self.add_main_option('show-next-pending-event', 0, GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Pops up a window with the next pending event'))
self.add_main_option('start-chat', 0, GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
_('Start a new chat'))
self.add_main_option_entries(self._get_remaining_entry())
@ -132,20 +193,24 @@ class GajimApplication(Gtk.Application):
caps_cache.initialize(app.logger)
except exceptions.DatabaseMalformed as error:
dlg = Gtk.MessageDialog(
None,
Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.OK,
_('Database Error'))
transient_for=None,
destroy_with_parent=True,
modal=True,
message_type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
text=_('Database Error'))
dlg.format_secondary_text(str(error))
dlg.run()
dlg.destroy()
sys.exit()
from gajim.gtk.util import load_user_iconsets
load_user_iconsets()
# Set Application Menu
app.app = self
from gajim import gtkgui_helpers
builder = gtkgui_helpers.get_gtk_builder('application_menu.ui')
from gajim.gtk.util import get_builder
builder = get_builder('application_menu.ui')
menubar = builder.get_object("menubar")
appmenu = builder.get_object("appmenu")
if app.prefers_app_menu():
@ -166,6 +231,10 @@ class GajimApplication(Gtk.Application):
from gajim import gui_menu_builder
gui_menu_builder.build_accounts_menu()
app.ged.register_event_handler('feature-discovered',
ged.CORE,
self._on_feature_discovered)
def _open_uris(self, uris):
for uri in uris:
app.log('uri_handler').info('open %s', uri)
@ -186,11 +255,12 @@ class GajimApplication(Gtk.Application):
attributes = cmd.split(';')
message = None
for key in attributes:
if key.startswith('body'):
try:
message = unquote(key.split('=')[1])
except Exception:
app.log('uri_handler').error('Invalid URI: %s', cmd)
if not key.startswith('body'):
continue
try:
message = unquote(key.split('=')[1])
except Exception:
app.log('uri_handler').error('Invalid URI: %s', cmd)
accounts = list(app.connections.keys())
if not accounts:
continue
@ -214,10 +284,11 @@ class GajimApplication(Gtk.Application):
# Parse all options that should be executed on a remote instance
options = command_line.get_options_dict()
remote_commands = ['ipython',
'show-next-pending-event',
'start-chat',
]
remote_commands = [
'ipython',
'show-next-pending-event',
'start-chat',
]
remaining = options.lookup_value(GLib.OPTION_REMAINING,
GLib.VariantType.new('as'))
@ -227,6 +298,14 @@ class GajimApplication(Gtk.Application):
self.activate_action(cmd)
return 0
if options.contains('simulate-network-lost'):
app.interface.network_status_changed(None, False)
return 0
if options.contains('simulate-network-connected'):
app.interface.network_status_changed(None, True)
return 0
if remaining is not None:
self._open_uris(remaining.unpack())
return 0
@ -234,9 +313,13 @@ class GajimApplication(Gtk.Application):
self.activate()
return 0
def _handle_local_options(self, application,
def _handle_local_options(self,
application: Gtk.Application,
options: GLib.VariantDict) -> int:
# Parse all options that have to be executed before ::startup
if options.contains('version'):
print(gajim.__version__)
return 0
if options.contains('profile'):
# Incorporate profile name into application id
# to have a single app instance for each profile.
@ -251,7 +334,14 @@ class GajimApplication(Gtk.Application):
configpaths.set_config_root(path)
configpaths.init()
logging_helpers.init()
if app.get_win_debug_mode():
# Redirect has to happen before logging init
self._redirect_output()
logging_helpers.init()
logging_helpers.set_verbose()
else:
logging_helpers.init()
if options.contains('quiet'):
logging_helpers.set_quiet()
@ -278,6 +368,14 @@ class GajimApplication(Gtk.Application):
warnings.showwarning = warn_with_traceback
warnings.filterwarnings(action="always")
@staticmethod
def _redirect_output():
debug_folder = Path(configpaths.get('DEBUG'))
date = datetime.today().strftime('%Y-%m-%d')
filename = '%s-debug.log' % date
fd = open(debug_folder / filename, 'a')
sys.stderr = sys.stdout = fd
def add_actions(self):
''' Build Application Actions '''
from gajim import app_actions
@ -290,11 +388,6 @@ class GajimApplication(Gtk.Application):
act.connect('change-state', app_actions.on_merge_accounts)
self.add_action(act)
act = Gio.SimpleAction.new_stateful(
'agent', None,
GLib.Variant.new_boolean(app.config.get('use_gpg_agent')))
self.add_action(act)
# General Actions
general_actions = [
@ -323,6 +416,19 @@ class GajimApplication(Gtk.Application):
act.connect("activate", app_actions.on_add_contact_jid)
self.add_action(act)
act = Gio.SimpleAction.new('copy-text', GLib.VariantType.new('s'))
act.connect("activate", app_actions.copy_text)
self.add_action(act)
act = Gio.SimpleAction.new('open-link', GLib.VariantType.new('s'))
act.connect("activate", app_actions.open_link)
self.add_action(act)
act = Gio.SimpleAction.new('browse-history',
GLib.VariantType.new('a{sv}'))
act.connect("activate", app_actions.on_browse_history)
self.add_action(act)
for action in general_actions:
action_name, func = action
act = Gio.SimpleAction.new(action_name, None)
@ -339,33 +445,33 @@ class GajimApplication(Gtk.Application):
self.add_account_actions(accounts_list[0])
def _get_account_actions(self, account):
from gajim import app_actions
from gajim import app_actions as a
if account == 'Local':
return [
('-xml-console', app_actions.on_xml_console, 'always', 's')
('-xml-console', a.on_xml_console, 'always', 's')
]
return [
('-start-single-chat', app_actions.on_single_message, 'online', 's'),
('-join-groupchat', app_actions.on_join_gc, 'online', 's'),
('-add-contact', app_actions.on_add_contact, 'online', 's'),
('-services', app_actions.on_service_disco, 'online', 's'),
('-profile', app_actions.on_profile, 'feature', 's'),
('-xml-console', app_actions.on_xml_console, 'always', 's'),
('-server-info', app_actions.on_server_info, 'online', 's'),
('-archive', app_actions.on_mam_preferences, 'feature', 's'),
('-sync-history', app_actions.on_history_sync, 'online', 's'),
('-privacylists', app_actions.on_privacy_lists, 'feature', 's'),
('-send-server-message',
app_actions.on_send_server_message, 'online', 's'),
('-set-motd', app_actions.on_set_motd, 'online', 's'),
('-update-motd', app_actions.on_update_motd, 'online', 's'),
('-delete-motd', app_actions.on_delete_motd, 'online', 's'),
('-activate-bookmark',
app_actions.on_activate_bookmark, 'online', 'a{sv}'),
('-open-event', app_actions.on_open_event, 'always', 'a{sv}'),
('-import-contacts', app_actions.on_import_contacts, 'online', 's'),
('-start-single-chat', a.on_single_message, 'online', 's'),
('-start-chat', a.start_chat, 'online', 'as'),
('-join-groupchat', a.on_join_gc, 'online', 'as'),
('-add-contact', a.on_add_contact, 'online', 'as'),
('-services', a.on_service_disco, 'online', 's'),
('-profile', a.on_profile, 'feature', 's'),
('-xml-console', a.on_xml_console, 'always', 's'),
('-server-info', a.on_server_info, 'online', 's'),
('-archive', a.on_mam_preferences, 'feature', 's'),
('-sync-history', a.on_history_sync, 'online', 's'),
('-privacylists', a.on_privacy_lists, 'feature', 's'),
('-blocking', a.on_blocking_list, 'feature', 's'),
('-send-server-message', a.on_send_server_message, 'online', 's'),
('-set-motd', a.on_set_motd, 'online', 's'),
('-update-motd', a.on_update_motd, 'online', 's'),
('-delete-motd', a.on_delete_motd, 'online', 's'),
('-activate-bookmark', a.on_activate_bookmark, 'online', 'a{sv}'),
('-open-event', a.on_open_event, 'always', 'a{sv}'),
('-import-contacts', a.on_import_contacts, 'online', 's'),
]
def add_account_actions(self, account):
@ -396,3 +502,17 @@ class GajimApplication(Gtk.Application):
elif new_state and state == 'online':
# We go online
self.lookup_action(account + action_name).set_enabled(True)
def _on_feature_discovered(self, event):
if event.feature == nbxmpp.NS_VCARD:
action = '%s-profile' % event.account
self.lookup_action(action).set_enabled(True)
elif event.feature in (nbxmpp.NS_MAM_1, nbxmpp.NS_MAM_2):
action = '%s-archive' % event.account
self.lookup_action(action).set_enabled(True)
elif event.feature == nbxmpp.NS_PRIVACY:
action = '%s-privacylists' % event.account
self.lookup_action(action).set_enabled(True)
elif event.feature == nbxmpp.NS_BLOCKING:
action = '%s-blocking' % event.account
self.lookup_action(action).set_enabled(True)

View file

@ -1,152 +0,0 @@
# -*- coding:utf-8 -*-
## src/atom_window.py
##
## Copyright (C) 2006 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
from gi.repository import Gdk
from gi.repository import GLib
from gajim import gtkgui_helpers
from gajim.common import helpers
from gajim.common import i18n
class AtomWindow:
window = None
entries = []
@classmethod
def newAtomEntry(cls, entry):
"""
Queue new entry, open window if there's no one opened
"""
cls.entries.append(entry)
if cls.window is None:
cls.window = AtomWindow()
else:
cls.window.updateCounter()
@classmethod
def windowClosed(cls):
cls.window = None
def __init__(self):
"""
Create new window... only if we have anything to show
"""
assert len(self.__class__.entries)
self.entry = None # the entry actually displayed
self.xml = gtkgui_helpers.get_gtk_builder('atom_entry_window.ui')
self.window = self.xml.get_object('atom_entry_window')
for name in ('new_entry_label', 'feed_title_label',
'feed_title_eventbox', 'feed_tagline_label', 'entry_title_label',
'entry_title_eventbox', 'last_modified_label', 'close_button',
'next_button'):
self.__dict__[name] = self.xml.get_object(name)
self.displayNextEntry()
self.xml.connect_signals(self)
self.window.show_all()
self.entry_title_eventbox.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.feed_title_eventbox.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
def displayNextEntry(self):
"""
Get next entry from the queue and display it in the window
"""
assert len(self.__class__.entries)>0
newentry = self.__class__.entries.pop(0)
# fill the fields
if newentry.feed_link is not None:
self.feed_title_label.set_markup(
'<span foreground="blue" underline="single">%s</span>' % \
GLib.markup_escape_text(newentry.feed_title))
else:
self.feed_title_label.set_markup(GLib.markup_escape_text(
newentry.feed_title))
self.feed_tagline_label.set_markup(
'<small>%s</small>' % GLib.markup_escape_text(
newentry.feed_tagline))
if newentry.title:
if newentry.uri is not None:
self.entry_title_label.set_markup(
'<span foreground="blue" underline="single">%s</span>' % \
GLib.markup_escape_text(newentry.title))
else:
self.entry_title_label.set_markup(GLib.markup_escape_text(
newentry.title))
else:
self.entry_title_label.set_markup('')
self.last_modified_label.set_text(newentry.updated)
# update the counters
self.updateCounter()
self.entry = newentry
def updateCounter(self):
"""
Display number of events on the top of window, sometimes it needs to be
changed
"""
count = len(self.__class__.entries)
if count:
self.new_entry_label.set_text(i18n.ngettext(
'You have received new entries (and %d not displayed):',
'You have received new entries (and %d not displayed):', count,
count, count))
self.next_button.set_sensitive(True)
else:
self.new_entry_label.set_text(_('You have received new entry:'))
self.next_button.set_sensitive(False)
def on_close_button_clicked(self, widget):
self.window.destroy()
self.windowClosed()
def on_next_button_clicked(self, widget):
self.displayNextEntry()
def on_entry_title_eventbox_button_press_event(self, widget, event):
#FIXME: make it using special gtk2.10 widget
if event.button == 1: # left click
uri = self.entry.uri
if uri is not None:
helpers.launch_browser_mailer('url', uri)
return True
def on_feed_title_eventbox_button_press_event(self, widget, event):
#FIXME: make it using special gtk2.10 widget
if event.button == 1: # left click
uri = self.entry.feed_uri
if uri is not None:
helpers.launch_browser_mailer('url', uri)
return True

View file

@ -1,159 +0,0 @@
# -*- coding:utf-8 -*-
## src/cell_renderer_image.py
##
## Copyright (C) 2003-2014 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2005 Vincent Hanquez <tab AT snarc.org>
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006 Travis Shirk <travis AT pobox.com>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
from gi.repository import GLib
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject
class CellRendererImage(Gtk.CellRendererPixbuf):
__gproperties__ = {
'image': (GObject.TYPE_OBJECT, 'Image',
'Image', GObject.ParamFlags.READWRITE),
}
def __init__(self, col_index, tv_index):
super(CellRendererImage, self).__init__()
self.image = None
self.col_index = col_index
self.tv_index = tv_index
self.iters = {}
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
def do_get_property(self, pspec):
return getattr(self, pspec.name)
def do_activate(event, widget, path, bg_area, cell_area, flags):
"""Renderers cannot be activated; always return True."""
return True
def do_editing_started(event, widget, path, fb_area, cell_area, flags):
"""Renderers cannot be edited; always return None."""
return None
def func(self, model, path, iter_, image_tree):
image, tree = image_tree
if model.get_value(iter_, self.tv_index) != image:
return
self.redraw = 1
col = tree.get_column(self.col_index)
cell_area = tree.get_cell_area(path, col)
tree.queue_draw_area(cell_area.x, cell_area.y, cell_area.width,
cell_area.height)
def animation_timeout(self, tree, image):
if image.get_storage_type() != Gtk.ImageType.ANIMATION:
return
self.redraw = 0
iter_ = self.iters[image]
timeval = GLib.TimeVal()
timeval.tv_sec = GLib.get_monotonic_time() / 1000000
iter_.advance(timeval)
model = tree.get_model()
if model:
model.foreach(self.func, (image, tree))
if self.redraw:
GLib.timeout_add(iter_.get_delay_time(),
self.animation_timeout, tree, image)
elif image in self.iters:
del self.iters[image]
def do_render(self, ctx, widget, background_area, cell_area, flags):
if not self.image:
return
if self.image.get_storage_type() == Gtk.ImageType.ANIMATION:
if self.image not in self.iters:
if not isinstance(widget, Gtk.TreeView):
return
animation = self.image.get_animation()
timeval = GLib.TimeVal()
timeval.tv_sec = GLib.get_monotonic_time() / 1000000
iter_ = animation.get_iter(timeval)
self.iters[self.image] = iter_
GLib.timeout_add(iter_.get_delay_time(), self.animation_timeout,
widget, self.image)
pix = self.iters[self.image].get_pixbuf()
elif self.image.get_storage_type() == Gtk.ImageType.PIXBUF:
pix = self.image.get_pixbuf()
else:
return
calc_width = self.get_property('xpad') * 2 + pix.get_width()
calc_height = self.get_property('ypad') * 2 + pix.get_height()
x_pos = cell_area.x + self.get_property('xalign') * \
(cell_area.width - calc_width - self.get_property('xpad'))
y_pos = cell_area.y + self.get_property('yalign') * \
(cell_area.height - calc_height - self.get_property('ypad'))
Gdk.cairo_set_source_pixbuf(ctx, pix, x_pos, y_pos)
ctx.paint()
def do_get_preferred_height(self, widget):
"""
Return the height we need for this cell.
Each cell is drawn individually and is only as wide as it needs
to be, we let the TreeViewColumn take care of making them all
line up.
"""
if not self.image:
return 0, 0
if self.image.get_storage_type() == Gtk.ImageType.ANIMATION:
animation = self.image.get_animation()
timeval = GLib.TimeVal()
timeval.tv_sec = GLib.get_monotonic_time() / 1000000
pix = animation.get_iter(timeval).get_pixbuf()
elif self.image.get_storage_type() == Gtk.ImageType.PIXBUF:
pix = self.image.get_pixbuf()
else:
return 0, 0, 0, 0
calc_height = self.get_property('ypad') * 2 + pix.get_height()
return calc_height, calc_height
def do_get_preferred_width(self, widget):
"""
Return the width we need for this cell.
Each cell is drawn individually and is only as wide as it needs
to be, we let the TreeViewColumn take care of making them all
line up.
"""
if not self.image:
return 0, 0
if self.image.get_storage_type() == Gtk.ImageType.ANIMATION:
animation = self.image.get_animation()
timeval = GLib.TimeVal()
timeval.tv_sec = GLib.get_monotonic_time() / 1000000
pix = animation.get_iter(timeval).get_pixbuf()
elif self.image.get_storage_type() == Gtk.ImageType.PIXBUF:
pix = self.image.get_pixbuf()
else:
return 0, 0, 0, 0
calc_width = self.get_property('xpad') * 2 + pix.get_width()
return calc_width, calc_width

View file

@ -1,58 +1,75 @@
# -*- coding:utf-8 -*-
## src/chat_control.py
##
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Nikos Kouremenos <kourem AT gmail.com>
## Travis Shirk <travis AT pobox.com>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## Julien Pivotto <roidelapluie AT gmail.com>
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
## Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##
# Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
# Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
# Nikos Kouremenos <kourem AT gmail.com>
# Travis Shirk <travis AT pobox.com>
# Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
# Julien Pivotto <roidelapluie AT gmail.com>
# Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
# Stephan Erb <steve-e AT h3c.de>
# Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
from typing import ClassVar # pylint: disable=unused-import
from typing import Type # pylint: disable=unused-import
import os
import time
from gi.repository import Gtk
from gi.repository import Gio
from gi.repository import Pango
from gi.repository import GLib
from gajim import gtkgui_helpers
from gajim import gui_menu_builder
from gajim import message_control
from gajim import dialogs
from gajim.gtk import ConfirmationDialog
from gajim.gtk import AddNewContactWindow
from nbxmpp.protocol import NS_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC
from nbxmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO
from nbxmpp.protocol import NS_JINGLE_ICE_UDP, NS_JINGLE_FILE_TRANSFER_5
from gajim.common import app
from gajim.common import helpers
from gajim.common import ged
from gajim.common import i18n
from gajim.common.i18n import _
from gajim.common.helpers import AdditionalDataDict
from gajim.common.helpers import open_uri
from gajim.common.helpers import geo_provider_from_location
from gajim.common.contacts import GC_Contact
from nbxmpp.protocol import NS_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC
from nbxmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO
from nbxmpp.protocol import NS_JINGLE_ICE_UDP, NS_JINGLE_FILE_TRANSFER_5
from nbxmpp.protocol import NS_CHATSTATES
from gajim.common.connection_handlers_events import MessageOutgoingEvent
from gajim.common.const import AvatarSize, KindConstant
from gajim.common.const import AvatarSize
from gajim.common.const import KindConstant
from gajim.common.const import Chatstate
from gajim.common.const import PEPEventType
from gajim import gtkgui_helpers
from gajim import gui_menu_builder
from gajim import message_control
from gajim import dialogs
from gajim.gtk.dialogs import NewConfirmationDialog
from gajim.gtk.dialogs import DialogButton
from gajim.gtk.add_contact import AddNewContactWindow
from gajim.gtk.util import get_icon_name
from gajim.gtk.util import get_cursor
from gajim.gtk.util import ensure_proper_control
from gajim.gtk.util import format_mood
from gajim.gtk.util import format_activity
from gajim.gtk.util import format_tune
from gajim.gtk.util import format_location
from gajim.gtk.util import get_activity_icon_name
from gajim.command_system.implementation.hosts import ChatCommands
from gajim.command_system.framework import CommandHost # pylint: disable=unused-import
from gajim.chat_control_base import ChatControlBase
################################################################################
@ -73,7 +90,7 @@ class ChatControl(ChatControlBase):
# Set a command host to bound to. Every command given through a chat will be
# processed with this command host.
COMMAND_HOST = ChatCommands
COMMAND_HOST = ChatCommands # type: ClassVar[Type[CommandHost]]
def __init__(self, parent_win, contact, acct, session, resource=None):
ChatControlBase.__init__(self, self.TYPE_ID, parent_win,
@ -105,7 +122,7 @@ class ChatControl(ChatControlBase):
# Menu for the HeaderBar
self.control_menu = gui_menu_builder.get_singlechat_menu(
self.control_id)
self.control_id, self.account, self.contact.jid)
settings_menu = self.xml.get_object('settings_menu')
settings_menu.set_menu_model(self.control_menu)
@ -119,22 +136,10 @@ class ChatControl(ChatControlBase):
self.video_available = False
self.update_toolbar()
self._pep_images = {}
self._pep_images['mood'] = self.xml.get_object('mood_image')
self._pep_images['activity'] = self.xml.get_object('activity_image')
self._pep_images['tune'] = self.xml.get_object('tune_image')
self._pep_images['geoloc'] = self.xml.get_object('location_image')
self.update_all_pep_types()
self.show_avatar()
# Hook up signals
message_tv_buffer = self.msg_textview.get_buffer()
id_ = message_tv_buffer.connect('changed',
self._on_message_tv_buffer_changed)
self.handlers[id_] = message_tv_buffer
widget = self.xml.get_object('avatar_eventbox')
widget.set_property('height-request', AvatarSize.CHAT)
@ -160,16 +165,6 @@ class ChatControl(ChatControlBase):
id_ = widget.connect('released', self.on_num_button_released)
self.handlers[id_] = widget
self.dtmf_window = self.xml.get_object('dtmf_window')
self.dtmf_window.get_child().set_direction(Gtk.TextDirection.LTR)
id_ = self.dtmf_window.connect('focus-out-event',
self.on_dtmf_window_focus_out_event)
self.handlers[id_] = self.dtmf_window
widget = self.xml.get_object('dtmf_button')
id_ = widget.connect('clicked', self.on_dtmf_button_clicked)
self.handlers[id_] = widget
widget = self.xml.get_object('mic_hscale')
id_ = widget.connect('value_changed', self.on_mic_hscale_value_changed)
self.handlers[id_] = widget
@ -203,7 +198,7 @@ class ChatControl(ChatControlBase):
session = app.connections[self.account].find_controlless_session(
self.contact.jid, resource)
self.setup_seclabel(self.xml.get_object('label_selector'))
self.setup_seclabel()
if session:
session.control = self
self.session = session
@ -223,8 +218,18 @@ class ChatControl(ChatControlBase):
self.restore_conversation()
self.msg_textview.grab_focus()
app.ged.register_event_handler('pep-received', ged.GUI1,
self._nec_pep_received)
app.ged.register_event_handler('nickname-received', ged.GUI1,
self._on_nickname_received)
app.ged.register_event_handler('mood-received', ged.GUI1,
self._on_mood_received)
app.ged.register_event_handler('activity-received', ged.GUI1,
self._on_activity_received)
app.ged.register_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
app.ged.register_event_handler('location-received', ged.GUI1,
self._on_location_received)
app.ged.register_event_handler('update-client-info', ged.GUI1,
self._on_update_client_info)
if self.TYPE_ID == message_control.TYPE_CHAT:
# Dont connect this when PrivateChatControl is used
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
@ -276,6 +281,17 @@ class ChatControl(ChatControlBase):
self.video_action.connect('change-state', self._on_video)
self.parent_win.window.add_action(self.video_action)
default_chatstate = app.config.get('send_chatstate_default')
chatstate = app.config.get_per(
'contacts', self.contact.jid, 'send_chatstate', default_chatstate)
act = Gio.SimpleAction.new_stateful(
'send-chatstate-' + self.control_id,
GLib.VariantType.new("s"),
GLib.Variant("s", chatstate))
act.connect('change-state', self._on_send_chatstate)
self.parent_win.window.add_action(act)
def update_actions(self):
win = self.parent_win.window
online = app.account_is_connected(self.account)
@ -363,6 +379,11 @@ class ChatControl(ChatControlBase):
state = param.get_boolean()
self.on_jingle_button_toggled(state, 'video')
def _on_send_chatstate(self, action, param):
action.set_state(param)
app.config.set_per('contacts', self.contact.jid,
'send_chatstate', param.get_string())
def subscribe_events(self):
"""
Register listeners to the events class
@ -386,12 +407,8 @@ class ChatControl(ChatControlBase):
'Show a list of formattings'))
else:
self._formattings_button.set_sensitive(False)
if self.contact.supports(NS_XHTML_IM):
self._formattings_button.set_tooltip_text(_('Formatting is not '
'available so long as GPG is active'))
else:
self._formattings_button.set_tooltip_text(_('This contact does '
'not support HTML'))
self._formattings_button.set_tooltip_text(
_('This contact does not support HTML'))
# Jingle detection
if self.contact.supports(NS_JINGLE_ICE_UDP) and \
@ -405,35 +422,74 @@ class ChatControl(ChatControlBase):
self.audio_available = False
def update_all_pep_types(self):
for pep_type in self._pep_images:
self.update_pep(pep_type)
self._update_pep(PEPEventType.LOCATION)
self._update_pep(PEPEventType.MOOD)
self._update_pep(PEPEventType.ACTIVITY)
self._update_pep(PEPEventType.TUNE)
def update_pep(self, pep_type):
if isinstance(self.contact, GC_Contact):
return
if pep_type not in self._pep_images:
return
pep = self.contact.pep
img = self._pep_images[pep_type]
if pep_type in pep:
img.set_from_pixbuf(gtkgui_helpers.get_pep_as_pixbuf(pep[pep_type]))
img.set_tooltip_markup(pep[pep_type].asMarkupText())
img.show()
else:
img.hide()
def _nec_pep_received(self, obj):
if obj.conn.name != self.account:
return
if obj.jid != self.contact.jid:
def _update_pep(self, type_):
image = self._get_pep_widget(type_)
data = self.contact.pep.get(type_)
if data is None:
image.hide()
return
if obj.pep_type == 'nick':
self.update_ui()
self.parent_win.redraw_tab(self)
self.parent_win.show_title()
else:
self.update_pep(obj.pep_type)
if type_ == PEPEventType.MOOD:
icon = 'mood-%s' % data.mood
formated_text = format_mood(*data)
elif type_ == PEPEventType.ACTIVITY:
icon = get_activity_icon_name(data.activity, data.subactivity)
formated_text = format_activity(*data)
elif type_ == PEPEventType.TUNE:
icon = 'audio-x-generic'
formated_text = format_tune(*data)
elif type_ == PEPEventType.LOCATION:
icon = 'applications-internet'
formated_text = format_location(data)
image.set_from_icon_name(icon, Gtk.IconSize.MENU)
image.set_tooltip_markup(formated_text)
image.show()
def _get_pep_widget(self, type_):
if type_ == PEPEventType.MOOD:
return self.xml.get_object('mood_image')
if type_ == PEPEventType.ACTIVITY:
return self.xml.get_object('activity_image')
if type_ == PEPEventType.TUNE:
return self.xml.get_object('tune_image')
if type_ == PEPEventType.LOCATION:
return self.xml.get_object('location_image')
@ensure_proper_control
def _on_mood_received(self, _event):
self._update_pep(PEPEventType.MOOD)
@ensure_proper_control
def _on_activity_received(self, _event):
self._update_pep(PEPEventType.ACTIVITY)
@ensure_proper_control
def _on_tune_received(self, _event):
self._update_pep(PEPEventType.TUNE)
@ensure_proper_control
def _on_location_received(self, _event):
self._update_pep(PEPEventType.LOCATION)
@ensure_proper_control
def _on_nickname_received(self, _event):
self.update_ui()
self.parent_win.redraw_tab(self)
self.parent_win.show_title()
@ensure_proper_control
def _on_update_client_info(self, event):
contact = app.contacts.get_contact(
self.account, event.jid, event.resource)
if contact is None:
return
self.xml.get_object('phone_image').set_visible(contact.uses_phone)
def _update_jingle(self, jingle_type):
if jingle_type not in ('audio', 'video'):
@ -446,16 +502,16 @@ class ChatControl(ChatControlBase):
banner_image.show()
if state == self.JINGLE_STATE_CONNECTING:
banner_image.set_from_icon_name(
Gtk.STOCK_CONVERT, Gtk.IconSize.MENU)
'network-transmit-symbolic', Gtk.IconSize.MENU)
elif state == self.JINGLE_STATE_CONNECTION_RECEIVED:
banner_image.set_from_icon_name(
"network-workgroup", Gtk.IconSize.MENU)
'network-receive-symbolic', Gtk.IconSize.MENU)
elif state == self.JINGLE_STATE_CONNECTED:
banner_image.set_from_icon_name(
Gtk.STOCK_CONNECT, Gtk.IconSize.MENU)
'network-transmit-receive-symbolic', Gtk.IconSize.MENU)
elif state == self.JINGLE_STATE_ERROR:
banner_image.set_from_icon_name(
"dialog-warning", Gtk.IconSize.MENU)
'network-error-symbolic', Gtk.IconSize.MENU)
self.update_toolbar()
def update_audio(self):
@ -538,7 +594,7 @@ class ChatControl(ChatControlBase):
self._set_jingle_state('video', state, sid=sid, reason=reason)
def _get_audio_content(self):
session = app.connections[self.account].get_jingle_session(
session = app.connections[self.account].get_module('Jingle').get_jingle_session(
self.contact.get_full_jid(), self.audio_sid)
return session.get_content('audio')
@ -548,12 +604,6 @@ class ChatControl(ChatControlBase):
def on_num_button_released(self, released):
self._get_audio_content()._stop_dtmf()
def on_dtmf_button_clicked(self, widget):
self.dtmf_window.show_all()
def on_dtmf_window_focus_out_event(self, widget, event):
self.dtmf_window.hide()
def on_mic_hscale_value_changed(self, widget, value):
self._get_audio_content().set_mic_volume(value / 100)
# Save volume to config
@ -569,8 +619,6 @@ class ChatControl(ChatControlBase):
If right-clicked, show popup
"""
if event.button == 3: # right click
menu = Gtk.Menu()
menuitem = Gtk.MenuItem.new_with_mnemonic(_('Save _As'))
if self.TYPE_ID == message_control.TYPE_CHAT:
sha = app.contacts.get_avatar_sha(
self.account, self.contact.jid)
@ -578,36 +626,27 @@ class ChatControl(ChatControlBase):
else:
sha = self.gc_contact.avatar_sha
name = self.gc_contact.get_shown_name()
id_ = menuitem.connect('activate',
gtkgui_helpers.on_avatar_save_as_menuitem_activate, sha, name)
self.handlers[id_] = menuitem
menu.append(menuitem)
menu.show_all()
menu.connect('selection-done', lambda w: w.destroy())
# show the menu
menu.show_all()
menu.attach_to_widget(widget, None)
menu.popup(None, None, None, None, event.button, event.time)
if sha is not None:
gui_menu_builder.show_save_as_menu(sha, name)
return True
def on_location_eventbox_button_release_event(self, widget, event):
if 'geoloc' in self.contact.pep:
location = self.contact.pep['geoloc']._pep_specific_data
if ('lat' in location) and ('lon' in location):
uri = 'https://www.openstreetmap.org/?' + \
'mlat=%(lat)s&mlon=%(lon)s&zoom=16' % {'lat': location['lat'],
'lon': location['lon']}
helpers.launch_browser_mailer('url', uri)
location = self.contact.pep['geoloc'].data
if 'lat' in location and 'lon' in location:
uri = geo_provider_from_location(location['lat'],
location['lon'])
open_uri(uri)
def on_location_eventbox_leave_notify_event(self, widget, event):
"""
Just moved the mouse so show the cursor
"""
cursor = gtkgui_helpers.get_cursor('LEFT_PTR')
cursor = get_cursor('LEFT_PTR')
self.parent_win.window.get_window().set_cursor(cursor)
def on_location_eventbox_enter_notify_event(self, widget, event):
cursor = gtkgui_helpers.get_cursor('HAND2')
cursor = get_cursor('HAND2')
self.parent_win.window.get_window().set_cursor(cursor)
def update_ui(self):
@ -616,16 +655,15 @@ class ChatControl(ChatControlBase):
self.update_toolbar()
def _update_banner_state_image(self):
contact = app.contacts.get_contact_with_highest_priority(self.account,
self.contact.jid)
contact = app.contacts.get_contact_with_highest_priority(
self.account, self.contact.jid)
if not contact or self.resource:
# For transient contacts
contact = self.contact
show = contact.show
jid = contact.jid
# Set banner image
icon = gtkgui_helpers.get_iconset_name_for(show)
icon = get_icon_name(show)
banner_status_img = self.xml.get_object('banner_status_image')
banner_status_img.set_from_icon_name(icon, Gtk.IconSize.DND)
@ -663,7 +701,8 @@ class ChatControl(ChatControlBase):
if other_contact_.get_shown_name() == \
self.contact.get_shown_name():
acct_info = i18n.direction_mark + ' (%s)' % \
GLib.markup_escape_text(self.account)
GLib.markup_escape_text(
app.get_account_label(self.account))
break
status = contact.status
@ -675,15 +714,14 @@ class ChatControl(ChatControlBase):
status_reduced = ''
status_escaped = GLib.markup_escape_text(status_reduced)
st = app.config.get('displayed_chat_state_notifications')
cs = contact.chatstate
if cs and st in ('composing_only', 'all'):
if contact.show == 'offline':
chatstate = ''
elif st == 'all' or cs == 'composing':
chatstate = helpers.get_uf_chatstate(cs)
else:
chatstate = ''
if self.TYPE_ID == 'pm':
cs = self.gc_contact.chatstate
else:
cs = app.contacts.get_combined_chatstate(
self.account, self.contact.jid)
if app.config.get('show_chatstate_in_banner'):
chatstate = helpers.get_uf_chatstate(cs)
label_text = '<span>%s</span><span size="x-small" weight="light">%s %s</span>' \
% (name, acct_info, chatstate)
@ -719,8 +757,8 @@ class ChatControl(ChatControlBase):
return
setattr(self, jingle_type + '_sid', None)
setattr(self, jingle_type + '_state', self.JINGLE_STATE_NULL)
session = app.connections[self.account].get_jingle_session(
self.contact.get_full_jid(), sid)
session = app.connections[self.account].get_module('Jingle').get_jingle_session(
self.contact.get_full_jid(), sid)
if session:
content = session.get_content(jingle_type)
if content:
@ -730,10 +768,6 @@ class ChatControl(ChatControlBase):
getattr(self, 'update_' + jingle_type)()
def on_jingle_button_toggled(self, state, jingle_type):
img_name = 'gajim-%s_%s' % ({'audio': 'mic', 'video': 'cam'}[jingle_type],
{True: 'active', False: 'inactive'}[state])
path_to_img = gtkgui_helpers.get_icon_path(img_name)
if state:
if getattr(self, jingle_type + '_state') == \
self.JINGLE_STATE_NULL:
@ -756,7 +790,7 @@ class ChatControl(ChatControlBase):
in_da = self.xml.get_object('incoming_drawingarea')
in_da.realize()
in_xid = in_da.get_window().get_xid()
sid = app.connections[self.account].start_video(
sid = app.connections[self.account].get_module('Jingle').start_video(
self.contact.get_full_jid(), in_xid, out_xid)
else:
sid = getattr(app.connections[self.account],
@ -771,8 +805,6 @@ class ChatControl(ChatControlBase):
self.close_jingle_content(jingle_type)
def set_lock_image(self):
loggable = self.session and self.session.is_loggable()
encryption_state = {'visible': self.encryption is not None,
'enc_type': self.encryption,
'authenticated': False}
@ -790,17 +822,17 @@ class ChatControl(ChatControlBase):
if authenticated:
authenticated_string = _('and authenticated')
self.lock_image.set_from_icon_name(
'security-high', Gtk.IconSize.MENU)
'security-high-symbolic', Gtk.IconSize.MENU)
else:
authenticated_string = _('and NOT authenticated')
self.lock_image.set_from_icon_name(
'security-low', Gtk.IconSize.MENU)
'security-low-symbolic', Gtk.IconSize.MENU)
tooltip = _('%(type)s encryption is active %(authenticated)s.') % {'type': enc_type, 'authenticated': authenticated_string}
tooltip = _('%(type)s encryption is active %(authenticated)s') % \
{'type': enc_type, 'authenticated': authenticated_string}
self.authentication_button.set_tooltip_text(tooltip)
self.widget_set_visible(self.authentication_button, not visible)
context = self.msg_scrolledwindow.get_style_context()
self.lock_image.set_sensitive(visible)
def _on_authentication_button_clicked(self, widget):
@ -823,8 +855,9 @@ class ChatControl(ChatControlBase):
if obj.kind == KindConstant.CHAT_MSG_SENT:
kind = 'outgoing'
self.print_conversation(obj.msgtxt, kind, tim=obj.timestamp,
encrypted=obj.encrypted, correct_id=obj.correct_id,
self.print_conversation(
obj.msgtxt, kind, tim=obj.timestamp,
encrypted=obj.encrypted, correct_id=obj.correct_id,
msg_stanza_id=obj.message_id, additional_data=obj.additional_data)
def _nec_decrypted_message_received(self, obj):
@ -886,8 +919,8 @@ class ChatControl(ChatControlBase):
correct_id=obj.correct_id,
additional_data=obj.additional_data)
def send_message(self, message, keyID='', chatstate=None, xhtml=None,
process_commands=True, attention=False):
def send_message(self, message, xhtml=None,
process_commands=True, attention=False):
"""
Send a message to contact
"""
@ -903,24 +936,12 @@ class ChatControl(ChatControlBase):
if message in ('', None, '\n'):
return None
contact = self.contact
keyID = contact.keyID
chatstates_on = app.config.get('outgoing_chat_state_notifications') != \
'disabled'
chatstate_to_send = None
if contact is not None:
if contact.supports(NS_CHATSTATES):
# send active chatstate on every message (as XEP says)
chatstate_to_send = 'active'
contact.our_chatstate = 'active'
self._schedule_activity_timers()
ChatControlBase.send_message(self, message, keyID, type_='chat',
chatstate=chatstate_to_send, xhtml=xhtml,
process_commands=process_commands, attention=attention)
ChatControlBase.send_message(self,
message,
type_='chat',
xhtml=xhtml,
process_commands=process_commands,
attention=attention)
def get_our_nick(self):
return app.nicks[self.account]
@ -944,7 +965,7 @@ class ChatControl(ChatControlBase):
contact = self.contact
if additional_data is None:
additional_data = {}
additional_data = AdditionalDataDict()
if frm == 'status':
if not app.config.get('print_status_in_chats'):
@ -1031,29 +1052,27 @@ class ChatControl(ChatControlBase):
['printed_' + self.type_id, self.type_id]))
else:
num_unread = 0
# Set tab image (always 16x16); unread messages show the 'event' image
tab_img = None
transport = None
if app.jid_is_transport(jid):
transport = app.get_transport_name_from_jid(jid)
if num_unread and app.config.get('show_unread_tab_icon'):
img_16 = app.interface.roster.get_appropriate_state_images(
self.contact.jid, icon_name='event')
tab_img = img_16['event']
icon_name = get_icon_name('event', transport=transport)
else:
contact = app.contacts.get_contact_with_highest_priority(
self.account, self.contact.jid)
if not contact or self.resource:
# For transient contacts
contact = self.contact
img_16 = app.interface.roster.get_appropriate_state_images(
self.contact.jid, icon_name=contact.show)
tab_img = img_16[contact.show]
icon_name = get_icon_name(contact.show, transport=transport)
return tab_img
return icon_name
def prepare_context_menu(self, hide_buttonbar_items=False):
"""
Set compact view menuitem active state sets active and sensitivity state
for history_menuitem (False for tranasports) and file_transfer_menuitem
for history_menuitem (False for tranasports) and file_transfer_menuitem
and hide()/show() for add_to_roster_menuitem
"""
if app.jid_is_transport(self.contact.jid):
@ -1066,86 +1085,22 @@ class ChatControl(ChatControlBase):
show_buttonbar_items=not hide_buttonbar_items)
return menu
def send_chatstate(self, state, contact=None):
"""
Send OUR chatstate as STANDLONE chat state message (eg. no body)
to contact only if new chatstate is different from the previous one
if jid is not specified, send to active tab
"""
# JEP 85 does not allow resending the same chatstate
# this function checks for that and just returns so it's safe to call it
# with same state.
# This functions also checks for violation in state transitions
# and raises RuntimeException with appropriate message
# more on that http://xmpp.org/extensions/xep-0085.html#statechart
# do not send if we have chat state notifications disabled
# that means we won't reply to the <active/> from other peer
# so we do not broadcast jep85 capabalities
chatstate_setting = app.config.get('outgoing_chat_state_notifications')
if chatstate_setting == 'disabled':
return
# Dont leak presence to contacts
# which are not allowed to see our status
if contact and contact.sub in ('to', 'none'):
return
if self.contact.jid == app.get_jid_from_account(self.account):
return
elif chatstate_setting == 'composing_only' and state != 'active' and\
state != 'composing':
return
if contact is None:
contact = self.parent_win.get_active_contact()
if contact is None:
# contact was from pm in MUC, and left the room so contact is None
# so we cannot send chatstate anymore
return
# Don't send chatstates to offline contacts
if contact.show == 'offline':
return
if not contact.supports(NS_CHATSTATES):
return
if contact.our_chatstate == False:
return
# if the new state we wanna send (state) equals
# the current state (contact.our_chatstate) then return
if contact.our_chatstate == state:
return
# if wel're inactive prevent composing (XEP violation)
if contact.our_chatstate == 'inactive' and state == 'composing':
# go active before
app.log('chatstates').info('%-10s - %s', 'active', self.contact.jid)
app.nec.push_outgoing_event(MessageOutgoingEvent(None,
account=self.account, jid=self.contact.jid, chatstate='active',
control=self))
contact.our_chatstate = 'active'
self.reset_kbd_mouse_timeout_vars()
app.log('chatstates').info('%-10s - %s', state, self.contact.jid)
app.nec.push_outgoing_event(MessageOutgoingEvent(None,
account=self.account, jid=self.contact.jid, chatstate=state,
control=self))
contact.our_chatstate = state
if state == 'active':
self.reset_kbd_mouse_timeout_vars()
def shutdown(self):
# PluginSystem: removing GUI extension points connected with ChatControl
# instance object
app.plugin_manager.remove_gui_extension_point('chat_control', self)
app.ged.remove_event_handler('pep-received', ged.GUI1,
self._nec_pep_received)
app.ged.remove_event_handler('nickname-received', ged.GUI1,
self._on_nickname_received)
app.ged.remove_event_handler('mood-received', ged.GUI1,
self._on_mood_received)
app.ged.remove_event_handler('activity-received', ged.GUI1,
self._on_activity_received)
app.ged.remove_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
app.ged.remove_event_handler('location-received', ged.GUI1,
self._on_location_received)
app.ged.remove_event_handler('update-client-info', ged.GUI1,
self._on_update_client_info)
if self.TYPE_ID == message_control.TYPE_CHAT:
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar)
@ -1168,9 +1123,8 @@ class ChatControl(ChatControlBase):
self.unsubscribe_events()
# Send 'gone' chatstate
self.send_chatstate('gone', self.contact)
self.contact.chatstate = None
self.contact.our_chatstate = None
con = app.connections[self.account]
con.get_module('Chatstate').set_chatstate(self.contact, Chatstate.GONE)
for jingle_type in ('audio', 'video'):
self.close_jingle_content(jingle_type)
@ -1210,35 +1164,45 @@ class ChatControl(ChatControlBase):
def safe_shutdown(self):
return False
def allow_shutdown(self, method, on_yes, on_no, on_minimize):
if time.time() - app.last_message_time[self.account]\
[self.get_full_jid()] < 2:
def allow_shutdown(self, method, on_yes, on_no, _on_minimize):
time_ = app.last_message_time[self.account][self.get_full_jid()]
if time.time() - time_ < 2:
# 2 seconds
def on_ok():
on_yes(self)
def on_cancel():
on_no(self)
ConfirmationDialog(
#%s is being replaced in the code with JID
_('You just received a new message from "%s"') % \
self.contact.jid,
_('If you close this tab and you have history disabled, '\
'this message will be lost.'), on_response_ok=on_ok,
on_response_cancel=on_cancel,
transient_for=self.parent_win.window)
NewConfirmationDialog(
_('Close'),
_('You just received a new message from %s') % self.contact.jid,
_('If you close this tab and you have history disabled, '
'this message will be lost.'),
[DialogButton.make('Cancel',
callback=lambda: on_no(self)),
DialogButton.make('OK',
text=_('Close'),
callback=lambda: on_yes(self))],
transient_for=self.parent_win.window).show()
return
on_yes(self)
def _nec_chatstate_received(self, obj):
"""
Handle incoming chatstate that jid SENT TO us
"""
def _nec_chatstate_received(self, event):
if event.account != self.account:
return
if self.TYPE_ID == 'pm':
if event.contact != self<