nit: This method is quite fat. In some sense, it's needed for coherency, but I might've overlooked some potential issues with early returns. If possible, I suggest extracting at least body of the cycle.
note to check: do we sort by timestamp when we fetch from the sqlite? Or is it default sorting by id which presumes that all messages are in order?
the issue doesn't appear to be pure debug level, but rather warn at the very least
We can't just print Exported %s... to user after this case. It's a error and should be handled as such.
nit: this conversion is done twice (see l463: auto_gchar gchar* ts = msg->timestamp ? g_date_time_format_iso8601(msg->timestamp) : g_strdup("");).
Same issue as earlier with copyright. We are not affiliated with Profanity.
O_APPEND won't execute since O_EXCL would throw an error if file already exists.
It future, this requirement should be removed as it doesn't make much sense. Offline capabilities are really lacking. But I see why it exists (local SQLite is getting disconnected on disconnect).
nit: It might be more readable if it's in the separate method. I suggest extraction of the error printing in a separate method.
it feels like it could substituted with prof_timeout_reset to deduplicate code.