Bug #606181 - Accepting bad SSL certificate applies to any hostname
[platform/upstream/evolution-data-server.git] / camel / providers / imapx / camel-imapx-job.c
1 /*
2  * camel-imapx-job.c
3  *
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.
8  *
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.
13  *
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/>
16  *
17  */
18
19 #include "camel-imapx-job.h"
20
21 #include <string.h>
22
23 typedef struct _CamelIMAPXRealJob CamelIMAPXRealJob;
24
25 /* CamelIMAPXJob + some private bits */
26 struct _CamelIMAPXRealJob {
27         CamelIMAPXJob public;
28
29         volatile gint ref_count;
30
31         /* Used for running some jobs synchronously. */
32         GCond *done_cond;
33         GMutex *done_mutex;
34         gboolean done_flag;
35
36         /* Extra job-specific data. */
37         gpointer data;
38         GDestroyNotify destroy_data;
39 };
40
41 static void
42 imapx_job_cancelled_cb (GCancellable *cancellable,
43                         CamelIMAPXJob *job)
44 {
45         /* Unblock camel_imapx_run_job() immediately.
46          *
47          * If camel_imapx_job_done() is called sometime later,
48          * the GCond will broadcast but no one will be listening. */
49
50         camel_imapx_job_done (job);
51 }
52
53 CamelIMAPXJob *
54 camel_imapx_job_new (GCancellable *cancellable)
55 {
56         CamelIMAPXRealJob *real_job;
57
58         if (cancellable != NULL)
59                 g_object_ref (cancellable);
60
61         real_job = g_slice_new0 (CamelIMAPXRealJob);
62
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 ();
67
68         /* Initialize public bits. */
69         real_job->public.cancellable = cancellable;
70
71         return (CamelIMAPXJob *) real_job;
72 }
73
74 CamelIMAPXJob *
75 camel_imapx_job_ref (CamelIMAPXJob *job)
76 {
77         CamelIMAPXRealJob *real_job;
78
79         g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
80
81         real_job = (CamelIMAPXRealJob *) job;
82
83         g_atomic_int_inc (&real_job->ref_count);
84
85         return job;
86 }
87
88 void
89 camel_imapx_job_unref (CamelIMAPXJob *job)
90 {
91         CamelIMAPXRealJob *real_job;
92
93         g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
94
95         real_job = (CamelIMAPXRealJob *) job;
96
97         if (g_atomic_int_dec_and_test (&real_job->ref_count)) {
98
99                 /* Free the public stuff. */
100
101                 g_clear_error (&real_job->public.error);
102
103                 if (real_job->public.pop_operation_msg)
104                         camel_operation_pop_message (
105                                 real_job->public.cancellable);
106
107                 if (real_job->public.cancellable != NULL)
108                         g_object_unref (real_job->public.cancellable);
109
110                 /* Free the private stuff. */
111
112                 g_cond_free (real_job->done_cond);
113                 g_mutex_free (real_job->done_mutex);
114
115                 if (real_job->destroy_data != NULL)
116                         real_job->destroy_data (real_job->data);
117
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));
122
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;
126
127                 g_slice_free (CamelIMAPXRealJob, real_job);
128         }
129 }
130
131 gboolean
132 camel_imapx_job_check (CamelIMAPXJob *job)
133 {
134         CamelIMAPXRealJob *real_job;
135
136         real_job = (CamelIMAPXRealJob *) job;
137
138         return (real_job != NULL && real_job->ref_count > 0);
139 }
140
141 void
142 camel_imapx_job_wait (CamelIMAPXJob *job)
143 {
144         CamelIMAPXRealJob *real_job;
145
146         g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
147
148         real_job = (CamelIMAPXRealJob *) job;
149
150         g_mutex_lock (real_job->done_mutex);
151         while (!real_job->done_flag)
152                 g_cond_wait (
153                         real_job->done_cond,
154                         real_job->done_mutex);
155         g_mutex_unlock (real_job->done_mutex);
156 }
157
158 void
159 camel_imapx_job_done (CamelIMAPXJob *job)
160 {
161         CamelIMAPXRealJob *real_job;
162
163         g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
164
165         real_job = (CamelIMAPXRealJob *) job;
166
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);
171 }
172
173 gboolean
174 camel_imapx_job_run (CamelIMAPXJob *job,
175                      CamelIMAPXServer *is,
176                      GError **error)
177 {
178         gulong cancel_id = 0;
179
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);
183
184         if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
185                 return FALSE;
186
187         if (G_IS_CANCELLABLE (job->cancellable))
188                 cancel_id = g_cancellable_connect (
189                         job->cancellable,
190                         G_CALLBACK (imapx_job_cancelled_cb),
191                         camel_imapx_job_ref (job),
192                         (GDestroyNotify) camel_imapx_job_unref);
193
194         job->start (job, is);
195
196         if (!job->noreply)
197                 camel_imapx_job_wait (job);
198
199         if (cancel_id > 0)
200                 g_cancellable_disconnect (job->cancellable, cancel_id);
201
202         if (g_cancellable_set_error_if_cancelled (job->cancellable, error))
203                 return FALSE;
204
205         if (job->error != NULL) {
206                 g_propagate_error (error, job->error);
207                 job->error = NULL;
208                 return FALSE;
209         }
210
211         return TRUE;
212 }
213
214 gboolean
215 camel_imapx_job_matches (CamelIMAPXJob *job,
216                          CamelFolder *folder,
217                          const gchar *uid)
218 {
219         /* XXX CamelFolder can be NULL.  I'm less sure about the
220          *     message UID but let's assume that can be NULL too. */
221
222         g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), FALSE);
223
224         if (folder != NULL)
225                 g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
226
227         if (job->matches == NULL)
228                 return FALSE;
229
230         return job->matches (job, folder, uid);
231 }
232
233 gpointer
234 camel_imapx_job_get_data (CamelIMAPXJob *job)
235 {
236         CamelIMAPXRealJob *real_job;
237
238         g_return_val_if_fail (CAMEL_IS_IMAPX_JOB (job), NULL);
239
240         real_job = (CamelIMAPXRealJob *) job;
241
242         return real_job->data;
243 }
244
245 void
246 camel_imapx_job_set_data (CamelIMAPXJob *job,
247                           gpointer data,
248                           GDestroyNotify destroy_data)
249 {
250         CamelIMAPXRealJob *real_job;
251
252         g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
253
254         real_job = (CamelIMAPXRealJob *) job;
255
256         if (real_job->destroy_data != NULL)
257                 real_job->destroy_data (real_job->data);
258
259         real_job->data = data;
260         real_job->destroy_data = destroy_data;
261 }
262