1
/* Copyright 2016 Software Freedom Conservancy Inc.
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.
8
* The representation of an IMAP parenthesized list.
10
* See [[http://tools.ietf.org/html/rfc3501#section-4.4]]
13
public class Geary.Imap.ListParameter : Geary.Imap.Parameter {
15
* The maximum length a literal parameter may be to be auto-converted to a StringParameter
16
* in the StringParameter getters.
18
public const int MAX_STRING_LITERAL_LENGTH = 4096;
21
* Returns the number of {@link Parameter}s held in this {@link ListParameter}.
29
private Gee.List<Parameter> list = new Gee.ArrayList<Parameter>();
33
* Appends a parameter to the end of this list.
35
* The same {@link Parameter} can't be added more than once to the
36
* same {@link ListParameter}. There are no other restrictions,
39
* @return true if added.
41
public bool add(Parameter param) {
42
return this.list.add(param);
46
* Adds all parameters in the given collection to this list.
48
* The same {@link Parameter} can't be added more than once to the
49
* same {@link ListParameter}. There are no other restrictions,
52
* @return number of Parameters added.
54
public int add_all(Gee.Collection<Parameter> params) {
56
foreach (Parameter param in params) {
57
count += add(param) ? 1 : 0;
63
* Adds all elements in the given list to the end of this list.
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")):
71
* Instead, extend(ListParameter("three")) adds each element of the ListParameter to this one, not
76
* @return Number of added elements. This will not abort if an
77
* element fails to be added.
79
public int extend(ListParameter listp) {
80
return add_all(listp.list);
84
* Clears the {@link ListParameter} of all its children.
91
// Parameter retrieval
95
* Returns the {@link Parameter} at the index in the list, null if index is out of range.
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]]
101
public new Parameter? get(int index) {
102
return ((index >= 0) && (index < list.size)) ? list.get(index) : null;
106
* Returns the Parameter at the index. Throws an ImapError.TYPE_ERROR if the index is out of
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]]
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);
117
Parameter? param = list.get(index);
119
throw new ImapError.TYPE_ERROR("No parameter at index %d", index);
125
* Returns {@link Parameter} at index if in range and of Type type, otherwise throws an
126
* {@link ImapError.TYPE_ERROR}.
128
* type must be of type Parameter.
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);
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());
144
* Like {@link get_as}, but returns null if the {@link Parameter} at index is a
145
* {@link NilParameter}.
147
* type must be of type Parameter.
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);
153
Parameter param = get_required(index);
154
if (param is NilParameter)
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))
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());
172
* Like {@link get}, but returns null if {@link Parameter} at index is not of the specified type.
174
* type must be of type Parameter.
176
public Parameter? get_if(int index, Type type) {
177
if (!type.is_a(typeof(Parameter)))
180
Parameter? param = get(index);
181
if (param == null || !param.get_type().is_a(type))
192
* Returns a {@link StringParameter} only if the {@link Parameter} at index is a StringParameter.
194
* Compare to {@link get_as_nullable_string}.
196
public StringParameter? get_if_string(int index) {
197
return (StringParameter?) get_if(index, typeof(StringParameter));
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}.
205
* Because literal data is being coerced into a StringParameter, the result may not be suitable
206
* for transmission as-is.
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.
212
public StringParameter get_as_string(int index) throws ImapError {
213
Parameter param = get_required(index);
215
StringParameter? stringp = param as StringParameter;
219
LiteralParameter? literalp = param as LiteralParameter;
220
if (literalp != null && literalp.value.size <= MAX_STRING_LITERAL_LENGTH)
221
return literalp.coerce_to_string_parameter();
223
throw new ImapError.TYPE_ERROR("Parameter %d not of type string or literal (is %s)", index,
224
param.get_type().name());
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}.
232
* Because literal data is being coerced into a StringParameter, the result may not be suitable
233
* for transmission as-is.
235
* @return null if no StringParameter or LiteralParameter at index.
237
* @throws ImapError.TYPE_ERROR if literal is longer than MAX_STRING_LITERAL_LENGTH.
239
public StringParameter? get_as_nullable_string(int index) throws ImapError {
240
Parameter? param = get_as_nullable(index, typeof(Parameter));
244
StringParameter? stringp = param as StringParameter;
248
LiteralParameter? literalp = param as LiteralParameter;
249
if (literalp != null && literalp.value.size <= MAX_STRING_LITERAL_LENGTH)
250
return literalp.coerce_to_string_parameter();
252
throw new ImapError.TYPE_ERROR("Parameter %d not of type string or literal (is %s)", index,
253
param.get_type().name());
257
* Much like get_as_nullable_string() but returns an empty StringParameter (rather than null)
258
* if the parameter at index is a NilParameter.
260
public StringParameter get_as_empty_string(int index) throws ImapError {
261
StringParameter? stringp = get_as_nullable_string(index);
263
return stringp ?? StringParameter.get_best_for("");
271
* Returns a {@link NumberParameter} at index, null if not of that type.
275
public NumberParameter? get_if_number(int index) {
276
return (NumberParameter?) get_if(index, typeof(NumberParameter));
280
* Returns a {@link NumberParameter} at index.
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.
286
public NumberParameter get_as_number(int index) throws ImapError {
287
Parameter param = get_required(index);
289
NumberParameter? numberp = param as NumberParameter;
293
StringParameter? stringp = param as StringParameter;
294
if (stringp != null) {
295
numberp = stringp.coerce_to_number_parameter();
300
throw new ImapError.TYPE_ERROR("Parameter %d not of type number or string (is %s)", index,
301
param.get_type().name());
309
* Returns a {@link ListParameter} at index.
313
public ListParameter get_as_list(int index) throws ImapError {
314
return (ListParameter) get_as(index, typeof(ListParameter));
318
* Returns a {@link ListParameter} at index, null if NIL.
320
* @see get_as_nullable
322
public ListParameter? get_as_nullable_list(int index) throws ImapError {
323
return (ListParameter?) get_as_nullable(index, typeof(ListParameter));
327
* Returns {@link ListParameter} at index, an empty list if NIL.
329
public ListParameter get_as_empty_list(int index) throws ImapError {
330
ListParameter? param = get_as_nullable_list(index);
332
return param ?? new ListParameter();
336
* Returns a {@link ListParameter} at index, null if not a list.
340
public ListParameter? get_if_list(int index) {
341
return (ListParameter?) get_if(index, typeof(ListParameter));
349
* Returns a {@link LiteralParameter} at index.
353
public LiteralParameter get_as_literal(int index) throws ImapError {
354
return (LiteralParameter) get_as(index, typeof(LiteralParameter));
358
* Returns a {@link LiteralParameter} at index, null if NIL.
360
* @see get_as_nullable
362
public LiteralParameter? get_as_nullable_literal(int index) throws ImapError {
363
return (LiteralParameter?) get_as_nullable(index, typeof(LiteralParameter));
367
* Returns a {@link LiteralParameter} at index, null if not a list.
371
public LiteralParameter? get_if_literal(int index) {
372
return (LiteralParameter?) get_if(index, typeof(LiteralParameter));
376
* Returns [@link LiteralParameter} at index, an empty list if NIL.
378
public LiteralParameter get_as_empty_literal(int index) throws ImapError {
379
LiteralParameter? param = get_as_nullable_literal(index);
381
return param ?? new LiteralParameter(Geary.Memory.EmptyBuffer.instance);
385
* Returns a {@link Memory.Buffer} for the {@link Parameter} at position index.
387
* Only converts {@link StringParameter} and {@link LiteralParameter}. All other types return
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;
395
StringParameter? stringp = get_if_string(index);
397
return stringp.as_buffer();
403
* Returns a {@link Memory.Buffer} for the {@link Parameter} at position index.
405
* Only converts {@link StringParameter} and {@link LiteralParameter}. All other types return
406
* as an empty buffer.
408
public Memory.Buffer get_as_empty_buffer(int index) throws ImapError {
409
return get_as_nullable_buffer(index) ?? Memory.EmptyBuffer.instance;
413
* Returns a read-only List of {@link Parameter}s.
415
public Gee.List<Parameter> get_all() {
416
return list.read_only_view;
420
* Returns the replaced Parameter. Throws ImapError.TYPE_ERROR if no Parameter exists at the
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);
427
Parameter old = this.list[index];
428
this.list[index] = parameter;
433
* Moves all child parameters from the supplied list into this list, clearing this list first.
435
* The supplied list will be "stripped" of its children. This ListParameter is cleared prior
436
* to adopting the new children.
438
public void adopt_children(ListParameter src) {
441
Gee.List<Parameter> src_children = new Gee.ArrayList<Parameter>();
442
src_children.add_all(src.list);
445
add_all(src_children);
448
protected string stringize_list() {
449
StringBuilder builder = new StringBuilder();
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(' ');
464
public override string to_string() {
465
return "(%s)".printf(stringize_list());
471
public override void serialize(Serializer ser, GLib.Cancellable cancellable)
473
ser.push_ascii('(', cancellable);
474
serialize_list(ser, cancellable);
475
ser.push_ascii(')', cancellable);
478
protected void serialize_list(Serializer ser, GLib.Cancellable cancellable)
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);