1 /* 2 * Copyright (C) 2007-2008 Esmertec AG. 3 * Copyright (C) 2007-2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.messaging.mmslib.pdu; 19 20 import android.net.Uri; 21 import android.util.SparseArray; 22 23 /** 24 * The pdu part. 25 */ 26 public class PduPart { 27 /** 28 * Well-Known Parameters. 29 */ 30 public static final int P_Q = 0x80; 31 public static final int P_CHARSET = 0x81; 32 public static final int P_LEVEL = 0x82; 33 public static final int P_TYPE = 0x83; 34 public static final int P_DEP_NAME = 0x85; 35 public static final int P_DEP_FILENAME = 0x86; 36 public static final int P_DIFFERENCES = 0x87; 37 public static final int P_PADDING = 0x88; 38 // This value of "TYPE" s used with Content-Type: multipart/related 39 public static final int P_CT_MR_TYPE = 0x89; 40 public static final int P_DEP_START = 0x8A; 41 public static final int P_DEP_START_INFO = 0x8B; 42 public static final int P_DEP_COMMENT = 0x8C; 43 public static final int P_DEP_DOMAIN = 0x8D; 44 public static final int P_MAX_AGE = 0x8E; 45 public static final int P_DEP_PATH = 0x8F; 46 public static final int P_SECURE = 0x90; 47 public static final int P_SEC = 0x91; 48 public static final int P_MAC = 0x92; 49 public static final int P_CREATION_DATE = 0x93; 50 public static final int P_MODIFICATION_DATE = 0x94; 51 public static final int P_READ_DATE = 0x95; 52 public static final int P_SIZE = 0x96; 53 public static final int P_NAME = 0x97; 54 public static final int P_FILENAME = 0x98; 55 public static final int P_START = 0x99; 56 public static final int P_START_INFO = 0x9A; 57 public static final int P_COMMENT = 0x9B; 58 public static final int P_DOMAIN = 0x9C; 59 public static final int P_PATH = 0x9D; 60 61 /** 62 * Header field names. 63 */ 64 public static final int P_CONTENT_TYPE = 0x91; 65 public static final int P_CONTENT_LOCATION = 0x8E; 66 public static final int P_CONTENT_ID = 0xC0; 67 public static final int P_DEP_CONTENT_DISPOSITION = 0xAE; 68 public static final int P_CONTENT_DISPOSITION = 0xC5; 69 // The next header is unassigned header, use reserved header(0x48) value. 70 public static final int P_CONTENT_TRANSFER_ENCODING = 0xC8; 71 72 /** 73 * Content=Transfer-Encoding string. 74 */ 75 public static final String CONTENT_TRANSFER_ENCODING = 76 "Content-Transfer-Encoding"; 77 78 /** 79 * Value of Content-Transfer-Encoding. 80 */ 81 public static final String P_BINARY = "binary"; 82 public static final String P_7BIT = "7bit"; 83 public static final String P_8BIT = "8bit"; 84 public static final String P_BASE64 = "base64"; 85 public static final String P_QUOTED_PRINTABLE = "quoted-printable"; 86 87 /** 88 * Value of disposition can be set to PduPart when the value is octet in 89 * the PDU. 90 * "from-data" instead of Form-data<Octet 128>. 91 * "attachment" instead of Attachment<Octet 129>. 92 * "inline" instead of Inline<Octet 130>. 93 */ 94 static final byte[] DISPOSITION_FROM_DATA = "from-data".getBytes(); 95 static final byte[] DISPOSITION_ATTACHMENT = "attachment".getBytes(); 96 static final byte[] DISPOSITION_INLINE = "inline".getBytes(); 97 98 /** 99 * Content-Disposition value. 100 */ 101 public static final int P_DISPOSITION_FROM_DATA = 0x80; 102 public static final int P_DISPOSITION_ATTACHMENT = 0x81; 103 public static final int P_DISPOSITION_INLINE = 0x82; 104 105 /** 106 * Header of part. 107 */ 108 private SparseArray<Object> mPartHeader = null; 109 110 /** 111 * Data uri. 112 */ 113 private Uri mUri = null; 114 115 /** 116 * Part data. 117 */ 118 private byte[] mPartData = null; 119 120 private static final String TAG = "PduPart"; 121 122 /** 123 * Empty Constructor. 124 */ 125 public PduPart() { 126 mPartHeader = new SparseArray<Object>(); 127 } 128 129 /** 130 * Set part data. The data are stored as byte array. 131 * 132 * @param data the data 133 */ 134 public void setData(final byte[] data) { 135 mPartData = data; 136 } 137 138 /** 139 * @return The part data or null if the data wasn't set or 140 * the data is stored as Uri. 141 * @see #getDataUri 142 */ 143 public byte[] getData() { 144 return mPartData; 145 } 146 147 /** 148 * Set data uri. The data are stored as Uri. 149 * 150 * @param uri the uri 151 */ 152 public void setDataUri(final Uri uri) { 153 mUri = uri; 154 } 155 156 /** 157 * @return The Uri of the part data or null if the data wasn't set or 158 * the data is stored as byte array. 159 * @see #getData 160 */ 161 public Uri getDataUri() { 162 return mUri; 163 } 164 165 /** 166 * Set Content-id value 167 * 168 * @param contentId the content-id value 169 * @throws NullPointerException if the value is null. 170 */ 171 public void setContentId(final byte[] contentId) { 172 if ((contentId == null) || (contentId.length == 0)) { 173 throw new IllegalArgumentException( 174 "Content-Id may not be null or empty."); 175 } 176 177 if ((contentId.length > 1) 178 && ((char) contentId[0] == '<') 179 && ((char) contentId[contentId.length - 1] == '>')) { 180 mPartHeader.put(P_CONTENT_ID, contentId); 181 return; 182 } 183 184 // Insert beginning '<' and trailing '>' for Content-Id. 185 final byte[] buffer = new byte[contentId.length + 2]; 186 buffer[0] = (byte) (0xff & '<'); 187 buffer[buffer.length - 1] = (byte) (0xff & '>'); 188 System.arraycopy(contentId, 0, buffer, 1, contentId.length); 189 mPartHeader.put(P_CONTENT_ID, buffer); 190 } 191 192 /** 193 * Get Content-id value. 194 * 195 * @return the value 196 */ 197 public byte[] getContentId() { 198 return (byte[]) mPartHeader.get(P_CONTENT_ID); 199 } 200 201 /** 202 * Set Char-set value. 203 * 204 * @param charset the value 205 */ 206 public void setCharset(final int charset) { 207 mPartHeader.put(P_CHARSET, charset); 208 } 209 210 /** 211 * Get Char-set value 212 * 213 * @return the charset value. Return 0 if charset was not set. 214 */ 215 public int getCharset() { 216 final Integer charset = (Integer) mPartHeader.get(P_CHARSET); 217 if (charset == null) { 218 return 0; 219 } else { 220 return charset.intValue(); 221 } 222 } 223 224 /** 225 * Set Content-Location value. 226 * 227 * @param contentLocation the value 228 * @throws NullPointerException if the value is null. 229 */ 230 public void setContentLocation(final byte[] contentLocation) { 231 if (contentLocation == null) { 232 throw new NullPointerException("null content-location"); 233 } 234 235 mPartHeader.put(P_CONTENT_LOCATION, contentLocation); 236 } 237 238 /** 239 * Get Content-Location value. 240 * 241 * @return the value 242 * return PduPart.disposition[0] instead of <Octet 128> (Form-data). 243 * return PduPart.disposition[1] instead of <Octet 129> (Attachment). 244 * return PduPart.disposition[2] instead of <Octet 130> (Inline). 245 */ 246 public byte[] getContentLocation() { 247 return (byte[]) mPartHeader.get(P_CONTENT_LOCATION); 248 } 249 250 /** 251 * Set Content-Disposition value. 252 * Use PduPart.disposition[0] instead of <Octet 128> (Form-data). 253 * Use PduPart.disposition[1] instead of <Octet 129> (Attachment). 254 * Use PduPart.disposition[2] instead of <Octet 130> (Inline). 255 * 256 * @param contentDisposition the value 257 * @throws NullPointerException if the value is null. 258 */ 259 public void setContentDisposition(final byte[] contentDisposition) { 260 if (contentDisposition == null) { 261 throw new NullPointerException("null content-disposition"); 262 } 263 264 mPartHeader.put(P_CONTENT_DISPOSITION, contentDisposition); 265 } 266 267 /** 268 * Get Content-Disposition value. 269 * 270 * @return the value 271 */ 272 public byte[] getContentDisposition() { 273 return (byte[]) mPartHeader.get(P_CONTENT_DISPOSITION); 274 } 275 276 /** 277 * Set Content-Type value. 278 * 279 * @param value the value 280 * @throws NullPointerException if the value is null. 281 */ 282 public void setContentType(final byte[] contentType) { 283 if (contentType == null) { 284 throw new NullPointerException("null content-type"); 285 } 286 287 mPartHeader.put(P_CONTENT_TYPE, contentType); 288 } 289 290 /** 291 * Get Content-Type value of part. 292 * 293 * @return the value 294 */ 295 public byte[] getContentType() { 296 return (byte[]) mPartHeader.get(P_CONTENT_TYPE); 297 } 298 299 /** 300 * Set Content-Transfer-Encoding value 301 * 302 * @param contentId the content-id value 303 * @throws NullPointerException if the value is null. 304 */ 305 public void setContentTransferEncoding(final byte[] contentTransferEncoding) { 306 if (contentTransferEncoding == null) { 307 throw new NullPointerException("null content-transfer-encoding"); 308 } 309 310 mPartHeader.put(P_CONTENT_TRANSFER_ENCODING, contentTransferEncoding); 311 } 312 313 /** 314 * Get Content-Transfer-Encoding value. 315 * 316 * @return the value 317 */ 318 public byte[] getContentTransferEncoding() { 319 return (byte[]) mPartHeader.get(P_CONTENT_TRANSFER_ENCODING); 320 } 321 322 /** 323 * Set Content-type parameter: name. 324 * 325 * @param name the name value 326 * @throws NullPointerException if the value is null. 327 */ 328 public void setName(final byte[] name) { 329 if (null == name) { 330 throw new NullPointerException("null content-id"); 331 } 332 333 mPartHeader.put(P_NAME, name); 334 } 335 336 /** 337 * Get content-type parameter: name. 338 * 339 * @return the name 340 */ 341 public byte[] getName() { 342 return (byte[]) mPartHeader.get(P_NAME); 343 } 344 345 /** 346 * Get Content-disposition parameter: filename 347 * 348 * @param fileName the filename value 349 * @throws NullPointerException if the value is null. 350 */ 351 public void setFilename(final byte[] fileName) { 352 if (null == fileName) { 353 throw new NullPointerException("null content-id"); 354 } 355 356 mPartHeader.put(P_FILENAME, fileName); 357 } 358 359 /** 360 * Set Content-disposition parameter: filename 361 * 362 * @return the filename 363 */ 364 public byte[] getFilename() { 365 return (byte[]) mPartHeader.get(P_FILENAME); 366 } 367 368 public String generateLocation() { 369 // Assumption: At least one of the content-location / name / filename 370 // or content-id should be set. This is guaranteed by the PduParser 371 // for incoming messages and by MM composer for outgoing messages. 372 byte[] location = (byte[]) mPartHeader.get(P_NAME); 373 if (null == location) { 374 location = (byte[]) mPartHeader.get(P_FILENAME); 375 376 if (null == location) { 377 location = (byte[]) mPartHeader.get(P_CONTENT_LOCATION); 378 } 379 } 380 381 if (null == location) { 382 final byte[] contentId = (byte[]) mPartHeader.get(P_CONTENT_ID); 383 return "cid:" + new String(contentId); 384 } else { 385 return new String(location); 386 } 387 } 388 } 389 390