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 */ 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 */ 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 */ 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 * Set data uri. The data are stored as Uri. 162 * 163 * @param uri the uri 164 */ 165 public void setDataUri(Uri uri) { 166 mUri = uri; 167 } 168 169 /** 170 * @return The Uri of the part data or null if the data wasn't set or 171 * the data is stored as byte array. 172 * @see #getData 173 */ 174 public Uri getDataUri() { 175 return mUri; 176 } 177 178 /** 179 * Set Content-id value 180 * 181 * @param contentId the content-id value 182 * @throws NullPointerException if the value is null. 183 */ 184 public void setContentId(byte[] contentId) { 185 if((contentId == null) || (contentId.length == 0)) { 186 throw new IllegalArgumentException( 187 "Content-Id may not be null or empty."); 188 } 189 190 if ((contentId.length > 1) 191 && ((char) contentId[0] == '<') 192 && ((char) contentId[contentId.length - 1] == '>')) { 193 mPartHeader.put(P_CONTENT_ID, contentId); 194 return; 195 } 196 197 // Insert beginning '<' and trailing '>' for Content-Id. 198 byte[] buffer = new byte[contentId.length + 2]; 199 buffer[0] = (byte) (0xff & '<'); 200 buffer[buffer.length - 1] = (byte) (0xff & '>'); 201 System.arraycopy(contentId, 0, buffer, 1, contentId.length); 202 mPartHeader.put(P_CONTENT_ID, buffer); 203 } 204 205 /** 206 * Get Content-id value. 207 * 208 * @return the value 209 */ 210 public byte[] getContentId() { 211 return (byte[]) mPartHeader.get(P_CONTENT_ID); 212 } 213 214 /** 215 * Set Char-set value. 216 * 217 * @param charset the value 218 */ 219 public void setCharset(int charset) { 220 mPartHeader.put(P_CHARSET, charset); 221 } 222 223 /** 224 * Get Char-set value 225 * 226 * @return the charset value. Return 0 if charset was not set. 227 */ 228 public int getCharset() { 229 Integer charset = (Integer) mPartHeader.get(P_CHARSET); 230 if(charset == null) { 231 return 0; 232 } else { 233 return charset.intValue(); 234 } 235 } 236 237 /** 238 * Set Content-Location value. 239 * 240 * @param contentLocation the value 241 * @throws NullPointerException if the value is null. 242 */ 243 public void setContentLocation(byte[] contentLocation) { 244 if(contentLocation == null) { 245 throw new NullPointerException("null content-location"); 246 } 247 248 mPartHeader.put(P_CONTENT_LOCATION, contentLocation); 249 } 250 251 /** 252 * Get Content-Location value. 253 * 254 * @return the value 255 * return PduPart.disposition[0] instead of <Octet 128> (Form-data). 256 * return PduPart.disposition[1] instead of <Octet 129> (Attachment). 257 * return PduPart.disposition[2] instead of <Octet 130> (Inline). 258 */ 259 public byte[] getContentLocation() { 260 return (byte[]) mPartHeader.get(P_CONTENT_LOCATION); 261 } 262 263 /** 264 * Set Content-Disposition value. 265 * Use PduPart.disposition[0] instead of <Octet 128> (Form-data). 266 * Use PduPart.disposition[1] instead of <Octet 129> (Attachment). 267 * Use PduPart.disposition[2] instead of <Octet 130> (Inline). 268 * 269 * @param contentDisposition the value 270 * @throws NullPointerException if the value is null. 271 */ 272 public void setContentDisposition(byte[] contentDisposition) { 273 if(contentDisposition == null) { 274 throw new NullPointerException("null content-disposition"); 275 } 276 277 mPartHeader.put(P_CONTENT_DISPOSITION, contentDisposition); 278 } 279 280 /** 281 * Get Content-Disposition value. 282 * 283 * @return the value 284 */ 285 public byte[] getContentDisposition() { 286 return (byte[]) mPartHeader.get(P_CONTENT_DISPOSITION); 287 } 288 289 /** 290 * Set Content-Type value. 291 * 292 * @param value the value 293 * @throws NullPointerException if the value is null. 294 */ 295 public void setContentType(byte[] contentType) { 296 if(contentType == null) { 297 throw new NullPointerException("null content-type"); 298 } 299 300 mPartHeader.put(P_CONTENT_TYPE, contentType); 301 } 302 303 /** 304 * Get Content-Type value of part. 305 * 306 * @return the value 307 */ 308 public byte[] getContentType() { 309 return (byte[]) mPartHeader.get(P_CONTENT_TYPE); 310 } 311 312 /** 313 * Set Content-Transfer-Encoding value 314 * 315 * @param contentId the content-id value 316 * @throws NullPointerException if the value is null. 317 */ 318 public void setContentTransferEncoding(byte[] contentTransferEncoding) { 319 if(contentTransferEncoding == null) { 320 throw new NullPointerException("null content-transfer-encoding"); 321 } 322 323 mPartHeader.put(P_CONTENT_TRANSFER_ENCODING, contentTransferEncoding); 324 } 325 326 /** 327 * Get Content-Transfer-Encoding value. 328 * 329 * @return the value 330 */ 331 public byte[] getContentTransferEncoding() { 332 return (byte[]) mPartHeader.get(P_CONTENT_TRANSFER_ENCODING); 333 } 334 335 /** 336 * Set Content-type parameter: name. 337 * 338 * @param name the name value 339 * @throws NullPointerException if the value is null. 340 */ 341 public void setName(byte[] name) { 342 if(null == name) { 343 throw new NullPointerException("null content-id"); 344 } 345 346 mPartHeader.put(P_NAME, name); 347 } 348 349 /** 350 * Get content-type parameter: name. 351 * 352 * @return the name 353 */ 354 public byte[] getName() { 355 return (byte[]) mPartHeader.get(P_NAME); 356 } 357 358 /** 359 * Get Content-disposition parameter: filename 360 * 361 * @param fileName the filename value 362 * @throws NullPointerException if the value is null. 363 */ 364 public void setFilename(byte[] fileName) { 365 if(null == fileName) { 366 throw new NullPointerException("null content-id"); 367 } 368 369 mPartHeader.put(P_FILENAME, fileName); 370 } 371 372 /** 373 * Set Content-disposition parameter: filename 374 * 375 * @return the filename 376 */ 377 public byte[] getFilename() { 378 return (byte[]) mPartHeader.get(P_FILENAME); 379 } 380 381 public String generateLocation() { 382 // Assumption: At least one of the content-location / name / filename 383 // or content-id should be set. This is guaranteed by the PduParser 384 // for incoming messages and by MM composer for outgoing messages. 385 byte[] location = (byte[]) mPartHeader.get(P_NAME); 386 if(null == location) { 387 location = (byte[]) mPartHeader.get(P_FILENAME); 388 389 if (null == location) { 390 location = (byte[]) mPartHeader.get(P_CONTENT_LOCATION); 391 } 392 } 393 394 if (null == location) { 395 byte[] contentId = (byte[]) mPartHeader.get(P_CONTENT_ID); 396 return "cid:" + new String(contentId); 397 } else { 398 return new String(location); 399 } 400 } 401 } 402 403