Bug #606181 - Accepting bad SSL certificate applies to any hostname
[platform/upstream/evolution-data-server.git] / camel / providers / imapx / camel-imapx-command.c
1 /*
2  * camel-imapx-command.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-command.h"
20
21 #include <config.h>
22 #include <string.h>
23 #include <glib/gstdio.h>
24 #include <glib/gi18n-lib.h>
25
26 #include "camel-imapx-job.h"
27 #include "camel-imapx-server.h"
28 #include "camel-imapx-store.h"
29
30 #define c(...) camel_imapx_debug(command, __VA_ARGS__)
31
32 typedef struct _CamelIMAPXRealCommand CamelIMAPXRealCommand;
33
34 /* CamelIMAPXCommand + some private bits */
35 struct _CamelIMAPXRealCommand {
36         CamelIMAPXCommand public;
37
38         volatile gint ref_count;
39
40         CamelIMAPXJob *job;
41
42         /* For building the part. */
43         GString *buffer;
44
45         /* Used for running some commands synchronously. */
46         GCond *done_sync_cond;
47         GMutex *done_sync_mutex;
48         gboolean done_sync_flag;
49 };
50
51 /* Safe to cast to a GQueue. */
52 struct _CamelIMAPXCommandQueue {
53         GQueue g_queue;
54 };
55
56 CamelIMAPXCommand *
57 camel_imapx_command_new (CamelIMAPXServer *is,
58                          const gchar *name,
59                          CamelFolder *select,
60                          const gchar *format,
61                          ...)
62 {
63         CamelIMAPXRealCommand *real_ic;
64         static gint tag = 0;
65         va_list ap;
66
67         real_ic = g_slice_new0 (CamelIMAPXRealCommand);
68
69         /* Initialize private bits. */
70         real_ic->ref_count = 1;
71         real_ic->buffer = g_string_sized_new (512);
72         real_ic->done_sync_cond = g_cond_new ();
73         real_ic->done_sync_mutex = g_mutex_new ();
74
75         /* Initialize public bits. */
76         real_ic->public.is = is;
77         real_ic->public.tag = tag++;
78         real_ic->public.name = name;
79         real_ic->public.select = select;
80         g_queue_init (&real_ic->public.parts);
81
82         if (format != NULL && *format != '\0') {
83                 va_start (ap, format);
84                 camel_imapx_command_addv (
85                         (CamelIMAPXCommand *) real_ic, format, ap);
86                 va_end (ap);
87         }
88
89         return (CamelIMAPXCommand *) real_ic;
90 }
91
92 CamelIMAPXCommand *
93 camel_imapx_command_ref (CamelIMAPXCommand *ic)
94 {
95         CamelIMAPXRealCommand *real_ic;
96
97         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
98
99         real_ic = (CamelIMAPXRealCommand *) ic;
100
101         g_atomic_int_inc (&real_ic->ref_count);
102
103         return ic;
104 }
105
106 void
107 camel_imapx_command_unref (CamelIMAPXCommand *ic)
108 {
109         CamelIMAPXRealCommand *real_ic;
110
111         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
112
113         real_ic = (CamelIMAPXRealCommand *) ic;
114
115         if (g_atomic_int_dec_and_test (&real_ic->ref_count)) {
116                 CamelIMAPXCommandPart *cp;
117
118                 /* Free the public stuff. */
119
120                 imapx_free_status (ic->status);
121
122                 while ((cp = g_queue_pop_head (&ic->parts)) != NULL) {
123                         g_free (cp->data);
124                         if (cp->ob) {
125                                 switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
126                                 case CAMEL_IMAPX_COMMAND_FILE:
127                                 case CAMEL_IMAPX_COMMAND_STRING:
128                                         g_free (cp->ob);
129                                         break;
130                                 default:
131                                         g_object_unref (cp->ob);
132                                 }
133                         }
134                         g_free (cp);
135                 }
136
137                 /* Free the private stuff. */
138
139                 if (real_ic->job != NULL)
140                         camel_imapx_job_unref (real_ic->job);
141
142                 g_string_free (real_ic->buffer, TRUE);
143
144                 g_cond_free (real_ic->done_sync_cond);
145                 g_mutex_free (real_ic->done_sync_mutex);
146
147                 /* Do NOT try to free the GError.  If set it should have been
148                  * propagated to the CamelIMAPXJob, so it's either NULL or the
149                  * CamelIMAPXJob owns it now. */
150
151                 /* Fill the memory with a bit pattern before releasing
152                  * it back to the slab allocator, so we can more easily
153                  * identify dangling CamelIMAPXCommand pointers. */
154                 memset (real_ic, 0xaa, sizeof (CamelIMAPXRealCommand));
155
156                 /* But leave the reference count set to zero, so
157                  * CAMEL_IS_IMAPX_COMMAND can identify it as bad. */
158                 real_ic->ref_count = 0;
159
160                 g_slice_free (CamelIMAPXRealCommand, real_ic);
161         }
162 }
163
164 gboolean
165 camel_imapx_command_check (CamelIMAPXCommand *ic)
166 {
167         CamelIMAPXRealCommand *real_ic;
168
169         real_ic = (CamelIMAPXRealCommand *) ic;
170
171         return (real_ic != NULL && real_ic->ref_count > 0);
172 }
173
174 gint
175 camel_imapx_command_compare (CamelIMAPXCommand *ic1,
176                              CamelIMAPXCommand *ic2)
177 {
178         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic1), 0);
179         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic2), 0);
180
181         if (ic1->pri == ic2->pri)
182                 return 0;
183
184         return (ic1->pri < ic2->pri) ? -1 : 1;
185 }
186
187 CamelIMAPXJob *
188 camel_imapx_command_get_job (CamelIMAPXCommand *ic)
189 {
190         CamelIMAPXRealCommand *real_ic;
191
192         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), NULL);
193
194         real_ic = (CamelIMAPXRealCommand *) ic;
195
196         return real_ic->job;
197 }
198
199 void
200 camel_imapx_command_set_job (CamelIMAPXCommand *ic,
201                              CamelIMAPXJob *job)
202 {
203         CamelIMAPXRealCommand *real_ic;
204
205         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
206
207         real_ic = (CamelIMAPXRealCommand *) ic;
208
209         if (job != NULL) {
210                 g_return_if_fail (CAMEL_IS_IMAPX_JOB (job));
211                 camel_imapx_job_ref (job);
212         }
213
214         if (real_ic->job != NULL)
215                 camel_imapx_job_unref (real_ic->job);
216
217         real_ic->job = job;
218 }
219
220 void
221 camel_imapx_command_add (CamelIMAPXCommand *ic,
222                          const gchar *format,
223                          ...)
224 {
225         va_list ap;
226
227         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
228
229         if (format != NULL && *format != '\0') {
230                 va_start (ap, format);
231                 camel_imapx_command_addv (ic, format, ap);
232                 va_end (ap);
233         }
234 }
235
236 void
237 camel_imapx_command_addv (CamelIMAPXCommand *ic,
238                           const gchar *format,
239                           va_list ap)
240 {
241         const gchar *p, *ps, *start;
242         guchar c;
243         guint width;
244         gchar ch;
245         gint llong;
246         gchar *s;
247         gchar *P;
248         gint d;
249         glong l;
250         guint32 f;
251         CamelFlag *F;
252         CamelStream *S;
253         CamelDataWrapper *D;
254         CamelSasl *A;
255         gchar literal_format[16];
256         CamelFolder *folder;
257         CamelStore *parent_store;
258         GString *buffer;
259         gchar *fname = NULL, *encoded = NULL;
260         const gchar *full_name;
261
262         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
263
264         c(ic->is->tagprefix, "adding command, format = '%s'\n", format);
265
266         buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
267
268         p = format;
269         ps = format;
270         while ((c = *p++) != '\0') {
271                 switch (c) {
272                 case '%':
273                         if (*p == '%') {
274                                 g_string_append_len (buffer, ps, p - ps);
275                                 p++;
276                                 ps = p;
277                                 continue;
278                         }
279
280                         g_string_append_len (buffer, ps, p - ps - 1);
281                         start = p - 1;
282                         width = 0;
283                         llong = 0;
284
285                         do {
286                                 c = *p++;
287                                 if (c == '0')
288                                         ;
289                                 else if ( c== '-')
290                                         ;
291                                 else
292                                         break;
293                         } while (c);
294
295                         do {
296                                 if (g_ascii_isdigit (c))
297                                         width = width * 10 + (c - '0');
298                                 else
299                                         break;
300                         } while ((c = *p++));
301
302                         while (c == 'l') {
303                                 llong++;
304                                 c = *p++;
305                         }
306
307                         switch (c) {
308                         case 'A': /* auth object - sasl auth, treat as special kind of continuation */
309                                 A = va_arg (ap, CamelSasl *);
310                                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_AUTH, A);
311                                 break;
312                         case 'S': /* stream */
313                                 S = va_arg (ap, CamelStream *);
314                                 c(ic->is->tagprefix, "got stream '%p'\n", S);
315                                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STREAM, S);
316                                 break;
317                         case 'D': /* datawrapper */
318                                 D = va_arg (ap, CamelDataWrapper *);
319                                 c(ic->is->tagprefix, "got data wrapper '%p'\n", D);
320                                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_DATAWRAPPER, D);
321                                 break;
322                         case 'P': /* filename path */
323                                 P = va_arg (ap, gchar *);
324                                 c(ic->is->tagprefix, "got file path '%s'\n", P);
325                                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_FILE, P);
326                                 break;
327                         case 't': /* token */
328                                 s = va_arg (ap, gchar *);
329                                 g_string_append (buffer, s);
330                                 break;
331                         case 's': /* simple string */
332                                 s = va_arg (ap, gchar *);
333                                 c(ic->is->tagprefix, "got string '%s'\n", g_str_has_prefix (format, "LOGIN") ? "***" : s);
334                         output_string:
335                                 if (s && *s) {
336                                         guchar mask = imapx_is_mask (s);
337
338                                         if (mask & IMAPX_TYPE_ATOM_CHAR)
339                                                 g_string_append (buffer, s);
340                                         else if (mask & IMAPX_TYPE_TEXT_CHAR) {
341                                                 g_string_append_c (buffer, '"');
342                                                 while (*s) {
343                                                         gchar *start = s;
344
345                                                         while (*s && imapx_is_quoted_char (*s))
346                                                                 s++;
347                                                         g_string_append_len (buffer, start, s - start);
348                                                         if (*s) {
349                                                                 g_string_append_c (buffer, '\\');
350                                                                 g_string_append_c (buffer, *s);
351                                                                 s++;
352                                                         }
353                                                 }
354                                                 g_string_append_c (buffer, '"');
355                                         } else {
356                                                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_STRING, s);
357                                         }
358                                 } else {
359                                         g_string_append (buffer, "\"\"");
360                                 }
361                                 if (encoded) {
362                                         g_free (encoded);
363                                         encoded = NULL;
364                                 }
365                                 break;
366                         case 'f': /* imap folder name */
367                                 folder = va_arg (ap, CamelFolder *);
368                                 full_name = camel_folder_get_full_name (folder);
369                                 c(ic->is->tagprefix, "got folder '%s'\n", full_name);
370                                 parent_store = camel_folder_get_parent_store (folder);
371                                 fname = camel_imapx_store_summary_full_from_path (((CamelIMAPXStore *) parent_store)->summary, full_name);
372                                 if (fname) {
373                                         encoded = camel_utf8_utf7 (fname);
374                                         g_free (fname);
375                                 } else
376                                         encoded = camel_utf8_utf7 (full_name);
377
378                                 if (encoded) {
379                                         s = encoded;
380                                         goto output_string;
381                                 } else
382                                         g_string_append (buffer, "\"\"");
383
384                                 break;
385                         case 'F': /* IMAP flags set */
386                                 f = va_arg (ap, guint32);
387                                 F = va_arg (ap, CamelFlag *);
388                                 imapx_write_flags (buffer, f, F);
389                                 break;
390                         case 'c':
391                                 d = va_arg (ap, gint);
392                                 ch = d;
393                                 g_string_append_c (buffer, ch);
394                                 break;
395                         case 'd': /* int/unsigned */
396                         case 'u':
397                                 if (llong == 1) {
398                                         l = va_arg (ap, glong);
399                                         c(ic->is->tagprefix, "got glong '%d'\n", (gint)l);
400                                         memcpy (literal_format, start, p - start);
401                                         literal_format[p - start] = 0;
402                                         g_string_append_printf (buffer, literal_format, l);
403                                 } else if (llong == 2) {
404                                         guint64 i64 = va_arg (ap, guint64);
405                                         c(ic->is->tagprefix, "got guint64 '%d'\n", (gint)i64);
406                                         memcpy (literal_format, start, p - start);
407                                         literal_format[p - start] = 0;
408                                         g_string_append_printf (buffer, literal_format, i64);
409                                 } else {
410                                         d = va_arg (ap, gint);
411                                         c(ic->is->tagprefix, "got gint '%d'\n", d);
412                                         memcpy (literal_format, start, p - start);
413                                         literal_format[p - start] = 0;
414                                         g_string_append_printf (buffer, literal_format, d);
415                                 }
416                                 break;
417                         }
418
419                         ps = p;
420                         break;
421
422                 case '\\':      /* only for \\ really, we dont support \n\r etc at all */
423                         c = *p;
424                         if (c) {
425                                 g_assert (c == '\\');
426                                 g_string_append_len (buffer, ps, p - ps);
427                                 p++;
428                                 ps = p;
429                         }
430                 }
431         }
432
433         g_string_append_len (buffer, ps, p - ps - 1);
434 }
435
436 void
437 camel_imapx_command_add_part (CamelIMAPXCommand *ic,
438                               CamelIMAPXCommandPartType type,
439                               gpointer data)
440 {
441         CamelIMAPXCommandPart *cp;
442         CamelStreamNull *null;
443         GString *buffer;
444         guint ob_size = 0;
445
446         buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
447
448         /* TODO: literal+? */
449
450         switch (type & CAMEL_IMAPX_COMMAND_MASK) {
451         case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
452         case CAMEL_IMAPX_COMMAND_STREAM: {
453                 CamelObject *ob = data;
454
455                 /* TODO: seekable streams we could just seek to the end and back */
456                 null = (CamelStreamNull *) camel_stream_null_new ();
457                 if ( (type & CAMEL_IMAPX_COMMAND_MASK) == CAMEL_IMAPX_COMMAND_DATAWRAPPER) {
458                         camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) ob, (CamelStream *) null, NULL, NULL);
459                 } else {
460                         g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
461                         camel_stream_write_to_stream ((CamelStream *) ob, (CamelStream *) null, NULL, NULL);
462                         g_seekable_seek (G_SEEKABLE (ob), 0, G_SEEK_SET, NULL, NULL);
463                 }
464                 type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
465                 g_object_ref (ob);
466                 ob_size = null->written;
467                 g_object_unref (null);
468                 break;
469         }
470         case CAMEL_IMAPX_COMMAND_AUTH: {
471                 CamelObject *ob = data;
472                 const gchar *mechanism;
473
474                 /* we presume we'll need to get additional data only if we're not authenticated yet */
475                 g_object_ref (ob);
476                 mechanism = camel_sasl_get_mechanism (CAMEL_SASL (ob));
477                 g_string_append (buffer, mechanism);
478                 if (!camel_sasl_get_authenticated ((CamelSasl *) ob))
479                         type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
480                 break;
481         }
482         case CAMEL_IMAPX_COMMAND_FILE: {
483                 gchar *path = data;
484                 struct stat st;
485
486                 if (g_stat (path, &st) == 0) {
487                         data = g_strdup (data);
488                         ob_size = st.st_size;
489                 } else
490                         data = NULL;
491
492                 type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
493                 break;
494         }
495         case CAMEL_IMAPX_COMMAND_STRING:
496                 data = g_strdup (data);
497                 ob_size = strlen (data);
498                 type |= CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
499                 break;
500         default:
501                 ob_size = 0;
502         }
503
504         if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
505                 g_string_append_c (buffer, '{');
506                 g_string_append_printf (buffer, "%u", ob_size);
507                 if (ic->is->cinfo && ic->is->cinfo->capa & IMAPX_CAPABILITY_LITERALPLUS) {
508                         g_string_append_c (buffer, '+');
509                 } else {
510                         type &= ~CAMEL_IMAPX_COMMAND_LITERAL_PLUS;
511                         type |= CAMEL_IMAPX_COMMAND_CONTINUATION;
512                 }
513                 g_string_append_c (buffer, '}');
514         }
515
516         cp = g_malloc0 (sizeof (*cp));
517         cp->type = type;
518         cp->ob_size = ob_size;
519         cp->ob = data;
520         cp->data_size = buffer->len;
521         cp->data = g_strdup (buffer->str);
522
523         g_string_set_size (buffer, 0);
524
525         g_queue_push_tail (&ic->parts, cp);
526 }
527
528 void
529 camel_imapx_command_close (CamelIMAPXCommand *ic)
530 {
531         GString *buffer;
532
533         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
534
535         buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
536
537         if (buffer->len > 5 && g_ascii_strncasecmp (buffer->str, "LOGIN", 5) == 0) {
538                 c(ic->is->tagprefix, "completing command buffer is [%d] 'LOGIN...'\n", (gint) buffer->len);
539         } else {
540                 c(ic->is->tagprefix, "completing command buffer is [%d] '%.*s'\n", (gint) buffer->len, (gint) buffer->len, buffer->str);
541         }
542         if (buffer->len > 0)
543                 camel_imapx_command_add_part (ic, CAMEL_IMAPX_COMMAND_SIMPLE, NULL);
544
545         g_string_set_size (buffer, 0);
546 }
547
548 void
549 camel_imapx_command_wait (CamelIMAPXCommand *ic)
550 {
551         CamelIMAPXRealCommand *real_ic;
552
553         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
554
555         real_ic = (CamelIMAPXRealCommand *) ic;
556
557         g_mutex_lock (real_ic->done_sync_mutex);
558         while (!real_ic->done_sync_flag)
559                 g_cond_wait (
560                         real_ic->done_sync_cond,
561                         real_ic->done_sync_mutex);
562         g_mutex_unlock (real_ic->done_sync_mutex);
563 }
564
565 void
566 camel_imapx_command_done (CamelIMAPXCommand *ic)
567 {
568         CamelIMAPXRealCommand *real_ic;
569
570         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
571
572         real_ic = (CamelIMAPXRealCommand *) ic;
573
574         g_mutex_lock (real_ic->done_sync_mutex);
575         real_ic->done_sync_flag = TRUE;
576         g_cond_broadcast (real_ic->done_sync_cond);
577         g_mutex_unlock (real_ic->done_sync_mutex);
578 }
579
580 gboolean
581 camel_imapx_command_set_error_if_failed (CamelIMAPXCommand *ic,
582                                          GError **error)
583 {
584         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
585
586         if (ic->status != NULL && ic->status->result != IMAPX_OK) {
587                 if (ic->status->text != NULL)
588                         g_set_error (
589                                 error, CAMEL_IMAPX_ERROR, 1,
590                                 "%s", ic->status->text);
591                 else
592                         g_set_error (
593                                 error, CAMEL_IMAPX_ERROR, 1,
594                                 "%s", _("Unknown error"));
595                 return TRUE;
596         }
597
598         return FALSE;
599 }
600
601 CamelIMAPXCommandQueue *
602 camel_imapx_command_queue_new (void)
603 {
604         /* An initialized GQueue is simply zero-filled,
605          * so we can skip calling g_queue_init() here. */
606         return g_slice_new0 (CamelIMAPXCommandQueue);
607 }
608
609 void
610 camel_imapx_command_queue_free (CamelIMAPXCommandQueue *queue)
611 {
612         CamelIMAPXCommand *ic;
613
614         g_return_if_fail (queue != NULL);
615
616         while ((ic = g_queue_pop_head ((GQueue *) queue)) != NULL)
617                 camel_imapx_command_unref (ic);
618
619         g_slice_free (CamelIMAPXCommandQueue, queue);
620 }
621
622 void
623 camel_imapx_command_queue_transfer (CamelIMAPXCommandQueue *from,
624                                     CamelIMAPXCommandQueue *to)
625 {
626         GList *link;
627
628         g_return_if_fail (from != NULL);
629         g_return_if_fail (to != NULL);
630
631         while ((link = g_queue_pop_head_link ((GQueue *) from)) != NULL)
632                 g_queue_push_tail_link ((GQueue *) to, link);
633 }
634
635 void
636 camel_imapx_command_queue_push_tail (CamelIMAPXCommandQueue *queue,
637                                      CamelIMAPXCommand *ic)
638 {
639         g_return_if_fail (queue != NULL);
640         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
641
642         camel_imapx_command_ref (ic);
643
644         g_queue_push_tail ((GQueue *) queue, ic);
645 }
646
647 void
648 camel_imapx_command_queue_insert_sorted (CamelIMAPXCommandQueue *queue,
649                                          CamelIMAPXCommand *ic)
650 {
651         g_return_if_fail (queue != NULL);
652         g_return_if_fail (CAMEL_IS_IMAPX_COMMAND (ic));
653
654         camel_imapx_command_ref (ic);
655
656         g_queue_insert_sorted (
657                 (GQueue *) queue, ic, (GCompareDataFunc)
658                 camel_imapx_command_compare, NULL);
659 }
660
661 gboolean
662 camel_imapx_command_queue_is_empty (CamelIMAPXCommandQueue *queue)
663 {
664         g_return_val_if_fail (queue != NULL, TRUE);
665
666         return g_queue_is_empty ((GQueue *) queue);
667 }
668
669 guint
670 camel_imapx_command_queue_get_length (CamelIMAPXCommandQueue *queue)
671 {
672         g_return_val_if_fail (queue != NULL, 0);
673
674         return g_queue_get_length ((GQueue *) queue);
675 }
676
677 CamelIMAPXCommand *
678 camel_imapx_command_queue_peek_head (CamelIMAPXCommandQueue *queue)
679 {
680         g_return_val_if_fail (queue != NULL, NULL);
681
682         return g_queue_peek_head ((GQueue *) queue);
683 }
684
685 GList *
686 camel_imapx_command_queue_peek_head_link (CamelIMAPXCommandQueue *queue)
687 {
688         g_return_val_if_fail (queue != NULL, NULL);
689
690         return g_queue_peek_head_link ((GQueue *) queue);
691 }
692
693 gboolean
694 camel_imapx_command_queue_remove (CamelIMAPXCommandQueue *queue,
695                                   CamelIMAPXCommand *ic)
696 {
697         g_return_val_if_fail (queue != NULL, FALSE);
698         g_return_val_if_fail (CAMEL_IS_IMAPX_COMMAND (ic), FALSE);
699
700         if (g_queue_remove ((GQueue *) queue, ic)) {
701                 camel_imapx_command_unref (ic);
702                 return TRUE;
703         }
704
705         return FALSE;
706 }
707
708 void
709 camel_imapx_command_queue_delete_link (CamelIMAPXCommandQueue *queue,
710                                        GList *link)
711 {
712         g_return_if_fail (queue != NULL);
713         g_return_if_fail (link != NULL);
714
715         /* Verify the link is actually in the queue. */
716         if (g_queue_link_index ((GQueue *) queue, link) == -1) {
717                 g_warning ("%s: Link not found in queue", G_STRFUNC);
718                 return;
719         }
720
721         camel_imapx_command_unref ((CamelIMAPXCommand *) link->data);
722         g_queue_delete_link ((GQueue *) queue, link);
723 }
724