1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-pop3-folder.c : class for a pop3 folder */
6 * Dan Winship <danw@ximian.com>
7 * Michael Zucchi <notzed@ximian.com>
9 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
11 * This library is free software you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation.
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
31 #include <glib/gi18n-lib.h>
33 #include "camel-pop3-folder.h"
34 #include "camel-pop3-store.h"
35 #include "camel-pop3-settings.h"
37 #define d(x) if (camel_debug("pop3")) x;
39 typedef struct _CamelPOP3FolderInfo CamelPOP3FolderInfo;
41 struct _CamelPOP3FolderInfo {
45 guint32 index; /* index of request */
47 struct _CamelPOP3Command *cmd;
48 struct _CamelStream *stream;
51 G_DEFINE_TYPE (CamelPOP3Folder, camel_pop3_folder, CAMEL_TYPE_FOLDER)
54 cmd_uidl (CamelPOP3Engine *pe,
55 CamelPOP3Stream *stream,
56 GCancellable *cancellable,
65 CamelPOP3FolderInfo *fi;
66 CamelPOP3Folder *folder = data;
69 ret = camel_pop3_stream_line (stream, &line, &len, cancellable, error);
71 if (strlen ((gchar *) line) > 1024)
73 if (sscanf ((gchar *) line, "%u %s", &id, uid) == 2) {
74 fi = g_hash_table_lookup (folder->uids_id, GINT_TO_POINTER (id));
76 camel_operation_progress (NULL, (fi->index + 1) * 100 / folder->uids->len);
77 fi->uid = g_strdup (uid);
78 g_hash_table_insert (folder->uids_fi, fi->uid, fi);
80 g_warning ("ID %u (uid: %s) not in previous LIST output", id, uid);
87 /* create a uid from md5 of 'top' output */
89 cmd_builduid (CamelPOP3Engine *pe,
90 CamelPOP3Stream *stream,
91 GCancellable *cancellable,
96 CamelPOP3FolderInfo *fi = data;
97 struct _camel_header_raw *h;
102 length = g_checksum_type_get_length (G_CHECKSUM_MD5);
103 digest = g_alloca (length);
105 /* TODO; somehow work out the limit and use that for proper progress reporting
106 * We need a pointer to the folder perhaps? */
107 camel_operation_progress (NULL, fi->id);
109 checksum = g_checksum_new (G_CHECKSUM_MD5);
110 mp = camel_mime_parser_new ();
111 camel_mime_parser_init_with_stream (mp, (CamelStream *) stream, NULL);
112 switch (camel_mime_parser_step (mp, NULL, NULL)) {
113 case CAMEL_MIME_PARSER_STATE_HEADER:
114 case CAMEL_MIME_PARSER_STATE_MESSAGE:
115 case CAMEL_MIME_PARSER_STATE_MULTIPART:
116 h = camel_mime_parser_headers_raw (mp);
118 if (g_ascii_strcasecmp (h->name, "status") != 0
119 && g_ascii_strcasecmp (h->name, "x-status") != 0) {
120 g_checksum_update (checksum, (guchar *) h->name, -1);
121 g_checksum_update (checksum, (guchar *) h->value, -1);
129 g_checksum_get_digest (checksum, digest, &length);
130 g_checksum_free (checksum);
132 fi->uid = g_base64_encode ((guchar *) digest, length);
134 d (printf ("building uid for id '%d' = '%s'\n", fi->id, fi->uid));
138 cmd_list (CamelPOP3Engine *pe,
139 CamelPOP3Stream *stream,
140 GCancellable *cancellable,
147 CamelFolder *folder = data;
148 CamelPOP3FolderInfo *fi;
149 CamelPOP3Folder *pop3_folder;
151 g_return_if_fail (pe != NULL);
153 pop3_folder = (CamelPOP3Folder *) folder;
156 ret = camel_pop3_stream_line (stream, &line, &len, cancellable, error);
158 if (sscanf ((gchar *) line, "%u %u", &id, &size) == 2) {
159 fi = g_malloc0 (sizeof (*fi));
162 fi->index = ((CamelPOP3Folder *) folder)->uids->len;
163 if ((pe->capa & CAMEL_POP3_CAP_UIDL) == 0)
164 fi->cmd = camel_pop3_engine_command_new (
166 CAMEL_POP3_COMMAND_MULTI,
170 g_ptr_array_add (pop3_folder->uids, fi);
171 g_hash_table_insert (
172 pop3_folder->uids_id,
173 GINT_TO_POINTER (id), fi);
180 cmd_tocache (CamelPOP3Engine *pe,
181 CamelPOP3Stream *stream,
182 GCancellable *cancellable,
186 CamelPOP3FolderInfo *fi = data;
189 GError *local_error = NULL;
191 /* What if it fails? */
193 /* We write an '*' to the start of the stream to say its not complete yet */
194 /* This should probably be part of the cache code */
195 if ((n = camel_stream_write (fi->stream, "*", 1, cancellable, &local_error)) == -1)
198 while ((n = camel_stream_read ((CamelStream *) stream, buffer, sizeof (buffer), cancellable, &local_error)) > 0) {
199 n = camel_stream_write (fi->stream, buffer, n, cancellable, &local_error);
207 camel_operation_progress (NULL, (w * 100) / fi->size);
210 /* it all worked, output a '#' to say we're a-ok */
211 if (local_error == NULL) {
213 G_SEEKABLE (fi->stream),
214 0, G_SEEK_SET, cancellable, NULL);
215 camel_stream_write (fi->stream, "#", 1, cancellable, &local_error);
219 if (local_error != NULL) {
220 g_propagate_error (error, local_error);
223 g_object_unref (fi->stream);
228 pop3_folder_dispose (GObject *object)
230 CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (object);
231 CamelPOP3Store *pop3_store = NULL;
232 CamelStore *parent_store;
234 parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (object));
236 pop3_store = CAMEL_POP3_STORE (parent_store);
238 if (pop3_folder->uids) {
240 CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **) pop3_folder->uids->pdata;
241 gboolean is_online = camel_service_get_connection_status (CAMEL_SERVICE (parent_store)) == CAMEL_SERVICE_CONNECTED;
243 for (i = 0; i < pop3_folder->uids->len; i++, fi++) {
244 if (fi[0]->cmd && pop3_store && is_online) {
245 CamelPOP3Engine *pop3_engine;
247 pop3_engine = camel_pop3_store_ref_engine (pop3_store);
249 while (camel_pop3_engine_iterate (pop3_engine, fi[0]->cmd, NULL, NULL) > 0)
251 camel_pop3_engine_command_free (pop3_engine, fi[0]->cmd);
253 g_clear_object (&pop3_engine);
260 g_ptr_array_free (pop3_folder->uids, TRUE);
261 pop3_folder->uids = NULL;
264 if (pop3_folder->uids_fi) {
265 g_hash_table_destroy (pop3_folder->uids_fi);
266 pop3_folder->uids_fi = NULL;
269 /* Chain up to parent's dispose() method. */
270 G_OBJECT_CLASS (camel_pop3_folder_parent_class)->dispose (object);
274 pop3_folder_get_message_count (CamelFolder *folder)
276 CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
278 return pop3_folder->uids->len;
282 pop3_folder_get_uids (CamelFolder *folder)
284 CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
285 GPtrArray *uids = g_ptr_array_new ();
286 CamelPOP3FolderInfo **fi = (CamelPOP3FolderInfo **) pop3_folder->uids->pdata;
289 for (i = 0; i < pop3_folder->uids->len; i++,fi++) {
291 g_ptr_array_add (uids, fi[0]->uid);
298 pop3_get_uncached_uids (CamelFolder *folder,
302 CamelPOP3Folder *pop3_folder;
303 CamelPOP3Store *pop3_store;
304 GPtrArray *uncached_uids;
307 g_return_val_if_fail (CAMEL_IS_POP3_FOLDER (folder), NULL);
308 g_return_val_if_fail (uids != NULL, NULL);
310 pop3_folder = CAMEL_POP3_FOLDER (folder);
311 pop3_store = CAMEL_POP3_STORE (camel_folder_get_parent_store (folder));
313 uncached_uids = g_ptr_array_new ();
315 for (ii = 0; ii < uids->len; ii++) {
316 const gchar *uid = uids->pdata[ii];
317 CamelPOP3FolderInfo *fi;
318 gboolean uid_is_cached = FALSE;
320 fi = g_hash_table_lookup (pop3_folder->uids_fi, uid);
323 uid_is_cached = camel_pop3_store_cache_has (
324 pop3_store, fi->uid);
327 if (!uid_is_cached) {
329 uncached_uids, (gpointer)
330 camel_pstring_strdup (uid));
334 return uncached_uids;
338 pop3_folder_get_filename (CamelFolder *folder,
342 CamelStore *parent_store;
343 CamelPOP3Folder *pop3_folder;
344 CamelPOP3Store *pop3_store;
345 CamelDataCache *pop3_cache;
346 CamelPOP3FolderInfo *fi;
349 parent_store = camel_folder_get_parent_store (folder);
351 pop3_folder = CAMEL_POP3_FOLDER (folder);
352 pop3_store = CAMEL_POP3_STORE (parent_store);
354 fi = g_hash_table_lookup (pop3_folder->uids_fi, uid);
357 error, CAMEL_FOLDER_ERROR,
358 CAMEL_FOLDER_ERROR_INVALID_UID,
359 _("No message with UID %s"), uid);
363 pop3_cache = camel_pop3_store_ref_cache (pop3_store);
365 g_warn_if_reached ();
369 filename = camel_data_cache_get_filename (
370 pop3_cache, "cache", fi->uid);
371 g_clear_object (&pop3_cache);
377 pop3_folder_set_message_flags (CamelFolder *folder,
379 CamelMessageFlags flags,
380 CamelMessageFlags set)
382 CamelPOP3Folder *pop3_folder = CAMEL_POP3_FOLDER (folder);
383 CamelPOP3FolderInfo *fi;
384 gboolean res = FALSE;
386 fi = g_hash_table_lookup (pop3_folder->uids_fi, uid);
388 guint32 new = (fi->flags & ~flags) | (set & flags);
390 if (fi->flags != new) {
399 static CamelMimeMessage *
400 pop3_folder_get_message_sync (CamelFolder *folder,
402 GCancellable *cancellable,
405 CamelStore *parent_store;
406 CamelMimeMessage *message = NULL;
407 CamelPOP3Store *pop3_store;
408 CamelPOP3Folder *pop3_folder;
409 CamelPOP3Engine *pop3_engine;
410 CamelPOP3Command *pcr;
411 CamelPOP3FolderInfo *fi;
414 CamelStream *stream = NULL;
415 CamelService *service;
416 CamelSettings *settings;
419 g_return_val_if_fail (uid != NULL, NULL);
421 parent_store = camel_folder_get_parent_store (folder);
423 pop3_folder = CAMEL_POP3_FOLDER (folder);
424 pop3_store = CAMEL_POP3_STORE (parent_store);
426 service = CAMEL_SERVICE (parent_store);
428 settings = camel_service_ref_settings (service);
432 "auto-fetch", &auto_fetch,
435 g_object_unref (settings);
437 fi = g_hash_table_lookup (pop3_folder->uids_fi, uid);
440 error, CAMEL_FOLDER_ERROR,
441 CAMEL_FOLDER_ERROR_INVALID_UID,
442 _("No message with UID %s"), uid);
446 if (camel_service_get_connection_status (CAMEL_SERVICE (parent_store)) != CAMEL_SERVICE_CONNECTED) {
448 error, CAMEL_SERVICE_ERROR,
449 CAMEL_SERVICE_ERROR_UNAVAILABLE,
450 _("You must be working online to complete this operation"));
454 /* Sigh, most of the crap in this function is so that the cancel button
455 * returns the proper exception code. Sigh. */
457 camel_operation_push_message (
458 cancellable, _("Retrieving POP message %d"), fi->id);
460 pop3_engine = camel_pop3_store_ref_engine (pop3_store);
462 /* If we have an oustanding retrieve message running, wait for that to complete
463 * & then retrieve from cache, otherwise, start a new one, and similar */
465 if (fi->cmd != NULL) {
466 while ((i = camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, error)) > 0)
469 /* getting error code? */
470 /*g_assert (fi->cmd->state == CAMEL_POP3_COMMAND_DATA);*/
471 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
476 error, _("Cannot get message %s: "), uid);
481 /* check to see if we have safely written flag set */
482 if (!camel_pop3_store_cache_has (pop3_store, fi->uid)) {
483 /* Initiate retrieval, if disk backing fails, use a memory backing */
484 stream = camel_pop3_store_cache_add (pop3_store, fi->uid, NULL);
486 stream = camel_stream_mem_new ();
488 /* ref it, the cache storage routine unref's when done */
489 fi->stream = g_object_ref (stream);
490 pcr = camel_pop3_engine_command_new (
492 CAMEL_POP3_COMMAND_MULTI,
495 "RETR %u\r\n", fi->id);
497 /* Also initiate retrieval of some of the following
498 * messages, assume we'll be receiving them. */
500 /* This should keep track of the last one retrieved,
501 * also how many are still oustanding incase of random
502 * access on large folders. */
504 last = MIN (i + 10, pop3_folder->uids->len);
505 for (; i < last; i++) {
506 CamelPOP3FolderInfo *pfi = pop3_folder->uids->pdata[i];
508 if (pfi->uid && pfi->cmd == NULL) {
509 pfi->stream = camel_pop3_store_cache_add (
510 pop3_store, pfi->uid, NULL);
511 if (pfi->stream != NULL) {
512 pfi->cmd = camel_pop3_engine_command_new (
514 CAMEL_POP3_COMMAND_MULTI,
517 "RETR %u\r\n", pfi->id);
523 /* now wait for the first one to finish */
524 while ((i = camel_pop3_engine_iterate (pop3_engine, pcr, cancellable, error)) > 0)
527 /* getting error code? */
528 /*g_assert (pcr->state == CAMEL_POP3_COMMAND_DATA);*/
529 camel_pop3_engine_command_free (pop3_engine, pcr);
531 G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
533 /* Check to see we have safely written flag set */
536 error, _("Cannot get message %s: "), uid);
540 if (camel_stream_read (stream, buffer, 1, cancellable, error) == -1)
543 if (buffer[0] != '#') {
545 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
546 _("Cannot get message %s: %s"), uid,
547 _("Unknown reason"));
552 message = camel_mime_message_new ();
553 if (stream != NULL && !camel_data_wrapper_construct_from_stream_sync (
554 CAMEL_DATA_WRAPPER (message), stream, cancellable, error)) {
555 g_prefix_error (error, _("Cannot get message %s: "), uid);
556 g_object_unref (message);
559 /* because the UID in the local store doesn't match with the UID in the pop3 store */
560 camel_medium_add_header (CAMEL_MEDIUM (message), "X-Evolution-POP3-UID", uid);
563 g_clear_object (&stream);
565 g_clear_object (&pop3_engine);
567 camel_operation_pop_message (cancellable);
573 pop3_folder_refresh_info_sync (CamelFolder *folder,
574 GCancellable *cancellable,
577 CamelStore *parent_store;
578 CamelPOP3Store *pop3_store;
579 CamelPOP3Folder *pop3_folder = (CamelPOP3Folder *) folder;
580 CamelPOP3Engine *pop3_engine;
581 CamelPOP3Command *pcl, *pcu = NULL;
582 gboolean success = TRUE;
583 GError *local_error = NULL;
586 parent_store = camel_folder_get_parent_store (folder);
587 pop3_store = CAMEL_POP3_STORE (parent_store);
589 if (camel_service_get_connection_status (CAMEL_SERVICE (parent_store)) != CAMEL_SERVICE_CONNECTED) {
591 error, CAMEL_SERVICE_ERROR,
592 CAMEL_SERVICE_ERROR_UNAVAILABLE,
593 _("You must be working online to complete this operation"));
597 camel_operation_push_message (
598 cancellable, _("Retrieving POP summary"));
600 pop3_engine = camel_pop3_store_ref_engine (pop3_store);
602 /* Get rid of the old cache */
603 if (pop3_folder->uids) {
605 CamelPOP3FolderInfo *last_fi;
607 if (pop3_folder->uids->len) {
608 last_fi = pop3_folder->uids->pdata[pop3_folder->uids->len - 1];
610 pop3_folder->latest_id = last_fi->id;
612 pop3_folder->latest_id = -1;
614 pop3_folder->latest_id = -1;
616 for (i = 0; i < pop3_folder->uids->len; i++) {
617 CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
619 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
626 g_ptr_array_free (pop3_folder->uids, TRUE);
629 if (pop3_folder->uids_fi) {
630 g_hash_table_destroy (pop3_folder->uids_fi);
631 pop3_folder->uids_fi = NULL;
634 /* Get a new working set. */
635 pop3_folder->uids = g_ptr_array_new ();
636 pop3_folder->uids_fi = g_hash_table_new (g_str_hash, g_str_equal);
638 /* only used during setup */
639 pop3_folder->uids_id = g_hash_table_new (NULL, NULL);
641 pcl = camel_pop3_engine_command_new (
643 CAMEL_POP3_COMMAND_MULTI,
645 cancellable, &local_error,
647 if (!local_error && pop3_engine && (pop3_engine->capa & CAMEL_POP3_CAP_UIDL) != 0)
648 pcu = camel_pop3_engine_command_new (
650 CAMEL_POP3_COMMAND_MULTI,
652 cancellable, &local_error,
654 while ((i = camel_pop3_engine_iterate (pop3_engine, NULL, cancellable, &local_error)) > 0)
658 g_propagate_error (error, local_error);
659 g_prefix_error (error, _("Cannot get POP summary: "));
661 } else if (i == -1) {
662 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
666 /* TODO: check every id has a uid & commands returned OK too? */
669 if (success && pcl->state == CAMEL_POP3_COMMAND_ERR) {
673 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, pcl->error_str);
675 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
678 camel_pop3_engine_command_free (pop3_engine, pcl);
682 if (success && pcu->state == CAMEL_POP3_COMMAND_ERR) {
686 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, pcu->error_str);
688 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
691 camel_pop3_engine_command_free (pop3_engine, pcu);
693 for (i = 0; i < pop3_folder->uids->len; i++) {
694 CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
696 if (success && fi->cmd->state == CAMEL_POP3_COMMAND_ERR) {
699 if (fi->cmd->error_str)
700 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, fi->cmd->error_str);
702 g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
705 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
709 g_hash_table_insert (pop3_folder->uids_fi, fi->uid, fi);
714 /* dont need this anymore */
715 g_hash_table_destroy (pop3_folder->uids_id);
716 pop3_folder->uids_id = NULL;
718 g_clear_object (&pop3_engine);
720 camel_operation_pop_message (cancellable);
726 pop3_folder_synchronize_sync (CamelFolder *folder,
728 GCancellable *cancellable,
731 CamelService *service;
732 CamelSettings *settings;
733 CamelStore *parent_store;
734 CamelPOP3Folder *pop3_folder;
735 CamelPOP3Store *pop3_store;
736 CamelDataCache *pop3_cache;
737 CamelPOP3Engine *pop3_engine;
738 CamelPOP3FolderInfo *fi;
739 gint delete_after_days;
740 gboolean delete_expunged;
741 gboolean keep_on_server;
745 parent_store = camel_folder_get_parent_store (folder);
747 pop3_folder = CAMEL_POP3_FOLDER (folder);
748 pop3_store = CAMEL_POP3_STORE (parent_store);
750 service = CAMEL_SERVICE (parent_store);
751 is_online = camel_service_get_connection_status (service) == CAMEL_SERVICE_CONNECTED;
753 settings = camel_service_ref_settings (service);
757 "delete-after-days", &delete_after_days,
758 "delete-expunged", &delete_expunged,
759 "keep-on-server", &keep_on_server,
762 g_object_unref (settings);
764 if (is_online && delete_after_days > 0 && !expunge && !g_cancellable_is_cancelled (cancellable)) {
765 camel_operation_push_message (
766 cancellable, _("Expunging old messages"));
768 camel_pop3_folder_delete_old (
769 folder, delete_after_days, cancellable, error);
771 camel_operation_pop_message (cancellable);
774 if (g_cancellable_is_cancelled (cancellable)) {
775 if (error && !*error) {
776 /* coverity[unchecked_value] */
777 g_cancellable_set_error_if_cancelled (cancellable, error);
782 if (!expunge || (keep_on_server && !delete_expunged))
787 error, CAMEL_SERVICE_ERROR,
788 CAMEL_SERVICE_ERROR_UNAVAILABLE,
789 _("You must be working online to complete this operation"));
793 camel_operation_push_message (
794 cancellable, _("Expunging deleted messages"));
796 pop3_cache = camel_pop3_store_ref_cache (pop3_store);
797 pop3_engine = camel_pop3_store_ref_engine (pop3_store);
799 for (i = 0; i < pop3_folder->uids->len; i++) {
800 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
801 g_clear_object (&pop3_cache);
802 g_clear_object (&pop3_engine);
804 camel_operation_pop_message (cancellable);
809 fi = pop3_folder->uids->pdata[i];
810 /* busy already? wait for that to finish first */
812 while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
814 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
818 if (fi->flags & CAMEL_MESSAGE_DELETED) {
819 fi->cmd = camel_pop3_engine_command_new (
823 "DELE %u\r\n", fi->id);
825 /* also remove from cache */
826 if (pop3_cache != NULL && fi->uid)
827 camel_data_cache_remove (pop3_cache, "cache", fi->uid, NULL);
831 for (i = 0; i < pop3_folder->uids->len; i++) {
832 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
833 g_clear_object (&pop3_cache);
834 g_clear_object (&pop3_engine);
836 camel_operation_pop_message (cancellable);
841 fi = pop3_folder->uids->pdata[i];
842 /* wait for delete commands to finish */
844 while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
846 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
849 camel_operation_progress (
850 cancellable, (i + 1) * 100 / pop3_folder->uids->len);
853 g_clear_object (&pop3_cache);
854 g_clear_object (&pop3_engine);
856 camel_operation_pop_message (cancellable);
858 return camel_pop3_store_expunge (pop3_store, cancellable, error);
862 camel_pop3_folder_class_init (CamelPOP3FolderClass *class)
864 GObjectClass *object_class;
865 CamelFolderClass *folder_class;
867 object_class = G_OBJECT_CLASS (class);
868 object_class->dispose = pop3_folder_dispose;
870 folder_class = CAMEL_FOLDER_CLASS (class);
871 folder_class->get_message_count = pop3_folder_get_message_count;
872 folder_class->get_uids = pop3_folder_get_uids;
873 folder_class->free_uids = camel_folder_free_shallow;
874 folder_class->get_uncached_uids = pop3_get_uncached_uids;
875 folder_class->get_filename = pop3_folder_get_filename;
876 folder_class->set_message_flags = pop3_folder_set_message_flags;
877 folder_class->get_message_sync = pop3_folder_get_message_sync;
878 folder_class->refresh_info_sync = pop3_folder_refresh_info_sync;
879 folder_class->synchronize_sync = pop3_folder_synchronize_sync;
883 camel_pop3_folder_init (CamelPOP3Folder *pop3_folder)
885 pop3_folder->uids = g_ptr_array_new ();
886 pop3_folder->uids_fi = g_hash_table_new (g_str_hash, g_str_equal);
890 camel_pop3_folder_new (CamelStore *parent,
891 GCancellable *cancellable,
895 CamelPOP3Folder *pop3_folder;
897 d (printf ("opening pop3 INBOX folder\n"));
899 folder = g_object_new (
900 CAMEL_TYPE_POP3_FOLDER,
901 "full-name", "inbox", "display-name", "inbox",
902 "parent-store", parent, NULL);
904 pop3_folder = (CamelPOP3Folder *) folder;
906 pop3_folder->fetch_more = 0;
907 if (camel_service_get_connection_status (CAMEL_SERVICE (parent)) != CAMEL_SERVICE_CONNECTED)
910 /* mt-ok, since we dont have the folder-lock for new() */
911 if (!camel_folder_refresh_info_sync (folder, cancellable, error)) {
912 g_object_unref (folder);
920 pop3_get_message_time_from_cache (CamelFolder *folder,
922 time_t *message_time)
924 CamelStore *parent_store;
925 CamelPOP3Store *pop3_store;
926 CamelStream *stream = NULL;
927 gboolean res = FALSE;
929 g_return_val_if_fail (folder != NULL, FALSE);
930 g_return_val_if_fail (uid != NULL, FALSE);
931 g_return_val_if_fail (message_time != NULL, FALSE);
933 parent_store = camel_folder_get_parent_store (folder);
934 pop3_store = CAMEL_POP3_STORE (parent_store);
936 stream = camel_pop3_store_cache_get (pop3_store, uid, NULL);
937 if (stream != NULL) {
938 CamelMimeMessage *message;
939 GError *error = NULL;
941 message = camel_mime_message_new ();
942 camel_data_wrapper_construct_from_stream_sync (
943 (CamelDataWrapper *) message, stream, NULL, &error);
945 g_warning (_("Cannot get message %s: %s"), uid, error->message);
946 g_error_free (error);
948 g_object_unref (message);
954 *message_time = message->date + message->date_offset;
956 g_object_unref (message);
959 g_object_unref (stream);
966 camel_pop3_folder_delete_old (CamelFolder *folder,
968 GCancellable *cancellable,
971 CamelStore *parent_store;
972 CamelPOP3Folder *pop3_folder;
973 CamelPOP3FolderInfo *fi;
974 CamelPOP3Engine *pop3_engine;
975 CamelPOP3Store *pop3_store;
976 CamelDataCache *pop3_cache;
977 CamelMimeMessage *message;
978 time_t temp, message_time;
981 parent_store = camel_folder_get_parent_store (folder);
983 if (camel_service_get_connection_status (CAMEL_SERVICE (parent_store)) != CAMEL_SERVICE_CONNECTED) {
985 error, CAMEL_SERVICE_ERROR,
986 CAMEL_SERVICE_ERROR_UNAVAILABLE,
987 _("You must be working online to complete this operation"));
991 if (g_cancellable_set_error_if_cancelled (cancellable, error))
994 pop3_folder = CAMEL_POP3_FOLDER (folder);
995 pop3_store = CAMEL_POP3_STORE (parent_store);
996 pop3_cache = camel_pop3_store_ref_cache (pop3_store);
997 pop3_engine = camel_pop3_store_ref_engine (pop3_store);
1001 d (printf ("%s(%d): pop3_folder->uids->len=[%d]\n", __FILE__, __LINE__, pop3_folder->uids->len));
1002 for (i = 0; i < pop3_folder->uids->len; i++) {
1004 fi = pop3_folder->uids->pdata[i];
1006 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
1007 g_clear_object (&pop3_cache);
1008 g_clear_object (&pop3_engine);
1014 while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0) {
1015 ; /* do nothing - iterating until end */
1018 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
1022 /* continue, if message wasn't received yet */
1026 d (printf ("%s(%d): fi->uid=[%s]\n", __FILE__, __LINE__, fi->uid));
1027 if (!pop3_get_message_time_from_cache (folder, fi->uid, &message_time)) {
1028 d (printf ("could not get message time from cache, trying from pop3\n"));
1029 message = pop3_folder_get_message_sync (
1030 folder, fi->uid, cancellable, error);
1032 message_time = message->date + message->date_offset;
1033 g_object_unref (message);
1038 gdouble time_diff = difftime (temp,message_time);
1039 gint day_lag = time_diff / (60 * 60 * 24);
1042 "%s(%d): message_time= [%" G_GINT64_FORMAT "]\n",
1043 __FILE__, __LINE__, (gint64) message_time));
1045 "%s(%d): day_lag=[%d] \t days_to_delete=[%d]\n",
1046 __FILE__, __LINE__, day_lag, days_to_delete));
1048 if (day_lag > days_to_delete) {
1049 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
1050 g_clear_object (&pop3_cache);
1051 g_clear_object (&pop3_engine);
1057 while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0) {
1058 ; /* do nothing - iterating until end */
1061 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
1065 "%s(%d): Deleting old messages\n",
1066 __FILE__, __LINE__));
1067 fi->cmd = camel_pop3_engine_command_new (
1071 "DELE %u\r\n", fi->id);
1072 /* also remove from cache */
1073 if (pop3_cache != NULL && fi->uid) {
1074 camel_data_cache_remove (pop3_cache, "cache", fi->uid, NULL);
1080 for (i = 0; i < pop3_folder->uids->len; i++) {
1081 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
1082 g_clear_object (&pop3_cache);
1083 g_clear_object (&pop3_engine);
1088 fi = pop3_folder->uids->pdata[i];
1089 /* wait for delete commands to finish */
1091 while (camel_pop3_engine_iterate (pop3_engine, fi->cmd, cancellable, NULL) > 0)
1093 camel_pop3_engine_command_free (pop3_engine, fi->cmd);
1096 camel_operation_progress (
1097 cancellable, (i + 1) * 100 / pop3_folder->uids->len);
1100 g_clear_object (&pop3_cache);
1101 g_clear_object (&pop3_engine);
1103 return camel_pop3_store_expunge (pop3_store, cancellable, error);