~ubuntu-branches/ubuntu/karmic/libtinymail/karmic

« back to all changes in this revision

Viewing changes to libtinymail-camel/camel-lite/camel/providers/pop3/camel-pop3-store.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-10-12 11:21:12 UTC
  • Revision ID: james.westby@ubuntu.com-20071012112112-fod9fs7yrooxjr7i
Tags: upstream-0.0.2
ImportĀ upstreamĀ versionĀ 0.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/* camel-pop3-store.c : class for a pop3 store */
 
3
 
 
4
/* 
 
5
 * Authors:
 
6
 *   Dan Winship <danw@ximian.com>
 
7
 *   Michael Zucchi <notzed@ximian.com>
 
8
 *   Philip Van Hoof <pvanhoof@gnome.org>
 
9
 *
 
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.
 
13
 * 
 
14
 * Copyright (C) 2000-2002 Ximian, Inc. (www.ximian.com)
 
15
 *
 
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.
 
19
 *
 
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.
 
24
 *
 
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
 
28
 * USA
 
29
 */
 
30
 
 
31
#ifdef HAVE_CONFIG_H
 
32
#include <config.h>
 
33
#endif
 
34
 
 
35
#include <sys/types.h>
 
36
#include <ctype.h>
 
37
#include <errno.h>
 
38
#include <stdio.h>
 
39
#include <stdlib.h>
 
40
#include <string.h>
 
41
#include <unistd.h>
 
42
#include <dirent.h>
 
43
 
 
44
#include <stdio.h>
 
45
#include <stdlib.h>
 
46
#include <string.h>
 
47
#include <unistd.h>
 
48
#include <errno.h>
 
49
 
 
50
#include <glib.h>
 
51
#include <glib/gstdio.h>
 
52
#include <stdio.h>
 
53
#include <sys/types.h>
 
54
 
 
55
#include "camel-file-utils.h"
 
56
 
 
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"
 
71
 
 
72
#ifdef HAVE_SSL
 
73
#include "camel-tcp-stream-ssl.h"
 
74
#endif
 
75
#include "camel-disco-diary.h"
 
76
 
 
77
#include <libedataserver/md5-utils.h>
 
78
 
 
79
/* Specified in RFC 1939 */
 
80
#define POP3_PORT "110"
 
81
#define POP3S_PORT "995"
 
82
 
 
83
#define _(o) o
 
84
 
 
85
static CamelStoreClass *parent_class = NULL;
 
86
 
 
87
static void finalize (CamelObject *object);
 
88
 
 
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);
 
92
 
 
93
static CamelFolder *get_folder (CamelStore *store, const char *folder_name, 
 
94
                                guint32 flags, CamelException *ex);
 
95
 
 
96
static CamelFolder *get_trash  (CamelStore *store, CamelException *ex);
 
97
 
 
98
static void pop3_get_folder_status (CamelStore *store, const char *folder_name, int *unseen, int *messages, int *uidnext);
 
99
 
 
100
 
 
101
 
 
102
static void 
 
103
pop3_delete_cache  (CamelStore *store)
 
104
{
 
105
        CamelPOP3Store *pop3_store = (CamelPOP3Store *) store;
 
106
        gchar *folder_dir = pop3_store->storage_path;
 
107
        camel_rm (folder_dir);
 
108
}
 
109
 
 
110
 
 
111
static gboolean
 
112
pop3_can_work_offline (CamelDiscoStore *disco_store)
 
113
{
 
114
        return TRUE;
 
115
}
 
116
 
 
117
static gboolean
 
118
pop3_connect_offline (CamelService *service, CamelException *ex)
 
119
{
 
120
        CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 
121
        store->connected = !camel_exception_is_set (ex);
 
122
        return store->connected ;
 
123
}
 
124
 
 
125
static gboolean
 
126
unref_it (gpointer user_data)
 
127
{
 
128
        if (user_data)
 
129
                camel_object_unref (user_data);
 
130
        return FALSE;
 
131
}
 
132
 
 
133
static gboolean
 
134
pop3_connect_online (CamelService *service, CamelException *ex)
 
135
{
 
136
        return pop3_connect (service, ex);
 
137
}
 
138
 
 
139
 
 
140
static gboolean
 
141
pop3_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex)
 
142
{
 
143
        return TRUE;
 
144
}
 
145
 
 
146
static gboolean
 
147
pop3_disconnect_online (CamelService *service, gboolean clean, CamelException *ex)
 
148
{
 
149
 
 
150
        CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 
151
 
 
152
        g_static_rec_mutex_lock (store->eng_lock);
 
153
 
 
154
        if (store->engine == NULL) {
 
155
                g_static_rec_mutex_lock (store->eng_lock);
 
156
                return TRUE;
 
157
        }
 
158
 
 
159
        if (clean) {
 
160
                CamelPOP3Command *pc;
 
161
                
 
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)
 
164
                        ;
 
165
                camel_pop3_engine_command_free(store->engine, pc);
 
166
        }
 
167
 
 
168
        g_timeout_add (20000, unref_it, store->engine);
 
169
        store->engine = NULL;
 
170
        g_static_rec_mutex_unlock (store->eng_lock);
 
171
 
 
172
        /* camel_object_unref((CamelObject *)store->engine); */
 
173
 
 
174
        return TRUE;
 
175
}
 
176
 
 
177
static CamelFolder *
 
178
pop3_get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
 
179
{
 
180
        return get_folder (store, folder_name, flags, ex);
 
181
}
 
182
 
 
183
 
 
184
static CamelFolderInfo *
 
185
pop3_build_folder_info (CamelPOP3Store *store, const char *folder_name)
 
186
{
 
187
        const char *name;
 
188
        CamelFolderInfo *fi;
 
189
        gint msize = 0;
 
190
        gchar *folder_dir = store->storage_path;
 
191
        gchar *spath;
 
192
        FILE *f;
 
193
 
 
194
        fi = camel_folder_info_new ();
 
195
 
 
196
        fi->flags |= CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_TYPE_INBOX|CAMEL_FOLDER_SUBSCRIBED;
 
197
 
 
198
        fi->full_name = g_strdup(folder_name);
 
199
        fi->unread = 0;
 
200
        fi->total = 0;
 
201
 
 
202
        camel_du (folder_dir, &msize);
 
203
 
 
204
        spath = g_strdup_printf ("%s/summary.mmap", folder_dir);
 
205
        f = fopen (spath, "r");
 
206
        g_free (spath);
 
207
        if (f) {
 
208
                gint tsize = ((sizeof (guint32) * 5) + sizeof (time_t));
 
209
                char *buffer = malloc (tsize), *ptr;
 
210
                guint32 version, a;
 
211
                a = fread (buffer, 1, tsize, f);
 
212
                if (a == tsize) 
 
213
                {
 
214
                        ptr = buffer;
 
215
                        version = g_ntohl(get_unaligned_u32(ptr));
 
216
                        ptr += 16;
 
217
                        fi->total = g_ntohl(get_unaligned_u32(ptr));
 
218
                        ptr += 4;
 
219
                        if (version < 0x100 && version >= 13)
 
220
                                fi->unread = g_ntohl(get_unaligned_u32(ptr));
 
221
                }
 
222
                g_free (buffer);
 
223
                fclose (f);
 
224
        } 
 
225
 
 
226
        fi->local_size = (guint) msize;
 
227
 
 
228
        fi->uri = g_strdup ("");
 
229
        name = strrchr (fi->full_name, '/');
 
230
        if (name == NULL)
 
231
                name = fi->full_name;
 
232
        else
 
233
                name++;
 
234
        if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
 
235
                fi->name = g_strdup ((const gchar *) _("Inbox"));
 
236
        else
 
237
                fi->name = g_strdup (name);
 
238
 
 
239
        return fi;
 
240
}
 
241
 
 
242
static CamelFolder *
 
243
pop3_get_folder_offline (CamelStore *store, const char *folder_name,
 
244
                    guint32 flags, CamelException *ex)
 
245
{
 
246
        return get_folder (store, folder_name, flags, ex);
 
247
}
 
248
 
 
249
 
 
250
static CamelFolderInfo *
 
251
pop3_get_folder_info_offline (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
 
252
{
 
253
        return pop3_build_folder_info (CAMEL_POP3_STORE (store), "INBOX");
 
254
}
 
255
 
 
256
static CamelFolderInfo *
 
257
pop3_get_folder_info_online (CamelStore *store, const char *top, guint32 flags, CamelException *ex)
 
258
{
 
259
        CamelFolderInfo *info =  pop3_get_folder_info_offline (store, top, flags, ex);
 
260
        gint unseen = -1, messages = -1, uidnext = -1;
 
261
 
 
262
        pop3_get_folder_status (store, "INBOX", &unseen, &messages, &uidnext);
 
263
 
 
264
        if (messages != -1)
 
265
                info->total = messages;
 
266
 
 
267
        return info;
 
268
}
 
269
 
 
270
 
 
271
enum {
 
272
        MODE_CLEAR,
 
273
        MODE_SSL,
 
274
        MODE_TLS,
 
275
};
 
276
 
 
277
#ifdef HAVE_SSL
 
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)
 
280
#endif
 
281
 
 
282
static gboolean
 
283
connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, int must_tls, CamelException *ex)
 
284
{
 
285
        CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 
286
        CamelStream *tcp_stream;
 
287
        CamelPOP3Command *pc;
 
288
        guint32 flags = 0;
 
289
        int clean_quit = TRUE;
 
290
        int ret;
 
291
        gchar *delete_days;
 
292
 
 
293
        store->connected = FALSE;
 
294
 
 
295
        if (ssl_mode != MODE_CLEAR) 
 
296
        {
 
297
 
 
298
#ifdef HAVE_SSL
 
299
                if (ssl_mode == MODE_TLS)
 
300
                        tcp_stream = camel_tcp_stream_ssl_new_raw (service, service->url->host, STARTTLS_FLAGS);
 
301
                else 
 
302
                        tcp_stream = camel_tcp_stream_ssl_new (service, service->url->host, SSL_PORT_FLAGS);
 
303
#else
 
304
 
 
305
                camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 
306
                                _("Could not connect to %s: %s"),
 
307
                                service->url->host, _("SSL unavailable"));
 
308
 
 
309
                return FALSE;
 
310
 
 
311
#endif /* HAVE_SSL */
 
312
        } else 
 
313
                tcp_stream = camel_tcp_stream_raw_new ();
 
314
 
 
315
        if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) 
 
316
        {
 
317
                if (errno == EINTR)
 
318
                        camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
 
319
                                _("Connection canceled"));
 
320
                else
 
321
                        camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 
322
                                _("Could not connect to %s: %s"),
 
323
                                service->url->host,
 
324
                                g_strerror (errno));
 
325
                
 
326
                camel_object_unref (tcp_stream);
 
327
                
 
328
                return FALSE;
 
329
        }
 
330
 
 
331
        /* parent class connect initialization */
 
332
        /*if (CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex) == FALSE) {
 
333
                camel_object_unref (tcp_stream);
 
334
                return FALSE;
 
335
        }*/
 
336
 
 
337
        if (camel_url_get_param (service->url, "disable_extensions"))
 
338
                flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
 
339
 
 
340
        if ((delete_days = (gchar *) camel_url_get_param(service->url,"delete_after"))) 
 
341
                store->delete_after =  atoi(delete_days);
 
342
 
 
343
        g_static_rec_mutex_lock (store->eng_lock); /* ! */
 
344
 
 
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"),
 
348
                        service->url->host);
 
349
                camel_object_unref (tcp_stream);
 
350
 
 
351
                g_static_rec_mutex_unlock (store->eng_lock); /* ! */
 
352
 
 
353
                return FALSE;
 
354
        }
 
355
        store->engine->store = store;
 
356
        store->engine->partial_happening = FALSE;
 
357
 
 
358
#ifndef HAVE_SSL /* ! */
 
359
        g_static_rec_mutex_unlock (store->eng_lock);
 
360
#endif
 
361
 
 
362
        if (!must_tls && (ssl_mode != MODE_TLS)) 
 
363
        {
 
364
                camel_object_unref (tcp_stream);
 
365
                store->connected = TRUE;
 
366
 
 
367
#ifdef HAVE_SSL /* ! */
 
368
                g_static_rec_mutex_unlock (store->eng_lock);
 
369
#endif
 
370
 
 
371
                return TRUE;
 
372
        }
 
373
 
 
374
#ifdef HAVE_SSL
 
375
 
 
376
        if (!(store->engine->capa & CAMEL_POP3_CAP_STLS)) 
 
377
        {
 
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"));
 
381
                goto stls_exception;
 
382
        }
 
383
 
 
384
        /* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */
 
385
        clean_quit = FALSE;
 
386
 
 
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)
 
389
                ;
 
390
 
 
391
        ret = pc->state == CAMEL_POP3_COMMAND_OK;
 
392
        camel_pop3_engine_command_free (store->engine, pc);
 
393
 
 
394
        if (ret == FALSE) 
 
395
        {
 
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);
 
399
                goto stls_exception;
 
400
        }
 
401
 
 
402
        /* Okay, now toggle SSL/TLS mode */
 
403
        ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream));
 
404
 
 
405
        if (ret == -1) {
 
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"));
 
409
                goto stls_exception;
 
410
        }
 
411
 
 
412
#else
 
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"));
 
416
 
 
417
        goto stls_exception;
 
418
#endif /* HAVE_SSL */
 
419
 
 
420
        camel_object_unref (tcp_stream);
 
421
 
 
422
        /* rfc2595, section 4 states that after a successful STLS
 
423
           command, the client MUST discard prior CAPA responses */
 
424
 
 
425
        camel_pop3_engine_reget_capabilities (store->engine);
 
426
        store->connected = TRUE;
 
427
 
 
428
        g_static_rec_mutex_unlock (store->eng_lock); /* ! */
 
429
 
 
430
        return TRUE;
 
431
 
 
432
 stls_exception:
 
433
 
 
434
 
 
435
        if (clean_quit) 
 
436
        {
 
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)
 
440
                        ;
 
441
                camel_pop3_engine_command_free (store->engine, pc);
 
442
        }
 
443
 
 
444
        camel_object_unref (CAMEL_OBJECT (store->engine));
 
445
        camel_object_unref (CAMEL_OBJECT (tcp_stream));
 
446
        store->engine = NULL;
 
447
        store->connected = FALSE;
 
448
 
 
449
        g_static_rec_mutex_unlock (store->eng_lock); /* ! */
 
450
 
 
451
        return FALSE;
 
452
}
 
453
 
 
454
static struct {
 
455
        char *value;
 
456
        char *serv;
 
457
        char *port;
 
458
        int mode;
 
459
        int must_tls;
 
460
} ssl_options[] = {
 
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 },
 
467
};
 
468
 
 
469
static gboolean
 
470
connect_to_server_wrapper (CamelService *service, CamelException *ex)
 
471
{
 
472
        struct addrinfo hints, *ai;
 
473
        const char *ssl_mode;
 
474
        int mode, ret, i, must_tls=0;
 
475
        char *serv;
 
476
        const char *port;
 
477
 
 
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))
 
481
                                break;
 
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;
 
486
        } else {
 
487
                mode = MODE_CLEAR;
 
488
                serv = "pop3";
 
489
                port = POP3S_PORT;
 
490
                must_tls = 0;
 
491
        }
 
492
        
 
493
        if (service->url->port) {
 
494
                serv = g_alloca (16);
 
495
                sprintf (serv, "%d", service->url->port);
 
496
                port = NULL;
 
497
        }
 
498
        
 
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);
 
506
        }
 
507
        
 
508
        if (ai == NULL)
 
509
                return FALSE;
 
510
        
 
511
        ret = connect_to_server (service, ai, mode, must_tls, ex);
 
512
        
 
513
        camel_freeaddrinfo (ai);
 
514
        
 
515
        return ret;
 
516
}
 
517
 
 
518
extern CamelServiceAuthType camel_pop3_password_authtype;
 
519
extern CamelServiceAuthType camel_pop3_apop_authtype;
 
520
 
 
521
static GList *
 
522
query_auth_types (CamelService *service, CamelException *ex)
 
523
{
 
524
        CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 
525
        GList *types = NULL;
 
526
 
 
527
        types = CAMEL_SERVICE_CLASS (parent_class)->query_auth_types (service, ex);
 
528
        if (camel_exception_is_set (ex))
 
529
                return NULL;
 
530
 
 
531
        if (connect_to_server_wrapper (service, NULL)) {
 
532
 
 
533
                g_static_rec_mutex_lock (store->eng_lock);
 
534
 
 
535
                if (store->engine == NULL) {
 
536
                        g_static_rec_mutex_unlock (store->eng_lock);
 
537
                        return NULL;
 
538
                }
 
539
 
 
540
                types = g_list_concat(types, g_list_copy(store->engine->auth));
 
541
                g_static_rec_mutex_unlock (store->eng_lock);
 
542
 
 
543
                pop3_disconnect (service, TRUE, NULL);
 
544
        } else {
 
545
                camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
 
546
                                      _("Could not connect to POP server %s"),
 
547
                                      service->url->host);
 
548
        }
 
549
 
 
550
        return types;
 
551
}
 
552
 
 
553
 
 
554
static int
 
555
try_sasl(CamelPOP3Store *store, const char *mech, CamelException *ex)
 
556
{
 
557
        CamelPOP3Stream *stream = store->engine->stream;
 
558
        unsigned char *line, *resp;
 
559
        CamelSasl *sasl;
 
560
        unsigned int len;
 
561
        int ret;
 
562
 
 
563
        sasl = camel_sasl_new("pop3", mech, (CamelService *)store);
 
564
        if (sasl == NULL) {
 
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);
 
569
                return -1;
 
570
        }
 
571
 
 
572
        if (camel_stream_printf((CamelStream *)stream, "AUTH %s\r\n", mech) == -1)
 
573
                goto ioerror;
 
574
 
 
575
        while (1) {
 
576
                if (camel_pop3_stream_line(stream, &line, &len) == -1)
 
577
                        goto ioerror;
 
578
                if (strncmp((char *) line, "+OK", 3) == 0)
 
579
                        break;
 
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);
 
584
                        goto done;
 
585
                }
 
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);
 
596
                        goto done;
 
597
                }
 
598
 
 
599
                ret = camel_stream_printf((CamelStream *)stream, "%s\r\n", resp);
 
600
                g_free(resp);
 
601
                if (ret == -1)
 
602
                        goto ioerror;
 
603
 
 
604
        }
 
605
        camel_object_unref((CamelObject *)sasl);
 
606
        return 0;
 
607
        
 
608
 ioerror:
 
609
        if (errno == EINTR) {
 
610
                camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
 
611
        } else {
 
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));
 
615
        }
 
616
 done:
 
617
        camel_object_unref((CamelObject *)sasl);
 
618
        return -1;
 
619
}
 
620
 
 
621
static int
 
622
pop3_try_authenticate (CamelService *service, gboolean reprompt, const char *errmsg, CamelException *ex)
 
623
{
 
624
        CamelPOP3Store *store = (CamelPOP3Store *)service;
 
625
        CamelPOP3Command *pcu = NULL, *pcp = NULL;
 
626
        int status;
 
627
        
 
628
        /* override, testing only */
 
629
        /*printf("Forcing authmech to 'login'\n");
 
630
        service->url->authmech = g_strdup("LOGIN");*/
 
631
        
 
632
        if (!service->url->passwd) {
 
633
                char *prompt;
 
634
                guint32 flags = CAMEL_SESSION_PASSWORD_SECRET;
 
635
                
 
636
                if (reprompt)
 
637
                        flags |= CAMEL_SESSION_PASSWORD_REPROMPT;
 
638
                
 
639
                prompt = g_strdup_printf (_("%sPlease enter the POP password for %s on host %s"),
 
640
                                          errmsg ? errmsg : "",
 
641
                                          service->url->user,
 
642
                                          service->url->host);
 
643
                service->url->passwd = camel_session_get_password (camel_service_get_session (service), service, NULL,
 
644
                                                                   prompt, "password", flags, ex);
 
645
                g_free (prompt);
 
646
                if (!service->url->passwd)
 
647
                        return FALSE;
 
648
        }
 
649
 
 
650
        if (!service->url->authmech) {
 
651
 
 
652
                g_static_rec_mutex_lock (store->eng_lock);
 
653
 
 
654
                if (store->engine == NULL) {
 
655
                        g_static_rec_mutex_unlock (store->eng_lock);
 
656
                        return FALSE;
 
657
                }
 
658
 
 
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);
 
662
 
 
663
                g_static_rec_mutex_unlock (store->eng_lock);
 
664
 
 
665
        } else if (strcmp(service->url->authmech, "+APOP") == 0 && store->engine->apop) {
 
666
                char *secret, md5asc[33], *d;
 
667
                unsigned char md5sum[16], *s;
 
668
 
 
669
                d = store->engine->apop;
 
670
 
 
671
                while (*d != '\0') {
 
672
                        if (!isascii((int)*d)) {
 
673
 
 
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);
 
678
 
 
679
                                return FALSE;
 
680
                        }
 
681
                        d++;
 
682
                }
 
683
 
 
684
                g_static_rec_mutex_lock (store->eng_lock);
 
685
 
 
686
                if (store->engine == NULL) {
 
687
                        g_static_rec_mutex_unlock (store->eng_lock);
 
688
                        return FALSE;
 
689
                }
 
690
 
 
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);
 
694
 
 
695
                for (s = md5sum, d = md5asc; d < md5asc + 32; s++, d += 2)
 
696
                        sprintf (d, "%.2x", *s);
 
697
 
 
698
                pcp = camel_pop3_engine_command_new(store->engine, 0, NULL, NULL, "APOP %s %s\r\n",
 
699
                                                    service->url->user, md5asc);
 
700
 
 
701
                g_static_rec_mutex_unlock (store->eng_lock);
 
702
 
 
703
        } else {
 
704
                CamelServiceAuthType *auth;
 
705
                GList *l;
 
706
 
 
707
                g_static_rec_mutex_lock (store->eng_lock);
 
708
 
 
709
                if (store->engine == NULL) {
 
710
                        g_static_rec_mutex_unlock (store->eng_lock);
 
711
                        return FALSE;
 
712
                }
 
713
 
 
714
                l = store->engine->auth;
 
715
                while (l) {
 
716
                        auth = l->data;
 
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;
 
720
                        }
 
721
                        l = l->next;
 
722
                }
 
723
 
 
724
                g_static_rec_mutex_unlock (store->eng_lock);
 
725
 
 
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);
 
730
                return FALSE;
 
731
        }
 
732
 
 
733
        g_static_rec_mutex_lock (store->eng_lock);
 
734
 
 
735
        if (store->engine == NULL) {
 
736
                g_static_rec_mutex_unlock (store->eng_lock);
 
737
                return FALSE;
 
738
        }
 
739
 
 
740
        while ((status = camel_pop3_engine_iterate(store->engine, pcp)) > 0)
 
741
                ;
 
742
 
 
743
 
 
744
        if (status == -1) {
 
745
                if (errno == EINTR) {
 
746
                        camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, "Canceled");
 
747
                } else {
 
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"));
 
753
                }
 
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"));
 
766
 
 
767
        camel_pop3_engine_command_free (store->engine, pcp);
 
768
        
 
769
        if (pcu)
 
770
                camel_pop3_engine_command_free(store->engine, pcu);
 
771
 
 
772
        g_static_rec_mutex_unlock (store->eng_lock);
 
773
 
 
774
        return status;
 
775
}
 
776
 
 
777
static gboolean
 
778
pop3_connect (CamelService *service, CamelException *ex)
 
779
{
 
780
        CamelPOP3Store *store = (CamelPOP3Store *)service;
 
781
        gboolean reprompt = FALSE;
 
782
        CamelSession *session;
 
783
        char *errbuf = NULL;
 
784
        int status;
 
785
 
 
786
        session = camel_service_get_session (service);
 
787
 
 
788
        if (!connect_to_server_wrapper (service, ex))
 
789
                return FALSE;
 
790
        
 
791
        while (1) {
 
792
                status = pop3_try_authenticate (service, reprompt, errbuf, ex);
 
793
                g_free (errbuf);
 
794
                errbuf = NULL;
 
795
                
 
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;
 
801
                        reprompt = TRUE;
 
802
                        camel_exception_clear (ex);
 
803
                        sleep (5); /* For example Cyrus-POPd dislikes hammering */
 
804
                } else
 
805
                        break;
 
806
        }
 
807
        
 
808
        g_free (errbuf);
 
809
        
 
810
        if (status == -1 || camel_exception_is_set(ex)) {
 
811
                camel_service_disconnect(service, TRUE, ex);
 
812
                return FALSE;
 
813
        }
 
814
        
 
815
        /* Now that we are in the TRANSACTION state, try regetting the capabilities */
 
816
 
 
817
        g_static_rec_mutex_lock (store->eng_lock);
 
818
 
 
819
        if (store->engine == NULL) {
 
820
                g_static_rec_mutex_unlock (store->eng_lock);
 
821
                return FALSE;
 
822
        }
 
823
 
 
824
        store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
 
825
        camel_pop3_engine_reget_capabilities (store->engine);
 
826
 
 
827
        g_static_rec_mutex_unlock (store->eng_lock);
 
828
 
 
829
        return TRUE;
 
830
}
 
831
 
 
832
static gboolean
 
833
pop3_disconnect (CamelService *service, gboolean clean, CamelException *ex)
 
834
{
 
835
        CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 
836
 
 
837
        g_static_rec_mutex_lock (store->eng_lock);
 
838
        if (store->engine == NULL) {
 
839
                g_static_rec_mutex_unlock (store->eng_lock);
 
840
                return TRUE;
 
841
        }
 
842
 
 
843
        if (clean) {
 
844
                CamelPOP3Command *pc;
 
845
                
 
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)
 
848
                        ;
 
849
                camel_pop3_engine_command_free(store->engine, pc);
 
850
        }
 
851
 
 
852
        camel_object_unref((CamelObject *)store->engine);
 
853
        store->engine = NULL;
 
854
        g_static_rec_mutex_unlock (store->eng_lock);
 
855
 
 
856
        return TRUE;
 
857
}
 
858
 
 
859
static CamelFolder *
 
860
get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex)
 
861
{
 
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);
 
865
                return NULL;
 
866
        }
 
867
        return camel_pop3_folder_new (store, ex);
 
868
}
 
869
 
 
870
static CamelFolder *
 
871
get_trash (CamelStore *store, CamelException *ex)
 
872
{
 
873
        /* no-op */
 
874
        return NULL;
 
875
}
 
876
 
 
877
 
 
878
static void
 
879
finalize (CamelObject *object)
 
880
{
 
881
        CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (object);
 
882
 
 
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);
 
888
 
 
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;
 
895
 
 
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;
 
900
        return;
 
901
}
 
902
 
 
903
typedef struct {
 
904
        guint items, bytes;
 
905
} StatInfo;
 
906
 
 
907
static int
 
908
cmd_stat (CamelPOP3Engine *pe, CamelPOP3Stream *stream, void *data)
 
909
{
 
910
        unsigned char *line = (unsigned char *) stream; /* moeha, ugly! */
 
911
        StatInfo *info = data;
 
912
 
 
913
        if (!line)
 
914
                return 0;
 
915
 
 
916
        sscanf((char *) line, "+OK %d %d", &info->items, &info->bytes);
 
917
 
 
918
        return 1;
 
919
}
 
920
 
 
921
static void
 
922
pop3_get_folder_status (CamelStore *store, const char *folder_name, int *unseen, int *messages, int *uidnext)
 
923
{
 
924
        CamelPOP3Store *pop3_store = (CamelPOP3Store *) store;
 
925
        CamelPOP3Command *cmd = NULL;
 
926
        StatInfo *info = NULL;
 
927
        int i = -1;
 
928
 
 
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;
 
934
 
 
935
        camel_file_util_read_counts_2 (spath, &mversion, &mflags, &mnextuid,
 
936
                &mtime, &msaved_count, &munread_count, &mdeleted_count,
 
937
                &mjunk_count);
 
938
 
 
939
        if (munread_count != -1)
 
940
                *unseen = munread_count;
 
941
        if (msaved_count != -1)
 
942
                *messages = msaved_count;
 
943
        if (mnextuid != -1)
 
944
                *uidnext = mnextuid;
 
945
 
 
946
        g_free (spath);
 
947
 
 
948
        if (camel_disco_store_status (CAMEL_DISCO_STORE (pop3_store)) == CAMEL_DISCO_STORE_OFFLINE)
 
949
                return;
 
950
 
 
951
        g_static_rec_mutex_lock (pop3_store->eng_lock);
 
952
 
 
953
        if (pop3_store->engine == NULL) {
 
954
                g_static_rec_mutex_unlock (pop3_store->eng_lock);
 
955
                return;
 
956
        }
 
957
 
 
958
        camel_operation_start(NULL, _("Getting POP3 status"));
 
959
 
 
960
        info = g_slice_new (StatInfo);
 
961
 
 
962
        info->items = -1;
 
963
        info->bytes = -1;
 
964
 
 
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);
 
968
 
 
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);
 
976
                }
 
977
        }
 
978
 
 
979
        g_slice_free (StatInfo, info);
 
980
        camel_pop3_engine_command_free (pop3_store->engine, cmd);
 
981
 
 
982
        camel_operation_end(NULL);
 
983
        g_static_rec_mutex_unlock (pop3_store->eng_lock);
 
984
}
 
985
 
 
986
 
 
987
static void
 
988
pop3_construct (CamelService *service, CamelSession *session,
 
989
           CamelProvider *provider, CamelURL *url,
 
990
           CamelException *ex)
 
991
{
 
992
        CamelPOP3Store *pop3_store = CAMEL_POP3_STORE (service);
 
993
        CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service);
 
994
        char *path;
 
995
 
 
996
        CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex);
 
997
        if (camel_exception_is_set (ex))
 
998
                return;
 
999
 
 
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);
 
1002
 
 
1003
        if (!pop3_store->storage_path)
 
1004
                return;
 
1005
 
 
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);
 
1011
        }
 
1012
 
 
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));
 
1016
 
 
1017
        /* setup journal*/
 
1018
        path = g_strdup_printf ("%s/journal", pop3_store->storage_path);
 
1019
        disco_store->diary = camel_disco_diary_new (disco_store, path, ex);
 
1020
        g_free (path);
 
1021
 
 
1022
}
 
1023
 
 
1024
static void
 
1025
camel_pop3_store_class_init (CamelPOP3StoreClass *camel_pop3_store_class)
 
1026
{
 
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);
 
1033
 
 
1034
        parent_class = CAMEL_STORE_CLASS (camel_type_get_global_classfuncs (camel_disco_store_get_type ()));
 
1035
 
 
1036
        /* virtual method overload */
 
1037
        camel_service_class->construct = pop3_construct;
 
1038
        camel_service_class->query_auth_types = query_auth_types;
 
1039
 
 
1040
        /* camel_service_class->connect = pop3_connect; */
 
1041
        /* camel_service_class->disconnect = pop3_disconnect; */
 
1042
 
 
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;
 
1047
 
 
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;
 
1059
}
 
1060
 
 
1061
 
 
1062
 
 
1063
static void
 
1064
camel_pop3_store_init (gpointer object, gpointer klass)
 
1065
{
 
1066
        CamelPOP3Store *store = (CamelPOP3Store *) object;
 
1067
 
 
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);
 
1073
 
 
1074
        return;
 
1075
}
 
1076
 
 
1077
CamelType
 
1078
camel_pop3_store_get_type (void)
 
1079
{
 
1080
        static CamelType camel_pop3_store_type = CAMEL_INVALID_TYPE;
 
1081
 
 
1082
        if (!camel_pop3_store_type) {
 
1083
                camel_pop3_store_type = camel_type_register (CAMEL_DISCO_STORE_TYPE,
 
1084
                                                             "CamelPOP3Store",
 
1085
                                                             sizeof (CamelPOP3Store),
 
1086
                                                             sizeof (CamelPOP3StoreClass),
 
1087
                                                             (CamelObjectClassInitFunc) camel_pop3_store_class_init,
 
1088
                                                             NULL,
 
1089
                                                             (CamelObjectInitFunc) camel_pop3_store_init,
 
1090
                                                             finalize);
 
1091
        }
 
1092
 
 
1093
        return camel_pop3_store_type;
 
1094
}