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

« back to all changes in this revision

Viewing changes to camel/providers/imapp/camel-imapp-utils.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
 
 
2
 
#include <ctype.h>
3
 
#include <errno.h>
4
 
#include <string.h>
5
 
 
6
 
#include "camel-folder-summary.h"
7
 
#include "camel-store.h"
8
 
#include "camel-string-utils.h"
9
 
#include "camel-utf8.h"
10
 
 
11
 
#include "camel-imapp-engine.h"
12
 
#include "camel-imapp-exception.h"
13
 
#include "camel-imapp-folder.h"
14
 
#include "camel-imapp-stream.h"
15
 
#include "camel-imapp-utils.h"
16
 
 
17
 
/* high-level parser state */
18
 
#define p(x)
19
 
/* debug */
20
 
#define d(x)
21
 
 
22
 
/* ANSI-C code produced by gperf version 2.7 */
23
 
/* Command-line: gperf -H imap_hash -N imap_tokenise -L ANSI-C -o -t -k1,$ imap-tokens.txt  */
24
 
struct _imap_keyword { gchar *name; camel_imapp_id_t id; };
25
 
/*
26
 
 gperf input file
27
 
 best hash generated using: gperf -o -s-2 -k1,'$' -t -H imap_hash -N imap_tokenise -L ANSI-C
28
 
*/
29
 
 
30
 
#define TOTAL_KEYWORDS 23
31
 
#define MIN_WORD_LENGTH 2
32
 
#define MAX_WORD_LENGTH 14
33
 
#define MIN_HASH_VALUE 2
34
 
#define MAX_HASH_VALUE 38
35
 
/* maximum key range = 37, duplicates = 0 */
36
 
 
37
 
#ifdef __GNUC__
38
 
__inline
39
 
#endif
40
 
static guint
41
 
imap_hash (register const gchar *str, register guint len)
42
 
{
43
 
  static guchar asso_values[] =
44
 
    {
45
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
46
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
47
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
48
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
49
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
50
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
51
 
      39, 39, 39, 39, 39, 10, 15, 39, 20,  0,
52
 
       0, 39,  0, 10, 39,  0, 39, 39, 10,  0,
53
 
       0, 39,  0, 10,  5, 10, 39, 39, 39,  0,
54
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
55
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
56
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
57
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
58
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
59
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
60
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
61
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
62
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
63
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
64
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
65
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
66
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
67
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
68
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
69
 
      39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
70
 
      39, 39, 39, 39, 39, 39
71
 
    };
72
 
  return len + asso_values[(guchar)str[len - 1]] + asso_values[(guchar)str[0]];
73
 
}
74
 
 
75
 
#ifdef __GNUC__
76
 
__inline
77
 
#endif
78
 
camel_imapp_id_t
79
 
imap_tokenise (register const gchar *str, register guint len)
80
 
{
81
 
  static struct _imap_keyword wordlist[] =
82
 
    {
83
 
      {""}, {""},
84
 
      {"OK",            IMAP_OK},
85
 
      {""}, {""},
86
 
      {"PARSE",         IMAP_PARSE},
87
 
      {""},
88
 
      {"PREAUTH",       IMAP_PREAUTH},
89
 
      {"ENVELOPE",      IMAP_ENVELOPE},
90
 
      {"READ-ONLY",     IMAP_READ_ONLY},
91
 
      {"READ-WRITE",    IMAP_READ_WRITE},
92
 
      {"RFC822.SIZE",   IMAP_RFC822_SIZE},
93
 
      {"NO",            IMAP_NO},
94
 
      {"RFC822.HEADER", IMAP_RFC822_HEADER},
95
 
      {"TRYCREATE",     IMAP_TRYCREATE},
96
 
      {"FLAGS",         IMAP_FLAGS},
97
 
      {"RFC822.TEXT",   IMAP_RFC822_TEXT},
98
 
      {"NEWNAME",       IMAP_NEWNAME},
99
 
      {"BYE",           IMAP_BYE},
100
 
      {"BODY",          IMAP_BODY},
101
 
      {"ALERT",          IMAP_ALERT},
102
 
      {"UIDVALIDITY",   IMAP_UIDVALIDITY},
103
 
      {"INTERNALDATE",  IMAP_INTERNALDATE},
104
 
      {""},
105
 
      {"PERMANENTFLAGS",        IMAP_PERMANENTFLAGS},
106
 
      {""},
107
 
      {"UNSEEN",                IMAP_UNSEEN},
108
 
      {""},
109
 
      {"BODYSTRUCTURE", IMAP_BODYSTRUCTURE},
110
 
      {""}, {""}, {""}, {""},
111
 
      {"UID",           IMAP_UID},
112
 
      {""}, {""}, {""}, {""},
113
 
      {"BAD",           IMAP_BAD}
114
 
    };
115
 
 
116
 
  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
117
 
    {
118
 
      register gint key = imap_hash (str, len);
119
 
 
120
 
      if (key <= MAX_HASH_VALUE && key >= 0)
121
 
        {
122
 
          register const gchar *s = wordlist[key].name;
123
 
 
124
 
          if (*str == *s && !strcmp (str + 1, s + 1))
125
 
            return wordlist[key].id;
126
 
        }
127
 
    }
128
 
  return 0;
129
 
}
130
 
 
131
 
/* flag table */
132
 
static struct {
133
 
        gchar *name;
134
 
        guint32 flag;
135
 
} flag_table[] = {
136
 
        { "\\ANSWERED", CAMEL_MESSAGE_ANSWERED },
137
 
        { "\\DELETED", CAMEL_MESSAGE_DELETED },
138
 
        { "\\DRAFT", CAMEL_MESSAGE_DRAFT },
139
 
        { "\\FLAGGED", CAMEL_MESSAGE_FLAGGED },
140
 
        { "\\SEEN", CAMEL_MESSAGE_SEEN },
141
 
        { "\\RECENT", CAMEL_IMAPP_MESSAGE_RECENT },
142
 
        { "\\*", CAMEL_MESSAGE_USER },
143
 
};
144
 
 
145
 
/* utility functions
146
 
   shoudl this be part of imapp-driver? */
147
 
/* mabye this should be a stream op? */
148
 
void
149
 
imap_parse_flags(CamelIMAPPStream *stream, guint32 *flagsp)
150
 
/* throws IO,PARSE exception */
151
 
{
152
 
        gint tok, len, i;
153
 
        guchar *token, *p, c;
154
 
        guint32 flags = 0;
155
 
 
156
 
        *flagsp = flags;
157
 
 
158
 
        tok = camel_imapp_stream_token(stream, &token, &len);
159
 
        if (tok == '(') {
160
 
                do {
161
 
                        tok = camel_imapp_stream_token(stream, &token, &len);
162
 
                        if (tok == IMAP_TOK_TOKEN) {
163
 
                                p = token;
164
 
                                while ((c=*p))
165
 
                                        *p++ = toupper(c);
166
 
                                for (i=0;i<(gint)(sizeof(flag_table)/sizeof(flag_table[0]));i++)
167
 
                                        if (!strcmp(token, flag_table[i].name))
168
 
                                                flags |= flag_table[i].flag;
169
 
                        } else if (tok != ')') {
170
 
                                camel_exception_throw(1, "expecting flag");
171
 
                        }
172
 
                } while (tok != ')');
173
 
        } else {
174
 
                camel_exception_throw(1, "expecting flag list");
175
 
        }
176
 
 
177
 
        *flagsp = flags;
178
 
}
179
 
 
180
 
void
181
 
imap_write_flags(CamelStream *stream, guint32 flags)
182
 
/* throws IO exception */
183
 
{
184
 
        gint i;
185
 
 
186
 
        /* all this ugly exception throwing goes away once camel streams throw their own? */
187
 
        if (camel_stream_write(stream, "(", 1) == -1)
188
 
                camel_exception_throw(1, "io error: %s", g_strerror(errno));
189
 
 
190
 
        for (i=0;flags!=0 && i<(gint)(sizeof(flag_table)/sizeof(flag_table[0]));i++) {
191
 
                if (flag_table[i].flag & flags) {
192
 
                        if (camel_stream_write(stream, flag_table[i].name, strlen(flag_table[i].name)) == -1)
193
 
                                camel_exception_throw(1, "io error: %s", g_strerror(errno));
194
 
                        flags &= ~flag_table[i].flag;
195
 
                        if (flags != 0)
196
 
                                if (camel_stream_write(stream, " ", 1) == -1)
197
 
                                        camel_exception_throw(1, "io error: %s", g_strerror(errno));
198
 
                }
199
 
        }
200
 
 
201
 
        if (camel_stream_write(stream, ")", 1) == -1)
202
 
                camel_exception_throw(1, "io error: %s", g_strerror(errno));
203
 
}
204
 
 
205
 
/*
206
 
body            ::= "(" body_type_1part / body_type_mpart ")"
207
 
 
208
 
body_extension  ::= nstring / number / "(" 1#body_extension ")"
209
 
                    ;; Future expansion.  Client implementations
210
 
                    ;; MUST accept body_extension fields.  Server
211
 
                    ;; implementations MUST NOT generate
212
 
                    ;; body_extension fields except as defined by
213
 
                    ;; future standard or standards-track
214
 
                    ;; revisions of this specification.
215
 
 
216
 
body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
217
 
                    [SPACE body_fld_lang
218
 
                    [SPACE 1#body_extension]]]
219
 
                    ;; MUST NOT be returned on non-extensible
220
 
                    ;; "BODY" fetch
221
 
 
222
 
body_ext_mpart  ::= body_fld_param
223
 
                    [SPACE body_fld_dsp SPACE body_fld_lang
224
 
                    [SPACE 1#body_extension]]
225
 
                    ;; MUST NOT be returned on non-extensible
226
 
                    ;; "BODY" fetch
227
 
 
228
 
body_fields     ::= body_fld_param SPACE body_fld_id SPACE
229
 
                    body_fld_desc SPACE body_fld_enc SPACE
230
 
                    body_fld_octets
231
 
 
232
 
body_fld_desc   ::= nstring
233
 
 
234
 
body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil
235
 
 
236
 
body_fld_enc    ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
237
 
                    "QUOTED-PRINTABLE") <">) / string
238
 
 
239
 
body_fld_id     ::= nstring
240
 
 
241
 
body_fld_lang   ::= nstring / "(" 1#string ")"
242
 
 
243
 
body_fld_lines  ::= number
244
 
 
245
 
body_fld_md5    ::= nstring
246
 
 
247
 
body_fld_octets ::= number
248
 
 
249
 
body_fld_param  ::= "(" 1#(string SPACE string) ")" / nil
250
 
 
251
 
body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
252
 
                    [SPACE body_ext_1part]
253
 
 
254
 
body_type_basic ::= media_basic SPACE body_fields
255
 
                    ;; MESSAGE subtype MUST NOT be "RFC822"
256
 
 
257
 
body_type_mpart ::= 1*body SPACE media_subtype
258
 
                    [SPACE body_ext_mpart]
259
 
 
260
 
body_type_msg   ::= media_message SPACE body_fields SPACE envelope
261
 
                    SPACE body SPACE body_fld_lines
262
 
 
263
 
body_type_text  ::= media_text SPACE body_fields SPACE body_fld_lines
264
 
 
265
 
envelope        ::= "(" env_date SPACE env_subject SPACE env_from
266
 
                    SPACE env_sender SPACE env_reply_to SPACE env_to
267
 
                    SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
268
 
                    SPACE env_message_id ")"
269
 
 
270
 
env_bcc         ::= "(" 1*address ")" / nil
271
 
 
272
 
env_cc          ::= "(" 1*address ")" / nil
273
 
 
274
 
env_date        ::= nstring
275
 
 
276
 
env_from        ::= "(" 1*address ")" / nil
277
 
 
278
 
env_in_reply_to ::= nstring
279
 
 
280
 
env_message_id  ::= nstring
281
 
 
282
 
env_reply_to    ::= "(" 1*address ")" / nil
283
 
 
284
 
env_sender      ::= "(" 1*address ")" / nil
285
 
 
286
 
env_subject     ::= nstring
287
 
 
288
 
env_to          ::= "(" 1*address ")" / nil
289
 
 
290
 
media_basic     ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
291
 
                    "MESSAGE" / "VIDEO") <">) / string)
292
 
                    SPACE media_subtype
293
 
                    ;; Defined in [MIME-IMT]
294
 
 
295
 
media_message   ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">
296
 
                    ;; Defined in [MIME-IMT]
297
 
 
298
 
media_subtype   ::= string
299
 
                    ;; Defined in [MIME-IMT]
300
 
 
301
 
media_text      ::= <"> "TEXT" <"> SPACE media_subtype
302
 
                    ;; Defined in [MIME-IMT]
303
 
 
304
 
 ( "type" "subtype"  body_fields [envelope body body_fld_lines]
305
 
                                 [body_fld_lines]
306
 
 
307
 
 (("TEXT" "PLAIN" ("CHARSET"
308
 
                     "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN"
309
 
                     ("CHARSET" "US-ASCII" "NAME" "cc.diff")
310
 
                     "<960723163407.20117h@cac.washington.edu>"
311
 
                     "Compiler diff" "BASE64" 4554 73) "MIXED"))
312
 
 
313
 
*/
314
 
 
315
 
/*
316
 
struct _body_fields {
317
 
        CamelContentType *ct;
318
 
        gchar *msgid, *desc;
319
 
        CamelTransferEncoding encoding;
320
 
        guint32 size;
321
 
        };*/
322
 
 
323
 
void
324
 
imap_free_body(struct _CamelMessageContentInfo *cinfo)
325
 
{
326
 
        struct _CamelMessageContentInfo *list, *next;
327
 
 
328
 
        list = cinfo->childs;
329
 
        while (list) {
330
 
                next = list->next;
331
 
                imap_free_body(list);
332
 
                list = next;
333
 
        }
334
 
 
335
 
        if (cinfo->type)
336
 
                camel_content_type_unref(cinfo->type);
337
 
        g_free(cinfo->id);
338
 
        g_free(cinfo->description);
339
 
        g_free(cinfo->encoding);
340
 
        g_free(cinfo);
341
 
}
342
 
 
343
 
void
344
 
imap_parse_param_list(CamelIMAPPStream *is, struct _camel_header_param **plist)
345
 
{
346
 
        gint tok, len;
347
 
        guchar *token, *param;
348
 
 
349
 
        p(printf("body_fld_param\n"));
350
 
 
351
 
        /* body_fld_param  ::= "(" 1#(string SPACE string) ")" / nil */
352
 
        tok = camel_imapp_stream_token(is, &token, &len);
353
 
        if (tok == '(') {
354
 
                while (1) {
355
 
                        tok = camel_imapp_stream_token(is, &token, &len);
356
 
                        if (tok == ')')
357
 
                                break;
358
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
359
 
 
360
 
                        camel_imapp_stream_astring(is, &token);
361
 
                        param = alloca(strlen(token)+1);
362
 
                        strcpy(param, token);
363
 
                        camel_imapp_stream_astring(is, &token);
364
 
                        camel_header_set_param(plist, param, token);
365
 
                }
366
 
        } /* else check nil?  no need */
367
 
}
368
 
 
369
 
struct _CamelContentDisposition *
370
 
imap_parse_ext_optional(CamelIMAPPStream *is)
371
 
{
372
 
        gint tok, len;
373
 
        guchar *token;
374
 
        struct _CamelContentDisposition * volatile dinfo = NULL;
375
 
 
376
 
        /* this parses both extension types, from the body_fld_dsp onwards */
377
 
        /* although the grammars are different, they can be parsed the same way */
378
 
 
379
 
        /* body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
380
 
           [SPACE body_fld_lang
381
 
           [SPACE 1#body_extension]]]
382
 
           ;; MUST NOT be returned on non-extensible
383
 
           ;; "BODY" fetch */
384
 
 
385
 
        /* body_ext_mpart  ::= body_fld_param
386
 
           [SPACE body_fld_dsp SPACE body_fld_lang
387
 
           [SPACE 1#body_extension]]
388
 
           ;; MUST NOT be returned on non-extensible
389
 
           ;; "BODY" fetch */
390
 
 
391
 
        CAMEL_TRY {
392
 
                /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
393
 
 
394
 
                tok = camel_imapp_stream_token(is, &token, &len);
395
 
                switch (tok) {
396
 
                case '(':
397
 
                        dinfo = g_malloc0(sizeof(*dinfo));
398
 
                        dinfo->refcount = 1;
399
 
                        /* should be string */
400
 
                        camel_imapp_stream_astring(is, &token);
401
 
 
402
 
                        dinfo->disposition = g_strdup(token);
403
 
                        imap_parse_param_list(is, &dinfo->params);
404
 
                case IMAP_TOK_TOKEN:
405
 
                        d(printf("body_fld_dsp: NIL\n"));
406
 
                        break;
407
 
                default:
408
 
                        camel_exception_throw(1, "body_fld_disp: expecting nil or list");
409
 
                }
410
 
 
411
 
                p(printf("body_fld_lang\n"));
412
 
 
413
 
                /* body_fld_lang   ::= nstring / "(" 1#string ")" */
414
 
 
415
 
                /* we just drop the lang string/list, save it somewhere? */
416
 
 
417
 
                tok = camel_imapp_stream_token(is, &token, &len);
418
 
                switch (tok) {
419
 
                case '(':
420
 
                        while (1) {
421
 
                                tok = camel_imapp_stream_token(is, &token, &len);
422
 
                                if (tok == ')') {
423
 
                                        break;
424
 
                                } else if (tok != IMAP_TOK_STRING) {
425
 
                                        camel_exception_throw(1, "expecting string");
426
 
                                }
427
 
                        }
428
 
                        break;
429
 
                case IMAP_TOK_TOKEN:
430
 
                        d(printf("body_fld_lang = nil\n"));
431
 
                        /* treat as 'nil' */
432
 
                        break;
433
 
                case IMAP_TOK_STRING:
434
 
                        /* we have a string */
435
 
                        break;
436
 
                case IMAP_TOK_LITERAL:
437
 
                        /* we have a literal string */
438
 
                        camel_imapp_stream_set_literal(is, len);
439
 
                        while ((tok = camel_imapp_stream_getl(is, &token, &len)) > 0) {
440
 
                                d(printf("Skip literal data '%.*s'\n", (gint)len, token));
441
 
                        }
442
 
                        break;
443
 
 
444
 
                }
445
 
        } CAMEL_CATCH(ex) {
446
 
                if (dinfo)
447
 
                        camel_content_disposition_unref(dinfo);
448
 
                camel_exception_throw_ex(ex);
449
 
        } CAMEL_DONE;
450
 
 
451
 
        return dinfo;
452
 
}
453
 
 
454
 
struct _CamelMessageContentInfo *
455
 
imap_parse_body_fields(CamelIMAPPStream *is)
456
 
{
457
 
        guchar *token, *type;
458
 
        struct _CamelMessageContentInfo *cinfo;
459
 
 
460
 
        /* body_fields     ::= body_fld_param SPACE body_fld_id SPACE
461
 
           body_fld_desc SPACE body_fld_enc SPACE
462
 
           body_fld_octets */
463
 
 
464
 
        p(printf("body_fields\n"));
465
 
 
466
 
        cinfo = g_malloc0(sizeof(*cinfo));
467
 
 
468
 
        CAMEL_TRY {
469
 
                /* this should be string not astring */
470
 
                camel_imapp_stream_astring(is, &token);
471
 
                type = alloca(strlen(token)+1);
472
 
                strcpy(type, token);
473
 
                camel_imapp_stream_astring(is, &token);
474
 
                cinfo->type = camel_content_type_new(type, token);
475
 
                imap_parse_param_list(is, &cinfo->type->params);
476
 
 
477
 
                /* body_fld_id     ::= nstring */
478
 
                camel_imapp_stream_nstring(is, &token);
479
 
                cinfo->id = g_strdup(token);
480
 
 
481
 
                /* body_fld_desc   ::= nstring */
482
 
                camel_imapp_stream_nstring(is, &token);
483
 
                cinfo->description = g_strdup(token);
484
 
 
485
 
                /* body_fld_enc    ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
486
 
                   "QUOTED-PRINTABLE") <">) / string */
487
 
                camel_imapp_stream_astring(is, &token);
488
 
                cinfo->encoding = g_strdup(token);
489
 
 
490
 
                /* body_fld_octets ::= number */
491
 
                cinfo->size = camel_imapp_stream_number(is);
492
 
        } CAMEL_CATCH(ex) {
493
 
                imap_free_body(cinfo);
494
 
                camel_exception_throw_ex(ex);
495
 
        } CAMEL_DONE;
496
 
 
497
 
        return cinfo;
498
 
}
499
 
 
500
 
struct _camel_header_address *
501
 
imap_parse_address_list(CamelIMAPPStream *is)
502
 
/* throws PARSE,IO exception */
503
 
{
504
 
        gint tok, len;
505
 
        guchar *token, *host, *mbox;
506
 
        struct _camel_header_address *list = NULL;
507
 
 
508
 
        /* "(" 1*address ")" / nil */
509
 
 
510
 
        CAMEL_TRY {
511
 
                tok = camel_imapp_stream_token(is, &token, &len);
512
 
                if (tok == '(') {
513
 
                        while (1) {
514
 
                                struct _camel_header_address *addr, *group = NULL;
515
 
 
516
 
                                /* address         ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
517
 
                                   SPACE addr_host ")" */
518
 
                                tok = camel_imapp_stream_token(is, &token, &len);
519
 
                                if (tok == ')')
520
 
                                        break;
521
 
                                if (tok != '(')
522
 
                                        camel_exception_throw(1, "missing '(' for address");
523
 
 
524
 
                                addr = camel_header_address_new();
525
 
                                addr->type = CAMEL_HEADER_ADDRESS_NAME;
526
 
                                tok = camel_imapp_stream_nstring(is, &token);
527
 
                                addr->name = g_strdup(token);
528
 
                                /* we ignore the route, nobody uses it in the real world */
529
 
                                tok = camel_imapp_stream_nstring(is, &token);
530
 
 
531
 
                                /* [RFC-822] group syntax is indicated by a special
532
 
                                   form of address structure in which the host name
533
 
                                   field is NIL.  If the mailbox name field is also
534
 
                                   NIL, this is an end of group marker (semi-colon in
535
 
                                   RFC 822 syntax).  If the mailbox name field is
536
 
                                   non-NIL, this is a start of group marker, and the
537
 
                                   mailbox name field holds the group name phrase. */
538
 
 
539
 
                                tok = camel_imapp_stream_nstring(is, &mbox);
540
 
                                mbox = g_strdup(mbox);
541
 
                                tok = camel_imapp_stream_nstring(is, &host);
542
 
                                if (host == NULL) {
543
 
                                        if (mbox == NULL) {
544
 
                                                group = NULL;
545
 
                                        } else {
546
 
                                                d(printf("adding group '%s'\n", mbox));
547
 
                                                g_free(addr->name);
548
 
                                                addr->name = mbox;
549
 
                                                addr->type = CAMEL_HEADER_ADDRESS_GROUP;
550
 
                                                camel_header_address_list_append(&list, addr);
551
 
                                                group = addr;
552
 
                                        }
553
 
                                } else {
554
 
                                        addr->v.addr = g_strdup_printf("%s%s%s", mbox?(gchar *)mbox:"", host?"@":"", host?(gchar *)host:"");
555
 
                                        g_free(mbox);
556
 
                                        d(printf("adding address '%s'\n", addr->v.addr));
557
 
                                        if (group != NULL)
558
 
                                                camel_header_address_add_member(group, addr);
559
 
                                        else
560
 
                                                camel_header_address_list_append(&list, addr);
561
 
                                }
562
 
                                do {
563
 
                                        tok = camel_imapp_stream_token(is, &token, &len);
564
 
                                } while (tok != ')');
565
 
                        }
566
 
                } else {
567
 
                        d(printf("empty, nil '%s'\n", token));
568
 
                }
569
 
        } CAMEL_CATCH(ex) {
570
 
                camel_header_address_list_clear(&list);
571
 
                camel_exception_throw_ex(ex);
572
 
        } CAMEL_DONE;
573
 
 
574
 
        return list;
575
 
}
576
 
 
577
 
struct _CamelMessageInfo *
578
 
imap_parse_envelope(CamelIMAPPStream *is)
579
 
{
580
 
        gint tok, len;
581
 
        guchar *token;
582
 
        struct _camel_header_address *addr, *addr_from;
583
 
        gchar *addrstr;
584
 
        struct _CamelMessageInfoBase *minfo;
585
 
 
586
 
        /* envelope        ::= "(" env_date SPACE env_subject SPACE env_from
587
 
           SPACE env_sender SPACE env_reply_to SPACE env_to
588
 
           SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
589
 
           SPACE env_message_id ")" */
590
 
 
591
 
        p(printf("envelope\n"));
592
 
 
593
 
        minfo = (CamelMessageInfoBase *)camel_message_info_new(NULL);
594
 
 
595
 
        CAMEL_TRY {
596
 
                tok = camel_imapp_stream_token(is, &token, &len);
597
 
                if (tok != '(')
598
 
                        camel_exception_throw(1, "envelope: expecting '('");
599
 
 
600
 
                /* env_date        ::= nstring */
601
 
                camel_imapp_stream_nstring(is, &token);
602
 
                minfo->date_sent = camel_header_decode_date(token, NULL);
603
 
 
604
 
                /* env_subject     ::= nstring */
605
 
                tok = camel_imapp_stream_nstring(is, &token);
606
 
                minfo->subject = camel_pstring_strdup(token);
607
 
 
608
 
                /* we merge from/sender into from, append should probably merge more smartly? */
609
 
 
610
 
                /* env_from        ::= "(" 1*address ")" / nil */
611
 
                addr_from = imap_parse_address_list(is);
612
 
 
613
 
                /* env_sender      ::= "(" 1*address ")" / nil */
614
 
                addr = imap_parse_address_list(is);
615
 
                if (addr_from) {
616
 
                        camel_header_address_list_clear(&addr);
617
 
#if 0
618
 
                        if (addr)
619
 
                                camel_header_address_list_append_list(&addr_from, &addr);
620
 
#endif
621
 
                } else {
622
 
                        if (addr)
623
 
                                addr_from = addr;
624
 
                }
625
 
 
626
 
                if (addr_from) {
627
 
                        addrstr = camel_header_address_list_format(addr_from);
628
 
                        minfo->from = camel_pstring_strdup(addrstr);
629
 
                        g_free(addrstr);
630
 
                        camel_header_address_list_clear(&addr_from);
631
 
                }
632
 
 
633
 
                /* we dont keep reply_to */
634
 
 
635
 
                /* env_reply_to    ::= "(" 1*address ")" / nil */
636
 
                addr = imap_parse_address_list(is);
637
 
                camel_header_address_list_clear(&addr);
638
 
 
639
 
                /* env_to          ::= "(" 1*address ")" / nil */
640
 
                addr = imap_parse_address_list(is);
641
 
                if (addr) {
642
 
                        addrstr = camel_header_address_list_format(addr);
643
 
                        minfo->to = camel_pstring_strdup(addrstr);
644
 
                        g_free(addrstr);
645
 
                        camel_header_address_list_clear(&addr);
646
 
                }
647
 
 
648
 
                /* env_cc          ::= "(" 1*address ")" / nil */
649
 
                addr = imap_parse_address_list(is);
650
 
                if (addr) {
651
 
                        addrstr = camel_header_address_list_format(addr);
652
 
                        minfo->cc = camel_pstring_strdup(addrstr);
653
 
                        g_free(addrstr);
654
 
                        camel_header_address_list_clear(&addr);
655
 
                }
656
 
 
657
 
                /* we dont keep bcc either */
658
 
 
659
 
                /* env_bcc         ::= "(" 1*address ")" / nil */
660
 
                addr = imap_parse_address_list(is);
661
 
                camel_header_address_list_clear(&addr);
662
 
 
663
 
                /* FIXME: need to put in-reply-to into references hash list */
664
 
 
665
 
                /* env_in_reply_to ::= nstring */
666
 
                tok = camel_imapp_stream_nstring(is, &token);
667
 
 
668
 
                /* FIXME: need to put message-id into message-id hash */
669
 
 
670
 
                /* env_message_id  ::= nstring */
671
 
                tok = camel_imapp_stream_nstring(is, &token);
672
 
 
673
 
                tok = camel_imapp_stream_token(is, &token, &len);
674
 
                if (tok != ')')
675
 
                        camel_exception_throw(1, "expecting ')'");
676
 
        } CAMEL_CATCH(ex) {
677
 
                camel_message_info_free(minfo);
678
 
                camel_exception_throw_ex(ex);
679
 
        } CAMEL_DONE;
680
 
 
681
 
        return (CamelMessageInfo *)minfo;
682
 
}
683
 
 
684
 
struct _CamelMessageContentInfo *
685
 
imap_parse_body(CamelIMAPPStream *is)
686
 
{
687
 
        gint tok, len;
688
 
        guchar *token;
689
 
        struct _CamelMessageContentInfo * volatile cinfo = NULL;
690
 
        struct _CamelMessageContentInfo *subinfo, *last;
691
 
        struct _CamelContentDisposition * volatile dinfo = NULL;
692
 
        struct _CamelMessageInfo * volatile minfo = NULL;
693
 
 
694
 
        /* body            ::= "(" body_type_1part / body_type_mpart ")" */
695
 
 
696
 
        p(printf("body\n"));
697
 
 
698
 
        CAMEL_TRY {
699
 
                tok = camel_imapp_stream_token(is, &token, &len);
700
 
                if (tok != '(')
701
 
                        camel_exception_throw(1, "body: expecting '('");
702
 
 
703
 
                /* 1*body (optional for multiparts) */
704
 
                tok = camel_imapp_stream_token(is, &token, &len);
705
 
                camel_imapp_stream_ungettoken(is, tok, token, len);
706
 
                if (tok == '(') {
707
 
                        /* body_type_mpart ::= 1*body SPACE media_subtype
708
 
                           [SPACE body_ext_mpart] */
709
 
 
710
 
                        cinfo = g_malloc0(sizeof(*cinfo));
711
 
                        last = (struct _CamelMessageContentInfo *)&cinfo->childs;
712
 
                        do {
713
 
                                subinfo = imap_parse_body(is);
714
 
                                last->next = subinfo;
715
 
                                last = subinfo;
716
 
                                subinfo->parent = cinfo;
717
 
                                tok = camel_imapp_stream_token(is, &token, &len);
718
 
                                camel_imapp_stream_ungettoken(is, tok, token, len);
719
 
                        } while (tok == '(');
720
 
 
721
 
                        d(printf("media_subtype\n"));
722
 
 
723
 
                        camel_imapp_stream_astring(is, &token);
724
 
                        cinfo->type = camel_content_type_new("multipart", token);
725
 
 
726
 
                        /* body_ext_mpart  ::= body_fld_param
727
 
                           [SPACE body_fld_dsp SPACE body_fld_lang
728
 
                           [SPACE 1#body_extension]]
729
 
                           ;; MUST NOT be returned on non-extensible
730
 
                           ;; "BODY" fetch */
731
 
 
732
 
                        d(printf("body_ext_mpart\n"));
733
 
 
734
 
                        tok = camel_imapp_stream_token(is, &token, &len);
735
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
736
 
                        if (tok == '(') {
737
 
                                imap_parse_param_list(is, &cinfo->type->params);
738
 
 
739
 
                                /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
740
 
 
741
 
                                tok = camel_imapp_stream_token(is, &token, &len);
742
 
                                camel_imapp_stream_ungettoken(is, tok, token, len);
743
 
                                if (tok == '(' || tok == IMAP_TOK_TOKEN) {
744
 
                                        dinfo = imap_parse_ext_optional(is);
745
 
                                        /* other extension fields?, soaked up below */
746
 
                                } else {
747
 
                                        camel_imapp_stream_ungettoken(is, tok, token, len);
748
 
                                }
749
 
                        }
750
 
                } else {
751
 
                        /* body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
752
 
                           [SPACE body_ext_1part]
753
 
 
754
 
                           body_type_basic ::= media_basic SPACE body_fields
755
 
                           body_type_text  ::= media_text SPACE body_fields SPACE body_fld_lines
756
 
                           body_type_msg   ::= media_message SPACE body_fields SPACE envelope
757
 
                           SPACE body SPACE body_fld_lines */
758
 
 
759
 
                        d(printf("Single part body\n"));
760
 
 
761
 
                        cinfo = imap_parse_body_fields(is);
762
 
 
763
 
                        d(printf("envelope?\n"));
764
 
 
765
 
                        /* do we have an envelope following */
766
 
                        tok = camel_imapp_stream_token(is, &token, &len);
767
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
768
 
                        if (tok == '(') {
769
 
                                /* what do we do with the envelope?? */
770
 
                                minfo = imap_parse_envelope(is);
771
 
                                /* what do we do with the message content info?? */
772
 
                                ((CamelMessageInfoBase *)minfo)->content = imap_parse_body(is);
773
 
                                camel_message_info_free(minfo);
774
 
                                minfo = NULL;
775
 
                                d(printf("Scanned envelope - what do i do with it?\n"));
776
 
                        }
777
 
 
778
 
                        d(printf("fld_lines?\n"));
779
 
 
780
 
                        /* do we have fld_lines following? */
781
 
                        tok = camel_imapp_stream_token(is, &token, &len);
782
 
                        if (tok == IMAP_TOK_INT) {
783
 
                                d(printf("field lines: %s\n", token));
784
 
                                tok = camel_imapp_stream_token(is, &token, &len);
785
 
                        }
786
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
787
 
 
788
 
                        /* body_ext_1part  ::= body_fld_md5 [SPACE body_fld_dsp
789
 
                           [SPACE body_fld_lang
790
 
                           [SPACE 1#body_extension]]]
791
 
                           ;; MUST NOT be returned on non-extensible
792
 
                           ;; "BODY" fetch */
793
 
 
794
 
                        d(printf("extension data?\n"));
795
 
 
796
 
                        if (tok != ')') {
797
 
                                camel_imapp_stream_nstring(is, &token);
798
 
 
799
 
                                d(printf("md5: %s\n", token?(gchar *)token:"NIL"));
800
 
 
801
 
                                /* body_fld_dsp    ::= "(" string SPACE body_fld_param ")" / nil */
802
 
 
803
 
                                tok = camel_imapp_stream_token(is, &token, &len);
804
 
                                camel_imapp_stream_ungettoken(is, tok, token, len);
805
 
                                if (tok == '(' || tok == IMAP_TOK_TOKEN) {
806
 
                                        dinfo = imap_parse_ext_optional(is);
807
 
                                        /* then other extension fields, soaked up below */
808
 
                                }
809
 
                        }
810
 
                }
811
 
 
812
 
                /* soak up any other extension fields that may be present */
813
 
                /* there should only be simple tokens, no lists */
814
 
                do {
815
 
                        tok = camel_imapp_stream_token(is, &token, &len);
816
 
                        if (tok != ')')
817
 
                                d(printf("Dropping extension data '%s'\n", token));
818
 
                } while (tok != ')');
819
 
        } CAMEL_CATCH(ex) {
820
 
                if (cinfo)
821
 
                        imap_free_body(cinfo);
822
 
                if (dinfo)
823
 
                        camel_content_disposition_unref(dinfo);
824
 
                if (minfo)
825
 
                        camel_message_info_free(minfo);
826
 
                camel_exception_throw_ex(ex);
827
 
        } CAMEL_DONE;
828
 
 
829
 
        /* FIXME: do something with the disposition, currently we have no way to pass it out? */
830
 
        if (dinfo)
831
 
                camel_content_disposition_unref(dinfo);
832
 
 
833
 
        return cinfo;
834
 
}
835
 
 
836
 
gchar *
837
 
imap_parse_section(CamelIMAPPStream *is)
838
 
{
839
 
        gint tok, len;
840
 
        guchar *token;
841
 
        gchar * volatile section = NULL;
842
 
 
843
 
        /* currently we only return the part within the [section] specifier
844
 
           any header fields are parsed, but dropped */
845
 
 
846
 
        /*
847
 
          section         ::= "[" [section_text /
848
 
          (nz_number *["." nz_number] ["." (section_text / "MIME")])] "]"
849
 
 
850
 
          section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
851
 
          SPACE header_list / "TEXT"
852
 
        */
853
 
 
854
 
        CAMEL_TRY {
855
 
                tok = camel_imapp_stream_token(is, &token, &len);
856
 
                if (tok != '[')
857
 
                        camel_exception_throw(1, "section: expecting '['");
858
 
 
859
 
                tok = camel_imapp_stream_token(is, &token, &len);
860
 
                if (tok == IMAP_TOK_INT || tok == IMAP_TOK_TOKEN)
861
 
                        section = g_strdup(token);
862
 
                else if (tok == ']') {
863
 
                        section = g_strdup("");
864
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
865
 
                } else
866
 
                        camel_exception_throw(1, "section: expecting token");
867
 
 
868
 
                /* header_list     ::= "(" 1#header_fld_name ")"
869
 
                   header_fld_name ::= astring */
870
 
 
871
 
                /* we dont need the header specifiers */
872
 
                tok = camel_imapp_stream_token(is, &token, &len);
873
 
                if (tok == '(') {
874
 
                        do {
875
 
                                tok = camel_imapp_stream_token(is, &token, &len);
876
 
                                if (tok == IMAP_TOK_STRING || tok == IMAP_TOK_TOKEN || tok == IMAP_TOK_INT) {
877
 
                                        /* ?do something? */
878
 
                                } else if (tok != ')')
879
 
                                        camel_exception_throw(1, "section: header fields: expecting string");
880
 
                        } while (tok != ')');
881
 
                        tok = camel_imapp_stream_token(is, &token, &len);
882
 
                }
883
 
 
884
 
                if (tok != ']')
885
 
                        camel_exception_throw(1, "section: expecting ']'");
886
 
        } CAMEL_CATCH(ex) {
887
 
                g_free(section);
888
 
                camel_exception_throw_ex(ex);
889
 
        } CAMEL_DONE;
890
 
 
891
 
        return section;
892
 
}
893
 
 
894
 
void
895
 
imap_free_fetch(struct _fetch_info *finfo)
896
 
{
897
 
        if (finfo == NULL)
898
 
                return;
899
 
 
900
 
        if (finfo->body)
901
 
                camel_object_unref((CamelObject *)finfo->body);
902
 
        if (finfo->text)
903
 
                camel_object_unref((CamelObject *)finfo->text);
904
 
        if (finfo->header)
905
 
                camel_object_unref((CamelObject *)finfo->header);
906
 
        if (finfo->minfo)
907
 
                camel_message_info_free(finfo->minfo);
908
 
        if (finfo->cinfo)
909
 
                imap_free_body(finfo->cinfo);
910
 
        g_free(finfo->date);
911
 
        g_free(finfo->section);
912
 
        g_free(finfo->uid);
913
 
        g_free(finfo);
914
 
}
915
 
 
916
 
extern void camel_content_info_dump(CamelMessageContentInfo *ci, gint depth);
917
 
extern void camel_message_info_dump(CamelMessageInfo *mi);
918
 
 
919
 
#include "camel-stream-fs.h"
920
 
 
921
 
/* debug, dump one out */
922
 
void
923
 
imap_dump_fetch(struct _fetch_info *finfo)
924
 
{
925
 
        CamelStream *sout;
926
 
        gint fd;
927
 
 
928
 
        printf("Fetch info:\n");
929
 
        if (finfo == NULL) {
930
 
                printf("Empty\n");
931
 
                return;
932
 
        }
933
 
 
934
 
        fd = dup(1);
935
 
        sout = camel_stream_fs_new_with_fd(fd);
936
 
        if (finfo->body) {
937
 
                camel_stream_printf(sout, "Body content:\n");
938
 
                camel_stream_write_to_stream(finfo->body, sout);
939
 
        }
940
 
        if (finfo->text) {
941
 
                camel_stream_printf(sout, "Text content:\n");
942
 
                camel_stream_write_to_stream(finfo->text, sout);
943
 
        }
944
 
        if (finfo->header) {
945
 
                camel_stream_printf(sout, "Header content:\n");
946
 
                camel_stream_write_to_stream(finfo->header, sout);
947
 
        }
948
 
        if (finfo->minfo) {
949
 
                camel_stream_printf(sout, "Message Info:\n");
950
 
                camel_message_info_dump(finfo->minfo);
951
 
        }
952
 
        if (finfo->cinfo) {
953
 
                camel_stream_printf(sout, "Content Info:\n");
954
 
                camel_content_info_dump(finfo->cinfo, 0);
955
 
        }
956
 
        if (finfo->got & FETCH_SIZE)
957
 
                camel_stream_printf(sout, "Size: %d\n", (gint)finfo->size);
958
 
        if (finfo->got & FETCH_BODY)
959
 
                camel_stream_printf(sout, "Offset: %d\n", (gint)finfo->offset);
960
 
        if (finfo->got & FETCH_FLAGS)
961
 
                camel_stream_printf(sout, "Flags: %08x\n", (gint)finfo->flags);
962
 
        if (finfo->date)
963
 
                camel_stream_printf(sout, "Date: '%s'\n", finfo->date);
964
 
        if (finfo->section)
965
 
                camel_stream_printf(sout, "Section: '%s'\n", finfo->section);
966
 
        if (finfo->date)
967
 
                camel_stream_printf(sout, "UID: '%s'\n", finfo->uid);
968
 
        camel_object_unref((CamelObject *)sout);
969
 
}
970
 
 
971
 
struct _fetch_info *
972
 
imap_parse_fetch(CamelIMAPPStream *is)
973
 
{
974
 
        gint tok, len;
975
 
        guchar *token, *p, c;
976
 
        struct _fetch_info *finfo;
977
 
 
978
 
        finfo = g_malloc0(sizeof(*finfo));
979
 
 
980
 
        CAMEL_TRY {
981
 
                tok = camel_imapp_stream_token(is, &token, &len);
982
 
                if (tok != '(')
983
 
                        camel_exception_throw(1, "fetch: expecting '('");
984
 
 
985
 
                while ( (tok = camel_imapp_stream_token(is, &token, &len)) == IMAP_TOK_TOKEN ) {
986
 
 
987
 
                        p = token;
988
 
                        while ((c=*p))
989
 
                                *p++ = toupper(c);
990
 
 
991
 
                        switch (imap_tokenise(token, len)) {
992
 
                        case IMAP_ENVELOPE:
993
 
                                finfo->minfo = imap_parse_envelope(is);
994
 
                                finfo->got |= FETCH_MINFO;
995
 
                                break;
996
 
                        case IMAP_FLAGS:
997
 
                                imap_parse_flags(is, &finfo->flags);
998
 
                                finfo->got |= FETCH_FLAGS;
999
 
                                break;
1000
 
                        case IMAP_INTERNALDATE:
1001
 
                                camel_imapp_stream_nstring(is, &token);
1002
 
                                /* TODO: convert to camel format? */
1003
 
                                finfo->date = g_strdup(token);
1004
 
                                finfo->got |= FETCH_DATE;
1005
 
                                break;
1006
 
                        case IMAP_RFC822_HEADER:
1007
 
                                camel_imapp_stream_nstring_stream(is, &finfo->header);
1008
 
                                finfo->got |= FETCH_HEADER;
1009
 
                                break;
1010
 
                        case IMAP_RFC822_TEXT:
1011
 
                                camel_imapp_stream_nstring_stream(is, &finfo->text);
1012
 
                                finfo->got |= FETCH_TEXT;
1013
 
                                break;
1014
 
                        case IMAP_RFC822_SIZE:
1015
 
                                finfo->size = camel_imapp_stream_number(is);
1016
 
                                finfo->got |= FETCH_SIZE;
1017
 
                                break;
1018
 
                        case IMAP_BODYSTRUCTURE:
1019
 
                                finfo->cinfo = imap_parse_body(is);
1020
 
                                finfo->got |= FETCH_CINFO;
1021
 
                                break;
1022
 
                        case IMAP_BODY:
1023
 
                                tok = camel_imapp_stream_token(is, &token, &len);
1024
 
                                camel_imapp_stream_ungettoken(is, tok, token, len);
1025
 
                                if (tok == '(') {
1026
 
                                        finfo->cinfo = imap_parse_body(is);
1027
 
                                        finfo->got |= FETCH_CINFO;
1028
 
                                } else if (tok == '[') {
1029
 
                                        finfo->section = imap_parse_section(is);
1030
 
                                        finfo->got |= FETCH_SECTION;
1031
 
                                        tok = camel_imapp_stream_token(is, &token, &len);
1032
 
                                        if (token[0] == '<') {
1033
 
                                                finfo->offset = strtoul(token+1, NULL, 10);
1034
 
                                        } else {
1035
 
                                                camel_imapp_stream_ungettoken(is, tok, token, len);
1036
 
                                        }
1037
 
                                        camel_imapp_stream_nstring_stream(is, &finfo->body);
1038
 
                                        finfo->got |= FETCH_BODY;
1039
 
                                } else {
1040
 
                                        camel_exception_throw(1, "unknown body response");
1041
 
                                }
1042
 
                                break;
1043
 
                        case IMAP_UID:
1044
 
                                tok = camel_imapp_stream_token(is, &token, &len);
1045
 
                                if (tok != IMAP_TOK_INT)
1046
 
                                        camel_exception_throw(1, "uid not integer");
1047
 
                                finfo->uid = g_strdup(token);
1048
 
                                finfo->got |= FETCH_UID;
1049
 
                                break;
1050
 
                        default:
1051
 
                                camel_exception_throw(1, "unknown body response");
1052
 
                        }
1053
 
                }
1054
 
 
1055
 
                if (tok != ')')
1056
 
                        camel_exception_throw(1, "missing closing ')' on fetch response");
1057
 
        } CAMEL_CATCH(ex) {
1058
 
                imap_free_fetch(finfo);
1059
 
                camel_exception_throw_ex(ex);
1060
 
        } CAMEL_DONE;
1061
 
 
1062
 
        return finfo;
1063
 
}
1064
 
 
1065
 
/* rfc 2060 section 7.1 Status Responses */
1066
 
/* shoudl this start after [ or before the [? token_unget anyone? */
1067
 
struct _status_info *
1068
 
imap_parse_status(CamelIMAPPStream *is)
1069
 
{
1070
 
        gint tok, len;
1071
 
        guchar *token;
1072
 
        struct _status_info *sinfo;
1073
 
 
1074
 
        sinfo = g_malloc0(sizeof(*sinfo));
1075
 
 
1076
 
        CAMEL_TRY {
1077
 
                camel_imapp_stream_atom(is, &token, &len);
1078
 
 
1079
 
                /*
1080
 
                  resp_cond_auth  ::= ("OK" / "PREAUTH") SPACE resp_text
1081
 
                  ;; Authentication condition
1082
 
 
1083
 
                  resp_cond_bye   ::= "BYE" SPACE resp_text
1084
 
 
1085
 
                  resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
1086
 
                  ;; Status condition
1087
 
                */
1088
 
 
1089
 
                sinfo->result = imap_tokenise(token, len);
1090
 
                switch (sinfo->result) {
1091
 
                case IMAP_OK:
1092
 
                case IMAP_NO:
1093
 
                case IMAP_BAD:
1094
 
                case IMAP_PREAUTH:
1095
 
                case IMAP_BYE:
1096
 
                        break;
1097
 
                default:
1098
 
                        camel_exception_throw(1, "expecting OK/NO/BAD");
1099
 
                }
1100
 
 
1101
 
                tok = camel_imapp_stream_token(is, &token, &len);
1102
 
                if (tok == '[') {
1103
 
                        camel_imapp_stream_atom(is, &token, &len);
1104
 
                        sinfo->condition = imap_tokenise(token, len);
1105
 
 
1106
 
                        /* parse any details */
1107
 
                        switch (sinfo->condition) {
1108
 
                        case IMAP_READ_ONLY:
1109
 
                        case IMAP_READ_WRITE:
1110
 
                        case IMAP_ALERT:
1111
 
                        case IMAP_PARSE:
1112
 
                        case IMAP_TRYCREATE:
1113
 
                                break;
1114
 
                        case IMAP_NEWNAME:
1115
 
                                /* the rfc doesn't specify the bnf for this */
1116
 
                                camel_imapp_stream_astring(is, &token);
1117
 
                                sinfo->u.newname.oldname = g_strdup(token);
1118
 
                                camel_imapp_stream_astring(is, &token);
1119
 
                                sinfo->u.newname.newname = g_strdup(token);
1120
 
                                break;
1121
 
                        case IMAP_PERMANENTFLAGS:
1122
 
                                imap_parse_flags(is, &sinfo->u.permanentflags);
1123
 
                                break;
1124
 
                        case IMAP_UIDVALIDITY:
1125
 
                                sinfo->u.uidvalidity = camel_imapp_stream_number(is);
1126
 
                                break;
1127
 
                        case IMAP_UNSEEN:
1128
 
                                sinfo->u.unseen = camel_imapp_stream_number(is);
1129
 
                                break;
1130
 
                        default:
1131
 
                                sinfo->condition = IMAP_UNKNOWN;
1132
 
                                printf("Got unknown response code: %s: ignored\n", token);
1133
 
                        }
1134
 
 
1135
 
                        /* ignore anything we dont know about */
1136
 
                        do {
1137
 
                                tok = camel_imapp_stream_token(is, &token, &len);
1138
 
                                if (tok == '\n')
1139
 
                                        camel_exception_throw(1, "server response truncated");
1140
 
                        } while (tok != ']');
1141
 
                } else {
1142
 
                        camel_imapp_stream_ungettoken(is, tok, token, len);
1143
 
                }
1144
 
 
1145
 
                /* and take the human readable response */
1146
 
                camel_imapp_stream_text(is, (guchar **)&sinfo->text);
1147
 
        } CAMEL_CATCH(ex) {
1148
 
                imap_free_status(sinfo);
1149
 
                camel_exception_throw_ex(ex);
1150
 
        } CAMEL_DONE;
1151
 
 
1152
 
        return sinfo;
1153
 
}
1154
 
 
1155
 
void
1156
 
imap_free_status(struct _status_info *sinfo)
1157
 
{
1158
 
        if (sinfo == NULL)
1159
 
                return;
1160
 
 
1161
 
        switch (sinfo->condition) {
1162
 
        case IMAP_NEWNAME:
1163
 
                g_free(sinfo->u.newname.oldname);
1164
 
                g_free(sinfo->u.newname.newname);
1165
 
        default:
1166
 
                break;
1167
 
        }
1168
 
 
1169
 
        g_free(sinfo->text);
1170
 
        g_free(sinfo);
1171
 
}
1172
 
 
1173
 
/* FIXME: use tokeniser? */
1174
 
/* FIXME: real flags */
1175
 
static struct {
1176
 
        gchar *name;
1177
 
        guint32 flag;
1178
 
} list_flag_table[] = {
1179
 
        { "\\NOINFERIORS", CAMEL_FOLDER_NOINFERIORS },
1180
 
        { "\\NOSELECT", CAMEL_FOLDER_NOSELECT },
1181
 
        { "\\MARKED", 1<<8 },
1182
 
        { "\\UNMARKED", 1<<9 },
1183
 
};
1184
 
 
1185
 
struct _list_info *
1186
 
imap_parse_list(CamelIMAPPStream *is)
1187
 
/* throws io, parse */
1188
 
{
1189
 
        gint tok, len, i;
1190
 
        guchar *token, *p, c;
1191
 
        struct _list_info * volatile linfo;
1192
 
 
1193
 
        linfo = g_malloc0(sizeof(*linfo));
1194
 
 
1195
 
        CAMEL_TRY {
1196
 
                /* mailbox_list    ::= "(" #("\Marked" / "\Noinferiors" /
1197
 
                   "\Noselect" / "\Unmarked" / flag_extension) ")"
1198
 
                   SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox */
1199
 
 
1200
 
                tok = camel_imapp_stream_token(is, &token, &len);
1201
 
                if (tok != '(')
1202
 
                        camel_exception_throw(1, "list: expecting '('");
1203
 
 
1204
 
                while ( (tok = camel_imapp_stream_token(is, &token, &len)) != ')' ) {
1205
 
                        if (tok == IMAP_TOK_STRING || tok == IMAP_TOK_TOKEN) {
1206
 
                                p = token;
1207
 
                                while ((c=*p))
1208
 
                                        *p++ = toupper(c);
1209
 
                                for (i=0;i<(gint)(sizeof(list_flag_table)/sizeof(list_flag_table[0]));i++)
1210
 
                                        if (!strcmp(token, list_flag_table[i].name))
1211
 
                                                linfo->flags |= list_flag_table[i].flag;
1212
 
                        } else {
1213
 
                                camel_exception_throw(1, "list: expecting flag or ')'");
1214
 
                        }
1215
 
                }
1216
 
 
1217
 
                camel_imapp_stream_nstring(is, &token);
1218
 
                linfo->separator = token?*token:0;
1219
 
                camel_imapp_stream_astring(is, &token);
1220
 
                linfo->name = g_strdup(token);
1221
 
        } CAMEL_CATCH(ex) {
1222
 
                imap_free_list(linfo);
1223
 
                camel_exception_throw_ex(ex);
1224
 
        } CAMEL_DONE;
1225
 
 
1226
 
        return linfo;
1227
 
}
1228
 
 
1229
 
gchar *
1230
 
imapp_list_get_path(struct _list_info *li)
1231
 
{
1232
 
        gchar *path, *p;
1233
 
        gint c;
1234
 
        const gchar *f;
1235
 
 
1236
 
        if (li->separator != 0 && li->separator != '/') {
1237
 
                p = path = alloca(strlen(li->name)*3+1);
1238
 
                f = li->name;
1239
 
                while ( (c = *f++ & 0xff) ) {
1240
 
                        if (c == li->separator)
1241
 
                                *p++ = '/';
1242
 
                        else if (c == '/' || c == '%')
1243
 
                                p += sprintf(p, "%%%02X", c);
1244
 
                        else
1245
 
                                *p++ = c;
1246
 
                }
1247
 
                *p = 0;
1248
 
        } else
1249
 
                path = li->name;
1250
 
 
1251
 
        return camel_utf7_utf8(path);
1252
 
}
1253
 
 
1254
 
void
1255
 
imap_free_list(struct _list_info *linfo)
1256
 
{
1257
 
        if (linfo) {
1258
 
                g_free(linfo->name);
1259
 
                g_free(linfo);
1260
 
        }
1261
 
}
1262
 
 
1263
 
/* ********************************************************************** */
1264
 
/* utility functions */
1265
 
 
1266
 
/* should the rest of imapp-utils go into imapp-parse? */
1267
 
 
1268
 
/* this creates a uid (or sequence number) set directly into the command,
1269
 
  optionally breaking it into smaller chunks */
1270
 
 
1271
 
void
1272
 
imapp_uidset_init(struct _uidset_state *ss, CamelIMAPPEngine *ie)
1273
 
{
1274
 
        ss->ie = ie;
1275
 
        ss->len = 0;
1276
 
        ss->start = 0;
1277
 
        ss->last = 0;
1278
 
}
1279
 
 
1280
 
gint
1281
 
imapp_uidset_done(struct _uidset_state *ss, CamelIMAPPCommand *ic)
1282
 
{
1283
 
        gint ret = 0;
1284
 
 
1285
 
        if (ss->last != 0 && ss->last != ss->start) {
1286
 
                camel_imapp_engine_command_add(ss->ie, ic, ":%d", ss->last);
1287
 
                printf(":%d", ss->last);
1288
 
        }
1289
 
 
1290
 
        ret = ss->last != 0;
1291
 
 
1292
 
        ss->start = 0;
1293
 
        ss->last = 0;
1294
 
        ss->len = 0;
1295
 
 
1296
 
        return ret;
1297
 
}
1298
 
 
1299
 
gint
1300
 
imapp_uidset_add(struct _uidset_state *ss, CamelIMAPPCommand *ic, const gchar *uid)
1301
 
{
1302
 
        guint32 uidn;
1303
 
 
1304
 
        uidn = strtoul(uid, NULL, 10);
1305
 
        if (uidn == 0)
1306
 
                return -1;
1307
 
 
1308
 
        if (ss->last == 0) {
1309
 
                camel_imapp_engine_command_add(ss->ie, ic, "%d", uidn);
1310
 
                printf("%d", uidn);
1311
 
                ss->len ++;
1312
 
                ss->start = uidn;
1313
 
        } else {
1314
 
                if (ss->last != uidn-1) {
1315
 
                        if (ss->last == ss->start) {
1316
 
                                camel_imapp_engine_command_add(ss->ie, ic, ",%d", uidn);
1317
 
                                printf(",%d", uidn);
1318
 
                                ss->len ++;
1319
 
                        } else {
1320
 
                                camel_imapp_engine_command_add(ss->ie, ic, ":%d,%d", ss->last, uidn);
1321
 
                                printf(":%d,%d", ss->last, uidn);
1322
 
                                ss->len+=2;
1323
 
                        }
1324
 
                        ss->start = uidn;
1325
 
                }
1326
 
        }
1327
 
 
1328
 
        ss->last = uidn;
1329
 
 
1330
 
        if (ss->len > 10) {
1331
 
                imapp_uidset_done(ss, ic);
1332
 
                return 1;
1333
 
        }
1334
 
 
1335
 
        return 0;
1336
 
}