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:
Not Zed
2000-12-24 00:46:20 +00:00
committed by Michael Zucci
parent 6183d89039
commit 6de256c2a2
52 changed files with 2983 additions and 1279 deletions

View File

@ -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

View File

@ -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
View 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.

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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:
**/

View File

@ -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
View 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 */

View File

@ -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);
}

View File

@ -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, ...);

View File

@ -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

View File

@ -47,6 +47,7 @@ extern "C" {
struct _CamelService {
CamelObject parent_object;
struct _CamelServicePrivate *priv;
CamelSession *session;
CamelProvider *provider;

View File

@ -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;
}

View File

@ -60,6 +60,7 @@ typedef gboolean (*CamelTimeoutRemoveCallback) (guint id);
struct _CamelSession
{
CamelObject parent_object;
struct _CamelSessionPrivate *priv;
char *storage_path;
CamelAuthCallback authenticator;

View File

@ -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);
}

View File

@ -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,

View File

@ -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,

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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 *

View File

@ -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

View File

@ -44,6 +44,8 @@ extern "C" {
typedef struct {
CamelFolder parent_object;
struct _CamelImapFolderPrivate *priv;
CamelFolderSearch *search;
CamelFolderSummary *summary;
int exists;

View 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 */

View File

@ -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;
}

View File

@ -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);
}

View File

@ -56,7 +56,8 @@ typedef enum {
typedef struct {
CamelRemoteStore parent_object;
struct _CamelImapStorePrivate *priv;
CamelFolder *current_folder;
guint32 command;

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View 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 */

View File

@ -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

View File

@ -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));

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 */

View File

@ -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"),

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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
View 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 */

View File

@ -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)

View File

@ -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();