This allows us to import the app module without triggering
dependency detection
Also add is_installed() for checking if a dependency is installed and
disable_dependency() in case we dont want to use a dependency
- Move database migration to the logger module
- Dont depend on Gajim version for migration use PRAGMA user_version
- Refactoring of some methods in the logger module
- Dont use cursor object, if there is no reason
- Make some attributes and methods private
- init configpaths earlier so logging can access it to store debug logs
- First step for more consistency across Gajim when looking up paths
Recommended usage for the future:
app.configpaths.get()
configpaths.get()
- Groupchats promote a vcard hash with presence
Refactoring:
- Dont delete groupchat contacts if they are maximized from the roster
- Roster and GroupchatControl use the same contact object
Only print the status, if status has changed or the status message
Clients announce there idle-time with presences but adding a idle-time
does not necessarily mean they went from available -> away
Fixes#9001
For MUCs on the blacklist we do a deduplication not depending on
stanza-id
This patch is only for current Prosody 0.10 stable and the mod_mam_muc
module which does not add stanza-id to the messages.
This can be removed once Prosody 0.11 hits or the module is updated
Don't try to resolve _xmppconnect records for servers before trying to connect.
Prevent warnings from gajim.c.resolver for accounts with "connect on startup" disabled.
This adds a method that returns only a contact if there is an exact match,
instead of a contact where only the barejid matches.
We need this when we update the Caps of a contact.
Its later than StanzaMessageOutgoingEvent, this allows encryption
Plugins to not return the encrypted payload immediatly.
For example encrypting may take some time because a password is needed
or the load has to be encrypted in another Thread.
- Use ComboBoxText, its much simpler
- Add a dedicated method that returns all available themes
- If the configured Theme is not available fallback to font-emoticons
getTimestamp() generates always a timestring with a resolution of seconds and
this means time gets always rounded down.
Because we use a resolution of .00000 precision for outgoing messages this
can lead to wrongly sorted messages.
prosody includes the supplied queryid in the `<fin>` tag, but this is not XEP compliant.
We set the queryid attr so we can match the MAM Messages to our query.
Thats the only purpose, it is not used to identify the iq result at the end of the query.
For that purpose is the `id` attr on the `<iq>` node.
So dont try to parse `queryid` from the `<fin>` tag.
Using a callback to display a sent message inside the ChatControl means
that all messages we send have to be issued from the GUI layer
(send_message()) if we want them to display in the ChatControl.
This replaces the callback and catches the stanza-message-outgoing event
after it was processed by the core.
This is easier to read/understand than dealing with callbacks and lets
the core issue messages without having to care if a ChatControl is open or not
- Complete rewrite of the old Groupchat dialog
- Has now a "minimal" mode, which is used if we have all infos for joining except the nickname and if we want to bookmark
- Handle xmpp uris received via command line
This was somehow lost once we implemented random resource strings
Although its good that initally a random resource is chosen, it
still should persist across sessions.
This helps to kill zombie client connections on the server because
most servers kill the old session once a new with the same resource
connects
Also dont notify the user about resource conflicts if no custom
resource is set. We should not expect users to know about resources
and what they are used for as long as possible.
- Calculating so many hashes for each Message is quite expensive
- It hides our own implementation bugs, like when we retrieve history
from a MUC with wrong timestamps, or on rejoin. We never know about it
because the Messages are dropped.
- It should not be necessary anymore. The original problem was a bug
in nbxmpp which triggered mass resending of old messages.
Right now oob data is merged into the message text and stored into the DB.
If we load this message from the DB we cannot know anymore if and which
parts of the text was oob data.
Use the additional_data api to store oob data into the DB instead of
altering the original message text.
This lets us decide later on if and which data we want to display, even
on history replays. Also plugins can use the data.
- Move ActionBar into HeaderMenu
- Make Design of ChatControl look cleaner
- Hide the Roster in Groupchats per default
- Add Button to hide/show Roster in Groupchats
- Move Groupchat topic into popover
- Display Avatars on the right side of the ChatControl and status on the
left
- Add a default Avatar for contacts that have none
We use PubSub only on our account jid, this use case is what PEP
was made for. If PEP is discovered we know that certain PubSub
features are supported, see: https://xmpp.org/extensions/xep-0163.html#defaults
The current check for <feature var='http://jabber.org/protocol/pubsub'/>
is pretty useless, as it just tells us that there is a PubSub implementation
but not much about the features. Only `publish` and `subscribe` are MUST
in XEP-0060 which is not enough for our needs.
If there is ever need to discover a generic PubSub implementation
that is not PEP we should check for all the PubSub features we need
instead of only for <feature var='http://jabber.org/protocol/pubsub'/>
- Add support for Pubsub Avatars
- Dont poll for vCard Updates, only use XEP-0153
- Dont cache vCards
- Store the avatar SHA of roster contacts in the DB
- Store the current SHA of each contact in the Contacts Object
- Move some code into the ConnectionVcard Class
_registered_name is None on a smacks resume.
Gajim creates on every connection attempt a new nbxmpp.NonBlockingClient
instance. This is why _registered_name is None when we go through a
smacks resume, because there is no bind event, and the new NonBlockingClient
instance has no knowledge of the previous successful bind.
- Use new parse_datetime() method
- Drop message with error if MAM doesnt supply a timestamp.
- If the user supplys an own timestamp, save it so we can decide in the
future how to display it.
Goal is to make the logger module easier to maintain in the future
- extract deduplication out into a own method, so we can use it
on its own in some other places.
- add new insert_into_logs() method
the DB fields we want to write to are passed as arguments, this makes
it so we dont have to change the method when we add or remove DB fields
in the future.
- instead of using get_jid_id() all around gajim to get the jid_id
before we write to the DB, we only have to pass the jid to
insert_into_logs(), it makes sure to get the correct jid_id or add
one in case it doesnt exist.
This handles every possible XEP-0082 timestamp
It has some additional options:
- Check if a timestring is a valid UTC timestamp, as required by some
XEPs (for example: XEP-0203)
- Return timestamp as datetime in UTC
- Return timestamp as datetime in localtime
- Return timestamp as epoch
We get our full JID on the bind event.
After that it is saved in the `registered_name` attr on the Connection
Object.
In case the bind never occured we get the bare JID from config.
- Condition type = groupchat is not needed because we drop messages
type groupchat that come from the user archive. To get these messages
we will query the MUC.
- Because of this the logging method save_if_not_exists() can be much
simpler
A missing stanza ID means, we will have to take some measures to make
sure we get no duplicates in the Database later on.
Also fix getting the origin-id. Third time is a charm.
The gaol why we need to determine what ID should be used as stanza-id,
is so we can use the stanza-id in the future for deduplication.
Case we are the sender:
Either we look for a origin-id element, which we will include in the
Future in all messages we send, or until then the ID we set on the
message as attr.
Case we are the receiver:
If our server supports mam:2 we take the ID of the result element,
because mam:2 injects the archive ID live into every message we
receive. If we dont have mam:2 we fall back to the ID of the message
attr.
- Refactor and clean up code around MamMessageReceivedEvent
- Goal is to add a GcMamMessageReceivedEvent later on
- For that cause added a raw-mam-message-received base event
This lets us attach all attributes of the base event to the
new event. Often Events trigger other Events. When that happens
we often want to keep all attr from the previous Event, and just
continue under a new Event. Until now all attr had to be pulled
out of `self.base_event` again.
- Refactor get_last_date_that_has_logs()
- use NATURAL JOIN in SQL query instead of multiple SELECT via
_build_contact_where
- make code more concise
- update method documentation
- use NATURAL JOIN in SQL query instead of multiple SELECT via
_build_contact_where
- make code more concise
- update method documentation
- Fix a bug where messages were displayed in wrong order when
they had the same timestamp
_continue_connection_request_privacy() should only trigger
once after we received the discoinfo on the hostname.
We do a discoinfo on all items that the server offers,
_continue_connection_request_privacy() was triggered on every received
discoinfo again, hence requesting metacontacts and delimiters again.
also _continue_connection_request_privacy() was called on every
discoinfo error, instead of only on a hostname discoinfo error.
This bug is only triggered if the server doesnt support privacy rules.
The purpose of
`if version and not gajim.contacts.get_contacts_jid_list()`
seemed to be that when cache.db is empty (maybe it was deleted)
`gajim.contacts.get_contacts_jid_list()` should come back empty.
So on an empty roster cache, version was set to None, so that we
request in any case a new roster.
The Problem is that `gajim.contacts.get_contacts_jid_list()` is not
a good indication for an empty cache.db. On start we trigger a
`RosterReceivedEvent` which does a DB query to get the roster. Even
if that DB query comes up empty, the Event is still pushed.
In the event handler `_nec_roster_received` in roster_window.py we
add then previously open controls and our self (if the option is set)
to the roster, making `gajim.contacts.get_contacts_jid_list()` return
these contacts and hence the condition in `request_roster()` always
False.
So the version is set in the roster request, and if there is no new
version on the server, we request no new roster even though we only
have ourself and previously open controls in our roster.
As a solution for this we delete the roster version from the config
in `RosterReceivedEvent` if the DB query comes back empty, which
triggers a new roster request.
Set restore timeout inactiv, this should be really an advanced option,
probably only set for specific MUCs not as default for every MUC.
Set restore_lines to 10, so the User has an indication that Gajim can
display history, and that there is probably a setting to adjust.
Set muc_restore_lines to 100, this is a try to get a reasonable amount
of history, especially in small Groupchats. Most server will limit this
to 20-50 anyway. The limit 100 is more of a precaution if we run into a
misconfigured server. This is intended as a workaround until we can
implement MAM for Groupchats.
muc_restore_timeout set to -1 means we want no particular time set, up
to which we request messages. But we should not deliberate request
messages we already have. Hence even if muc_restore_timeout is set
to -1, we should only request up to the last message we received.
Example:
If we receive a message the last message date is now.
If we restart Gajim and join the MUC again, `time.time() - timeout`
will be most likly smaller then when we received the last message
If the timeout is an hour, this would mean that many messages are requested
from the archive which we already received.
So we always want the most current timestamp (MAX).
Because some operations use the _timeout_commit() it happens that a timeout
is active while we shutdown.
This makes sure everything is commited before shutdown.