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.example.android.mmslib.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