• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "pbap_pse_state_machine.h"
17 #include <cstring>
18 #include <numeric>
19 #include "../obex/obex_utils.h"
20 #include "interface_profile_pbap_pse.h"
21 #include "log.h"
22 #include "log_util.h"
23 #include "pbap_pse_app_params.h"
24 #include "pbap_pse_def.h"
25 #include "pbap_pse_obex_server.h"
26 #include "pbap_pse_service.h"
27 #include "pbap_pse_vcard_manager.h"
28 #include "power_manager.h"
29 #include "raw_address.h"
30 #include "securec.h"
31 
32 namespace OHOS {
33 namespace bluetooth {
PseWaitingForConnect(const std::string & name,PbapPseStateMachine & stm)34 PseWaitingForConnect::PseWaitingForConnect(const std::string &name, PbapPseStateMachine &stm)
35     : State(name, stm), stm_(stm)
36 {}
37 
Entry()38 void PseWaitingForConnect::Entry()
39 {
40     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
41 }
42 
Exit()43 void PseWaitingForConnect::Exit()
44 {
45     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
46 }
47 
Dispatch(const utility::Message & msg)48 bool PseWaitingForConnect::Dispatch(const utility::Message &msg)
49 {
50     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
51     bool ret = true;
52     switch (msg.what_) {
53         case PSE_DEVICE_CONNECT_INCOMING:
54             Transition(PbapPseStateMachine::PSE_CONNECTING_STATE);
55             stm_.ProcessMessage(msg);
56             break;
57         default:
58             PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
59             ret = false;
60             break;
61     }
62     PBAP_PSE_LOG_INFO("%{public}s end, ret = %{public}d", __PRETTY_FUNCTION__, ret);
63     return ret;
64 }
65 
PseConnecting(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList,std::function<uint32_t ()> & getNextConnectIdFun)66 PseConnecting::PseConnecting(const std::string &name, PbapPseStateMachine &stm,
67     BaseObserverList<IPbapPseObserver> &observerMgrList, std::function<uint32_t()> &getNextConnectIdFun)
68     : State(name, stm), stm_(stm), observerMgrList_(observerMgrList), getNextConnectIdFun_(getNextConnectIdFun)
69 {}
70 
Entry()71 void PseConnecting::Entry()
72 {
73     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
74     auto &device = stm_.GetDevice();
75     observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
76         observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::CONNECTING));
77     });
78     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
79 }
80 
Exit()81 void PseConnecting::Exit()
82 {
83     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
84     stm_.StopTimer();
85 }
86 
Dispatch(const utility::Message & msg)87 bool PseConnecting::Dispatch(const utility::Message &msg)
88 {
89     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
90     bool ret = true;
91     switch (msg.what_) {
92         case PSE_DEVICE_CONNECT_INCOMING:
93             // No need to delete
94             incomeConnect_ = static_cast<ObexIncomingConnect *>(msg.arg2_);
95             break;
96         case PSE_INCOMING_ACCEPT:
97             AcceptConnection();
98             break;
99         case PSE_INCOMING_REJECT:
100             RejectConnection();
101             break;
102         case PSE_WAITING_CONNECTED_TO_DISCONNECT:
103             waitingDisconnect_ = true;
104             break;
105         case PSE_REQ_OBEX_CONNECT:
106             // No need to delete
107             CheckConnectReq(*static_cast<PbapPseObexMessage *>(msg.arg2_));
108             break;
109         case PSE_PASSWORD_INPUT:
110             // No need to delete
111             PasswordInput(*static_cast<PbapPsePasswordInputMsg *>(msg.arg2_));
112             break;
113         case PSE_DEVICE_DISCONNECTED:  // OnIncomingDisconnected
114             Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
115             Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
116             break;
117         default:
118             PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
119             ret = false;
120             break;
121     }
122     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
123     return ret;
124 }
125 
AcceptConnection()126 void PseConnecting::AcceptConnection()
127 {
128     if (incomeConnect_ != nullptr) {
129         PBAP_PSE_LOG_INFO("%{public}s AcceptConnection", __PRETTY_FUNCTION__);
130         stm_.StopTimer();
131         incomeConnect_->AcceptConnection();
132         stm_.GetStmInfo().accepted_ = true;
133         incomeConnect_ = nullptr;
134     } else {
135         HILOGI("%{public}s incomeConnect is null, maybe accepted or rejected.",
136             GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
137     }
138 }
139 
RejectConnection()140 void PseConnecting::RejectConnection()
141 {
142     if (incomeConnect_ != nullptr) {
143         HILOGI("%{public}s RejectConnection", GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
144         stm_.StopTimer();
145         Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
146         incomeConnect_->RejectConnection();
147         incomeConnect_ = nullptr;
148         Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
149     } else {
150         HILOGI("%{public}s incomeConnect is null, maybe accepted or rejected.",
151             GetEncryptAddr(stm_.GetDevice().GetAddress()).c_str());
152     }
153 }
154 
CheckConnectHeader(const ObexHeader & req) const155 bool PseConnecting::CheckConnectHeader(const ObexHeader &req) const
156 {
157     auto target = req.GetItemTarget();
158     if (target == nullptr) {
159         PBAP_PSE_LOG_ERROR("Target doesn't exist");
160         return false;
161     }
162     if (target->GetHeaderDataSize() != PBAP_SERVICE_UUID_LEN) {
163         PBAP_PSE_LOG_ERROR("Wrong Target size %u", target->GetHeaderDataSize());
164         return false;
165     }
166     if (memcmp(target->GetBytes().get(), PBAP_SERVICE_UUID, PBAP_SERVICE_UUID_LEN) != 0) {
167         PBAP_PSE_LOG_ERROR("Wrong TargetId:%{public}s",
168             ObexUtils::ToDebugString(target->GetBytes().get(), PBAP_SERVICE_UUID_LEN).c_str());
169         return false;
170     }
171     return true;
172 }
173 
ToDisconnect(ObexRspCode rspCode)174 void PseConnecting::ToDisconnect(ObexRspCode rspCode)
175 {
176     auto obexSession = stm_.GetStmInfo().obexSession_;
177     if (obexSession != nullptr) {
178         Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
179         auto header = ObexHeader::CreateResponse(rspCode, true);
180         obexSession->SendResponse(*header);
181         obexSession->Disconnect();
182     } else {
183         Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
184     }
185 }
186 
SendSuccessResponse(const std::string & userId,const std::string & pwd)187 void PseConnecting::SendSuccessResponse(const std::string &userId, const std::string &pwd)
188 {
189     auto header = ObexHeader::CreateResponse(ObexRspCode::SUCCESS, true);
190     auto &stmInfo = stm_.GetStmInfo();
191     stmInfo.connectId_ = getNextConnectIdFun_();
192 
193     // set connection id
194     header->AppendItemConnectionId(stmInfo.connectId_);
195     // set who
196     header->AppendItemWho(PBAP_SERVICE_UUID, PBAP_SERVICE_UUID_LEN);
197 
198     if (authChallenge_) {
199         // Authenticate Response
200         // Carries the digest-response string. This is the response to the challenge from the Client.
201         ObexDigestResponse response;
202         std::vector<uint8_t> requestDigest = ObexUtils::MakeRequestDigest(authNonce_.data(), authNonce_.size(), pwd);
203         response.AppendRequestDigest(requestDigest.data(), requestDigest.size());
204         if (authNeedUser_ && userId.size() > 0) {
205             response.AppendUserId(reinterpret_cast<const uint8_t *>(userId.c_str()), userId.size());
206         }
207         response.AppendNonce(authNonce_.data(), authNonce_.size());
208         header->AppendItemAuthResponse(response);
209     }
210     // send response to client
211     stmInfo.obexSession_->SendResponse(*header);
212     Transition(PbapPseStateMachine::PSE_CONNECTED_STATE);
213 }
214 
CheckConnectReq(const PbapPseObexMessage & obexMsg)215 void PseConnecting::CheckConnectReq(const PbapPseObexMessage &obexMsg)
216 {
217     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
218     const ObexHeader &req = obexMsg.GetObexHeader();
219     stm_.GetStmInfo().obexSession_ = &obexMsg.GetObexSession();
220     if (waitingDisconnect_) {
221         ToDisconnect(ObexRspCode::SERVICE_UNAVAILABLE);
222         return;
223     }
224     if (!CheckConnectHeader(req)) {
225         ToDisconnect();
226         return;
227     }
228 
229     auto appParamsTlv = req.GetItemAppParams();
230     if (appParamsTlv != nullptr && appParamsTlv->GetTlvParamters()) {
231         PbapPseAppParams pbapAppParams;
232         pbapAppParams.Init(*appParamsTlv->GetTlvParamters());
233         if (pbapAppParams.GetPbapSupportedFeatures()) {
234             stm_.GetStmInfo().pceFeatures_ = *pbapAppParams.GetPbapSupportedFeatures();
235             PBAP_PSE_LOG_INFO("Set PbapPceSupportedFeatures to %x", *pbapAppParams.GetPbapSupportedFeatures());
236         }
237     }
238 
239     auto authChallenges = req.GetItemAuthChallenges();
240     if (authChallenges == nullptr) {
241         SendSuccessResponse();
242         return;
243     }
244 
245     // support for legacy PBAP devices
246     CheckAuthChallenges(req, *authChallenges);
247     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
248 }
249 
CheckAuthChallenges(const ObexHeader & req,const ObexOptionalTlvHeader & authChallenges)250 void PseConnecting::CheckAuthChallenges(const ObexHeader &req, const ObexOptionalTlvHeader &authChallenges)
251 {
252     // support for legacy PBAP devices
253     // PBAP_v1.2.3-6.3 Implementations conforming to this specification shall not send the first OBEX
254     // authentication request. It is solely supported for backwards compatibility with legacy PBAP devices.
255     // create auth Response use challenge
256     // note: ignore AuthResponse from client. because our server don't auth the client.
257     auto digestChallenge = static_cast<ObexDigestChallenge *>(authChallenges.GetTlvParamters().get());
258     auto nonceTlv = digestChallenge->GetNonce();
259     if (!nonceTlv) {  // nonce is require, but no find
260         ToDisconnect();
261         return;
262     }
263     authChallenge_ = true;
264     authNonce_.clear();
265     authDescription_.clear();
266     authFullAccess_ = true;
267     authNeedUser_ = false;
268     auto targetHr = req.GetItemTarget();
269     auto targetBytes = targetHr->GetBytes();
270     authNonce_.insert(authNonce_.end(), nonceTlv->GetVal(), nonceTlv->GetVal() + nonceTlv->GetLen());
271     auto optionsTlv = digestChallenge->GetOptions();
272     if (optionsTlv) {
273         uint8_t option = optionsTlv->GetVal()[0];
274         // When set, the User Id must be sent in the authenticate response.
275         if ((option & 0x01) != 0) {
276             authNeedUser_ = true;
277         }
278         // Access mode: Read Only when set, otherwise Full access is permitted.
279         if ((option & 0x02) != 0) {
280             authFullAccess_ = false;
281         }
282     }
283     auto realmTlv = digestChallenge->GetRealm();
284     if (realmTlv) {
285         if (realmTlv->GetLen() > 0) {
286             authUserCharset_ = realmTlv->GetVal()[0];
287             if (realmTlv->GetLen() > 1) {
288                 authDescription_.insert(
289                     authDescription_.end(), realmTlv->GetVal() + 1, realmTlv->GetVal() + realmTlv->GetLen());
290             }
291         }
292     }
293     auto &device = stm_.GetDevice();
294     auto &authDescription = authDescription_;
295     auto &authUserCharset = authUserCharset_;
296     auto &authFullAccess = authFullAccess_;
297     observerMgrList_.ForEach([device, authDescription, authUserCharset, authFullAccess](IPbapPseObserver &observer) {
298         observer.OnServicePasswordRequired(device, authDescription, authUserCharset, authFullAccess);
299     });
300 }
301 
PasswordInput(const PbapPsePasswordInputMsg & pwdInputMsg)302 void PseConnecting::PasswordInput(const PbapPsePasswordInputMsg &pwdInputMsg)
303 {
304     if (waitingDisconnect_) {
305         ToDisconnect(ObexRspCode::SERVICE_UNAVAILABLE);
306         return;
307     }
308     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
309     if (!authChallenge_) {
310         return;
311     }
312     if (pwdInputMsg.GetPassword().size() == 0) {
313         return;
314     }
315 
316     SendSuccessResponse(pwdInputMsg.GetUserId(), pwdInputMsg.GetPassword());
317     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
318 }
319 
PseConnected(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)320 PseConnected::PseConnected(
321     const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
322     : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
323 {}
324 
Entry()325 void PseConnected::Entry()
326 {
327     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
328     auto &device = stm_.GetDevice();
329     IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_ON, PROFILE_NAME_PBAP_PSE, device);
330     observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
331         observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::CONNECTED));
332     });
333     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
334 }
335 
Exit()336 void PseConnected::Exit()
337 {
338     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
339 }
340 
Dispatch(const utility::Message & msg)341 bool PseConnected::Dispatch(const utility::Message &msg)
342 {
343     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
344     bool ret = true;
345     switch (msg.what_) {
346         case PSE_REQ_OBEX_DISCONNECT:
347             Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
348             // No need to delete
349             DisconnectObex(*static_cast<PbapPseObexMessage *>(msg.arg2_));
350             break;
351         case PSE_DEVICE_DISCONNECTED:
352             Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
353             Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
354             break;
355         case PSE_API_DISCONNECT:
356             if (stm_.GetStmInfo().obexSession_ != nullptr) {
357                 Transition(PbapPseStateMachine::PSE_DISCONNECTING_STATE);
358                 int retVal = stm_.GetStmInfo().obexSession_->Disconnect();
359                 if (retVal != 0) {
360                     PBAP_PSE_LOG_ERROR("Obex Disconnect fail ret=%{public}d", retVal);
361                 }
362             }
363             break;
364         case PSE_REQ_OBEX_GET:
365             // No need to delete
366             stm_.SetBusy(true);
367             HandleGetRequest(*static_cast<PbapPseObexMessage *>(msg.arg2_));
368             stm_.SetBusy(false);
369             break;
370         case PSE_REQ_OBEX_SETPATH:
371             // No need to delete
372             stm_.SetBusy(true);
373             HandleSetPathRequest(*static_cast<PbapPseObexMessage *>(msg.arg2_));
374             stm_.SetBusy(false);
375             break;
376         default:
377             PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
378             ret = false;
379             break;
380     }
381     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
382     return ret;
383 }
384 
HandleGetRequest(const PbapPseObexMessage & obexMsg)385 void PseConnected::HandleGetRequest(const PbapPseObexMessage &obexMsg)
386 {
387     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
388     const ObexHeader &req = obexMsg.GetObexHeader();
389     ObexServerSession &obexSession = obexMsg.GetObexSession();
390     auto typeItem = req.GetItemType();
391     if (typeItem == nullptr) {
392         PBAP_PSE_LOG_ERROR("PullPhoneBook: type can't be null!");
393         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
394         return;
395     }
396     std::string type = typeItem->GetString();
397     if (PBAP_PSE_TYPE_PB == type) {  // type for PullPhoneBook function
398         PullPhoneBook(obexSession, req);
399     } else if (PBAP_PSE_TYPE_LISTING == type) {  // type for PullvCardListing function
400         PullvCardListing(obexSession, req);
401     } else if (PBAP_PSE_TYPE_VCARD == type) {  // type for PullvCardEntry Function
402         PullvCardEntry(obexSession, req);
403     } else {
404         PBAP_PSE_LOG_ERROR("PullPhoneBook: type [%{public}s] is unknow.", type.c_str());
405         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
406     }
407 }
408 
HandleSetPathRequest(const PbapPseObexMessage & obexMsg)409 void PseConnected::HandleSetPathRequest(const PbapPseObexMessage &obexMsg)
410 {
411     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
412     const ObexHeader &req = obexMsg.GetObexHeader();
413     const ObexServerSession &obexSession = obexMsg.GetObexSession();
414     uint8_t flags = *req.GetFieldFlags();
415     PBAP_PSE_LOG_DEBUG("SetPath flags is %x", flags);
416     bool backup = false;
417     bool create = true;
418     if ((flags & OBEX_SETPATH_BACKUP) != 0) {
419         backup = true;
420     }
421     if ((flags & OBEX_SETPATH_NOCREATE) != 0) {
422         create = false;
423     }
424     if (create) {
425         PBAP_PSE_LOG_ERROR("path create is forbidden!");
426         obexSession.SendSimpleResponse(ObexRspCode::FORBIDDEN);
427         return;
428     }
429     std::vector<std::u16string> tmpPaths = currentPath_;
430     if (backup) {
431         if (currentPath_.size() > 0) {
432             tmpPaths.pop_back();
433         }
434     } else {
435         std::u16string name = u"";
436         auto nameItem = req.GetItemName();
437         if (nameItem != nullptr) {
438             name = nameItem->GetUnicodeText();
439         }
440         if (name.size() == 0) {
441             tmpPaths.clear();
442         } else {
443             tmpPaths.push_back(name);
444         }
445     }
446     std::u16string tmpFullPath = GetFullPath(tmpPaths);
447     if (!PbapPseVcardManager::CheckPhoneBookPath(tmpFullPath)) {
448         PBAP_PSE_LOG_ERROR("path isn't allowed! %{public}s", ObexUtils::UnicodeToUtf8(tmpFullPath).c_str());
449         obexSession.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::NOT_FOUND));
450         return;
451     }
452     currentPath_ = tmpPaths;
453     std::u16string path16 = GetCurrentPath();
454     std::string path = ObexUtils::UnicodeToUtf8(path16);
455     PBAP_PSE_LOG_DEBUG("CurrentPath is change to %{public}s", path.c_str());
456     obexSession.SendResponse(*ObexHeader::CreateResponse(ObexRspCode::SUCCESS));
457 }
458 
SendPhoneBookResponse(ObexServerSession & obexSession,const ObexHeader & req,const PbapPseVcardManager::PhoneBookResult & pbResult,const PbapPsePhoneBookResOpt & opt) const459 void PseConnected::SendPhoneBookResponse(ObexServerSession &obexSession, const ObexHeader &req,
460     const PbapPseVcardManager::PhoneBookResult &pbResult, const PbapPsePhoneBookResOpt &opt) const
461 {
462     PbapPseAppParams respAppParams;
463     if (opt.phonebookSize_) {
464         uint16_t phoneBookSize = pbResult.phoneBookSize_;
465         respAppParams.SetPhonebookSize(phoneBookSize);
466     }
467     if (opt.newMissedCall_) {
468         respAppParams.SetNewMissedCalls(pbResult.newMissedCallsSize_);
469     }
470     // the “Folder Version Counters” PSE and PCE feature bits are set
471     if (opt.folderVer_) {
472         respAppParams.SetPrimaryFolderVersion(pbResult.primaryFolderVersion_);
473         respAppParams.SetSecondaryFolderVersion(pbResult.secondaryFolderVersion_);
474     }
475     // the “Database Version” PSE and PCE feature bits are set
476     if (opt.dbIdentifier_) {
477         respAppParams.SetDatabaseIdentifier(pbResult.databaseIdentifier_);
478     }
479     auto resp = ObexHeader::CreateResponse(ObexRspCode::SUCCESS);
480     respAppParams.AddToObexHeader(*resp);
481     std::shared_ptr<ObexArrayBodyObject> bodyObject = nullptr;
482     // ADD BODY
483     if (!pbResult.phoneBookSizeOnly_ && pbResult.result_.size() > 0) {
484             PBAP_PSE_LOG_DEBUG("pbResult.result_.size() = %{public}zu", pbResult.result_.size());
485             bodyObject = std::make_shared<ObexArrayBodyObject>(pbResult.result_.data(), pbResult.result_.size());
486     }
487     obexSession.SendGetResponse(req, *resp, bodyObject);
488 }
489 
PullPhoneBook(ObexServerSession & obexSession,const ObexHeader & req) const490 void PseConnected::PullPhoneBook(ObexServerSession &obexSession, const ObexHeader &req) const
491 {
492     PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
493     auto nameItem = req.GetItemName();
494     if (nameItem == nullptr) {
495         PBAP_PSE_LOG_ERROR("PullPhoneBook: name can't be null!");
496         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
497         return;
498     }
499     std::u16string nameWithFolder = nameItem->GetUnicodeText();
500     if (!IsVCardName(nameWithFolder)) {
501         PBAP_PSE_LOG_ERROR("PullPhoneBook: name must endwith [.vcf]");
502         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
503         return;
504     }
505 
506     auto appParamsItem = req.GetItemAppParams();
507     PbapPseAppParams pbapAppParams;
508     if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
509         bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
510         if (!result) {
511             obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
512             return;
513         }
514     }
515     PbapPseVcardManager::PhoneBookResult pbResult;
516     PbapPseVcardManager::PullPhoneBook(nameWithFolder, pbapAppParams, GetSupportedFeatures(), pbResult);
517     if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
518         obexSession.SendSimpleResponse(pbResult.rspCode_);
519         return;
520     }
521 
522     PbapPsePhoneBookResOpt opts;
523     (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
524     opts.phonebookSize_ = pbResult.phoneBookSizeOnly_;
525     opts.newMissedCall_ = pbResult.newMissedCalls_;
526     opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
527     opts.folderVer_ = PbapPseVcardManager::IsSupportedFolderVer(GetSupportedFeatures());
528 
529     SendPhoneBookResponse(obexSession, req, pbResult, opts);
530 }
531 
PullvCardListing(ObexServerSession & obexSession,const ObexHeader & req) const532 void PseConnected::PullvCardListing(ObexServerSession &obexSession, const ObexHeader &req) const
533 {
534     PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
535     auto nameItem = req.GetItemName();
536     if (nameItem == nullptr) {
537         PBAP_PSE_LOG_ERROR("PullvCardListing: name can't be null!");
538         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
539         return;
540     }
541     std::u16string folderName = nameItem->GetUnicodeText();
542     if (folderName.find(u"/") != std::u16string::npos || folderName.find(u".") != std::u16string::npos) {
543         PBAP_PSE_LOG_ERROR("PullvCardListing: The name shall not include any path/file information!");
544         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
545         return;
546     }
547     auto appParamsItem = req.GetItemAppParams();
548     PbapPseAppParams pbapAppParams;
549     if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
550         bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
551         if (!result) {
552             obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
553             return;
554         }
555     }
556     PbapPseVcardManager::PhoneBookResult pbResult;
557     PbapPseVcardManager::PullvCardListing(
558         GetCurrentPath(), folderName, pbapAppParams, GetSupportedFeatures(), pbResult);
559     if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
560         obexSession.SendResponse(*ObexHeader::CreateResponse(pbResult.rspCode_));
561         return;
562     }
563 
564     PbapPsePhoneBookResOpt opts;
565     (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
566     opts.phonebookSize_ = pbResult.phoneBookSizeOnly_;
567     opts.newMissedCall_ = pbResult.newMissedCalls_;
568     opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
569     opts.folderVer_ = PbapPseVcardManager::IsSupportedFolderVer(GetSupportedFeatures());
570 
571     SendPhoneBookResponse(obexSession, req, pbResult, opts);
572 }
573 
CheckvCardEntryId(std::u16string & entryId) const574 bool PseConnected::CheckvCardEntryId(std::u16string &entryId) const
575 {
576     if (entryId.find(u"/") != std::u16string::npos) {
577         PBAP_PSE_LOG_ERROR("PullvCardEntry: The name shall not include any path information!");
578         return false;
579     }
580     if (!IsVCardName(entryId) && entryId.find(PBAP_PSE_X_BT_UID_PREFIX) != 0) {
581         PBAP_PSE_LOG_ERROR("PullvCardEntry: name must endwith [.vcf] or startWith [X-BT-UID:]");
582         return false;
583     }
584 
585     if (entryId.find(PBAP_PSE_X_BT_UID_PREFIX) == 0) {
586         if (entryId.size() == PBAP_PSE_X_BT_UID_PREFIX.size()) {
587             PBAP_PSE_LOG_ERROR("PullvCardEntry: X-BT-UID is empty!");
588             return false;
589         }
590     } else {
591         if (entryId.size() == PBAP_PSE_VCARD_SUFFIX.size() ||
592             entryId.size() > (PBAP_PSE_VCARD_SUFFIX.size() + PBAP_PSE_HANDLE_MAX_LENGTH)) {
593             PBAP_PSE_LOG_ERROR("PullvCardEntry: vcf size is invalid!");
594             return false;
595         }
596         std::u16string hdlId = entryId.substr(0, entryId.size() - PBAP_PSE_VCARD_SUFFIX.size());
597         if (!PbapPseVcardManager::CheckVcardHandleId(hdlId)) {
598             PBAP_PSE_LOG_ERROR("PullvCardEntry: vcf is invalid! %{public}s", ObexUtils::UnicodeToUtf8(entryId).c_str());
599             return false;
600         }
601     }
602     return true;
603 }
604 
PullvCardEntry(ObexServerSession & obexSession,const ObexHeader & req) const605 void PseConnected::PullvCardEntry(ObexServerSession &obexSession, const ObexHeader &req) const
606 {
607     PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
608     auto nameItem = req.GetItemName();
609     if (nameItem == nullptr) {
610         PBAP_PSE_LOG_ERROR("PullvCardEntry: name can't be null!");
611         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
612         return;
613     }
614     std::u16string entryId = nameItem->GetUnicodeText();
615     if (!CheckvCardEntryId(entryId)) {
616         obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
617         return;
618     }
619     auto appParamsItem = req.GetItemAppParams();
620     PbapPseAppParams pbapAppParams;
621     if (appParamsItem != nullptr && appParamsItem->GetTlvParamters()) {
622         bool result = pbapAppParams.Init(*appParamsItem->GetTlvParamters());
623         if (!result) {
624             obexSession.SendSimpleResponse(ObexRspCode::NOT_ACCEPTABLE);
625             return;
626         }
627     }
628     PbapPseVcardManager::PhoneBookResult pbResult;
629     PbapPseVcardManager::PullvCardEntry(GetCurrentPath(), entryId, pbapAppParams, GetSupportedFeatures(), pbResult);
630     if (pbResult.rspCode_ != ObexRspCode::SUCCESS) {
631         obexSession.SendSimpleResponse(pbResult.rspCode_);
632         return;
633     }
634 
635     PbapPsePhoneBookResOpt opts;
636     (void)memset_s(&opts, sizeof(PbapPsePhoneBookResOpt), 0, sizeof(PbapPsePhoneBookResOpt));
637     opts.phonebookSize_ = false;
638     opts.newMissedCall_ = false;
639     opts.dbIdentifier_ = PbapPseVcardManager::IsSupportedDbVer(GetSupportedFeatures());
640     opts.folderVer_ = false;
641 
642     SendPhoneBookResponse(obexSession, req, pbResult, opts);
643 }
644 
IsVCardName(std::u16string & name) const645 bool PseConnected::IsVCardName(std::u16string &name) const
646 {
647     return name.size() >= PBAP_PSE_VCARD_SUFFIX.size() &&
648            name.find(PBAP_PSE_VCARD_SUFFIX, name.size() - PBAP_PSE_VCARD_SUFFIX.size()) != std::u16string::npos;
649 }
650 
GetCurrentPath() const651 std::u16string PseConnected::GetCurrentPath() const
652 {
653     return GetFullPath(currentPath_);
654 }
655 
GetFullPath(const std::vector<std::u16string> & paths) const656 std::u16string PseConnected::GetFullPath(const std::vector<std::u16string> &paths) const
657 {
658     std::u16string currentPath = std::accumulate(paths.begin(), paths.end(), std::u16string(u""),
659         [](std::u16string strRet, std::u16string str)->std::u16string {
660             return strRet + u"/" + str;
661         });
662 
663     return currentPath;
664 }
665 
GetSupportedFeatures() const666 uint32_t PseConnected::GetSupportedFeatures() const
667 {
668     return stm_.GetStmInfo().pceFeatures_ & PBAP_PSE_SUPPORTED_FEATURES;
669 }
670 
DisconnectObex(const PbapPseObexMessage & obexMsg) const671 void PseConnected::DisconnectObex(const PbapPseObexMessage &obexMsg) const
672 {
673     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
674     ObexServerSession &obexSession = obexMsg.GetObexSession();
675     obexSession.SendSimpleResponse(ObexRspCode::SUCCESS);
676     obexSession.Disconnect();
677     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
678 }
679 
PseDisConnected(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)680 PseDisConnected::PseDisConnected(
681     const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
682     : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
683 {}
684 
Entry()685 void PseDisConnected::Entry()
686 {
687     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
688     auto &device = stm_.GetDevice();
689     IPowerManager::GetInstance().StatusUpdate(RequestStatus::CONNECT_OFF, PROFILE_NAME_PBAP_PSE, device);
690     observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
691         observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::DISCONNECTED));
692     });
693     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
694 }
695 
Exit()696 void PseDisConnected::Exit()
697 {}
698 
Dispatch(const utility::Message & msg)699 bool PseDisConnected::Dispatch(const utility::Message &msg)
700 {
701     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
702     PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
703     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
704     return false;
705 }
706 
PseDisConnecting(const std::string & name,PbapPseStateMachine & stm,BaseObserverList<IPbapPseObserver> & observerMgrList)707 PseDisConnecting::PseDisConnecting(
708     const std::string &name, PbapPseStateMachine &stm, BaseObserverList<IPbapPseObserver> &observerMgrList)
709     : State(name, stm), stm_(stm), observerMgrList_(observerMgrList)
710 {}
711 
Entry()712 void PseDisConnecting::Entry()
713 {
714     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
715     auto &device = stm_.GetDevice();
716     observerMgrList_.ForEach([device](IPbapPseObserver &observer) {
717         observer.OnServiceConnectionStateChanged(device, static_cast<int>(BTConnectState::DISCONNECTING));
718     });
719     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
720 }
721 
Exit()722 void PseDisConnecting::Exit()
723 {
724     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
725 }
726 
Dispatch(const utility::Message & msg)727 bool PseDisConnecting::Dispatch(const utility::Message &msg)
728 {
729     PBAP_PSE_LOG_INFO("%{public}s start", __PRETTY_FUNCTION__);
730     bool ret = true;
731     switch (msg.what_) {
732         case PSE_DEVICE_DISCONNECTED:
733             Transition(PbapPseStateMachine::PSE_DISCONNECTED_STATE);
734             break;
735         default:
736             PBAP_PSE_LOG_ERROR("NOT SUPPORT MSGID %{public}d", msg.what_);
737             ret = false;
738             break;
739     }
740 
741     PBAP_PSE_LOG_INFO("%{public}s end", __PRETTY_FUNCTION__);
742     return ret;
743 }
744 
PbapPseStateMachine(const RawAddress & device,BaseObserverList<IPbapPseObserver> & observerMgrList,std::function<uint32_t ()> getNextConnectIdFun)745 PbapPseStateMachine::PbapPseStateMachine(const RawAddress &device, BaseObserverList<IPbapPseObserver> &observerMgrList,
746     std::function<uint32_t()> getNextConnectIdFun)
747     : device_(device), observerMgrList_(observerMgrList), getNextConnectIdFun_(std::move(getNextConnectIdFun))
748 {
749 }
750 
~PbapPseStateMachine()751 PbapPseStateMachine::~PbapPseStateMachine()
752 {
753     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
754 }
755 
756 const std::string PbapPseStateMachine::PSE_WAITING_FOR_CONNECT_STATE = "PseWaitingForConnect";
757 const std::string PbapPseStateMachine::PSE_CONNECTED_STATE = "PseConnected";
758 const std::string PbapPseStateMachine::PSE_CONNECTING_STATE = "PseConnecting";
759 const std::string PbapPseStateMachine::PSE_DISCONNECTED_STATE = "PseDisConnected";
760 const std::string PbapPseStateMachine::PSE_DISCONNECTING_STATE = "PseDisConnecting";
761 
Init()762 void PbapPseStateMachine::Init()
763 {
764     std::unique_ptr<State> disconnected =
765         std::make_unique<PseDisConnected>(PSE_DISCONNECTED_STATE, *this, observerMgrList_);
766     std::unique_ptr<State> disconnecting =
767         std::make_unique<PseDisConnecting>(PSE_DISCONNECTING_STATE, *this, observerMgrList_);
768     std::unique_ptr<State> connecting =
769         std::make_unique<PseConnecting>(PSE_CONNECTING_STATE, *this, observerMgrList_, getNextConnectIdFun_);
770     std::unique_ptr<State> waitingForCnt = std::make_unique<PseWaitingForConnect>(PSE_WAITING_FOR_CONNECT_STATE, *this);
771     std::unique_ptr<State> connected = std::make_unique<PseConnected>(PSE_CONNECTED_STATE, *this, observerMgrList_);
772 
773     Move(disconnected);
774     Move(disconnecting);
775     Move(connecting);
776     Move(waitingForCnt);
777     Move(connected);
778 
779     InitState(PSE_WAITING_FOR_CONNECT_STATE);
780 }
781 
StartTimer(std::function<void ()> callback,int ms)782 bool PbapPseStateMachine::StartTimer(std::function<void()> callback, int ms)
783 {
784     PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
785     timer_ = std::make_unique<utility::Timer>(callback);
786     return timer_->Start(ms, false);
787 }
788 
StopTimer()789 void PbapPseStateMachine::StopTimer()
790 {
791     if (timer_) {
792         PBAP_PSE_LOG_INFO("%{public}s", __PRETTY_FUNCTION__);
793         timer_->Stop();
794         timer_ = nullptr;
795     }
796 }
797 
GetConnectState() const798 BTConnectState PbapPseStateMachine::GetConnectState() const
799 {
800     std::string name = GetState()->Name();
801     if (name == PSE_CONNECTING_STATE) {
802         return BTConnectState::CONNECTING;
803     }
804     if (name == PSE_CONNECTED_STATE) {
805         return BTConnectState::CONNECTED;
806     }
807     if (name == PSE_DISCONNECTING_STATE) {
808         return BTConnectState::DISCONNECTING;
809     }
810     return BTConnectState::DISCONNECTED;
811 }
812 
813 /**
814  * @brief get remote address
815  * @details get remote address
816  * @return RawAddress&
817  */
GetDevice() const818 const RawAddress &PbapPseStateMachine::GetDevice() const
819 {
820     return device_;
821 }
822 
823 /**
824  * @brief Is Connected
825  * @details Is Connected
826  * @return bool
827  */
IsConnected() const828 bool PbapPseStateMachine::IsConnected() const
829 {
830     return GetState()->Name() == PSE_CONNECTED_STATE;
831 }
832 
IsAccepted() const833 bool PbapPseStateMachine::IsAccepted() const
834 {
835     return stmInfo_.accepted_;
836 }
837 
SetBusy(bool isBusy)838 void PbapPseStateMachine::SetBusy(bool isBusy)
839 {
840     if (stmInfo_.isBusy_ == isBusy) {
841         return;
842     }
843     stmInfo_.isBusy_ = isBusy;
844     if (isBusy) {
845         HILOGI("[%{public}s] PowerStatusUpdate -> BUSY", GetEncryptAddr(device_.GetAddress()).c_str());
846         IPowerManager::GetInstance().StatusUpdate(RequestStatus::BUSY, PROFILE_NAME_PBAP_PSE, device_);
847     } else {
848         HILOGI("[%{public}s] PowerStatusUpdate -> IDLE", GetEncryptAddr(device_.GetAddress()).c_str());
849         IPowerManager::GetInstance().StatusUpdate(RequestStatus::IDLE, PROFILE_NAME_PBAP_PSE, device_);
850     }
851 }
852 
IsBusy() const853 bool PbapPseStateMachine::IsBusy() const
854 {
855     return stmInfo_.isBusy_;
856 }
857 
GetStmInfo()858 PbapPseStateMachineInfo &PbapPseStateMachine::GetStmInfo()
859 {
860     return stmInfo_;
861 }
862 }  // namespace bluetooth
863 }  // namespace OHOS