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