~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to camel/providers/imapp/camel-imapp-engine.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ifdef HAVE_CONFIG_H
2
 
#include "config.h"
3
 
#endif
4
 
 
5
 
#include <ctype.h>
6
 
#include <stdio.h>
7
 
#include <string.h>
8
 
 
9
 
#include "camel-data-wrapper.h"
10
 
#include "camel-folder-summary.h"
11
 
#include "camel-sasl.h"
12
 
#include "camel-stream-mem.h"
13
 
#include "camel-stream-null.h"
14
 
 
15
 
#include "camel-imapp-engine.h"
16
 
#include "camel-imapp-exception.h"
17
 
#include "camel-imapp-stream.h"
18
 
#include "camel-imapp-utils.h"
19
 
 
20
 
#define e(x)
21
 
#define c(x)                    /* command build debug */
22
 
 
23
 
static void imap_engine_command_addv(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const gchar *fmt, va_list ap);
24
 
static void imap_engine_command_complete(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic);
25
 
 
26
 
struct _handler {
27
 
        CamelIMAPPEngineFunc func;
28
 
        gpointer data;
29
 
        gchar name[1];
30
 
};
31
 
 
32
 
static void
33
 
class_init(CamelIMAPPEngineClass *ieclass)
34
 
{
35
 
        ieclass->tagprefix = 'A';
36
 
 
37
 
        camel_object_class_add_event((CamelObjectClass *)ieclass, "status", NULL);
38
 
}
39
 
 
40
 
static void
41
 
object_init(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass)
42
 
{
43
 
        ie->handlers = g_hash_table_new(g_str_hash, g_str_equal);
44
 
        camel_dlist_init(&ie->active);
45
 
        camel_dlist_init(&ie->done);
46
 
 
47
 
        ie->port = camel_msgport_new();
48
 
 
49
 
        ie->tagprefix = ieclass->tagprefix;
50
 
        ieclass->tagprefix++;
51
 
        if (ieclass->tagprefix > 'Z')
52
 
                ieclass->tagprefix = 'A';
53
 
        ie->tagprefix = 'A';
54
 
 
55
 
        ie->state = IMAP_ENGINE_DISCONNECT;
56
 
}
57
 
 
58
 
static void
59
 
handler_free(gpointer key, gpointer mem, gpointer data)
60
 
{
61
 
        g_free(mem);
62
 
}
63
 
 
64
 
static void
65
 
object_finalise(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass)
66
 
{
67
 
        /* FIXME: need to free the commands ... */
68
 
        while (camel_imapp_engine_iterate(ie, NULL) > 0)
69
 
                ;
70
 
 
71
 
        g_hash_table_foreach(ie->handlers, (GHFunc)handler_free, NULL);
72
 
        g_hash_table_destroy(ie->handlers);
73
 
}
74
 
 
75
 
CamelType
76
 
camel_imapp_engine_get_type (void)
77
 
{
78
 
        static CamelType type = CAMEL_INVALID_TYPE;
79
 
 
80
 
        if (type == CAMEL_INVALID_TYPE) {
81
 
                type = camel_type_register (
82
 
                        camel_object_get_type (),
83
 
                        "CamelIMAPPEngine",
84
 
                        sizeof (CamelIMAPPEngine),
85
 
                        sizeof (CamelIMAPPEngineClass),
86
 
                        (CamelObjectClassInitFunc) class_init,
87
 
                        NULL,
88
 
                        (CamelObjectInitFunc) object_init,
89
 
                        (CamelObjectFinalizeFunc) object_finalise);
90
 
        }
91
 
 
92
 
        return type;
93
 
}
94
 
 
95
 
/* FIXME: check this, just taken from old code, not rfc */
96
 
struct {
97
 
        gchar *name;
98
 
        guint32 flag;
99
 
} capa_table[] = {
100
 
        { "IMAP4", IMAP_CAPABILITY_IMAP4 },
101
 
        { "IMAP4REV1", IMAP_CAPABILITY_IMAP4REV1 },
102
 
        { "STATUS",  IMAP_CAPABILITY_STATUS } ,
103
 
        { "NAMESPACE", IMAP_CAPABILITY_NAMESPACE },
104
 
        { "UIDPLUS",  IMAP_CAPABILITY_UIDPLUS },
105
 
        { "LITERAL+", IMAP_CAPABILITY_LITERALPLUS },
106
 
        { "STARTTLS", IMAP_CAPABILITY_STARTTLS },
107
 
};
108
 
 
109
 
/*
110
 
capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
111
 
                    [SPACE 1#capability]
112
 
                    ;; IMAP4rev1 servers which offer RFC 1730
113
 
                    ;; compatibility MUST list "IMAP4" as the first
114
 
                    ;; capability.
115
 
*/
116
 
static gint resp_capability(CamelIMAPPEngine *ie, guint32 id, gpointer data)
117
 
{
118
 
        gint tok, len, i;
119
 
        guchar *token, *p, c;
120
 
 
121
 
        /* FIXME: handle auth types */
122
 
 
123
 
        printf("got capability response:\n");
124
 
        while (1) {
125
 
                tok = camel_imapp_stream_token(ie->stream, &token, &len);
126
 
                switch (tok) {
127
 
                case IMAP_TOK_TOKEN:
128
 
                        p = token;
129
 
                        while ((c = *p))
130
 
                                *p++ = toupper(c);
131
 
                case IMAP_TOK_INT:
132
 
                        printf(" cap: '%s'\n", token);
133
 
                        for (i=0;i<(gint)(sizeof(capa_table)/sizeof(capa_table[0]));i++)
134
 
                                if (strcmp(token, capa_table[i].name))
135
 
                                        ie->capa |= capa_table[i].flag;
136
 
                        break;
137
 
                case '\n':
138
 
                        return 0;
139
 
                case IMAP_TOK_ERROR:
140
 
                case IMAP_TOK_PROTOCOL:
141
 
                        camel_imapp_engine_skip(ie);
142
 
                        return -1;
143
 
                default:
144
 
                        printf("Unknown Response token %02x '%c'\n", tok, isprint(tok)?tok:'.');
145
 
                }
146
 
        } while (tok != '\n');
147
 
 
148
 
        return 0;
149
 
}
150
 
 
151
 
/* expunge command, id is expunged seq number */
152
 
/* message_data    ::= nz_number SPACE ("EXPUNGE" /
153
 
   ("FETCH" SPACE msg_att)) */
154
 
static gint resp_expunge(CamelIMAPPEngine *ie, guint32 id, gpointer data)
155
 
{
156
 
        printf("message expunged: %d\n", id);
157
 
 
158
 
        return camel_imapp_engine_skip(ie);
159
 
}
160
 
 
161
 
static gint resp_flags(CamelIMAPPEngine *ie, guint32 id, gpointer data)
162
 
{
163
 
        guint32 flags;
164
 
 
165
 
        imap_parse_flags(ie->stream, &flags);
166
 
 
167
 
        printf("flags: %08x\n", flags);
168
 
 
169
 
        return camel_imapp_engine_skip(ie);
170
 
}
171
 
 
172
 
/* exists count */
173
 
static gint resp_exists(CamelIMAPPEngine *ie, guint32 id, gpointer data)
174
 
{
175
 
        printf("messages exist: %d\n", id);
176
 
 
177
 
        if (ie->select_response)
178
 
                ie->select_response->exists = id;
179
 
 
180
 
        return camel_imapp_engine_skip(ie);
181
 
}
182
 
 
183
 
static gint resp_recent(CamelIMAPPEngine *ie, guint32 id, gpointer data)
184
 
{
185
 
        printf("messages recent: %d\n", id);
186
 
 
187
 
        if (ie->select_response)
188
 
                ie->select_response->recent = id;
189
 
 
190
 
        return camel_imapp_engine_skip(ie);
191
 
}
192
 
 
193
 
static gint resp_fetch(CamelIMAPPEngine *ie, guint32 id, gpointer data)
194
 
{
195
 
        struct _fetch_info *finfo;
196
 
 
197
 
        finfo = imap_parse_fetch(ie->stream);
198
 
        imap_dump_fetch(finfo);
199
 
        imap_free_fetch(finfo);
200
 
 
201
 
        return camel_imapp_engine_skip(ie);
202
 
}
203
 
 
204
 
#if 0
205
 
static gint resp_list(CamelIMAPPEngine *ie, guint32 id, gpointer data)
206
 
{
207
 
        struct _list_info *linfo;
208
 
 
209
 
        linfo = imap_parse_list(ie->stream);
210
 
        printf("list:  '%s' (%c)\n", linfo->name, linfo->separator);
211
 
        imap_free_list(linfo);
212
 
 
213
 
        return camel_imapp_engine_skip(ie);
214
 
}
215
 
#endif
216
 
 
217
 
CamelIMAPPEngine *
218
 
camel_imapp_engine_new(CamelIMAPPStream *stream)
219
 
{
220
 
        CamelIMAPPEngine * volatile engine;
221
 
 
222
 
        engine = CAMEL_IMAPP_ENGINE (camel_object_new (CAMEL_IMAPP_ENGINE_TYPE));
223
 
        engine->stream = stream;
224
 
        camel_object_ref((CamelObject *)stream);
225
 
 
226
 
        camel_imapp_engine_add_handler(engine, "CAPABILITY", resp_capability, engine);
227
 
 
228
 
        /* mailbox_data */
229
 
        camel_imapp_engine_add_handler(engine, "FLAGS", (CamelIMAPPEngineFunc)resp_flags, engine);
230
 
        camel_imapp_engine_add_handler(engine, "EXISTS", (CamelIMAPPEngineFunc)resp_exists, engine);
231
 
        camel_imapp_engine_add_handler(engine, "RECENT", (CamelIMAPPEngineFunc)resp_recent, engine);
232
 
 
233
 
#if 0
234
 
        camel_imapp_engine_add_handler(engine, "LIST", (CamelIMAPPEngineFunc)resp_list, engine);
235
 
        camel_imapp_engine_add_handler(engine, "LSUB", (CamelIMAPPEngineFunc)resp_list, engine);
236
 
#endif
237
 
        /* message_data */
238
 
        camel_imapp_engine_add_handler(engine, "EXPUNGE", (CamelIMAPPEngineFunc)resp_expunge, engine);
239
 
        camel_imapp_engine_add_handler(engine, "FETCH", (CamelIMAPPEngineFunc)resp_fetch, engine);
240
 
 
241
 
        /* TODO: move this to a driver:connect call? */
242
 
        CAMEL_TRY {
243
 
                guchar *token;
244
 
                guint len;
245
 
                gint tok;
246
 
 
247
 
                tok = camel_imapp_stream_token(stream, &token, &len);
248
 
                if (tok == '*') {
249
 
                        struct _status_info *sinfo = imap_parse_status(stream);
250
 
 
251
 
                        switch (sinfo->result) {
252
 
                        case IMAP_OK:
253
 
                                engine->state = IMAP_ENGINE_CONNECT;
254
 
                                printf("Server connected ok: %s\n", sinfo->text);
255
 
                                break;
256
 
                        case IMAP_PREAUTH:
257
 
                                printf("pre-authenticated ...\n");
258
 
                                engine->state = IMAP_ENGINE_AUTH;
259
 
                                break;
260
 
                        default:
261
 
                                imap_free_status(sinfo);
262
 
                                camel_exception_throw(1, "Server refused connection: %s", sinfo->text);
263
 
                                break;
264
 
                        }
265
 
                        imap_free_status(sinfo);
266
 
                } else {
267
 
                        engine->state = IMAP_ENGINE_CONNECT;
268
 
                        printf("unknwon server greeting, ignored\n");
269
 
                        camel_imapp_engine_skip(engine);
270
 
                }
271
 
                camel_imapp_engine_capabilities(engine);
272
 
        } CAMEL_CATCH(ex) {
273
 
                printf("connection failed: %s\n", ex->desc);
274
 
                camel_object_unref((CamelObject *)engine);
275
 
                engine = NULL;
276
 
        } CAMEL_DONE;
277
 
 
278
 
        return engine;
279
 
}
280
 
 
281
 
void
282
 
camel_imapp_engine_add_handler(CamelIMAPPEngine *imap, const gchar *response, CamelIMAPPEngineFunc func, gpointer data)
283
 
{
284
 
        struct _handler *h;
285
 
        const guchar *p;
286
 
        guchar *o, c;
287
 
 
288
 
        h = g_malloc0(sizeof(*h) + strlen(response));
289
 
        h->func = func;
290
 
        h->data = data;
291
 
 
292
 
        p = response;
293
 
        o = h->name;
294
 
        while ((c = *p++))
295
 
                *o++ = toupper(c);
296
 
        *o = 0;
297
 
 
298
 
        g_hash_table_insert(imap->handlers, h->name, h);
299
 
}
300
 
 
301
 
gint
302
 
camel_imapp_engine_capabilities(CamelIMAPPEngine *ie)
303
 
{
304
 
        CamelIMAPPCommand *ic;
305
 
 
306
 
        /* reset capabilities */
307
 
        ie->capa = 0;
308
 
 
309
 
        ic = camel_imapp_engine_command_new(ie, "CAPABILITY", NULL, "CAPABILITY");
310
 
        camel_imapp_engine_command_queue(ie, ic);
311
 
        while (camel_imapp_engine_iterate(ie, ic)>0)
312
 
                ;
313
 
        camel_imapp_engine_command_free(ie, ic);
314
 
 
315
 
        return 0;
316
 
}
317
 
 
318
 
/* skip the rest of the line of tokens */
319
 
gint
320
 
camel_imapp_engine_skip(CamelIMAPPEngine *imap)
321
 
{
322
 
        gint tok;
323
 
        guchar *token;
324
 
        guint len;
325
 
 
326
 
        do {
327
 
                tok = camel_imapp_stream_token(imap->stream, &token, &len);
328
 
                if (tok == IMAP_TOK_LITERAL) {
329
 
                        camel_imapp_stream_set_literal(imap->stream, len);
330
 
                        while ((tok = camel_imapp_stream_getl(imap->stream, &token, &len)) > 0) {
331
 
                                printf("Skip literal data '%.*s'\n", (gint)len, token);
332
 
                        }
333
 
                }
334
 
        } while (tok != '\n' && tok >= 0);
335
 
 
336
 
        if (tok < 0)
337
 
                return -1;
338
 
 
339
 
        return 0;
340
 
}
341
 
 
342
 
/* handle any untagged responses */
343
 
static gint
344
 
iterate_untagged(CamelIMAPPEngine *imap)
345
 
{
346
 
        guint id, len;
347
 
        guchar *token, *p, c;
348
 
        gint tok;
349
 
        struct _handler *h;
350
 
        struct _status_info *sinfo;
351
 
 
352
 
        e(printf("got untagged response\n"));
353
 
        id = 0;
354
 
        tok = camel_imapp_stream_token(imap->stream, &token, &len);
355
 
        if (tok == IMAP_TOK_INT) {
356
 
                id = strtoul(token, NULL, 10);
357
 
                tok = camel_imapp_stream_token(imap->stream, &token, &len);
358
 
        }
359
 
 
360
 
        if (tok == '\n')
361
 
                camel_exception_throw(1, "truncated server response");
362
 
 
363
 
        e(printf("Have token '%s' id %d\n", token, id));
364
 
        p = token;
365
 
        while ((c = *p))
366
 
                *p++ = toupper(c);
367
 
 
368
 
        /* first, check for generic unsolicited response */
369
 
        h = g_hash_table_lookup(imap->handlers, token);
370
 
        if (h) {
371
 
                tok = h->func(imap, id, h->data);
372
 
                if (tok < 0)
373
 
                        return tok;
374
 
                return 1;
375
 
        }
376
 
 
377
 
        /* TODO: apart from bye/preauth, these could be callbacks/events? */
378
 
 
379
 
        /* now, check for status responses */
380
 
        switch (imap_tokenise(token, len)) {
381
 
        case IMAP_BYE:
382
 
        case IMAP_OK:
383
 
        case IMAP_NO:
384
 
        case IMAP_BAD:
385
 
        case IMAP_PREAUTH:
386
 
                /* TODO: validate which ones of these can happen as unsolicited responses */
387
 
                /* TODO: handle bye/preauth differently */
388
 
                /* FIXME: free sinfo */
389
 
                camel_imapp_stream_ungettoken(imap->stream, tok, token, len);
390
 
                sinfo = imap_parse_status(imap->stream);
391
 
                camel_object_trigger_event(imap, "status", sinfo);
392
 
                imap_free_status(sinfo);
393
 
#if 0
394
 
                switch (sinfo->condition) {
395
 
                case IMAP_READ_WRITE:
396
 
                        printf("folder is read-write\n");
397
 
                        break;
398
 
                case IMAP_READ_ONLY:
399
 
                        printf("folder is read-only\n");
400
 
                        break;
401
 
                case IMAP_UIDVALIDITY:
402
 
                        if (imap->select_response)
403
 
                                imap->select_response->uidvalidity = sinfo->u.uidvalidity;
404
 
                        break;
405
 
#if 0
406
 
                        /* not defined yet ... */
407
 
                case IMAP_UIDNEXT:
408
 
                        printf("got uidnext for folder: %d\n", sinfo->u.uidnext);
409
 
                        break;
410
 
#endif
411
 
                case IMAP_UNSEEN:
412
 
                        if (imap->select_response)
413
 
                                imap->select_response->unseen = sinfo->u.unseen;
414
 
                        break;
415
 
                case IMAP_PERMANENTFLAGS:
416
 
                        if (imap->select_response)
417
 
                                imap->select_response->permanentflags = sinfo->u.permanentflags;
418
 
                        break;
419
 
                case IMAP_ALERT:
420
 
                        printf("ALERT!: %s\n", sinfo->text);
421
 
                        break;
422
 
                case IMAP_PARSE:
423
 
                        printf("PARSE: %s\n", sinfo->text);
424
 
                        break;
425
 
                default:
426
 
                        break;
427
 
                }
428
 
#endif
429
 
                break;
430
 
        default:
431
 
                printf("unknown token: %s\n", token);
432
 
                camel_imapp_engine_skip(imap);
433
 
                /* unknown response, just ignore it */
434
 
        }
435
 
 
436
 
        return 1;
437
 
}
438
 
 
439
 
/* handle any continuation requests
440
 
   either data continuations, or auth continuation */
441
 
static gint
442
 
iterate_continuation(CamelIMAPPEngine *imap)
443
 
{
444
 
        CamelIMAPPCommand *ic;
445
 
        CamelIMAPPCommandPart *cp;
446
 
 
447
 
        printf("got continuation response\n");
448
 
 
449
 
        ic = imap->literal;
450
 
        imap->literal = NULL;
451
 
        if (ic == NULL) {
452
 
                camel_imapp_engine_skip(imap);
453
 
                printf("got continuation response with no outstanding continuation requests?\n");
454
 
                return 1;
455
 
        }
456
 
 
457
 
        printf("got continuation response for data\n");
458
 
        cp = ic->current;
459
 
        switch (cp->type & CAMEL_IMAPP_COMMAND_MASK) {
460
 
        case CAMEL_IMAPP_COMMAND_DATAWRAPPER:
461
 
                printf("writing data wrapper to literal\n");
462
 
                camel_data_wrapper_write_to_stream((CamelDataWrapper *)cp->ob, (CamelStream *)imap->stream);
463
 
                break;
464
 
        case CAMEL_IMAPP_COMMAND_STREAM:
465
 
                printf("writing stream to literal\n");
466
 
                camel_stream_write_to_stream((CamelStream *)cp->ob, (CamelStream *)imap->stream);
467
 
                break;
468
 
        case CAMEL_IMAPP_COMMAND_AUTH: {
469
 
                CamelException *ex = camel_exception_new();
470
 
                gchar *resp;
471
 
                guchar *token;
472
 
                gint tok, len;
473
 
 
474
 
                tok = camel_imapp_stream_token(imap->stream, &token, &len);
475
 
                resp = camel_sasl_challenge_base64((CamelSasl *)cp->ob, token, ex);
476
 
                if (camel_exception_is_set(ex))
477
 
                        camel_exception_throw_ex(ex);
478
 
                camel_exception_free(ex);
479
 
 
480
 
                printf("got auth continuation, feeding token '%s' back to auth mech\n", resp);
481
 
 
482
 
                camel_stream_write((CamelStream *)imap->stream, resp, strlen(resp));
483
 
 
484
 
                /* we want to keep getting called until we get a status reponse from the server
485
 
                   ignore what sasl tells us */
486
 
                imap->literal = ic;
487
 
 
488
 
                break; }
489
 
        default:
490
 
                /* should we just ignore? */
491
 
                camel_exception_throw(1, "continuation response for non-continuation request");
492
 
        }
493
 
 
494
 
        camel_imapp_engine_skip(imap);
495
 
 
496
 
        cp = cp->next;
497
 
        if (cp->next) {
498
 
                ic->current = cp;
499
 
                printf("next part of command \"A%05u: %s\"\n", ic->tag, cp->data);
500
 
                camel_stream_printf((CamelStream *)imap->stream, "%s\r\n", cp->data);
501
 
                if (cp->type & CAMEL_IMAPP_COMMAND_CONTINUATION) {
502
 
                        imap->literal = ic;
503
 
                } else {
504
 
                        g_assert(cp->next->next == NULL);
505
 
                }
506
 
        } else {
507
 
                printf("%p: queueing continuation\n", ic);
508
 
                camel_stream_printf((CamelStream *)imap->stream, "\r\n");
509
 
        }
510
 
 
511
 
        if (imap->literal == NULL) {
512
 
                ic = (CamelIMAPPCommand *)camel_dlist_remhead(&imap->queue);
513
 
                if (ic) {
514
 
                        printf("found outstanding op, queueing\n");
515
 
                        camel_imapp_engine_command_queue(imap, ic);
516
 
                }
517
 
        }
518
 
 
519
 
        return 1;
520
 
}
521
 
 
522
 
/* handle a completion line */
523
 
static gint
524
 
iterate_completion(CamelIMAPPEngine *imap, guchar *token)
525
 
{
526
 
        CamelIMAPPCommand *ic;
527
 
        guint tag;
528
 
 
529
 
        if (token[0] != imap->tagprefix)
530
 
                camel_exception_throw(1, "Server sent unexpected response: %s", token);
531
 
 
532
 
        tag = strtoul(token+1, NULL, 10);
533
 
        ic = camel_imapp_engine_command_find_tag(imap, tag);
534
 
        if (ic) {
535
 
                printf("Got completion response for command %05u '%s'\n", ic->tag, ic->name);
536
 
                printf("%p: removing command from qwueue, we were at '%s'\n", ic, ic->current->data);
537
 
                printf("%p: removing command\n", ic);
538
 
                camel_dlist_remove((CamelDListNode *)ic);
539
 
                camel_dlist_addtail(&imap->done, (CamelDListNode *)ic);
540
 
                if (imap->literal == ic)
541
 
                        imap->literal = NULL;
542
 
                ic->status = imap_parse_status(imap->stream);
543
 
                printf("got response code: %s\n", ic->status->text);
544
 
 
545
 
                /* TODO: remove this stuff and use a completion handler? */
546
 
                /* TODO: handle 'SELECT' command cleanup here */
547
 
                /* FIXME: have this use tokeniser, have this handle close/logout/select etc as well */
548
 
                /* ok response from login/authenticate, then we're in happy land */
549
 
                if ((!strcmp(ic->name, "LOGIN") || !strcmp(ic->name, "AUTHENTICATE"))
550
 
                    && ic->status->result == IMAP_OK)
551
 
                        imap->state = IMAP_ENGINE_AUTH;
552
 
 
553
 
                if (ic->complete)
554
 
                        ic->complete(imap, ic, ic->complete_data);
555
 
        } else {
556
 
                camel_exception_throw(1, "got response tag unexpectedly: %s", token);
557
 
        }
558
 
 
559
 
        if (imap->literal != NULL) {
560
 
                printf("Warning: continuation command '%s' finished with outstanding continuation\n", imap->literal->name);
561
 
                ic = imap->literal;
562
 
                                /* set the command complete with a failure code? */
563
 
                camel_dlist_remove((CamelDListNode *)ic);
564
 
                camel_dlist_addtail(&imap->done, (CamelDListNode *)ic);
565
 
                imap->literal = NULL;
566
 
        }
567
 
 
568
 
        ic = (CamelIMAPPCommand *)camel_dlist_remhead(&imap->queue);
569
 
        if (ic) {
570
 
                printf("found outstanding op, queueing\n");
571
 
                camel_imapp_engine_command_queue(imap, ic);
572
 
        }
573
 
 
574
 
        return 1;
575
 
}
576
 
 
577
 
/* Do work if there's any to do */
578
 
gint
579
 
camel_imapp_engine_iterate(CamelIMAPPEngine *imap, CamelIMAPPCommand *icwait)
580
 
/* throws IO,PARSE exception */
581
 
{
582
 
        guint len;
583
 
        guchar *token;
584
 
        gint tok;
585
 
 
586
 
        if ((icwait && icwait->status != NULL) || camel_dlist_empty(&imap->active))
587
 
                return 0;
588
 
 
589
 
        /* handle exceptions here? */
590
 
 
591
 
        /* lock here? */
592
 
 
593
 
        tok = camel_imapp_stream_token(imap->stream, &token, &len);
594
 
        if (tok == '*')
595
 
                iterate_untagged(imap);
596
 
        else if (tok == IMAP_TOK_TOKEN)
597
 
                iterate_completion(imap, token);
598
 
        else if (tok == '+')
599
 
                iterate_continuation(imap);
600
 
        else
601
 
                camel_exception_throw(1, "unexpected server response: %s", token);
602
 
 
603
 
        if (camel_dlist_empty(&imap->active))
604
 
                return 0;
605
 
 
606
 
        return 1;
607
 
}
608
 
 
609
 
CamelIMAPPCommand *
610
 
camel_imapp_engine_command_new(CamelIMAPPEngine *imap, const gchar *name, const gchar *select, const gchar *fmt, ...)
611
 
{
612
 
        CamelIMAPPCommand *ic;
613
 
        va_list ap;
614
 
 
615
 
        ic = g_malloc0(sizeof(*ic));
616
 
        ic->tag = imap->tag++;
617
 
        ic->name = name;
618
 
        ic->mem = (CamelStreamMem *)camel_stream_mem_new();
619
 
        ic->select = g_strdup(select);
620
 
        camel_dlist_init(&ic->parts);
621
 
 
622
 
        if (fmt && fmt[0]) {
623
 
                va_start(ap, fmt);
624
 
                imap_engine_command_addv(imap, ic, fmt, ap);
625
 
                va_end(ap);
626
 
        }
627
 
 
628
 
        return ic;
629
 
}
630
 
 
631
 
void
632
 
camel_imapp_engine_command_add(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const gchar *fmt, ...)
633
 
{
634
 
        va_list ap;
635
 
 
636
 
        g_assert(ic->mem);      /* gets reset on queue */
637
 
 
638
 
        if (fmt && fmt[0]) {
639
 
                va_start(ap, fmt);
640
 
                imap_engine_command_addv(imap, ic, fmt, ap);
641
 
                va_end(ap);
642
 
        }
643
 
}
644
 
 
645
 
void
646
 
camel_imapp_engine_command_complete(CamelIMAPPEngine *imap, struct _CamelIMAPPCommand *ic, CamelIMAPPCommandFunc func, gpointer data)
647
 
{
648
 
        ic->complete = func;
649
 
        ic->complete_data = data;
650
 
}
651
 
 
652
 
/* FIXME: make imap command's refcounted? */
653
 
void
654
 
camel_imapp_engine_command_free (CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
655
 
{
656
 
        CamelIMAPPCommandPart *cp, *cn;
657
 
 
658
 
        if (ic == NULL)
659
 
                return;
660
 
 
661
 
        /* Note the command must not be in any queue? */
662
 
 
663
 
        if (ic->mem)
664
 
                camel_object_unref((CamelObject *)ic->mem);
665
 
        imap_free_status(ic->status);
666
 
        g_free(ic->select);
667
 
 
668
 
        while ( (cp = ((CamelIMAPPCommandPart *)camel_dlist_remhead(&ic->parts))) ) {
669
 
                g_free(cp->data);
670
 
                if (cp->ob)
671
 
                        camel_object_unref(cp->ob);
672
 
                g_free(cp);
673
 
        }
674
 
 
675
 
        g_free(ic);
676
 
}
677
 
 
678
 
/* FIXME: error handling */
679
 
void
680
 
camel_imapp_engine_command_queue(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
681
 
{
682
 
        CamelIMAPPCommandPart *cp;
683
 
 
684
 
        g_assert(ic->msg.reply_port);
685
 
 
686
 
        if (ic->mem)
687
 
                imap_engine_command_complete(imap, ic);
688
 
 
689
 
        camel_msgport_push(imap->port, (CamelMsg *)ic);
690
 
}
691
 
 
692
 
CamelIMAPPCommand *
693
 
camel_imapp_engine_command_find (CamelIMAPPEngine *imap, const gchar *name)
694
 
{
695
 
        CamelIMAPPCommand *ic, *in;
696
 
 
697
 
        ic = imap->literal;
698
 
        if (ic && strcmp(ic->name, name) == 0)
699
 
                return ic;
700
 
 
701
 
        /* first, try active */
702
 
        ic = (CamelIMAPPCommand *)imap->active.head;
703
 
        in = ic->msg.ln.next;
704
 
        while (in) {
705
 
                if (strcmp(ic->name, name) == 0)
706
 
                        return ic;
707
 
                ic = in;
708
 
                in = in->msg.ln.next;
709
 
        }
710
 
 
711
 
        return NULL;
712
 
}
713
 
 
714
 
CamelIMAPPCommand *
715
 
camel_imapp_engine_command_find_tag(CamelIMAPPEngine *imap, guint tag)
716
 
{
717
 
        CamelIMAPPCommand *ic, *in;
718
 
 
719
 
        ic = imap->literal;
720
 
        if (ic && ic->tag == tag)
721
 
                return ic;
722
 
 
723
 
        ic = (CamelIMAPPCommand *)imap->active.head;
724
 
        in = ic->msg.ln.next;
725
 
        while (in) {
726
 
                if (ic->tag == tag)
727
 
                        return ic;
728
 
                ic = in;
729
 
                in = in->msg.ln.next;
730
 
        }
731
 
 
732
 
        return NULL;
733
 
}
734
 
 
735
 
/* ********************************************************************** */
736
 
 
737
 
CamelIMAPPSelectResponse *
738
 
camel_imapp_engine_select(CamelIMAPPEngine *imap, const gchar *name)
739
 
{
740
 
        CamelIMAPPSelectResponse * volatile resp;
741
 
        CamelIMAPPCommand * volatile ic = NULL;
742
 
 
743
 
        resp = g_malloc0(sizeof(*resp));
744
 
        imap->select_response = resp;
745
 
 
746
 
        CAMEL_TRY {
747
 
                ic = camel_imapp_engine_command_new(imap, "SELECT", NULL, "SELECT %s", name);
748
 
                camel_imapp_engine_command_queue(imap, ic);
749
 
                while (camel_imapp_engine_iterate(imap, ic) > 0)
750
 
                        ;
751
 
 
752
 
                if (ic->status->result != IMAP_OK)
753
 
                        camel_exception_throw(1, "select failed: %s", ic->status->text);
754
 
                resp->status = ic->status;
755
 
                ic->status = NULL;
756
 
        } CAMEL_CATCH (e) {
757
 
                camel_imapp_engine_command_free(imap, ic);
758
 
                camel_imapp_engine_select_free(imap, resp);
759
 
                imap->select_response = NULL;
760
 
                camel_exception_throw_ex(e);
761
 
        } CAMEL_DONE;
762
 
 
763
 
        camel_imapp_engine_command_free(imap, ic);
764
 
        imap->select_response = NULL;
765
 
 
766
 
        return resp;
767
 
}
768
 
 
769
 
void
770
 
camel_imapp_engine_select_free(CamelIMAPPEngine *imap, CamelIMAPPSelectResponse *select)
771
 
{
772
 
        if (select) {
773
 
                imap_free_status(select->status);
774
 
                g_free(select);
775
 
        }
776
 
}
777
 
 
778
 
/* ********************************************************************** */
779
 
 
780
 
static void
781
 
imap_engine_command_add_part(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, camel_imapp_command_part_t type, CamelObject *ob)
782
 
{
783
 
        CamelIMAPPCommandPart *cp;
784
 
        CamelStreamNull *null;
785
 
        guint ob_size = 0;
786
 
 
787
 
        switch (type & CAMEL_IMAPP_COMMAND_MASK) {
788
 
        case CAMEL_IMAPP_COMMAND_DATAWRAPPER:
789
 
        case CAMEL_IMAPP_COMMAND_STREAM:
790
 
                null = (CamelStreamNull *)camel_stream_null_new();
791
 
                if ( (type & CAMEL_IMAPP_COMMAND_MASK) == CAMEL_IMAPP_COMMAND_DATAWRAPPER) {
792
 
                        camel_data_wrapper_write_to_stream((CamelDataWrapper *)ob, (CamelStream *)null);
793
 
                } else {
794
 
                        camel_stream_reset((CamelStream *)ob);
795
 
                        camel_stream_write_to_stream((CamelStream *)ob, (CamelStream *)null);
796
 
                        camel_stream_reset((CamelStream *)ob);
797
 
                }
798
 
                type |= CAMEL_IMAPP_COMMAND_CONTINUATION;
799
 
                camel_object_ref(ob);
800
 
                ob_size = null->written;
801
 
                camel_object_unref((CamelObject *)null);
802
 
                camel_stream_printf((CamelStream *)ic->mem, "{%u}", ob_size);
803
 
                break;
804
 
        case CAMEL_IMAPP_COMMAND_AUTH:
805
 
                /* we presume we'll need to get additional data only if we're not authenticated yet */
806
 
                camel_object_ref(ob);
807
 
                camel_stream_printf((CamelStream *)ic->mem, "%s", ((CamelSasl *)ob)->mech);
808
 
                if (!camel_sasl_authenticated((CamelSasl *)ob))
809
 
                        type |= CAMEL_IMAPP_COMMAND_CONTINUATION;
810
 
                break;
811
 
        default:
812
 
                ob_size = 0;
813
 
        }
814
 
 
815
 
        cp = g_malloc0(sizeof(*cp));
816
 
        cp->type = type;
817
 
        cp->ob_size = ob_size;
818
 
        cp->ob = ob;
819
 
        cp->data_size = ic->mem->buffer->len;
820
 
        cp->data = g_malloc(cp->data_size+1);
821
 
        memcpy(cp->data, ic->mem->buffer->data, cp->data_size);
822
 
        cp->data[cp->data_size] = 0;
823
 
 
824
 
        camel_stream_reset((CamelStream *)ic->mem);
825
 
        /* FIXME: hackish? */
826
 
        g_byte_array_set_size(ic->mem->buffer, 0);
827
 
 
828
 
        camel_dlist_addtail(&ic->parts, (CamelDListNode *)cp);
829
 
}
830
 
 
831
 
#if c(!)0
832
 
static gint len(CamelDList *list)
833
 
{
834
 
        gint count = 0;
835
 
        CamelDListNode *n = list->head;
836
 
 
837
 
        while (n->next) {
838
 
                n = n->next;
839
 
                count++;
840
 
        }
841
 
        return count;
842
 
}
843
 
#endif
844
 
 
845
 
static void
846
 
imap_engine_command_complete(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
847
 
{
848
 
        c(printf("completing command buffer is [%d] '%.*s'\n", ic->mem->buffer->len, (gint)ic->mem->buffer->len, ic->mem->buffer->data));
849
 
        c(printf("command has %d parts\n", len(&ic->parts)));
850
 
        if (ic->mem->buffer->len > 0)
851
 
                imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_SIMPLE, NULL);
852
 
 
853
 
        c(printf("command has %d parts\n", len(&ic->parts)));
854
 
 
855
 
        camel_object_unref((CamelObject *)ic->mem);
856
 
        ic->mem = NULL;
857
 
}
858
 
 
859
 
static void
860
 
imap_engine_command_addv(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const gchar *fmt, va_list ap)
861
 
{
862
 
        const guchar *p, *ps, *start;
863
 
        guchar c;
864
 
        guint width;
865
 
        gchar ch;
866
 
        gint llong;
867
 
        gint left;
868
 
        gint fill;
869
 
        gint zero;
870
 
        gchar *s;
871
 
        gint d;
872
 
        gglong l;
873
 
        guint32 f;
874
 
        CamelStream *S;
875
 
        CamelDataWrapper *D;
876
 
        CamelSasl *A;
877
 
        gchar buffer[16];
878
 
 
879
 
        c(printf("adding command, fmt = '%s'\n", fmt));
880
 
 
881
 
        p = fmt;
882
 
        ps = fmt;
883
 
        while ( ( c = *p++ ) ) {
884
 
                switch (c) {
885
 
                case '%':
886
 
                        if (*p == '%') {
887
 
                                camel_stream_write((CamelStream *)ic->mem, ps, p-ps);
888
 
                                p++;
889
 
                                ps = p;
890
 
                        } else {
891
 
                                camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1);
892
 
                                start = p-1;
893
 
                                width = 0;
894
 
                                left = FALSE;
895
 
                                fill = FALSE;
896
 
                                zero = FALSE;
897
 
                                llong = FALSE;
898
 
 
899
 
                                do {
900
 
                                        c = *p++;
901
 
                                        if (c == '0')
902
 
                                                zero = TRUE;
903
 
                                        else if ( c== '-')
904
 
                                                left = TRUE;
905
 
                                        else
906
 
                                                break;
907
 
                                } while (c);
908
 
 
909
 
                                do {
910
 
                                        if (isdigit(c))
911
 
                                                width = width * 10 + (c-'0');
912
 
                                        else
913
 
                                                break;
914
 
                                } while ((c = *p++));
915
 
 
916
 
                                if (c == 'l') {
917
 
                                        llong = TRUE;
918
 
                                        c = *p++;
919
 
                                }
920
 
 
921
 
                                switch (c) {
922
 
                                case 'A': /* auth object - sasl auth, treat as special kind of continuation */
923
 
                                        A = va_arg(ap, CamelSasl *);
924
 
                                        imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_AUTH, (CamelObject *)A);
925
 
                                        break;
926
 
                                case 'S': /* stream */
927
 
                                        S = va_arg(ap, CamelStream *);
928
 
                                        c(printf("got stream '%p'\n", S));
929
 
                                        imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_STREAM, (CamelObject *)S);
930
 
                                        break;
931
 
                                case 'D': /* datawrapper */
932
 
                                        D = va_arg(ap, CamelDataWrapper *);
933
 
                                        c(printf("got data wrapper '%p'\n", D));
934
 
                                        imap_engine_command_add_part(imap, ic, CAMEL_IMAPP_COMMAND_DATAWRAPPER, (CamelObject *)D);
935
 
                                        break;
936
 
                                case 't': /* token */
937
 
                                        s = va_arg(ap, gchar *);
938
 
                                        camel_stream_write((CamelStream *)ic->mem, s, strlen(s));
939
 
                                        break;
940
 
                                case 's': /* simple string */
941
 
                                        s = va_arg(ap, gchar *);
942
 
                                        c(printf("got string '%s'\n", s));
943
 
                                        /* FIXME: escpae chars, convert to literal or literal+, etc */
944
 
                                        camel_stream_printf((CamelStream *)ic->mem, "\"%s\"", s);
945
 
                                        break;
946
 
                                case 'f': /* imap folder name */
947
 
                                        s = va_arg(ap, gchar *);
948
 
                                        c(printf("got folder '%s'\n", s));
949
 
                                        /* FIXME: encode folder name */
950
 
                                        /* FIXME: namespace? */
951
 
                                        camel_stream_printf((CamelStream *)ic->mem, "\"%s\"", s?s:"");
952
 
                                        break;
953
 
                                case 'F': /* IMAP flags set */
954
 
                                        f = va_arg(ap, guint32);
955
 
                                        imap_write_flags((CamelStream *)ic->mem, f);
956
 
                                        break;
957
 
                                case 'c':
958
 
                                        d = va_arg(ap, gint);
959
 
                                        ch = d;
960
 
                                        camel_stream_write((CamelStream *)ic->mem, &ch, 1);
961
 
                                        break;
962
 
                                case 'd': /* int/unsigned */
963
 
                                case 'u':
964
 
                                        if (llong) {
965
 
                                                l = va_arg(ap, gglong);
966
 
                                                c(printf("got gglong '%d'\n", (gint)l));
967
 
                                                memcpy(buffer, start, p-start);
968
 
                                                buffer[p-start] = 0;
969
 
                                                camel_stream_printf((CamelStream *)ic->mem, buffer, l);
970
 
                                        } else {
971
 
                                                d = va_arg(ap, gint);
972
 
                                                c(printf("got gint '%d'\n", d));
973
 
                                                memcpy(buffer, start, p-start);
974
 
                                                buffer[p-start] = 0;
975
 
                                                camel_stream_printf((CamelStream *)ic->mem, buffer, d);
976
 
                                        }
977
 
                                        break;
978
 
                                }
979
 
 
980
 
                                ps = p;
981
 
                        }
982
 
                        break;
983
 
                case '\\':      /* only for \\ really, we dont support \n\r etc at all */
984
 
                        c = *p;
985
 
                        if (c) {
986
 
                                g_assert(c == '\\');
987
 
                                camel_stream_write((CamelStream *)ic->mem, ps, p-ps);
988
 
                                p++;
989
 
                                ps = p;
990
 
                        }
991
 
                }
992
 
        }
993
 
 
994
 
        camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1);
995
 
}
996
 
 
997
 
static gpointer
998
 
cie_worker(gpointer data)
999
 
{
1000
 
        CamelIMAPPCommand *ic = data;
1001
 
        CamelIMAPPEngine *imap;
1002
 
        CamelIMAPPCommandPart *cp;
1003
 
 
1004
 
        /* FIXME: remove select stuff */
1005
 
 
1006
 
        /* see if we need to pre-queue a select command to select the right folder first */
1007
 
        if (ic->select && (imap->last_select == NULL || strcmp(ic->select, imap->last_select) != 0)) {
1008
 
                CamelIMAPPCommand *select;
1009
 
 
1010
 
                /* of course ... we can't do anything like store/search if we have to select
1011
 
                   first, because it'll mess up all the sequence numbers ... hrm ... bugger */
1012
 
 
1013
 
                select = camel_imapp_engine_command_new(imap, "SELECT", NULL, "SELECT %s", ic->select);
1014
 
                g_free(imap->last_select);
1015
 
                imap->last_select = g_strdup(ic->select);
1016
 
                camel_imapp_engine_command_queue(imap, select);
1017
 
                /* how does it get freed? handle inside engine? */
1018
 
        }
1019
 
 
1020
 
        /* first, check if command can be sent yet ... queue if not */
1021
 
        if (imap->literal != NULL) {
1022
 
                printf("%p: queueing while literal active\n", ic);
1023
 
                camel_dlist_addtail(&imap->queue, (CamelDListNode *)ic);
1024
 
                return;
1025
 
        }
1026
 
 
1027
 
        cp = (CamelIMAPPCommandPart *)ic->parts.head;
1028
 
        g_assert(cp);
1029
 
        ic->current = cp;
1030
 
 
1031
 
        /* how to handle exceptions here? */
1032
 
 
1033
 
        printf("queueing command \"%c%05u %s\"\n", imap->tagprefix, ic->tag, cp->data);
1034
 
        camel_stream_printf((CamelStream *)imap->stream, "%c%05u %s\r\n", imap->tagprefix, ic->tag, cp->data);
1035
 
 
1036
 
        if (cp->type & CAMEL_IMAPP_COMMAND_CONTINUATION) {
1037
 
                printf("%p: active literal\n", ic);
1038
 
                g_assert(cp->next);
1039
 
                imap->literal = ic;
1040
 
                camel_dlist_addtail(&imap->active, (CamelDListNode *)ic);
1041
 
        } else {
1042
 
                printf("%p: active non-literal\n", ic);
1043
 
                g_assert(cp->next && cp->next->next == NULL);
1044
 
                camel_dlist_addtail(&imap->active, (CamelDListNode *)ic);
1045
 
        }
1046
 
}
1047
 
 
1048
 
/* here temporarily while its experimental */
1049
 
 
1050
 
#ifdef ENABLE_THREADS
1051
 
#include <pthread.h>
1052
 
 
1053
 
static pthread_key_t handler_key = 0;
1054
 
 
1055
 
void camel_exception_setup(void)
1056
 
{
1057
 
        pthread_key_create(&handler_key, NULL);
1058
 
}
1059
 
 
1060
 
#else
1061
 
/* this is per-thread in threaded mode */
1062
 
static struct _CamelExceptionEnv *handler = NULL;
1063
 
 
1064
 
void camel_exception_setup(void)
1065
 
{
1066
 
}
1067
 
#endif
1068
 
 
1069
 
void
1070
 
camel_exception_try(struct _CamelExceptionEnv *env)
1071
 
{
1072
 
#ifdef ENABLE_THREADS
1073
 
        struct _CamelExceptionEnv *handler;
1074
 
 
1075
 
        handler = pthread_getspecific(handler_key);
1076
 
#endif
1077
 
        env->parent = handler;
1078
 
        handler = env;
1079
 
        env->ex = NULL;
1080
 
 
1081
 
#ifdef ENABLE_THREADS
1082
 
        pthread_setspecific(handler_key, handler);
1083
 
#endif
1084
 
}
1085
 
 
1086
 
void
1087
 
camel_exception_throw_ex(CamelException *ex)
1088
 
{
1089
 
        struct _CamelExceptionEnv *env;
1090
 
#ifdef ENABLE_THREADS
1091
 
        struct _CamelExceptionEnv *handler;
1092
 
 
1093
 
        handler = pthread_getspecific(handler_key);
1094
 
#endif
1095
 
        printf("throwing exception '%s'\n", ex->desc);
1096
 
 
1097
 
        env = handler;
1098
 
        if (env != NULL) {
1099
 
                env->ex = ex;
1100
 
                handler = env->parent;
1101
 
#ifdef ENABLE_THREADS
1102
 
                pthread_setspecific(handler_key, handler);
1103
 
#endif
1104
 
                longjmp(env->env, ex->id);
1105
 
        } else {
1106
 
                g_warning("Uncaught exception: %s\n", ex->desc);
1107
 
                /* we just crash and burn, this is a code problem */
1108
 
                /* we dont use g_assert_not_reached() since its not a noreturn function */
1109
 
                abort();
1110
 
        }
1111
 
}
1112
 
 
1113
 
void
1114
 
camel_exception_throw(gint id, gchar *fmt, ...)
1115
 
{
1116
 
        CamelException *ex;
1117
 
        va_list ap;
1118
 
 
1119
 
        ex = camel_exception_new();
1120
 
        ex->id = id;
1121
 
        va_start(ap, fmt);
1122
 
        ex->desc = g_strdup_vprintf(fmt, ap);
1123
 
        va_end(ap);
1124
 
 
1125
 
        camel_exception_throw_ex(ex);
1126
 
}
1127
 
 
1128
 
void
1129
 
camel_exception_drop(struct _CamelExceptionEnv *env)
1130
 
{
1131
 
#ifdef ENABLE_THREADS
1132
 
        pthread_setspecific(handler_key, env->parent);
1133
 
#else
1134
 
        handler = env->parent;
1135
 
#endif
1136
 
}
1137
 
 
1138
 
void
1139
 
camel_exception_done(struct _CamelExceptionEnv *env)
1140
 
{
1141
 
#ifdef ENABLE_THREADS
1142
 
        pthread_setspecific(handler_key, env->parent);
1143
 
#else
1144
 
        handler = env->parent;
1145
 
#endif
1146
 
        if (env->ex != NULL) {
1147
 
                camel_exception_free(env->ex);
1148
 
        }
1149
 
}