1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.mapclient;
18 
19 import com.android.obex.ClientOperation;
20 import com.android.obex.ClientSession;
21 import com.android.obex.HeaderSet;
22 import com.android.obex.Operation;
23 import com.android.obex.ResponseCodes;
24 
25 import java.io.DataOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 
29 abstract class Request {
30 
31     protected static final byte OAP_TAGID_MAX_LIST_COUNT = 0x01;
32     protected static final byte OAP_TAGID_START_OFFSET = 0x02;
33     protected static final byte OAP_TAGID_FILTER_MESSAGE_TYPE = 0x03;
34     protected static final byte OAP_TAGID_FILTER_PERIOD_BEGIN = 0x04;
35     protected static final byte OAP_TAGID_FILTER_PERIOD_END = 0x05;
36     protected static final byte OAP_TAGID_FILTER_READ_STATUS = 0x06;
37     protected static final byte OAP_TAGID_FILTER_RECIPIENT = 0x07;
38     protected static final byte OAP_TAGID_FILTER_ORIGINATOR = 0x08;
39     protected static final byte OAP_TAGID_FILTER_PRIORITY = 0x09;
40     protected static final byte OAP_TAGID_ATTACHMENT = 0x0a;
41     protected static final byte OAP_TAGID_TRANSPARENT = 0xb;
42     protected static final byte OAP_TAGID_RETRY = 0xc;
43     protected static final byte OAP_TAGID_NEW_MESSAGE = 0x0d;
44     protected static final byte OAP_TAGID_NOTIFICATION_STATUS = 0x0e;
45     protected static final byte OAP_TAGID_MAS_INSTANCE_ID = 0x0f;
46     protected static final byte OAP_TAGID_PARAMETER_MASK = 0x10;
47     protected static final byte OAP_TAGID_FOLDER_LISTING_SIZE = 0x11;
48     protected static final byte OAP_TAGID_MESSAGES_LISTING_SIZE = 0x12;
49     protected static final byte OAP_TAGID_SUBJECT_LENGTH = 0x13;
50     protected static final byte OAP_TAGID_CHARSET = 0x14;
51     protected static final byte OAP_TAGID_STATUS_INDICATOR = 0x17;
52     protected static final byte OAP_TAGID_STATUS_VALUE = 0x18;
53     protected static final byte OAP_TAGID_MSE_TIME = 0x19;
54     /* used for PUT requests which require filler byte */
55     protected static final byte[] FILLER_BYTE = {0x30};
56     protected static final byte NOTIFICATION_ON = 0x01;
57     protected static final byte NOTIFICATION_OFF = 0x00;
58     protected static final byte ATTACHMENT_ON = 0x01;
59     protected static final byte ATTACHMENT_OFF = 0x00;
60     protected static final byte CHARSET_NATIVE = 0x00;
61     protected static final byte CHARSET_UTF8 = 0x01;
62     protected static final byte STATUS_INDICATOR_READ = 0x00;
63     protected static final byte STATUS_INDICATOR_DELETED = 0x01;
64     protected static final byte STATUS_NO = 0x00;
65     protected static final byte STATUS_YES = 0x01;
66     protected static final byte TRANSPARENT_OFF = 0x00;
67     protected static final byte TRANSPARENT_ON = 0x01;
68     protected static final byte RETRY_OFF = 0x00;
69     protected static final byte RETRY_ON = 0x01;
70 
71     protected HeaderSet mHeaderSet;
72     protected int mResponseCode;
73     private boolean mAborted = false;
74     private ClientOperation mOp = null;
75 
Request()76     Request() {
77         mHeaderSet = new HeaderSet();
78     }
79 
execute(ClientSession session)80     public abstract void execute(ClientSession session) throws IOException;
81 
executeGet(ClientSession session)82     protected void executeGet(ClientSession session) throws IOException {
83         /* in case request is aborted before can be executed */
84         if (mAborted) {
85             mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
86             return;
87         }
88 
89         try {
90             mOp = (ClientOperation) session.get(mHeaderSet);
91 
92             /*
93              * MAP spec does not explicitly require that GET request should be
94              * sent in single packet but for some reason PTS complains when
95              * final GET packet with no headers follows non-final GET with all
96              * headers. So this is workaround, at least temporary. TODO: check
97              * with PTS
98              */
99             mOp.setGetFinalFlag(true);
100 
101             /*
102              * this will trigger ClientOperation to use non-buffered stream so
103              * we can abort operation
104              */
105             mOp.continueOperation(true, false);
106 
107             readResponseHeaders(mOp.getReceivedHeader());
108 
109             InputStream is = mOp.openInputStream();
110             readResponse(is);
111             is.close();
112 
113             mOp.close();
114 
115             mResponseCode = mOp.getResponseCode();
116         } catch (IOException e) {
117             mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
118 
119             throw e;
120         }
121     }
122 
executePut(ClientSession session, byte[] body)123     protected void executePut(ClientSession session, byte[] body) throws IOException {
124         Operation op = null;
125 
126         mHeaderSet.setHeader(HeaderSet.LENGTH, Long.valueOf(body.length));
127 
128         try {
129             op = session.put(mHeaderSet);
130 
131             DataOutputStream out = op.openDataOutputStream();
132             out.write(body);
133             out.close();
134 
135             readResponseHeaders(op.getReceivedHeader());
136 
137             op.close();
138             mResponseCode = op.getResponseCode();
139         } catch (IOException e) {
140             mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
141 
142             throw e;
143         }
144     }
145 
abort()146     public void abort() {
147         mAborted = true;
148 
149         if (mOp != null) {
150             try {
151                 mOp.abort();
152             } catch (IOException e) {
153                 // Do nothing
154             }
155         }
156     }
157 
isSuccess()158     public final boolean isSuccess() {
159         return (mResponseCode == ResponseCodes.OBEX_HTTP_OK);
160     }
161 
readResponse(InputStream stream)162     protected void readResponse(InputStream stream) throws IOException {
163         /* nothing here by default */
164     }
165 
readResponseHeaders(HeaderSet headerset)166     protected void readResponseHeaders(HeaderSet headerset) {
167         /* nothing here by default */
168     }
169 }
170