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"
15
#include "camel-imapp-engine.h"
16
#include "camel-imapp-exception.h"
17
#include "camel-imapp-stream.h"
18
#include "camel-imapp-utils.h"
21
#define c(x) /* command build debug */
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);
27
CamelIMAPPEngineFunc func;
33
class_init(CamelIMAPPEngineClass *ieclass)
35
ieclass->tagprefix = 'A';
37
camel_object_class_add_event((CamelObjectClass *)ieclass, "status", NULL);
41
object_init(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass)
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);
47
ie->port = camel_msgport_new();
49
ie->tagprefix = ieclass->tagprefix;
51
if (ieclass->tagprefix > 'Z')
52
ieclass->tagprefix = 'A';
55
ie->state = IMAP_ENGINE_DISCONNECT;
59
handler_free(gpointer key, gpointer mem, gpointer data)
65
object_finalise(CamelIMAPPEngine *ie, CamelIMAPPEngineClass *ieclass)
67
/* FIXME: need to free the commands ... */
68
while (camel_imapp_engine_iterate(ie, NULL) > 0)
71
g_hash_table_foreach(ie->handlers, (GHFunc)handler_free, NULL);
72
g_hash_table_destroy(ie->handlers);
76
camel_imapp_engine_get_type (void)
78
static CamelType type = CAMEL_INVALID_TYPE;
80
if (type == CAMEL_INVALID_TYPE) {
81
type = camel_type_register (
82
camel_object_get_type (),
84
sizeof (CamelIMAPPEngine),
85
sizeof (CamelIMAPPEngineClass),
86
(CamelObjectClassInitFunc) class_init,
88
(CamelObjectInitFunc) object_init,
89
(CamelObjectFinalizeFunc) object_finalise);
95
/* FIXME: check this, just taken from old code, not rfc */
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 },
110
capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
112
;; IMAP4rev1 servers which offer RFC 1730
113
;; compatibility MUST list "IMAP4" as the first
116
static gint resp_capability(CamelIMAPPEngine *ie, guint32 id, gpointer data)
119
guchar *token, *p, c;
121
/* FIXME: handle auth types */
123
printf("got capability response:\n");
125
tok = camel_imapp_stream_token(ie->stream, &token, &len);
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;
140
case IMAP_TOK_PROTOCOL:
141
camel_imapp_engine_skip(ie);
144
printf("Unknown Response token %02x '%c'\n", tok, isprint(tok)?tok:'.');
146
} while (tok != '\n');
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)
156
printf("message expunged: %d\n", id);
158
return camel_imapp_engine_skip(ie);
161
static gint resp_flags(CamelIMAPPEngine *ie, guint32 id, gpointer data)
165
imap_parse_flags(ie->stream, &flags);
167
printf("flags: %08x\n", flags);
169
return camel_imapp_engine_skip(ie);
173
static gint resp_exists(CamelIMAPPEngine *ie, guint32 id, gpointer data)
175
printf("messages exist: %d\n", id);
177
if (ie->select_response)
178
ie->select_response->exists = id;
180
return camel_imapp_engine_skip(ie);
183
static gint resp_recent(CamelIMAPPEngine *ie, guint32 id, gpointer data)
185
printf("messages recent: %d\n", id);
187
if (ie->select_response)
188
ie->select_response->recent = id;
190
return camel_imapp_engine_skip(ie);
193
static gint resp_fetch(CamelIMAPPEngine *ie, guint32 id, gpointer data)
195
struct _fetch_info *finfo;
197
finfo = imap_parse_fetch(ie->stream);
198
imap_dump_fetch(finfo);
199
imap_free_fetch(finfo);
201
return camel_imapp_engine_skip(ie);
205
static gint resp_list(CamelIMAPPEngine *ie, guint32 id, gpointer data)
207
struct _list_info *linfo;
209
linfo = imap_parse_list(ie->stream);
210
printf("list: '%s' (%c)\n", linfo->name, linfo->separator);
211
imap_free_list(linfo);
213
return camel_imapp_engine_skip(ie);
218
camel_imapp_engine_new(CamelIMAPPStream *stream)
220
CamelIMAPPEngine * volatile engine;
222
engine = CAMEL_IMAPP_ENGINE (camel_object_new (CAMEL_IMAPP_ENGINE_TYPE));
223
engine->stream = stream;
224
camel_object_ref((CamelObject *)stream);
226
camel_imapp_engine_add_handler(engine, "CAPABILITY", resp_capability, engine);
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);
234
camel_imapp_engine_add_handler(engine, "LIST", (CamelIMAPPEngineFunc)resp_list, engine);
235
camel_imapp_engine_add_handler(engine, "LSUB", (CamelIMAPPEngineFunc)resp_list, engine);
238
camel_imapp_engine_add_handler(engine, "EXPUNGE", (CamelIMAPPEngineFunc)resp_expunge, engine);
239
camel_imapp_engine_add_handler(engine, "FETCH", (CamelIMAPPEngineFunc)resp_fetch, engine);
241
/* TODO: move this to a driver:connect call? */
247
tok = camel_imapp_stream_token(stream, &token, &len);
249
struct _status_info *sinfo = imap_parse_status(stream);
251
switch (sinfo->result) {
253
engine->state = IMAP_ENGINE_CONNECT;
254
printf("Server connected ok: %s\n", sinfo->text);
257
printf("pre-authenticated ...\n");
258
engine->state = IMAP_ENGINE_AUTH;
261
imap_free_status(sinfo);
262
camel_exception_throw(1, "Server refused connection: %s", sinfo->text);
265
imap_free_status(sinfo);
267
engine->state = IMAP_ENGINE_CONNECT;
268
printf("unknwon server greeting, ignored\n");
269
camel_imapp_engine_skip(engine);
271
camel_imapp_engine_capabilities(engine);
273
printf("connection failed: %s\n", ex->desc);
274
camel_object_unref((CamelObject *)engine);
282
camel_imapp_engine_add_handler(CamelIMAPPEngine *imap, const gchar *response, CamelIMAPPEngineFunc func, gpointer data)
288
h = g_malloc0(sizeof(*h) + strlen(response));
298
g_hash_table_insert(imap->handlers, h->name, h);
302
camel_imapp_engine_capabilities(CamelIMAPPEngine *ie)
304
CamelIMAPPCommand *ic;
306
/* reset capabilities */
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)
313
camel_imapp_engine_command_free(ie, ic);
318
/* skip the rest of the line of tokens */
320
camel_imapp_engine_skip(CamelIMAPPEngine *imap)
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);
334
} while (tok != '\n' && tok >= 0);
342
/* handle any untagged responses */
344
iterate_untagged(CamelIMAPPEngine *imap)
347
guchar *token, *p, c;
350
struct _status_info *sinfo;
352
e(printf("got untagged response\n"));
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);
361
camel_exception_throw(1, "truncated server response");
363
e(printf("Have token '%s' id %d\n", token, id));
368
/* first, check for generic unsolicited response */
369
h = g_hash_table_lookup(imap->handlers, token);
371
tok = h->func(imap, id, h->data);
377
/* TODO: apart from bye/preauth, these could be callbacks/events? */
379
/* now, check for status responses */
380
switch (imap_tokenise(token, len)) {
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);
394
switch (sinfo->condition) {
395
case IMAP_READ_WRITE:
396
printf("folder is read-write\n");
399
printf("folder is read-only\n");
401
case IMAP_UIDVALIDITY:
402
if (imap->select_response)
403
imap->select_response->uidvalidity = sinfo->u.uidvalidity;
406
/* not defined yet ... */
408
printf("got uidnext for folder: %d\n", sinfo->u.uidnext);
412
if (imap->select_response)
413
imap->select_response->unseen = sinfo->u.unseen;
415
case IMAP_PERMANENTFLAGS:
416
if (imap->select_response)
417
imap->select_response->permanentflags = sinfo->u.permanentflags;
420
printf("ALERT!: %s\n", sinfo->text);
423
printf("PARSE: %s\n", sinfo->text);
431
printf("unknown token: %s\n", token);
432
camel_imapp_engine_skip(imap);
433
/* unknown response, just ignore it */
439
/* handle any continuation requests
440
either data continuations, or auth continuation */
442
iterate_continuation(CamelIMAPPEngine *imap)
444
CamelIMAPPCommand *ic;
445
CamelIMAPPCommandPart *cp;
447
printf("got continuation response\n");
450
imap->literal = NULL;
452
camel_imapp_engine_skip(imap);
453
printf("got continuation response with no outstanding continuation requests?\n");
457
printf("got continuation response for data\n");
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);
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);
468
case CAMEL_IMAPP_COMMAND_AUTH: {
469
CamelException *ex = camel_exception_new();
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);
480
printf("got auth continuation, feeding token '%s' back to auth mech\n", resp);
482
camel_stream_write((CamelStream *)imap->stream, resp, strlen(resp));
484
/* we want to keep getting called until we get a status reponse from the server
485
ignore what sasl tells us */
490
/* should we just ignore? */
491
camel_exception_throw(1, "continuation response for non-continuation request");
494
camel_imapp_engine_skip(imap);
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) {
504
g_assert(cp->next->next == NULL);
507
printf("%p: queueing continuation\n", ic);
508
camel_stream_printf((CamelStream *)imap->stream, "\r\n");
511
if (imap->literal == NULL) {
512
ic = (CamelIMAPPCommand *)camel_dlist_remhead(&imap->queue);
514
printf("found outstanding op, queueing\n");
515
camel_imapp_engine_command_queue(imap, ic);
522
/* handle a completion line */
524
iterate_completion(CamelIMAPPEngine *imap, guchar *token)
526
CamelIMAPPCommand *ic;
529
if (token[0] != imap->tagprefix)
530
camel_exception_throw(1, "Server sent unexpected response: %s", token);
532
tag = strtoul(token+1, NULL, 10);
533
ic = camel_imapp_engine_command_find_tag(imap, tag);
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);
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;
554
ic->complete(imap, ic, ic->complete_data);
556
camel_exception_throw(1, "got response tag unexpectedly: %s", token);
559
if (imap->literal != NULL) {
560
printf("Warning: continuation command '%s' finished with outstanding continuation\n", imap->literal->name);
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;
568
ic = (CamelIMAPPCommand *)camel_dlist_remhead(&imap->queue);
570
printf("found outstanding op, queueing\n");
571
camel_imapp_engine_command_queue(imap, ic);
577
/* Do work if there's any to do */
579
camel_imapp_engine_iterate(CamelIMAPPEngine *imap, CamelIMAPPCommand *icwait)
580
/* throws IO,PARSE exception */
586
if ((icwait && icwait->status != NULL) || camel_dlist_empty(&imap->active))
589
/* handle exceptions here? */
593
tok = camel_imapp_stream_token(imap->stream, &token, &len);
595
iterate_untagged(imap);
596
else if (tok == IMAP_TOK_TOKEN)
597
iterate_completion(imap, token);
599
iterate_continuation(imap);
601
camel_exception_throw(1, "unexpected server response: %s", token);
603
if (camel_dlist_empty(&imap->active))
610
camel_imapp_engine_command_new(CamelIMAPPEngine *imap, const gchar *name, const gchar *select, const gchar *fmt, ...)
612
CamelIMAPPCommand *ic;
615
ic = g_malloc0(sizeof(*ic));
616
ic->tag = imap->tag++;
618
ic->mem = (CamelStreamMem *)camel_stream_mem_new();
619
ic->select = g_strdup(select);
620
camel_dlist_init(&ic->parts);
624
imap_engine_command_addv(imap, ic, fmt, ap);
632
camel_imapp_engine_command_add(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const gchar *fmt, ...)
636
g_assert(ic->mem); /* gets reset on queue */
640
imap_engine_command_addv(imap, ic, fmt, ap);
646
camel_imapp_engine_command_complete(CamelIMAPPEngine *imap, struct _CamelIMAPPCommand *ic, CamelIMAPPCommandFunc func, gpointer data)
649
ic->complete_data = data;
652
/* FIXME: make imap command's refcounted? */
654
camel_imapp_engine_command_free (CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
656
CamelIMAPPCommandPart *cp, *cn;
661
/* Note the command must not be in any queue? */
664
camel_object_unref((CamelObject *)ic->mem);
665
imap_free_status(ic->status);
668
while ( (cp = ((CamelIMAPPCommandPart *)camel_dlist_remhead(&ic->parts))) ) {
671
camel_object_unref(cp->ob);
678
/* FIXME: error handling */
680
camel_imapp_engine_command_queue(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
682
CamelIMAPPCommandPart *cp;
684
g_assert(ic->msg.reply_port);
687
imap_engine_command_complete(imap, ic);
689
camel_msgport_push(imap->port, (CamelMsg *)ic);
693
camel_imapp_engine_command_find (CamelIMAPPEngine *imap, const gchar *name)
695
CamelIMAPPCommand *ic, *in;
698
if (ic && strcmp(ic->name, name) == 0)
701
/* first, try active */
702
ic = (CamelIMAPPCommand *)imap->active.head;
703
in = ic->msg.ln.next;
705
if (strcmp(ic->name, name) == 0)
708
in = in->msg.ln.next;
715
camel_imapp_engine_command_find_tag(CamelIMAPPEngine *imap, guint tag)
717
CamelIMAPPCommand *ic, *in;
720
if (ic && ic->tag == tag)
723
ic = (CamelIMAPPCommand *)imap->active.head;
724
in = ic->msg.ln.next;
729
in = in->msg.ln.next;
735
/* ********************************************************************** */
737
CamelIMAPPSelectResponse *
738
camel_imapp_engine_select(CamelIMAPPEngine *imap, const gchar *name)
740
CamelIMAPPSelectResponse * volatile resp;
741
CamelIMAPPCommand * volatile ic = NULL;
743
resp = g_malloc0(sizeof(*resp));
744
imap->select_response = resp;
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)
752
if (ic->status->result != IMAP_OK)
753
camel_exception_throw(1, "select failed: %s", ic->status->text);
754
resp->status = ic->status;
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);
763
camel_imapp_engine_command_free(imap, ic);
764
imap->select_response = NULL;
770
camel_imapp_engine_select_free(CamelIMAPPEngine *imap, CamelIMAPPSelectResponse *select)
773
imap_free_status(select->status);
778
/* ********************************************************************** */
781
imap_engine_command_add_part(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, camel_imapp_command_part_t type, CamelObject *ob)
783
CamelIMAPPCommandPart *cp;
784
CamelStreamNull *null;
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);
794
camel_stream_reset((CamelStream *)ob);
795
camel_stream_write_to_stream((CamelStream *)ob, (CamelStream *)null);
796
camel_stream_reset((CamelStream *)ob);
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);
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;
815
cp = g_malloc0(sizeof(*cp));
817
cp->ob_size = ob_size;
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;
824
camel_stream_reset((CamelStream *)ic->mem);
825
/* FIXME: hackish? */
826
g_byte_array_set_size(ic->mem->buffer, 0);
828
camel_dlist_addtail(&ic->parts, (CamelDListNode *)cp);
832
static gint len(CamelDList *list)
835
CamelDListNode *n = list->head;
846
imap_engine_command_complete(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic)
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);
853
c(printf("command has %d parts\n", len(&ic->parts)));
855
camel_object_unref((CamelObject *)ic->mem);
860
imap_engine_command_addv(CamelIMAPPEngine *imap, CamelIMAPPCommand *ic, const gchar *fmt, va_list ap)
862
const guchar *p, *ps, *start;
879
c(printf("adding command, fmt = '%s'\n", fmt));
883
while ( ( c = *p++ ) ) {
887
camel_stream_write((CamelStream *)ic->mem, ps, p-ps);
891
camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1);
911
width = width * 10 + (c-'0');
914
} while ((c = *p++));
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);
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);
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);
936
case 't': /* token */
937
s = va_arg(ap, gchar *);
938
camel_stream_write((CamelStream *)ic->mem, s, strlen(s));
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);
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:"");
953
case 'F': /* IMAP flags set */
954
f = va_arg(ap, guint32);
955
imap_write_flags((CamelStream *)ic->mem, f);
958
d = va_arg(ap, gint);
960
camel_stream_write((CamelStream *)ic->mem, &ch, 1);
962
case 'd': /* int/unsigned */
965
l = va_arg(ap, gglong);
966
c(printf("got gglong '%d'\n", (gint)l));
967
memcpy(buffer, start, p-start);
969
camel_stream_printf((CamelStream *)ic->mem, buffer, l);
971
d = va_arg(ap, gint);
972
c(printf("got gint '%d'\n", d));
973
memcpy(buffer, start, p-start);
975
camel_stream_printf((CamelStream *)ic->mem, buffer, d);
983
case '\\': /* only for \\ really, we dont support \n\r etc at all */
987
camel_stream_write((CamelStream *)ic->mem, ps, p-ps);
994
camel_stream_write((CamelStream *)ic->mem, ps, p-ps-1);
998
cie_worker(gpointer data)
1000
CamelIMAPPCommand *ic = data;
1001
CamelIMAPPEngine *imap;
1002
CamelIMAPPCommandPart *cp;
1004
/* FIXME: remove select stuff */
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;
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 */
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? */
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);
1027
cp = (CamelIMAPPCommandPart *)ic->parts.head;
1031
/* how to handle exceptions here? */
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);
1036
if (cp->type & CAMEL_IMAPP_COMMAND_CONTINUATION) {
1037
printf("%p: active literal\n", ic);
1040
camel_dlist_addtail(&imap->active, (CamelDListNode *)ic);
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);
1048
/* here temporarily while its experimental */
1050
#ifdef ENABLE_THREADS
1051
#include <pthread.h>
1053
static pthread_key_t handler_key = 0;
1055
void camel_exception_setup(void)
1057
pthread_key_create(&handler_key, NULL);
1061
/* this is per-thread in threaded mode */
1062
static struct _CamelExceptionEnv *handler = NULL;
1064
void camel_exception_setup(void)
1070
camel_exception_try(struct _CamelExceptionEnv *env)
1072
#ifdef ENABLE_THREADS
1073
struct _CamelExceptionEnv *handler;
1075
handler = pthread_getspecific(handler_key);
1077
env->parent = handler;
1081
#ifdef ENABLE_THREADS
1082
pthread_setspecific(handler_key, handler);
1087
camel_exception_throw_ex(CamelException *ex)
1089
struct _CamelExceptionEnv *env;
1090
#ifdef ENABLE_THREADS
1091
struct _CamelExceptionEnv *handler;
1093
handler = pthread_getspecific(handler_key);
1095
printf("throwing exception '%s'\n", ex->desc);
1100
handler = env->parent;
1101
#ifdef ENABLE_THREADS
1102
pthread_setspecific(handler_key, handler);
1104
longjmp(env->env, ex->id);
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 */
1114
camel_exception_throw(gint id, gchar *fmt, ...)
1119
ex = camel_exception_new();
1122
ex->desc = g_strdup_vprintf(fmt, ap);
1125
camel_exception_throw_ex(ex);
1129
camel_exception_drop(struct _CamelExceptionEnv *env)
1131
#ifdef ENABLE_THREADS
1132
pthread_setspecific(handler_key, env->parent);
1134
handler = env->parent;
1139
camel_exception_done(struct _CamelExceptionEnv *env)
1141
#ifdef ENABLE_THREADS
1142
pthread_setspecific(handler_key, env->parent);
1144
handler = env->parent;
1146
if (env->ex != NULL) {
1147
camel_exception_free(env->ex);