1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
/* camel-pop3-store.c : class for a pop3 store */
6
* Dan Winship <danw@ximian.com>
7
* Michael Zucchi <notzed@ximian.com>
8
* Philip Van Hoof <pvanhoof@gnome.org>
10
* This is CamelPop3Store for camel-lite that implements CamelDiscoStore. Its
11
* implementation is significantly different from Camel's upstream version
12
* (being used by Evolution): this version supports offline and online modes.
14
* Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com)
16
* This program is free software; you can redistribute it and/or
17
* modify it under the terms of version 2 of the GNU Lesser General Public
18
* License as published by the Free Software Foundation.
20
* This program is distributed in the hope that it will be useful,
21
* but WITHOUT ANY WARRANTY; without even the implied warranty of
22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
* GNU Lesser General Public License for more details.
25
* You should have received a copy of the GNU Lesser General Public License
26
* along with this program; if not, write to the Free Software
27
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
35
#include <sys/types.h>
51
#include <glib/gstdio.h>
53
#include <sys/types.h>
55
#include "camel-file-utils.h"
57
#include "camel-data-cache.h"
58
#include "camel-exception.h"
59
#include "camel-net-utils.h"
60
#include "camel-operation.h"
61
#include "camel-pop3-engine.h"
62
#include "camel-pop3-folder.h"
63
#include "camel-pop3-store.h"
64
#include "camel-sasl.h"
65
#include "camel-session.h"
66
#include "camel-stream-buffer.h"
67
#include "camel-tcp-stream-raw.h"
68
#include "camel-tcp-stream.h"
69
#include "camel-url.h"
70
#include "camel/camel-string-utils.h"
73
#include "camel-tcp-stream-ssl.h"
75
#include "camel-disco-diary.h"
77
#include <libedataserver/md5-utils.h>
79
/* Specified in RFC 1939 */
80
#define POP3_PORT "110"
81
#define POP3S_PORT "995"
85
static CamelStoreClass *parent_class = NULL;
87
static void finalize (CamelObject *object);
89
static gboolean pop3_connect (CamelService *service, CamelException *ex);
90
static gboolean pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex);
91
static GList *query_auth_types (CamelService *service, CamelException *ex);
93
static CamelFolder *get_folder (CamelStore *store, const char *folder_name,
94
guint32 flags, CamelException *ex);
96
static CamelFolder *get_trash (CamelStore *store, CamelException *ex);
98
static void pop3_get_folder_status (CamelStore *store, const char *folder_name, int *unseen, int *messages, int *uidnext);
103
pop3_delete_cache (CamelStore *store)
105
CamelPOP3Store *pop3_store = (CamelPOP3Store *) store;
106
gchar *folder_dir = pop3_store->storage_path;
107
camel_rm (folder_dir);
112
pop3_can_work_offline (CamelDiscoStore *disco_store)
118
pop3_connect_offline (CamelService *service, CamelException *ex)
120
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
121
store->connected = !camel_exception_is_set (ex);
122
return store->connected ;
126
unref_it (gpointer user_data)
129
camel_object_unref (user_data);
134
pop3_connect_online (CamelService *service, CamelException *ex)
136
return pop3_connect (service, ex);
141
pop3_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex)
147
pop3_disconnect_online (CamelService *service, gboolean clean, CamelException *ex)
150
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
152
g_static_rec_mutex_lock (store->eng_lock);
154
if (store->engine == NULL) {
155
g_static_rec_mutex_lock (store->eng_lock);
160
CamelPOP3Command *pc;
162
pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
163
while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
165
camel_pop3_engine_command_free(store->engine, pc);
168
g_timeout_add (20000, unref_it, store->engine);
169
store->engine = NULL;
170
g_static_rec_mutex_unlock (store->eng_lock);
172
/* camel_object_unref((CamelObject *)store->engine); */
178
pop3_get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
180
return get_folder (store, folder_name, flags, ex);
184
static CamelFolderInfo *
185
pop3_build_folder_info (CamelPOP3Store *store, const char *folder_name)
190
gchar *folder_dir = store->storage_path;
194
fi = camel_folder_info_new ();
196
fi->flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_TYPE_INBOX|CAMEL_FOLDER_SUBSCRIBED;
198
fi->full_name = g_strdup(folder_name);
202
camel_du (folder_dir, &msize);
204
spath = g_strdup_printf ("%s/summary.mmap", folder_dir);
205
f = fopen (spath, "r");
208
gint tsize = ((sizeof (guint32) * 5) + sizeof (time_t));
209
char *buffer = malloc (tsize), *ptr;
211
a = fread (buffer, 1, tsize, f);
215
version = g_ntohl(get_unaligned_u32(ptr));
217
fi->total = g_ntohl(get_unaligned_u32(ptr));
219
if (version < 0x100 && version >= 13)
220
fi->unread = g_ntohl(get_unaligned_u32(ptr));
226
fi->local_size = (guint) msize;
228
fi->uri = g_strdup ("");
229
name = strrchr (fi->full_name, '/');
231
name = fi->full_name;
234
if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
235
fi->name = g_strdup ((const gchar *) _("Inbox"));
237
fi->name = g_strdup (name);
243
pop3_get_folder_offline (CamelStore *store, const char *folder_name,
244
guint32 flags, CamelException *ex)
246
return get_folder (store, folder_name, flags, ex);
250
static CamelFolderInfo *
251
pop3_get_folder_info_offline (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
253
return pop3_build_folder_info (CAMEL_POP3_STORE (store), "INBOX");
256
static CamelFolderInfo *
257
pop3_get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
259
CamelFolderInfo *info = pop3_get_folder_info_offline (store, top, flags, ex);
260
gint unseen = -1, messages = -1, uidnext = -1;
262
pop3_get_folder_status (store, "INBOX", &unseen, &messages, &uidnext);
265
info->total = messages;
278
#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3)
279
#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS)
283
connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, int must_tls, CamelException *ex)
285
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
286
CamelStream *tcp_stream;
287
CamelPOP3Command *pc;
289
int clean_quit = TRUE;
293
store->connected = FALSE;
295
if (ssl_mode != MODE_CLEAR)
299
if (ssl_mode == MODE_TLS)
300
tcp_stream = camel_tcp_stream_ssl_new_raw (service, service->url->host, STARTTLS_FLAGS);
302
tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host, SSL_PORT_FLAGS);
305
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
306
_("Could not connect to %s: %s"),
307
service->url->host, _("SSL unavailable"));
311
#endif /* HAVE_SSL */
313
tcp_stream = camel_tcp_stream_raw_new ();
315
if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1)
318
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
319
_("Connection canceled"));
321
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
322
_("Could not connect to %s: %s"),
326
camel_object_unref (tcp_stream);
331
/* parent class connect initialization */
332
/*if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
333
camel_object_unref (tcp_stream);
337
if (camel_url_get_param (service->url, "disable_extensions"))
338
flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
340
if ((delete_days = (gchar *) camel_url_get_param(service->url,"delete_after")))
341
store->delete_after = atoi(delete_days);
343
g_static_rec_mutex_lock (store->eng_lock); /* ! */
345
if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) {
346
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
347
_("Failed to read a valid greeting from POP server %s"),
349
camel_object_unref (tcp_stream);
351
g_static_rec_mutex_unlock (store->eng_lock); /* ! */
355
store->engine->store = store;
356
store->engine->partial_happening = FALSE;
358
#ifndef HAVE_SSL /* ! */
359
g_static_rec_mutex_unlock (store->eng_lock);
362
if (!must_tls && (ssl_mode != MODE_TLS))
364
camel_object_unref (tcp_stream);
365
store->connected = TRUE;
367
#ifdef HAVE_SSL /* ! */
368
g_static_rec_mutex_unlock (store->eng_lock);
376
if (!(store->engine->capa & CAMEL_POP3_CAP_STLS))
378
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
379
_("Failed to connect to POP server %s in secure mode: %s"),
380
service->url->host, _("STLS not supported by server"));
384
/* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */
387
pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "STLS\r\n");
388
while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
391
ret = pc->state == CAMEL_POP3_COMMAND_OK;
392
camel_pop3_engine_command_free (store->engine, pc);
396
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
397
_("Failed to connect to POP server %s in secure mode: %s"),
398
service->url->host, store->engine->line);
402
/* Okay, now toggle SSL/TLS mode */
403
ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
406
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
407
_("Failed to connect to POP server %s in secure mode: %s"),
408
service->url->host, _("TLS negotiations failed"));
413
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
414
_("Failed to connect to POP server %s in secure mode: %s"),
415
service->url->host, _("TLS is not available in this build"));
418
#endif /* HAVE_SSL */
420
camel_object_unref (tcp_stream);
422
/* rfc2595, section 4 states that after a successful STLS
423
command, the client MUST discard prior CAPA responses */
425
camel_pop3_engine_reget_capabilities (store->engine);
426
store->connected = TRUE;
428
g_static_rec_mutex_unlock (store->eng_lock); /* ! */
437
/* try to disconnect cleanly */
438
pc = camel_pop3_engine_command_new (store->engine, 0, NULL, NULL, "QUIT\r\n");
439
while (camel_pop3_engine_iterate (store->engine, NULL) > 0)
441
camel_pop3_engine_command_free (store->engine, pc);
444
camel_object_unref (CAMEL_OBJECT (store->engine));
445
camel_object_unref (CAMEL_OBJECT (tcp_stream));
446
store->engine = NULL;
447
store->connected = FALSE;
449
g_static_rec_mutex_unlock (store->eng_lock); /* ! */
461
{ "", "pop3s", POP3S_PORT, MODE_SSL, 0 }, /* really old (1.x) */
462
{ "wrapped", "pop3s", POP3S_PORT, MODE_SSL, 0 },
463
{ "tls", "pop3", POP3_PORT, MODE_TLS, 1 },
464
{ "when-possible", "pop3", POP3_PORT, MODE_TLS, 0 },
465
{ "never", "pop3", POP3_PORT, MODE_CLEAR, 0 },
466
{ NULL, "pop3", POP3_PORT, MODE_CLEAR, 0 },
470
connect_to_server_wrapper (CamelService *service, CamelException *ex)
472
struct addrinfo hints, *ai;
473
const char *ssl_mode;
474
int mode, ret, i, must_tls=0;
478
if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) {
479
for (i = 0; ssl_options[i].value; i++)
480
if (!strcmp (ssl_options[i].value, ssl_mode))
482
mode = ssl_options[i].mode;
483
serv = ssl_options[i].serv;
484
port = ssl_options[i].port;
485
must_tls = ssl_options[i].must_tls;
493
if (service->url->port) {
494
serv = g_alloca (16);
495
sprintf (serv, "%d", service->url->port);
499
memset (&hints, 0, sizeof (hints));
500
hints.ai_socktype = SOCK_STREAM;
501
hints.ai_family = PF_UNSPEC;
502
ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
503
if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) {
504
camel_exception_clear (ex);
505
ai = camel_getaddrinfo(service->url->host, port, &hints, ex);
511
ret = connect_to_server (service, ai, mode, must_tls, ex);
513
camel_freeaddrinfo (ai);
518
extern CamelServiceAuthType camel_pop3_password_authtype;
519
extern CamelServiceAuthType camel_pop3_apop_authtype;
522
query_auth_types (CamelService *service, CamelException *ex)
524
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
527
types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
528
if (camel_exception_is_set (ex))
531
if (connect_to_server_wrapper (service, NULL)) {
533
g_static_rec_mutex_lock (store->eng_lock);
535
if (store->engine == NULL) {
536
g_static_rec_mutex_unlock (store->eng_lock);
540
types = g_list_concat(types, g_list_copy(store->engine->auth));
541
g_static_rec_mutex_unlock (store->eng_lock);
543
pop3_disconnect (service, TRUE, NULL);
545
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
546
_("Could not connect to POP server %s"),
555
try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex)
557
CamelPOP3Stream *stream = store->engine->stream;
558
unsigned char *line, *resp;
563
sasl = camel_sasl_new("pop3", mech, (CamelService *)store);
565
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
566
_("Unable to connect to POP server %s: "
567
"No support for requested authentication mechanism."),
568
CAMEL_SERVICE (store)->url->host);
572
if (camel_stream_printf((CamelStream *)stream, "AUTH %s\r\n", mech) == -1)
576
if (camel_pop3_stream_line(stream, &line, &len) == -1)
578
if (strncmp((char *) line, "+OK", 3) == 0)
580
if (strncmp((char *) line, "-ERR", 4) == 0) {
581
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
582
_("SASL `%s' Login failed for POP server %s: %s"),
583
mech, CAMEL_SERVICE (store)->url->host, line);
586
/* If we dont get continuation, or the sasl object's run out of work, or we dont get a challenge,
587
its a protocol error, so fail, and try reset the server */
588
if (strncmp((char *) line, "+ ", 2) != 0
589
|| camel_sasl_authenticated(sasl)
590
|| (resp = (unsigned char *) camel_sasl_challenge_base64(sasl, (const char *) line+2, ex)) == NULL) {
591
camel_stream_printf((CamelStream *)stream, "*\r\n");
592
camel_pop3_stream_line(stream, &line, &len);
593
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
594
_("Cannot login to POP server %s: SASL Protocol error"),
595
CAMEL_SERVICE (store)->url->host);
599
ret = camel_stream_printf((CamelStream *)stream, "%s\r\n", resp);
605
camel_object_unref((CamelObject *)sasl);
609
if (errno == EINTR) {
610
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
612
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
613
_("Failed to authenticate on POP server %s: %s"),
614
CAMEL_SERVICE (store)->url->host, g_strerror (errno));
617
camel_object_unref((CamelObject *)sasl);
622
pop3_try_authenticate (CamelService *service, gboolean reprompt, const char *errmsg, CamelException *ex)
624
CamelPOP3Store *store = (CamelPOP3Store *)service;
625
CamelPOP3Command *pcu = NULL, *pcp = NULL;
628
/* override, testing only */
629
/*printf("Forcing authmech to 'login'\n");
630
service->url->authmech = g_strdup("LOGIN");*/
632
if (!service->url->passwd) {
634
guint32 flags = CAMEL_SESSION_PASSWORD_SECRET;
637
flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
639
prompt = g_strdup_printf (_("%sPlease enter the POP password for %s on host %s"),
640
errmsg ? errmsg : "",
643
service->url->passwd = camel_session_get_password (camel_service_get_session (service), service, NULL,
644
prompt, "password", flags, ex);
646
if (!service->url->passwd)
650
if (!service->url->authmech) {
652
g_static_rec_mutex_lock (store->eng_lock);
654
if (store->engine == NULL) {
655
g_static_rec_mutex_unlock (store->eng_lock);
659
/* pop engine will take care of pipelining ability */
660
pcu = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "USER %s\r\n", service->url->user);
661
pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "PASS %s\r\n", service->url->passwd);
663
g_static_rec_mutex_unlock (store->eng_lock);
665
} else if (strcmp(service->url->authmech, "+APOP") == 0 && store->engine->apop) {
666
char *secret, md5asc[33], *d;
667
unsigned char md5sum[16], *s;
669
d = store->engine->apop;
672
if (!isascii((int)*d)) {
674
/* README for Translators: The string APOP should not be translated */
675
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
676
_("Unable to connect to POP server %s: Invalid APOP ID received. Impersonation attack suspected. Please contact your admin."),
677
CAMEL_SERVICE (store)->url->host);
684
g_static_rec_mutex_lock (store->eng_lock);
686
if (store->engine == NULL) {
687
g_static_rec_mutex_unlock (store->eng_lock);
691
secret = g_alloca(strlen(store->engine->apop)+strlen(service->url->passwd)+1);
692
sprintf(secret, "%s%s", store->engine->apop, service->url->passwd);
693
md5_get_digest(secret, strlen (secret), md5sum);
695
for (s = md5sum, d = md5asc; d < md5asc + 32; s++, d += 2)
696
sprintf (d, "%.2x", *s);
698
pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "APOP %s %s\r\n",
699
service->url->user, md5asc);
701
g_static_rec_mutex_unlock (store->eng_lock);
704
CamelServiceAuthType *auth;
707
g_static_rec_mutex_lock (store->eng_lock);
709
if (store->engine == NULL) {
710
g_static_rec_mutex_unlock (store->eng_lock);
714
l = store->engine->auth;
717
if (strcmp(auth->authproto, service->url->authmech) == 0) {
718
g_static_rec_mutex_unlock (store->eng_lock);
719
return try_sasl(store, service->url->authmech, ex) == -1;
724
g_static_rec_mutex_unlock (store->eng_lock);
726
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_URL_INVALID,
727
_("Unable to connect to POP server %s: "
728
"No support for requested authentication mechanism."),
729
CAMEL_SERVICE (store)->url->host);
733
g_static_rec_mutex_lock (store->eng_lock);
735
if (store->engine == NULL) {
736
g_static_rec_mutex_unlock (store->eng_lock);
740
while ((status = camel_pop3_engine_iterate(store->engine, pcp)) > 0)
745
if (errno == EINTR) {
746
camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
748
camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
749
_("Unable to connect to POP server %s.\n"
750
"Error sending password: %s"),
751
CAMEL_SERVICE (store)->url->host,
752
errno ? g_strerror (errno) : _("Unknown error"));
754
} else if (pcu && pcu->state != CAMEL_POP3_COMMAND_OK) {
755
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
756
_("Unable to connect to POP server %s.\n"
757
"Error sending username: %s"),
758
CAMEL_SERVICE (store)->url->host,
759
store->engine->line ? (char *)store->engine->line : _("Unknown error"));
760
} else if (pcp->state != CAMEL_POP3_COMMAND_OK)
761
camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE,
762
_("Unable to connect to POP server %s.\n"
763
"Error sending password: %s"),
764
CAMEL_SERVICE (store)->url->host,
765
store->engine->line ? (char *)store->engine->line : _("Unknown error"));
767
camel_pop3_engine_command_free (store->engine, pcp);
770
camel_pop3_engine_command_free(store->engine, pcu);
772
g_static_rec_mutex_unlock (store->eng_lock);
778
pop3_connect (CamelService *service, CamelException *ex)
780
CamelPOP3Store *store = (CamelPOP3Store *)service;
781
gboolean reprompt = FALSE;
782
CamelSession *session;
786
session = camel_service_get_session (service);
788
if (!connect_to_server_wrapper (service, ex))
792
status = pop3_try_authenticate (service, reprompt, errbuf, ex);
796
/* we only re-prompt if we failed to authenticate, any other error and we just abort */
797
if (status == 0 && camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE) {
798
errbuf = g_strdup_printf ("%s\n\n", camel_exception_get_description (ex));
799
g_free (service->url->passwd);
800
service->url->passwd = NULL;
802
camel_exception_clear (ex);
803
sleep (5); /* For example Cyrus-POPd dislikes hammering */
810
if (status == -1 || camel_exception_is_set(ex)) {
811
camel_service_disconnect(service, TRUE, ex);
815
/* Now that we are in the TRANSACTION state, try regetting the capabilities */
817
g_static_rec_mutex_lock (store->eng_lock);
819
if (store->engine == NULL) {
820
g_static_rec_mutex_unlock (store->eng_lock);
824
store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
825
camel_pop3_engine_reget_capabilities (store->engine);
827
g_static_rec_mutex_unlock (store->eng_lock);
833
pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex)
835
CamelPOP3Store *store = CAMEL_POP3_STORE (service);
837
g_static_rec_mutex_lock (store->eng_lock);
838
if (store->engine == NULL) {
839
g_static_rec_mutex_unlock (store->eng_lock);
844
CamelPOP3Command *pc;
846
pc = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "QUIT\r\n");
847
while (camel_pop3_engine_iterate(store->engine, NULL) > 0)
849
camel_pop3_engine_command_free(store->engine, pc);
852
camel_object_unref((CamelObject *)store->engine);
853
store->engine = NULL;
854
g_static_rec_mutex_unlock (store->eng_lock);
860
get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
862
if (g_ascii_strcasecmp (folder_name, "inbox") != 0) {
863
camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
864
_("No such folder `%s'."), folder_name);
867
return camel_pop3_folder_new (store, ex);
871
get_trash (CamelStore *store, CamelException *ex)
879
finalize (CamelObject *object)
881
CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
883
g_static_rec_mutex_lock (pop3_store->eng_lock);
884
if (pop3_store->engine)
885
camel_object_unref((CamelObject *)pop3_store->engine);
886
pop3_store->engine = NULL;
887
g_static_rec_mutex_unlock (pop3_store->eng_lock);
889
if (pop3_store->cache)
890
camel_object_unref((CamelObject *)pop3_store->cache);
891
pop3_store->cache = NULL;
892
if (pop3_store->storage_path)
893
g_free (pop3_store->storage_path);
894
pop3_store->storage_path = NULL;
896
g_static_rec_mutex_free (pop3_store->eng_lock);
897
pop3_store->eng_lock = NULL;
898
camel_object_unref (pop3_store->book);
899
pop3_store->book = NULL;
908
cmd_stat (CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data)
910
unsigned char *line = (unsigned char *) stream; /* moeha, ugly! */
911
StatInfo *info = data;
916
sscanf((char *) line, "+OK %d %d", &info->items, &info->bytes);
922
pop3_get_folder_status (CamelStore *store, const char *folder_name, int *unseen, int *messages, int *uidnext)
924
CamelPOP3Store *pop3_store = (CamelPOP3Store *) store;
925
CamelPOP3Command *cmd = NULL;
926
StatInfo *info = NULL;
929
gchar *spath = g_strdup_printf ("%s/summary.mmap", pop3_store->storage_path);
930
guint32 mversion=-1; guint32 mflags=-1;
931
guint32 mnextuid=-1; time_t mtime=-1; guint32 msaved_count=-1;
932
guint32 munread_count=-1; guint32 mdeleted_count=-1;
933
guint32 mjunk_count=-1;
935
camel_file_util_read_counts_2 (spath, &mversion, &mflags, &mnextuid,
936
&mtime, &msaved_count, &munread_count, &mdeleted_count,
939
if (munread_count != -1)
940
*unseen = munread_count;
941
if (msaved_count != -1)
942
*messages = msaved_count;
948
if (camel_disco_store_status (CAMEL_DISCO_STORE (pop3_store)) == CAMEL_DISCO_STORE_OFFLINE)
951
g_static_rec_mutex_lock (pop3_store->eng_lock);
953
if (pop3_store->engine == NULL) {
954
g_static_rec_mutex_unlock (pop3_store->eng_lock);
958
camel_operation_start(NULL, _("Getting POP3 status"));
960
info = g_slice_new (StatInfo);
965
cmd = camel_pop3_engine_command_new(pop3_store->engine, 0,
966
cmd_stat, info, "STAT\r\n");
967
while ((i = camel_pop3_engine_iterate(pop3_store->engine, NULL)) > 0);
969
if (info->items != -1) {
970
*messages = info->items;
971
if (munread_count == -1) {
972
CamelFolderInfo *inf = pop3_build_folder_info (
973
CAMEL_POP3_STORE (store), "INBOX");
974
*unseen = inf->unread;
975
camel_folder_info_free (inf);
979
g_slice_free (StatInfo, info);
980
camel_pop3_engine_command_free (pop3_store->engine, cmd);
982
camel_operation_end(NULL);
983
g_static_rec_mutex_unlock (pop3_store->eng_lock);
988
pop3_construct (CamelService *service, CamelSession *session,
989
CamelProvider *provider, CamelURL *url,
992
CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (service);
993
CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
996
CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
997
if (camel_exception_is_set (ex))
1000
pop3_store->storage_path = camel_session_get_storage_path (session, service, ex);
1001
camel_pop3_logbook_set_rootpath (pop3_store->book, pop3_store->storage_path);
1003
if (!pop3_store->storage_path)
1006
pop3_store->cache = camel_data_cache_new(pop3_store->storage_path, 0, ex);
1007
if (pop3_store->cache) {
1008
/* Default cache expiry - 1 week or not visited in a day */
1009
camel_data_cache_set_expire_age (pop3_store->cache, 60*60*24*7);
1010
camel_data_cache_set_expire_access (pop3_store->cache, 60*60*24);
1013
pop3_store->base_url = camel_url_to_string (service->url, (CAMEL_URL_HIDE_PASSWORD |
1014
CAMEL_URL_HIDE_PARAMS |
1015
CAMEL_URL_HIDE_AUTH));
1018
path = g_strdup_printf ("%s/journal", pop3_store->storage_path);
1019
disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
1025
camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
1027
CamelServiceClass *camel_service_class =
1028
CAMEL_SERVICE_CLASS (camel_pop3_store_class);
1029
CamelStoreClass *camel_store_class =
1030
CAMEL_STORE_CLASS (camel_pop3_store_class);
1031
CamelDiscoStoreClass *camel_disco_store_class =
1032
CAMEL_DISCO_STORE_CLASS (camel_pop3_store_class);
1034
parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ()));
1036
/* virtual method overload */
1037
camel_service_class->construct = pop3_construct;
1038
camel_service_class->query_auth_types = query_auth_types;
1040
/* camel_service_class->connect = pop3_connect; */
1041
/* camel_service_class->disconnect = pop3_disconnect; */
1043
camel_store_class->get_folder = get_folder;
1044
camel_store_class->get_trash = get_trash;
1045
camel_store_class->get_folder_status = pop3_get_folder_status;
1046
camel_store_class->delete_cache = pop3_delete_cache;
1048
camel_disco_store_class->can_work_offline = pop3_can_work_offline;
1049
camel_disco_store_class->connect_online = pop3_connect_online;
1050
camel_disco_store_class->connect_offline = pop3_connect_offline;
1051
camel_disco_store_class->disconnect_online = pop3_disconnect_online;
1052
camel_disco_store_class->disconnect_offline = pop3_disconnect_offline;
1053
camel_disco_store_class->get_folder_online = pop3_get_folder_online;
1054
camel_disco_store_class->get_folder_offline = pop3_get_folder_offline;
1055
camel_disco_store_class->get_folder_resyncing = pop3_get_folder_online;
1056
camel_disco_store_class->get_folder_info_online = pop3_get_folder_info_online;
1057
camel_disco_store_class->get_folder_info_offline = pop3_get_folder_info_offline;
1058
camel_disco_store_class->get_folder_info_resyncing = pop3_get_folder_info_online;
1064
camel_pop3_store_init (gpointer object, gpointer klass)
1066
CamelPOP3Store *store = (CamelPOP3Store *) object;
1068
store->is_refreshing = FALSE;
1069
store->immediate_delete_after = FALSE;
1070
store->book = camel_pop3_logbook_new (store);
1071
store->eng_lock = g_new0 (GStaticRecMutex, 1);
1072
g_static_rec_mutex_init (store->eng_lock);
1078
camel_pop3_store_get_type (void)
1080
static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
1082
if (!camel_pop3_store_type) {
1083
camel_pop3_store_type = camel_type_register (CAMEL_DISCO_STORE_TYPE,
1085
sizeof (CamelPOP3Store),
1086
sizeof (CamelPOP3StoreClass),
1087
(CamelObjectClassInitFunc) camel_pop3_store_class_init,
1089
(CamelObjectInitFunc) camel_pop3_store_init,
1093
return camel_pop3_store_type;