Lock the command channel while searching. (imap_body_contains): If
2000-12-24 Not Zed <NotZed@HelixCode.com> * providers/imap/camel-imap-search.c (imap_body_contains): Lock the command channel while searching. (imap_body_contains): If performing a whole uid search, then add references to our own summary items, dont look it up in the folder. This way they can't vanish unexpectedly. * providers/imap/camel-imap-folder.h (CamelImapFolder): Added a private field. * providers/imap/camel-imap-private.h: Added lock for imap searches. * Merge from camel-mt-branch. * providers/imap/camel-imap-folder.c (imap_update_summary): Merge fix, use the folder->summary. (imap_get_message_flags, imap_set_message_flags, imap_get_message_user_flag, imap_set_message_user_flag): Removed again. (camel_imap_folder_init): Setup private data/lock. (imap_finalize): Free private data/search lock. (imap_search_free): Lock the search_lock. (imap_search_by_expression): Lock the search lock when using the search object. Also copy/ref hte summary, rather than getting it directly. (imap_refresh_info): Free any info lookups. Use folder->summary not imap_folder->summary. And lock around commands. svn path=/trunk/; revision=7150
This commit is contained in:
594
camel/ChangeLog
594
camel/ChangeLog
@ -1,3 +1,33 @@
|
||||
2000-12-24 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* providers/imap/camel-imap-search.c (imap_body_contains): Lock
|
||||
the command channel while searching.
|
||||
(imap_body_contains): If performing a whole uid search, then add
|
||||
references to our own summary items, dont look it up in the
|
||||
folder. This way they can't vanish unexpectedly.
|
||||
|
||||
* providers/imap/camel-imap-folder.h (CamelImapFolder): Added a
|
||||
private field.
|
||||
|
||||
* providers/imap/camel-imap-private.h: Added lock for imap
|
||||
searches.
|
||||
|
||||
* Merge from camel-mt-branch.
|
||||
|
||||
* providers/imap/camel-imap-folder.c (imap_update_summary): Merge
|
||||
fix, use the folder->summary.
|
||||
(imap_get_message_flags, imap_set_message_flags,
|
||||
imap_get_message_user_flag, imap_set_message_user_flag): Removed
|
||||
again.
|
||||
(camel_imap_folder_init): Setup private data/lock.
|
||||
(imap_finalize): Free private data/search lock.
|
||||
(imap_search_free): Lock the search_lock.
|
||||
(imap_search_by_expression): Lock the search lock when using the
|
||||
search object. Also copy/ref hte summary, rather than getting it
|
||||
directly.
|
||||
(imap_refresh_info): Free any info lookups. Use folder->summary
|
||||
not imap_folder->summary. And lock around commands.
|
||||
|
||||
2000-12-22 Dan Winship <danw@helixcode.com>
|
||||
|
||||
* providers/imap/camel-imap-store.c (get_folder_info): When
|
||||
@ -76,6 +106,570 @@
|
||||
* providers/imap/camel-imap-folder.c: Use %S instead of "%s" where
|
||||
appropriate.
|
||||
|
||||
2000-12-22 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* camel-folder-summary.c (GLOBAL_INFO_UNLOCK): Doh, cut and paste
|
||||
victim again, call unlock instead of lock!
|
||||
(summary_assign_uid): Unlock around trying to get a new uid, if we
|
||||
have a clash.
|
||||
|
||||
2000-12-21 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* tests/folder/Makefile.am (TESTS): reenabled the tests here.
|
||||
|
||||
* providers/nntp/camel-nntp-newsrc.c (CamelNNTPNewsrc): Add a
|
||||
lock. Made completely mt-safe. Sigh, this is all so i can
|
||||
support snooping of the set_flags stuff inside camel-nntp-folder,
|
||||
since i've removed the global folder lock from all of the other
|
||||
folder summary operations.
|
||||
(camel_nntp_newsrc_read_for_server): Setup lock.
|
||||
(camel_nntp_newsrc_get_highest_article_read): Lock internal access.
|
||||
(camel_nntp_newsrc_get_num_articles_read):
|
||||
(camel_nntp_newsrc_mark_article_read):
|
||||
(camel_nntp_newsrc_mark_range_read):
|
||||
(camel_nntp_newsrc_article_is_read):
|
||||
(camel_nntp_newsrc_group_is_subscribed):
|
||||
(camel_nntp_newsrc_unsubscribe_group):
|
||||
(camel_nntp_newsrc_subscribe_group):
|
||||
(camel_nntp_newsrc_get_subscribed_group_names):
|
||||
(camel_nntp_newsrc_get_all_group_names): "
|
||||
(camel_nntp_newsrc_write_to_file): Lock internal accesses.
|
||||
(camel_nntp_newsrc_write): Lock around diry stuff.
|
||||
|
||||
* providers/local/camel-maildir-summary.c (maildir_summary_check):
|
||||
Lock around our internal poking of the summary hashtable/array.
|
||||
(maildir_summary_sync): And the same here too.
|
||||
|
||||
* camel-folder-summary.c: Moved the summaryprivate data into
|
||||
camel-private.h. Only needed for the locks really.
|
||||
(camel_folder_summary_init): Setup locks.
|
||||
(camel_folder_summary_set_filename): Lock.
|
||||
(camel_folder_summary_index): lock
|
||||
(camel_folder_summary_uid): Lock
|
||||
(camel_folder_summary_next_uid): "
|
||||
(camel_folder_summary_set_uid): "
|
||||
(camel_folder_summary_load): Lock around whole load. Hrm,
|
||||
probably not required.
|
||||
(camel_folder_summary_save): Lock around whole save, this is
|
||||
reqwuired, unless we ref/copy the whole list first, and i couldn't
|
||||
be bothreed.
|
||||
(camel_folder_summary_add): lock
|
||||
(summary_assign_uid): Lock around internal accesses.
|
||||
(camel_folder_summary_info_new_from_parser): Lock around filtr stuff.
|
||||
(camel_folder_summary_info_ref): Add locking. Could probably use
|
||||
its own lock?
|
||||
(camel_folder_summary_touch): Add locking, likewise.
|
||||
(camel_folder_summary_clear): Lock. If the preiovus two are
|
||||
changed, then so this will need mroe locking.
|
||||
(camel_folder_summary_info_free): Lock around refcounting.
|
||||
(camel_folder_summary_remove): Locking.
|
||||
(camel_folder_summary_remove_uid): Lock ref, unlock, unref. Also
|
||||
fixed a bug that would have made this never work, freeing the key,
|
||||
which isn't allocated.
|
||||
(camel_folder_summary_remove_index): lock, ref, unlock unref also.
|
||||
(camel_message_info_ref): Lock using a separate global lock, since
|
||||
we have no context here.
|
||||
(camel_message_info_free): Here too.
|
||||
(content_info_alloc): Use an alocation lock here. avoids races
|
||||
with setting up content_info_chunks, etc.
|
||||
(camel_folder_summary_info_new): And here too.
|
||||
(camel_folder_summary_load): Changed to use a differnet lock for
|
||||
loading/saving.
|
||||
(camel_folder_summary_init): Doh, i do need a reflock afterall,
|
||||
set one up.
|
||||
(camel_folder_summary_finalize): Free it.
|
||||
(camel_folder_summary_index): Add a reflock.
|
||||
(camel_folder_summary_uid): And here too.
|
||||
(camel_folder_summary_info_free): Use reflock instead of
|
||||
summary_lock.
|
||||
(camel_folder_summary_info_ref): Likewise.
|
||||
(camel_folder_summary_remove_uid): Add reflocking.
|
||||
(camel_folder_summary_remove_index): And here too.
|
||||
|
||||
* providers/vee/camel-vee-folder.c (camel_vee_folder_new): Setup a
|
||||
summary object.
|
||||
(vee_folder_build): Build each item into the real summary object.
|
||||
(vee_folder_add, vee_folder_add_uid, vee_folder_add_change): New
|
||||
functions to add a single record to the vfolder summary.
|
||||
(vee_folder_build_folder): Use a real summary.
|
||||
(vee_get_uids): Removed, use default impl.
|
||||
(vee_free_message_info): "
|
||||
(vee_get_message_info): "
|
||||
(vee_get_summary): "
|
||||
(vee_get_unread_message_count): "
|
||||
(vee_get_message_count): "
|
||||
(vee_sync): Make vee-folder-sync sync all subordinate folders.
|
||||
Well i dont think this is right, but enough peopl ehave aksed for
|
||||
it.
|
||||
(vee_expunge): Same for expunge.
|
||||
(vee_set_message_flags): Call parent class, then mirror flags to
|
||||
subfolder.
|
||||
(vee_get_message_user_flag): Removed, we just use the default
|
||||
impl, and our flags should always match.
|
||||
(vee_set_message_user_flag): Snoop the set and set on subfolder.
|
||||
(vee_get_message_flags): Removed, jsut use parent impl, assume our
|
||||
copy matches the real ones.
|
||||
(get_real_message): Removed. We sort ofneed to keep the
|
||||
summaryitem refed while we use it, so this doesn't make as much
|
||||
sense as it did once.
|
||||
(camel_vee_folder_finalise): Unhook listening events as we unref
|
||||
folders.
|
||||
(camel_vee_folder_new): Set the summary messageinfo data size
|
||||
properly.
|
||||
(vfolder_remove_match): Fixed for summary change.
|
||||
(folder_changed): ditto. Also stopped changed items from being
|
||||
re-searched and possibly removed. Might have to resort to the old
|
||||
whole-search idea again.
|
||||
(message_changed): Similarly. Might be easier just not to bother
|
||||
with a whole search.
|
||||
|
||||
* providers/vee/camel-vee-folder.h: Removes summary
|
||||
hashtable/array, and use a real summary object. Sigh, more work.
|
||||
|
||||
* providers/nntp/camel-nntp-folder.c (nntp_folder_sync): Move
|
||||
summary to folder object.
|
||||
(nntp_folder_get_message_count): Removed, use default impl.
|
||||
(nntp_folder_set_message_flags): Call parent impl to do the work,
|
||||
but snoop for newsrc.
|
||||
(nntp_folder_get_uids): Removed, use default impl.
|
||||
(nntp_folder_get_summary): "
|
||||
(nntp_folder_get_message_info): "
|
||||
(nntp_folder_free_message_info): "
|
||||
(camel_nntp_folder_new): moved summary to folder class
|
||||
|
||||
* providers/imap/camel-imap-folder.c (camel_imap_folder_init):
|
||||
Move summary to folder object.
|
||||
(camel_imap_folder_new): "
|
||||
(imap_finalize): No longer unref the summary (or infact, do
|
||||
anything else either).
|
||||
(imap_refresh_info): move summary to folder object.
|
||||
(imap_sync): "
|
||||
(imap_get_message_count): Removed, use default impl.
|
||||
(imap_get_unread_message_count): "
|
||||
(imap_get_uids): "
|
||||
(imap_get_summary): "
|
||||
(imap_free_summary): "
|
||||
(imap_get_message_info): "
|
||||
(imap_free_message_info): "
|
||||
(imap_get_message_flags): "
|
||||
(imap_set_message_flags): "
|
||||
(imap_get_message_user_flag): ", this changes functionality, but
|
||||
only by providing non-permanent flags.
|
||||
(imap_set_message_user_flag): "
|
||||
(imap_update_summary): move summary to folder object, and use
|
||||
camel_folder_summary_info_new_from_header, instead of calling the
|
||||
virtual function directly.
|
||||
|
||||
* providers/local/camel-maildir-folder.c (maildir_append_message):
|
||||
move summary to folder object, again.
|
||||
(maildir_get_message): "
|
||||
|
||||
* providers/local/camel-mh-folder.c (mh_append_message): move
|
||||
summary to folder object.
|
||||
(mh_get_message): "
|
||||
|
||||
* providers/local/camel-mbox-folder.c (mbox_append_message): Move
|
||||
summary to folder object
|
||||
(mbox_get_message): "
|
||||
(mbox_set_message_user_flag): We need our own copy of this, sigh,
|
||||
so we can track if the xev needs a rewrite (probably, its only a
|
||||
guide anyway).
|
||||
(mbox_set_message_user_tag): Same same with this one.
|
||||
(camel_mbox_folder_class_init): Link in these new virtual functions.
|
||||
|
||||
* providers/local/camel-local-folder.h (CamelLocalFolder): removed
|
||||
summary.
|
||||
|
||||
* providers/local/camel-local-folder.c (local_get_message_count):
|
||||
(local_get_unread_message_count):
|
||||
(local_get_uids):
|
||||
(local_get_summary):
|
||||
(local_free_summary):
|
||||
(local_get_message_info):
|
||||
(local_free_message_info):
|
||||
(local_get_message_flags):
|
||||
(local_set_message_flags):
|
||||
(local_get_message_user_flag):
|
||||
(local_set_message_user_flag):
|
||||
(local_get_message_user_tag):
|
||||
(local_set_message_user_tag): Removed, all now use default
|
||||
implementation.
|
||||
(camel_local_folder_class_init): Removed overrides.
|
||||
(local_init): Clear folder->summary.
|
||||
(local_finalize): move summary to folder.
|
||||
(camel_local_folder_construct): "
|
||||
(local_sync): "
|
||||
|
||||
* camel-folder.c (free_summary): Provide a real impl.
|
||||
(get_summary): "
|
||||
(free_uids): "
|
||||
(get_uids): "
|
||||
(free_message_info): "
|
||||
(get_message_info): "
|
||||
(set_message_user_tag): "
|
||||
(get_message_user_tag): "
|
||||
(set_message_user_flag): "
|
||||
(get_message_user_flag): " Sigh, the last so far.
|
||||
(get_message_flags): Sigh, 1 more afterall.
|
||||
(get_unread_message_count): And and this.
|
||||
(get_message_count): and this!
|
||||
(set_message_flags): Sigh, and this.
|
||||
(camel_folder_finalize): Unref the summary if we have it.
|
||||
(camel_folder_free_uids): Remove locking.
|
||||
(camel_folder_get_message_flags): Remove locks, since the summary
|
||||
is now mt-safe.
|
||||
(camel_folder_set_message_flags): "
|
||||
(camel_folder_get_message_user_flag): "
|
||||
(camel_folder_set_message_user_flag): "
|
||||
(camel_folder_get_message_user_tag): "
|
||||
(camel_folder_set_message_user_tag): "
|
||||
(camel_folder_get_message_info): "
|
||||
(camel_folder_free_message_info): "
|
||||
(camel_folder_get_uids): "
|
||||
(camel_folder_free_summary): "
|
||||
(camel_folder_get_unread_message_count): "
|
||||
(get_unread_message_count): Check we got info, no big deal, but
|
||||
the summary might change while we're counting, and upset the count
|
||||
slightly.
|
||||
(camel_folder_get_message_count): Remove locks.
|
||||
|
||||
* camel-folder.h (struct _CamelFolder): Added CamelFolderSummary
|
||||
to the base folder object. Sigh, this is going to be a lot of
|
||||
work ...
|
||||
|
||||
* camel-service.c (camel_service_init, finalise): changed
|
||||
connect_lock to be recursive e_mutex.
|
||||
|
||||
* camel-remote-store.c (camel_remote_store_init, finalise): Changed
|
||||
stream_lock to recursive e_mutex.
|
||||
|
||||
* camel-private.h (RemoteStorePrivate, ServicePrivate): Use
|
||||
recursive mutexes for connect_lock & stream_lock. Ick. Because
|
||||
of the imap code.
|
||||
|
||||
* providers/imap/camel-imap-private.h: Change the command_lock to
|
||||
be an EMutex.
|
||||
|
||||
* providers/imap/camel-imap-store.c (connect_to_server): Removed
|
||||
the command_lock stuff. If we are just connected again, it should
|
||||
be safe to assume we have exclusive access at this point without
|
||||
it (and yes, removes a deadlock).
|
||||
(imap_create): Remove a lock that wasn't even supposed to be
|
||||
there.
|
||||
(camel_imap_store_finalize, init): g_mutex->e_mutex(E_MUTEX_REC).
|
||||
Use a recursive mutex since the imap code is multiply recursivly
|
||||
calling some functions (sigh, it would be nice to fix this).
|
||||
|
||||
2000-12-20 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* camel-folder.c (folder_changed): Change the locks to inside the
|
||||
if. Stops a deadloc,k and we dont need a lock to read a value.
|
||||
(message_changed): Likewise.
|
||||
|
||||
* camel.c (camel_init): Blah, comment out g_thread_init, leave it
|
||||
to the caller, since it can only ever be done once.
|
||||
|
||||
* camel-folder-thread.c (camel_folder_thread_messages_new): Ref
|
||||
and save the folder in the thread return. Also get the summary
|
||||
once, and access that for the messageinfo's. Added bonus that now
|
||||
threads should come out in a similar order. We need to do this so
|
||||
that the messageinfo's dont get unref'd under us, and using the
|
||||
summary directly simplifies memory management.
|
||||
(camel_folder_thread_messages_destroy): Free the summary/unref the
|
||||
folder.
|
||||
|
||||
* camel-folder-thread.h: Add a folder to CamelFolderThread struct.
|
||||
|
||||
2000-12-19 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* providers/imap/camel-imap-utils.c (imap_translate_sexp): Unref
|
||||
using e_sexp_unref, since it is no longer an object.
|
||||
|
||||
* tests/lib/camel-test.c: Added a global lock, and made it
|
||||
thread-aware.
|
||||
|
||||
* camel-exception.c: Add a global lock. Not sure its really
|
||||
needed here, but it doesn't really hurt.
|
||||
(camel_exception_clear): Lock around access.
|
||||
(camel_exception_set): Same.
|
||||
(camel_exception_setv): "
|
||||
(camel_exception_xfer): "
|
||||
|
||||
* providers/local/Makefile.am (noinst_HEADERS): Added, for
|
||||
camel-local-private.h
|
||||
|
||||
* camel-folder.c (camel_folder_search_by_expression): Removed
|
||||
locking here, now upto the implementing class to lock.
|
||||
(camel_folder_search_free): Removed the folder lock here too, for
|
||||
consistency really, and the locking probably wasn't needed.
|
||||
|
||||
* providers/local/camel-local-folder.c (local_get_summary):
|
||||
Changed to copy/ref the summary items.
|
||||
(local_free_summary): Unref the summary items/free the array.
|
||||
(local_get_unread_message_count): Free info lookups.
|
||||
(local_search_by_expression): Perform more fine-grained locking,
|
||||
and dont lock the whole folder while searching, just the search
|
||||
object. Dum de dum, it *would* be possible to not even have to
|
||||
lock the search, by using our own copy of the search object each
|
||||
time. Could be investigated.
|
||||
(local_init): Init priaate data/lock.
|
||||
(local_finalize): Free private data/lock.
|
||||
(local_search_free): Also lock around the search object, because
|
||||
it accesses global data inside.
|
||||
|
||||
* README.mt: Some info about the mt code development.
|
||||
|
||||
* camel-folder-search.c (match_message): Put in a warning, this
|
||||
plain deadlocks so far, but i'm going to bed now.
|
||||
(camel_folder_search_finalize): Use e_sexp_unref() since its no
|
||||
longer an object.
|
||||
|
||||
* camel-session.c (camel_session_init): Init private data/lock.
|
||||
(camel_session_finalise): Free private data/lock.
|
||||
(camel_session_register_provider): Lock hash insert.
|
||||
(service_cache_remove): Lock.
|
||||
(camel_session_list_providers): "
|
||||
(camel_session_get_service): Lock the whole function.
|
||||
|
||||
* camel-session.h (struct _CamelSession): Added private data.
|
||||
|
||||
* providers/imap/camel-imap-store.c (camel_imap_store_init): Setup
|
||||
private data.
|
||||
(camel_imap_store_finalize): Free private data.
|
||||
(connect_to_server): Lock around command calls. I dont think its
|
||||
needed, but it shouldn't hurt either.
|
||||
(imap_connect): Lock around command calls. Again, I don think it
|
||||
is needed, but wont hurt.
|
||||
(imap_disconnect): ditto for this one.
|
||||
(imap_create): Lock around command.
|
||||
(get_folder): "
|
||||
(get_folder_info): "
|
||||
(subscribe_folder): "
|
||||
(unsubscribe_folder): "
|
||||
(imap_keepalive): "
|
||||
|
||||
* providers/imap/camel-imap-folder.c (camel_imap_folder_new): Lock
|
||||
around calling a command.
|
||||
(imap_refresh_info): Likewise.
|
||||
(imap_sync): "
|
||||
(imap_append_message): "
|
||||
(imap_copy_message_to): "
|
||||
(imap_move_message_to): "
|
||||
(imap_get_message): "
|
||||
(imap_update_summary): "
|
||||
(imap_search_by_expression): ", also minor logic cleanup.
|
||||
(imap_get_summary): Copy/ref the summary items.
|
||||
(imap_free_summary): And free it now too.
|
||||
|
||||
* providers/imap/camel-imap-auth.c (imap_try_kerberos_v4_auth):
|
||||
Lock the command stream for the command session.
|
||||
|
||||
* providers/imap/camel-imap-private.h: Private (locking info)
|
||||
stuff for imap provider.
|
||||
(CAMEL_IMAP_STORE_UNLOCK): Fix to call unlock, rather than lock!
|
||||
|
||||
* camel-service.c (camel_service_query_auth_types): Lock also for
|
||||
the connection here, incase the service needs to connect.
|
||||
|
||||
* camel-remote-store.c (camel_remote_store_init): Init private
|
||||
data/lock.
|
||||
(camel_remote_store_finalise): Readded, free private data/lock.
|
||||
(remote_send_stream): Changed to return the number of bytes
|
||||
written, like a good little stream function should.
|
||||
(camel_remote_store_send_string): Lock for stream access.
|
||||
(camel_remote_store_send_stream): Same here.
|
||||
(camel_remote_store_recv_line): And here.
|
||||
(camel_remote_store_refresh_folders): Lock the store for cache
|
||||
access.
|
||||
(timeout_cb): Lock for stream access.
|
||||
|
||||
2000-12-18 Not Zed <NotZed@HelixCode.com>
|
||||
|
||||
* camel-service.c (camel_service_init): Init private data.
|
||||
(camel_service_finalise): Free private data.
|
||||
(camel_service_connect): Lock around connection access.
|
||||
(camel_service_disconnect): "
|
||||
|
||||
* camel-service.h (struct _CamelService): Added private field.
|
||||
|
||||
* camel-store.c (camel_store_init): Init private data/lock.
|
||||
(camel_store_finalize): Free private data/lock.
|
||||
(camel_store_get_folder): Lock internal calls.
|
||||
(camel_store_delete_folder): "
|
||||
(camel_store_rename_folder): "
|
||||
(camel_store_get_root_folder): "
|
||||
(camel_store_get_default_folder): "
|
||||
(camel_store_get_folder_info): "
|
||||
(camel_store_folder_subscribed): "
|
||||
(camel_store_subscribe_folder): "
|
||||
(camel_store_unsubscribe_folder): "
|
||||
(lookup_folder): Lock accesses to the folder cache.
|
||||
(cache_folder): "
|
||||
(uncache_folder): And here too.
|
||||
|
||||
* camel-store.h (struct _CamelStore): Added a private field.
|
||||
|
||||
* Makefile.am (noinst_HEADERS): Add camel-private.h. There is a
|
||||
comment in that header as to why it ins't installed.
|
||||
|
||||
* camel-private.h: New header for private data, that subclasses
|
||||
can get to.
|
||||
|
||||
* tests/lib/camel-test.c (camel_test_init): If we do have threads
|
||||
enabled already, dont call g_thread_init().
|
||||
|
||||
* tests/lib/folders.c (test_folder_counts): Add free of info.
|
||||
(test_folder_message): And here too.
|
||||
|
||||
* providers/local/camel-maildir-summary.c (remove_summary): Free
|
||||
info.
|
||||
(maildir_summary_check): Free info lookups.
|
||||
|
||||
* providers/local/camel-mh-summary.c (message_info_new): Removed,
|
||||
didn't add value.
|
||||
(remove_summary): free info after being used.
|
||||
(mh_summary_check): Free info lookups.
|
||||
(mh_summary_sync): and here too.
|
||||
|
||||
* providers/local/camel-mbox-summary.c (summary_update): Free info
|
||||
lookups.
|
||||
(mbox_summary_sync_full): Likewise.
|
||||
(mbox_summary_sync_quick): And here.
|
||||
(mbox_summary_sync): ... and here.
|
||||
|
||||
* providers/local/camel-maildir-folder.c (maildir_get_message):
|
||||
Free messageinfo lookups.
|
||||
|
||||
* providers/local/camel-mh-folder.c (mh_get_message): Free
|
||||
messageinfo lookups.
|
||||
|
||||
* providers/local/camel-mbox-folder.c (mbox_get_message): Free
|
||||
messageinfo lookups.
|
||||
|
||||
* providers/local/camel-local-summary.c
|
||||
(message_info_new_from_message): Removed, since it wasn't doing
|
||||
anything useful.
|
||||
(message_info_new_from_parser): Same. And some other dead code.
|
||||
|
||||
* providers/local/camel-local-folder.c (local_get_message_info):
|
||||
deconstify.
|
||||
(local_free_message_info):new func to free info.
|
||||
(local_get_uids):
|
||||
(local_get_message_flags):
|
||||
(local_set_message_flags):
|
||||
(local_get_message_user_flag):
|
||||
(local_set_message_user_flag):
|
||||
(local_get_message_user_tag):
|
||||
(local_set_message_user_tag): Free all info lookups.
|
||||
(local_expunge): Dont call camel_folder_* functions, to avoid a deadlock.
|
||||
|
||||
* providers/nntp/camel-nntp-folder.c
|
||||
(nntp_folder_get_message_info): deconstify.
|
||||
(nntp_folder_free_message_info): Free summary item.
|
||||
(nntp_folder_get_message_flags): Free summary lookup.
|
||||
(nntp_folder_set_message_flags): and here.
|
||||
(nntp_folder_get_uids): And here.
|
||||
|
||||
* providers/imap/camel-imap-auth.c: Make base64_*_simple optional
|
||||
with the HAVE_KRB4 flag.
|
||||
|
||||
* providers/imap/camel-imap-folder.c (imap_free_message_info):
|
||||
Added a free of the message info.
|
||||
(imap_refresh_info):
|
||||
(imap_sync):
|
||||
(imap_refresh_info):
|
||||
(imap_get_unread_message_count):
|
||||
(imap_get_uids):
|
||||
(imap_get_message_flags):
|
||||
(imap_set_message_flags): Free any summary lookups.
|
||||
(imap_get_message_flags): Get the message info directly from the
|
||||
summary, not via the folder interface.
|
||||
(imap_move_message_to): Dont call folder functions directly
|
||||
(delete_message), as it will deadlock since we already have the
|
||||
lock.
|
||||
|
||||
* providers/vee/camel-vee-folder.c (vee_free_message_info): Free/unref
|
||||
the messageinfo.
|
||||
(vee_get_message_info): First ref the internal copy, then return it.
|
||||
(folder_changed): Free all got message info's.
|
||||
(message_changed): And here.
|
||||
(get_real_message): And here.
|
||||
(vee_folder_build): and here.
|
||||
(vee_folder_build_folder): ... and here.
|
||||
|
||||
* camel-folder-summary.c (camel_folder_summary_info_new):
|
||||
Initialise the messageinfo refcount to 1.
|
||||
(camel_folder_summary_info_free): Down the refcount till we need
|
||||
to free.
|
||||
(camel_folder_summary_info_ref): New function to up the refcount.
|
||||
(camel_message_info_dup_to): Sewt the refcount of the dest to 1.
|
||||
(camel_message_info_new): Set refcount to 1.
|
||||
(camel_message_info_new_from_header): Dont allocate the mi
|
||||
ourselves.
|
||||
(camel_message_info_free): Handle refcounting.
|
||||
(camel_message_info_ref): New function.
|
||||
(camel_folder_summary_index): Ref the messageinfo before returning
|
||||
it.
|
||||
(camel_folder_summary_uid): Likewise.
|
||||
(camel_folder_summary_save): Access the messageinfo array
|
||||
directly, rather than through accessors (saves ref/unref).
|
||||
(camel_folder_summary_clear): Likewise.
|
||||
(camel_folder_summary_remove_index): Likewise.
|
||||
(main): Free lookups.
|
||||
|
||||
* camel-folder-summary.h (CamelMessageInfo): Added a refcount
|
||||
value.
|
||||
|
||||
* camel-folder.c (camel_folder_free_message_info): New function to
|
||||
'free' a message info.
|
||||
(camel_folder_get_message_info): Deconstify return.
|
||||
(camel_folder_lock): New (internal) function to thread-lock the
|
||||
folder.
|
||||
(camel_folder_unlock): Likewise for unlocking.
|
||||
(freeze):
|
||||
(thaw): Lock around access to folder->frozen/changed_frozen.
|
||||
(folder_changed): Likewise.
|
||||
(message_changed): Likewise.
|
||||
(camel_folder_init): Init private data, locks and moved frozen
|
||||
info.
|
||||
(camel_folder_finalize): Free new private data, locks and moved
|
||||
frozen info.
|
||||
(copy_message_to): Free the messageinfo after we've used it.
|
||||
(move_message_to): And here too.
|
||||
(camel_folder_sync): Lock around virtual method invocation. Just
|
||||
locking around any virtual method that is known to need it. This
|
||||
is the first cut at locking.
|
||||
(camel_folder_refresh_info): "
|
||||
(camel_folder_expunge): "
|
||||
(camel_folder_get_message_count): "
|
||||
(camel_folder_get_unread_message_count): "
|
||||
(camel_folder_append_message): "
|
||||
(camel_folder_set_message_flags): "
|
||||
(camel_folder_get_message_flags): "
|
||||
(camel_folder_get_message_user_flag): "
|
||||
(camel_folder_set_message_user_flag): "
|
||||
(camel_folder_get_message_user_tag): "
|
||||
(camel_folder_set_message_user_tag): "
|
||||
(camel_folder_get_message): "
|
||||
(camel_folder_get_uids): "
|
||||
(camel_folder_free_uids): "
|
||||
(camel_folder_get_summary): "
|
||||
(camel_folder_search_by_expression): "
|
||||
(camel_folder_free_summary): "
|
||||
(camel_folder_search_free): "
|
||||
(camel_folder_move_message_to): "
|
||||
(camel_folder_copy_message_to): "
|
||||
(copy_message_to): Dont call any of our own folder functions
|
||||
directly, otherwise we will deadlock.
|
||||
(move_message_to): Likewise.
|
||||
|
||||
* camel-folder.h (CamelFolder): Added free_message_info() function
|
||||
& deconstify get_message_info()'s return.
|
||||
(CamelFolder): Add a private field (for locks).
|
||||
(struct _CamelFolder): Moved changed_changed/frozen into private
|
||||
data, since it really is private and now needs locked access.
|
||||
|
||||
>>>>>>> 1.641.2.8
|
||||
2000-12-15 Jeffrey Stedfast <fejj@helixcode.com>
|
||||
|
||||
* camel-mime-utils.c (header_fold): When checking to see if we
|
||||
|
||||
@ -127,7 +127,8 @@ libcamel_la_LIBADD = $(top_builddir)/e-util/libeutil.la $(UNICODE_LIBS)
|
||||
|
||||
|
||||
noinst_HEADERS = \
|
||||
camel-charset-map-private.h
|
||||
camel-charset-map-private.h \
|
||||
camel-private.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
README
|
||||
|
||||
171
camel/README.mt
Normal file
171
camel/README.mt
Normal file
@ -0,0 +1,171 @@
|
||||
|
||||
This version of camel is working towards being multi-thread safe
|
||||
(MT-SAFE). At least, for the important api's.
|
||||
|
||||
This code has now been merged into the main head, but this file
|
||||
will remain here as a log of how it was done, incase any issues
|
||||
arise. The ChangeLog of course has a much more detailed list
|
||||
of changes.
|
||||
|
||||
Intended method
|
||||
===============
|
||||
|
||||
I intend working on it in several stages:
|
||||
|
||||
1. Making the api multi-threadable. Basically removing some const-returns,
|
||||
and copying some data where it wasn't before. The api should
|
||||
still continue to work if not being used in a multithreaded
|
||||
application. There is not a significant amount of work here since
|
||||
this was more or less the intention all along.
|
||||
|
||||
Some functions where references to objects are returned may have to be
|
||||
changed slightly, so that refcounts are incremented before return.
|
||||
This doesn't affect much though.
|
||||
|
||||
camel_folder::get_message_info done
|
||||
camel_folder_summary::uid done
|
||||
camel_folder_summary::index done
|
||||
camel_folder::get_summary
|
||||
Needs to ref each summary item it points to. done
|
||||
camel_folder::free_summary
|
||||
Needs to unref each summary item it points to. done
|
||||
camel_folder_get_message_tag
|
||||
needs to copy the tag return
|
||||
camel_maildir_summary filename string
|
||||
should not be able to modify the string
|
||||
array contents after it has been added to
|
||||
the summary.
|
||||
camel_folder done
|
||||
Make every camel-folder use a camel-folder-summary.
|
||||
This just reduces some of the code duplication,
|
||||
since everything but vee-folder does this already.
|
||||
|
||||
2. Adding high level locks for proof of concept. The locks will
|
||||
be stored in private or global data, so the api should remain the same for
|
||||
non-threaded applications.
|
||||
|
||||
A per-folder lock which governs access to the folder
|
||||
summary, the folder file or
|
||||
communications socket, etc. done
|
||||
Locking for exceptions. done
|
||||
Per store locks for internal stuff. done
|
||||
Per-service locks for various internal lists and
|
||||
caches done
|
||||
|
||||
3. Further fine-grained locking where it can be done/is worthwhile.
|
||||
|
||||
A per-index lock for libibex done
|
||||
Locking for the search object half done
|
||||
Internal lock for the folder_summary itself
|
||||
So that searching can be detatched from other
|
||||
folder operations, etc. done
|
||||
Possibly a lock for access to parts of a mime-part
|
||||
or message
|
||||
|
||||
4. A method to cancel operations.
|
||||
|
||||
Individual outstanding operations must be cancellable, and not just
|
||||
'all current operations'. This will probably not use pthread_cancel
|
||||
type of cancelling.
|
||||
|
||||
This will however, probably use a method for starting a new thread,
|
||||
through camel, that can then be cancelled, and/or some method of
|
||||
registering that a thread can be cancelled. Blocking states within
|
||||
camel, within that thread, will then act as checkpoints for if the
|
||||
operation, and if it is cancelled, the operation will abort
|
||||
(i.e. fail, with an appropriate exception code).
|
||||
|
||||
Operation cancelling should also function when the application is not
|
||||
multi-threaded. Not sure of the api for this yet, probably a callback
|
||||
system. Hopefully the api for both scenarios can be made the same.
|
||||
|
||||
Other thoughts
|
||||
==============
|
||||
|
||||
Basically much of the code in camel that does the actual work does NOT
|
||||
need to be thread safe to make it safely usable in an mt context.
|
||||
|
||||
camel-folder, camel-summary, camel-imap-search, and the camel-service
|
||||
classes (at least) are the important ones to be made multithreaded.
|
||||
|
||||
For other things, they are either resources that are created
|
||||
one-off (for example, camel-mime-message, and its associated
|
||||
parts, like camel-internet-address), or multithreadedness
|
||||
doesn't make a lot of sense - e.g. camel-stream, or camel-mime-parser.
|
||||
|
||||
So basically the approach is a low-risk one. Adding the minimum
|
||||
number of locks to start with, and providing further fine-grained
|
||||
locks as required. The locks should not need to be particularly
|
||||
fine-grained in order to get reasonable results.
|
||||
|
||||
Log of changes
|
||||
==============
|
||||
|
||||
Changed CamelFolder:get_message_info() to return a ref'd copy, requiring
|
||||
all get_message_info()'s to have a matching free_message_info().
|
||||
|
||||
Moved the CamelFolder frozen changelog data to a private structure.
|
||||
|
||||
Added a mutex for CamelFolder frozen changelog stuff (it was just easy
|
||||
to do, although it isn't needed yet).
|
||||
|
||||
Added a single mutex around all other CamelFolder functions that need
|
||||
it, this is just the first cut at mt'edness.
|
||||
|
||||
Fixed all camel-folder implementations that call any other
|
||||
camel-folder functions to call via virtual methods, to bypass the locks.
|
||||
|
||||
Added camel-store private data.
|
||||
|
||||
Added a single mutex lock for camel-store's folder functions.
|
||||
|
||||
Added camel-service private data.
|
||||
|
||||
Added a single mutex lock for camel-service's connect stuff.
|
||||
|
||||
Added a mutex for remote-store stream io stuff.
|
||||
|
||||
Added a mutex for imap, so it can bracket a compound command
|
||||
exclusively. Pop doesn't need this since you can only have a single
|
||||
folder per store, and the folder interface is already forced
|
||||
single-threaded.
|
||||
|
||||
Added mutex for camel-session, most operations.
|
||||
|
||||
Running the tests finds at least 1 deadlock so far. Need to
|
||||
work on that.
|
||||
|
||||
Fixed get_summary to ref/unref its items.
|
||||
|
||||
Removed the global folder lock from the toplevel
|
||||
camel_folder_search(), each implementation must now handle locking.
|
||||
|
||||
Fixed the local-folder implementation of searching. imap-folder
|
||||
searching should already be mt-safe through the command lock.
|
||||
|
||||
Fixed imap summary to ref/unref too.
|
||||
|
||||
Built some test cases, and expanded the test framework library to
|
||||
handle multiple threads. It works!
|
||||
|
||||
Next, added a recursive mutex class, so that locking inside imap had
|
||||
any chance of working. Got imap working.
|
||||
|
||||
Moved the camel folder summary into the base folder class, and fixed
|
||||
everything to use it that way.
|
||||
|
||||
Made the vfolder use a real camel-folder-summary rather than a
|
||||
hashtable + array that it was using, and probably fixed some problems
|
||||
which caused evolution-mail not to always catch flag updates. Oh, and
|
||||
made it sync/expunge all its subfolders when sync/expungeing.
|
||||
|
||||
Made the camel-folder summary completely mt-safe.
|
||||
|
||||
Removed all of the locks on the folder functions dealing directly with
|
||||
the summary, so now for example all summary lookups will not be
|
||||
interupted by long operations.
|
||||
|
||||
Made the nntp newsrc thing mt-safe, because of some unfortunate
|
||||
sideeffect of it being called from the summary interaction code in
|
||||
nntp-folder.
|
||||
|
||||
@ -27,7 +27,21 @@
|
||||
#include <config.h>
|
||||
#include "camel-exception.h"
|
||||
|
||||
/* i dont know why gthread_mutex stuff even exists, this is easier */
|
||||
|
||||
/* also, i'm not convinced mutexes are needed here. But it
|
||||
doesn't really hurt either */
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t exception_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#define CAMEL_EXCEPTION_LOCK(e) (pthread_mutex_lock(&exception_mutex))
|
||||
#define CAMEL_EXCEPTION_UNLOCK(e) (pthread_mutex_unlock(&exception_mutex))
|
||||
#else
|
||||
#define CAMEL_EXCEPTION_LOCK(e)
|
||||
#define CAMEL_EXCEPTION_UNLOCK(e)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* camel_exception_new: allocate a new exception object.
|
||||
@ -83,20 +97,19 @@ camel_exception_init (CamelException *ex)
|
||||
void
|
||||
camel_exception_clear (CamelException *exception)
|
||||
{
|
||||
if (!exception) return;
|
||||
|
||||
/* free the description text */
|
||||
if (!exception)
|
||||
return;
|
||||
|
||||
CAMEL_EXCEPTION_LOCK(exception);
|
||||
|
||||
if (exception->desc)
|
||||
g_free (exception->desc);
|
||||
exception->desc = NULL;
|
||||
|
||||
/* set the Exception Id to NULL */
|
||||
exception->id = CAMEL_EXCEPTION_NONE;
|
||||
|
||||
CAMEL_EXCEPTION_UNLOCK(exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* camel_exception_free: Free an exception
|
||||
* @exception: The exception object to free
|
||||
@ -108,12 +121,11 @@ camel_exception_clear (CamelException *exception)
|
||||
void
|
||||
camel_exception_free (CamelException *exception)
|
||||
{
|
||||
if (!exception) return;
|
||||
if (!exception)
|
||||
return;
|
||||
|
||||
/* free the description text */
|
||||
if (exception->desc)
|
||||
g_free (exception->desc);
|
||||
/* free the exeption itself */
|
||||
g_free (exception);
|
||||
}
|
||||
|
||||
@ -137,17 +149,19 @@ camel_exception_set (CamelException *ex,
|
||||
ExceptionId id,
|
||||
const char *desc)
|
||||
{
|
||||
/* if no exception is given, do nothing */
|
||||
if (!ex) return;
|
||||
if (!ex)
|
||||
return;
|
||||
|
||||
CAMEL_EXCEPTION_LOCK(exception);
|
||||
|
||||
ex->id = id;
|
||||
|
||||
/* remove the previous exception description */
|
||||
if (ex->desc)
|
||||
g_free (ex->desc);
|
||||
ex->desc = g_strdup (desc);
|
||||
}
|
||||
g_free(ex->desc);
|
||||
ex->desc = g_strdup(desc);
|
||||
|
||||
CAMEL_EXCEPTION_UNLOCK(exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_exception_setv: set an exception
|
||||
@ -178,26 +192,23 @@ camel_exception_setv (CamelException *ex,
|
||||
{
|
||||
va_list args;
|
||||
|
||||
/* if no exception is given, do nothing */
|
||||
if (!ex) return;
|
||||
if (!ex)
|
||||
return;
|
||||
|
||||
CAMEL_EXCEPTION_LOCK(exception);
|
||||
|
||||
if (ex->desc)
|
||||
g_free (ex->desc);
|
||||
|
||||
/* create the temporary exception string */
|
||||
va_start(args, format);
|
||||
ex->desc = g_strdup_vprintf (format, args);
|
||||
va_end (args);
|
||||
|
||||
ex->id = id;
|
||||
|
||||
CAMEL_EXCEPTION_UNLOCK(exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* camel_exception_xfer: transfer an exception
|
||||
* @ex_dst: Destination exception object
|
||||
@ -212,6 +223,8 @@ void
|
||||
camel_exception_xfer (CamelException *ex_dst,
|
||||
CamelException *ex_src)
|
||||
{
|
||||
CAMEL_EXCEPTION_LOCK(exception);
|
||||
|
||||
if (ex_dst->desc)
|
||||
g_free (ex_dst->desc);
|
||||
|
||||
@ -220,14 +233,10 @@ camel_exception_xfer (CamelException *ex_dst,
|
||||
|
||||
ex_src->desc = NULL;
|
||||
ex_src->id = CAMEL_EXCEPTION_NONE;
|
||||
|
||||
CAMEL_EXCEPTION_UNLOCK(exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* camel_exception_get_id: get the exception id
|
||||
* @ex: The exception object
|
||||
@ -246,9 +255,6 @@ camel_exception_get_id (CamelException *ex)
|
||||
return CAMEL_EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* camel_exception_get_description: get the description of an exception.
|
||||
* @ex: The exception object
|
||||
@ -262,8 +268,10 @@ camel_exception_get_id (CamelException *ex)
|
||||
const gchar *
|
||||
camel_exception_get_description (CamelException *ex)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
if (ex)
|
||||
return ex->desc;
|
||||
else
|
||||
return NULL;
|
||||
ret = ex->desc;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -118,9 +118,8 @@ camel_folder_search_finalize (CamelObject *obj)
|
||||
CamelFolderSearch *search = (CamelFolderSearch *)obj;
|
||||
struct _CamelFolderSearchPrivate *p = _PRIVATE(obj);
|
||||
|
||||
/* yeah, this is a gtk object */
|
||||
if (search->sexp)
|
||||
gtk_object_unref((GtkObject *)search->sexp);
|
||||
e_sexp_unref(search->sexp);
|
||||
|
||||
g_free(search->last_search);
|
||||
g_hash_table_foreach(p->mempool_hash, free_mempool, obj);
|
||||
@ -404,6 +403,9 @@ void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *resul
|
||||
g_ptr_array_free(result, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* dummy function, returns false always, or an empty match array */
|
||||
static ESExpResult *
|
||||
search_dummy(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
|
||||
|
||||
@ -43,6 +43,21 @@
|
||||
#include "e-util/md5-utils.h"
|
||||
#include "e-util/e-memory.h"
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* this lock is ONLY for the standalone messageinfo stuff */
|
||||
#define GLOBAL_INFO_LOCK(i) pthread_mutex_lock(&info_lock)
|
||||
#define GLOBAL_INFO_UNLOCK(i) pthread_mutex_unlock(&info_lock)
|
||||
#else
|
||||
#define GLOBAL_INFO_LOCK(i)
|
||||
#define GLOBAL_INFO_UNLOCK(i)
|
||||
#endif
|
||||
|
||||
/* this should probably be conditional on it existing */
|
||||
#define USE_BSEARCH
|
||||
|
||||
@ -55,17 +70,6 @@ extern int strdup_count, malloc_count, free_count;
|
||||
|
||||
#define CAMEL_FOLDER_SUMMARY_VERSION (11)
|
||||
|
||||
struct _CamelFolderSummaryPrivate {
|
||||
GHashTable *filter_charset; /* CamelMimeFilterCharset's indexed by source charset */
|
||||
|
||||
CamelMimeFilterIndex *filter_index;
|
||||
CamelMimeFilterBasic *filter_64;
|
||||
CamelMimeFilterBasic *filter_qp;
|
||||
CamelMimeFilterSave *filter_save;
|
||||
|
||||
ibex *index;
|
||||
};
|
||||
|
||||
#define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv)
|
||||
|
||||
/* trivial lists, just because ... */
|
||||
@ -155,6 +159,14 @@ camel_folder_summary_init (CamelFolderSummary *s)
|
||||
|
||||
s->messages = g_ptr_array_new();
|
||||
s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
p->summary_lock = g_mutex_new();
|
||||
p->io_lock = g_mutex_new();
|
||||
p->filter_lock = g_mutex_new();
|
||||
p->alloc_lock = g_mutex_new();
|
||||
p->ref_lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void free_o_name(void *key, void *value, void *data)
|
||||
@ -194,6 +206,14 @@ camel_folder_summary_finalize (CamelObject *obj)
|
||||
if (p->filter_save)
|
||||
camel_object_unref ((CamelObject *)p->filter_save);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(p->summary_lock);
|
||||
g_mutex_free(p->io_lock);
|
||||
g_mutex_free(p->filter_lock);
|
||||
g_mutex_free(p->alloc_lock);
|
||||
g_mutex_free(p->ref_lock);
|
||||
#endif
|
||||
|
||||
g_free(p);
|
||||
}
|
||||
|
||||
@ -225,8 +245,7 @@ camel_folder_summary_get_type (void)
|
||||
CamelFolderSummary *
|
||||
camel_folder_summary_new (void)
|
||||
{
|
||||
CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ()));
|
||||
return new;
|
||||
CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ())); return new;
|
||||
}
|
||||
|
||||
|
||||
@ -239,8 +258,12 @@ camel_folder_summary_new (void)
|
||||
**/
|
||||
void camel_folder_summary_set_filename(CamelFolderSummary *s, const char *name)
|
||||
{
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
g_free(s->summary_path);
|
||||
s->summary_path = g_strdup(name);
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,16 +317,33 @@ camel_folder_summary_count(CamelFolderSummary *s)
|
||||
* @i:
|
||||
*
|
||||
* Retrieve a summary item by index number.
|
||||
*
|
||||
* A referenced to the summary item is returned, which may be
|
||||
* ref'd or free'd as appropriate.
|
||||
*
|
||||
* Return value: The summary item, or NULL if the index @i is out
|
||||
* of range.
|
||||
* It must be freed using camel_folder_summary_info_free().
|
||||
**/
|
||||
CamelMessageInfo *
|
||||
camel_folder_summary_index(CamelFolderSummary *s, int i)
|
||||
{
|
||||
CamelMessageInfo *info = NULL;
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
if (i<s->messages->len)
|
||||
return g_ptr_array_index(s->messages, i);
|
||||
return NULL;
|
||||
info = g_ptr_array_index(s->messages, i);
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
|
||||
if (info)
|
||||
info->refcount++;
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,14 +352,32 @@ camel_folder_summary_index(CamelFolderSummary *s, int i)
|
||||
* @uid:
|
||||
*
|
||||
* Retrieve a summary item by uid.
|
||||
*
|
||||
* A referenced to the summary item is returned, which may be
|
||||
* ref'd or free'd as appropriate.
|
||||
*
|
||||
* Return value: The summary item, or NULL if the uid @uid
|
||||
* is not available.
|
||||
* It must be freed using camel_folder_summary_info_free().
|
||||
**/
|
||||
CamelMessageInfo *
|
||||
camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
|
||||
{
|
||||
return g_hash_table_lookup(s->messages_uid, uid);
|
||||
CamelMessageInfo *info;
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
info = g_hash_table_lookup(s->messages_uid, uid);
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
|
||||
if (info)
|
||||
info->refcount++;
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -333,7 +391,14 @@ camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
|
||||
**/
|
||||
guint32 camel_folder_summary_next_uid(CamelFolderSummary *s)
|
||||
{
|
||||
guint32 uid = s->nextuid++;
|
||||
guint32 uid;
|
||||
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
uid = s->nextuid++;
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
|
||||
/* FIXME: sync this to disk */
|
||||
/* summary_header_save(s);*/
|
||||
@ -352,7 +417,11 @@ guint32 camel_folder_summary_next_uid(CamelFolderSummary *s)
|
||||
void camel_folder_summary_set_uid(CamelFolderSummary *s, guint32 uid)
|
||||
{
|
||||
/* TODO: sync to disk? */
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
s->nextuid = MAX(s->nextuid, uid);
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,8 +475,10 @@ camel_folder_summary_load(CamelFolderSummary *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, io_lock);
|
||||
if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in) == -1) {
|
||||
fclose(in);
|
||||
CAMEL_SUMMARY_UNLOCK(s, io_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -422,6 +493,8 @@ camel_folder_summary_load(CamelFolderSummary *s)
|
||||
|
||||
camel_folder_summary_add(s, mi);
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, io_lock);
|
||||
|
||||
if (fclose(in) == -1)
|
||||
return -1;
|
||||
@ -481,22 +554,29 @@ camel_folder_summary_save(CamelFolderSummary *s)
|
||||
|
||||
io(printf("saving header\n"));
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, io_lock);
|
||||
|
||||
if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_save(s, out) == -1) {
|
||||
fclose(out);
|
||||
CAMEL_SUMMARY_UNLOCK(s, io_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now write out each message ... */
|
||||
/* FIXME: check returns */
|
||||
count = camel_folder_summary_count(s);
|
||||
|
||||
count = s->messages->len;
|
||||
for (i=0;i<count;i++) {
|
||||
mi = camel_folder_summary_index(s, i);
|
||||
mi = s->messages->pdata[i];
|
||||
((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_save(s, out, mi);
|
||||
|
||||
if (s->build_content) {
|
||||
perform_content_info_save(s, out, mi->content);
|
||||
}
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, io_lock);
|
||||
|
||||
if (fclose(out) == -1)
|
||||
return -1;
|
||||
|
||||
@ -515,12 +595,18 @@ summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info)
|
||||
uid = camel_message_info_uid(info);
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
while (g_hash_table_lookup(s->messages_uid, uid)) {
|
||||
g_warning("Trying to insert message with clashing uid (%s). new uid re-assigned", camel_message_info_uid(info));
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s));
|
||||
uid = camel_message_info_uid(info);
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -542,6 +628,8 @@ void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
|
||||
|
||||
summary_assign_uid(s, info);
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
|
||||
#ifdef DOESTRV
|
||||
/* this is vitally important, and also if this is ever modified, then
|
||||
the hash table needs to be resynced */
|
||||
@ -551,6 +639,8 @@ void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
|
||||
g_ptr_array_add(s->messages, info);
|
||||
g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
|
||||
s->flags |= CAMEL_SUMMARY_DIRTY;
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -668,6 +758,8 @@ CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *
|
||||
* know if we are going to store this in the summary, but no matter */
|
||||
summary_assign_uid(s, info);
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, filter_lock);
|
||||
|
||||
if (p->index) {
|
||||
if (p->filter_index == NULL)
|
||||
p->filter_index = camel_mime_filter_index_new_ibex(p->index);
|
||||
@ -677,6 +769,9 @@ CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *
|
||||
|
||||
/* always scan the content info, even if we dont save it */
|
||||
info->content = summary_build_content_info(s, info, mp);
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, filter_lock);
|
||||
|
||||
info->size = camel_mime_parser_tell(mp) - start;
|
||||
}
|
||||
return info;
|
||||
@ -731,7 +826,7 @@ perform_content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci)
|
||||
* @s:
|
||||
* @mi:
|
||||
*
|
||||
* Free the message info @mi, and all associated memory.
|
||||
* Unref and potentially free the message info @mi, and all associated memory.
|
||||
**/
|
||||
void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
|
||||
{
|
||||
@ -740,6 +835,18 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
|
||||
g_assert(mi);
|
||||
g_assert(s);
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
|
||||
g_assert(mi->refcount >= 1);
|
||||
|
||||
mi->refcount--;
|
||||
if (mi->refcount > 0) {
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
|
||||
ci = mi->content;
|
||||
|
||||
((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_free(s, mi);
|
||||
@ -748,6 +855,24 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_folder_summary_info_ref:
|
||||
* @s:
|
||||
* @mi:
|
||||
*
|
||||
* Add an extra reference to @mi.
|
||||
**/
|
||||
void camel_folder_summary_info_ref(CamelFolderSummary *s, CamelMessageInfo *mi)
|
||||
{
|
||||
g_assert(mi);
|
||||
g_assert(s);
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
g_assert(mi->refcount >= 1);
|
||||
mi->refcount++;
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_folder_summary_touch:
|
||||
* @s:
|
||||
@ -757,7 +882,9 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
|
||||
void
|
||||
camel_folder_summary_touch(CamelFolderSummary *s)
|
||||
{
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
s->flags |= CAMEL_SUMMARY_DIRTY;
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -771,16 +898,20 @@ camel_folder_summary_clear(CamelFolderSummary *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (camel_folder_summary_count(s) == 0)
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
if (camel_folder_summary_count(s) == 0) {
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0;i<camel_folder_summary_count(s);i++)
|
||||
camel_folder_summary_info_free(s, camel_folder_summary_index(s, i));
|
||||
for (i=0;i<s->messages->len;i++)
|
||||
camel_folder_summary_info_free(s, s->messages->pdata[i]);
|
||||
|
||||
g_ptr_array_set_size(s->messages, 0);
|
||||
g_hash_table_destroy(s->messages_uid);
|
||||
s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
s->flags |= CAMEL_SUMMARY_DIRTY;
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -792,10 +923,13 @@ camel_folder_summary_clear(CamelFolderSummary *s)
|
||||
**/
|
||||
void camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info)
|
||||
{
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
|
||||
g_ptr_array_remove(s->messages, info);
|
||||
camel_folder_summary_info_free(s, info);
|
||||
s->flags |= CAMEL_SUMMARY_DIRTY;
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
|
||||
camel_folder_summary_info_free(s, info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -810,10 +944,19 @@ void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
|
||||
CamelMessageInfo *oldinfo;
|
||||
char *olduid;
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
if (g_hash_table_lookup_extended(s->messages_uid, uid, (void *)&olduid, (void *)&oldinfo)) {
|
||||
/* make sure it doesn't vanish while we're removing it */
|
||||
oldinfo->refcount++;
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
camel_folder_summary_remove(s, oldinfo);
|
||||
g_free(olduid);
|
||||
}
|
||||
camel_folder_summary_info_free(s, oldinfo);
|
||||
} else {
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -825,11 +968,20 @@ void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
|
||||
**/
|
||||
void camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
|
||||
{
|
||||
CamelMessageInfo *oldinfo;
|
||||
|
||||
oldinfo = camel_folder_summary_index (s, index);
|
||||
if (oldinfo)
|
||||
camel_folder_summary_remove(s, oldinfo);
|
||||
CAMEL_SUMMARY_LOCK(s, ref_lock);
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
if (index < s->messages->len) {
|
||||
CamelMessageInfo *info = s->messages->pdata[index];
|
||||
/* make sure it doesn't vanish while we're not looking */
|
||||
info->refcount++;
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
camel_folder_summary_remove(s, info);
|
||||
camel_folder_summary_info_free(s, info);
|
||||
} else {
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
CAMEL_SUMMARY_UNLOCK(s, ref_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1430,13 +1582,17 @@ camel_folder_summary_info_new(CamelFolderSummary *s)
|
||||
{
|
||||
CamelMessageInfo *mi;
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, alloc_lock);
|
||||
if (s->message_info_chunks == NULL)
|
||||
s->message_info_chunks = e_memchunk_new(32, s->message_info_size);
|
||||
mi = e_memchunk_alloc(s->message_info_chunks);
|
||||
CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
|
||||
|
||||
memset(mi, 0, s->message_info_size);
|
||||
#ifdef DOESTRV
|
||||
mi->strings = e_strv_new(s->message_info_strings);
|
||||
#endif
|
||||
mi->refcount = 1;
|
||||
return mi;
|
||||
}
|
||||
|
||||
@ -1445,9 +1601,12 @@ content_info_alloc(CamelFolderSummary *s)
|
||||
{
|
||||
CamelMessageContentInfo *ci;
|
||||
|
||||
CAMEL_SUMMARY_LOCK(s, alloc_lock);
|
||||
if (s->content_info_chunks == NULL)
|
||||
s->content_info_chunks = e_memchunk_new(32, s->content_info_size);
|
||||
ci = e_memchunk_alloc(s->content_info_chunks);
|
||||
CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
|
||||
|
||||
memset(ci, 0, s->content_info_size);
|
||||
return ci;
|
||||
}
|
||||
@ -1769,6 +1928,7 @@ next_uid_string(CamelFolderSummary *s)
|
||||
and any indexing and what not is performed
|
||||
*/
|
||||
|
||||
/* must have filter_lock before calling this function */
|
||||
static CamelMessageContentInfo *
|
||||
summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp)
|
||||
{
|
||||
@ -1892,6 +2052,7 @@ summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, Cam
|
||||
}
|
||||
|
||||
/* build the content-info, from a message */
|
||||
/* this needs no lock, as we copy all data, and ibex is threadsafe */
|
||||
static CamelMessageContentInfo *
|
||||
summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object)
|
||||
{
|
||||
@ -2212,14 +2373,29 @@ camel_message_info_new (void)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
|
||||
info = g_new0 (CamelMessageInfo, 1);
|
||||
info = g_malloc0(sizeof(*info));
|
||||
#ifdef DOESTRV
|
||||
info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST);
|
||||
#endif
|
||||
|
||||
info->refcount = 1;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_message_info_ref:
|
||||
* @info:
|
||||
*
|
||||
* Reference an info.
|
||||
*
|
||||
* NOTE: This interface is not MT-SAFE, like the others.
|
||||
**/
|
||||
void camel_message_info_ref(CamelMessageInfo *info)
|
||||
{
|
||||
GLOBAL_INFO_LOCK(info);
|
||||
info->refcount++;
|
||||
GLOBAL_INFO_UNLOCK(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_message_info_new_from_header:
|
||||
@ -2238,20 +2414,13 @@ camel_message_info_new_from_header (struct _header_raw *header)
|
||||
to = camel_folder_summary_format_address (header, "to");
|
||||
cc = camel_folder_summary_format_address (header, "cc");
|
||||
|
||||
info = g_new0 (CamelMessageInfo, 1);
|
||||
#ifdef DOESTRV
|
||||
info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST);
|
||||
info = camel_message_info_new();
|
||||
|
||||
camel_message_info_set_subject (info, subject);
|
||||
camel_message_info_set_from (info, from);
|
||||
camel_message_info_set_to (info, to);
|
||||
camel_message_info_set_cc (info, cc);
|
||||
#else
|
||||
info->subject = subject;
|
||||
info->from = from;
|
||||
info->to = to;
|
||||
info->cc = cc;
|
||||
#endif
|
||||
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -2276,6 +2445,7 @@ camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to)
|
||||
to->size = from->size;
|
||||
to->date_sent = from->date_sent;
|
||||
to->date_received = from->date_received;
|
||||
to->refcount = 1;
|
||||
|
||||
/* Copy strings */
|
||||
#ifdef DOESTRV
|
||||
@ -2325,15 +2495,27 @@ camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to)
|
||||
* camel_message_info_free:
|
||||
* @mi: the message info
|
||||
*
|
||||
* Frees a CamelMessageInfo and its contents.
|
||||
* Unref's and potentially frees a CamelMessageInfo and its contents.
|
||||
*
|
||||
* Can only be used to free CamelMessageInfo's created with
|
||||
* camel_message_info_dup_to.
|
||||
*
|
||||
* NOTE: This interface is not MT-SAFE, like the others.
|
||||
*
|
||||
**/
|
||||
void
|
||||
camel_message_info_free(CamelMessageInfo *mi)
|
||||
{
|
||||
g_return_if_fail(mi != NULL);
|
||||
|
||||
GLOBAL_INFO_LOCK(info);
|
||||
mi->refcount--;
|
||||
if (mi->refcount > 0) {
|
||||
GLOBAL_INFO_UNLOCK(info);
|
||||
return;
|
||||
}
|
||||
GLOBAL_INFO_UNLOCK(info);
|
||||
|
||||
#ifdef DOESTRV
|
||||
e_strv_destroy(mi->strings);
|
||||
#else
|
||||
@ -2468,7 +2650,9 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("Printing summary\n");
|
||||
for (i=0;i<camel_folder_summary_count(s);i++) {
|
||||
message_info_dump(camel_folder_summary_index(s, i));
|
||||
CamelMessageInfo *info = camel_folder_summary_index(s, i);
|
||||
message_info_dump(info);
|
||||
camel_folder_summary_info_free(info);
|
||||
}
|
||||
|
||||
printf("Saivng summary\n");
|
||||
@ -2486,7 +2670,9 @@ int main(int argc, char **argv)
|
||||
|
||||
printf("Printing summary\n");
|
||||
for (i=0;i<camel_folder_summary_count(n);i++) {
|
||||
message_info_dump(camel_folder_summary_index(n, i));
|
||||
CamelMessageInfo *info = camel_folder_summary_index(s, i);
|
||||
message_info_dump(info);
|
||||
camel_folder_summary_info_free(info);
|
||||
}
|
||||
camel_object_unref(n);
|
||||
}
|
||||
|
||||
@ -121,6 +121,7 @@ typedef struct {
|
||||
#endif
|
||||
guint32 flags;
|
||||
guint32 size;
|
||||
guint32 refcount;
|
||||
|
||||
time_t date_sent;
|
||||
time_t date_received;
|
||||
@ -228,6 +229,7 @@ CamelMessageInfo *camel_folder_summary_info_new_from_header(CamelFolderSummary *
|
||||
CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *);
|
||||
CamelMessageInfo *camel_folder_summary_info_new_from_message(CamelFolderSummary *, CamelMimeMessage *);
|
||||
|
||||
void camel_folder_summary_info_ref(CamelFolderSummary *, CamelMessageInfo *);
|
||||
void camel_folder_summary_info_free(CamelFolderSummary *, CamelMessageInfo *);
|
||||
|
||||
/* removes a summary item, doesn't fix content offsets */
|
||||
@ -280,8 +282,9 @@ void camel_tag_list_free(CamelTag **list);
|
||||
/* message info utils for working with pseudo-messageinfo structures
|
||||
NOTE: These cannot be added to a real summary object, but suffice for all
|
||||
other external interfaces that use message info's */
|
||||
CamelMessageInfo *camel_message_info_new (void);
|
||||
CamelMessageInfo *camel_message_info_new_from_header (struct _header_raw *header);
|
||||
CamelMessageInfo *camel_message_info_new(void);
|
||||
void camel_message_info_ref(CamelMessageInfo *info);
|
||||
CamelMessageInfo *camel_message_info_new_from_header(struct _header_raw *header);
|
||||
void camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to);
|
||||
void camel_message_info_free(CamelMessageInfo *mi);
|
||||
|
||||
|
||||
@ -433,7 +433,8 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
|
||||
int i;
|
||||
CamelFolderThreadNode *c, *child, *head;
|
||||
CamelFolderThread *thread;
|
||||
GPtrArray *myuids;
|
||||
GHashTable *wanted = NULL;
|
||||
GPtrArray *summary;
|
||||
|
||||
#ifdef TIMEIT
|
||||
struct timeval start, end;
|
||||
@ -445,22 +446,26 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
|
||||
thread = g_malloc(sizeof(*thread));
|
||||
thread->tree = NULL;
|
||||
thread->node_chunks = e_memchunk_new(32, sizeof(CamelFolderThreadNode));
|
||||
thread->folder = folder;
|
||||
camel_object_ref((CamelObject *)folder);
|
||||
|
||||
if (uids == NULL)
|
||||
uids = myuids = camel_folder_get_uids(folder);
|
||||
else
|
||||
myuids = NULL;
|
||||
/* wanted is the list of what we want, we put it in a hash for quick lookup */
|
||||
if (uids) {
|
||||
wanted = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
for (i=0;i<uids->len;i++)
|
||||
g_hash_table_insert(wanted, uids->pdata[i], uids->pdata[i]);
|
||||
}
|
||||
|
||||
thread->summary = summary = camel_folder_get_summary(folder);
|
||||
|
||||
id_table = g_hash_table_new((GHashFunc)id_hash, (GCompareFunc)id_equal);
|
||||
no_id_table = g_hash_table_new(NULL, NULL);
|
||||
for (i=0;i<uids->len;i++) {
|
||||
const CamelMessageInfo *mi;
|
||||
mi = camel_folder_get_message_info(folder, uids->pdata[i]);
|
||||
for (i=0;i<summary->len;i++) {
|
||||
CamelMessageInfo *mi = summary->pdata[i];
|
||||
const char *uid = camel_message_info_uid(mi);
|
||||
|
||||
if (mi == NULL) {
|
||||
g_warning("Folder doesn't contain uid %s", (char *)uids->pdata[i]);
|
||||
if (wanted && g_hash_table_lookup(wanted, uid) == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mi->message_id.id.id) {
|
||||
c = g_hash_table_lookup(id_table, &mi->message_id);
|
||||
@ -540,9 +545,6 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
|
||||
uids->len, diff / 1000, diff % 1000);
|
||||
#endif
|
||||
|
||||
if (myuids)
|
||||
camel_folder_free_uids(folder, myuids);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
@ -555,6 +557,8 @@ camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids)
|
||||
void
|
||||
camel_folder_thread_messages_destroy(CamelFolderThread *thread)
|
||||
{
|
||||
camel_folder_free_summary(thread->folder, thread->summary);
|
||||
camel_object_unref((CamelObject *)thread->folder);
|
||||
e_memchunk_destroy(thread->node_chunks);
|
||||
g_free(thread);
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@ typedef struct _CamelFolderThreadNode {
|
||||
typedef struct CamelFolderThread {
|
||||
struct _CamelFolderThreadNode *tree;
|
||||
struct _EMemChunk *node_chunks;
|
||||
CamelFolder *folder;
|
||||
GPtrArray *summary;
|
||||
} CamelFolderThread;
|
||||
|
||||
CamelFolderThread *camel_folder_thread_messages_new(CamelFolder *folder, GPtrArray *uids);
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
#include "string-utils.h"
|
||||
#include "e-util/e-memory.h"
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
static CamelObjectClass *parent_class = NULL;
|
||||
|
||||
/* Returns the class for a CamelFolder */
|
||||
@ -80,8 +82,8 @@ static CamelMimeMessage *get_message (CamelFolder *folder,
|
||||
const gchar *uid,
|
||||
CamelException *ex);
|
||||
|
||||
static const CamelMessageInfo *get_message_info (CamelFolder *folder,
|
||||
const char *uid);
|
||||
static CamelMessageInfo *get_message_info (CamelFolder *folder, const char *uid);
|
||||
static void free_message_info (CamelFolder *folder, CamelMessageInfo *info);
|
||||
|
||||
static GPtrArray *search_by_expression (CamelFolder *folder,
|
||||
const char *exp,
|
||||
@ -140,6 +142,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class)
|
||||
camel_folder_class->search_by_expression = search_by_expression;
|
||||
camel_folder_class->search_free = search_free;
|
||||
camel_folder_class->get_message_info = get_message_info;
|
||||
camel_folder_class->free_message_info = free_message_info;
|
||||
camel_folder_class->copy_message_to = copy_message_to;
|
||||
camel_folder_class->move_message_to = move_message_to;
|
||||
camel_folder_class->freeze = freeze;
|
||||
@ -157,8 +160,13 @@ camel_folder_init (gpointer object, gpointer klass)
|
||||
{
|
||||
CamelFolder *folder = object;
|
||||
|
||||
folder->frozen = 0;
|
||||
folder->changed_frozen = camel_folder_change_info_new();
|
||||
folder->priv = g_malloc0(sizeof(*folder->priv));
|
||||
folder->priv->frozen = 0;
|
||||
folder->priv->changed_frozen = camel_folder_change_info_new();
|
||||
#ifdef ENABLE_THREADS
|
||||
folder->priv->lock = g_mutex_new();
|
||||
folder->priv->change_lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -172,7 +180,15 @@ camel_folder_finalize (CamelObject *object)
|
||||
if (camel_folder->parent_store)
|
||||
camel_object_unref (CAMEL_OBJECT (camel_folder->parent_store));
|
||||
|
||||
camel_folder_change_info_free(camel_folder->changed_frozen);
|
||||
if (camel_folder->summary)
|
||||
camel_object_unref((CamelObject *)camel_folder->summary);
|
||||
|
||||
camel_folder_change_info_free(camel_folder->priv->changed_frozen);
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(camel_folder->priv->lock);
|
||||
g_mutex_free(camel_folder->priv->change_lock);
|
||||
#endif
|
||||
g_free(camel_folder->priv);
|
||||
}
|
||||
|
||||
CamelType
|
||||
@ -241,7 +257,11 @@ camel_folder_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
{
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
|
||||
CAMEL_FOLDER_LOCK(folder, lock);
|
||||
|
||||
CF_CLASS (folder)->sync (folder, expunge, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, lock);
|
||||
}
|
||||
|
||||
|
||||
@ -263,7 +283,11 @@ camel_folder_refresh_info (CamelFolder *folder, CamelException *ex)
|
||||
{
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
|
||||
CAMEL_FOLDER_LOCK(folder, lock);
|
||||
|
||||
CF_CLASS (folder)->refresh_info (folder, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, lock);
|
||||
}
|
||||
|
||||
|
||||
@ -355,16 +379,19 @@ camel_folder_expunge (CamelFolder *folder, CamelException *ex)
|
||||
{
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
|
||||
CF_CLASS (folder)->expunge (folder, ex);
|
||||
}
|
||||
CAMEL_FOLDER_LOCK(folder, lock);
|
||||
|
||||
CF_CLASS (folder)->expunge (folder, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, lock);
|
||||
}
|
||||
|
||||
static int
|
||||
get_message_count (CamelFolder *folder)
|
||||
{
|
||||
g_warning ("CamelFolder::get_message_count not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return -1;
|
||||
g_return_val_if_fail(folder->summary != NULL, -1);
|
||||
|
||||
return camel_folder_summary_count(folder->summary);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -376,18 +403,33 @@ get_message_count (CamelFolder *folder)
|
||||
int
|
||||
camel_folder_get_message_count (CamelFolder *folder)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), -1);
|
||||
|
||||
return CF_CLASS (folder)->get_message_count (folder);
|
||||
ret = CF_CLASS (folder)->get_message_count (folder);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_unread_message_count (CamelFolder *folder)
|
||||
get_unread_message_count(CamelFolder *folder)
|
||||
{
|
||||
g_warning ("CamelFolder::get_unread_message_count not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return -1;
|
||||
int i, count, unread=0;
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, -1);
|
||||
|
||||
count = camel_folder_summary_count(folder->summary);
|
||||
for (i=0; i<count; i++) {
|
||||
CamelMessageInfo *info = camel_folder_summary_index(folder->summary, i);
|
||||
|
||||
if (info && !(info->flags & CAMEL_MESSAGE_SEEN))
|
||||
unread++;
|
||||
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
return unread;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -399,12 +441,15 @@ get_unread_message_count (CamelFolder *folder)
|
||||
int
|
||||
camel_folder_get_unread_message_count (CamelFolder *folder)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), -1);
|
||||
|
||||
ret = CF_CLASS (folder)->get_unread_message_count (folder);
|
||||
|
||||
return CF_CLASS (folder)->get_unread_message_count (folder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
const CamelMessageInfo *info, CamelException *ex)
|
||||
@ -432,7 +477,11 @@ camel_folder_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
{
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
|
||||
CAMEL_FOLDER_LOCK(folder, lock);
|
||||
|
||||
CF_CLASS (folder)->append_message (folder, message, info, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, lock);
|
||||
}
|
||||
|
||||
|
||||
@ -458,13 +507,21 @@ camel_folder_get_permanent_flags (CamelFolder *folder)
|
||||
return CF_CLASS (folder)->get_permanent_flags (folder);
|
||||
}
|
||||
|
||||
|
||||
static guint32
|
||||
get_message_flags (CamelFolder *folder, const char *uid)
|
||||
get_message_flags(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
g_warning ("CamelFolder::get_message_flags not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return 0;
|
||||
CamelMessageInfo *info;
|
||||
guint32 flags;
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, 0);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_val_if_fail(info != NULL, 0);
|
||||
|
||||
flags = info->flags;
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,18 +535,37 @@ get_message_flags (CamelFolder *folder, const char *uid)
|
||||
guint32
|
||||
camel_folder_get_message_flags (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
guint32 ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), 0);
|
||||
|
||||
return CF_CLASS (folder)->get_message_flags (folder, uid);
|
||||
ret = CF_CLASS (folder)->get_message_flags (folder, uid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_message_flags (CamelFolder *folder, const char *uid,
|
||||
guint32 flags, guint32 set)
|
||||
set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
|
||||
{
|
||||
g_warning ("CamelFolder::set_message_flags not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
CamelMessageInfo *info;
|
||||
guint32 new;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
new = (info->flags & ~flags) | (set & flags);
|
||||
if (new == info->flags) {
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
return;
|
||||
}
|
||||
|
||||
info->flags = new | CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
camel_folder_summary_touch(folder->summary);
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -514,12 +590,20 @@ camel_folder_set_message_flags (CamelFolder *folder, const char *uid,
|
||||
|
||||
|
||||
static gboolean
|
||||
get_message_user_flag (CamelFolder *folder, const char *uid,
|
||||
const char *name)
|
||||
get_message_user_flag(CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
g_warning ("CamelFolder::get_message_user_flag not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return FALSE;
|
||||
CamelMessageInfo *info;
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, FALSE);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_val_if_fail(info != NULL, FALSE);
|
||||
|
||||
ret = camel_flag_get(&info->user_flags, name);
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -534,18 +618,31 @@ gboolean
|
||||
camel_folder_get_message_user_flag (CamelFolder *folder, const char *uid,
|
||||
const char *name)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), 0);
|
||||
|
||||
return CF_CLASS (folder)->get_message_user_flag (folder, uid, name);
|
||||
ret = CF_CLASS (folder)->get_message_user_flag (folder, uid, name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_message_user_flag (CamelFolder *folder, const char *uid,
|
||||
const char *name, gboolean value)
|
||||
set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
|
||||
{
|
||||
g_warning ("CamelFolder::set_message_user_flag not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
CamelMessageInfo *info;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (camel_flag_set(&info->user_flags, name, value)) {
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
camel_folder_summary_touch(folder->summary);
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -568,11 +665,23 @@ camel_folder_set_message_user_flag (CamelFolder *folder, const char *uid,
|
||||
CF_CLASS (folder)->set_message_user_flag (folder, uid, name, value);
|
||||
}
|
||||
|
||||
static const char *get_message_user_tag(CamelFolder *folder, const char *uid, const char *name)
|
||||
static const char *
|
||||
get_message_user_tag(CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
g_warning ("CamelFolder::get_message_user_tag not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return NULL;
|
||||
CamelMessageInfo *info;
|
||||
const char *ret;
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_val_if_fail(info != NULL, FALSE);
|
||||
|
||||
#warning "Need to duplicate tag string"
|
||||
|
||||
ret = camel_tag_get(&info->user_tags, name);
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -586,17 +695,32 @@ static const char *get_message_user_tag(CamelFolder *folder, const char *uid, co
|
||||
const char *
|
||||
camel_folder_get_message_user_tag (CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), 0);
|
||||
|
||||
return CF_CLASS (folder)->get_message_user_tag (folder, uid, name);
|
||||
}
|
||||
#warning "get_message_user_tag() needs to copy the tag contents"
|
||||
ret = CF_CLASS (folder)->get_message_user_tag (folder, uid, name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
|
||||
{
|
||||
g_warning ("CamelFolder::set_message_user_tag not implemented "
|
||||
"for `%s'", camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
CamelMessageInfo *info;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (camel_tag_set(&info->user_tags, name, value)) {
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
camel_folder_summary_touch(folder->summary);
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -618,13 +742,12 @@ camel_folder_set_message_user_tag (CamelFolder *folder, const char *uid, const c
|
||||
CF_CLASS (folder)->set_message_user_tag (folder, uid, name, value);
|
||||
}
|
||||
|
||||
|
||||
static const CamelMessageInfo *
|
||||
static CamelMessageInfo *
|
||||
get_message_info (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
g_warning ("CamelFolder::get_message_info not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return NULL;
|
||||
g_return_val_if_fail(folder->summary != NULL, NULL);
|
||||
|
||||
return camel_folder_summary_uid(folder->summary, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,17 +755,48 @@ get_message_info (CamelFolder *folder, const char *uid)
|
||||
* @folder: a CamelFolder
|
||||
* @uid: the uid of a message
|
||||
*
|
||||
* Return value: the summary information for the indicated message
|
||||
* Retrieve the CamelMessageInfo for the specified @uid. This return
|
||||
* must be freed using free_message_info().
|
||||
*
|
||||
* Return value: the summary information for the indicated message, or NULL
|
||||
* if the uid does not exist.
|
||||
**/
|
||||
const CamelMessageInfo *
|
||||
CamelMessageInfo *
|
||||
camel_folder_get_message_info (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelMessageInfo *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
|
||||
g_return_val_if_fail (uid != NULL, NULL);
|
||||
|
||||
return CF_CLASS (folder)->get_message_info (folder, uid);
|
||||
ret = CF_CLASS (folder)->get_message_info (folder, uid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
free_message_info (CamelFolder *folder, CamelMessageInfo *info)
|
||||
{
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* camel_folder_free_message_info:
|
||||
* @folder:
|
||||
* @info:
|
||||
*
|
||||
* Free (unref) a CamelMessageInfo, previously obtained with get_message_info().
|
||||
**/
|
||||
void
|
||||
camel_folder_free_message_info(CamelFolder *folder, CamelMessageInfo *info)
|
||||
{
|
||||
g_return_if_fail(CAMEL_IS_FOLDER (folder));
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
CF_CLASS (folder)->free_message_info(folder, info);
|
||||
}
|
||||
|
||||
/* TODO: is this function required anyway? */
|
||||
gboolean
|
||||
@ -677,21 +831,45 @@ get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
* Return value: Message corresponding to the UID
|
||||
**/
|
||||
CamelMimeMessage *
|
||||
camel_folder_get_message (CamelFolder *folder, const gchar *uid,
|
||||
CamelException *ex)
|
||||
camel_folder_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
{
|
||||
CamelMimeMessage *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
|
||||
|
||||
return CF_CLASS (folder)->get_message (folder, uid, ex);
|
||||
CAMEL_FOLDER_LOCK(folder, lock);
|
||||
|
||||
ret = CF_CLASS (folder)->get_message (folder, uid, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static GPtrArray *
|
||||
get_uids (CamelFolder *folder)
|
||||
get_uids(CamelFolder *folder)
|
||||
{
|
||||
g_warning ("CamelFolder::get_uids not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return NULL;
|
||||
GPtrArray *array;
|
||||
int i, count;
|
||||
|
||||
array = g_ptr_array_new();
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, array);
|
||||
|
||||
count = camel_folder_summary_count(folder->summary);
|
||||
g_ptr_array_set_size(array, count);
|
||||
for (i=0; i<count; i++) {
|
||||
CamelMessageInfo *info = camel_folder_summary_index(folder->summary, i);
|
||||
|
||||
if (info) {
|
||||
array->pdata[i] = g_strdup(camel_message_info_uid(info));
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
} else {
|
||||
array->pdata[i] = g_strdup("xx unknown uid xx");
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -709,17 +887,23 @@ get_uids (CamelFolder *folder)
|
||||
GPtrArray *
|
||||
camel_folder_get_uids (CamelFolder *folder)
|
||||
{
|
||||
GPtrArray *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
|
||||
|
||||
return CF_CLASS (folder)->get_uids (folder);
|
||||
}
|
||||
ret = CF_CLASS (folder)->get_uids (folder);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
free_uids (CamelFolder *folder, GPtrArray *array)
|
||||
{
|
||||
g_warning ("CamelFolder::free_uids not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
int i;
|
||||
|
||||
for (i=0; i<array->len; i++)
|
||||
g_free(array->pdata[i]);
|
||||
g_ptr_array_free(array, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -737,13 +921,20 @@ camel_folder_free_uids (CamelFolder *folder, GPtrArray *array)
|
||||
CF_CLASS (folder)->free_uids (folder, array);
|
||||
}
|
||||
|
||||
|
||||
static GPtrArray *
|
||||
get_summary (CamelFolder *folder)
|
||||
get_summary(CamelFolder *folder)
|
||||
{
|
||||
g_warning ("CamelFolder::get_summary not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return NULL;
|
||||
GPtrArray *res = g_ptr_array_new();
|
||||
int i, count;
|
||||
|
||||
g_return_val_if_fail(folder->summary != NULL, res);
|
||||
|
||||
count = camel_folder_summary_count(folder->summary);
|
||||
g_ptr_array_set_size(res, count);
|
||||
for (i=0;i<count;i++)
|
||||
res->pdata[i] = camel_folder_summary_index(folder->summary, i);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -759,17 +950,26 @@ get_summary (CamelFolder *folder)
|
||||
GPtrArray *
|
||||
camel_folder_get_summary (CamelFolder *folder)
|
||||
{
|
||||
GPtrArray *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
|
||||
|
||||
return CF_CLASS (folder)->get_summary (folder);
|
||||
ret = CF_CLASS (folder)->get_summary (folder);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_summary (CamelFolder *folder, GPtrArray *array)
|
||||
free_summary(CamelFolder *folder, GPtrArray *summary)
|
||||
{
|
||||
g_warning ("CamelFolder::free_summary not implemented for `%s'",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
int i;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
for (i=0;i<summary->len;i++)
|
||||
camel_folder_summary_info_free(folder->summary, summary->pdata[i]);
|
||||
|
||||
g_ptr_array_free(summary, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -826,10 +1026,16 @@ GPtrArray *
|
||||
camel_folder_search_by_expression (CamelFolder *folder, const char *expression,
|
||||
CamelException *ex)
|
||||
{
|
||||
GPtrArray *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
|
||||
g_return_val_if_fail (folder->has_search_capability, NULL);
|
||||
|
||||
return CF_CLASS (folder)->search_by_expression (folder, expression, ex);
|
||||
/* NOTE: that it is upto the callee to lock */
|
||||
|
||||
ret = CF_CLASS (folder)->search_by_expression (folder, expression, ex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -855,25 +1061,28 @@ camel_folder_search_free (CamelFolder *folder, GPtrArray *result)
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
g_return_if_fail (folder->has_search_capability);
|
||||
|
||||
return CF_CLASS (folder)->search_free (folder, result);
|
||||
/* NOTE: upto the callee to lock */
|
||||
CF_CLASS (folder)->search_free (folder, result);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
copy_message_to (CamelFolder *source, const char *uid, CamelFolder *dest,
|
||||
CamelException *ex)
|
||||
copy_message_to (CamelFolder *source, const char *uid, CamelFolder *dest, CamelException *ex)
|
||||
{
|
||||
CamelMimeMessage *msg;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
|
||||
/* Default implementation. */
|
||||
|
||||
msg = camel_folder_get_message (source, uid, ex);
|
||||
/* we alredy have the lock, dont deadlock */
|
||||
msg = CF_CLASS(source)->get_message(source, uid, ex);
|
||||
if (!msg)
|
||||
return;
|
||||
info = camel_folder_get_message_info (source, uid);
|
||||
info = CF_CLASS(source)->get_message_info (source, uid);
|
||||
camel_folder_append_message (dest, msg, info, ex);
|
||||
camel_object_unref (CAMEL_OBJECT (msg));
|
||||
if (info)
|
||||
CF_CLASS(source)->free_message_info(source, info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -900,11 +1109,14 @@ camel_folder_copy_message_to (CamelFolder *source, const char *uid,
|
||||
|
||||
g_warning("CamelFolder.copy_message_to() is a deprecated api");
|
||||
|
||||
if (source->parent_store == dest->parent_store) {
|
||||
return CF_CLASS (source)->copy_message_to (source, uid,
|
||||
dest, ex);
|
||||
} else
|
||||
return copy_message_to (source, uid, dest, ex);
|
||||
CAMEL_FOLDER_LOCK(source, lock);
|
||||
|
||||
if (source->parent_store == dest->parent_store)
|
||||
return CF_CLASS (source)->copy_message_to (source, uid, dest, ex);
|
||||
else
|
||||
copy_message_to (source, uid, dest, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(source, lock);
|
||||
}
|
||||
|
||||
|
||||
@ -913,19 +1125,21 @@ move_message_to (CamelFolder *source, const char *uid,
|
||||
CamelFolder *dest, CamelException *ex)
|
||||
{
|
||||
CamelMimeMessage *msg;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
|
||||
/* Default implementation. */
|
||||
|
||||
msg = camel_folder_get_message (source, uid, ex);
|
||||
msg = CF_CLASS(source)->get_message (source, uid, ex);
|
||||
if (!msg)
|
||||
return;
|
||||
info = camel_folder_get_message_info (source, uid);
|
||||
info = CF_CLASS(source)->get_message_info (source, uid);
|
||||
camel_folder_append_message (dest, msg, info, ex);
|
||||
camel_object_unref (CAMEL_OBJECT (msg));
|
||||
if (camel_exception_is_set(ex))
|
||||
return;
|
||||
camel_folder_delete_message (source, uid);
|
||||
if (!camel_exception_is_set(ex))
|
||||
CF_CLASS(source)->set_message_flags(source, uid, CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED);
|
||||
|
||||
if (info)
|
||||
CF_CLASS(source)->free_message_info(source, info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -939,9 +1153,6 @@ move_message_to (CamelFolder *source, const char *uid,
|
||||
* @dest folders have the same parent_store, this may be more efficient
|
||||
* than a camel_folder_append_message() followed by
|
||||
* camel_folder_delete_message().
|
||||
*
|
||||
* FIXME: This call should be depracated, since append_message() can
|
||||
* determine this from the message itself.
|
||||
**/
|
||||
void
|
||||
camel_folder_move_message_to (CamelFolder *source, const char *uid,
|
||||
@ -953,17 +1164,24 @@ camel_folder_move_message_to (CamelFolder *source, const char *uid,
|
||||
|
||||
g_warning("CamelFolder.move_message_to() is a deprecated api");
|
||||
|
||||
if (source->parent_store == dest->parent_store) {
|
||||
return CF_CLASS (source)->move_message_to (source, uid,
|
||||
dest, ex);
|
||||
} else
|
||||
return move_message_to (source, uid, dest, ex);
|
||||
CAMEL_FOLDER_LOCK(source, lock);
|
||||
|
||||
if (source->parent_store == dest->parent_store)
|
||||
CF_CLASS (source)->move_message_to (source, uid, dest, ex);
|
||||
else
|
||||
move_message_to (source, uid, dest, ex);
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(source, lock);
|
||||
}
|
||||
|
||||
static void
|
||||
freeze (CamelFolder *folder)
|
||||
{
|
||||
folder->frozen++;
|
||||
CAMEL_FOLDER_LOCK(folder, change_lock);
|
||||
|
||||
folder->priv->frozen++;
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, change_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -989,23 +1207,25 @@ thaw (CamelFolder * folder)
|
||||
int i;
|
||||
CamelFolderChangeInfo *info;
|
||||
|
||||
folder->frozen--;
|
||||
if (folder->frozen != 0)
|
||||
return;
|
||||
CAMEL_FOLDER_LOCK(folder, change_lock);
|
||||
|
||||
/* If we have more or less messages, do a folder changed, otherwise just
|
||||
do a message changed for each one.
|
||||
TODO: message_changed is now probably irrelevant and not required */
|
||||
info = folder->changed_frozen;
|
||||
if (info->uid_added->len > 0 || info->uid_removed->len > 0) {
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", info);
|
||||
} else if (info->uid_changed->len > 0) {
|
||||
for (i=0;i<info->uid_changed->len;i++) {
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", info->uid_changed->pdata[i]);
|
||||
folder->priv->frozen--;
|
||||
if (folder->priv->frozen == 0) {
|
||||
/* If we have more or less messages, do a folder changed, otherwise just
|
||||
do a message changed for each one.
|
||||
TODO: message_changed is now probably irrelevant and not required */
|
||||
info = folder->priv->changed_frozen;
|
||||
if (info->uid_added->len > 0 || info->uid_removed->len > 0) {
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", info);
|
||||
} else if (info->uid_changed->len > 0) {
|
||||
for (i=0;i<info->uid_changed->len;i++) {
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", info->uid_changed->pdata[i]);
|
||||
}
|
||||
}
|
||||
camel_folder_change_info_clear(info);
|
||||
}
|
||||
|
||||
camel_folder_change_info_clear(info);
|
||||
CAMEL_FOLDER_UNLOCK(folder, change_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1019,7 +1239,7 @@ void
|
||||
camel_folder_thaw (CamelFolder *folder)
|
||||
{
|
||||
g_return_if_fail (CAMEL_IS_FOLDER (folder));
|
||||
g_return_if_fail (folder->frozen != 0);
|
||||
g_return_if_fail (folder->priv->frozen != 0);
|
||||
|
||||
CF_CLASS (folder)->thaw (folder);
|
||||
}
|
||||
@ -1031,29 +1251,40 @@ folder_changed (CamelObject *obj, gpointer event_data)
|
||||
{
|
||||
CamelFolder *folder = CAMEL_FOLDER (obj);
|
||||
CamelFolderChangeInfo *changed = event_data;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
if (folder->priv->frozen) {
|
||||
CAMEL_FOLDER_LOCK(folder, change_lock);
|
||||
|
||||
if (folder->frozen) {
|
||||
if (changed != NULL)
|
||||
camel_folder_change_info_cat(folder->changed_frozen, changed);
|
||||
camel_folder_change_info_cat(folder->priv->changed_frozen, changed);
|
||||
else
|
||||
g_warning("Class %s is passing NULL to folder_changed event",
|
||||
camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
|
||||
return FALSE;
|
||||
ret = FALSE;
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, change_lock);
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
message_changed (CamelObject *obj, /*const char *uid*/gpointer event_data)
|
||||
{
|
||||
CamelFolder *folder = CAMEL_FOLDER (obj);
|
||||
gboolean ret = TRUE;
|
||||
|
||||
if (folder->frozen) {
|
||||
camel_folder_change_info_change_uid(folder->changed_frozen, (char *)event_data);
|
||||
return FALSE;
|
||||
if (folder->priv->frozen) {
|
||||
CAMEL_FOLDER_LOCK(folder, change_lock);
|
||||
|
||||
camel_folder_change_info_change_uid(folder->priv->changed_frozen, (char *)event_data);
|
||||
ret = FALSE;
|
||||
|
||||
CAMEL_FOLDER_UNLOCK(folder, change_lock);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1112,6 +1343,9 @@ camel_folder_free_deep (CamelFolder *folder, GPtrArray *array)
|
||||
* @void:
|
||||
*
|
||||
* Create a new folder change info structure.
|
||||
*
|
||||
* Change info structures are not MT-SAFE and must be
|
||||
* locked for exclusive access externally.
|
||||
*
|
||||
* Return value:
|
||||
**/
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/* camel-folder.h: Abstract class for an email folder */
|
||||
|
||||
/*
|
||||
* Author:
|
||||
* Bertrand Guiheneuf <bertrand@helixcode.com>
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
*
|
||||
* camel-folder.h: Abstract class for an email folder
|
||||
*
|
||||
* Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
|
||||
* Michael Zucchi <notzed@helixcode.com>
|
||||
*
|
||||
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
|
||||
*
|
||||
@ -23,7 +23,6 @@
|
||||
* USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CAMEL_FOLDER_H
|
||||
#define CAMEL_FOLDER_H 1
|
||||
|
||||
@ -50,22 +49,24 @@ struct _CamelFolderChangeInfo {
|
||||
|
||||
GHashTable *uid_source; /* used to create unique lists */
|
||||
struct _EMemPool *uid_pool; /* pool used to store copies of uid strings */
|
||||
struct _CamelFolderChangeInfoPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CamelFolder
|
||||
{
|
||||
CamelObject parent_object;
|
||||
|
||||
int frozen;
|
||||
CamelFolderChangeInfo *changed_frozen; /* queues changed events */
|
||||
struct _CamelFolderPrivate *priv;
|
||||
|
||||
char *name;
|
||||
char *full_name;
|
||||
CamelStore *parent_store;
|
||||
CamelFolderSummary *summary;
|
||||
|
||||
guint32 permanent_flags;
|
||||
gboolean has_summary_capability:1;
|
||||
gboolean has_search_capability:1;
|
||||
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -137,7 +138,8 @@ typedef struct {
|
||||
|
||||
void (*search_free) (CamelFolder *folder, GPtrArray *result);
|
||||
|
||||
const CamelMessageInfo * (*get_message_info) (CamelFolder *, const char *uid);
|
||||
CamelMessageInfo * (*get_message_info) (CamelFolder *, const char *uid);
|
||||
void (*free_message_info) (CamelFolder *, CamelMessageInfo *);
|
||||
|
||||
void (*copy_message_to) (CamelFolder *source,
|
||||
const char *uid,
|
||||
@ -250,9 +252,10 @@ GPtrArray * camel_folder_search_by_expression (CamelFolder *folder,
|
||||
void camel_folder_search_free (CamelFolder *folder, GPtrArray *);
|
||||
|
||||
/* summary info */
|
||||
const CamelMessageInfo *camel_folder_get_message_info (CamelFolder *summary,
|
||||
const char *uid);
|
||||
CamelMessageInfo *camel_folder_get_message_info (CamelFolder *folder, const char *uid);
|
||||
void camel_folder_free_message_info (CamelFolder *folder, CamelMessageInfo *info);
|
||||
|
||||
/* FIXME: copy-message-to is not required */
|
||||
void camel_folder_copy_message_to (CamelFolder *source,
|
||||
const char *uid,
|
||||
CamelFolder *dest,
|
||||
@ -263,9 +266,15 @@ void camel_folder_move_message_to (CamelFolder *source,
|
||||
CamelFolder *dest,
|
||||
CamelException *ex);
|
||||
|
||||
/* stop/restart getting events */
|
||||
void camel_folder_freeze (CamelFolder *folder);
|
||||
void camel_folder_thaw (CamelFolder *folder);
|
||||
|
||||
#if 0
|
||||
/* lock/unlock at the thread level, NOTE: only used internally */
|
||||
void camel_folder_lock (CamelFolder *folder);
|
||||
void camel_folder_unlock (CamelFolder *folder);
|
||||
#endif
|
||||
|
||||
/* For use by subclasses (for free_{uids,summary,subfolder_names}) */
|
||||
void camel_folder_free_nop (CamelFolder *folder, GPtrArray *array);
|
||||
|
||||
153
camel/camel-private.h
Normal file
153
camel/camel-private.h
Normal file
@ -0,0 +1,153 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
* camel-private.h: Private info for class implementers.
|
||||
*
|
||||
* Authors: Michael Zucchi <notzed@helixcode.com>
|
||||
*
|
||||
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifndef CAMEL_PRIVATE_H
|
||||
#define CAMEL_PRIVATE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#pragma }
|
||||
#endif /* __cplusplus }*/
|
||||
|
||||
/* need a way to configure and save this data, if this header is to
|
||||
be installed. For now, dont install it */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#include "e-util/e-msgport.h"
|
||||
#endif
|
||||
|
||||
struct _CamelFolderPrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *lock;
|
||||
GMutex *change_lock;
|
||||
#endif
|
||||
|
||||
/* must require the 'change_lock' to access this */
|
||||
int frozen;
|
||||
struct _CamelFolderChangeInfo *changed_frozen; /* queues changed events */
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelFolder *)f)->priv->l))
|
||||
#define CAMEL_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelFolder *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_FOLDER_LOCK(f, l)
|
||||
#define CAMEL_FOLDER_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
struct _CamelStorePrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *folder_lock; /* for locking folder operations */
|
||||
GMutex *cache_lock; /* for locking access to the cache */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_STORE_LOCK(f, l) (g_mutex_lock(((CamelStore *)f)->priv->l))
|
||||
#define CAMEL_STORE_UNLOCK(f, l) (g_mutex_unlock(((CamelStore *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_STORE_LOCK(f, l)
|
||||
#define CAMEL_STORE_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
struct _CamelServicePrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
EMutex *connect_lock; /* for locking connection operations */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_SERVICE_LOCK(f, l) (e_mutex_lock(((CamelService *)f)->priv->l))
|
||||
#define CAMEL_SERVICE_UNLOCK(f, l) (e_mutex_unlock(((CamelService *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_SERVICE_LOCK(f, l)
|
||||
#define CAMEL_SERVICE_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
struct _CamelSessionPrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *lock; /* for locking everything basically */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_SESSION_LOCK(f, l) (g_mutex_lock(((CamelSession *)f)->priv->l))
|
||||
#define CAMEL_SESSION_UNLOCK(f, l) (g_mutex_unlock(((CamelSession *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_SESSION_LOCK(f, l)
|
||||
#define CAMEL_SESSION_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
|
||||
struct _CamelRemoteStorePrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
EMutex *stream_lock; /* for locking stream operations */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_REMOTE_STORE_LOCK(f, l) (e_mutex_lock(((CamelRemoteStore *)f)->priv->l))
|
||||
#define CAMEL_REMOTE_STORE_UNLOCK(f, l) (e_mutex_unlock(((CamelRemoteStore *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_REMOTE_STORE_LOCK(f, l)
|
||||
#define CAMEL_REMOTE_STORE_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
/* most of this stuff really is private, but the lock can be used by subordinate classes */
|
||||
struct _CamelFolderSummaryPrivate {
|
||||
GHashTable *filter_charset; /* CamelMimeFilterCharset's indexed by source charset */
|
||||
|
||||
CamelMimeFilterIndex *filter_index;
|
||||
CamelMimeFilterBasic *filter_64;
|
||||
CamelMimeFilterBasic *filter_qp;
|
||||
CamelMimeFilterSave *filter_save;
|
||||
|
||||
struct ibex *index;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *summary_lock; /* for the summary hashtable/array */
|
||||
GMutex *io_lock; /* load/save lock, for access to saved_count, etc */
|
||||
GMutex *filter_lock; /* for accessing any of the filtering/indexing stuff, since we share them */
|
||||
GMutex *alloc_lock; /* for setting up and using allocators */
|
||||
GMutex *ref_lock; /* for reffing/unreffing messageinfo's ALWAYS obtain before summary_lock */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_SUMMARY_LOCK(f, l) (g_mutex_lock(((CamelFolderSummary *)f)->priv->l))
|
||||
#define CAMEL_SUMMARY_UNLOCK(f, l) (g_mutex_unlock(((CamelFolderSummary *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_SUMMARY_LOCK(f, l)
|
||||
#define CAMEL_SUMMARY_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CAMEL_H */
|
||||
|
||||
@ -47,6 +47,8 @@
|
||||
#include "camel-url.h"
|
||||
#include "string-utils.h"
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
#define d(x) x
|
||||
#if d(!)0
|
||||
extern gboolean camel_verbose_debug;
|
||||
@ -112,17 +114,24 @@ camel_remote_store_init (CamelObject *object)
|
||||
remote_store->istream = NULL;
|
||||
remote_store->ostream = NULL;
|
||||
remote_store->timeout_id = 0;
|
||||
|
||||
remote_store->priv = g_malloc0(sizeof(*remote_store->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
remote_store->priv->stream_lock = e_mutex_new(E_MUTEX_REC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
camel_remote_store_finalise(CamelObject *object)
|
||||
{
|
||||
CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
e_mutex_destroy(remote_store->priv->stream_lock);
|
||||
#endif
|
||||
g_free(remote_store->priv);
|
||||
}
|
||||
|
||||
/*
|
||||
*static void
|
||||
*camel_remote_store_finalize (CamelObject *object)
|
||||
*{
|
||||
* CamelRemoteStore *remote_store = CAMEL_REMOTE_STORE (object);
|
||||
*
|
||||
* g_free (remote_store->nice_name);
|
||||
*}
|
||||
*/
|
||||
|
||||
CamelType
|
||||
camel_remote_store_get_type (void)
|
||||
@ -137,7 +146,7 @@ camel_remote_store_get_type (void)
|
||||
(CamelObjectClassInitFunc) camel_remote_store_class_init,
|
||||
NULL,
|
||||
(CamelObjectInitFunc) camel_remote_store_init,
|
||||
(CamelObjectFinalizeFunc) NULL);
|
||||
(CamelObjectFinalizeFunc) camel_remote_store_finalise);
|
||||
}
|
||||
|
||||
return camel_remote_store_type;
|
||||
@ -193,7 +202,14 @@ remote_get_name (CamelService *service, gboolean brief)
|
||||
static gboolean
|
||||
timeout_cb (gpointer data)
|
||||
{
|
||||
CRSC (data)->keepalive (CAMEL_REMOTE_STORE (data));
|
||||
CamelRemoteStore *store = CAMEL_REMOTE_STORE(data);
|
||||
|
||||
CAMEL_REMOTE_STORE_LOCK(store, stream_lock);
|
||||
|
||||
CRSC (data)->keepalive(store);
|
||||
|
||||
CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -331,6 +347,9 @@ remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_l
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: All of these functions need an api overhaul, they're not like
|
||||
any other functions, anywhere in the world ... */
|
||||
|
||||
/**
|
||||
* camel_remote_store_send_string: Writes a string to the server
|
||||
* @store: a CamelRemoteStore
|
||||
@ -353,7 +372,9 @@ camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex,
|
||||
g_return_val_if_fail (fmt, -1);
|
||||
|
||||
va_start (ap, fmt);
|
||||
CAMEL_REMOTE_STORE_LOCK(store, stream_lock);
|
||||
ret = CRSC (store)->send_string (store, ex, fmt, ap);
|
||||
CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock);
|
||||
va_end (ap);
|
||||
|
||||
return ret;
|
||||
@ -362,9 +383,11 @@ camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex,
|
||||
static gint
|
||||
remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check for connectedness. Failed (or cancelled) operations will
|
||||
* close the connection. */
|
||||
|
||||
|
||||
if (store->ostream == NULL) {
|
||||
d(g_message ("remote: (sendstream) disconnected, reconnecting."));
|
||||
|
||||
@ -374,15 +397,15 @@ remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException
|
||||
|
||||
d(fprintf (stderr, "(sending stream)\n"));
|
||||
|
||||
if (camel_stream_write_to_stream (stream, store->ostream) < 0) {
|
||||
ret = camel_stream_write_to_stream (stream, store->ostream);
|
||||
if (ret < 0) {
|
||||
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
|
||||
g_strerror (errno));
|
||||
|
||||
camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -398,10 +421,18 @@ remote_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException
|
||||
gint
|
||||
camel_remote_store_send_stream (CamelRemoteStore *store, CamelStream *stream, CamelException *ex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1);
|
||||
g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
|
||||
|
||||
CAMEL_REMOTE_STORE_LOCK(store, stream_lock);
|
||||
|
||||
return CRSC (store)->send_stream (store, stream, ex);
|
||||
ret = CRSC (store)->send_stream (store, stream, ex);
|
||||
|
||||
CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -476,7 +507,7 @@ remote_recv_line (CamelRemoteStore *store, char **dest, CamelException *ex)
|
||||
* @dest: a pointer that will be set to the location of a buffer
|
||||
* holding the server's response
|
||||
* @ex: a CamelException
|
||||
* Return value: 0 on success, -1 on error
|
||||
* Return value: -1 on error, otherwise the length read.
|
||||
*
|
||||
* Reads a line from the server (terminated by \n or \r\n).
|
||||
**/
|
||||
@ -485,10 +516,18 @@ gint
|
||||
camel_remote_store_recv_line (CamelRemoteStore *store, char **dest,
|
||||
CamelException *ex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_REMOTE_STORE (store), -1);
|
||||
g_return_val_if_fail (dest, -1);
|
||||
|
||||
CAMEL_REMOTE_STORE_LOCK(store, stream_lock);
|
||||
|
||||
return CRSC (store)->recv_line (store, dest, ex);
|
||||
ret = CRSC (store)->recv_line (store, dest, ex);
|
||||
|
||||
CAMEL_REMOTE_STORE_UNLOCK(store, stream_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -507,9 +546,12 @@ refresh_folder_info (gpointer key, gpointer value, gpointer data)
|
||||
*
|
||||
* Refreshes the folders listed in the folders hashtable.
|
||||
**/
|
||||
|
||||
void
|
||||
camel_remote_store_refresh_folders (CamelRemoteStore *store, CamelException *ex)
|
||||
{
|
||||
CAMEL_STORE_LOCK(store, cache_lock);
|
||||
|
||||
g_hash_table_foreach (CAMEL_STORE (store)->folders, refresh_folder_info, ex);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, cache_lock);
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ extern "C" {
|
||||
|
||||
typedef struct {
|
||||
CamelStore parent_object;
|
||||
|
||||
struct _CamelRemoteStorePrivate *priv;
|
||||
|
||||
CamelStream *istream, *ostream;
|
||||
guint timeout_id, default_port;
|
||||
} CamelRemoteStore;
|
||||
@ -62,6 +63,9 @@ typedef struct {
|
||||
/* Standard Camel function */
|
||||
CamelType camel_remote_store_get_type (void);
|
||||
|
||||
/* FIXME: All of these i/o functions need an api overhaul, they're not like
|
||||
any other functions, anywhere in the world ... */
|
||||
|
||||
/* Extra public functions */
|
||||
gint camel_remote_store_send_string (CamelRemoteStore *store, CamelException *ex,
|
||||
char *fmt, ...);
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
static CamelObjectClass *parent_class = NULL;
|
||||
|
||||
/* Returns the class for a CamelService */
|
||||
@ -63,6 +65,17 @@ camel_service_class_init (CamelServiceClass *camel_service_class)
|
||||
camel_service_class->get_path = get_path;
|
||||
}
|
||||
|
||||
static void
|
||||
camel_service_init (void *o, void *k)
|
||||
{
|
||||
CamelService *service = o;
|
||||
|
||||
service->priv = g_malloc0(sizeof(*service->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
service->priv->connect_lock = e_mutex_new(E_MUTEX_REC);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
camel_service_finalize (CamelObject *object)
|
||||
{
|
||||
@ -85,6 +98,11 @@ camel_service_finalize (CamelObject *object)
|
||||
camel_url_free (camel_service->url);
|
||||
if (camel_service->session)
|
||||
camel_object_unref (CAMEL_OBJECT (camel_service->session));
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
e_mutex_destroy(camel_service->priv->connect_lock);
|
||||
#endif
|
||||
g_free(camel_service->priv);
|
||||
}
|
||||
|
||||
|
||||
@ -100,7 +118,7 @@ camel_service_get_type (void)
|
||||
sizeof (CamelServiceClass),
|
||||
(CamelObjectClassInitFunc) camel_service_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
(CamelObjectInitFunc) camel_service_init,
|
||||
camel_service_finalize );
|
||||
}
|
||||
|
||||
@ -209,24 +227,28 @@ service_connect (CamelService *service, CamelException *ex)
|
||||
gboolean
|
||||
camel_service_connect (CamelService *service, CamelException *ex)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
|
||||
g_return_val_if_fail (service->session != NULL, FALSE);
|
||||
g_return_val_if_fail (service->url != NULL, FALSE);
|
||||
|
||||
CAMEL_SERVICE_LOCK(service, connect_lock);
|
||||
|
||||
if (service->connected) {
|
||||
/* But we're still connected, so no exception
|
||||
* and return true.
|
||||
*/
|
||||
g_warning ("camel_service_connect: trying to connect to an already connected service");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (CSERV_CLASS (service)->connect (service, ex)) {
|
||||
ret = TRUE;
|
||||
} else if (CSERV_CLASS (service)->connect (service, ex)) {
|
||||
service->connected = TRUE;
|
||||
return TRUE;
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
CAMEL_SERVICE_UNLOCK(service, connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -257,13 +279,17 @@ gboolean
|
||||
camel_service_disconnect (CamelService *service, gboolean clean,
|
||||
CamelException *ex)
|
||||
{
|
||||
gboolean res;
|
||||
gboolean res = TRUE;
|
||||
|
||||
if (!service->connected)
|
||||
return TRUE;
|
||||
CAMEL_SERVICE_LOCK(service, connect_lock);
|
||||
|
||||
if (service->connected) {
|
||||
res = CSERV_CLASS (service)->disconnect (service, clean, ex);
|
||||
service->connected = FALSE;
|
||||
}
|
||||
|
||||
CAMEL_SERVICE_UNLOCK(service, connect_lock);
|
||||
|
||||
res = CSERV_CLASS (service)->disconnect (service, clean, ex);
|
||||
service->connected = FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -431,10 +457,20 @@ query_auth_types_func (CamelService *service, CamelException *ex)
|
||||
GList *
|
||||
camel_service_query_auth_types (CamelService *service, CamelException *ex)
|
||||
{
|
||||
GList *ret;
|
||||
|
||||
/* note that we get the connect lock here, which means the callee
|
||||
must not call the connect functions itself */
|
||||
CAMEL_SERVICE_LOCK(service, connect_lock);
|
||||
|
||||
if (service->url->empty)
|
||||
return CSERV_CLASS (service)->query_auth_types_generic (service, ex);
|
||||
ret = CSERV_CLASS (service)->query_auth_types_generic (service, ex);
|
||||
else
|
||||
return CSERV_CLASS (service)->query_auth_types_connected (service, ex);
|
||||
ret = CSERV_CLASS (service)->query_auth_types_connected (service, ex);
|
||||
|
||||
CAMEL_SERVICE_UNLOCK(service, connect_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -475,6 +511,8 @@ camel_service_gethost (CamelService *service, CamelException *ex)
|
||||
struct hostent *h;
|
||||
char *hostname;
|
||||
|
||||
#warning "This needs to use gethostbyname_r()"
|
||||
|
||||
if (service->url->host)
|
||||
hostname = service->url->host;
|
||||
else
|
||||
|
||||
@ -47,6 +47,7 @@ extern "C" {
|
||||
|
||||
struct _CamelService {
|
||||
CamelObject parent_object;
|
||||
struct _CamelServicePrivate *priv;
|
||||
|
||||
CamelSession *session;
|
||||
CamelProvider *provider;
|
||||
|
||||
@ -41,6 +41,8 @@
|
||||
#include "camel-url.h"
|
||||
#include "hash-table-utils.h"
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
static CamelObjectClass *parent_class;
|
||||
|
||||
static void
|
||||
@ -48,6 +50,10 @@ camel_session_init (CamelSession *session)
|
||||
{
|
||||
session->modules = camel_provider_init ();
|
||||
session->providers = g_hash_table_new (g_strcase_hash, g_strcase_equal);
|
||||
session->priv = g_malloc0(sizeof(*session->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
session->priv->lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -69,6 +75,12 @@ camel_session_finalise (CamelObject *o)
|
||||
g_hash_table_foreach_remove (session->providers,
|
||||
camel_session_destroy_provider, NULL);
|
||||
g_hash_table_destroy (session->providers);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(session->priv->lock);
|
||||
#endif
|
||||
|
||||
g_free(session->priv);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -131,6 +143,9 @@ camel_session_new (const char *storage_path,
|
||||
* @provider: provider object
|
||||
*
|
||||
* Registers a protocol to provider mapping for the session.
|
||||
*
|
||||
* Assumes the session lock has already been obtained,
|
||||
* which is the case for automatically loaded provider modules.
|
||||
**/
|
||||
void
|
||||
camel_session_register_provider (CamelSession *session,
|
||||
@ -194,12 +209,16 @@ camel_session_list_providers (CamelSession *session, gboolean load)
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
|
||||
|
||||
if (load) {
|
||||
CAMEL_SESSION_LOCK(session, lock);
|
||||
|
||||
if (load)
|
||||
g_hash_table_foreach (session->modules, ensure_loaded, session);
|
||||
}
|
||||
|
||||
list = NULL;
|
||||
g_hash_table_foreach (session->providers, add_to_list, &list);
|
||||
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -213,8 +232,12 @@ service_cache_remove (CamelService *service, gpointer event_data, gpointer user_
|
||||
g_return_if_fail (service != NULL);
|
||||
g_return_if_fail (service->url != NULL);
|
||||
|
||||
CAMEL_SESSION_LOCK(session, lock);
|
||||
|
||||
provider = g_hash_table_lookup (session->providers, service->url->protocol);
|
||||
g_hash_table_remove (provider->service_cache, service->url);
|
||||
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,6 +273,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
|
||||
|
||||
/* We need to look up the provider so we can then lookup
|
||||
the service in the provider's cache */
|
||||
CAMEL_SESSION_LOCK(session, lock);
|
||||
provider = g_hash_table_lookup (session->providers, url->protocol);
|
||||
if (!provider) {
|
||||
/* See if there's one we can load. */
|
||||
@ -261,6 +285,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
|
||||
if (camel_exception_get_id (ex) !=
|
||||
CAMEL_EXCEPTION_NONE) {
|
||||
camel_url_free (url);
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -272,6 +297,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
|
||||
_("No provider available for protocol `%s'"),
|
||||
url->protocol);
|
||||
camel_url_free (url);
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -280,6 +306,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
|
||||
if (service != NULL) {
|
||||
camel_url_free (url);
|
||||
camel_object_ref (CAMEL_OBJECT (service));
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
return service;
|
||||
}
|
||||
|
||||
@ -288,6 +315,7 @@ camel_session_get_service (CamelSession *session, const char *url_string,
|
||||
g_hash_table_insert (provider->service_cache, url, service);
|
||||
camel_object_hook_event (CAMEL_OBJECT (service), "finalize", (CamelObjectEventHookFunc) service_cache_remove, session);
|
||||
}
|
||||
CAMEL_SESSION_UNLOCK(session, lock);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
@ -60,6 +60,7 @@ typedef gboolean (*CamelTimeoutRemoveCallback) (guint id);
|
||||
struct _CamelSession
|
||||
{
|
||||
CamelObject parent_object;
|
||||
struct _CamelSessionPrivate *priv;
|
||||
|
||||
char *storage_path;
|
||||
CamelAuthCallback authenticator;
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
#include "camel-folder.h"
|
||||
#include "camel-exception.h"
|
||||
|
||||
#include "camel-private.h"
|
||||
|
||||
static CamelServiceClass *parent_class = NULL;
|
||||
|
||||
/* Returns the class for a CamelStore */
|
||||
@ -93,6 +95,12 @@ camel_store_init (void *o, void *k)
|
||||
if (store->folders == NULL)
|
||||
store->folders = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
store->flags = 0;
|
||||
|
||||
store->priv = g_malloc0(sizeof(*store->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
store->priv->folder_lock = g_mutex_new();
|
||||
store->priv->cache_lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -108,6 +116,12 @@ camel_store_finalize (CamelObject *object)
|
||||
}
|
||||
g_hash_table_destroy (store->folders);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(store->priv->folder_lock);
|
||||
g_mutex_free(store->priv->cache_lock);
|
||||
#endif
|
||||
g_free(store->priv);
|
||||
}
|
||||
|
||||
|
||||
@ -185,13 +199,19 @@ get_default_folder_name (CamelStore *store, CamelException *ex)
|
||||
static CamelFolder *
|
||||
lookup_folder (CamelStore *store, const char *folder_name)
|
||||
{
|
||||
CamelFolder *folder = NULL;
|
||||
|
||||
CAMEL_STORE_LOCK(store, cache_lock);
|
||||
|
||||
if (store->folders) {
|
||||
CamelFolder *folder = g_hash_table_lookup (store->folders, folder_name);
|
||||
folder = g_hash_table_lookup (store->folders, folder_name);
|
||||
if (folder)
|
||||
camel_object_ref(CAMEL_OBJECT(folder));
|
||||
return folder;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, cache_lock);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
static void folder_finalize (CamelObject *folder, gpointer event_data, gpointer user_data)
|
||||
@ -202,16 +222,18 @@ static void folder_finalize (CamelObject *folder, gpointer event_data, gpointer
|
||||
static void
|
||||
cache_folder (CamelStore *store, const char *folder_name, CamelFolder *folder)
|
||||
{
|
||||
if (!store->folders)
|
||||
return;
|
||||
CAMEL_STORE_LOCK(store, cache_lock);
|
||||
|
||||
if (g_hash_table_lookup (store->folders, folder_name)) {
|
||||
g_warning ("Caching folder %s that already exists.",
|
||||
folder_name);
|
||||
if (store->folders) {
|
||||
if (g_hash_table_lookup (store->folders, folder_name)) {
|
||||
g_warning ("Caching folder %s that already exists.", folder_name);
|
||||
}
|
||||
g_hash_table_insert (store->folders, g_strdup (folder_name), folder);
|
||||
|
||||
camel_object_hook_event (CAMEL_OBJECT (folder), "finalize", folder_finalize, store);
|
||||
}
|
||||
g_hash_table_insert (store->folders, g_strdup (folder_name), folder);
|
||||
|
||||
camel_object_hook_event (CAMEL_OBJECT (folder), "finalize", folder_finalize, store);
|
||||
CAMEL_STORE_UNLOCK(store, cache_lock);
|
||||
|
||||
/*
|
||||
* gt_k so as not to get caught by my little gt_k cleanliness detector.
|
||||
@ -235,7 +257,11 @@ folder_matches (gpointer key, gpointer value, gpointer user_data)
|
||||
static void
|
||||
uncache_folder (CamelStore *store, CamelFolder *folder)
|
||||
{
|
||||
CAMEL_STORE_LOCK(store, cache_lock);
|
||||
|
||||
g_hash_table_foreach_remove (store->folders, folder_matches, folder);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, cache_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -244,6 +270,8 @@ get_folder_internal(CamelStore *store, const char *folder_name, guint32 flags, C
|
||||
{
|
||||
CamelFolder *folder = NULL;
|
||||
|
||||
/* NB: we already have folder_lock */
|
||||
|
||||
/* Try cache first. */
|
||||
folder = CS_CLASS(store)->lookup_folder(store, folder_name);
|
||||
|
||||
@ -279,11 +307,16 @@ camel_store_get_folder(CamelStore *store, const char *folder_name, guint32 flags
|
||||
char *name;
|
||||
CamelFolder *folder = NULL;
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
name = CS_CLASS(store)->get_folder_name(store, folder_name, ex);
|
||||
if (name) {
|
||||
folder = get_folder_internal(store, name, flags, ex);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
@ -302,11 +335,15 @@ camel_store_delete_folder (CamelStore *store, const char *folder_name,
|
||||
{
|
||||
char *name;
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
name = CS_CLASS (store)->get_folder_name (store, folder_name, ex);
|
||||
if (name) {
|
||||
CS_CLASS (store)->delete_folder (store, name, ex);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,6 +362,8 @@ void camel_store_rename_folder (CamelStore *store,
|
||||
{
|
||||
char *old, *new;
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
old = CS_CLASS (store)->get_folder_name(store, old_name, ex);
|
||||
if (old) {
|
||||
new = CS_CLASS (store)->get_folder_name(store, new_name, ex);
|
||||
@ -334,6 +373,8 @@ void camel_store_rename_folder (CamelStore *store,
|
||||
}
|
||||
g_free(old);
|
||||
}
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -351,11 +392,16 @@ camel_store_get_root_folder (CamelStore *store, CamelException *ex)
|
||||
char *name;
|
||||
CamelFolder *folder = NULL;
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
name = CS_CLASS (store)->get_root_folder_name (store, ex);
|
||||
if (name) {
|
||||
folder = get_folder_internal (store, name, CAMEL_STORE_FOLDER_CREATE, ex);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
@ -374,11 +420,16 @@ camel_store_get_default_folder (CamelStore *store, CamelException *ex)
|
||||
char *name;
|
||||
CamelFolder *folder = NULL;
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
name = CS_CLASS (store)->get_default_folder_name (store, ex);
|
||||
if (name) {
|
||||
folder = get_folder_internal (store, name, CAMEL_STORE_FOLDER_CREATE, ex);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
|
||||
return folder;
|
||||
}
|
||||
|
||||
@ -420,11 +471,17 @@ camel_store_get_folder_info (CamelStore *store, const char *top,
|
||||
gboolean subscribed_only,
|
||||
CamelException *ex)
|
||||
{
|
||||
CamelFolderInfo *ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
|
||||
|
||||
return CS_CLASS (store)->get_folder_info (store, top, fast,
|
||||
recursive, subscribed_only,
|
||||
ex);
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
ret = CS_CLASS (store)->get_folder_info (store, top, fast, recursive, subscribed_only, ex);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -596,10 +653,18 @@ gboolean
|
||||
camel_store_folder_subscribed (CamelStore *store,
|
||||
const char *folder_name)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
|
||||
g_return_val_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS, FALSE);
|
||||
|
||||
return CS_CLASS (store)->folder_subscribed (store, folder_name);
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
ret = CS_CLASS (store)->folder_subscribed (store, folder_name);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -622,7 +687,11 @@ camel_store_subscribe_folder (CamelStore *store,
|
||||
g_return_if_fail (CAMEL_IS_STORE (store));
|
||||
g_return_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS);
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
CS_CLASS (store)->subscribe_folder (store, folder_name, ex);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -646,6 +715,10 @@ camel_store_unsubscribe_folder (CamelStore *store,
|
||||
g_return_if_fail (CAMEL_IS_STORE (store));
|
||||
g_return_if_fail (store->flags & CAMEL_STORE_SUBSCRIPTIONS);
|
||||
|
||||
CAMEL_STORE_LOCK(store, folder_lock);
|
||||
|
||||
CS_CLASS (store)->unsubscribe_folder (store, folder_name, ex);
|
||||
|
||||
CAMEL_STORE_UNLOCK(store, folder_lock);
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +57,9 @@ typedef struct _CamelFolderInfo {
|
||||
struct _CamelStore
|
||||
{
|
||||
CamelService parent_object;
|
||||
struct _CamelStorePrivate *priv;
|
||||
|
||||
/* should have cache_lock when accessing this (priv->cache_lock) */
|
||||
GHashTable *folders;
|
||||
|
||||
int flags;
|
||||
@ -99,6 +101,7 @@ typedef struct {
|
||||
void (*uncache_folder) (CamelStore *store,
|
||||
CamelFolder *folder);
|
||||
|
||||
/* this should take flags instead, so its more futureproof */
|
||||
CamelFolderInfo *(*get_folder_info) (CamelStore *store,
|
||||
const char *top,
|
||||
gboolean fast,
|
||||
|
||||
@ -71,6 +71,7 @@ gboolean camel_transport_send (CamelTransport *transport,
|
||||
CamelMedium *message,
|
||||
CamelException *ex);
|
||||
|
||||
/* FIXME: This should use a camel-address */
|
||||
gboolean camel_transport_send_to (CamelTransport *transport,
|
||||
CamelMedium *message,
|
||||
GList *recipients,
|
||||
|
||||
@ -34,7 +34,7 @@ camel_init(void)
|
||||
{
|
||||
#ifdef ENABLE_THREADS
|
||||
#ifdef G_THREADS_ENABLED
|
||||
g_thread_init (NULL);
|
||||
/*g_thread_init (NULL);*/
|
||||
#else /* G_THREADS_ENABLED */
|
||||
printf ("Threads are not supported by your version of glib\n");
|
||||
#endif /* G_THREADS_ENABLED */
|
||||
|
||||
@ -42,6 +42,9 @@ libcamelimapinclude_HEADERS = \
|
||||
|
||||
libcamelimap_la_LDFLAGS = $(KRB4_LDFLAGS) -version-info 0:0:0
|
||||
|
||||
noinst_HEADERS = \
|
||||
camel-imap-private.h
|
||||
|
||||
EXTRA_DIST = libcamelimap.urls
|
||||
|
||||
|
||||
|
||||
@ -42,6 +42,10 @@
|
||||
#include "camel-imap-command.h"
|
||||
#include "camel-imap-utils.h"
|
||||
|
||||
#include "camel-imap-private.h"
|
||||
|
||||
#ifdef HAVE_KRB4
|
||||
|
||||
static char *
|
||||
base64_encode_simple (const char *data, int len)
|
||||
{
|
||||
@ -66,7 +70,6 @@ base64_decode_simple (char *data, int len)
|
||||
(unsigned char *)data, &state, &save);
|
||||
}
|
||||
|
||||
#ifdef HAVE_KRB4
|
||||
#define IMAP_KERBEROS_V4_PROTECTION_NONE 1
|
||||
#define IMAP_KERBEROS_V4_PROTECTION_INTEGRITY 2
|
||||
#define IMAP_KERBEROS_V4_PROTECTION_PRIVACY 4
|
||||
@ -85,14 +88,17 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
|
||||
des_cblock session;
|
||||
des_key_schedule schedule;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
|
||||
/* The kickoff. */
|
||||
response = camel_imap_command (store, NULL, ex,
|
||||
"AUTHENTICATE KERBEROS_V4");
|
||||
if (!response)
|
||||
return FALSE;
|
||||
goto fail;
|
||||
resp = camel_imap_response_extract_continuation (response, ex);
|
||||
if (!resp)
|
||||
return FALSE;
|
||||
goto fail;
|
||||
|
||||
data = imap_next_word (resp);
|
||||
|
||||
/* First server response is a base64-encoded 32-bit random number
|
||||
@ -182,6 +188,7 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
|
||||
if (!response)
|
||||
goto lose;
|
||||
camel_imap_response_free (response);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
return TRUE;
|
||||
|
||||
break_and_lose:
|
||||
@ -197,6 +204,8 @@ imap_try_kerberos_v4_auth (CamelImapStore *store, CamelException *ex)
|
||||
camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
|
||||
_("Bad authentication response from server."));
|
||||
}
|
||||
fail:
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* HAVE_KRB4 */
|
||||
|
||||
@ -67,6 +67,9 @@ static char *imap_command_strdup_vprintf (CamelImapStore *store,
|
||||
* and quoted strings otherwise. (%S does not support strings that
|
||||
* contain newlines.)
|
||||
*
|
||||
* This function assumes you have an exclusive lock on the command
|
||||
* channel/stream.
|
||||
*
|
||||
* Return value: %NULL if an error occurred (in which case @ex will
|
||||
* be set). Otherwise, a CamelImapResponse describing the server's
|
||||
* response, which the caller must free with camel_imap_response_free().
|
||||
@ -120,6 +123,8 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
|
||||
* This method is for sending continuing responses to the IMAP server
|
||||
* after camel_imap_command returns a CAMEL_IMAP_PLUS response.
|
||||
*
|
||||
* This function assumes you have an exclusive lock on the remote stream.
|
||||
*
|
||||
* Return value: as for camel_imap_command()
|
||||
**/
|
||||
CamelImapResponse *
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
#include "camel-mime-filter-crlf.h"
|
||||
#include "camel-exception.h"
|
||||
#include "camel-mime-utils.h"
|
||||
#include "camel-imap-private.h"
|
||||
|
||||
#define d(x) x
|
||||
|
||||
@ -69,10 +70,6 @@ static void imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex
|
||||
static const char *imap_get_full_name (CamelFolder *folder);
|
||||
static void imap_expunge (CamelFolder *folder, CamelException *ex);
|
||||
|
||||
/* message counts */
|
||||
static gint imap_get_message_count (CamelFolder *folder);
|
||||
static gint imap_get_unread_message_count (CamelFolder *folder);
|
||||
|
||||
/* message manipulation */
|
||||
static CamelMimeMessage *imap_get_message (CamelFolder *folder, const gchar *uid,
|
||||
CamelException *ex);
|
||||
@ -84,10 +81,6 @@ static void imap_move_message_to (CamelFolder *source, const char *uid,
|
||||
CamelFolder *destination, CamelException *ex);
|
||||
|
||||
/* summary info */
|
||||
static GPtrArray *imap_get_uids (CamelFolder *folder);
|
||||
static GPtrArray *imap_get_summary (CamelFolder *folder);
|
||||
static const CamelMessageInfo *imap_get_message_info (CamelFolder *folder, const char *uid);
|
||||
|
||||
static void imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
CamelFolderChangeInfo *changes,
|
||||
CamelException *ex);
|
||||
@ -119,27 +112,13 @@ camel_imap_folder_class_init (CamelImapFolderClass *camel_imap_folder_class)
|
||||
camel_folder_class->expunge = imap_expunge;
|
||||
camel_folder_class->get_full_name = imap_get_full_name;
|
||||
|
||||
camel_folder_class->get_uids = imap_get_uids;
|
||||
camel_folder_class->free_uids = camel_folder_free_nop;
|
||||
|
||||
camel_folder_class->get_message_count = imap_get_message_count;
|
||||
camel_folder_class->get_unread_message_count = imap_get_unread_message_count;
|
||||
camel_folder_class->get_message = imap_get_message;
|
||||
camel_folder_class->append_message = imap_append_message;
|
||||
camel_folder_class->copy_message_to = imap_copy_message_to;
|
||||
camel_folder_class->move_message_to = imap_move_message_to;
|
||||
|
||||
camel_folder_class->get_summary = imap_get_summary;
|
||||
camel_folder_class->get_message_info = imap_get_message_info;
|
||||
camel_folder_class->free_summary = camel_folder_free_nop;
|
||||
|
||||
camel_folder_class->search_by_expression = imap_search_by_expression;
|
||||
camel_folder_class->search_free = imap_search_free;
|
||||
|
||||
camel_folder_class->get_message_flags = imap_get_message_flags;
|
||||
camel_folder_class->set_message_flags = imap_set_message_flags;
|
||||
camel_folder_class->get_message_user_flag = imap_get_message_user_flag;
|
||||
camel_folder_class->set_message_user_flag = imap_set_message_user_flag;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -151,7 +130,11 @@ camel_imap_folder_init (gpointer object, gpointer klass)
|
||||
folder->has_summary_capability = TRUE;
|
||||
folder->has_search_capability = TRUE;
|
||||
|
||||
imap_folder->summary = NULL;
|
||||
folder->summary = NULL;
|
||||
imap_folder->priv = g_malloc0(sizeof(*imap_folder->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
imap_folder->priv->search_lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
CamelType
|
||||
@ -188,7 +171,10 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
|
||||
|
||||
camel_folder_construct (folder, parent, folder_name, short_name);
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, folder, ex, NULL);
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
|
||||
if (!response) {
|
||||
camel_object_unref ((CamelObject *)folder);
|
||||
return NULL;
|
||||
@ -213,8 +199,8 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name,
|
||||
}
|
||||
camel_imap_response_free (response);
|
||||
|
||||
imap_folder->summary = camel_imap_summary_new (summary_file, validity);
|
||||
if (!imap_folder->summary) {
|
||||
folder->summary = camel_imap_summary_new (summary_file, validity);
|
||||
if (!folder->summary) {
|
||||
camel_object_unref (CAMEL_OBJECT (folder));
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
|
||||
_("Could not load summary for %s"),
|
||||
@ -236,9 +222,13 @@ imap_finalize (CamelObject *object)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (object);
|
||||
|
||||
camel_object_unref ((CamelObject *)imap_folder->summary);
|
||||
if (imap_folder->search)
|
||||
camel_object_unref ((CamelObject *)imap_folder->search);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(imap_folder->priv->search_lock);
|
||||
#endif
|
||||
g_free(imap_folder->priv);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -262,9 +252,11 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
|
||||
|
||||
/* Get UIDs and flags of all messages. */
|
||||
if (imap_folder->exists) {
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"FETCH 1:%d (UID FLAGS)",
|
||||
imap_folder->exists);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
if (!response) {
|
||||
camel_folder_change_info_free (changes);
|
||||
return;
|
||||
@ -298,18 +290,21 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
|
||||
* the UID in the folder, that it means the message was
|
||||
* deleted on the server, so we remove it from the summary.
|
||||
*/
|
||||
summary_len = camel_folder_summary_count (imap_folder->summary);
|
||||
summary_len = camel_folder_summary_count (folder->summary);
|
||||
for (i = 0; i < summary_len && i < imap_folder->exists; i++) {
|
||||
info = camel_folder_summary_index (imap_folder->summary, i);
|
||||
iinfo = (CamelImapMessageInfo *)info;
|
||||
|
||||
/* Shouldn't happen, but... */
|
||||
if (!new[i].uid)
|
||||
continue;
|
||||
|
||||
info = camel_folder_summary_index (imap_folder->summary, i);
|
||||
iinfo = (CamelImapMessageInfo *)info;
|
||||
|
||||
if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) {
|
||||
camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
|
||||
camel_folder_summary_remove (imap_folder->summary, info);
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
folder_changed = TRUE;
|
||||
g_free (new[i].uid);
|
||||
i--;
|
||||
summary_len--;
|
||||
continue;
|
||||
@ -328,14 +323,17 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
|
||||
camel_folder_change_info_change_uid (changes, new[i].uid);
|
||||
}
|
||||
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
g_free (new[i].uid);
|
||||
}
|
||||
|
||||
/* Remove any leftover cached summary messages. */
|
||||
while (summary_len > i + 1) {
|
||||
info = camel_folder_summary_index (imap_folder->summary, --summary_len);
|
||||
info = camel_folder_summary_index (folder->summary, --summary_len);
|
||||
camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
|
||||
camel_folder_summary_remove (imap_folder->summary, info);
|
||||
camel_folder_summary_remove (folder->summary, info);
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
/* Add any new folder messages. */
|
||||
@ -360,40 +358,48 @@ static void
|
||||
imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
/*CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);*/
|
||||
CamelImapResponse *response;
|
||||
int i, max;
|
||||
|
||||
/* Set the flags on any messages that have changed this session */
|
||||
max = camel_folder_summary_count (imap_folder->summary);
|
||||
max = camel_folder_summary_count (folder->summary);
|
||||
for (i = 0; i < max; i++) {
|
||||
CamelMessageInfo *info;
|
||||
|
||||
info = camel_folder_summary_index (imap_folder->summary, i);
|
||||
if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
|
||||
info = camel_folder_summary_index (folder->summary, i);
|
||||
if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
|
||||
char *flags;
|
||||
|
||||
flags = imap_create_flag_list (info->flags);
|
||||
if (flags) {
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (
|
||||
store, folder, ex,
|
||||
"UID STORE %s FLAGS.SILENT %s",
|
||||
camel_message_info_uid(info), flags);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
|
||||
g_free (flags);
|
||||
if (!response)
|
||||
if (!response) {
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
return;
|
||||
}
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
}
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
if (expunge) {
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, folder, ex, "EXPUNGE");
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
camel_folder_summary_save (imap_folder->summary);
|
||||
camel_folder_summary_save (folder->summary);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -417,31 +423,6 @@ imap_get_full_name (CamelFolder *folder)
|
||||
return folder->full_name;
|
||||
}
|
||||
|
||||
static gint
|
||||
imap_get_message_count (CamelFolder *folder)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
|
||||
return camel_folder_summary_count (imap_folder->summary);
|
||||
}
|
||||
|
||||
static gint
|
||||
imap_get_unread_message_count (CamelFolder *folder)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
CamelMessageInfo *info;
|
||||
int i, max, count = 0;
|
||||
|
||||
max = camel_folder_summary_count (imap_folder->summary);
|
||||
for (i = 0; i < max; i++) {
|
||||
info = camel_folder_summary_index (imap_folder->summary, i);
|
||||
if (!(info->flags & CAMEL_MESSAGE_SEEN))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
const CamelMessageInfo *info, CamelException *ex)
|
||||
@ -476,6 +457,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
camel_object_unref (CAMEL_OBJECT (crlf_filter));
|
||||
camel_object_unref (CAMEL_OBJECT (memstream));
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, NULL, ex, "APPEND %S%s%s {%d}",
|
||||
folder->full_name, flagstr ? " " : "",
|
||||
flagstr ? flagstr : "", ba->len);
|
||||
@ -483,11 +465,13 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
|
||||
if (!response) {
|
||||
g_byte_array_free (ba, TRUE);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
return;
|
||||
}
|
||||
result = camel_imap_response_extract_continuation (response, ex);
|
||||
if (!result) {
|
||||
g_byte_array_free (ba, TRUE);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
return;
|
||||
}
|
||||
g_free (result);
|
||||
@ -496,6 +480,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
|
||||
g_byte_array_append (ba, "\0", 3);
|
||||
response = camel_imap_command_continuation (store, ex, ba->data);
|
||||
g_byte_array_free (ba, TRUE);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
if (!response)
|
||||
return;
|
||||
camel_imap_response_free (response);
|
||||
@ -508,8 +493,11 @@ imap_copy_message_to (CamelFolder *source, const char *uid,
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
|
||||
CamelImapResponse *response;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, source, ex, "UID COPY %s %S",
|
||||
uid, destination->full_name);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
@ -520,8 +508,10 @@ imap_move_message_to (CamelFolder *source, const char *uid,
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
|
||||
CamelImapResponse *response;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, source, ex, "UID COPY %s %S",
|
||||
uid, destination->full_name);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
camel_imap_response_free (response);
|
||||
|
||||
if (camel_exception_is_set (ex))
|
||||
@ -530,27 +520,6 @@ imap_move_message_to (CamelFolder *source, const char *uid,
|
||||
camel_folder_delete_message (source, uid);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
imap_get_uids (CamelFolder *folder)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
const CamelMessageInfo *info;
|
||||
GPtrArray *array;
|
||||
int i, count;
|
||||
|
||||
count = camel_folder_summary_count (imap_folder->summary);
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
g_ptr_array_set_size (array, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
info = camel_folder_summary_index (imap_folder->summary, i);
|
||||
array->pdata[i] = g_strdup (camel_message_info_uid(info));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static CamelMimeMessage *
|
||||
imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
{
|
||||
@ -561,8 +530,11 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
char *result, *mesg, *p;
|
||||
int len;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"UID FETCH %s BODY.PEEK[]", uid);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
|
||||
if (!response)
|
||||
return NULL;
|
||||
result = camel_imap_response_extract (response, "FETCH", ex);
|
||||
@ -622,7 +594,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
CamelFolderChangeInfo *changes, CamelException *ex)
|
||||
{
|
||||
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
/*CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);*/
|
||||
CamelImapResponse *response;
|
||||
GPtrArray *headers = NULL;
|
||||
char *q, *summary_specifier;
|
||||
@ -630,6 +602,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
int i;
|
||||
|
||||
summary_specifier = imap_protocol_get_summary_specifier (store);
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
if (first == last) {
|
||||
response = camel_imap_command (store, folder, ex,
|
||||
"FETCH %d (%s)", first,
|
||||
@ -639,6 +612,7 @@ imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
"FETCH %d:%d (%s)", first,
|
||||
last, summary_specifier);
|
||||
}
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
g_free (summary_specifier);
|
||||
|
||||
if (!response)
|
||||
@ -683,9 +657,10 @@ imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
/* We can't just call camel_folder_summary_add_from_parser
|
||||
* because it will assign the wrong UID, and thus get the
|
||||
* uid hash table wrong and all that. FIXME some day.
|
||||
* Well you can actually now, because you can override next_uid_string(), but
|
||||
* it hasn't been done yet.
|
||||
*/
|
||||
info = camel_folder_summary_info_new_from_header (
|
||||
imap_folder->summary, h);
|
||||
info = camel_folder_summary_info_new_from_header(folder->summary, h);
|
||||
iinfo = (CamelImapMessageInfo *)info;
|
||||
header_raw_clear (&h);
|
||||
uid = g_strndup (uid, q - uid);
|
||||
@ -708,42 +683,33 @@ imap_update_summary (CamelFolder *folder, int first, int last,
|
||||
} else
|
||||
info->size = strtoul (size + 12, NULL, 10);
|
||||
|
||||
camel_folder_summary_add (imap_folder->summary, info);
|
||||
camel_folder_summary_add (folder->summary, info);
|
||||
}
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
imap_get_summary (CamelFolder *folder)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
|
||||
return imap_folder->summary->messages;
|
||||
}
|
||||
|
||||
/* get a single message info, by uid */
|
||||
static const CamelMessageInfo *
|
||||
imap_get_message_info (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
|
||||
return camel_folder_summary_uid (imap_folder->summary, uid);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
|
||||
{
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
|
||||
GPtrArray *matches, *summary;
|
||||
|
||||
/* we could get around this by creating a new search object each time,
|
||||
but i doubt its worth it since any long operation would lock the
|
||||
command channel too */
|
||||
CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
|
||||
|
||||
if (!imap_folder->search)
|
||||
imap_folder->search = camel_imap_search_new ();
|
||||
|
||||
camel_folder_search_set_folder (imap_folder->search, folder);
|
||||
camel_folder_search_set_summary (
|
||||
imap_folder->search, imap_folder->summary->messages);
|
||||
summary = camel_folder_get_summary(folder);
|
||||
camel_folder_search_set_summary(imap_folder->search, summary);
|
||||
uids = camel_folder_search_execute_expression (imap_folder->search, expression, ex);
|
||||
|
||||
return camel_folder_search_execute_expression (imap_folder->search,
|
||||
expression, ex);
|
||||
CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
|
||||
|
||||
camel_folder_free_summary(folder, summary);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -753,54 +719,11 @@ imap_search_free (CamelFolder *folder, GPtrArray *uids)
|
||||
|
||||
g_return_if_fail (imap_folder->search);
|
||||
|
||||
CAMEL_IMAP_FOLDER_LOCK(folder, search_lock);
|
||||
|
||||
camel_folder_search_free_result (imap_folder->search, uids);
|
||||
}
|
||||
|
||||
static guint32
|
||||
imap_get_message_flags (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
const CamelMessageInfo *info;
|
||||
|
||||
info = imap_get_message_info (folder, uid);
|
||||
g_return_val_if_fail (info != NULL, 0);
|
||||
|
||||
return info->flags;
|
||||
}
|
||||
|
||||
static void
|
||||
imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
|
||||
{
|
||||
CamelImapFolder *imap_folder = (CamelImapFolder *)folder;
|
||||
CamelMessageInfo *info;
|
||||
guint32 new;
|
||||
|
||||
info = camel_folder_summary_uid (imap_folder->summary, uid);
|
||||
g_return_if_fail (info != NULL);
|
||||
|
||||
new = (info->flags & ~flags) | (set & flags);
|
||||
if (new == info->flags)
|
||||
return;
|
||||
|
||||
info->flags = new | CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
camel_folder_summary_touch (imap_folder->summary);
|
||||
|
||||
camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
|
||||
(gpointer)uid);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
imap_get_message_user_flag (CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
/* FIXME */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
imap_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value)
|
||||
{
|
||||
/* FIXME */
|
||||
camel_object_trigger_event (CAMEL_OBJECT (folder), "message_changed",
|
||||
(gpointer)uid);
|
||||
CAMEL_IMAP_FOLDER_UNLOCK(folder, search_lock);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -44,6 +44,8 @@ extern "C" {
|
||||
typedef struct {
|
||||
CamelFolder parent_object;
|
||||
|
||||
struct _CamelImapFolderPrivate *priv;
|
||||
|
||||
CamelFolderSearch *search;
|
||||
CamelFolderSummary *summary;
|
||||
int exists;
|
||||
|
||||
74
camel/providers/imap/camel-imap-private.h
Normal file
74
camel/providers/imap/camel-imap-private.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
* camel-imap-private.h: Private info for imap.
|
||||
*
|
||||
* Authors: Michael Zucchi <notzed@helixcode.com>
|
||||
*
|
||||
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifndef CAMEL_PRIVATE_H
|
||||
#define CAMEL_PRIVATE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#pragma }
|
||||
#endif /* __cplusplus }*/
|
||||
|
||||
/* need a way to configure and save this data, if this header is to
|
||||
be installed. For now, dont install it */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include "e-util/e-msgport.h"
|
||||
#endif
|
||||
|
||||
struct _CamelImapStorePrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
EMutex *command_lock; /* for locking the command stream for a complete operation */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_IMAP_STORE_LOCK(f, l) (e_mutex_lock(((CamelImapStore *)f)->priv->l))
|
||||
#define CAMEL_IMAP_STORE_UNLOCK(f, l) (e_mutex_unlock(((CamelImapStore *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_IMAP_STORE_LOCK(f, l)
|
||||
#define CAMEL_IMAP_STORE_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
struct _CamelImapFolderPrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *search_lock; /* for locking the search object */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_IMAP_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelImapFolder *)f)->priv->l))
|
||||
#define CAMEL_IMAP_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelImapFolder *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_IMAP_FOLDER_LOCK(f, l)
|
||||
#define CAMEL_IMAP_FOLDER_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CAMEL_H */
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "camel-imap-command.h"
|
||||
#include "camel-imap-folder.h"
|
||||
#include "camel-imap-search.h"
|
||||
#include "camel-imap-private.h"
|
||||
|
||||
static ESExpResult *
|
||||
imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
|
||||
@ -72,10 +73,13 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
|
||||
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (s->folder);
|
||||
char *value = argv[0]->value.string;
|
||||
CamelImapResponse *response;
|
||||
char *result, *p, *lasts = NULL;
|
||||
char *result, *p, *lasts = NULL, *real_uid;
|
||||
const char *uid;
|
||||
ESExpResult *r;
|
||||
CamelMessageInfo *info;
|
||||
GHashTable *uid_hash = NULL;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
|
||||
if (s->current) {
|
||||
uid = camel_message_info_uid (s->current);
|
||||
@ -91,6 +95,9 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
|
||||
"UID SEARCH BODY \"%s\"",
|
||||
value);
|
||||
}
|
||||
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
|
||||
if (!response)
|
||||
return r;
|
||||
result = camel_imap_response_extract (response, "SEARCH", NULL);
|
||||
@ -105,14 +112,27 @@ imap_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* FIXME: The strings added to the array must be
|
||||
* static...
|
||||
*/
|
||||
info = camel_folder_summary_uid (imap_folder->summary, p);
|
||||
g_ptr_array_add (r->value.ptrarray, (char *)camel_message_info_uid (info));
|
||||
/* if we need to setup a hash of summary items, this way we get
|
||||
access to the summary memory which is locked for the duration of
|
||||
the search, and wont vanish on us */
|
||||
if (uid_hash == NULL) {
|
||||
int i;
|
||||
|
||||
uid_hash = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
for (i=0;i<s->summary->len;i++) {
|
||||
info = s->summary->pdata[i];
|
||||
g_hash_table_insert(uid_hash, camel_message_info_uid(info), info);
|
||||
}
|
||||
}
|
||||
if (g_hash_table_lookup_extended(uid_hash, p, &real_uid, &info))
|
||||
g_ptr_array_add (r->value.ptrarray, real_uid);
|
||||
}
|
||||
}
|
||||
|
||||
/* we could probably cache this globally, but its probably not worth it */
|
||||
if (uid_hash)
|
||||
g_hash_table_destroy(uid_hash);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,8 @@
|
||||
#include "camel-url.h"
|
||||
#include "string-utils.h"
|
||||
|
||||
#include "camel-imap-private.h"
|
||||
|
||||
#define d(x) x
|
||||
|
||||
/* Specified in RFC 2060 */
|
||||
@ -121,6 +123,10 @@ camel_imap_store_finalize (CamelObject *object)
|
||||
g_hash_table_foreach_remove (imap_store->subscribed_folders,
|
||||
free_sub, NULL);
|
||||
g_hash_table_destroy (imap_store->subscribed_folders);
|
||||
#ifdef ENABLE_THREADS
|
||||
e_mutex_destroy(imap_store->priv->command_lock);
|
||||
#endif
|
||||
g_free(imap_store->priv);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -139,6 +145,11 @@ camel_imap_store_init (gpointer object, gpointer klass)
|
||||
|
||||
imap_store->connected = FALSE;
|
||||
imap_store->subscribed_folders = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
imap_store->priv = g_malloc0(sizeof(*imap_store->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
imap_store->priv->command_lock = e_mutex_new(E_MUTEX_REC);
|
||||
#endif
|
||||
}
|
||||
|
||||
CamelType
|
||||
@ -175,6 +186,7 @@ static struct {
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/* we have remote-store:connect_lock by now */
|
||||
static gboolean
|
||||
connect_to_server (CamelService *service, CamelException *ex)
|
||||
{
|
||||
@ -351,10 +363,12 @@ imap_connect (CamelService *service, CamelException *ex)
|
||||
}
|
||||
}
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, NULL, ex,
|
||||
"LOGIN %S %S",
|
||||
service->url->user,
|
||||
service->url->passwd);
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
if (!response) {
|
||||
errbuf = g_strdup_printf (_("Unable to authenticate "
|
||||
"to IMAP server.\n%s\n\n"),
|
||||
@ -380,6 +394,8 @@ imap_connect (CamelService *service, CamelException *ex)
|
||||
namespace++;
|
||||
else
|
||||
namespace = "";
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
if (store->server_level >= IMAP_LEVEL_IMAP4REV1) {
|
||||
/* This idiom means "tell me the hierarchy separator
|
||||
* for the given path, even if that path doesn't exist.
|
||||
@ -396,6 +412,8 @@ imap_connect (CamelService *service, CamelException *ex)
|
||||
"LIST \"\" %S",
|
||||
namespace);
|
||||
}
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
|
||||
if (!response)
|
||||
return FALSE;
|
||||
|
||||
@ -431,7 +449,11 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
|
||||
|
||||
if (store->connected && clean) {
|
||||
/* send the logout command */
|
||||
|
||||
/* NB: this lock probably isn't required */
|
||||
CAMEL_IMAP_STORE_LOCK(store, command_lock);
|
||||
response = camel_imap_command (store, NULL, ex, "LOGOUT");
|
||||
CAMEL_IMAP_STORE_UNLOCK(store, command_lock);
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
@ -440,6 +462,7 @@ imap_disconnect (CamelService *service, gboolean clean, CamelException *ex)
|
||||
return CAMEL_SERVICE_CLASS (remote_store_class)->disconnect (service, clean, ex);
|
||||
}
|
||||
|
||||
/* NOTE: Must have imap_store::command_lock before calling this */
|
||||
static gboolean
|
||||
imap_folder_exists (CamelImapStore *store, const char *folder_name,
|
||||
gboolean *selectable, char **short_name,
|
||||
@ -481,6 +504,7 @@ imap_folder_exists (CamelImapStore *store, const char *folder_name,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* NOTE: Must have imap_store::command_lock before calling this */
|
||||
static gboolean
|
||||
imap_create (CamelImapStore *store, const char *folder_name,
|
||||
CamelException *ex)
|
||||
@ -503,18 +527,19 @@ get_folder (CamelStore *store, const char *folder_name, guint32 flags,
|
||||
char *short_name, *summary_file, *p;
|
||||
gboolean selectable;
|
||||
|
||||
/* lock around the whole lot to check/create atomically */
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
if (!imap_folder_exists (imap_store, folder_name,
|
||||
&selectable, &short_name, ex)) {
|
||||
if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0)
|
||||
return NULL;
|
||||
|
||||
if (!imap_create (imap_store, folder_name, ex))
|
||||
return NULL;
|
||||
|
||||
if (!imap_folder_exists (imap_store, folder_name,
|
||||
&selectable, &short_name, ex))
|
||||
if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0
|
||||
|| (!imap_create (imap_store, folder_name, ex))
|
||||
|| (!imap_folder_exists (imap_store, folder_name,
|
||||
&selectable, &short_name, ex))) {
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
|
||||
if (!selectable) {
|
||||
camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
|
||||
@ -621,8 +646,10 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
|
||||
else
|
||||
name = "";
|
||||
}
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, NULL, ex,
|
||||
"LIST \"\" %S", name);
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
if (!response)
|
||||
return FALSE;
|
||||
list = camel_imap_response_extract (response, "LIST", ex);
|
||||
@ -642,10 +669,13 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
|
||||
else
|
||||
pattern = g_strdup_printf ("%s%c", name,
|
||||
recursive ? '*' : '%');
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, NULL, ex,
|
||||
"%s \"\" %S",
|
||||
subscribed_only ? "LSUB" : "LIST",
|
||||
pattern);
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
|
||||
g_free (pattern);
|
||||
if (!response)
|
||||
return NULL;
|
||||
@ -694,10 +724,12 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
|
||||
if (!fi->url)
|
||||
continue;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (
|
||||
imap_store, NULL, NULL,
|
||||
"STATUS %S (MESSAGES UNSEEN)",
|
||||
fi->full_name);
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
if (!response)
|
||||
continue;
|
||||
status = camel_imap_response_extract (
|
||||
@ -757,6 +789,7 @@ subscribe_folder (CamelStore *store, const char *folder_name,
|
||||
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
|
||||
CamelImapResponse *response;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, NULL, ex,
|
||||
"SUBSCRIBE %S", folder_name);
|
||||
if (response) {
|
||||
@ -774,9 +807,11 @@ unsubscribe_folder (CamelStore *store, const char *folder_name,
|
||||
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
|
||||
CamelImapResponse *response;
|
||||
gpointer key, value;
|
||||
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, NULL, ex,
|
||||
"UNSUBSCRIBE %S", folder_name);
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
if (response) {
|
||||
g_hash_table_lookup_extended (imap_store->subscribed_folders,
|
||||
folder_name, &key, &value);
|
||||
@ -793,6 +828,8 @@ imap_keepalive (CamelRemoteStore *store)
|
||||
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
|
||||
CamelImapResponse *response;
|
||||
|
||||
CAMEL_IMAP_STORE_LOCK(imap_store, command_lock);
|
||||
response = camel_imap_command (imap_store, NULL, NULL, "NOOP");
|
||||
CAMEL_IMAP_STORE_UNLOCK(imap_store, command_lock);
|
||||
camel_imap_response_free (response);
|
||||
}
|
||||
|
||||
@ -56,7 +56,8 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
CamelRemoteStore parent_object;
|
||||
|
||||
struct _CamelImapStorePrivate *priv;
|
||||
|
||||
CamelFolder *current_folder;
|
||||
|
||||
guint32 command;
|
||||
|
||||
@ -47,6 +47,9 @@ libcamellocalinclude_HEADERS = \
|
||||
camel-maildir-store.h \
|
||||
camel-maildir-summary.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
camel-local-private.h
|
||||
|
||||
libcamellocal_la_LDFLAGS = -version-info 0:0:0
|
||||
|
||||
libcamellocal_la_LIBADD = $(top_builddir)/e-util/libeutil.la $(top_builddir)/libibex/libibex.la $(UNICODE_LIBS)
|
||||
|
||||
@ -42,6 +42,8 @@
|
||||
#include "camel-mime-filter-from.h"
|
||||
#include "camel-exception.h"
|
||||
|
||||
#include "camel-local-private.h"
|
||||
|
||||
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
|
||||
|
||||
static CamelFolderClass *parent_class = NULL;
|
||||
@ -55,30 +57,11 @@ static int local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *
|
||||
static void local_unlock(CamelLocalFolder *lf);
|
||||
|
||||
static void local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex);
|
||||
static gint local_get_message_count(CamelFolder *folder);
|
||||
static gint local_get_unread_message_count(CamelFolder *folder);
|
||||
|
||||
static GPtrArray *local_get_uids(CamelFolder *folder);
|
||||
static GPtrArray *local_get_summary(CamelFolder *folder);
|
||||
#if 0
|
||||
static void local_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, CamelException *ex);
|
||||
static CamelMimeMessage *local_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex);
|
||||
#endif
|
||||
static void local_expunge(CamelFolder *folder, CamelException *ex);
|
||||
|
||||
static const CamelMessageInfo *local_get_message_info(CamelFolder *folder, const char *uid);
|
||||
|
||||
static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
|
||||
static void local_search_free(CamelFolder *folder, GPtrArray * result);
|
||||
|
||||
static guint32 local_get_message_flags(CamelFolder *folder, const char *uid);
|
||||
static void local_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set);
|
||||
static gboolean local_get_message_user_flag(CamelFolder *folder, const char *uid, const char *name);
|
||||
static void local_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value);
|
||||
static const char *local_get_message_user_tag(CamelFolder *folder, const char *uid, const char *name);
|
||||
static void local_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value);
|
||||
|
||||
|
||||
static void local_finalize(CamelObject * object);
|
||||
|
||||
static void
|
||||
@ -92,26 +75,11 @@ camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class)
|
||||
|
||||
/* virtual method overload */
|
||||
camel_folder_class->sync = local_sync;
|
||||
camel_folder_class->get_message_count = local_get_message_count;
|
||||
camel_folder_class->get_unread_message_count = local_get_unread_message_count;
|
||||
camel_folder_class->get_uids = local_get_uids;
|
||||
camel_folder_class->free_uids = camel_folder_free_deep;
|
||||
camel_folder_class->get_summary = local_get_summary;
|
||||
camel_folder_class->free_summary = camel_folder_free_nop;
|
||||
camel_folder_class->expunge = local_expunge;
|
||||
|
||||
camel_folder_class->search_by_expression = local_search_by_expression;
|
||||
camel_folder_class->search_free = local_search_free;
|
||||
|
||||
camel_folder_class->get_message_info = local_get_message_info;
|
||||
|
||||
camel_folder_class->get_message_flags = local_get_message_flags;
|
||||
camel_folder_class->set_message_flags = local_set_message_flags;
|
||||
camel_folder_class->get_message_user_flag = local_get_message_user_flag;
|
||||
camel_folder_class->set_message_user_flag = local_set_message_user_flag;
|
||||
camel_folder_class->get_message_user_tag = local_get_message_user_tag;
|
||||
camel_folder_class->set_message_user_tag = local_set_message_user_tag;
|
||||
|
||||
camel_local_folder_class->lock = local_lock;
|
||||
camel_local_folder_class->unlock = local_unlock;
|
||||
}
|
||||
@ -129,18 +97,25 @@ local_init(gpointer object, gpointer klass)
|
||||
CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
|
||||
CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_USER;
|
||||
|
||||
local_folder->summary = NULL;
|
||||
folder->summary = NULL;
|
||||
local_folder->search = NULL;
|
||||
|
||||
local_folder->priv = g_malloc0(sizeof(*local_folder->priv));
|
||||
#ifdef ENABLE_THREADS
|
||||
local_folder->priv->search_lock = g_mutex_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
local_finalize(CamelObject * object)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(object);
|
||||
CamelFolder *folder = (CamelFolder *)object;
|
||||
|
||||
if (local_folder->summary) {
|
||||
camel_local_summary_sync(local_folder->summary, FALSE, local_folder->changes, NULL);
|
||||
camel_object_unref((CamelObject *)local_folder->summary);
|
||||
if (folder->summary) {
|
||||
camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, local_folder->changes, NULL);
|
||||
camel_object_unref((CamelObject *)folder->summary);
|
||||
folder->summary = NULL;
|
||||
}
|
||||
|
||||
if (local_folder->search) {
|
||||
@ -160,6 +135,11 @@ local_finalize(CamelObject * object)
|
||||
g_free(local_folder->index_path);
|
||||
|
||||
camel_folder_change_info_free(local_folder->changes);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
g_mutex_free(local_folder->priv->search_lock);
|
||||
#endif
|
||||
g_free(local_folder->priv);
|
||||
}
|
||||
|
||||
CamelType camel_local_folder_get_type(void)
|
||||
@ -228,8 +208,8 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con
|
||||
|
||||
lf->flags = flags;
|
||||
|
||||
lf->summary = CLOCALF_CLASS(lf)->create_summary(lf->summary_path, lf->folder_path, lf->index);
|
||||
if (camel_local_summary_load(lf->summary, forceindex, ex) == -1) {
|
||||
folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf->summary_path, lf->folder_path, lf->index);
|
||||
if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, ex) == -1) {
|
||||
camel_object_unref (CAMEL_OBJECT (folder));
|
||||
return NULL;
|
||||
}
|
||||
@ -289,7 +269,7 @@ local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
return;
|
||||
|
||||
/* if sync fails, we'll pass it up on exit through ex */
|
||||
camel_local_summary_sync(lf->summary, expunge, lf->changes, ex);
|
||||
camel_local_summary_sync((CamelLocalSummary *)folder->summary, expunge, lf->changes, ex);
|
||||
camel_local_folder_unlock(lf);
|
||||
|
||||
if (camel_folder_change_info_changed(lf->changes)) {
|
||||
@ -300,8 +280,8 @@ local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
/* force save of metadata */
|
||||
if (lf->index)
|
||||
ibex_save(lf->index);
|
||||
if (lf->summary)
|
||||
camel_folder_summary_save(CAMEL_FOLDER_SUMMARY(lf->summary));
|
||||
if (folder->summary)
|
||||
camel_folder_summary_save(folder->summary);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -310,105 +290,36 @@ local_expunge(CamelFolder *folder, CamelException *ex)
|
||||
d(printf("expunge\n"));
|
||||
|
||||
/* Just do a sync with expunge, serves the same purpose */
|
||||
camel_folder_sync(folder, TRUE, ex);
|
||||
}
|
||||
|
||||
/*
|
||||
The following functions all work off the summary, so the default operations provided
|
||||
in camel-local-folder will suffice for all subclasses. They may want to
|
||||
snoop various operations to ensure the status remains synced, or just wait
|
||||
for the sync operation
|
||||
*/
|
||||
static gint
|
||||
local_get_message_count(CamelFolder *folder)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
g_return_val_if_fail(local_folder->summary != NULL, -1);
|
||||
|
||||
return camel_folder_summary_count(CAMEL_FOLDER_SUMMARY(local_folder->summary));
|
||||
}
|
||||
|
||||
static gint
|
||||
local_get_unread_message_count(CamelFolder *folder)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
CamelMessageInfo *info;
|
||||
GPtrArray *infolist;
|
||||
gint i, max, count = 0;
|
||||
|
||||
g_return_val_if_fail(local_folder->summary != NULL, -1);
|
||||
|
||||
max = camel_folder_summary_count(CAMEL_FOLDER_SUMMARY(local_folder->summary));
|
||||
if (max == -1)
|
||||
return -1;
|
||||
|
||||
infolist = local_get_summary(folder);
|
||||
|
||||
for (i = 0; i < infolist->len; i++) {
|
||||
info = (CamelMessageInfo *) g_ptr_array_index(infolist, i);
|
||||
if (!(info->flags & CAMEL_MESSAGE_SEEN))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
local_get_uids(CamelFolder *folder)
|
||||
{
|
||||
GPtrArray *array;
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
int i, count;
|
||||
|
||||
count = camel_folder_summary_count(CAMEL_FOLDER_SUMMARY(local_folder->summary));
|
||||
array = g_ptr_array_new();
|
||||
g_ptr_array_set_size(array, count);
|
||||
for (i = 0; i < count; i++) {
|
||||
CamelMessageInfo *info = camel_folder_summary_index(CAMEL_FOLDER_SUMMARY(local_folder->summary), i);
|
||||
|
||||
array->pdata[i] = g_strdup(camel_message_info_uid(info));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
local_get_summary(CamelFolder *folder)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
return CAMEL_FOLDER_SUMMARY(local_folder->summary)->messages;
|
||||
}
|
||||
|
||||
/* get a single message info, by uid */
|
||||
static const CamelMessageInfo *
|
||||
local_get_message_info(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
return camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(local_folder->summary), uid);
|
||||
/* call the callback directly, to avoid locking problems */
|
||||
CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, TRUE, ex);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
GPtrArray *summary, *matches;
|
||||
|
||||
if (local_folder->search == NULL) {
|
||||
/* NOTE: could get away without the search lock by creating a new
|
||||
search object each time */
|
||||
|
||||
CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
|
||||
|
||||
if (local_folder->search == NULL)
|
||||
local_folder->search = camel_folder_search_new();
|
||||
}
|
||||
|
||||
camel_folder_search_set_folder(local_folder->search, folder);
|
||||
if (local_folder->summary) {
|
||||
/* FIXME: dont access summary array directly? */
|
||||
camel_folder_search_set_summary(local_folder->search,
|
||||
CAMEL_FOLDER_SUMMARY(local_folder->summary)->messages);
|
||||
}
|
||||
|
||||
camel_folder_search_set_body_index(local_folder->search, local_folder->index);
|
||||
summary = camel_folder_get_summary(folder);
|
||||
camel_folder_search_set_summary(local_folder->search, summary);
|
||||
|
||||
return camel_folder_search_execute_expression(local_folder->search, expression, ex);
|
||||
matches = camel_folder_search_execute_expression(local_folder->search, expression, ex);
|
||||
|
||||
CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
|
||||
|
||||
camel_folder_free_summary(folder, summary);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -416,97 +327,11 @@ local_search_free(CamelFolder *folder, GPtrArray * result)
|
||||
{
|
||||
CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
/* we need to lock this free because of the way search_free_result works */
|
||||
/* FIXME: put the lock inside search_free_result */
|
||||
CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
|
||||
|
||||
camel_folder_search_free_result(local_folder->search, result);
|
||||
|
||||
CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
|
||||
}
|
||||
|
||||
static guint32
|
||||
local_get_message_flags(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_val_if_fail(info != NULL, 0);
|
||||
|
||||
return info->flags;
|
||||
}
|
||||
|
||||
static void
|
||||
local_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
guint32 new;
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
new = (info->flags & ~flags) | (set & flags);
|
||||
if (new == info->flags)
|
||||
return;
|
||||
|
||||
info->flags = new | CAMEL_MESSAGE_FOLDER_FLAGGED;
|
||||
camel_folder_summary_touch(CAMEL_FOLDER_SUMMARY(mf->summary));
|
||||
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
local_get_message_user_flag(CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_val_if_fail(info != NULL, FALSE);
|
||||
|
||||
return camel_flag_get(&info->user_flags, name);
|
||||
}
|
||||
|
||||
static void
|
||||
local_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (!camel_flag_set(&info->user_flags, name, value))
|
||||
return;
|
||||
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
|
||||
camel_folder_summary_touch(CAMEL_FOLDER_SUMMARY(mf->summary));
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
|
||||
static const char *
|
||||
local_get_message_user_tag(CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_val_if_fail(info != NULL, FALSE);
|
||||
|
||||
return camel_tag_get(&info->user_tags, name);
|
||||
}
|
||||
|
||||
static void
|
||||
local_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelLocalFolder *mf = CAMEL_LOCAL_FOLDER(folder);
|
||||
|
||||
info = camel_folder_summary_uid(CAMEL_FOLDER_SUMMARY(mf->summary), uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (!camel_tag_set(&info->user_tags, name, value))
|
||||
return;
|
||||
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
|
||||
camel_folder_summary_touch(CAMEL_FOLDER_SUMMARY(mf->summary));
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ extern "C" {
|
||||
|
||||
typedef struct {
|
||||
CamelFolder parent_object;
|
||||
struct _CamelLocalFolderPrivate *priv;
|
||||
|
||||
guint32 flags; /* open mode flags */
|
||||
|
||||
@ -55,7 +56,6 @@ typedef struct {
|
||||
char *index_path; /* where the index file lives */
|
||||
|
||||
ibex *index; /* index for this folder */
|
||||
CamelLocalSummary *summary;
|
||||
CamelFolderSearch *search; /* used to run searches, we just use the real thing (tm) */
|
||||
CamelFolderChangeInfo *changes; /* used to store changes to the folder during processing */
|
||||
} CamelLocalFolder;
|
||||
|
||||
60
camel/providers/local/camel-local-private.h
Normal file
60
camel/providers/local/camel-local-private.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
* camel-local-private.h: Private info for local provider.
|
||||
*
|
||||
* Authors: Michael Zucchi <notzed@helixcode.com>
|
||||
*
|
||||
* Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifndef CAMEL_PRIVATE_H
|
||||
#define CAMEL_PRIVATE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#pragma }
|
||||
#endif /* __cplusplus }*/
|
||||
|
||||
/* need a way to configure and save this data, if this header is to
|
||||
be installed. For now, dont install it */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
struct _CamelLocalFolderPrivate {
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *search_lock; /* for locking the search object */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#define CAMEL_LOCAL_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelLocalFolder *)f)->priv->l))
|
||||
#define CAMEL_LOCAL_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelLocalFolder *)f)->priv->l))
|
||||
#else
|
||||
#define CAMEL_LOCAL_FOLDER_LOCK(f, l)
|
||||
#define CAMEL_LOCAL_FOLDER_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CAMEL_H */
|
||||
|
||||
@ -42,19 +42,7 @@ struct _CamelLocalSummaryPrivate {
|
||||
|
||||
#define _PRIVATE(o) (((CamelLocalSummary *)(o))->priv)
|
||||
|
||||
#if 0
|
||||
static int summary_header_load (CamelFolderSummary *, FILE *);
|
||||
static int summary_header_save (CamelFolderSummary *, FILE *);
|
||||
#endif
|
||||
|
||||
static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _header_raw *);
|
||||
static CamelMessageInfo * message_info_new_from_parser (CamelFolderSummary *, CamelMimeParser *);
|
||||
static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg);
|
||||
#if 0
|
||||
static CamelMessageInfo * message_info_load (CamelFolderSummary *, FILE *);
|
||||
static int message_info_save (CamelFolderSummary *, FILE *, CamelMessageInfo *);
|
||||
#endif
|
||||
/*static void message_info_free (CamelFolderSummary *, CamelMessageInfo *);*/
|
||||
|
||||
static int local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelMessageInfo *mi);
|
||||
static char *local_summary_encode_x_evolution(CamelLocalSummary *cls, const CamelMessageInfo *mi);
|
||||
@ -67,7 +55,6 @@ static CamelMessageInfo *local_summary_add(CamelLocalSummary *cls, CamelMimeMess
|
||||
static void camel_local_summary_class_init (CamelLocalSummaryClass *klass);
|
||||
static void camel_local_summary_init (CamelLocalSummary *obj);
|
||||
static void camel_local_summary_finalise (CamelObject *obj);
|
||||
|
||||
static CamelFolderSummaryClass *camel_local_summary_parent;
|
||||
|
||||
CamelType
|
||||
@ -95,16 +82,7 @@ camel_local_summary_class_init(CamelLocalSummaryClass *klass)
|
||||
|
||||
camel_local_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type()));
|
||||
|
||||
/*sklass->summary_header_load = summary_header_load;
|
||||
sklass->summary_header_save = summary_header_save;*/
|
||||
|
||||
sklass->message_info_new = message_info_new;
|
||||
sklass->message_info_new_from_parser = message_info_new_from_parser;
|
||||
sklass->message_info_new_from_message = message_info_new_from_message;
|
||||
|
||||
/*sklass->message_info_load = message_info_load;
|
||||
sklass->message_info_save = message_info_save;*/
|
||||
/*sklass->message_info_free = message_info_free;*/
|
||||
|
||||
klass->load = local_summary_load;
|
||||
klass->check = local_summary_check;
|
||||
@ -288,6 +266,7 @@ camel_local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changei
|
||||
for (i=0;i<camel_folder_summary_count(s);i++) {
|
||||
CamelMessageInfo *info = camel_folder_summary_index(s, i);
|
||||
do_stat_mi(cls, &stats, info);
|
||||
camel_folder_summary_info_free(s, info);
|
||||
}
|
||||
|
||||
printf("\nMemory used by summary:\n\n");
|
||||
@ -372,57 +351,10 @@ camel_local_summary_write_headers(int fd, struct _header_raw *header, char *xevl
|
||||
return outlen;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
summary_header_load(CamelFolderSummary *s, FILE *in)
|
||||
{
|
||||
CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(s);
|
||||
|
||||
if (((CamelFolderSummaryClass *)camel_local_summary_parent)->summary_header_load(s, in) == -1)
|
||||
return -1;
|
||||
|
||||
return camel_folder_summary_decode_uint32(in, &mbs->folder_size);
|
||||
}
|
||||
|
||||
static int
|
||||
summary_header_save(CamelFolderSummary *s, FILE *out)
|
||||
{
|
||||
CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(s);
|
||||
|
||||
if (((CamelFolderSummaryClass *)camel_local_summary_parent)->summary_header_save(s, out) == -1)
|
||||
return -1;
|
||||
|
||||
return camel_folder_summary_encode_uint32(out, mbs->folder_size);
|
||||
}
|
||||
|
||||
static int
|
||||
header_evolution_decode(const char *in, guint32 *uid, guint32 *flags)
|
||||
{
|
||||
char *header;
|
||||
|
||||
if (in && (header = header_token_decode(in))) {
|
||||
if (strlen (header) == strlen ("00000000-0000")
|
||||
&& sscanf (header, "%08x-%04x", uid, flags) == 2) {
|
||||
g_free(header);
|
||||
return *uid;
|
||||
}
|
||||
g_free(header);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
header_evolution_encode(guint32 uid, guint32 flags)
|
||||
{
|
||||
return g_strdup_printf("%08x-%04x", uid, flags & 0xffff);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
local_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex)
|
||||
{
|
||||
/* FIXME: sync index here */
|
||||
/* FIXME: sync index here ? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -623,90 +555,3 @@ message_info_new(CamelFolderSummary *s, struct _header_raw *h)
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg)
|
||||
{
|
||||
CamelMessageInfo *mi;
|
||||
/*CamelLocalSummary *cls = (CamelLocalSummary *)s;*/
|
||||
|
||||
mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_new_from_message(s, msg);
|
||||
#if 0
|
||||
if (mi) {
|
||||
|
||||
if (mi->uid == NULL) {
|
||||
d(printf("no uid assigned yet, assigning one\n"));
|
||||
mi->uid = camel_folder_summary_next_uid_string(s);
|
||||
mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV;
|
||||
}
|
||||
|
||||
if (cls->index
|
||||
&& (cls->index_force
|
||||
|| !ibex_contains_name(cls->index, mi->uid))) {
|
||||
d(printf("Am indexing message %s\n", mi->uid));
|
||||
camel_folder_summary_set_index(s, cls->index);
|
||||
} else {
|
||||
d(printf("Not indexing message %s\n", mi->uid));
|
||||
camel_folder_summary_set_index(s, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return mi;
|
||||
}
|
||||
|
||||
static CamelMessageInfo *
|
||||
message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
|
||||
{
|
||||
CamelMessageInfo *mi;
|
||||
/*CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(s);*/
|
||||
|
||||
mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_new_from_parser(s, mp);
|
||||
if (mi) {
|
||||
#if 0
|
||||
/* do we want to index this message as we add it, as well? */
|
||||
if (mbs->index
|
||||
&& (mbs->index_force
|
||||
|| !ibex_contains_name(mbs->index, mi->uid))) {
|
||||
d(printf("Am indexing message %s\n", mi->uid));
|
||||
camel_folder_summary_set_index(s, mbs->index);
|
||||
} else {
|
||||
d(printf("Not indexing message %s\n", mi->uid));
|
||||
camel_folder_summary_set_index(s, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static CamelMessageInfo *
|
||||
message_info_load(CamelFolderSummary *s, FILE *in)
|
||||
{
|
||||
CamelMessageInfo *mi;
|
||||
|
||||
io(printf("loading local message info\n"));
|
||||
|
||||
mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_load(s, in);
|
||||
if (mi) {
|
||||
guint32 position;
|
||||
CamelLocalMessageInfo *mbi = (CamelLocalMessageInfo *)mi;
|
||||
|
||||
camel_folder_summary_decode_uint32(in, &position);
|
||||
mbi->frompos = position;
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
static int
|
||||
message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi)
|
||||
{
|
||||
CamelLocalMessageInfo *mbi = (CamelLocalMessageInfo *)mi;
|
||||
|
||||
io(printf("saving local message info\n"));
|
||||
|
||||
((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_save(s, out, mi);
|
||||
|
||||
return camel_folder_summary_encode_uint32(out, mbi->frompos);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -131,7 +131,7 @@ static void maildir_append_message(CamelFolder * folder, CamelMimeMessage * mess
|
||||
d(printf("Appending message\n"));
|
||||
|
||||
/* add it to the summary/assign the uid, etc */
|
||||
mi = camel_local_summary_add(lf->summary, message, info, lf->changes, ex);
|
||||
mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
|
||||
if (camel_exception_is_set(ex)) {
|
||||
return;
|
||||
}
|
||||
@ -191,7 +191,7 @@ static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar *
|
||||
d(printf("getting message: %s\n", uid));
|
||||
|
||||
/* get the message summary info */
|
||||
if ((info = camel_folder_summary_uid((CamelFolderSummary *)lf->summary, uid)) == NULL) {
|
||||
if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) {
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message"));
|
||||
return NULL;
|
||||
}
|
||||
@ -200,6 +200,9 @@ static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar *
|
||||
|
||||
/* what do we do if the message flags (and :info data) changes? filename mismatch - need to recheck I guess */
|
||||
name = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename(mdi));
|
||||
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) {
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"),
|
||||
name, g_strerror(errno));
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "camel-private.h"
|
||||
#include "e-util/e-memory.h"
|
||||
|
||||
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
|
||||
@ -474,6 +475,7 @@ remove_summary(char *key, CamelMessageInfo *info, CamelLocalSummary *cls)
|
||||
if (cls->index)
|
||||
ibex_unindex(cls->index, (char *)camel_message_info_uid(info));
|
||||
camel_folder_summary_remove((CamelFolderSummary *)cls, info);
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -551,33 +553,47 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
|
||||
if (info == NULL || (cls->index && (!ibex_contains_name(cls->index, uid)))) {
|
||||
/* need to add this file to the summary */
|
||||
if (info != NULL) {
|
||||
g_hash_table_remove(left, uid);
|
||||
CamelMessageInfo *old = g_hash_table_lookup(left, camel_message_info_uid(info));
|
||||
if (old) {
|
||||
g_hash_table_remove(left, uid);
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, old);
|
||||
}
|
||||
camel_folder_summary_remove((CamelFolderSummary *)cls, info);
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
camel_maildir_summary_add(cls, d->d_name, forceindex);
|
||||
} else {
|
||||
const char *filename;
|
||||
CamelMessageInfo *old;
|
||||
|
||||
g_hash_table_remove(left, camel_message_info_uid(info));
|
||||
old = g_hash_table_lookup(left, camel_message_info_uid(info));
|
||||
if (old) {
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, old);
|
||||
g_hash_table_remove(left, camel_message_info_uid(info));
|
||||
}
|
||||
|
||||
mdi = (CamelMaildirMessageInfo *)info;
|
||||
filename = camel_maildir_info_filename(mdi);
|
||||
/* TODO: only store the extension in the mdi->filename struct, not the whole lot */
|
||||
if (filename == NULL || strcmp(filename, d->d_name) != 0) {
|
||||
#ifdef DOESTRV
|
||||
#warning "cannot modify the estrv after its been setup, for mt-safe code"
|
||||
d(printf("filename changed: %s to %s\n", filename, d->d_name));
|
||||
|
||||
/* need to update the summary hash string reference since it might (will) change */
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
g_hash_table_remove(s->messages_uid, uid);
|
||||
info->strings = e_strv_set_ref(info->strings, CAMEL_MAILDIR_INFO_FILENAME, d->d_name);
|
||||
/* we need to re-pack as well */
|
||||
info->strings = e_strv_pack(info->strings);
|
||||
g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
#else
|
||||
g_free(mdi->filename);
|
||||
mdi->filename = g_strdup(d->d_name);
|
||||
#endif
|
||||
}
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
g_free(uid);
|
||||
}
|
||||
@ -597,9 +613,10 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
|
||||
continue;
|
||||
|
||||
/* already in summary? shouldn't happen, but just incase ... */
|
||||
if (camel_folder_summary_uid((CamelFolderSummary *)cls, name))
|
||||
if ((info = camel_folder_summary_uid((CamelFolderSummary *)cls, name))) {
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
newname = destname = camel_folder_summary_next_uid_string(s);
|
||||
else {
|
||||
} else {
|
||||
newname = NULL;
|
||||
destname = name;
|
||||
}
|
||||
@ -633,7 +650,9 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
|
||||
g_free(cur);
|
||||
|
||||
/* sort the summary based on receive time, since the directory order is not useful */
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_receive_cmp);
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
|
||||
/* FIXME: move this up a class? */
|
||||
|
||||
@ -699,12 +718,18 @@ maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChange
|
||||
/* we'll assume it didn't work, but dont change anything else */
|
||||
g_free(newname);
|
||||
} else {
|
||||
/* TODO: If this is made mt-safe, then this code could be a problem, since
|
||||
the estrv is being modified.
|
||||
Sigh, this may mean the maildir name has to be cached another way */
|
||||
#ifdef DOESTRV
|
||||
#warning "cannot modify the estrv after its been setup, for mt-safe code"
|
||||
CAMEL_SUMMARY_LOCK(s, summary_lock);
|
||||
/* need to update the summary hash ref */
|
||||
g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
|
||||
info->strings = e_strv_set_ref_free(info->strings, CAMEL_MAILDIR_INFO_FILENAME, newname);
|
||||
info->strings = e_strv_pack(info->strings);
|
||||
g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
|
||||
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
|
||||
#else
|
||||
g_free(mdi->filename);
|
||||
mdi->filename = newname;
|
||||
@ -719,6 +744,7 @@ maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChange
|
||||
/* strip FOLDER_MESSAGE_FLAGED, etc */
|
||||
info->flags &= 0xffff;
|
||||
}
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -54,6 +54,9 @@ static CamelLocalFolderClass *parent_class = NULL;
|
||||
static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
|
||||
static void mbox_unlock(CamelLocalFolder *lf);
|
||||
|
||||
static void mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value);
|
||||
static void mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value);
|
||||
|
||||
static void mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, CamelException *ex);
|
||||
static CamelMimeMessage *mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex);
|
||||
static CamelLocalSummary *mbox_create_summary(const char *path, const char *folder, ibex *index);
|
||||
@ -74,6 +77,9 @@ camel_mbox_folder_class_init(CamelMboxFolderClass * camel_mbox_folder_class)
|
||||
camel_folder_class->append_message = mbox_append_message;
|
||||
camel_folder_class->get_message = mbox_get_message;
|
||||
|
||||
camel_folder_class->set_message_user_flag = mbox_set_message_user_flag;
|
||||
camel_folder_class->set_message_user_tag = mbox_set_message_user_tag;
|
||||
|
||||
lclass->create_summary = mbox_create_summary;
|
||||
lclass->lock = mbox_lock;
|
||||
lclass->unlock = mbox_unlock;
|
||||
@ -164,7 +170,7 @@ mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const Camel
|
||||
CamelLocalFolder *lf = (CamelLocalFolder *)folder;
|
||||
CamelStream *output_stream = NULL, *filter_stream = NULL;
|
||||
CamelMimeFilter *filter_from = NULL;
|
||||
CamelMboxSummary *mbs = (CamelMboxSummary *)lf->summary;
|
||||
CamelMboxSummary *mbs = (CamelMboxSummary *)folder->summary;
|
||||
CamelMessageInfo *mi;
|
||||
char *fromline = NULL;
|
||||
int fd;
|
||||
@ -179,12 +185,12 @@ mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const Camel
|
||||
d(printf("Appending message\n"));
|
||||
|
||||
/* first, check the summary is correct (updates folder_size too) */
|
||||
camel_local_summary_check(lf->summary, lf->changes, ex);
|
||||
camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex);
|
||||
if (camel_exception_is_set(ex))
|
||||
goto fail;
|
||||
|
||||
/* add it to the summary/assign the uid, etc */
|
||||
mi = camel_local_summary_add(lf->summary, message, info, lf->changes, ex);
|
||||
mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
|
||||
if (camel_exception_is_set(ex))
|
||||
goto fail;
|
||||
|
||||
@ -199,7 +205,7 @@ mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const Camel
|
||||
/* and we need to set the frompos/XEV explicitly */
|
||||
((CamelMboxMessageInfo *)mi)->frompos = mbs->folder_size?mbs->folder_size+1:0;
|
||||
#if 0
|
||||
xev = camel_local_summary_encode_x_evolution(lf->summary, mi);
|
||||
xev = camel_local_summary_encode_x_evolution((CamelLocalSummary *)folder->summary, mi);
|
||||
if (xev) {
|
||||
/* the x-ev header should match the 'current' flags, no problem, so store as much */
|
||||
camel_medium_set_header((CamelMedium *)message, "X-Evolution", xev);
|
||||
@ -304,7 +310,7 @@ mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex)
|
||||
|
||||
retry:
|
||||
/* get the message summary info */
|
||||
info = (CamelMboxMessageInfo *) camel_folder_summary_uid((CamelFolderSummary *)lf->summary, uid);
|
||||
info = (CamelMboxMessageInfo *) camel_folder_summary_uid(folder->summary, uid);
|
||||
|
||||
if (info == NULL) {
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
|
||||
@ -327,6 +333,7 @@ retry:
|
||||
_("Cannot get message: %s from folder %s\n %s"), uid, lf->folder_path,
|
||||
strerror(errno));
|
||||
camel_local_folder_unlock(lf);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -345,10 +352,11 @@ retry:
|
||||
camel_mime_parser_state(parser));
|
||||
|
||||
camel_object_unref((CamelObject *)parser);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info);
|
||||
|
||||
if (!retried) {
|
||||
retried = TRUE;
|
||||
camel_local_summary_check(lf->summary, lf->changes, ex);
|
||||
camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex);
|
||||
if (!camel_exception_is_set(ex))
|
||||
goto retry;
|
||||
}
|
||||
@ -360,6 +368,8 @@ retry:
|
||||
camel_local_folder_unlock(lf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info);
|
||||
|
||||
message = camel_mime_message_new();
|
||||
if (camel_mime_part_construct_from_parser((CamelMimePart *)message, parser) == -1) {
|
||||
@ -386,3 +396,39 @@ retry:
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
static void
|
||||
mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (camel_flag_set(&info->user_flags, name, value)) {
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
|
||||
camel_folder_summary_touch(folder->summary);
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
static void
|
||||
mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
|
||||
g_return_if_fail(folder->summary != NULL);
|
||||
|
||||
info = camel_folder_summary_uid(folder->summary, uid);
|
||||
g_return_if_fail(info != NULL);
|
||||
|
||||
if (camel_tag_set(&info->user_tags, name, value)) {
|
||||
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE;
|
||||
camel_folder_summary_touch(folder->summary);
|
||||
camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", (char *) uid);
|
||||
}
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
}
|
||||
|
||||
@ -306,6 +306,7 @@ summary_update(CamelLocalSummary *cls, off_t offset, CamelFolderChangeInfo *chan
|
||||
CamelMessageInfo *mi = camel_folder_summary_index(s, i);
|
||||
|
||||
camel_folder_change_info_add_source(changeinfo, camel_message_info_uid(mi));
|
||||
camel_folder_summary_info_free(s, mi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,6 +319,7 @@ summary_update(CamelLocalSummary *cls, off_t offset, CamelFolderChangeInfo *chan
|
||||
for (i = 0; i < count; i++) {
|
||||
CamelMessageInfo *mi = camel_folder_summary_index(s, i);
|
||||
camel_folder_change_info_add_update(changeinfo, camel_message_info_uid(mi));
|
||||
camel_folder_summary_info_free(s, mi);
|
||||
}
|
||||
camel_folder_change_info_build_diff(changeinfo);
|
||||
}
|
||||
@ -459,7 +461,7 @@ mbox_summary_sync_full(CamelLocalSummary *cls, gboolean expunge, CamelFolderChan
|
||||
CamelFolderSummary *s = (CamelFolderSummary *)mbs;
|
||||
CamelMimeParser *mp = NULL;
|
||||
int i, count;
|
||||
CamelMboxMessageInfo *info;
|
||||
CamelMboxMessageInfo *info = NULL;
|
||||
int fd = -1, fdout = -1;
|
||||
char *tmpname = NULL;
|
||||
char *buffer, *xevnew = NULL;
|
||||
@ -533,6 +535,7 @@ mbox_summary_sync_full(CamelLocalSummary *cls, gboolean expunge, CamelFolderChan
|
||||
/* remove it from the change list */
|
||||
camel_folder_change_info_remove_uid(changeinfo, uid);
|
||||
camel_folder_summary_remove(s, (CamelMessageInfo *)info);
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
count--;
|
||||
i--;
|
||||
info = NULL;
|
||||
@ -584,6 +587,8 @@ mbox_summary_sync_full(CamelLocalSummary *cls, gboolean expunge, CamelFolderChan
|
||||
d(printf("we are now at %d, from = %d\n", (int)camel_mime_parser_tell(mp),
|
||||
(int)camel_mime_parser_tell_start_from(mp)));
|
||||
camel_mime_parser_unstep(mp);
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -634,6 +639,8 @@ mbox_summary_sync_full(CamelLocalSummary *cls, gboolean expunge, CamelFolderChan
|
||||
unlink(tmpname);
|
||||
if (mp)
|
||||
camel_object_unref((CamelObject *)mp);
|
||||
if (info)
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -646,7 +653,7 @@ mbox_summary_sync_quick(CamelLocalSummary *cls, gboolean expunge, CamelFolderCha
|
||||
CamelFolderSummary *s = (CamelFolderSummary *)mbs;
|
||||
CamelMimeParser *mp = NULL;
|
||||
int i, count;
|
||||
CamelMboxMessageInfo *info;
|
||||
CamelMboxMessageInfo *info = NULL;
|
||||
int fd = -1;
|
||||
char *xevnew, *xevtmp;
|
||||
const char *xev;
|
||||
@ -678,8 +685,11 @@ mbox_summary_sync_quick(CamelLocalSummary *cls, gboolean expunge, CamelFolderCha
|
||||
|
||||
d(printf("Checking message %s %08x\n", info->info.uid, info->info.flags));
|
||||
|
||||
if ((info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0)
|
||||
if ((info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) {
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
info = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
d(printf("Updating message %s\n", info->info.uid));
|
||||
|
||||
@ -738,6 +748,7 @@ mbox_summary_sync_quick(CamelLocalSummary *cls, gboolean expunge, CamelFolderCha
|
||||
camel_mime_parser_drop_step(mp);
|
||||
|
||||
info->info.flags &= 0xffff;
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
}
|
||||
|
||||
d(printf("Closing folders\n"));
|
||||
@ -757,9 +768,10 @@ mbox_summary_sync_quick(CamelLocalSummary *cls, gboolean expunge, CamelFolderCha
|
||||
error:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
if (mp)
|
||||
camel_object_unref((CamelObject *)mp);
|
||||
if (info)
|
||||
camel_folder_summary_info_free(s, (CamelMessageInfo *)info);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -792,6 +804,7 @@ mbox_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInf
|
||||
quick = FALSE;
|
||||
else
|
||||
work |= (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
|
||||
camel_folder_summary_info_free(s, info);
|
||||
}
|
||||
|
||||
/* yuck i hate this logic, but its to simplify the 'all ok, update summary' and failover cases */
|
||||
|
||||
@ -132,7 +132,7 @@ static void mh_append_message(CamelFolder * folder, CamelMimeMessage * message,
|
||||
d(printf("Appending message\n"));
|
||||
|
||||
/* add it to the summary/assign the uid, etc */
|
||||
mi = camel_local_summary_add(lf->summary, message, info, lf->changes, ex);
|
||||
mi = camel_local_summary_add((CamelLocalSummary *)folder->summary, message, info, lf->changes, ex);
|
||||
if (camel_exception_is_set(ex)) {
|
||||
return;
|
||||
}
|
||||
@ -179,11 +179,14 @@ static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid,
|
||||
d(printf("getting message: %s\n", uid));
|
||||
|
||||
/* get the message summary info */
|
||||
if ((info = camel_folder_summary_uid((CamelFolderSummary *)lf->summary, uid)) == NULL) {
|
||||
if ((info = camel_folder_summary_uid(folder->summary, uid)) == NULL) {
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we only need it to check the message exists */
|
||||
camel_folder_summary_info_free(folder->summary, info);
|
||||
|
||||
name = g_strdup_printf("%s/%s", lf->folder_path, uid);
|
||||
if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) {
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"),
|
||||
|
||||
@ -37,8 +37,6 @@
|
||||
|
||||
#define CAMEL_MH_SUMMARY_VERSION (0x2000)
|
||||
|
||||
static CamelMessageInfo *message_info_new(CamelFolderSummary *, struct _header_raw *);
|
||||
|
||||
static int mh_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex);
|
||||
static int mh_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex);
|
||||
/*static int mh_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex);*/
|
||||
@ -84,7 +82,6 @@ camel_mh_summary_class_init (CamelMhSummaryClass *class)
|
||||
parent_class = (CamelLocalSummaryClass *)camel_type_get_global_classfuncs(camel_local_summary_get_type ());
|
||||
|
||||
/* override methods */
|
||||
sklass->message_info_new = message_info_new;
|
||||
sklass->next_uid_string = mh_summary_next_uid_string;
|
||||
|
||||
lklass->check = mh_summary_check;
|
||||
@ -125,20 +122,6 @@ CamelMhSummary *camel_mh_summary_new (const char *filename, const char *mhdir, i
|
||||
return o;
|
||||
}
|
||||
|
||||
static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _header_raw *h)
|
||||
{
|
||||
CamelMessageInfo *mi;
|
||||
/*CamelMhSummary *mhs = (CamelMhSummary *)s;*/
|
||||
|
||||
mi = ((CamelFolderSummaryClass *) parent_class)->message_info_new(s, h);
|
||||
/* hmm, this isn't quite right */
|
||||
if (mi) {
|
||||
/*mi->uid = mh_summary_next_uid_string(s);*/
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
static char *mh_summary_next_uid_string(CamelFolderSummary *s)
|
||||
{
|
||||
CamelMhSummary *mhs = (CamelMhSummary *)s;
|
||||
@ -206,6 +189,7 @@ remove_summary(char *key, CamelMessageInfo *info, CamelLocalSummary *cls)
|
||||
if (cls->index)
|
||||
ibex_unindex(cls->index, (char *)camel_message_info_uid(info));
|
||||
camel_folder_summary_remove((CamelFolderSummary *)cls, info);
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -256,11 +240,19 @@ mh_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, Came
|
||||
if (info != NULL) {
|
||||
g_hash_table_remove(left, camel_message_info_uid(info));
|
||||
camel_folder_summary_remove((CamelFolderSummary *)cls, info);
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
camel_mh_summary_add(cls, d->d_name, forceindex);
|
||||
} else {
|
||||
g_hash_table_remove(left, camel_message_info_uid(info));
|
||||
}
|
||||
const char *uid = camel_message_info_uid(info);
|
||||
CamelMessageInfo *old = g_hash_table_lookup(left, uid);
|
||||
|
||||
if (old) {
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, old);
|
||||
g_hash_table_remove(left, uid);
|
||||
}
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
@ -394,6 +386,7 @@ mh_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo
|
||||
g_warning("Problem occured when trying to expunge, ignored");
|
||||
}
|
||||
}
|
||||
camel_folder_summary_info_free((CamelFolderSummary *)cls, info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -63,7 +63,7 @@ nntp_folder_sync (CamelFolder *folder, gboolean expunge,
|
||||
{
|
||||
CamelNNTPStore *store;
|
||||
|
||||
camel_folder_summary_save (CAMEL_NNTP_FOLDER(folder)->summary);
|
||||
camel_folder_summary_save (folder->summary);
|
||||
|
||||
store = CAMEL_NNTP_STORE (camel_folder_get_parent_store (folder));
|
||||
|
||||
@ -71,39 +71,12 @@ nntp_folder_sync (CamelFolder *folder, gboolean expunge,
|
||||
camel_nntp_newsrc_write (store->newsrc);
|
||||
}
|
||||
|
||||
static gint
|
||||
nntp_folder_get_message_count (CamelFolder *folder)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER(folder);
|
||||
|
||||
g_assert (folder);
|
||||
g_assert (nntp_folder->summary);
|
||||
|
||||
return camel_folder_summary_count(nntp_folder->summary);
|
||||
}
|
||||
|
||||
static guint32
|
||||
nntp_folder_get_message_flags (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
|
||||
CamelMessageInfo *info = camel_folder_summary_uid (nntp_folder->summary, uid);
|
||||
|
||||
return info->flags;
|
||||
}
|
||||
|
||||
static void
|
||||
nntp_folder_set_message_flags (CamelFolder *folder, const char *uid,
|
||||
guint32 flags, guint32 set)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
|
||||
CamelMessageInfo *info = camel_folder_summary_uid (nntp_folder->summary, uid);
|
||||
guint32 new;
|
||||
((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set);
|
||||
|
||||
new = (info->flags & ~flags) | (set & flags);
|
||||
if (new == info->flags)
|
||||
return;
|
||||
|
||||
info->flags = new;
|
||||
if (flags & set & CAMEL_MESSAGE_SEEN) {
|
||||
int article_num;
|
||||
CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (camel_folder_get_parent_store (folder));
|
||||
@ -114,8 +87,6 @@ nntp_folder_set_message_flags (CamelFolder *folder, const char *uid,
|
||||
folder->name,
|
||||
article_num);
|
||||
}
|
||||
|
||||
camel_folder_summary_touch (nntp_folder->summary);
|
||||
}
|
||||
|
||||
static CamelMimeMessage *
|
||||
@ -151,6 +122,9 @@ nntp_folder_get_message (CamelFolder *folder, const gchar *uid, CamelException *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this could probably done fairly easily with an nntp stream that
|
||||
returns eof after '.' */
|
||||
|
||||
/* XXX ick ick ick. read the entire message into a buffer and
|
||||
then create a stream_mem for it. */
|
||||
buf_alloc = 2048;
|
||||
@ -206,34 +180,6 @@ nntp_folder_get_message (CamelFolder *folder, const gchar *uid, CamelException *
|
||||
return message;
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
nntp_folder_get_uids (CamelFolder *folder)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
|
||||
GPtrArray *out;
|
||||
CamelMessageInfo *message_info;
|
||||
int i;
|
||||
int count = camel_folder_summary_count (nntp_folder->summary);
|
||||
|
||||
out = g_ptr_array_new ();
|
||||
g_ptr_array_set_size (out, count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
message_info = camel_folder_summary_index (nntp_folder->summary, i);
|
||||
out->pdata[i] = g_strdup (camel_message_info_uid(message_info));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
nntp_folder_get_summary (CamelFolder *folder)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
|
||||
|
||||
return nntp_folder->summary->messages;
|
||||
}
|
||||
|
||||
static GPtrArray*
|
||||
nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
|
||||
{
|
||||
@ -241,14 +187,6 @@ nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, C
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const CamelMessageInfo*
|
||||
nntp_folder_get_message_info (CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
|
||||
|
||||
return camel_folder_summary_uid (nntp_folder->summary, uid);
|
||||
}
|
||||
|
||||
static void
|
||||
nntp_folder_finalize (CamelObject *object)
|
||||
{
|
||||
@ -268,16 +206,9 @@ camel_nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
|
||||
|
||||
/* virtual method overload */
|
||||
camel_folder_class->sync = nntp_folder_sync;
|
||||
camel_folder_class->get_message_count = nntp_folder_get_message_count;
|
||||
camel_folder_class->set_message_flags = nntp_folder_set_message_flags;
|
||||
camel_folder_class->get_message_flags = nntp_folder_get_message_flags;
|
||||
camel_folder_class->get_message = nntp_folder_get_message;
|
||||
camel_folder_class->get_uids = nntp_folder_get_uids;
|
||||
camel_folder_class->free_uids = camel_folder_free_deep;
|
||||
camel_folder_class->get_summary = nntp_folder_get_summary;
|
||||
camel_folder_class->free_summary = camel_folder_free_nop;
|
||||
camel_folder_class->search_by_expression = nntp_folder_search_by_expression;
|
||||
camel_folder_class->get_message_info = nntp_folder_get_message_info;
|
||||
}
|
||||
|
||||
CamelType
|
||||
@ -313,11 +244,11 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
|
||||
root_dir_path,
|
||||
folder->name);
|
||||
|
||||
nntp_folder->summary = camel_folder_summary_new ();
|
||||
camel_folder_summary_set_filename (nntp_folder->summary,
|
||||
folder->summary = camel_folder_summary_new ();
|
||||
camel_folder_summary_set_filename (folder->summary,
|
||||
nntp_folder->summary_file_path);
|
||||
|
||||
if (-1 == camel_folder_summary_load (nntp_folder->summary)) {
|
||||
if (-1 == camel_folder_summary_load (folder->summary)) {
|
||||
/* Bad or nonexistant summary file */
|
||||
camel_nntp_get_headers (CAMEL_FOLDER( folder )->parent_store,
|
||||
nntp_folder, ex);
|
||||
@ -327,7 +258,7 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
|
||||
}
|
||||
|
||||
/* XXX check return value */
|
||||
camel_folder_summary_save (nntp_folder->summary);
|
||||
camel_folder_summary_save (folder->summary);
|
||||
}
|
||||
|
||||
return folder;
|
||||
|
||||
@ -32,6 +32,16 @@
|
||||
#include "camel-nntp-newsrc.h"
|
||||
#include <camel/camel-folder-summary.h>
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
|
||||
#define NEWSRC_LOCK(f, l) (g_mutex_lock(((CamelNNTPNewsrc *)f)->l))
|
||||
#define NEWSRC_UNLOCK(f, l) (g_mutex_unlock(((CamelNNTPNewsrc *)f)->l))
|
||||
#else
|
||||
#define NEWSRC_LOCK(f, l)
|
||||
#define NEWSRC_UNLOCK(f, l)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
guint low;
|
||||
guint high;
|
||||
@ -47,8 +57,12 @@ struct CamelNNTPNewsrc {
|
||||
gchar *filename;
|
||||
GHashTable *groups;
|
||||
gboolean dirty;
|
||||
#ifdef ENABLE_THREADS
|
||||
GMutex *lock;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
|
||||
static NewsrcGroup *
|
||||
camel_nntp_newsrc_group_add (CamelNNTPNewsrc *newsrc, const char *group_name, gboolean subscribed)
|
||||
{
|
||||
@ -180,26 +194,40 @@ int
|
||||
camel_nntp_newsrc_get_highest_article_read (CamelNNTPNewsrc *newsrc, const char *group_name)
|
||||
{
|
||||
NewsrcGroup *group;
|
||||
int ret;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
ret = camel_nntp_newsrc_group_get_highest_article_read (newsrc, group);
|
||||
|
||||
return camel_nntp_newsrc_group_get_highest_article_read (newsrc, group);
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
camel_nntp_newsrc_get_num_articles_read (CamelNNTPNewsrc *newsrc, const char *group_name)
|
||||
{
|
||||
NewsrcGroup *group;
|
||||
int ret;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
ret = camel_nntp_newsrc_group_get_num_articles_read (newsrc, group);
|
||||
|
||||
return camel_nntp_newsrc_group_get_num_articles_read (newsrc, group);
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
camel_nntp_newsrc_mark_article_read (CamelNNTPNewsrc *newsrc, const char *group_name, int num)
|
||||
{
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
camel_nntp_newsrc_mark_range_read (newsrc, group_name, num, num);
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
}
|
||||
|
||||
void
|
||||
@ -216,9 +244,11 @@ camel_nntp_newsrc_mark_range_read(CamelNNTPNewsrc *newsrc, const char *group_nam
|
||||
low = tmp;
|
||||
}
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
|
||||
camel_nntp_newsrc_group_mark_range_read (newsrc, group, low, high);
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -226,36 +256,51 @@ camel_nntp_newsrc_article_is_read (CamelNNTPNewsrc *newsrc, const char *group_na
|
||||
{
|
||||
int i;
|
||||
NewsrcGroup *group;
|
||||
int ret = FALSE;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
|
||||
for (i = 0; i < group->ranges->len; i++) {
|
||||
if (num >= g_array_index (group->ranges, ArticleRange, i).low &&
|
||||
num <= g_array_index (group->ranges, ArticleRange, i).high) {
|
||||
return TRUE;
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
camel_nntp_newsrc_group_is_subscribed (CamelNNTPNewsrc *newsrc, const char *group_name)
|
||||
{
|
||||
NewsrcGroup *group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
NewsrcGroup *group;
|
||||
int ret = FALSE;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
|
||||
if (group) {
|
||||
return group->subscribed;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
ret = group->subscribed;
|
||||
}
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
camel_nntp_newsrc_subscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name)
|
||||
{
|
||||
NewsrcGroup *group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
NewsrcGroup *group;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
|
||||
if (group) {
|
||||
if (!group->subscribed)
|
||||
@ -265,13 +310,18 @@ camel_nntp_newsrc_subscribe_group (CamelNNTPNewsrc *newsrc, const char *group_na
|
||||
else {
|
||||
camel_nntp_newsrc_group_add (newsrc, group_name, TRUE);
|
||||
}
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
}
|
||||
|
||||
void
|
||||
camel_nntp_newsrc_unsubscribe_group (CamelNNTPNewsrc *newsrc, const char *group_name)
|
||||
{
|
||||
NewsrcGroup *group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
NewsrcGroup *group;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
group = g_hash_table_lookup (newsrc->groups, group_name);
|
||||
if (group) {
|
||||
if (group->subscribed)
|
||||
newsrc->dirty = TRUE;
|
||||
@ -280,6 +330,8 @@ camel_nntp_newsrc_unsubscribe_group (CamelNNTPNewsrc *newsrc, const char *group_
|
||||
else {
|
||||
camel_nntp_newsrc_group_add (newsrc, group_name, FALSE);
|
||||
}
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
}
|
||||
|
||||
struct newsrc_ptr_array {
|
||||
@ -287,6 +339,7 @@ struct newsrc_ptr_array {
|
||||
gboolean subscribed_only;
|
||||
};
|
||||
|
||||
/* this needs to strdup the grup_name, if the group array is likely to change */
|
||||
static void
|
||||
get_group_foreach (char *group_name, NewsrcGroup *group, struct newsrc_ptr_array *npa)
|
||||
{
|
||||
@ -302,12 +355,16 @@ camel_nntp_newsrc_get_subscribed_group_names (CamelNNTPNewsrc *newsrc)
|
||||
|
||||
g_return_val_if_fail (newsrc, NULL);
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
npa.ptr_array = g_ptr_array_new();
|
||||
npa.subscribed_only = TRUE;
|
||||
|
||||
g_hash_table_foreach (newsrc->groups,
|
||||
(GHFunc)get_group_foreach, &npa);
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return npa.ptr_array;
|
||||
}
|
||||
|
||||
@ -318,12 +375,16 @@ camel_nntp_newsrc_get_all_group_names (CamelNNTPNewsrc *newsrc)
|
||||
|
||||
g_return_val_if_fail (newsrc, NULL);
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
npa.ptr_array = g_ptr_array_new();
|
||||
npa.subscribed_only = FALSE;
|
||||
|
||||
g_hash_table_foreach (newsrc->groups,
|
||||
(GHFunc)get_group_foreach, &npa);
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
return npa.ptr_array;
|
||||
}
|
||||
|
||||
@ -395,9 +456,13 @@ camel_nntp_newsrc_write_to_file(CamelNNTPNewsrc *newsrc, FILE *fp)
|
||||
newsrc_fp.newsrc = newsrc;
|
||||
newsrc_fp.fp = fp;
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
g_hash_table_foreach (newsrc->groups,
|
||||
(GHFunc)camel_nntp_newsrc_write_group_line,
|
||||
&newsrc_fp);
|
||||
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
}
|
||||
|
||||
void
|
||||
@ -407,17 +472,21 @@ camel_nntp_newsrc_write(CamelNNTPNewsrc *newsrc)
|
||||
|
||||
g_return_if_fail (newsrc);
|
||||
|
||||
NEWSRC_LOCK(newsrc, lock);
|
||||
|
||||
if (!newsrc->dirty)
|
||||
return;
|
||||
|
||||
if ((fp = fopen(newsrc->filename, "w")) == NULL) {
|
||||
g_warning ("Couldn't open newsrc file '%s'.\n", newsrc->filename);
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
return;
|
||||
}
|
||||
|
||||
camel_nntp_newsrc_write_to_file(newsrc, fp);
|
||||
|
||||
newsrc->dirty = FALSE;
|
||||
NEWSRC_UNLOCK(newsrc, lock);
|
||||
|
||||
camel_nntp_newsrc_write_to_file(newsrc, fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
@ -535,6 +604,9 @@ camel_nntp_newsrc_read_for_server (const char *server)
|
||||
newsrc = g_new0(CamelNNTPNewsrc, 1);
|
||||
newsrc->filename = filename;
|
||||
newsrc->groups = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
#ifdef ENABLE_THREADS
|
||||
newsrc->lock = g_mutex_new();
|
||||
#endif
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) {
|
||||
g_warning ("~/.newsrc-%s not present.\n", server);
|
||||
|
||||
@ -122,7 +122,8 @@ camel_pop3_folder_new (CamelStore *parent, CamelException *ex)
|
||||
folder = CAMEL_FOLDER (camel_object_new (CAMEL_POP3_FOLDER_TYPE));
|
||||
camel_folder_construct (folder, parent, "inbox", "inbox");
|
||||
|
||||
camel_folder_refresh_info (folder, ex);
|
||||
/* mt-ok, since we dont have the folder-lock for new() */
|
||||
camel_folder_refresh_info (folder, ex);/* mt-ok */
|
||||
if (camel_exception_is_set (ex)) {
|
||||
camel_object_unref (CAMEL_OBJECT (folder));
|
||||
folder = NULL;
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define d(x)
|
||||
|
||||
/* our message info includes the parent folder */
|
||||
typedef struct _CamelVeeMessageInfo {
|
||||
CamelMessageInfo info;
|
||||
@ -47,27 +49,22 @@ struct _CamelVeeFolderPrivate {
|
||||
#define _PRIVATE(o) (((CamelVeeFolder *)(o))->priv)
|
||||
|
||||
static void vee_sync (CamelFolder *folder, gboolean expunge, CamelException *ex);
|
||||
static void vee_expunge (CamelFolder *folder, CamelException *ex);
|
||||
|
||||
static GPtrArray *vee_get_uids (CamelFolder *folder);
|
||||
GPtrArray *vee_get_summary (CamelFolder *folder);
|
||||
|
||||
static gint vee_get_message_count (CamelFolder *folder);
|
||||
static gint vee_get_unread_message_count (CamelFolder *folder);
|
||||
static CamelMimeMessage *vee_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex);
|
||||
|
||||
static const CamelMessageInfo *vee_get_message_info (CamelFolder *folder, const char *uid);
|
||||
static GPtrArray *vee_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
|
||||
|
||||
static guint32 vee_get_message_flags (CamelFolder *folder, const char *uid);
|
||||
static void vee_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set);
|
||||
static gboolean vee_get_message_user_flag (CamelFolder *folder, const char *uid, const char *name);
|
||||
static void vee_set_message_user_flag (CamelFolder *folder, const char *uid, const char *name, gboolean value);
|
||||
|
||||
|
||||
static void camel_vee_folder_class_init (CamelVeeFolderClass *klass);
|
||||
static void camel_vee_folder_init (CamelVeeFolder *obj);
|
||||
static void camel_vee_folder_finalise (CamelObject *obj);
|
||||
|
||||
static void folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf);
|
||||
static void message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf);
|
||||
|
||||
static void vee_folder_build(CamelVeeFolder *vf, CamelException *ex);
|
||||
static void vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex);
|
||||
|
||||
@ -99,22 +96,13 @@ camel_vee_folder_class_init (CamelVeeFolderClass *klass)
|
||||
camel_vee_folder_parent = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs (camel_folder_get_type ()));
|
||||
|
||||
folder_class->sync = vee_sync;
|
||||
folder_class->expunge = vee_expunge;
|
||||
|
||||
folder_class->get_uids = vee_get_uids;
|
||||
folder_class->free_uids = camel_folder_free_deep;
|
||||
folder_class->get_summary = vee_get_summary;
|
||||
folder_class->free_summary = camel_folder_free_nop;
|
||||
folder_class->get_message = vee_get_message;
|
||||
|
||||
folder_class->get_message_info = vee_get_message_info;
|
||||
|
||||
folder_class->get_message_count = vee_get_message_count;
|
||||
folder_class->get_unread_message_count = vee_get_unread_message_count;
|
||||
folder_class->search_by_expression = vee_search_by_expression;
|
||||
|
||||
folder_class->get_message_flags = vee_get_message_flags;
|
||||
folder_class->set_message_flags = vee_set_message_flags;
|
||||
folder_class->get_message_user_flag = vee_get_message_user_flag;
|
||||
folder_class->set_message_user_flag = vee_set_message_user_flag;
|
||||
}
|
||||
|
||||
@ -154,10 +142,15 @@ camel_vee_folder_finalise (CamelObject *obj)
|
||||
node = p->folders;
|
||||
while (node) {
|
||||
CamelFolder *f = node->data;
|
||||
camel_object_unhook_event ((CamelObject *)f, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
|
||||
camel_object_unhook_event ((CamelObject *)f, "message_changed", (CamelObjectEventHookFunc) message_changed, vf);
|
||||
camel_object_unref((CamelObject *)f);
|
||||
node = g_list_next(node);
|
||||
}
|
||||
|
||||
g_free(vf->expression);
|
||||
g_free(vf->vname);
|
||||
|
||||
camel_folder_change_info_free(vf->changes);
|
||||
#ifdef DYNAMIC
|
||||
camel_object_unref((CamelObject *)vf->search);
|
||||
@ -195,8 +188,8 @@ camel_vee_folder_new (CamelStore *parent_store, const char *name, CamelException
|
||||
*searchpart++ = 0;
|
||||
}
|
||||
|
||||
vf->messages = g_ptr_array_new();
|
||||
vf->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
folder->summary = camel_folder_summary_new();
|
||||
folder->summary->message_info_size = sizeof(CamelVeeMessageInfo);
|
||||
|
||||
vf->expression = g_strdup(searchpart);
|
||||
vf->vname = namepart;
|
||||
@ -210,6 +203,43 @@ camel_vee_folder_new (CamelStore *parent_store, const char *name, CamelException
|
||||
return folder;
|
||||
}
|
||||
|
||||
static CamelVeeMessageInfo *
|
||||
vee_folder_add(CamelVeeFolder *vf, CamelFolder *f, CamelMessageInfo *info)
|
||||
{
|
||||
CamelVeeMessageInfo *mi;
|
||||
char *uid;
|
||||
CamelFolder *folder = (CamelFolder *)vf;
|
||||
|
||||
mi = (CamelVeeMessageInfo *)camel_folder_summary_info_new(folder->summary);
|
||||
camel_message_info_dup_to(info, (CamelMessageInfo *)mi);
|
||||
uid = g_strdup_printf("%p:%s", f, camel_message_info_uid(info));
|
||||
#ifdef DOESTRV
|
||||
mi->info.strings = e_strv_set_ref_free(mi->info.strings, CAMEL_MESSAGE_INFO_UID, uid);
|
||||
mi->info.strings = e_strv_pack(mi->info.strings);
|
||||
#else
|
||||
g_free(mi->info.uid);
|
||||
mi->info.uid = uid;
|
||||
#endif
|
||||
mi->folder = f;
|
||||
camel_folder_summary_add(folder->summary, (CamelMessageInfo *)mi);
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
static CamelVeeMessageInfo *
|
||||
vee_folder_add_uid(CamelVeeFolder *vf, CamelFolder *f, const char *inuid)
|
||||
{
|
||||
CamelMessageInfo *info;
|
||||
CamelVeeMessageInfo *mi = NULL;
|
||||
|
||||
info = camel_folder_get_message_info(f, inuid);
|
||||
if (info) {
|
||||
mi = vee_folder_add(vf, f, info);
|
||||
camel_folder_free_message_info(f, info);
|
||||
}
|
||||
return mi;
|
||||
}
|
||||
|
||||
#ifdef DYNAMIC
|
||||
static void
|
||||
vfolder_remove_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo)
|
||||
@ -218,38 +248,21 @@ vfolder_remove_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo)
|
||||
|
||||
printf("removing match %s\n", uid);
|
||||
|
||||
g_hash_table_remove(vf->messages_uid, uid);
|
||||
g_ptr_array_remove_fast(vf->messages, vinfo);
|
||||
camel_folder_summary_remove(((CamelFolder *)vf)->summary, (CamelMessageInfo *)vinfo);
|
||||
camel_folder_change_info_remove_uid(vf->changes, uid);
|
||||
camel_message_info_free((CamelMessageInfo *)vinfo);
|
||||
}
|
||||
|
||||
static CamelVeeMessageInfo *
|
||||
vfolder_add_match(CamelVeeFolder *vf, CamelFolder *f, const CamelMessageInfo *info)
|
||||
vee_folder_add_change(CamelVeeFolder *vf, CamelFolder *f, CamelMessageInfo *info)
|
||||
{
|
||||
CamelVeeMessageInfo *mi;
|
||||
char *uid;
|
||||
CamelVeeMessageInfo *mi = NULL;
|
||||
|
||||
mi = g_malloc0(sizeof(*mi));
|
||||
camel_message_info_dup_to(info, (CamelMessageInfo*)mi);
|
||||
uid = g_strdup_printf("%p:%s", f, camel_message_info_uid(info));
|
||||
#ifdef DOESTRV
|
||||
mi->info.strings = e_strv_set_ref_free(mi->info.strings, CAMEL_MESSAGE_INFO_UID, uid);
|
||||
mi->info.strings = e_strv_pack(mi->info.strings);
|
||||
#else
|
||||
g_free (mi->info.uid);
|
||||
mi->info.uid = uid;
|
||||
#endif
|
||||
mi->folder = f;
|
||||
g_ptr_array_add(vf->messages, mi);
|
||||
uid = (char *)camel_message_info_uid(mi);
|
||||
g_hash_table_insert(vf->messages_uid, uid, mi);
|
||||
|
||||
printf("adding match %s\n", uid);
|
||||
|
||||
camel_folder_change_info_add_uid(vf->changes, uid);
|
||||
mi = vee_folder_add(vf, f, info);
|
||||
camel_folder_change_info_add_uid(vf->changes, camel_message_info_uid(mi));
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
@ -258,7 +271,7 @@ vfolder_change_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo, const Camel
|
||||
CamelFlag *flag;
|
||||
CamelTag *tag;
|
||||
|
||||
printf("changing match %s\n", camel_message_info_uid(vinfo));
|
||||
d(printf("changing match %s\n", camel_message_info_uid(vinfo)));
|
||||
|
||||
vinfo->info.flags = info->flags;
|
||||
camel_flag_list_free(&vinfo->info.user_flags);
|
||||
@ -276,6 +289,8 @@ vfolder_change_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo, const Camel
|
||||
camel_folder_change_info_change_uid(vf->changes, camel_message_info_uid(vinfo));
|
||||
}
|
||||
|
||||
/* FIXME: This code is a big race, as it is never called locked ... */
|
||||
|
||||
static void
|
||||
folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
{
|
||||
@ -283,6 +298,7 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
|
||||
#ifdef DYNAMIC
|
||||
CamelFolderChangeInfo *changes = type;
|
||||
CamelFolder *folder = (CamelFolder *)vf;
|
||||
|
||||
/* assume its faster to search a long list in whole, than by part */
|
||||
if (changes && (changes->uid_added->len + changes->uid_changed->len) < 500) {
|
||||
@ -290,10 +306,18 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
char *vuid;
|
||||
CamelVeeMessageInfo *vinfo;
|
||||
gboolean match;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
|
||||
ex = camel_exception_new();
|
||||
|
||||
/* FIXME: We dont search body contents with this search, so, it isn't as
|
||||
useful as it might be.
|
||||
We shold probably just perform a whole search if we need to, i.e. there
|
||||
are added items. Changed items we are unlikely to want to remove immediately
|
||||
anyway, although I guess it might be useful.
|
||||
Removed items can always just be removed.
|
||||
*/
|
||||
|
||||
/* see if added ones now match us */
|
||||
for (i=0;i<changes->uid_added->len;i++) {
|
||||
info = camel_folder_get_message_info(sub, changes->uid_added->pdata[i]);
|
||||
@ -301,7 +325,8 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
camel_folder_search_set_folder(vf->search, sub);
|
||||
match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
|
||||
if (match)
|
||||
vinfo = vfolder_add_match(vf, sub, info);
|
||||
vinfo = vee_folder_add_change(vf, sub, info);
|
||||
camel_folder_free_message_info(sub, info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,20 +334,31 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
for (i=0;i<changes->uid_changed->len;i++) {
|
||||
info = camel_folder_get_message_info(sub, changes->uid_changed->pdata[i]);
|
||||
vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_changed->pdata[i]);
|
||||
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
|
||||
vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
|
||||
if (info) {
|
||||
camel_folder_search_set_folder(vf->search, sub);
|
||||
#if 0
|
||||
match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
|
||||
#endif
|
||||
if (vinfo) {
|
||||
if (match)
|
||||
vfolder_change_match(vf, vinfo, info);
|
||||
else
|
||||
#if 0
|
||||
if (!match)
|
||||
vfolder_remove_match(vf, vinfo);
|
||||
} else if (match)
|
||||
vfolder_add_match(vf, sub, info);
|
||||
else
|
||||
#endif
|
||||
vfolder_change_match(vf, vinfo, info);
|
||||
}
|
||||
#if 0
|
||||
else if (match)
|
||||
vee_folder_add_change(vf, sub, info);
|
||||
#endif
|
||||
camel_folder_free_message_info(sub, info);
|
||||
} else if (vinfo)
|
||||
vfolder_remove_match(vf, vinfo);
|
||||
|
||||
if (vinfo)
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
|
||||
|
||||
g_free(vuid);
|
||||
}
|
||||
|
||||
@ -331,9 +367,11 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
/* mirror removes directly, if they used to match */
|
||||
for (i=0;i<changes->uid_removed->len;i++) {
|
||||
vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_removed->pdata[i]);
|
||||
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
|
||||
if (vinfo)
|
||||
vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
|
||||
if (vinfo) {
|
||||
vfolder_remove_match(vf, vinfo);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
|
||||
}
|
||||
g_free(vuid);
|
||||
}
|
||||
} else {
|
||||
@ -352,21 +390,24 @@ folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: This code is a race, as it is never called locked */
|
||||
|
||||
/* track flag changes in the summary */
|
||||
static void
|
||||
message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf)
|
||||
{
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
CamelVeeMessageInfo *vinfo;
|
||||
char *vuid;
|
||||
CamelFolder *folder = (CamelFolder *)mf;
|
||||
#ifdef DYNAMIC
|
||||
gboolean match;
|
||||
/*gboolean match;*/
|
||||
CamelException *ex;
|
||||
#endif
|
||||
|
||||
info = camel_folder_get_message_info(f, uid);
|
||||
vuid = g_strdup_printf("%p:%s", f, uid);
|
||||
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)mf, vuid);
|
||||
vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
|
||||
|
||||
/* see if this message now matches/doesn't match anymore */
|
||||
|
||||
@ -376,16 +417,23 @@ message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf)
|
||||
#ifdef DYNAMIC
|
||||
camel_folder_search_set_folder(mf->search, f);
|
||||
ex = camel_exception_new();
|
||||
#if 0
|
||||
match = camel_folder_search_match_expression(mf->search, mf->expression, info, ex);
|
||||
#endif
|
||||
camel_exception_free(ex);
|
||||
if (info) {
|
||||
if (vinfo) {
|
||||
if (match)
|
||||
vfolder_change_match(mf, vinfo, info);
|
||||
else
|
||||
#if 0
|
||||
if (!match)
|
||||
vfolder_remove_match(mf, vinfo);
|
||||
} else if (match)
|
||||
vfolder_add_match(mf, f, info);
|
||||
else
|
||||
#endif
|
||||
vfolder_change_match(mf, vinfo, info);
|
||||
}
|
||||
#if 0
|
||||
else if (match)
|
||||
vee_folder_add_change(mf, f, info);
|
||||
#endif
|
||||
} else if (vinfo)
|
||||
vfolder_remove_match(mf, vinfo);
|
||||
#else
|
||||
@ -393,6 +441,11 @@ message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf)
|
||||
vfolder_change_match(mf, vinfo, info);
|
||||
#endif
|
||||
|
||||
if (info)
|
||||
camel_folder_free_message_info(f, info);
|
||||
if (vinfo)
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)vinfo);
|
||||
|
||||
/* cascade up, if required. This could probably be delayed,
|
||||
but doesn't matter really, that is what freeze is for. */
|
||||
if (camel_folder_change_info_changed(mf->changes)) {
|
||||
@ -432,97 +485,53 @@ camel_vee_folder_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vee_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
|
||||
{
|
||||
;
|
||||
CamelVeeFolder *vf = (CamelVeeFolder *)folder;
|
||||
struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
|
||||
GList *node;
|
||||
|
||||
node = p->folders;
|
||||
while (node) {
|
||||
CamelFolder *f = node->data;
|
||||
|
||||
camel_folder_sync(f, expunge, ex);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
static gint vee_get_message_count (CamelFolder *folder)
|
||||
static void
|
||||
vee_expunge (CamelFolder *folder, CamelException *ex)
|
||||
{
|
||||
CamelVeeFolder *vf = (CamelVeeFolder *)folder;
|
||||
struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
|
||||
GList *node;
|
||||
|
||||
return vf->messages->len;
|
||||
}
|
||||
node = p->folders;
|
||||
while (node) {
|
||||
CamelFolder *f = node->data;
|
||||
|
||||
static gint
|
||||
vee_get_unread_message_count (CamelFolder *folder)
|
||||
{
|
||||
CamelVeeFolder *vee_folder = CAMEL_VEE_FOLDER (folder);
|
||||
CamelMessageInfo *info;
|
||||
GPtrArray *infolist;
|
||||
gint i, count = 0;
|
||||
|
||||
g_return_val_if_fail (folder != NULL, -1);
|
||||
|
||||
infolist = vee_folder->messages;
|
||||
|
||||
for (i = 0; i < infolist->len; i++) {
|
||||
info = (CamelMessageInfo *) g_ptr_array_index (infolist, i);
|
||||
if (!(info->flags & CAMEL_MESSAGE_SEEN))
|
||||
count++;
|
||||
camel_folder_expunge(f, ex);
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_real_message(CamelFolder *folder, const char *uid, CamelFolder **out_folder, const char **out_uid)
|
||||
{
|
||||
CamelVeeMessageInfo *mi;
|
||||
|
||||
mi = (CamelVeeMessageInfo *)vee_get_message_info(folder, uid);
|
||||
g_return_val_if_fail(mi != NULL, FALSE);
|
||||
|
||||
*out_folder = mi->folder;
|
||||
*out_uid = strchr(camel_message_info_uid(mi), ':')+1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static CamelMimeMessage *vee_get_message(CamelFolder *folder, const gchar *uid, CamelException *ex)
|
||||
{
|
||||
const char *real_uid;
|
||||
CamelFolder *real_folder;
|
||||
CamelVeeMessageInfo *mi;
|
||||
CamelMimeMessage *msg = NULL;
|
||||
|
||||
if (!get_real_message(folder, uid, &real_folder, &real_uid)) {
|
||||
mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
|
||||
if (mi == NULL)
|
||||
camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
|
||||
"No such message %s in %s", uid,
|
||||
folder->name);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
msg = camel_folder_get_message(mi->folder, strchr(camel_message_info_uid(mi), ':') + 1, ex);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
|
||||
|
||||
return camel_folder_get_message (real_folder, real_uid, ex);
|
||||
}
|
||||
|
||||
GPtrArray *vee_get_summary(CamelFolder *folder)
|
||||
{
|
||||
CamelVeeFolder *vf = (CamelVeeFolder *)folder;
|
||||
|
||||
return vf->messages;
|
||||
}
|
||||
|
||||
static const CamelMessageInfo *vee_get_message_info(CamelFolder *f, const char *uid)
|
||||
{
|
||||
CamelVeeFolder *vf = (CamelVeeFolder *)f;
|
||||
|
||||
return g_hash_table_lookup(vf->messages_uid, uid);
|
||||
}
|
||||
|
||||
static GPtrArray *vee_get_uids (CamelFolder *folder)
|
||||
{
|
||||
GPtrArray *result;
|
||||
int i;
|
||||
CamelVeeFolder *vf = (CamelVeeFolder *)folder;
|
||||
|
||||
result = g_ptr_array_new ();
|
||||
g_ptr_array_set_size (result, vf->messages->len);
|
||||
for (i=0;i<vf->messages->len;i++) {
|
||||
CamelMessageInfo *mi = g_ptr_array_index(vf->messages, i);
|
||||
result->pdata[i] = g_strdup(camel_message_info_uid(mi));
|
||||
}
|
||||
|
||||
return result;
|
||||
return msg;
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
@ -551,55 +560,32 @@ vee_search_by_expression(CamelFolder *folder, const char *expression, CamelExcep
|
||||
return result;
|
||||
}
|
||||
|
||||
static guint32
|
||||
vee_get_message_flags(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
const char *real_uid;
|
||||
CamelFolder *real_folder;
|
||||
|
||||
if (!get_real_message (folder, uid, &real_folder, &real_uid))
|
||||
return 0;
|
||||
|
||||
return camel_folder_get_message_flags(real_folder, real_uid);
|
||||
}
|
||||
|
||||
static void
|
||||
vee_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
|
||||
{
|
||||
const char *real_uid;
|
||||
CamelFolder *real_folder;
|
||||
CamelVeeMessageInfo *mi;
|
||||
|
||||
if (!get_real_message(folder, uid, &real_folder, &real_uid))
|
||||
return;
|
||||
|
||||
camel_folder_set_message_flags(real_folder, real_uid, flags, set);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vee_get_message_user_flag(CamelFolder *folder, const char *uid, const char *name)
|
||||
{
|
||||
const char *real_uid;
|
||||
CamelFolder *real_folder;
|
||||
|
||||
if (!get_real_message(folder, uid, &real_folder, &real_uid))
|
||||
return FALSE;
|
||||
|
||||
return camel_folder_get_message_user_flag(real_folder, real_uid, name);
|
||||
mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
|
||||
if (mi) {
|
||||
((CamelFolderClass *)camel_vee_folder_parent)->set_message_flags(folder, uid, flags, set);
|
||||
camel_folder_set_message_flags(mi->folder, strchr(camel_message_info_uid(mi), ':') + 1, flags, set);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vee_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value)
|
||||
{
|
||||
const char *real_uid;
|
||||
CamelFolder *real_folder;
|
||||
CamelVeeMessageInfo *mi;
|
||||
|
||||
if (!get_real_message(folder, uid, &real_folder, &real_uid))
|
||||
return;
|
||||
|
||||
return camel_folder_set_message_user_flag(real_folder, real_uid, name, value);
|
||||
mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
|
||||
if (mi) {
|
||||
((CamelFolderClass *)camel_vee_folder_parent)->set_message_user_flag(folder, uid, name, value);
|
||||
camel_folder_set_message_user_flag(mi->folder, strchr(camel_message_info_uid(mi), ':') + 1, name, value);
|
||||
camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)mi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
need incremental update, based on folder.
|
||||
Need to watch folders for changes and update accordingly.
|
||||
@ -609,54 +595,22 @@ vee_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name
|
||||
static void
|
||||
vee_folder_build(CamelVeeFolder *vf, CamelException *ex)
|
||||
{
|
||||
CamelFolder *folder = (CamelFolder *)vf;
|
||||
struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
|
||||
GList *node;
|
||||
int i;
|
||||
GPtrArray *messages;
|
||||
GHashTable *messages_uid;
|
||||
|
||||
for (i=0;i<vf->messages->len;i++) {
|
||||
CamelMessageInfo *mi = g_ptr_array_index(vf->messages, i);
|
||||
camel_message_info_free(mi);
|
||||
}
|
||||
|
||||
messages = g_ptr_array_new();
|
||||
messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
g_ptr_array_free(vf->messages, TRUE);
|
||||
vf->messages = messages;
|
||||
g_hash_table_destroy(vf->messages_uid);
|
||||
vf->messages_uid = messages_uid;
|
||||
camel_folder_summary_clear(folder->summary);
|
||||
|
||||
node = p->folders;
|
||||
while (node) {
|
||||
GPtrArray *matches;
|
||||
CamelFolder *f = node->data;
|
||||
CamelVeeMessageInfo *mi;
|
||||
const CamelMessageInfo *info;
|
||||
int i;
|
||||
|
||||
matches = camel_folder_search_by_expression(f, vf->expression, ex);
|
||||
for (i = 0; i < matches->len; i++) {
|
||||
info = camel_folder_get_message_info(f, matches->pdata[i]);
|
||||
if (info) {
|
||||
char *uid;
|
||||
for (i = 0; i < matches->len; i++)
|
||||
vee_folder_add_uid(vf, f, matches->pdata[i]);
|
||||
|
||||
mi = g_malloc0(sizeof(*mi));
|
||||
camel_message_info_dup_to(info, (CamelMessageInfo *)mi);
|
||||
uid = g_strdup_printf("%p:%s", f, camel_message_info_uid(info));
|
||||
#ifdef DOESTRV
|
||||
mi->info.strings = e_strv_set_ref_free(mi->info.strings, CAMEL_MESSAGE_INFO_UID, uid);
|
||||
mi->info.strings = e_strv_pack(mi->info.strings);
|
||||
#else
|
||||
g_free(mi->info.uid);
|
||||
mi->info.uid = uid;
|
||||
#endif
|
||||
mi->folder = f;
|
||||
g_ptr_array_add(messages, mi);
|
||||
g_hash_table_insert(messages_uid, (char *)camel_message_info_uid(mi), mi);
|
||||
}
|
||||
}
|
||||
camel_folder_search_free(f, matches);
|
||||
node = g_list_next(node);
|
||||
}
|
||||
@ -670,50 +624,27 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException
|
||||
GPtrArray *matches;
|
||||
CamelFolder *f = source;
|
||||
CamelVeeMessageInfo *mi;
|
||||
const CamelMessageInfo *info;
|
||||
|
||||
GPtrArray *messages;
|
||||
GHashTable *messages_uid;
|
||||
CamelFolder *folder = (CamelFolder *)vf;
|
||||
int i;
|
||||
int count;
|
||||
|
||||
for (i=0;i<vf->messages->len;i++) {
|
||||
CamelVeeMessageInfo *mi = g_ptr_array_index(vf->messages, i);
|
||||
if (mi->folder == source) {
|
||||
count = camel_folder_summary_count(folder->summary);
|
||||
for (i=0;i<count;i++) {
|
||||
CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
|
||||
if (mi && mi->folder == source) {
|
||||
const char *uid = camel_message_info_uid(mi);
|
||||
camel_folder_change_info_add_source(vf->changes, uid);
|
||||
g_hash_table_remove(vf->messages_uid, uid);
|
||||
g_ptr_array_remove_index_fast(vf->messages, i);
|
||||
|
||||
camel_message_info_free((CamelMessageInfo *)mi);
|
||||
camel_folder_summary_remove(folder->summary, (CamelMessageInfo *)mi);
|
||||
i--;
|
||||
}
|
||||
camel_message_info_free((CamelMessageInfo *)mi);
|
||||
}
|
||||
|
||||
messages = vf->messages;
|
||||
messages_uid = vf->messages_uid;
|
||||
|
||||
matches = camel_folder_search_by_expression(f, vf->expression, ex);
|
||||
for (i = 0; i < matches->len; i++) {
|
||||
info = camel_folder_get_message_info(f, matches->pdata[i]);
|
||||
if (info) {
|
||||
char *uid;
|
||||
|
||||
mi = g_malloc0(sizeof(*mi));
|
||||
camel_message_info_dup_to(info, (CamelMessageInfo*)mi);
|
||||
uid = g_strdup_printf("%p:%s", f, camel_message_info_uid(info));
|
||||
#ifdef DOESTRV
|
||||
mi->info.strings = e_strv_set_ref_free(mi->info.strings, CAMEL_MESSAGE_INFO_UID, uid);
|
||||
mi->info.strings = e_strv_pack(mi->info.strings);
|
||||
#else
|
||||
g_free (mi->info.uid);
|
||||
mi->info.uid = uid;
|
||||
#endif
|
||||
mi->folder = f;
|
||||
g_ptr_array_add(messages, mi);
|
||||
uid = (char *)camel_message_info_uid(mi);
|
||||
g_hash_table_insert(messages_uid, uid, mi);
|
||||
camel_folder_change_info_add_update(vf->changes, uid);
|
||||
}
|
||||
mi = vee_folder_add_uid(vf, f, matches->pdata[i]);
|
||||
if (mi)
|
||||
camel_folder_change_info_add_update(vf->changes, camel_message_info_uid(mi));
|
||||
}
|
||||
camel_folder_search_free(f, matches);
|
||||
|
||||
|
||||
@ -43,9 +43,6 @@ struct _CamelVeeFolder {
|
||||
char *vname; /* local name */
|
||||
CamelFolder *local; /* local storage for folder */
|
||||
|
||||
/* FIXME: Move this to a summary object??? */
|
||||
GPtrArray *messages; /* message info's */
|
||||
GHashTable *messages_uid;
|
||||
CamelFolderChangeInfo *changes;
|
||||
#ifdef DYNAMIC
|
||||
CamelFolderSearch *search;
|
||||
|
||||
@ -15,11 +15,13 @@ LDADD = \
|
||||
check_PROGRAMS = \
|
||||
test1 test4 test5 \
|
||||
test2 test6 test7 \
|
||||
test3
|
||||
test3 \
|
||||
test8
|
||||
|
||||
TESTS = test1 test4 test5 \
|
||||
test2 test6 test7 \
|
||||
test3
|
||||
test3 \
|
||||
test8
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,3 +7,5 @@ test5 camel store folder operations, NNTP
|
||||
test6 basic folder operations, IMAP
|
||||
test7 basic folder operations, NNTP
|
||||
|
||||
test8 multithreaded folder torture test, local
|
||||
|
||||
|
||||
222
camel/tests/folder/test8.c
Normal file
222
camel/tests/folder/test8.c
Normal file
@ -0,0 +1,222 @@
|
||||
/* threaded folder testing */
|
||||
|
||||
#include "camel-test.h"
|
||||
#include "folders.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <camel/camel-exception.h>
|
||||
#include <camel/camel-service.h>
|
||||
#include <camel/camel-session.h>
|
||||
#include <camel/camel-store.h>
|
||||
|
||||
#define MAX_MESSAGES (100)
|
||||
#define MAX_THREADS (10)
|
||||
|
||||
#define d(x)
|
||||
|
||||
#ifndef ENABLE_THREADS
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Test %s is only compiled with threads enabled\n", argv[0]);
|
||||
return 77;
|
||||
}
|
||||
#else
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/* god, who designed this horrid interface */
|
||||
static char *auth_callback(CamelAuthCallbackMode mode,
|
||||
char *data, gboolean secret,
|
||||
CamelService *service, char *item,
|
||||
CamelException *ex)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
static char *local_providers[] = {
|
||||
"mbox",
|
||||
"mh",
|
||||
"maildir"
|
||||
};
|
||||
|
||||
static void
|
||||
test_add_message(CamelFolder *folder, int j)
|
||||
{
|
||||
CamelMimeMessage *msg;
|
||||
char *content;
|
||||
char *subject;
|
||||
CamelException ex;
|
||||
|
||||
camel_exception_init(&ex);
|
||||
|
||||
push("creating message %d\n", j);
|
||||
msg = test_message_create_simple();
|
||||
content = g_strdup_printf("Test message %d contents\n\n", j);
|
||||
test_message_set_content_simple((CamelMimePart *)msg, 0, "text/plain",
|
||||
content, strlen(content));
|
||||
test_free(content);
|
||||
subject = g_strdup_printf("Test message %d subject", j);
|
||||
camel_mime_message_set_subject(msg, subject);
|
||||
pull();
|
||||
|
||||
push("appending simple message %d", j);
|
||||
camel_folder_append_message(folder, msg, NULL, &ex);
|
||||
check_msg(!camel_exception_is_set(&ex), "%s", camel_exception_get_description(&ex));
|
||||
pull();
|
||||
|
||||
check_unref(msg, 1);
|
||||
}
|
||||
|
||||
struct _threadinfo {
|
||||
int id;
|
||||
CamelFolder *folder;
|
||||
};
|
||||
|
||||
static void *
|
||||
worker(void *d)
|
||||
{
|
||||
struct _threadinfo *info = d;
|
||||
int i, j, id = info->id;
|
||||
char *sub, *content;
|
||||
GPtrArray *res;
|
||||
CamelException *ex = camel_exception_new();
|
||||
CamelMimeMessage *msg;
|
||||
|
||||
/* we add a message, search for it, twiddle some flags, delete it */
|
||||
/* and flat out */
|
||||
for (i=0;i<MAX_MESSAGES;i++) {
|
||||
d(printf("Thread %ld message %i\n", pthread_self(), i));
|
||||
test_add_message(info->folder, id+i);
|
||||
|
||||
sub = g_strdup_printf("(match-all (header-contains \"subject\" \"message %d subject\"))", id+i);
|
||||
|
||||
push("searching for message %d\n\tusing: %s", id+i, sub);
|
||||
res = camel_folder_search_by_expression(info->folder, sub, ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
check_msg(res->len == 1, "res->len = %d", res->len);
|
||||
pull();
|
||||
|
||||
push("getting message '%s'", res->pdata[0]);
|
||||
msg = camel_folder_get_message(info->folder, (char *)res->pdata[0], ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
pull();
|
||||
|
||||
push("comparing content");
|
||||
content = g_strdup_printf("Test message %d contents\n\n", id+i);
|
||||
test_message_compare_content(camel_medium_get_content_object((CamelMedium *)msg), content, strlen(content));
|
||||
test_free(content);
|
||||
|
||||
push("deleting message, cleanup");
|
||||
j=(100.0*rand()/(RAND_MAX+1.0));
|
||||
if (j<=70) {
|
||||
camel_folder_delete_message(info->folder, res->pdata[0]);
|
||||
}
|
||||
|
||||
camel_folder_search_free(info->folder, res);
|
||||
res = NULL;
|
||||
test_free(sub);
|
||||
|
||||
check_unref(msg, 1);
|
||||
pull();
|
||||
|
||||
/* about 1-in 100 calls will expunge */
|
||||
j=(200.0*rand()/(RAND_MAX+1.0));
|
||||
if (j<=2) {
|
||||
d(printf("Forcing an expuge\n"));
|
||||
push("expunging folder");
|
||||
camel_folder_expunge(info->folder, ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
pull();
|
||||
}
|
||||
}
|
||||
|
||||
camel_exception_free(ex);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CamelSession *session;
|
||||
CamelException *ex;
|
||||
int i, j, index;
|
||||
char *path;
|
||||
CamelStore *store;
|
||||
pthread_t threads[MAX_THREADS];
|
||||
struct _threadinfo *info;
|
||||
CamelFolder *folder;
|
||||
GPtrArray *uids;
|
||||
|
||||
camel_test_init(argc, argv);
|
||||
|
||||
ex = camel_exception_new();
|
||||
|
||||
/* clear out any camel-test data */
|
||||
system("/bin/rm -rf /tmp/camel-test");
|
||||
|
||||
session = camel_session_new("/tmp/camel-test", auth_callback, NULL, NULL);
|
||||
|
||||
for (j=0;j<ARRAY_LEN(local_providers);j++) {
|
||||
for (index=0;index<2;index++) {
|
||||
path = g_strdup_printf("method %s %s", local_providers[j], index?"indexed":"nonindexed");
|
||||
camel_test_start(path);
|
||||
test_free(path);
|
||||
|
||||
push("trying %s index %d", local_providers[j], index);
|
||||
path = g_strdup_printf("%s:///tmp/camel-test/%s", local_providers[j], local_providers[j]);
|
||||
store = camel_session_get_store(session, path, ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
test_free(path);
|
||||
|
||||
if (index == 0)
|
||||
folder = camel_store_get_folder(store, "testbox", CAMEL_STORE_FOLDER_CREATE, ex);
|
||||
else
|
||||
folder = camel_store_get_folder(store, "testbox",
|
||||
CAMEL_STORE_FOLDER_CREATE|CAMEL_STORE_FOLDER_BODY_INDEX, ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
|
||||
for (i=0;i<MAX_THREADS;i++) {
|
||||
info = g_malloc(sizeof(*info));
|
||||
info->id = i*MAX_MESSAGES;
|
||||
info->folder = folder;
|
||||
pthread_create(&threads[i], 0, worker, info);
|
||||
}
|
||||
|
||||
for (i=0;i<MAX_THREADS;i++) {
|
||||
pthread_join(threads[i], (void **)&info);
|
||||
g_free(info);
|
||||
}
|
||||
pull();
|
||||
|
||||
push("deleting remaining messages");
|
||||
uids = camel_folder_get_uids(folder);
|
||||
for (i=0;i<uids->len;i++) {
|
||||
camel_folder_delete_message(folder, uids->pdata[i]);
|
||||
}
|
||||
camel_folder_free_uids(folder, uids);
|
||||
|
||||
camel_folder_expunge(folder, ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
|
||||
check_unref(folder, 1);
|
||||
|
||||
camel_store_delete_folder(store, "testbox", ex);
|
||||
check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex));
|
||||
|
||||
check_unref(store, 1);
|
||||
|
||||
pull();
|
||||
|
||||
camel_test_end();
|
||||
}
|
||||
}
|
||||
|
||||
camel_object_unref((CamelObject *)session);
|
||||
camel_exception_free(ex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_THREADS */
|
||||
@ -4,39 +4,97 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
/* well i dunno, doesn't seem to be in the headers but hte manpage mentions it */
|
||||
/* a nonportable checking mutex for glibc, not really needed, just validates
|
||||
the test harness really */
|
||||
# ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
|
||||
static pthread_mutex_t lock = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
|
||||
# else
|
||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
# endif
|
||||
#define CAMEL_TEST_LOCK pthread_mutex_lock(&lock)
|
||||
#define CAMEL_TEST_UNLOCK pthread_mutex_unlock(&lock)
|
||||
#define CAMEL_TEST_ID (pthread_self())
|
||||
#else
|
||||
#define CAMEL_TEST_LOCK
|
||||
#define CAMEL_TEST_UNLOCK
|
||||
#define CAMEL_TEST_ID (0)
|
||||
#endif
|
||||
|
||||
static int setup;
|
||||
static int ok;
|
||||
|
||||
struct _stack {
|
||||
struct _stack *next;
|
||||
int fatal;
|
||||
char *what;
|
||||
};
|
||||
|
||||
static int setup;
|
||||
static struct _stack *state;
|
||||
static struct _stack *nonfatal;
|
||||
static int ok;
|
||||
/* per-thread state */
|
||||
struct _state {
|
||||
char *test;
|
||||
int nonfatal;
|
||||
struct _stack *state;
|
||||
};
|
||||
|
||||
static GHashTable *info_table;
|
||||
|
||||
int camel_test_verbose;
|
||||
|
||||
static void
|
||||
dump_action(int id, struct _state *s, void *d)
|
||||
{
|
||||
struct _stack *node;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
printf("\nThread %d:\n", id);
|
||||
#endif
|
||||
node = s->state;
|
||||
if (node) {
|
||||
printf("Current action:\n");
|
||||
while (node) {
|
||||
printf("\t%s%s\n", node->fatal?"":"[nonfatal]", node->what);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
printf("\tTest: %s\n", s->test);
|
||||
}
|
||||
|
||||
static void die(int sig)
|
||||
{
|
||||
static int indie = 0;
|
||||
struct _stack *node;
|
||||
|
||||
if (!indie) {
|
||||
indie = 1;
|
||||
printf("\n\nReceived fatal signal %d\n", sig);
|
||||
node = state;
|
||||
if (node) {
|
||||
printf("Current action:\n");
|
||||
while (node) {
|
||||
printf("\t%s\n", node->what);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
g_hash_table_foreach(info_table, (GHFunc)dump_action, 0);
|
||||
}
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
static struct _state *
|
||||
current_state(void)
|
||||
{
|
||||
struct _state *info;
|
||||
|
||||
if (info_table == NULL)
|
||||
info_table = g_hash_table_new(0, 0);
|
||||
|
||||
info = g_hash_table_lookup(info_table, (void *)CAMEL_TEST_ID);
|
||||
if (info == NULL) {
|
||||
info = g_malloc0(sizeof(*info));
|
||||
g_hash_table_insert(info_table, (void *)CAMEL_TEST_ID, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
void camel_test_init(int argc, char **argv)
|
||||
{
|
||||
void camel_init(void);
|
||||
@ -44,7 +102,11 @@ void camel_test_init(int argc, char **argv)
|
||||
|
||||
setup = 1;
|
||||
|
||||
#ifndef ENABLE_THREADS
|
||||
camel_init();
|
||||
#endif
|
||||
|
||||
info_table = g_hash_table_new(0, 0);
|
||||
|
||||
/* yeah, we do need ot thread init, even though camel isn't compiled with enable threads */
|
||||
g_thread_init(NULL);
|
||||
@ -71,15 +133,25 @@ void camel_test_init(int argc, char **argv)
|
||||
|
||||
void camel_test_start(const char *what)
|
||||
{
|
||||
struct _state *s;
|
||||
|
||||
CAMEL_TEST_LOCK;
|
||||
|
||||
s = current_state();
|
||||
|
||||
if (!setup)
|
||||
camel_test_init(0, 0);
|
||||
|
||||
ok = 1;
|
||||
|
||||
s->test = g_strdup(what);
|
||||
|
||||
if (camel_test_verbose > 0) {
|
||||
printf("Test: %s ... ", what);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
CAMEL_TEST_UNLOCK;
|
||||
}
|
||||
|
||||
void camel_test_push(const char *what, ...)
|
||||
@ -87,6 +159,11 @@ void camel_test_push(const char *what, ...)
|
||||
struct _stack *node;
|
||||
va_list ap;
|
||||
char *text;
|
||||
struct _state *s;
|
||||
|
||||
CAMEL_TEST_LOCK;
|
||||
|
||||
s = current_state();
|
||||
|
||||
va_start(ap, what);
|
||||
text = g_strdup_vprintf(what, ap);
|
||||
@ -97,26 +174,40 @@ void camel_test_push(const char *what, ...)
|
||||
|
||||
node = g_malloc(sizeof(*node));
|
||||
node->what = text;
|
||||
node->next = state;
|
||||
state = node;
|
||||
node->next = s->state;
|
||||
node->fatal = 1;
|
||||
s->state = node;
|
||||
|
||||
CAMEL_TEST_UNLOCK;
|
||||
}
|
||||
|
||||
void camel_test_pull(void)
|
||||
{
|
||||
struct _stack *node;
|
||||
struct _state *s;
|
||||
|
||||
g_assert(state);
|
||||
CAMEL_TEST_LOCK;
|
||||
|
||||
s = current_state();
|
||||
|
||||
g_assert(s->state);
|
||||
|
||||
if (camel_test_verbose > 3)
|
||||
printf("Finish step: %s\n", state->what);
|
||||
printf("Finish step: %s\n", s->state->what);
|
||||
|
||||
node = state;
|
||||
state = node->next;
|
||||
node = s->state;
|
||||
s->state = node->next;
|
||||
if (!node->fatal)
|
||||
s->nonfatal--;
|
||||
g_free(node->what);
|
||||
g_free(node);
|
||||
|
||||
CAMEL_TEST_UNLOCK;
|
||||
}
|
||||
|
||||
/* where to set breakpoints */
|
||||
void camel_test_break(void);
|
||||
|
||||
void camel_test_break(void)
|
||||
{
|
||||
}
|
||||
@ -130,75 +221,75 @@ void camel_test_fail(const char *why, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void camel_test_failv(const char *why, va_list ap)
|
||||
{
|
||||
struct _stack *node;
|
||||
char *text;
|
||||
struct _state *s;
|
||||
|
||||
CAMEL_TEST_LOCK;
|
||||
|
||||
s = current_state();
|
||||
|
||||
text = g_strdup_vprintf(why, ap);
|
||||
|
||||
if ((nonfatal == NULL && camel_test_verbose > 0)
|
||||
|| (nonfatal && camel_test_verbose > 1)) {
|
||||
if ((s->nonfatal == 0 && camel_test_verbose > 0)
|
||||
|| (s->nonfatal && camel_test_verbose > 1)) {
|
||||
printf("Failed.\n%s\n", text);
|
||||
camel_test_break();
|
||||
}
|
||||
|
||||
g_free(text);
|
||||
|
||||
if ((nonfatal == NULL && camel_test_verbose > 0)
|
||||
|| (nonfatal && camel_test_verbose > 2)) {
|
||||
node = state;
|
||||
if (node) {
|
||||
printf("Current action:\n");
|
||||
while (node) {
|
||||
printf("\t%s\n", node->what);
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
if ((s->nonfatal == 0 && camel_test_verbose > 0)
|
||||
|| (s->nonfatal && camel_test_verbose > 2)) {
|
||||
g_hash_table_foreach(info_table, (GHFunc)dump_action, 0);
|
||||
}
|
||||
|
||||
if (nonfatal == NULL) {
|
||||
if (s->nonfatal == 0) {
|
||||
exit(1);
|
||||
} else {
|
||||
ok=0;
|
||||
if (camel_test_verbose > 1) {
|
||||
printf("Known problem (ignored): %s\n", nonfatal->what);
|
||||
printf("Known problem (ignored):\n");
|
||||
dump_action(CAMEL_TEST_ID, s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
CAMEL_TEST_UNLOCK;
|
||||
}
|
||||
|
||||
void camel_test_nonfatal(const char *why, ...)
|
||||
void camel_test_nonfatal(const char *what, ...)
|
||||
{
|
||||
struct _stack *node;
|
||||
va_list ap;
|
||||
char *text;
|
||||
struct _state *s;
|
||||
|
||||
va_start(ap, why);
|
||||
text = g_strdup_vprintf(why, ap);
|
||||
CAMEL_TEST_LOCK;
|
||||
|
||||
s = current_state();
|
||||
|
||||
va_start(ap, what);
|
||||
text = g_strdup_vprintf(what, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (camel_test_verbose>3)
|
||||
if (camel_test_verbose > 3)
|
||||
printf("Start nonfatal: %s\n", text);
|
||||
|
||||
node = g_malloc(sizeof(*node));
|
||||
node->what = text;
|
||||
node->next = nonfatal;
|
||||
nonfatal = node;
|
||||
node->next = s->state;
|
||||
node->fatal = 0;
|
||||
s->nonfatal++;
|
||||
s->state = node;
|
||||
|
||||
CAMEL_TEST_UNLOCK;
|
||||
}
|
||||
|
||||
void camel_test_fatal(void)
|
||||
{
|
||||
struct _stack *node;
|
||||
|
||||
g_assert(nonfatal);
|
||||
|
||||
if (camel_test_verbose>3)
|
||||
printf("Finish nonfatal: %s\n", nonfatal->what);
|
||||
|
||||
node = nonfatal;
|
||||
nonfatal = node->next;
|
||||
g_free(node->what);
|
||||
g_free(node);
|
||||
camel_test_pull();
|
||||
}
|
||||
|
||||
void camel_test_end(void)
|
||||
|
||||
@ -11,7 +11,7 @@ test_folder_counts(CamelFolder *folder, int total, int unread)
|
||||
{
|
||||
GPtrArray *s;
|
||||
int i, myunread;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
|
||||
push("test folder counts %d total %d unread", total, unread);
|
||||
|
||||
@ -41,6 +41,7 @@ test_folder_counts(CamelFolder *folder, int total, int unread)
|
||||
info = camel_folder_get_message_info(folder, s->pdata[i]);
|
||||
if (info->flags & CAMEL_MESSAGE_SEEN)
|
||||
myunread--;
|
||||
camel_folder_free_message_info(folder, info);
|
||||
}
|
||||
check(unread == myunread);
|
||||
camel_folder_free_uids(folder, s);
|
||||
@ -81,7 +82,7 @@ void
|
||||
test_folder_message(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelMimeMessage *msg;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
GPtrArray *s;
|
||||
int i;
|
||||
CamelException *ex = camel_exception_new();
|
||||
@ -93,6 +94,7 @@ test_folder_message(CamelFolder *folder, const char *uid)
|
||||
info = camel_folder_get_message_info(folder, uid);
|
||||
check(info != NULL);
|
||||
check(strcmp(camel_message_info_uid(info), uid) == 0);
|
||||
camel_folder_free_message_info(folder, info);
|
||||
|
||||
/* then, getting message */
|
||||
msg = camel_folder_get_message(folder, uid, ex);
|
||||
@ -137,7 +139,7 @@ void
|
||||
test_folder_not_message(CamelFolder *folder, const char *uid)
|
||||
{
|
||||
CamelMimeMessage *msg;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
GPtrArray *s;
|
||||
int i;
|
||||
CamelException *ex = camel_exception_new();
|
||||
@ -314,7 +316,7 @@ test_folder_message_ops(CamelSession *session, const char *name, int local)
|
||||
int j;
|
||||
int indexed, max;
|
||||
GPtrArray *uids;
|
||||
const CamelMessageInfo *info;
|
||||
CamelMessageInfo *info;
|
||||
|
||||
max=local?2:1;
|
||||
|
||||
@ -390,6 +392,7 @@ test_folder_message_ops(CamelSession *session, const char *name, int local)
|
||||
check_msg(strcmp(camel_message_info_subject(info), subject)==0,
|
||||
"info->subject %s", camel_message_info_subject(info));
|
||||
camel_folder_free_uids(folder, uids);
|
||||
camel_folder_free_message_info(folder, info);
|
||||
pull();
|
||||
|
||||
test_free(subject);
|
||||
@ -429,6 +432,7 @@ test_folder_message_ops(CamelSession *session, const char *name, int local)
|
||||
check_msg(strcmp(camel_message_info_subject(info), subject)==0,
|
||||
"info->subject %s", camel_message_info_subject(info));
|
||||
test_free(subject);
|
||||
camel_folder_free_message_info(folder, info);
|
||||
pull();
|
||||
}
|
||||
|
||||
@ -455,6 +459,7 @@ test_folder_message_ops(CamelSession *session, const char *name, int local)
|
||||
check_msg(strcmp(camel_message_info_subject(info), subject)==0,
|
||||
"info->subject %s", camel_message_info_subject(info));
|
||||
test_free(subject);
|
||||
camel_folder_free_message_info(folder, info);
|
||||
pull();
|
||||
}
|
||||
pull();
|
||||
@ -483,6 +488,7 @@ test_folder_message_ops(CamelSession *session, const char *name, int local)
|
||||
check_msg(strcmp(camel_message_info_subject(info), subject)==0,
|
||||
"info->subject %s", camel_message_info_subject(info));
|
||||
test_free(subject);
|
||||
camel_folder_free_message_info(folder, info);
|
||||
pull();
|
||||
}
|
||||
pull();
|
||||
|
||||
Reference in New Issue
Block a user