4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
19 #include "camel-imapx-job.h"
23 typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
25 /* CamelIMAPXJob + some private bits */
26 struct _CamelIMAPXRealJob {
29 volatile gint ref_count;
31 /* Used for running some jobs synchronously. */
36 /* Extra job-specific data. */
38 GDestroyNotify destroy_data;
42 imapx_job_cancelled_cb (GCancellable *cancellable,
45 /* Unblock camel_imapx_run_job() immediately.
47 * If camel_imapx_job_done() is called sometime later,
48 * the GCond will broadcast but no one will be listening. */
50 camel_imapx_job_done (job);
54 camel_imapx_job_new (GCancellable *cancellable)
56 CamelIMAPXRealJob *real_job;
58 if (cancellable != NULL)
59 g_object_ref (cancellable);
61 real_job = g_slice_new0 (CamelIMAPXRealJob);
63 /* Initialize private bits. */
64 real_job->ref_count = 1;
65 real_job->done_cond = g_cond_new ();
66 real_job->done_mutex = g_mutex_new ();
68 /* Initialize public bits. */
69 real_job->public.cancellable = cancellable;
71 return (CamelIMAPXJob *) real_job;
75 camel_imapx_job_ref (CamelIMAPXJob *job)
77 CamelIMAPXRealJob *real_job;
79 g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
81 real_job = (CamelIMAPXRealJob *) job;
83 g_atomic_int_inc (&real_job->ref_count);
89 camel_imapx_job_unref (CamelIMAPXJob *job)
91 CamelIMAPXRealJob *real_job;
93 g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
95 real_job = (CamelIMAPXRealJob *) job;
97 if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
99 /* Free the public stuff. */
101 g_clear_error (&real_job->public.error);
103 if (real_job->public.pop_operation_msg)
104 camel_operation_pop_message (
105 real_job->public.cancellable);
107 if (real_job->public.cancellable != NULL)
108 g_object_unref (real_job->public.cancellable);
110 /* Free the private stuff. */
112 g_cond_free (real_job->done_cond);
113 g_mutex_free (real_job->done_mutex);
115 if (real_job->destroy_data != NULL)
116 real_job->destroy_data (real_job->data);
118 /* Fill the memory with a bit pattern before releasing
119 * it back to the slab allocator, so we can more easily
120 * identify dangling CamelIMAPXJob pointers. */
121 memset (real_job, 0xaa, sizeof (CamelIMAPXRealJob));
123 /* But leave the reference count set to zero, so
124 * CAMEL_IS_IMAPX_JOB can identify it as bad. */
125 real_job->ref_count = 0;
127 g_slice_free (CamelIMAPXRealJob, real_job);
132 camel_imapx_job_check (CamelIMAPXJob *job)
134 CamelIMAPXRealJob *real_job;
136 real_job = (CamelIMAPXRealJob *) job;
138 return (real_job != NULL && real_job->ref_count > 0);
142 camel_imapx_job_wait (CamelIMAPXJob *job)
144 CamelIMAPXRealJob *real_job;
146 g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
148 real_job = (CamelIMAPXRealJob *) job;
150 g_mutex_lock (real_job->done_mutex);
151 while (!real_job->done_flag)
154 real_job->done_mutex);
155 g_mutex_unlock (real_job->done_mutex);
159 camel_imapx_job_done (CamelIMAPXJob *job)
161 CamelIMAPXRealJob *real_job;
163 g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
165 real_job = (CamelIMAPXRealJob *) job;
167 g_mutex_lock (real_job->done_mutex);
168 real_job->done_flag = TRUE;
169 g_cond_broadcast (real_job->done_cond);
170 g_mutex_unlock (real_job->done_mutex);
174 camel_imapx_job_run (CamelIMAPXJob *job,
175 CamelIMAPXServer *is,
178 gulong cancel_id = 0;
180 g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
181 g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
182 g_return_val_if_fail (job->start != NULL, FALSE);
184 if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
187 if (G_IS_CANCELLABLE (job->cancellable))
188 cancel_id = g_cancellable_connect (
190 G_CALLBACK (imapx_job_cancelled_cb),
191 camel_imapx_job_ref (job),
192 (GDestroyNotify) camel_imapx_job_unref);
194 job->start (job, is);
197 camel_imapx_job_wait (job);
200 g_cancellable_disconnect (job->cancellable, cancel_id);
202 if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
205 if (job->error != NULL) {
206 g_propagate_error (error, job->error);
215 camel_imapx_job_matches (CamelIMAPXJob *job,
219 /* XXX CamelFolder can be NULL. I'm less sure about the
220 * message UID but let's assume that can be NULL too. */
222 g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
225 g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
227 if (job->matches == NULL)
230 return job->matches (job, folder, uid);
234 camel_imapx_job_get_data (CamelIMAPXJob *job)
236 CamelIMAPXRealJob *real_job;
238 g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
240 real_job = (CamelIMAPXRealJob *) job;
242 return real_job->data;
246 camel_imapx_job_set_data (CamelIMAPXJob *job,
248 GDestroyNotify destroy_data)
250 CamelIMAPXRealJob *real_job;
252 g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
254 real_job = (CamelIMAPXRealJob *) job;
256 if (real_job->destroy_data != NULL)
257 real_job->destroy_data (real_job->data);
259 real_job->data = data;
260 real_job->destroy_data = destroy_data;