~hkdb/geary/disco-3.34.1

« back to all changes in this revision

Viewing changes to src/engine/imap/parameter/imap-list-parameter.vala

  • Committer: hkdb
  • Date: 2019-10-08 10:54:21 UTC
  • Revision ID: hkdb@3df.io-20191008105421-3dkwnpnhcamm77to
Tags: upstream-3.34.1-disco
ImportĀ upstreamĀ versionĀ 3.34.1-disco

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2016 Software Freedom Conservancy Inc.
 
2
 *
 
3
 * This software is licensed under the GNU Lesser General Public License
 
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
 
5
 */
 
6
 
 
7
/**
 
8
 * The representation of an IMAP parenthesized list.
 
9
 *
 
10
 * See [[http://tools.ietf.org/html/rfc3501#section-4.4]]
 
11
 */
 
12
 
 
13
public class Geary.Imap.ListParameter : Geary.Imap.Parameter {
 
14
    /**
 
15
     * The maximum length a literal parameter may be to be auto-converted to a StringParameter
 
16
     * in the StringParameter getters.
 
17
     */
 
18
    public const int MAX_STRING_LITERAL_LENGTH = 4096;
 
19
 
 
20
    /**
 
21
     * Returns the number of {@link Parameter}s held in this {@link ListParameter}.
 
22
     */
 
23
    public int size {
 
24
        get {
 
25
            return list.size;
 
26
        }
 
27
    }
 
28
 
 
29
    private Gee.List<Parameter> list = new Gee.ArrayList<Parameter>();
 
30
 
 
31
 
 
32
    /**
 
33
     * Appends a parameter to the end of this list.
 
34
     *
 
35
     * The same {@link Parameter} can't be added more than once to the
 
36
     * same {@link ListParameter}.  There are no other restrictions,
 
37
     * however.
 
38
     *
 
39
     * @return true if added.
 
40
     */
 
41
    public bool add(Parameter param) {
 
42
        return this.list.add(param);
 
43
    }
 
44
 
 
45
    /**
 
46
     * Adds all parameters in the given collection to this list.
 
47
     *
 
48
     * The same {@link Parameter} can't be added more than once to the
 
49
     * same {@link ListParameter}.  There are no other restrictions,
 
50
     * however.
 
51
     *
 
52
     * @return number of Parameters added.
 
53
     */
 
54
    public int add_all(Gee.Collection<Parameter> params) {
 
55
        int count = 0;
 
56
        foreach (Parameter param in params) {
 
57
            count += add(param) ? 1 : 0;
 
58
        }
 
59
        return count;
 
60
    }
 
61
 
 
62
    /**
 
63
     * Adds all elements in the given list to the end of this list.
 
64
     *
 
65
     * The difference between this call and {@link add} is that add() will simply insert the
 
66
     * {@link Parameter} to the tail of the list.  Thus, add(ListParameter) will add a child list
 
67
     * inside this list, i.e. add(ListParameter("three")):
 
68
     *
 
69
     * (one two (three))
 
70
     *
 
71
     * Instead, extend(ListParameter("three")) adds each element of the ListParameter to this one, not
 
72
     * creating a child:
 
73
     *
 
74
     * (one two three)
 
75
     *
 
76
     * @return Number of added elements. This will not abort if an
 
77
     * element fails to be added.
 
78
     */
 
79
    public int extend(ListParameter listp) {
 
80
        return add_all(listp.list);
 
81
    }
 
82
 
 
83
    /**
 
84
     * Clears the {@link ListParameter} of all its children.
 
85
     */
 
86
    public void clear() {
 
87
        list.clear();
 
88
    }
 
89
 
 
90
    //
 
91
    // Parameter retrieval
 
92
    //
 
93
 
 
94
    /**
 
95
     * Returns the {@link Parameter} at the index in the list, null if index is out of range.
 
96
     *
 
97
     * TODO: This call can cause memory leaks when used with the "as" operator until the following
 
98
     * Vala bug is fixed (probably in version 0.19.1).
 
99
     * [[https://bugzilla.gnome.org/show_bug.cgi?id=695671]]
 
100
     */
 
101
    public new Parameter? get(int index) {
 
102
        return ((index >= 0) && (index < list.size)) ? list.get(index) : null;
 
103
    }
 
104
 
 
105
    /**
 
106
     * Returns the Parameter at the index.  Throws an ImapError.TYPE_ERROR if the index is out of
 
107
     * range.
 
108
     *
 
109
     * TODO: This call can cause memory leaks when used with the "as" operator until the following
 
110
     * Vala bug is fixed (probably in version 0.19.1).
 
111
     * [[https://bugzilla.gnome.org/show_bug.cgi?id=695671]]
 
112
     */
 
113
    public Parameter get_required(int index) throws ImapError {
 
114
        if ((index < 0) || (index >= list.size))
 
115
            throw new ImapError.TYPE_ERROR("No parameter at index %d", index);
 
116
 
 
117
        Parameter? param = list.get(index);
 
118
        if (param == null)
 
119
            throw new ImapError.TYPE_ERROR("No parameter at index %d", index);
 
120
 
 
121
        return param;
 
122
    }
 
123
 
 
124
    /**
 
125
     * Returns {@link Parameter} at index if in range and of Type type, otherwise throws an
 
126
     * {@link ImapError.TYPE_ERROR}.
 
127
     *
 
128
     * type must be of type Parameter.
 
129
     */
 
130
    public Parameter get_as(int index, Type type) throws ImapError {
 
131
        if (!type.is_a(typeof(Parameter)))
 
132
            throw new ImapError.TYPE_ERROR("Attempting to cast non-Parameter at index %d", index);
 
133
 
 
134
        Parameter param = get_required(index);
 
135
        if (!param.get_type().is_a(type)) {
 
136
            throw new ImapError.TYPE_ERROR("Parameter %d is not of type %s (is %s)", index,
 
137
                type.name(), param.get_type().name());
 
138
        }
 
139
 
 
140
        return param;
 
141
    }
 
142
 
 
143
    /**
 
144
     * Like {@link get_as}, but returns null if the {@link Parameter} at index is a
 
145
     * {@link NilParameter}.
 
146
     *
 
147
     * type must be of type Parameter.
 
148
     */
 
149
    public Parameter? get_as_nullable(int index, Type type) throws ImapError {
 
150
        if (!type.is_a(typeof(Parameter)))
 
151
            throw new ImapError.TYPE_ERROR("Attempting to cast non-Parameter at index %d", index);
 
152
 
 
153
        Parameter param = get_required(index);
 
154
        if (param is NilParameter)
 
155
            return null;
 
156
 
 
157
        // Because Deserializer doesn't produce NilParameters, check manually if this Parameter
 
158
        // can legally be NIL according to IMAP grammar.
 
159
        StringParameter? stringp = param as StringParameter;
 
160
        if (stringp != null && NilParameter.is_nil(stringp))
 
161
            return null;
 
162
 
 
163
        if (!param.get_type().is_a(type)) {
 
164
            throw new ImapError.TYPE_ERROR("Parameter %d is not of type %s (is %s)", index,
 
165
                type.name(), param.get_type().name());
 
166
        }
 
167
 
 
168
        return param;
 
169
    }
 
170
 
 
171
    /**
 
172
     * Like {@link get}, but returns null if {@link Parameter} at index is not of the specified type.
 
173
     *
 
174
     * type must be of type Parameter.
 
175
     */
 
176
    public Parameter? get_if(int index, Type type) {
 
177
        if (!type.is_a(typeof(Parameter)))
 
178
            return null;
 
179
 
 
180
        Parameter? param = get(index);
 
181
        if (param == null || !param.get_type().is_a(type))
 
182
            return null;
 
183
 
 
184
        return param;
 
185
    }
 
186
 
 
187
    //
 
188
    // String retrieval
 
189
    //
 
190
 
 
191
    /**
 
192
     * Returns a {@link StringParameter} only if the {@link Parameter} at index is a StringParameter.
 
193
     *
 
194
     * Compare to {@link get_as_nullable_string}.
 
195
     */
 
196
    public StringParameter? get_if_string(int index) {
 
197
        return (StringParameter?) get_if(index, typeof(StringParameter));
 
198
    }
 
199
 
 
200
    /**
 
201
     * Returns a {@link StringParameter} for the value at the index only if the {@link Parameter}
 
202
     * is a StringParameter or a {@link LiteralParameter} with a length less than or equal to
 
203
     * {@link MAX_STRING_LITERAL_LENGTH}.
 
204
     *
 
205
     * Because literal data is being coerced into a StringParameter, the result may not be suitable
 
206
     * for transmission as-is.
 
207
     *
 
208
     * @see get_as_nullable_string
 
209
     * @throws ImapError.TYPE_ERROR if no StringParameter at index or the literal is longer than
 
210
     * MAX_STRING_LITERAL_LENGTH.
 
211
     */
 
212
    public StringParameter get_as_string(int index) throws ImapError {
 
213
        Parameter param = get_required(index);
 
214
 
 
215
        StringParameter? stringp = param as StringParameter;
 
216
        if (stringp != null)
 
217
            return stringp;
 
218
 
 
219
        LiteralParameter? literalp = param as LiteralParameter;
 
220
        if (literalp != null && literalp.value.size <= MAX_STRING_LITERAL_LENGTH)
 
221
            return literalp.coerce_to_string_parameter();
 
222
 
 
223
        throw new ImapError.TYPE_ERROR("Parameter %d not of type string or literal (is %s)", index,
 
224
            param.get_type().name());
 
225
    }
 
226
 
 
227
    /**
 
228
     * Returns a {@link StringParameter} for the value at the index only if the {@link Parameter}
 
229
     * is a StringParameter or a {@link LiteralParameter} with a length less than or equal to
 
230
     * {@link MAX_STRING_LITERAL_LENGTH}.
 
231
     *
 
232
     * Because literal data is being coerced into a StringParameter, the result may not be suitable
 
233
     * for transmission as-is.
 
234
     *
 
235
     * @return null if no StringParameter or LiteralParameter at index.
 
236
     * @see get_as_string
 
237
     * @throws ImapError.TYPE_ERROR if literal is longer than MAX_STRING_LITERAL_LENGTH.
 
238
     */
 
239
    public StringParameter? get_as_nullable_string(int index) throws ImapError {
 
240
        Parameter? param = get_as_nullable(index, typeof(Parameter));
 
241
        if (param == null)
 
242
            return null;
 
243
 
 
244
        StringParameter? stringp = param as StringParameter;
 
245
        if (stringp != null)
 
246
            return stringp;
 
247
 
 
248
        LiteralParameter? literalp = param as LiteralParameter;
 
249
        if (literalp != null && literalp.value.size <= MAX_STRING_LITERAL_LENGTH)
 
250
            return literalp.coerce_to_string_parameter();
 
251
 
 
252
        throw new ImapError.TYPE_ERROR("Parameter %d not of type string or literal (is %s)", index,
 
253
            param.get_type().name());
 
254
    }
 
255
 
 
256
    /**
 
257
     * Much like get_as_nullable_string() but returns an empty StringParameter (rather than null)
 
258
     * if the parameter at index is a NilParameter.
 
259
     */
 
260
    public StringParameter get_as_empty_string(int index) throws ImapError {
 
261
        StringParameter? stringp = get_as_nullable_string(index);
 
262
 
 
263
        return stringp ?? StringParameter.get_best_for("");
 
264
    }
 
265
 
 
266
    //
 
267
    // Number retrieval
 
268
    //
 
269
 
 
270
    /**
 
271
     * Returns a {@link NumberParameter} at index, null if not of that type.
 
272
     *
 
273
     * @see get_if
 
274
     */
 
275
    public NumberParameter? get_if_number(int index) {
 
276
        return (NumberParameter?) get_if(index, typeof(NumberParameter));
 
277
    }
 
278
 
 
279
    /**
 
280
     * Returns a {@link NumberParameter} at index.
 
281
     *
 
282
     * Like {@link get_as_string}, this method will attempt some coercion.  In this case,
 
283
     * {@link QuotedStringParameter} and {@link UnquotedStringParameter}s will be converted to
 
284
     * NumberParameter, if appropriate.
 
285
     */
 
286
    public NumberParameter get_as_number(int index) throws ImapError {
 
287
        Parameter param = get_required(index);
 
288
 
 
289
        NumberParameter? numberp = param as NumberParameter;
 
290
        if (numberp != null)
 
291
            return numberp;
 
292
 
 
293
        StringParameter? stringp = param as StringParameter;
 
294
        if (stringp != null) {
 
295
            numberp = stringp.coerce_to_number_parameter();
 
296
            if (numberp != null)
 
297
                return numberp;
 
298
        }
 
299
 
 
300
        throw new ImapError.TYPE_ERROR("Parameter %d not of type number or string (is %s)", index,
 
301
            param.get_type().name());
 
302
    }
 
303
 
 
304
    //
 
305
    // List retrieval
 
306
    //
 
307
 
 
308
    /**
 
309
     * Returns a {@link ListParameter} at index.
 
310
     *
 
311
     * @see get_as
 
312
     */
 
313
    public ListParameter get_as_list(int index) throws ImapError {
 
314
        return (ListParameter) get_as(index, typeof(ListParameter));
 
315
    }
 
316
 
 
317
    /**
 
318
     * Returns a {@link ListParameter} at index, null if NIL.
 
319
     *
 
320
     * @see get_as_nullable
 
321
     */
 
322
    public ListParameter? get_as_nullable_list(int index) throws ImapError {
 
323
        return (ListParameter?) get_as_nullable(index, typeof(ListParameter));
 
324
    }
 
325
 
 
326
    /**
 
327
     * Returns {@link ListParameter} at index, an empty list if NIL.
 
328
     */
 
329
    public ListParameter get_as_empty_list(int index) throws ImapError {
 
330
        ListParameter? param = get_as_nullable_list(index);
 
331
 
 
332
        return param ?? new ListParameter();
 
333
    }
 
334
 
 
335
    /**
 
336
     * Returns a {@link ListParameter} at index, null if not a list.
 
337
     *
 
338
     * @see get_if
 
339
     */
 
340
    public ListParameter? get_if_list(int index) {
 
341
        return (ListParameter?) get_if(index, typeof(ListParameter));
 
342
    }
 
343
 
 
344
    //
 
345
    // Literal retrieval
 
346
    //
 
347
 
 
348
    /**
 
349
     * Returns a {@link LiteralParameter} at index.
 
350
     *
 
351
     * @see get_as
 
352
     */
 
353
    public LiteralParameter get_as_literal(int index) throws ImapError {
 
354
        return (LiteralParameter) get_as(index, typeof(LiteralParameter));
 
355
    }
 
356
 
 
357
    /**
 
358
     * Returns a {@link LiteralParameter} at index, null if NIL.
 
359
     *
 
360
     * @see get_as_nullable
 
361
     */
 
362
    public LiteralParameter? get_as_nullable_literal(int index) throws ImapError {
 
363
        return (LiteralParameter?) get_as_nullable(index, typeof(LiteralParameter));
 
364
    }
 
365
 
 
366
    /**
 
367
     * Returns a {@link LiteralParameter} at index, null if not a list.
 
368
     *
 
369
     * @see get_if
 
370
     */
 
371
    public LiteralParameter? get_if_literal(int index) {
 
372
        return (LiteralParameter?) get_if(index, typeof(LiteralParameter));
 
373
    }
 
374
 
 
375
    /**
 
376
     * Returns [@link LiteralParameter} at index, an empty list if NIL.
 
377
     */
 
378
    public LiteralParameter get_as_empty_literal(int index) throws ImapError {
 
379
        LiteralParameter? param = get_as_nullable_literal(index);
 
380
 
 
381
        return param ?? new LiteralParameter(Geary.Memory.EmptyBuffer.instance);
 
382
    }
 
383
 
 
384
    /**
 
385
     * Returns a {@link Memory.Buffer} for the {@link Parameter} at position index.
 
386
     *
 
387
     * Only converts {@link StringParameter} and {@link LiteralParameter}.  All other types return
 
388
     * null.
 
389
     */
 
390
    public Memory.Buffer? get_as_nullable_buffer(int index) throws ImapError {
 
391
        LiteralParameter? literalp = get_if_literal(index);
 
392
        if (literalp != null)
 
393
            return literalp.value;
 
394
 
 
395
        StringParameter? stringp = get_if_string(index);
 
396
        if (stringp != null)
 
397
            return stringp.as_buffer();
 
398
 
 
399
        return null;
 
400
    }
 
401
 
 
402
    /**
 
403
     * Returns a {@link Memory.Buffer} for the {@link Parameter} at position index.
 
404
     *
 
405
     * Only converts {@link StringParameter} and {@link LiteralParameter}.  All other types return
 
406
     * as an empty buffer.
 
407
     */
 
408
    public Memory.Buffer get_as_empty_buffer(int index) throws ImapError {
 
409
        return get_as_nullable_buffer(index) ?? Memory.EmptyBuffer.instance;
 
410
    }
 
411
 
 
412
    /**
 
413
     * Returns a read-only List of {@link Parameter}s.
 
414
     */
 
415
    public Gee.List<Parameter> get_all() {
 
416
        return list.read_only_view;
 
417
    }
 
418
 
 
419
    /**
 
420
     * Returns the replaced Parameter.  Throws ImapError.TYPE_ERROR if no Parameter exists at the
 
421
     * index.
 
422
     */
 
423
    public Parameter replace(int index, Parameter parameter) throws ImapError {
 
424
        if (list.size <= index)
 
425
            throw new ImapError.TYPE_ERROR("No parameter at index %d", index);
 
426
 
 
427
        Parameter old = this.list[index];
 
428
        this.list[index] = parameter;
 
429
        return old;
 
430
    }
 
431
 
 
432
    /**
 
433
     * Moves all child parameters from the supplied list into this list, clearing this list first.
 
434
     *
 
435
     * The supplied list will be "stripped" of its children.  This ListParameter is cleared prior
 
436
     * to adopting the new children.
 
437
     */
 
438
    public void adopt_children(ListParameter src) {
 
439
        clear();
 
440
 
 
441
        Gee.List<Parameter> src_children = new Gee.ArrayList<Parameter>();
 
442
        src_children.add_all(src.list);
 
443
        src.clear();
 
444
 
 
445
        add_all(src_children);
 
446
    }
 
447
 
 
448
    protected string stringize_list() {
 
449
        StringBuilder builder = new StringBuilder();
 
450
 
 
451
        int length = list.size;
 
452
        for (int ctr = 0; ctr < length; ctr++) {
 
453
            builder.append(list[ctr].to_string());
 
454
            if (ctr < (length - 1))
 
455
                builder.append_c(' ');
 
456
        }
 
457
 
 
458
        return builder.str;
 
459
    }
 
460
 
 
461
    /**
 
462
     * {@inheritDoc}
 
463
     */
 
464
    public override string to_string() {
 
465
        return "(%s)".printf(stringize_list());
 
466
    }
 
467
 
 
468
    /**
 
469
     * {@inheritDoc}
 
470
     */
 
471
    public override void serialize(Serializer ser, GLib.Cancellable cancellable)
 
472
        throws GLib.Error {
 
473
        ser.push_ascii('(', cancellable);
 
474
        serialize_list(ser, cancellable);
 
475
        ser.push_ascii(')', cancellable);
 
476
    }
 
477
 
 
478
    protected void serialize_list(Serializer ser, GLib.Cancellable cancellable)
 
479
        throws GLib.Error {
 
480
        int length = list.size;
 
481
        for (int ctr = 0; ctr < length; ctr++) {
 
482
            list[ctr].serialize(ser, cancellable);
 
483
            if (ctr < (length - 1))
 
484
                ser.push_space(cancellable);
 
485
        }
 
486
    }
 
487
 
 
488
}