Asynchronous connecting
This is internal documentation of Tinymail's libtinymail-camel. It has very few to do with what application developers need to know to develop an application on top of this.
First of all, asynchronous operations
Asynchronous connecting is exactly the same as any other asynchronous operation. The difference is that it's solved internally within Tinymail's libtinymail-camel and that some components are adapted to cope with this correctly (all are internal problems, few of this comes on the surface of the external API).
The password question
The password question is one that you need to implement and pass to a TnyAccount using the tny_account_set_pass_func property. The invocation of this function pointer happens in TnySessionCamel's tny_session_camel_get_password. Actually, that's not true. This method will throw the request for a password to the mainloop then a conditional is set that will wait for the answer to have arrived on that mainloop, then it'll return with that answer. It of course also passes some data to and from the mainloop thread.
The get_password_idle_func is the function that happens in the mainloop, HadToWaitForPasswordInfo is that data that is being passed, get_password_destroy_func sets the conditional to continue (because the question is answered).
Forgetting the password
In case the password is wrong, another function pointer is invoked. You have to set this one using TnyAccount's tny_account_set_forget_pass_func property. This works exactly the same as how the password question works.
Dealing with alerts and simple questions
A simple question is one that requires a simple yes or no answer. For example the dialog that asks whether you want to trust a SSL certificate. There are two situations, with an answer (for example the SSL certificate question) and without an answer (for example reporting a failure during connecting). The application developer implements this in the TnyAccountStore's tny_account_store_alert method.
Just like the password question is the invocation thrown to the mainloop, a conditional is set that waits for the answer. Finally if there was an answer, it returns that answer.
When does this happen? How do I know if connecting failed or succeeded?
The TnySessionCamel has the TnyDevice that issues connection_changed signals. The TnySessionCamel also registers each account that gets created. There are three occasions where an account can get the "start connecting" operation on its queue:
- When the connection_changed signal happens at the TnyDevice
- When the account's tny_account_set_pass_func happened
- When the public tny_camel_account_set_online API is called
These put the "go online", or the "go offline" operation on the account's queue. They don't specify "when exactly" connecting will take place. They do specify "that" connecting "will" take place, "soon". This is why the tny_camel_account_set_online API has an optional callback and no GError byref parameter. That's because there's no way to know when exactly the connecting will take place. There is a way to know when it took place, by using that callback. It's also possible to know that connecting failed, again using that callback.
Internally does the TnySessionCamel use this callback mechanism to report a connecting failure to the alerting functionality (read about this above). For TnySessionCamel the callback's name is on_account_connect_done. This is for both when the tny_account_set_pass_func and the connecting_changed signal happened. For tny_camel_account_set_online the callback is of course defined and implemented by the application developer.
What is the TnyDevice's role in this?
The TnyDevice implementation (which is a type you as application developer can either reuse from one of the standard libraries or implement yourself for your device) is used in the following situations:
- Its initial return value for tny_device_is_online, if TRUE (online) during the tny_account_set_pass_func makes the account in question request a connection attempt in the account's queue
- Its connection-changed signal emission makes all accounts that are registered to request a connection state change in their queues. An account is registered as soon as its tny_camel_account_set_session got used correctly (you usually do this in your TnyAccountStore's implementation near the tny_account_set_pass_func).
Does a previous tny_camel_account_set_online influence what my TnyDevice does?
No it doesm't at this moment. It's possible that in future the state as set in tny_camel_account_set_online will be persisted even if the TnyDevice's connection-changed signal emission happens. Right now will the connection-changed emission override the state of each account to the new state (after the request that the connection-changed emission will cause to be put in the accounts's queues finishes).
I don't see folders!
That probably means that your account never went online. Does your tny_device_is_online returned true initially (during tny_account_set_pass_func) if the connection state of the device (your TnyDevice) was indeed online? Did you set your TnyDevice correctly in the TnySessionCamel (tny_session_camel_set_device at its construction in your TnyAccountStore implementation)? Does the connection-changed signal emits if the initial value of tny_device_is_online is initially not immediately synchronized with the real situation?
If your TnyDevice's tny_device_is_online does not initially return the correct value (the real situation, the real connectivity state of the device), then the only way to tell Tinymail "something has changed" (or in this case nothing really has changed, but no other subsystem in Tinymail yet knows about the real state because the tny_device_is_online was not synchronized with that real state at the time of first use) is to emit the connection-changed signal. Else will Tinymail assume that your device is offline. This, in that case, is the right assumption to make: you as the developer of the TnyDevice must make sure that each state change is correctly advertised! There's no magic that other subsystems in Tinymail can perform for you, so you have to perform all the magic for this in your TnyDevice's implementation.
Can I have a synchronous "go online" method?
You can make one yourself, but Tinymail wont offer you one. That's because this depends on how you in your application queue and wait for things. In Tinymail, the only way to connect to an account is by queuing the request for it. This means that Tinymail's libtinymail-camel would have to wait for the GError (in case of failure) and/or to know when it finally succeeded or finished connecting (so that it can return your function).
You can right after (and even before) the request to go online (TnyDevice's connection_changed signal, tny_camel_account_set_online or at tny_account_set_pass_func) already perform operations. It's only after the connection is made, though, that your operations will behave "online". Before that, the operations will behave "offline", of course.
If your TnyDevice's tny_device_is_online returns TRUE immediately (during application initialization), a connection operation will be queued instantly. The connection will only be made once its that queue item's turn. You can't "instantly" force a connection request to be made. If you think a little bit about it, such a functionality would require blocking the application's startup until the connection is finished.
Timeouts
Connecting has 15 seconds timeouts. This means that Tinymail's libtinymail-camel allows the name resolution to consume up to 15 seconds, that it allows the connecting itself to consume up to 15 seconds. This means that it's theoretically possible that it takes 30 full seconds before you are notified of a connecting failure.
