|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // btcmtm.cpp |
|
15 // |
|
16 |
|
17 //class include |
|
18 #include <btcmtm.h> |
|
19 |
|
20 //system includes |
|
21 #include <e32std.h> |
|
22 #include <e32base.h> |
|
23 #include <txtrich.h> // CRichText |
|
24 |
|
25 #include <mtmuids.h> // KUidMtmQueryCanSendMsg |
|
26 #include <msvreg.h> // CRegisteredMtmDll |
|
27 #include <mtmdef.h> // KUidMtmQueryxxx & TMsvPartList flags |
|
28 #include <msvuids.h> // KUidMsvMessageEntry |
|
29 #include "btmtmcmds.h" //EBtMtmCmdSend |
|
30 |
|
31 //user includes |
|
32 #include <btheader.h> |
|
33 #include "btmsgtypeuid.h" //KUidMsgTypeBt |
|
34 #include <cobexsendoperation.h> |
|
35 |
|
36 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
37 #include "msvconsts.h" |
|
38 #include <mtmuidsdef.hrh> |
|
39 #endif |
|
40 |
|
41 const TUint8 KObexConnectionIDHeader = 0xCB; |
|
42 |
|
43 CBtClientMtm::CBtClientMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession) |
|
44 : CObexClientMtm(aRegisteredMtmDll, aMsvSession, KUidMsgTypeBt) |
|
45 /** |
|
46 * Constructor--not for use by client applications |
|
47 * |
|
48 * @param aRegisteredMtmDll Registration data for MTM DLL. |
|
49 * @param aMsvSession CMsvSession of the client requesting the object. |
|
50 */ |
|
51 { |
|
52 } |
|
53 |
|
54 void CBtClientMtm::InitialiseHeaderL() |
|
55 /** |
|
56 * Deletes the old header, then creates a new CBtHeader. |
|
57 * |
|
58 * @leave KErrXXX System-wide error codes if allocation fails |
|
59 */ |
|
60 { |
|
61 delete iHeader; |
|
62 iHeader = 0; |
|
63 |
|
64 iHeader = CBtHeader::NewL(); |
|
65 } |
|
66 |
|
67 EXPORT_C CBtClientMtm* CBtClientMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession) |
|
68 /** |
|
69 * Canonical NewL factory function. |
|
70 * |
|
71 * @param aRegisteredMtmDll Reference to registration data for MTM DLL. |
|
72 * @param aMsvSession Reference to CMsvSession of the client requesting the object. |
|
73 * @return Pointer to a new, constructed CBtClientMtm |
|
74 * @leave Leaves if no memory is available. |
|
75 */ |
|
76 { |
|
77 CBtClientMtm* self = new(ELeave) CBtClientMtm(aRegisteredMtmDll, aMsvSession); |
|
78 CleanupStack::PushL(self); |
|
79 self->ConstructL(); |
|
80 CleanupStack::Pop(); |
|
81 return self; |
|
82 } |
|
83 |
|
84 CMsvOperation* CBtClientMtm::InvokeAsyncFunctionL(TInt aFunctionId, |
|
85 const CMsvEntrySelection& aSelection, |
|
86 TDes8& aParameter, |
|
87 TRequestStatus& aCompletionStatus) |
|
88 /** |
|
89 * Starts an asynchronous function as an active object. Only works for EBtcCmdSend. |
|
90 * |
|
91 * @param aFunctionId Identifier of the function to be invoked. Only supports EBtcCmdSend and |
|
92 * KMTMStandardFunctionsSendMessage. |
|
93 * @param aSelection Selction of message entries for the requested function to operate on. |
|
94 * @param aParameter Buffer containing input and output parameters. |
|
95 * @param aCompletionStatus Canonical TRequestStatus used for control of the active object. |
|
96 * @return Pointer to a new asynchronously completing CMsvOperation. If failed, this is a completed operation with |
|
97 * status set to the relevant error code. |
|
98 * @leave Leaves if no memory is available, or if the specified aFunctionId is unsupported. |
|
99 */ { |
|
100 __TEST_INVARIANT_VIRTUAL |
|
101 |
|
102 CMsvOperation* op = NULL; |
|
103 switch (aFunctionId) |
|
104 { |
|
105 case KMTMStandardFunctionsSendMessage: |
|
106 { |
|
107 // parameter ignored, it's assumed that the 1st addressee will contain all the |
|
108 // required information to send this item. Only the 1st item in the selection |
|
109 // list is sent. |
|
110 CreateMessageOperationL(op, aSelection, aCompletionStatus); |
|
111 break; |
|
112 } |
|
113 case EBtMtmCmdSend: |
|
114 { |
|
115 /* |
|
116 In order to get our password over the client-server boundary without breaking the client interface |
|
117 we will repack the client side package buffer into a server package buffer. |
|
118 */ |
|
119 TPckgBuf<CBtClientMtm::SBtcCmdSendServerParams> serverParams; |
|
120 |
|
121 TPckgBuf<CBtClientMtm::SBtcCmdSendParams>& clientParams = (TPckgBuf<CBtClientMtm::SBtcCmdSendParams>&)aParameter; |
|
122 |
|
123 /* at this point, it may be worth checking the length of the supplied password |
|
124 and leaving with KErrArgument if it's longer than allowed */ |
|
125 if(!clientParams().iConnectPassword || clientParams().iConnectPassword->Length() > KBlueToothObexPasswordLength) |
|
126 User::Leave(KErrArgument); |
|
127 |
|
128 serverParams().iTimeouts = clientParams().iTimeouts; |
|
129 serverParams().iRemoteObexPort = clientParams().iRemoteObexPort; |
|
130 serverParams().iConnectPassword = *(clientParams().iConnectPassword); |
|
131 |
|
132 op = Session().TransferCommandL(aSelection, aFunctionId, serverParams, |
|
133 aCompletionStatus); |
|
134 break; |
|
135 } |
|
136 default: |
|
137 User::Leave(KErrNotSupported); |
|
138 } |
|
139 return(op); // ownership of op is passed to caller |
|
140 } |
|
141 |
|
142 |
|
143 void CBtClientMtm::CreateMessageOperationL( |
|
144 CMsvOperation*& aOperation, const CMsvEntrySelection& aSelection, TRequestStatus& aCompletionStatus) |
|
145 { |
|
146 // must have at least 1 addressee (if more than 1 the others are ignored) |
|
147 if (AddresseeList().Count() == 0) |
|
148 { |
|
149 User::Leave(KErrArgument); |
|
150 } |
|
151 |
|
152 // extract and parse addressee information |
|
153 TPckgBuf<CBtClientMtm::SBtcCmdSendServerParams> serverParams; |
|
154 serverParams().iRemoteObexPort = 0; |
|
155 |
|
156 // Set some default values for the timeouts in case they have not been added to |
|
157 // the addressee. |
|
158 serverParams().iTimeouts.iConnectTimeout = 0; |
|
159 serverParams().iTimeouts.iPutTimeout = 0; |
|
160 |
|
161 // address already saved when addressee was added (and we know there is at least one) |
|
162 TBuf8<KBlueToothObexDeviceAddressLength> addressIgnored; |
|
163 TBuf<KBlueToothObexPasswordLength> password; |
|
164 ParseDestinationL(AddresseeList()[0], addressIgnored, password, |
|
165 serverParams().iTimeouts.iConnectTimeout, |
|
166 serverParams().iTimeouts.iPutTimeout); |
|
167 |
|
168 serverParams().iConnectPassword = password; |
|
169 |
|
170 // obex send operation wrapper, supporting standard progress |
|
171 CObexSendOperation* send = new(ELeave) CObexSendOperation(Session(), aCompletionStatus); |
|
172 CleanupStack::PushL(send); |
|
173 // start the send operation |
|
174 CMsvOperation* op = |
|
175 Session().TransferCommandL(aSelection, EBtMtmCmdSend, serverParams, send->iStatus); |
|
176 CleanupStack::PushL(op); |
|
177 send->Start(op); |
|
178 CleanupStack::Pop(2, send); // op, send |
|
179 aOperation = send; |
|
180 } |
|
181 |
|
182 void CBtClientMtm::AddAddresseeL(const TDesC& anAddressee) |
|
183 { |
|
184 // check addressee parses ok - checks all fields (that are there) |
|
185 TBuf8<KBlueToothObexDeviceAddressLength> address; |
|
186 TBuf<KBlueToothObexPasswordLength> ignored1; |
|
187 TInt ignored2(0); |
|
188 TInt ignored3(0); |
|
189 ParseDestinationL(anAddressee, address, ignored1, ignored2, ignored3); |
|
190 |
|
191 // parses ok, try to save it - fails if there is already an addressee |
|
192 CObexClientMtm::AddAddresseeL(anAddressee); |
|
193 |
|
194 // parses and saves ok, store device address in header |
|
195 iHeader->SetAddrL(address); |
|
196 } |
|
197 |
|
198 /** |
|
199 * Parse bluetooth addressee field |
|
200 * |
|
201 * @param aFieldTag Field tag ID (see TBtClientMtmAddresseeFieldType). |
|
202 * @param aField The next field (descriptor buffer of the correct size for the given field). |
|
203 * @param aFieldList Addressee field list. |
|
204 * @leave Leaves with KErrArgument if parameter or formatting incorrect. |
|
205 */ |
|
206 TBool CBtClientMtm::ParseDestinationFieldL(TUint16 aFieldTag, TDes8& aField, TPtrC& aFieldList) |
|
207 { |
|
208 TBool isDeviceAddress = (aFieldTag == EDeviceAddress); |
|
209 |
|
210 aField.Zero(); |
|
211 TInt length = aFieldList.Length(); |
|
212 if (!isDeviceAddress) |
|
213 { |
|
214 // end of field list |
|
215 if (length == 0) |
|
216 { |
|
217 return EFalse; |
|
218 } |
|
219 // expecting tag |
|
220 if (length < 2 || aFieldList[0] != ':' || aFieldList[1] != aFieldTag) |
|
221 { |
|
222 User::Leave(KErrArgument); |
|
223 } |
|
224 // remove tag and marker |
|
225 aFieldList.Set(aFieldList.Right(aFieldList.Length() - 2)); |
|
226 } |
|
227 |
|
228 // locate next tag |
|
229 TInt fieldLength = aFieldList.Locate(':'); |
|
230 if (fieldLength == KErrNotFound) |
|
231 { |
|
232 fieldLength = aFieldList.Length(); |
|
233 } |
|
234 |
|
235 // twice as many bytes |
|
236 TInt fieldLength8 = fieldLength << 1; |
|
237 if (fieldLength8 > aField.MaxLength()) |
|
238 { |
|
239 User::Leave(KErrArgument); |
|
240 } |
|
241 |
|
242 // copy field |
|
243 aField.Copy((TUint8*)aFieldList.Ptr(), fieldLength8); |
|
244 |
|
245 // remove field from field list |
|
246 aFieldList.Set(aFieldList.Right(aFieldList.Length() - fieldLength)); |
|
247 |
|
248 return ETrue; |
|
249 } |
|
250 |
|
251 /** |
|
252 * Parse bluetooth addressing information from addressee list. |
|
253 * |
|
254 * @param aDeviceAddress Device address (6 bytes). |
|
255 * @param aPassword Password (max length 16). |
|
256 * @param aConnectTimeout Connection timeout. |
|
257 * @param aPutTimeout Put timeout. |
|
258 * @leave Leaves with KErrArgument if parameter or formatting incorrect. |
|
259 */ |
|
260 void CBtClientMtm::ParseDestinationL(const TDesC& aFieldsToParse, TDes8& aDeviceAddress, |
|
261 TDes16& aPassword, TInt& aConnectTimeout, TInt& aPutTimeout) |
|
262 { |
|
263 TPtrC16 fields(aFieldsToParse); |
|
264 |
|
265 // get device address |
|
266 if (ParseDestinationFieldL(EDeviceAddress, aDeviceAddress, fields)) |
|
267 { |
|
268 // get password |
|
269 TPtr8 password((TUint8*)aPassword.Ptr(), aPassword.MaxLength()<<1); |
|
270 if (ParseDestinationFieldL(EPassword, password, fields)) |
|
271 { |
|
272 aPassword.SetLength(password.Length()>>1); |
|
273 // get connection timeout |
|
274 TPckg<TInt> connectTimeout(aConnectTimeout); |
|
275 TBool parsedOk = EFalse; |
|
276 |
|
277 // The connect timeout can have a field tag defined by ETimeout, or a |
|
278 // field tag defined by EAlternativeConnectTimeout. This is because an |
|
279 // older version of code looked for the wrong tag (EAlternativeConnectTimeout), |
|
280 // and we need to remain backward compatible with it. |
|
281 TRAPD(err, parsedOk = ParseDestinationFieldL(ETimeout, connectTimeout, fields)); |
|
282 |
|
283 if (err == KErrArgument) |
|
284 { |
|
285 parsedOk = ParseDestinationFieldL(EAlternativeConnectTimeout, connectTimeout, fields); |
|
286 } |
|
287 else |
|
288 { |
|
289 User::LeaveIfError(err); |
|
290 } |
|
291 |
|
292 if (parsedOk) |
|
293 { |
|
294 // get put timeout |
|
295 TPckg<TInt> putTimeout(aPutTimeout); |
|
296 ParseDestinationFieldL(EPutTimeout, putTimeout, fields); |
|
297 } |
|
298 } |
|
299 } |
|
300 } |
|
301 |
|
302 |
|
303 |
|
304 #ifdef _DEBUG |
|
305 void CBtClientMtm::TestInvariant() const |
|
306 { |
|
307 __ASSERT_DEBUG(iMsvEntry && |
|
308 iHeader && |
|
309 (iMsvEntry->Entry().iMtm == KUidMsgTypeBt) && |
|
310 (iMsvEntry->Entry().iType == KUidMsvMessageEntry), |
|
311 User::Invariant()); |
|
312 } |
|
313 #endif //_DEBUG |
|
314 |