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