dom/mobilemessage/src/gonk/MmsPduHelper.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
michael@0 8
michael@0 9 let WSP = {};
michael@0 10 Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP);
michael@0 11
michael@0 12 Cu.import("resource://gre/modules/mms_consts.js");
michael@0 13
michael@0 14 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
michael@0 15
michael@0 16 let DEBUG; // set to true to see debug messages
michael@0 17
michael@0 18 this.MMS_VERSION = (function() {
michael@0 19 Cu.import("resource://gre/modules/Services.jsm");
michael@0 20
michael@0 21 try {
michael@0 22 return Services.prefs.getIntPref("dom.mms.version");
michael@0 23 } catch(ex) {}
michael@0 24
michael@0 25 return MMS_VERSION_1_3;
michael@0 26 })();
michael@0 27
michael@0 28 this.translatePduErrorToStatus = function translatePduErrorToStatus(error) {
michael@0 29 if (error == MMS_PDU_ERROR_OK) {
michael@0 30 return MMS_PDU_STATUS_RETRIEVED;
michael@0 31 }
michael@0 32
michael@0 33 if ((error >= MMS_PDU_ERROR_TRANSIENT_FAILURE)
michael@0 34 && (error < MMS_PDU_ERROR_PERMANENT_FAILURE)) {
michael@0 35 return MMS_PDU_STATUS_DEFERRED;
michael@0 36 }
michael@0 37
michael@0 38 return MMS_PDU_STATUS_UNRECOGNISED;
michael@0 39 }
michael@0 40
michael@0 41 function defineLazyRegExp(obj, name, pattern) {
michael@0 42 obj.__defineGetter__(name, function() {
michael@0 43 delete obj[name];
michael@0 44 return obj[name] = new RegExp(pattern);
michael@0 45 });
michael@0 46 }
michael@0 47
michael@0 48 function RangedValue(name, min, max) {
michael@0 49 this.name = name;
michael@0 50 this.min = min;
michael@0 51 this.max = max;
michael@0 52 }
michael@0 53 RangedValue.prototype = {
michael@0 54 name: null,
michael@0 55 min: null,
michael@0 56 max: null,
michael@0 57
michael@0 58 /**
michael@0 59 * @param data
michael@0 60 * A wrapped object containing raw PDU data.
michael@0 61 *
michael@0 62 * @return A decoded integer.
michael@0 63 *
michael@0 64 * @throws CodeError if decoded value is not in the range [this.min, this.max].
michael@0 65 */
michael@0 66 decode: function(data) {
michael@0 67 let value = WSP.Octet.decode(data);
michael@0 68 if ((value >= this.min) && (value <= this.max)) {
michael@0 69 return value;
michael@0 70 }
michael@0 71
michael@0 72 throw new WSP.CodeError(this.name + ": invalid value " + value);
michael@0 73 },
michael@0 74
michael@0 75 /**
michael@0 76 * @param data
michael@0 77 * A wrapped object to store encoded raw data.
michael@0 78 * @param value
michael@0 79 * An integer value within thr range [this.min, this.max].
michael@0 80 */
michael@0 81 encode: function(data, value) {
michael@0 82 if ((value < this.min) || (value > this.max)) {
michael@0 83 throw new WSP.CodeError(this.name + ": invalid value " + value);
michael@0 84 }
michael@0 85
michael@0 86 WSP.Octet.encode(data, value);
michael@0 87 },
michael@0 88 };
michael@0 89
michael@0 90 /**
michael@0 91 * Internal decoding function for boolean values.
michael@0 92 *
michael@0 93 * Boolean-value = Yes | No
michael@0 94 * Yes = <Octet 128>
michael@0 95 * No = <Octet 129>
michael@0 96 */
michael@0 97 this.BooleanValue = {
michael@0 98 /**
michael@0 99 * @param data
michael@0 100 * A wrapped object containing raw PDU data.
michael@0 101 *
michael@0 102 * @return Boolean true or false.
michael@0 103 *
michael@0 104 * @throws CodeError if read octet equals to neither 128 nor 129.
michael@0 105 */
michael@0 106 decode: function(data) {
michael@0 107 let value = WSP.Octet.decode(data);
michael@0 108 if ((value != 128) && (value != 129)) {
michael@0 109 throw new WSP.CodeError("Boolean-value: invalid value " + value);
michael@0 110 }
michael@0 111
michael@0 112 return value == 128;
michael@0 113 },
michael@0 114
michael@0 115 /**
michael@0 116 * @param data
michael@0 117 * A wrapped object to store encoded raw data.
michael@0 118 * @param value
michael@0 119 * A boolean value to be encoded.
michael@0 120 */
michael@0 121 encode: function(data, value) {
michael@0 122 WSP.Octet.encode(data, value ? 128 : 129);
michael@0 123 },
michael@0 124 };
michael@0 125
michael@0 126 /**
michael@0 127 * MMS Address
michael@0 128 *
michael@0 129 * address = email | device-address | alphanum-shortcode | num-shortcode
michael@0 130 *
michael@0 131 * @see OMA-TS-MMS_ENC-V1_3-20110913-A section 8
michael@0 132 */
michael@0 133 this.Address = {
michael@0 134 /**
michael@0 135 * @param data
michael@0 136 * A wrapped object to store encoded raw data.
michael@0 137 *
michael@0 138 * @return An object of two string-typed attributes: address and type.
michael@0 139 */
michael@0 140 decode: function(data) {
michael@0 141 let str = EncodedStringValue.decode(data);
michael@0 142
michael@0 143 let result;
michael@0 144 if (((result = str.match(this.REGEXP_DECODE_PLMN)) != null)
michael@0 145 || ((result = str.match(this.REGEXP_DECODE_IPV4)) != null)
michael@0 146 || ((result = str.match(this.REGEXP_DECODE_IPV6)) != null)
michael@0 147 || ((result = str.match(this.REGEXP_DECODE_CUSTOM)) != null)) {
michael@0 148 return {address: result[1], type: result[2]};
michael@0 149 }
michael@0 150
michael@0 151 let type;
michael@0 152 if (str.match(this.REGEXP_NUM)) {
michael@0 153 type = "num";
michael@0 154 } else if (str.match(this.REGEXP_ALPHANUM)) {
michael@0 155 type = "alphanum";
michael@0 156 } else if (str.indexOf("@") > 0) {
michael@0 157 // E-mail should match the definition of `mailbox` as described in section
michael@0 158 // 3.4 of RFC2822, but excluding the obsolete definitions as indicated by
michael@0 159 // the "obs-" prefix. Here we match only a `@` character.
michael@0 160 type = "email";
michael@0 161 } else {
michael@0 162 throw new WSP.CodeError("Address: invalid address");
michael@0 163 }
michael@0 164
michael@0 165 return {address: str, type: type};
michael@0 166 },
michael@0 167
michael@0 168 /**
michael@0 169 * @param data
michael@0 170 * A wrapped object to store encoded raw data.
michael@0 171 * @param value
michael@0 172 * An object of two string-typed attributes: address and type.
michael@0 173 */
michael@0 174 encode: function(data, value) {
michael@0 175 if (!value || !value.type || !value.address) {
michael@0 176 throw new WSP.CodeError("Address: invalid value");
michael@0 177 }
michael@0 178
michael@0 179 let str;
michael@0 180 switch (value.type) {
michael@0 181 case "email":
michael@0 182 if (value.address.indexOf("@") > 0) {
michael@0 183 str = value.address;
michael@0 184 }
michael@0 185 break;
michael@0 186 case "num":
michael@0 187 if (value.address.match(this.REGEXP_NUM)) {
michael@0 188 str = value.address;
michael@0 189 }
michael@0 190 break;
michael@0 191 case "alphanum":
michael@0 192 if (value.address.match(this.REGEXP_ALPHANUM)) {
michael@0 193 str = value.address;
michael@0 194 }
michael@0 195 break;
michael@0 196 case "IPv4":
michael@0 197 if (value.address.match(this.REGEXP_ENCODE_IPV4)) {
michael@0 198 str = value.address + "/TYPE=IPv4";
michael@0 199 }
michael@0 200 break;
michael@0 201 case "IPv6":
michael@0 202 if (value.address.match(this.REGEXP_ENCODE_IPV6)) {
michael@0 203 str = value.address + "/TYPE=IPv6";
michael@0 204 }
michael@0 205 break;
michael@0 206 case "PLMN":
michael@0 207 if (value.address.match(this.REGEXP_ENCODE_PLMN)) {
michael@0 208 str = value.address + "/TYPE=PLMN";
michael@0 209 }
michael@0 210 break;
michael@0 211 default:
michael@0 212 if (value.type.match(this.REGEXP_ENCODE_CUSTOM_TYPE)
michael@0 213 && value.address.match(this.REGEXP_ENCODE_CUSTOM_ADDR)) {
michael@0 214 str = value.address + "/TYPE=" + value.type;
michael@0 215 }
michael@0 216 break;
michael@0 217 }
michael@0 218
michael@0 219 if (!str) {
michael@0 220 throw new WSP.CodeError("Address: invalid value: " + JSON.stringify(value));
michael@0 221 }
michael@0 222
michael@0 223 EncodedStringValue.encode(data, str);
michael@0 224 },
michael@0 225
michael@0 226 /**
michael@0 227 * @param address
michael@0 228 * Address string which want to find the type.
michael@0 229 *
michael@0 230 * @return Address type.
michael@0 231 */
michael@0 232 resolveType: function(address) {
michael@0 233 if (address.match(this.REGEXP_EMAIL)) {
michael@0 234 return "email";
michael@0 235 }
michael@0 236
michael@0 237 if (address.match(this.REGEXP_IPV4)) {
michael@0 238 return "IPv4";
michael@0 239 }
michael@0 240
michael@0 241 if (address.match(this.REGEXP_IPV6)) {
michael@0 242 return "IPv6";
michael@0 243 }
michael@0 244
michael@0 245 let normalizedAddress = PhoneNumberUtils.normalize(address, false);
michael@0 246 if (PhoneNumberUtils.isPlainPhoneNumber(normalizedAddress)) {
michael@0 247 return "PLMN";
michael@0 248 }
michael@0 249
michael@0 250 return "Others";
michael@0 251 },
michael@0 252 };
michael@0 253
michael@0 254 defineLazyRegExp(Address, "REGEXP_DECODE_PLMN", "^(\\+?[\\d.-]+)\\/TYPE=(PLMN)$");
michael@0 255 defineLazyRegExp(Address, "REGEXP_DECODE_IPV4", "^(\\d{1,3}(?:\\.\\d{1,3}){3})\\/TYPE=(IPv4)$");
michael@0 256 defineLazyRegExp(Address, "REGEXP_DECODE_IPV6", "^([\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7})\\/TYPE=(IPv6)$");
michael@0 257 defineLazyRegExp(Address, "REGEXP_DECODE_CUSTOM", "^([\\w\\+\\-.%]+)\\/TYPE=(\\w+)$");
michael@0 258 defineLazyRegExp(Address, "REGEXP_ENCODE_PLMN", "^\\+?[\\d.-]+$");
michael@0 259 defineLazyRegExp(Address, "REGEXP_ENCODE_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
michael@0 260 defineLazyRegExp(Address, "REGEXP_ENCODE_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
michael@0 261 defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_TYPE", "^\\w+$");
michael@0 262 defineLazyRegExp(Address, "REGEXP_ENCODE_CUSTOM_ADDR", "^[\\w\\+\\-.%]+$");
michael@0 263 defineLazyRegExp(Address, "REGEXP_NUM", "^[\\+*#]\\d+$");
michael@0 264 defineLazyRegExp(Address, "REGEXP_ALPHANUM", "^\\w+$");
michael@0 265 defineLazyRegExp(Address, "REGEXP_PLMN", "^\\?[\\d.-]$");
michael@0 266 defineLazyRegExp(Address, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
michael@0 267 defineLazyRegExp(Address, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
michael@0 268 defineLazyRegExp(Address, "REGEXP_EMAIL", "@");
michael@0 269
michael@0 270 /**
michael@0 271 * Header-field = MMS-header | Application-header
michael@0 272 *
michael@0 273 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.2
michael@0 274 */
michael@0 275 this.HeaderField = {
michael@0 276 /**
michael@0 277 * @param data
michael@0 278 * A wrapped object containing raw PDU data.
michael@0 279 * @param options
michael@0 280 * Extra context for decoding.
michael@0 281 *
michael@0 282 * @return A decoded object containing `name` and `value` properties or null
michael@0 283 * in case of a failed parsing. The `name` property must be a string,
michael@0 284 * but the `value` property can be many different types depending on
michael@0 285 * `name`.
michael@0 286 */
michael@0 287 decode: function(data, options) {
michael@0 288 return WSP.decodeAlternatives(data, options,
michael@0 289 MmsHeader, WSP.ApplicationHeader);
michael@0 290 },
michael@0 291
michael@0 292 /**
michael@0 293 * @param data
michael@0 294 * A wrapped object to store encoded raw data.
michael@0 295 * @param octet
michael@0 296 * Octet value to be encoded.
michael@0 297 * @param options
michael@0 298 * Extra context for encoding.
michael@0 299 */
michael@0 300 encode: function(data, value, options) {
michael@0 301 WSP.encodeAlternatives(data, value, options,
michael@0 302 MmsHeader, WSP.ApplicationHeader);
michael@0 303 },
michael@0 304 };
michael@0 305
michael@0 306 /**
michael@0 307 * MMS-header = MMS-field-name MMS-value
michael@0 308 * MMS-field-name = Short-integer
michael@0 309 *
michael@0 310 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.2
michael@0 311 */
michael@0 312 this.MmsHeader = {
michael@0 313 /**
michael@0 314 * @param data
michael@0 315 * A wrapped object containing raw PDU data.
michael@0 316 * @param options
michael@0 317 * Extra context for decoding.
michael@0 318 *
michael@0 319 * @return A decoded object containing `name` and `value` properties or null
michael@0 320 * in case of a failed parsing. The `name` property must be a string,
michael@0 321 * but the `value` property can be many different types depending on
michael@0 322 * `name`.
michael@0 323 *
michael@0 324 * @throws NotWellKnownEncodingError if decoded well-known header field
michael@0 325 * number is not registered or supported.
michael@0 326 */
michael@0 327 decode: function(data, options) {
michael@0 328 let index = WSP.ShortInteger.decode(data);
michael@0 329
michael@0 330 let entry = MMS_HEADER_FIELDS[index];
michael@0 331 if (!entry) {
michael@0 332 throw new WSP.NotWellKnownEncodingError(
michael@0 333 "MMS-header: not well known header " + index);
michael@0 334 }
michael@0 335
michael@0 336 let cur = data.offset, value;
michael@0 337 try {
michael@0 338 value = entry.coder.decode(data, options);
michael@0 339 } catch (e) {
michael@0 340 data.offset = cur;
michael@0 341
michael@0 342 value = WSP.skipValue(data);
michael@0 343 debug("Skip malformed well known header: "
michael@0 344 + JSON.stringify({name: entry.name, value: value}));
michael@0 345
michael@0 346 return null;
michael@0 347 }
michael@0 348
michael@0 349 return {
michael@0 350 name: entry.name,
michael@0 351 value: value,
michael@0 352 };
michael@0 353 },
michael@0 354
michael@0 355 /**
michael@0 356 * @param data
michael@0 357 * A wrapped object to store encoded raw data.
michael@0 358 * @param header
michael@0 359 * An object containing two attributes: a string-typed `name` and a
michael@0 360 * `value` of arbitrary type.
michael@0 361 *
michael@0 362 * @throws CodeError if got an empty header name.
michael@0 363 * @throws NotWellKnownEncodingError if the well-known header field number is
michael@0 364 * not registered or supported.
michael@0 365 */
michael@0 366 encode: function(data, header) {
michael@0 367 if (!header.name) {
michael@0 368 throw new WSP.CodeError("MMS-header: empty header name");
michael@0 369 }
michael@0 370
michael@0 371 let entry = MMS_HEADER_FIELDS[header.name.toLowerCase()];
michael@0 372 if (!entry) {
michael@0 373 throw new WSP.NotWellKnownEncodingError(
michael@0 374 "MMS-header: not well known header " + header.name);
michael@0 375 }
michael@0 376
michael@0 377 WSP.ShortInteger.encode(data, entry.number);
michael@0 378 entry.coder.encode(data, header.value);
michael@0 379 },
michael@0 380 };
michael@0 381
michael@0 382 /**
michael@0 383 * Cancel-status-value = Cancel Request Successfully received |
michael@0 384 * Cancel Request corrupted
michael@0 385 *
michael@0 386 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.7
michael@0 387 */
michael@0 388 this.CancelStatusValue = new RangedValue("Cancel-status-value", 128, 129);
michael@0 389
michael@0 390 /**
michael@0 391 * Content-class-value = text | image-basic| image-rich | video-basic |
michael@0 392 * video-rich | megapixel | content-basic | content-rich
michael@0 393 *
michael@0 394 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.9
michael@0 395 */
michael@0 396 this.ContentClassValue = new RangedValue("Content-class-value", 128, 135);
michael@0 397
michael@0 398 /**
michael@0 399 * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
michael@0 400 *
michael@0 401 * Content-location-value = Uri-value
michael@0 402 *
michael@0 403 * When used in the M-Mbox-Delete.conf and M-Delete.conf PDU:
michael@0 404 *
michael@0 405 * Content-location-Del-value = Value-length Status-count-value Content-location-value
michael@0 406 * Status-count-value = Integer-value
michael@0 407 *
michael@0 408 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.10
michael@0 409 */
michael@0 410 this.ContentLocationValue = {
michael@0 411 /**
michael@0 412 * @param data
michael@0 413 * A wrapped object containing raw PDU data.
michael@0 414 * @param options
michael@0 415 * Extra context for decoding.
michael@0 416 *
michael@0 417 * @return A decoded object containing `uri` and conditional `statusCount`
michael@0 418 * properties.
michael@0 419 */
michael@0 420 decode: function(data, options) {
michael@0 421 let type = WSP.ensureHeader(options, "x-mms-message-type");
michael@0 422
michael@0 423 let result = {};
michael@0 424 if ((type == MMS_PDU_TYPE_MBOX_DELETE_CONF)
michael@0 425 || (type == MMS_PDU_TYPE_DELETE_CONF)) {
michael@0 426 let length = WSP.ValueLength.decode(data);
michael@0 427 let end = data.offset + length;
michael@0 428
michael@0 429 result.statusCount = WSP.IntegerValue.decode(data);
michael@0 430 result.uri = WSP.UriValue.decode(data);
michael@0 431
michael@0 432 if (data.offset != end) {
michael@0 433 data.offset = end;
michael@0 434 }
michael@0 435 } else {
michael@0 436 result.uri = WSP.UriValue.decode(data);
michael@0 437 }
michael@0 438
michael@0 439 return result;
michael@0 440 },
michael@0 441 };
michael@0 442
michael@0 443 /**
michael@0 444 * Element-Descriptor-value = Value-length Content-Reference-value *(Parameter)
michael@0 445 * Content-Reference-value = Text-string
michael@0 446 *
michael@0 447 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.18
michael@0 448 */
michael@0 449 this.ElementDescriptorValue = {
michael@0 450 /**
michael@0 451 * @param data
michael@0 452 * A wrapped object containing raw PDU data.
michael@0 453 *
michael@0 454 * @return A decoded object containing a string property `contentReference`
michael@0 455 * and an optinal `params` name-value map.
michael@0 456 */
michael@0 457 decode: function(data) {
michael@0 458 let length = WSP.ValueLength.decode(data);
michael@0 459 let end = data.offset + length;
michael@0 460
michael@0 461 let result = {};
michael@0 462 result.contentReference = WSP.TextString.decode(data);
michael@0 463 if (data.offset < end) {
michael@0 464 result.params = Parameter.decodeMultiple(data, end);
michael@0 465 }
michael@0 466
michael@0 467 if (data.offset != end) {
michael@0 468 // Explicitly seek to end in case of skipped parameters.
michael@0 469 data.offset = end;
michael@0 470 }
michael@0 471
michael@0 472 return result;
michael@0 473 },
michael@0 474 };
michael@0 475
michael@0 476 /**
michael@0 477 * OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.18:
michael@0 478 * `For well-known parameter names binary tokens MUST be used as defined in
michael@0 479 * Table 27.` So we can't reuse that of WSP.
michael@0 480 *
michael@0 481 * Parameter = Parameter-name Parameter-value
michael@0 482 * Parameter-name = Short-integer | Text-string
michael@0 483 * Parameter-value = Constrained-encoding | Text-string
michael@0 484 *
michael@0 485 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.18
michael@0 486 */
michael@0 487 this.Parameter = {
michael@0 488 /**
michael@0 489 * @param data
michael@0 490 * A wrapped object containing raw PDU data.
michael@0 491 *
michael@0 492 * @return A decoded string.
michael@0 493 *
michael@0 494 * @throws NotWellKnownEncodingError if decoded well-known parameter number
michael@0 495 * is not registered or supported.
michael@0 496 */
michael@0 497 decodeParameterName: function(data) {
michael@0 498 let begin = data.offset;
michael@0 499 let number;
michael@0 500 try {
michael@0 501 number = WSP.ShortInteger.decode(data);
michael@0 502 } catch (e) {
michael@0 503 data.offset = begin;
michael@0 504 return WSP.TextString.decode(data).toLowerCase();
michael@0 505 }
michael@0 506
michael@0 507 let entry = MMS_WELL_KNOWN_PARAMS[number];
michael@0 508 if (!entry) {
michael@0 509 throw new WSP.NotWellKnownEncodingError(
michael@0 510 "Parameter-name: not well known parameter " + number);
michael@0 511 }
michael@0 512
michael@0 513 return entry.name;
michael@0 514 },
michael@0 515
michael@0 516 /**
michael@0 517 * @param data
michael@0 518 * A wrapped object containing raw PDU data.
michael@0 519 *
michael@0 520 * @return A decoded object containing `name` and `value` properties or null
michael@0 521 * in case of a failed parsing. The `name` property must be a string,
michael@0 522 * but the `value` property can be many different types depending on
michael@0 523 * `name`.
michael@0 524 */
michael@0 525 decode: function(data) {
michael@0 526 let name = this.decodeParameterName(data);
michael@0 527 let value = WSP.decodeAlternatives(data, null,
michael@0 528 WSP.ConstrainedEncoding, WSP.TextString);
michael@0 529 return {
michael@0 530 name: name,
michael@0 531 value: value,
michael@0 532 };
michael@0 533 },
michael@0 534
michael@0 535 /**
michael@0 536 * @param data
michael@0 537 * A wrapped object containing raw PDU data.
michael@0 538 * @param end
michael@0 539 * Ending offset of following parameters.
michael@0 540 *
michael@0 541 * @return An array of decoded objects.
michael@0 542 */
michael@0 543 decodeMultiple: function(data, end) {
michael@0 544 let params, param;
michael@0 545
michael@0 546 while (data.offset < end) {
michael@0 547 try {
michael@0 548 param = this.decode(data);
michael@0 549 } catch (e) {
michael@0 550 break;
michael@0 551 }
michael@0 552 if (param) {
michael@0 553 if (!params) {
michael@0 554 params = {};
michael@0 555 }
michael@0 556 params[param.name] = param.value;
michael@0 557 }
michael@0 558 }
michael@0 559
michael@0 560 return params;
michael@0 561 },
michael@0 562
michael@0 563 /**
michael@0 564 * @param data
michael@0 565 * A wrapped object to store encoded raw data.
michael@0 566 * @param param
michael@0 567 * An object containing two attributes: `name` and `value`.
michael@0 568 * @param options
michael@0 569 * Extra context for encoding.
michael@0 570 */
michael@0 571 encode: function(data, param, options) {
michael@0 572 if (!param || !param.name) {
michael@0 573 throw new WSP.CodeError("Parameter-name: empty param name");
michael@0 574 }
michael@0 575
michael@0 576 let entry = MMS_WELL_KNOWN_PARAMS[param.name.toLowerCase()];
michael@0 577 if (entry) {
michael@0 578 WSP.ShortInteger.encode(data, entry.number);
michael@0 579 } else {
michael@0 580 WSP.TextString.encode(data, param.name);
michael@0 581 }
michael@0 582
michael@0 583 WSP.encodeAlternatives(data, param.value, options,
michael@0 584 WSP.ConstrainedEncoding, WSP.TextString);
michael@0 585 },
michael@0 586 };
michael@0 587
michael@0 588 /**
michael@0 589 * The Char-set values are registered by IANA as MIBEnum value and SHALL be
michael@0 590 * encoded as Integer-value.
michael@0 591 *
michael@0 592 * Encoded-string-value = Text-string | Value-length Char-set Text-string
michael@0 593 *
michael@0 594 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.19
michael@0 595 * @see OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
michael@0 596 */
michael@0 597 this.EncodedStringValue = {
michael@0 598 /**
michael@0 599 * @param data
michael@0 600 * A wrapped object containing raw PDU data.
michael@0 601 *
michael@0 602 * @return Decoded string.
michael@0 603 *
michael@0 604 * @throws CodeError if the raw octets cannot be converted.
michael@0 605 * @throws NotWellKnownEncodingError if decoded well-known charset number is
michael@0 606 * not registered or supported.
michael@0 607 */
michael@0 608 decodeCharsetEncodedString: function(data) {
michael@0 609 let length = WSP.ValueLength.decode(data);
michael@0 610 let end = data.offset + length;
michael@0 611
michael@0 612 let charset = WSP.IntegerValue.decode(data);
michael@0 613 let entry = WSP.WSP_WELL_KNOWN_CHARSETS[charset];
michael@0 614 if (!entry) {
michael@0 615 throw new WSP.NotWellKnownEncodingError(
michael@0 616 "Charset-encoded-string: not well known charset " + charset);
michael@0 617 }
michael@0 618
michael@0 619 let str;
michael@0 620 if (entry.converter) {
michael@0 621 // Read a possible string quote(<Octet 127>).
michael@0 622 let begin = data.offset;
michael@0 623 if (WSP.Octet.decode(data) != 127) {
michael@0 624 data.offset = begin;
michael@0 625 }
michael@0 626
michael@0 627 let raw = WSP.Octet.decodeMultiple(data, end - 1);
michael@0 628 // Read NUL character.
michael@0 629 WSP.Octet.decodeEqualTo(data, 0);
michael@0 630
michael@0 631 if (!raw) {
michael@0 632 str = "";
michael@0 633 } else {
michael@0 634 let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
michael@0 635 .createInstance(Ci.nsIScriptableUnicodeConverter);
michael@0 636 conv.charset = entry.converter;
michael@0 637 try {
michael@0 638 str = conv.convertFromByteArray(raw, raw.length);
michael@0 639 } catch (e) {
michael@0 640 throw new WSP.CodeError("Charset-encoded-string: " + e.message);
michael@0 641 }
michael@0 642 }
michael@0 643 } else {
michael@0 644 str = WSP.TextString.decode(data);
michael@0 645 }
michael@0 646
michael@0 647 if (data.offset != end) {
michael@0 648 data.offset = end;
michael@0 649 }
michael@0 650
michael@0 651 return str;
michael@0 652 },
michael@0 653
michael@0 654 /**
michael@0 655 * @param data
michael@0 656 * A wrapped object containing raw PDU data.
michael@0 657 *
michael@0 658 * @return Decoded string.
michael@0 659 */
michael@0 660 decode: function(data) {
michael@0 661 let begin = data.offset;
michael@0 662 try {
michael@0 663 return WSP.TextString.decode(data);
michael@0 664 } catch (e) {
michael@0 665 data.offset = begin;
michael@0 666 return this.decodeCharsetEncodedString(data);
michael@0 667 }
michael@0 668 },
michael@0 669
michael@0 670 /**
michael@0 671 * Always encode target string with UTF-8 encoding.
michael@0 672 *
michael@0 673 * @param data
michael@0 674 * A wrapped object to store encoded raw data.
michael@0 675 * @param str
michael@0 676 * A string.
michael@0 677 */
michael@0 678 encodeCharsetEncodedString: function(data, str) {
michael@0 679 let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
michael@0 680 .createInstance(Ci.nsIScriptableUnicodeConverter);
michael@0 681 // `When the text string cannot be represented as us-ascii, the character
michael@0 682 // set SHALL be encoded as utf-8(IANA MIBenum 106) which has unique byte
michael@0 683 // ordering.` ~ OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
michael@0 684 conv.charset = "UTF-8";
michael@0 685
michael@0 686 let raw;
michael@0 687 try {
michael@0 688 raw = conv.convertToByteArray(str);
michael@0 689 } catch (e) {
michael@0 690 throw new WSP.CodeError("Charset-encoded-string: " + e.message);
michael@0 691 }
michael@0 692
michael@0 693 let length = raw.length + 2; // Charset number and NUL character
michael@0 694 // Prepend <Octet 127> if necessary.
michael@0 695 if (raw[0] >= 128) {
michael@0 696 ++length;
michael@0 697 }
michael@0 698
michael@0 699 WSP.ValueLength.encode(data, length);
michael@0 700
michael@0 701 let entry = WSP.WSP_WELL_KNOWN_CHARSETS["utf-8"];
michael@0 702 WSP.IntegerValue.encode(data, entry.number);
michael@0 703
michael@0 704 if (raw[0] >= 128) {
michael@0 705 WSP.Octet.encode(data, 127);
michael@0 706 }
michael@0 707 WSP.Octet.encodeMultiple(data, raw);
michael@0 708 WSP.Octet.encode(data, 0);
michael@0 709 },
michael@0 710
michael@0 711 /**
michael@0 712 * @param data
michael@0 713 * A wrapped object to store encoded raw data.
michael@0 714 * @param str
michael@0 715 * A string.
michael@0 716 */
michael@0 717 encode: function(data, str) {
michael@0 718 let begin = data.offset;
michael@0 719 try {
michael@0 720 // Quoted from OMA-TS-MMS-CONF-V1_3-20110913-A:
michael@0 721 // Some of the MMS headers have been defined as "Encoded-string-value".
michael@0 722 // The character set IANA MIBEnum value in these headers SHALL be
michael@0 723 // encoded as Integer-value ([WAPWSP] section 8.4.2.3). The character
michael@0 724 // set us-ascii (IANA MIBenum 3) SHALL always be accepted. If the
michael@0 725 // character set is not specified (simple Text-string encoding) the
michael@0 726 // character set SHALL be identified as us-ascii (lower half of ISO
michael@0 727 // 8859-1 [ISO8859-1]). When the text string cannot be represented as
michael@0 728 // us-ascii, the character set SHALL be encoded as utf-8 (IANA MIBenum
michael@0 729 // 106) which has unique byte ordering.
michael@0 730 WSP.TextString.encode(data, str, true);
michael@0 731 } catch (e) {
michael@0 732 data.offset = begin;
michael@0 733 this.encodeCharsetEncodedString(data, str);
michael@0 734 }
michael@0 735 },
michael@0 736 };
michael@0 737
michael@0 738 /**
michael@0 739 * Expiry-value = Value-length (Absolute-token Date-value | Relative-token Delta-seconds-value)
michael@0 740 * Absolute-token = <Octet 128>
michael@0 741 * Relative-token = <Octet 129>
michael@0 742 *
michael@0 743 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.20
michael@0 744 */
michael@0 745 this.ExpiryValue = {
michael@0 746 /**
michael@0 747 * @param data
michael@0 748 * A wrapped object containing raw PDU data.
michael@0 749 *
michael@0 750 * @return A Date object for absolute expiry or an integer for relative one.
michael@0 751 *
michael@0 752 * @throws CodeError if decoded token equals to neither 128 nor 129.
michael@0 753 */
michael@0 754 decode: function(data) {
michael@0 755 let length = WSP.ValueLength.decode(data);
michael@0 756 let end = data.offset + length;
michael@0 757
michael@0 758 let token = WSP.Octet.decode(data);
michael@0 759 if ((token != 128) && (token != 129)) {
michael@0 760 throw new WSP.CodeError("Expiry-value: invalid token " + token);
michael@0 761 }
michael@0 762
michael@0 763 let result;
michael@0 764 if (token == 128) {
michael@0 765 result = WSP.DateValue.decode(data);
michael@0 766 } else {
michael@0 767 result = WSP.DeltaSecondsValue.decode(data);
michael@0 768 }
michael@0 769
michael@0 770 if (data.offset != end) {
michael@0 771 data.offset = end;
michael@0 772 }
michael@0 773
michael@0 774 return result;
michael@0 775 },
michael@0 776
michael@0 777 /**
michael@0 778 * @param data
michael@0 779 * A wrapped object to store encoded raw data.
michael@0 780 * @param value
michael@0 781 * A Date object for absolute expiry or an integer for relative one.
michael@0 782 */
michael@0 783 encode: function(data, value) {
michael@0 784 let isDate, begin = data.offset;
michael@0 785 if (value instanceof Date) {
michael@0 786 isDate = true;
michael@0 787 WSP.DateValue.encode(data, value);
michael@0 788 } else if (typeof value == "number") {
michael@0 789 isDate = false;
michael@0 790 WSP.DeltaSecondsValue.encode(data, value);
michael@0 791 } else {
michael@0 792 throw new CodeError("Expiry-value: invalid value type");
michael@0 793 }
michael@0 794
michael@0 795 // Calculate how much octets will be written and seek back.
michael@0 796 // TODO: use memmove, see bug 730873
michael@0 797 let len = data.offset - begin;
michael@0 798 data.offset = begin;
michael@0 799
michael@0 800 WSP.ValueLength.encode(data, len + 1);
michael@0 801 if (isDate) {
michael@0 802 WSP.Octet.encode(data, 128);
michael@0 803 WSP.DateValue.encode(data, value);
michael@0 804 } else {
michael@0 805 WSP.Octet.encode(data, 129);
michael@0 806 WSP.DeltaSecondsValue.encode(data, value);
michael@0 807 }
michael@0 808 },
michael@0 809 };
michael@0 810
michael@0 811 /**
michael@0 812 * From-value = Value-length (Address-present-token Address | Insert-address-token)
michael@0 813 * Address-present-token = <Octet 128>
michael@0 814 * Insert-address-token = <Octet 129>
michael@0 815 *
michael@0 816 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.21
michael@0 817 */
michael@0 818 this.FromValue = {
michael@0 819 /**
michael@0 820 * @param data
michael@0 821 * A wrapped object containing raw PDU data.
michael@0 822 *
michael@0 823 * @return A decoded Address-value or null for MMS Proxy-Relay Insert-Address
michael@0 824 * mode.
michael@0 825 *
michael@0 826 * @throws CodeError if decoded token equals to neither 128 nor 129.
michael@0 827 */
michael@0 828 decode: function(data) {
michael@0 829 let length = WSP.ValueLength.decode(data);
michael@0 830 let end = data.offset + length;
michael@0 831
michael@0 832 let token = WSP.Octet.decode(data);
michael@0 833 if ((token != 128) && (token != 129)) {
michael@0 834 throw new WSP.CodeError("From-value: invalid token " + token);
michael@0 835 }
michael@0 836
michael@0 837 let result = null;
michael@0 838 if (token == 128) {
michael@0 839 result = Address.decode(data);
michael@0 840 }
michael@0 841
michael@0 842 if (data.offset != end) {
michael@0 843 data.offset = end;
michael@0 844 }
michael@0 845
michael@0 846 return result;
michael@0 847 },
michael@0 848
michael@0 849 /**
michael@0 850 * @param data
michael@0 851 * A wrapped object to store encoded raw data.
michael@0 852 * @param value
michael@0 853 * A Address-value or null for MMS Proxy-Relay Insert-Address mode.
michael@0 854 */
michael@0 855 encode: function(data, value) {
michael@0 856 if (!value) {
michael@0 857 WSP.ValueLength.encode(data, 1);
michael@0 858 WSP.Octet.encode(data, 129);
michael@0 859 return;
michael@0 860 }
michael@0 861
michael@0 862 // Calculate how much octets will be written and seek back.
michael@0 863 // TODO: use memmove, see bug 730873
michael@0 864 let begin = data.offset;
michael@0 865 Address.encode(data, value);
michael@0 866 let len = data.offset - begin;
michael@0 867 data.offset = begin;
michael@0 868
michael@0 869 WSP.ValueLength.encode(data, len + 1);
michael@0 870 WSP.Octet.encode(data, 128);
michael@0 871 Address.encode(data, value);
michael@0 872 },
michael@0 873 };
michael@0 874
michael@0 875 /**
michael@0 876 * Previously-sent-by-value = Value-length Forwarded-count-value Address
michael@0 877 * Forwarded-count-value = Integer-value
michael@0 878 *
michael@0 879 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.23
michael@0 880 */
michael@0 881 this.PreviouslySentByValue = {
michael@0 882 /**
michael@0 883 * @param data
michael@0 884 * A wrapped object containing raw PDU data.
michael@0 885 *
michael@0 886 * @return Decoded object containing an integer `forwardedCount` and an
michael@0 887 * string-typed `originator` attributes.
michael@0 888 */
michael@0 889 decode: function(data) {
michael@0 890 let length = WSP.ValueLength.decode(data);
michael@0 891 let end = data.offset + length;
michael@0 892
michael@0 893 let result = {};
michael@0 894 result.forwardedCount = WSP.IntegerValue.decode(data);
michael@0 895 result.originator = Address.decode(data);
michael@0 896
michael@0 897 if (data.offset != end) {
michael@0 898 data.offset = end;
michael@0 899 }
michael@0 900
michael@0 901 return result;
michael@0 902 },
michael@0 903 };
michael@0 904
michael@0 905 /**
michael@0 906 * Previously-sent-date-value = Value-length Forwarded-count-value Date-value
michael@0 907 *
michael@0 908 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.23
michael@0 909 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.24
michael@0 910 */
michael@0 911 this.PreviouslySentDateValue = {
michael@0 912 /**
michael@0 913 * @param data
michael@0 914 * A wrapped object containing raw PDU data.
michael@0 915 *
michael@0 916 * @return Decoded object containing an integer `forwardedCount` and an
michael@0 917 * Date-typed `timestamp` attributes.
michael@0 918 */
michael@0 919 decode: function(data) {
michael@0 920 let length = WSP.ValueLength.decode(data);
michael@0 921 let end = data.offset + length;
michael@0 922
michael@0 923 let result = {};
michael@0 924 result.forwardedCount = WSP.IntegerValue.decode(data);
michael@0 925 result.timestamp = WSP.DateValue.decode(data);
michael@0 926
michael@0 927 if (data.offset != end) {
michael@0 928 data.offset = end;
michael@0 929 }
michael@0 930
michael@0 931 return result;
michael@0 932 },
michael@0 933 };
michael@0 934
michael@0 935 /**
michael@0 936 * Message-class-value = Class-identifier | Token-text
michael@0 937 * Class-identifier = Personal | Advertisement | Informational | Auto
michael@0 938 * Personal = <Octet 128>
michael@0 939 * Advertisement = <Octet 129>
michael@0 940 * Informational = <Octet 130>
michael@0 941 * Auto = <Octet 131>
michael@0 942 *
michael@0 943 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.27
michael@0 944 */
michael@0 945 this.MessageClassValue = {
michael@0 946 WELL_KNOWN_CLASSES: ["personal", "advertisement", "informational", "auto"],
michael@0 947
michael@0 948 /**
michael@0 949 * @param data
michael@0 950 * A wrapped object containing raw PDU data.
michael@0 951 *
michael@0 952 * @return A decoded string.
michael@0 953 *
michael@0 954 * @throws CodeError if decoded value is not in the range 128..131.
michael@0 955 */
michael@0 956 decodeClassIdentifier: function(data) {
michael@0 957 let value = WSP.Octet.decode(data);
michael@0 958 if ((value >= 128) && (value < (128 + this.WELL_KNOWN_CLASSES.length))) {
michael@0 959 return this.WELL_KNOWN_CLASSES[value - 128];
michael@0 960 }
michael@0 961
michael@0 962 throw new WSP.CodeError("Class-identifier: invalid id " + value);
michael@0 963 },
michael@0 964
michael@0 965 /**
michael@0 966 * @param data
michael@0 967 * A wrapped object containing raw PDU data.
michael@0 968 *
michael@0 969 * @return A decoded string.
michael@0 970 */
michael@0 971 decode: function(data) {
michael@0 972 let begin = data.offset;
michael@0 973 try {
michael@0 974 return this.decodeClassIdentifier(data);
michael@0 975 } catch (e) {
michael@0 976 data.offset = begin;
michael@0 977 return WSP.TokenText.decode(data);
michael@0 978 }
michael@0 979 },
michael@0 980
michael@0 981 /**
michael@0 982 * @param data
michael@0 983 * A wrapped object to store encoded raw data.
michael@0 984 * @param klass
michael@0 985 */
michael@0 986 encode: function(data, klass) {
michael@0 987 let index = this.WELL_KNOWN_CLASSES.indexOf(klass.toLowerCase());
michael@0 988 if (index >= 0) {
michael@0 989 WSP.Octet.encode(data, index + 128);
michael@0 990 } else {
michael@0 991 WSP.TokenText.encode(data, klass);
michael@0 992 }
michael@0 993 },
michael@0 994 };
michael@0 995
michael@0 996 /**
michael@0 997 * Message-type-value = <Octet 128..151>
michael@0 998 *
michael@0 999 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.30
michael@0 1000 */
michael@0 1001 this.MessageTypeValue = new RangedValue("Message-type-value", 128, 151);
michael@0 1002
michael@0 1003 /**
michael@0 1004 * MM-flags-value = Value-length ( Add-token | Remove-token | Filter-token ) Encoded-string-value
michael@0 1005 * Add-token = <Octet 128>
michael@0 1006 * Remove-token = <Octet 129>
michael@0 1007 * Filter-token = <Octet 130>
michael@0 1008 *
michael@0 1009 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.32
michael@0 1010 */
michael@0 1011 this.MmFlagsValue = {
michael@0 1012 /**
michael@0 1013 * @param data
michael@0 1014 * A wrapped object containing raw PDU data.
michael@0 1015 *
michael@0 1016 * @return Decoded object containing an integer `type` and an string-typed
michael@0 1017 * `text` attributes.
michael@0 1018 *
michael@0 1019 * @throws CodeError if decoded value is not in the range 128..130.
michael@0 1020 */
michael@0 1021 decode: function(data) {
michael@0 1022 let length = WSP.ValueLength.decode(data);
michael@0 1023 let end = data.offset + length;
michael@0 1024
michael@0 1025 let result = {};
michael@0 1026 result.type = WSP.Octet.decode(data);
michael@0 1027 if ((result.type < 128) || (result.type > 130)) {
michael@0 1028 throw new WSP.CodeError("MM-flags-value: invalid type " + result.type);
michael@0 1029 }
michael@0 1030 result.text = EncodedStringValue.decode(data);
michael@0 1031
michael@0 1032 if (data.offset != end) {
michael@0 1033 data.offset = end;
michael@0 1034 }
michael@0 1035
michael@0 1036 return result;
michael@0 1037 },
michael@0 1038
michael@0 1039 /**
michael@0 1040 * @param data
michael@0 1041 * A wrapped object to store encoded raw data.
michael@0 1042 * @param value
michael@0 1043 * An object containing an integer `type` and an string-typed
michael@0 1044 * `text` attributes.
michael@0 1045 */
michael@0 1046 encode: function(data, value) {
michael@0 1047 if ((value.type < 128) || (value.type > 130)) {
michael@0 1048 throw new WSP.CodeError("MM-flags-value: invalid type " + value.type);
michael@0 1049 }
michael@0 1050
michael@0 1051 // Calculate how much octets will be written and seek back.
michael@0 1052 // TODO: use memmove, see bug 730873
michael@0 1053 let begin = data.offset;
michael@0 1054 EncodedStringValue.encode(data, value.text);
michael@0 1055 let len = data.offset - begin;
michael@0 1056 data.offset = begin;
michael@0 1057
michael@0 1058 WSP.ValueLength.encode(data, len + 1);
michael@0 1059 WSP.Octet.encode(data, value.type);
michael@0 1060 EncodedStringValue.encode(data, value.text);
michael@0 1061 },
michael@0 1062 };
michael@0 1063
michael@0 1064 /**
michael@0 1065 * MM-state-value = Draft | Sent | New | Retrieved | Forwarded
michael@0 1066 * Draft = <Octet 128>
michael@0 1067 * Sent = <Octet 129>
michael@0 1068 * New = <Octet 130>
michael@0 1069 * Retrieved = <Octet 131>
michael@0 1070 * Forwarded = <Octet 132>
michael@0 1071 *
michael@0 1072 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.33
michael@0 1073 */
michael@0 1074 this.MmStateValue = new RangedValue("MM-state-value", 128, 132);
michael@0 1075
michael@0 1076 /**
michael@0 1077 * Priority-value = Low | Normal | High
michael@0 1078 * Low = <Octet 128>
michael@0 1079 * Normal = <Octet 129>
michael@0 1080 * High = <Octet 130>
michael@0 1081 *
michael@0 1082 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.35
michael@0 1083 */
michael@0 1084 this.PriorityValue = new RangedValue("Priority-value", 128, 130);
michael@0 1085
michael@0 1086 /**
michael@0 1087 * Read-status-value = Read | Deleted without being read
michael@0 1088 *
michael@0 1089 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.38
michael@0 1090 */
michael@0 1091 this.ReadStatusValue = new RangedValue("Read-status-value", 128, 129);
michael@0 1092
michael@0 1093 /**
michael@0 1094 * Recommended-Retrieval-Mode-value = Manual
michael@0 1095 * Manual = <Octet 128>
michael@0 1096 *
michael@0 1097 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.39
michael@0 1098 */
michael@0 1099 this.RecommendedRetrievalModeValue = {
michael@0 1100 /**
michael@0 1101 * @param data
michael@0 1102 * A wrapped object containing raw PDU data.
michael@0 1103 *
michael@0 1104 * @return A decoded integer.
michael@0 1105 */
michael@0 1106 decode: function(data) {
michael@0 1107 return WSP.Octet.decodeEqualTo(data, 128);
michael@0 1108 },
michael@0 1109 };
michael@0 1110
michael@0 1111 /**
michael@0 1112 * Reply-charging-value = Requested | Requested text only | Accepted |
michael@0 1113 * Accepted text only
michael@0 1114 * Requested = <Octet 128>
michael@0 1115 * Requested text only = <Octet 129>
michael@0 1116 * Accepted = <Octet 130>
michael@0 1117 * Accepted text only = <Octet 131>
michael@0 1118 *
michael@0 1119 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.43
michael@0 1120 */
michael@0 1121 this.ReplyChargingValue = new RangedValue("Reply-charging-value", 128, 131);
michael@0 1122
michael@0 1123 /**
michael@0 1124 * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
michael@0 1125 *
michael@0 1126 * Response-text-value = Encoded-string-value
michael@0 1127 *
michael@0 1128 * When used in the M-Mbox-Delete.conf and M-Delete.conf PDUs:
michael@0 1129 *
michael@0 1130 * Response-text-Del-value = Value-length Status-count-value Response-text-value
michael@0 1131 *
michael@0 1132 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.49
michael@0 1133 */
michael@0 1134 this.ResponseText = {
michael@0 1135 /**
michael@0 1136 * @param data
michael@0 1137 * A wrapped object containing raw PDU data.
michael@0 1138 * @param options
michael@0 1139 * Extra context for decoding.
michael@0 1140 *
michael@0 1141 * @return An object containing a string-typed `text` attribute and a
michael@0 1142 * integer-typed `statusCount` one.
michael@0 1143 */
michael@0 1144 decode: function(data, options) {
michael@0 1145 let type = WSP.ensureHeader(options, "x-mms-message-type");
michael@0 1146
michael@0 1147 let result = {};
michael@0 1148 if ((type == MMS_PDU_TYPE_MBOX_DELETE_CONF)
michael@0 1149 || (type == MMS_PDU_TYPE_DELETE_CONF)) {
michael@0 1150 let length = WSP.ValueLength.decode(data);
michael@0 1151 let end = data.offset + length;
michael@0 1152
michael@0 1153 result.statusCount = WSP.IntegerValue.decode(data);
michael@0 1154 result.text = EncodedStringValue.decode(data);
michael@0 1155
michael@0 1156 if (data.offset != end) {
michael@0 1157 data.offset = end;
michael@0 1158 }
michael@0 1159 } else {
michael@0 1160 result.text = EncodedStringValue.decode(data);
michael@0 1161 }
michael@0 1162
michael@0 1163 return result;
michael@0 1164 },
michael@0 1165 };
michael@0 1166
michael@0 1167 /**
michael@0 1168 * Retrieve-status-value = Ok | Error-transient-failure |
michael@0 1169 * Error-transient-message-not-found |
michael@0 1170 * Error-transient-network-problem |
michael@0 1171 * Error-permanent-failure |
michael@0 1172 * Error-permanent-service-denied |
michael@0 1173 * Error-permanent-message-not-found |
michael@0 1174 * Error-permanent-content-unsupported
michael@0 1175 * Ok = <Octet 128>
michael@0 1176 * Error-transient-failure = <Octet 192>
michael@0 1177 * Error-transient-message-not-found = <Octet 193>
michael@0 1178 * Error-transient-network-problem = <Octet 194>
michael@0 1179 * Error-permanent-failure = <Octet 224>
michael@0 1180 * Error-permanent-service-denied = <Octet 225>
michael@0 1181 * Error-permanent-message-not-found = <Octet 226>
michael@0 1182 * Error-permanent-content-unsupported = <Octet 227>
michael@0 1183 *
michael@0 1184 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.50
michael@0 1185 */
michael@0 1186 this.RetrieveStatusValue = {
michael@0 1187 /**
michael@0 1188 * @param data
michael@0 1189 * A wrapped object containing raw PDU data.
michael@0 1190 *
michael@0 1191 * @return A decoded integer.
michael@0 1192 */
michael@0 1193 decode: function(data) {
michael@0 1194 let value = WSP.Octet.decode(data);
michael@0 1195 if (value == MMS_PDU_ERROR_OK) {
michael@0 1196 return value;
michael@0 1197 }
michael@0 1198
michael@0 1199 if ((value >= MMS_PDU_ERROR_TRANSIENT_FAILURE) && (value < 256)) {
michael@0 1200 return value;
michael@0 1201 }
michael@0 1202
michael@0 1203 // Any other values SHALL NOT be used. They are reserved for future use.
michael@0 1204 // An MMS Client that receives such a reserved value MUST react the same
michael@0 1205 // as it does to the value 224 (Error-permanent-failure).
michael@0 1206 return MMS_PDU_ERROR_PERMANENT_FAILURE;
michael@0 1207 },
michael@0 1208 };
michael@0 1209
michael@0 1210 /**
michael@0 1211 * Sender-visibility-value = Hide | Show
michael@0 1212 *
michael@0 1213 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.52
michael@0 1214 */
michael@0 1215 this.SenderVisibilityValue = new RangedValue("Sender-visibility-value", 128, 129);
michael@0 1216
michael@0 1217 /**
michael@0 1218 * Status-value = Expired | Retrieved | Rejected | Deferred | Unrecognised |
michael@0 1219 * Indeterminate | Forwarded | Unreachable
michael@0 1220 * Expired = <Octet 128>
michael@0 1221 * Retrieved = <Octet 129>
michael@0 1222 * Rejected = <Octet 130>
michael@0 1223 * Deferred = <Octet 131>
michael@0 1224 * Unrecognised = <Octet 132>
michael@0 1225 * Indeterminate = <Octet 133>
michael@0 1226 * Forwarded = <Octet 134>
michael@0 1227 * Unreachable = <Octet 135>
michael@0 1228 *
michael@0 1229 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.54
michael@0 1230 */
michael@0 1231 this.StatusValue = new RangedValue("Status-value", 128, 135);
michael@0 1232
michael@0 1233 this.PduHelper = {
michael@0 1234 /**
michael@0 1235 * @param data
michael@0 1236 * A wrapped object containing raw PDU data.
michael@0 1237 * @param headers
michael@0 1238 * An optional object to store parsed header fields. Created
michael@0 1239 * automatically if undefined.
michael@0 1240 *
michael@0 1241 * @return A boolean value indicating whether it's followed by message body.
michael@0 1242 */
michael@0 1243 parseHeaders: function(data, headers) {
michael@0 1244 if (!headers) {
michael@0 1245 headers = {};
michael@0 1246 }
michael@0 1247
michael@0 1248 let header;
michael@0 1249 while (data.offset < data.array.length) {
michael@0 1250 // There is no `header length` information in MMS PDU. If we just got
michael@0 1251 // something wrong in parsing header fields, we might not be able to
michael@0 1252 // determine the correct header-content boundary.
michael@0 1253 header = HeaderField.decode(data, headers);
michael@0 1254
michael@0 1255 if (header) {
michael@0 1256 let orig = headers[header.name];
michael@0 1257 if (Array.isArray(orig)) {
michael@0 1258 headers[header.name].push(header.value);
michael@0 1259 } else if (orig) {
michael@0 1260 headers[header.name] = [orig, header.value];
michael@0 1261 } else {
michael@0 1262 headers[header.name] = header.value;
michael@0 1263 }
michael@0 1264 if (header.name == "content-type") {
michael@0 1265 // `... if the PDU contains a message body the Content Type MUST be
michael@0 1266 // the last header field, followed by message body.` See
michael@0 1267 // OMA-TS-MMS_ENC-V1_3-20110913-A section 7.
michael@0 1268 break;
michael@0 1269 }
michael@0 1270 }
michael@0 1271 }
michael@0 1272
michael@0 1273 return headers;
michael@0 1274 },
michael@0 1275
michael@0 1276 /**
michael@0 1277 * @param data
michael@0 1278 * A wrapped object containing raw PDU data.
michael@0 1279 * @param msg
michael@0 1280 * A message object to store decoded multipart or octet array content.
michael@0 1281 */
michael@0 1282 parseContent: function(data, msg) {
michael@0 1283 let contentType = msg.headers["content-type"].media;
michael@0 1284 if ((contentType == "application/vnd.wap.multipart.related")
michael@0 1285 || (contentType == "application/vnd.wap.multipart.mixed")) {
michael@0 1286 msg.parts = WSP.PduHelper.parseMultiPart(data);
michael@0 1287 return;
michael@0 1288 }
michael@0 1289
michael@0 1290 if (data.offset >= data.array.length) {
michael@0 1291 return;
michael@0 1292 }
michael@0 1293
michael@0 1294 msg.content = WSP.Octet.decodeMultiple(data, data.array.length);
michael@0 1295 if (false) {
michael@0 1296 for (let begin = 0; begin < msg.content.length; begin += 20) {
michael@0 1297 debug("content: " + JSON.stringify(msg.content.subarray(begin, begin + 20)));
michael@0 1298 }
michael@0 1299 }
michael@0 1300 },
michael@0 1301
michael@0 1302 /**
michael@0 1303 * Check existences of all mandatory fields of a MMS message. Also sets `type`
michael@0 1304 * for convenient access.
michael@0 1305 *
michael@0 1306 * @param msg
michael@0 1307 * A MMS message object.
michael@0 1308 *
michael@0 1309 * @return The corresponding entry in MMS_PDU_TYPES;
michael@0 1310 *
michael@0 1311 * @throws FatalCodeError if the PDU type is not supported yet.
michael@0 1312 */
michael@0 1313 checkMandatoryFields: function(msg) {
michael@0 1314 let type = WSP.ensureHeader(msg.headers, "x-mms-message-type");
michael@0 1315 let entry = MMS_PDU_TYPES[type];
michael@0 1316 if (!entry) {
michael@0 1317 throw new WSP.FatalCodeError(
michael@0 1318 "checkMandatoryFields: unsupported message type " + type);
michael@0 1319 }
michael@0 1320
michael@0 1321 entry.mandatoryFields.forEach(function(name) {
michael@0 1322 WSP.ensureHeader(msg.headers, name);
michael@0 1323 });
michael@0 1324
michael@0 1325 // Setup convenient alias that referenced frequently.
michael@0 1326 msg.type = type;
michael@0 1327
michael@0 1328 return entry;
michael@0 1329 },
michael@0 1330
michael@0 1331 /**
michael@0 1332 * @param data
michael@0 1333 * A wrapped object containing raw PDU data.
michael@0 1334 * @param msg [optional]
michael@0 1335 * Optional target object for decoding.
michael@0 1336 *
michael@0 1337 * @return A MMS message object or null in case of errors found.
michael@0 1338 */
michael@0 1339 parse: function(data, msg) {
michael@0 1340 if (!msg) {
michael@0 1341 msg = {};
michael@0 1342 }
michael@0 1343
michael@0 1344 try {
michael@0 1345 msg.headers = this.parseHeaders(data, msg.headers);
michael@0 1346
michael@0 1347 // Validity checks
michael@0 1348 let typeinfo = this.checkMandatoryFields(msg);
michael@0 1349 if (typeinfo.hasContent) {
michael@0 1350 this.parseContent(data, msg);
michael@0 1351 }
michael@0 1352 } catch (e) {
michael@0 1353 debug("Failed to parse MMS message, error message: " + e.message);
michael@0 1354 return null;
michael@0 1355 }
michael@0 1356
michael@0 1357 return msg;
michael@0 1358 },
michael@0 1359
michael@0 1360 /**
michael@0 1361 * @param data
michael@0 1362 * A wrapped object to store encoded raw data.
michael@0 1363 * @param headers
michael@0 1364 * A dictionary object containing multiple name/value mapping.
michael@0 1365 * @param name
michael@0 1366 * Name of the header field to be encoded.
michael@0 1367 */
michael@0 1368 encodeHeader: function(data, headers, name) {
michael@0 1369 let value = headers[name];
michael@0 1370 if (Array.isArray(value)) {
michael@0 1371 for (let i = 0; i < value.length; i++) {
michael@0 1372 HeaderField.encode(data, {name: name, value: value[i]}, headers);
michael@0 1373 }
michael@0 1374 } else {
michael@0 1375 HeaderField.encode(data, {name: name, value: value}, headers);
michael@0 1376 }
michael@0 1377 },
michael@0 1378
michael@0 1379 /**
michael@0 1380 * @param data
michael@0 1381 * A wrapped object to store encoded raw data.
michael@0 1382 * @param headers
michael@0 1383 * A dictionary object containing multiple name/value mapping.
michael@0 1384 */
michael@0 1385 encodeHeaderIfExists: function(data, headers, name) {
michael@0 1386 // Header value could be zero or null.
michael@0 1387 if (headers[name] !== undefined) {
michael@0 1388 this.encodeHeader(data, headers, name);
michael@0 1389 }
michael@0 1390 },
michael@0 1391
michael@0 1392 /**
michael@0 1393 * @param data [optional]
michael@0 1394 * A wrapped object to store encoded raw data. Created if undefined.
michael@0 1395 * @param headers
michael@0 1396 * A dictionary object containing multiple name/value mapping.
michael@0 1397 *
michael@0 1398 * @return the passed data parameter or a created one.
michael@0 1399 */
michael@0 1400 encodeHeaders: function(data, headers) {
michael@0 1401 if (!data) {
michael@0 1402 data = {array: [], offset: 0};
michael@0 1403 }
michael@0 1404
michael@0 1405 // `In the encoding of the header fields, the order of the fields is not
michael@0 1406 // significant, except that X-Mms-Message-Type, X-Mms-Transaction-ID (when
michael@0 1407 // present) and X-Mms-MMS-Version MUST be at the beginning of the message
michael@0 1408 // headers, in that order, and if the PDU contains a message body the
michael@0 1409 // Content Type MUST be the last header field, followed by message body.`
michael@0 1410 // ~ OMA-TS-MMS_ENC-V1_3-20110913-A section 7
michael@0 1411 this.encodeHeader(data, headers, "x-mms-message-type");
michael@0 1412 this.encodeHeaderIfExists(data, headers, "x-mms-transaction-id");
michael@0 1413 this.encodeHeaderIfExists(data, headers, "x-mms-mms-version");
michael@0 1414
michael@0 1415 for (let key in headers) {
michael@0 1416 if ((key == "x-mms-message-type")
michael@0 1417 || (key == "x-mms-transaction-id")
michael@0 1418 || (key == "x-mms-mms-version")
michael@0 1419 || (key == "content-type")) {
michael@0 1420 continue;
michael@0 1421 }
michael@0 1422 this.encodeHeader(data, headers, key);
michael@0 1423 }
michael@0 1424
michael@0 1425 this.encodeHeaderIfExists(data, headers, "content-type");
michael@0 1426
michael@0 1427 return data;
michael@0 1428 },
michael@0 1429
michael@0 1430 /**
michael@0 1431 * @param multiStream
michael@0 1432 * An exsiting nsIMultiplexInputStream.
michael@0 1433 * @param msg
michael@0 1434 * A MMS message object.
michael@0 1435 *
michael@0 1436 * @return An instance of nsIMultiplexInputStream or null in case of errors.
michael@0 1437 */
michael@0 1438 compose: function(multiStream, msg) {
michael@0 1439 if (!multiStream) {
michael@0 1440 multiStream = Cc["@mozilla.org/io/multiplex-input-stream;1"]
michael@0 1441 .createInstance(Ci.nsIMultiplexInputStream);
michael@0 1442 }
michael@0 1443
michael@0 1444 try {
michael@0 1445 // Validity checks
michael@0 1446 let typeinfo = this.checkMandatoryFields(msg);
michael@0 1447
michael@0 1448 let data = this.encodeHeaders(null, msg.headers);
michael@0 1449 debug("Composed PDU Header: " + JSON.stringify(data.array));
michael@0 1450 WSP.PduHelper.appendArrayToMultiStream(multiStream, data.array, data.offset);
michael@0 1451
michael@0 1452 if (msg.content) {
michael@0 1453 WSP.PduHelper.appendArrayToMultiStream(multiStream, msg.content, msg.content.length);
michael@0 1454 } else if (msg.parts) {
michael@0 1455 WSP.PduHelper.composeMultiPart(multiStream, msg.parts);
michael@0 1456 } else if (typeinfo.hasContent) {
michael@0 1457 throw new WSP.CodeError("Missing message content");
michael@0 1458 }
michael@0 1459
michael@0 1460 return multiStream;
michael@0 1461 } catch (e) {
michael@0 1462 debug("Failed to compose MMS message, error message: " + e.message);
michael@0 1463 return null;
michael@0 1464 }
michael@0 1465 },
michael@0 1466 };
michael@0 1467
michael@0 1468 const MMS_PDU_TYPES = (function() {
michael@0 1469 let pdus = {};
michael@0 1470 function add(number, hasContent, mandatoryFields) {
michael@0 1471 pdus[number] = {
michael@0 1472 number: number,
michael@0 1473 hasContent: hasContent,
michael@0 1474 mandatoryFields: mandatoryFields,
michael@0 1475 };
michael@0 1476 }
michael@0 1477
michael@0 1478 add(MMS_PDU_TYPE_SEND_REQ, true, ["x-mms-message-type",
michael@0 1479 "x-mms-transaction-id",
michael@0 1480 "x-mms-mms-version",
michael@0 1481 "from",
michael@0 1482 "content-type"]);
michael@0 1483 add(MMS_PDU_TYPE_SEND_CONF, false, ["x-mms-message-type",
michael@0 1484 "x-mms-transaction-id",
michael@0 1485 "x-mms-mms-version",
michael@0 1486 "x-mms-response-status"]);
michael@0 1487 add(MMS_PDU_TYPE_NOTIFICATION_IND, false, ["x-mms-message-type",
michael@0 1488 "x-mms-transaction-id",
michael@0 1489 "x-mms-mms-version",
michael@0 1490 "x-mms-message-class",
michael@0 1491 "x-mms-message-size",
michael@0 1492 "x-mms-expiry",
michael@0 1493 "x-mms-content-location"]);
michael@0 1494 add(MMS_PDU_TYPE_RETRIEVE_CONF, true, ["x-mms-message-type",
michael@0 1495 "x-mms-mms-version",
michael@0 1496 "date",
michael@0 1497 "content-type"]);
michael@0 1498 add(MMS_PDU_TYPE_NOTIFYRESP_IND, false, ["x-mms-message-type",
michael@0 1499 "x-mms-transaction-id",
michael@0 1500 "x-mms-mms-version",
michael@0 1501 "x-mms-status"]);
michael@0 1502 add(MMS_PDU_TYPE_DELIVERY_IND, false, ["x-mms-message-type",
michael@0 1503 "x-mms-mms-version",
michael@0 1504 "message-id",
michael@0 1505 "to",
michael@0 1506 "date",
michael@0 1507 "x-mms-status"]);
michael@0 1508 add(MMS_PDU_TYPE_ACKNOWLEDGE_IND, false, ["x-mms-message-type",
michael@0 1509 "x-mms-transaction-id",
michael@0 1510 "x-mms-mms-version"]);
michael@0 1511 add(MMS_PDU_TYPE_READ_REC_IND, false, ["x-mms-message-type",
michael@0 1512 "message-id",
michael@0 1513 "x-mms-mms-version",
michael@0 1514 "to",
michael@0 1515 "from",
michael@0 1516 "x-mms-read-status"]);
michael@0 1517 add(MMS_PDU_TYPE_READ_ORIG_IND, false, ["x-mms-message-type",
michael@0 1518 "x-mms-mms-version",
michael@0 1519 "message-id",
michael@0 1520 "to",
michael@0 1521 "from",
michael@0 1522 "date",
michael@0 1523 "x-mms-read-status"]);
michael@0 1524
michael@0 1525 return pdus;
michael@0 1526 })();
michael@0 1527
michael@0 1528 /**
michael@0 1529 * Header field names and assigned numbers.
michael@0 1530 *
michael@0 1531 * @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.4
michael@0 1532 */
michael@0 1533 const MMS_HEADER_FIELDS = (function() {
michael@0 1534 let names = {};
michael@0 1535 function add(name, number, coder) {
michael@0 1536 let entry = {
michael@0 1537 name: name,
michael@0 1538 number: number,
michael@0 1539 coder: coder,
michael@0 1540 };
michael@0 1541 names[name] = names[number] = entry;
michael@0 1542 }
michael@0 1543
michael@0 1544 add("bcc", 0x01, Address);
michael@0 1545 add("cc", 0x02, Address);
michael@0 1546 add("x-mms-content-location", 0x03, ContentLocationValue);
michael@0 1547 add("content-type", 0x04, WSP.ContentTypeValue);
michael@0 1548 add("date", 0x05, WSP.DateValue);
michael@0 1549 add("x-mms-delivery-report", 0x06, BooleanValue);
michael@0 1550 add("x-mms-delivery-time", 0x07, ExpiryValue);
michael@0 1551 add("x-mms-expiry", 0x08, ExpiryValue);
michael@0 1552 add("from", 0x09, FromValue);
michael@0 1553 add("x-mms-message-class", 0x0A, MessageClassValue);
michael@0 1554 add("message-id", 0x0B, WSP.TextString);
michael@0 1555 add("x-mms-message-type", 0x0C, MessageTypeValue);
michael@0 1556 add("x-mms-mms-version", 0x0D, WSP.ShortInteger);
michael@0 1557 add("x-mms-message-size", 0x0E, WSP.LongInteger);
michael@0 1558 add("x-mms-priority", 0x0F, PriorityValue);
michael@0 1559 add("x-mms-read-report", 0x10, BooleanValue);
michael@0 1560 add("x-mms-report-allowed", 0x11, BooleanValue);
michael@0 1561 add("x-mms-response-status", 0x12, RetrieveStatusValue);
michael@0 1562 add("x-mms-response-text", 0x13, ResponseText);
michael@0 1563 add("x-mms-sender-visibility", 0x14, SenderVisibilityValue);
michael@0 1564 add("x-mms-status", 0x15, StatusValue);
michael@0 1565 add("subject", 0x16, EncodedStringValue);
michael@0 1566 add("to", 0x17, Address);
michael@0 1567 add("x-mms-transaction-id", 0x18, WSP.TextString);
michael@0 1568 add("x-mms-retrieve-status", 0x19, RetrieveStatusValue);
michael@0 1569 add("x-mms-retrieve-text", 0x1A, EncodedStringValue);
michael@0 1570 add("x-mms-read-status", 0x1B, ReadStatusValue);
michael@0 1571 add("x-mms-reply-charging", 0x1C, ReplyChargingValue);
michael@0 1572 add("x-mms-reply-charging-deadline", 0x1D, ExpiryValue);
michael@0 1573 add("x-mms-reply-charging-id", 0x1E, WSP.TextString);
michael@0 1574 add("x-mms-reply-charging-size", 0x1F, WSP.LongInteger);
michael@0 1575 add("x-mms-previously-sent-by", 0x20, PreviouslySentByValue);
michael@0 1576 add("x-mms-previously-sent-date", 0x21, PreviouslySentDateValue);
michael@0 1577 add("x-mms-store", 0x22, BooleanValue);
michael@0 1578 add("x-mms-mm-state", 0x23, MmStateValue);
michael@0 1579 add("x-mms-mm-flags", 0x24, MmFlagsValue);
michael@0 1580 add("x-mms-store-status", 0x25, RetrieveStatusValue);
michael@0 1581 add("x-mms-store-status-text", 0x26, EncodedStringValue);
michael@0 1582 add("x-mms-stored", 0x27, BooleanValue);
michael@0 1583 //add("x-mms-attributes", 0x28);
michael@0 1584 add("x-mms-totals", 0x29, BooleanValue);
michael@0 1585 //add("x-mms-mbox-totals", 0x2A);
michael@0 1586 add("x-mms-quotas", 0x2B, BooleanValue);
michael@0 1587 //add("x-mms-mbox-quotas", 0x2C);
michael@0 1588 add("x-mms-message-count", 0x2D, WSP.IntegerValue);
michael@0 1589 //add("content", 0x2E);
michael@0 1590 add("x-mms-start", 0x2F, WSP.IntegerValue);
michael@0 1591 //add("additional-headers", 0x30);
michael@0 1592 add("x-mms-distribution-indicator", 0x31, BooleanValue);
michael@0 1593 add("x-mms-element-descriptor", 0x32, ElementDescriptorValue);
michael@0 1594 add("x-mms-limit", 0x33, WSP.IntegerValue);
michael@0 1595 add("x-mms-recommended-retrieval-mode", 0x34, RecommendedRetrievalModeValue);
michael@0 1596 add("x-mms-recommended-retrieval-mode-text", 0x35, EncodedStringValue);
michael@0 1597 //add("x-mms-status-text", 0x36);
michael@0 1598 add("x-mms-applic-id", 0x37, WSP.TextString);
michael@0 1599 add("x-mms-reply-applic-id", 0x38, WSP.TextString);
michael@0 1600 add("x-mms-aux-applic-id", 0x39, WSP.TextString);
michael@0 1601 add("x-mms-content-class", 0x3A, ContentClassValue);
michael@0 1602 add("x-mms-drm-content", 0x3B, BooleanValue);
michael@0 1603 add("x-mms-adaptation-allowed", 0x3C, BooleanValue);
michael@0 1604 add("x-mms-replace-id", 0x3D, WSP.TextString);
michael@0 1605 add("x-mms-cancel-id", 0x3E, WSP.TextString);
michael@0 1606 add("x-mms-cancel-status", 0x3F, CancelStatusValue);
michael@0 1607
michael@0 1608 return names;
michael@0 1609 })();
michael@0 1610
michael@0 1611 // @see OMA-TS-MMS_ENC-V1_3-20110913-A Table 27: Parameter Name Assignments
michael@0 1612 const MMS_WELL_KNOWN_PARAMS = (function() {
michael@0 1613 let params = {};
michael@0 1614
michael@0 1615 function add(name, number, coder) {
michael@0 1616 let entry = {
michael@0 1617 name: name,
michael@0 1618 number: number,
michael@0 1619 coder: coder,
michael@0 1620 };
michael@0 1621 params[name] = params[number] = entry;
michael@0 1622 }
michael@0 1623
michael@0 1624 // Encoding Version: 1.2
michael@0 1625 add("type", 0x02, WSP.TypeValue);
michael@0 1626
michael@0 1627 return params;
michael@0 1628 })();
michael@0 1629
michael@0 1630 let debug;
michael@0 1631 if (DEBUG) {
michael@0 1632 debug = function(s) {
michael@0 1633 dump("-$- MmsPduHelper: " + s + "\n");
michael@0 1634 };
michael@0 1635 } else {
michael@0 1636 debug = function(s) {};
michael@0 1637 }
michael@0 1638
michael@0 1639 this.EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([
michael@0 1640 // Constant values
michael@0 1641 "MMS_VERSION",
michael@0 1642
michael@0 1643 // Utility functions
michael@0 1644 "translatePduErrorToStatus",
michael@0 1645
michael@0 1646 // Decoders
michael@0 1647 "BooleanValue",
michael@0 1648 "Address",
michael@0 1649 "HeaderField",
michael@0 1650 "MmsHeader",
michael@0 1651 "CancelStatusValue",
michael@0 1652 "ContentClassValue",
michael@0 1653 "ContentLocationValue",
michael@0 1654 "ElementDescriptorValue",
michael@0 1655 "Parameter",
michael@0 1656 "EncodedStringValue",
michael@0 1657 "ExpiryValue",
michael@0 1658 "FromValue",
michael@0 1659 "PreviouslySentByValue",
michael@0 1660 "PreviouslySentDateValue",
michael@0 1661 "MessageClassValue",
michael@0 1662 "MessageTypeValue",
michael@0 1663 "MmFlagsValue",
michael@0 1664 "MmStateValue",
michael@0 1665 "PriorityValue",
michael@0 1666 "ReadStatusValue",
michael@0 1667 "RecommendedRetrievalModeValue",
michael@0 1668 "ReplyChargingValue",
michael@0 1669 "ResponseText",
michael@0 1670 "RetrieveStatusValue",
michael@0 1671 "SenderVisibilityValue",
michael@0 1672 "StatusValue",
michael@0 1673
michael@0 1674 // Parser
michael@0 1675 "PduHelper",
michael@0 1676 ]);
michael@0 1677

mercurial