1 use std::collections::HashMap;
2 use std::fmt::{Display, Formatter};
3 use std::slice::SliceIndex;
4 use std::sync::{Arc, Mutex};
5 use std::time::Duration;
6 
7 use crate::bt_adv::AdvSet;
8 use crate::bt_gatt::AuthReq;
9 use crate::callbacks::{BtGattCallback, BtGattServerCallback};
10 use crate::ClientContext;
11 use crate::{console_red, console_yellow, print_error, print_info};
12 use bt_topshim::btif::{
13     BtConnectionState, BtDiscMode, BtStatus, BtTransport, RawAddress, Uuid, INVALID_RSSI,
14 };
15 use bt_topshim::profiles::gatt::{GattStatus, LePhy};
16 use bt_topshim::profiles::hid_host::BthhReportType;
17 use bt_topshim::profiles::sdp::{BtSdpMpsRecord, BtSdpRecord};
18 use bt_topshim::profiles::ProfileConnectionState;
19 use btstack::battery_manager::IBatteryManager;
20 use btstack::bluetooth::{BluetoothDevice, IBluetooth};
21 use btstack::bluetooth_gatt::{
22     BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService, GattDbElementType,
23     GattWriteType, IBluetoothGatt,
24 };
25 use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothTelephony};
26 use btstack::bluetooth_qa::IBluetoothQA;
27 use btstack::socket_manager::{IBluetoothSocketManager, SocketResult};
28 use btstack::uuid::{Profile, UuidHelper};
29 use manager_service::iface_bluetooth_manager::IBluetoothManager;
30 
31 const INDENT_CHAR: &str = " ";
32 const BAR1_CHAR: &str = "=";
33 const BAR2_CHAR: &str = "-";
34 const MAX_MENU_CHAR_WIDTH: usize = 72;
35 
36 const GATT_CLIENT_APP_UUID: &str = "12345678123456781234567812345678";
37 const GATT_SERVER_APP_UUID: &str = "12345678123456781234567812345679";
38 const HEART_RATE_SERVICE_UUID: &str = "0000180D-0000-1000-8000-00805F9B34FB";
39 const HEART_RATE_MEASUREMENT_UUID: &str = "00002A37-0000-1000-8000-00805F9B34FB";
40 const GENERIC_UUID: &str = "00000000-0000-1000-8000-00805F9B34FB";
41 const CCC_DESCRIPTOR_UUID: &str = "00002902-0000-1000-8000-00805F9B34FB";
42 const BATTERY_SERVICE_UUID: &str = "0000180F-0000-1000-8000-00805F9B34FB";
43 
44 enum CommandError {
45     // Command not handled due to invalid arguments.
46     InvalidArgs,
47     // Command handled but failed with the given reason.
48     Failed(String),
49 }
50 
51 impl From<&str> for CommandError {
from(s: &str) -> CommandError52     fn from(s: &str) -> CommandError {
53         CommandError::Failed(String::from(s))
54     }
55 }
56 
57 impl From<String> for CommandError {
from(s: String) -> CommandError58     fn from(s: String) -> CommandError {
59         CommandError::Failed(s)
60     }
61 }
62 
63 type CommandResult = Result<(), CommandError>;
64 
65 type CommandFunction = fn(&mut CommandHandler, &Vec<String>) -> CommandResult;
66 
_noop(_handler: &mut CommandHandler, _args: &Vec<String>) -> CommandResult67 fn _noop(_handler: &mut CommandHandler, _args: &Vec<String>) -> CommandResult {
68     // Used so we can add options with no direct function
69     // e.g. help and quit
70     Ok(())
71 }
72 
73 pub struct CommandOption {
74     rules: Vec<String>,
75     description: String,
76     function_pointer: CommandFunction,
77 }
78 
79 /// Handles string command entered from command line.
80 pub(crate) struct CommandHandler {
81     context: Arc<Mutex<ClientContext>>,
82     command_options: HashMap<String, CommandOption>,
83 }
84 
85 /// Define what to do when a socket connects. Mainly for qualification purposes.
86 /// Specifically, after a socket is connected/accepted, we will do
87 /// (1) send a chunk of data every |send_interval| time until |num_frame| chunks has been sent.
88 /// (2) wait another |disconnect_delay| time. any incoming data will be dumpted during this time.
89 /// (3) disconnect the socket.
90 #[derive(Copy, Clone)]
91 pub struct SocketSchedule {
92     /// Number of times to send data
93     pub num_frame: u32,
94     /// Time interval between each sending
95     pub send_interval: Duration,
96     /// Extra time after the last sending. Any incoming data will be printed during this time.
97     pub disconnect_delay: Duration,
98 }
99 
100 struct DisplayList<T>(Vec<T>);
101 
102 impl<T: Display> Display for DisplayList<T> {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result103     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
104         let _ = write!(f, "[\n");
105         for item in self.0.iter() {
106             let _ = write!(f, "  {}\n", item);
107         }
108 
109         write!(f, "]")
110     }
111 }
112 
wrap_help_text(text: &str, max: usize, indent: usize) -> String113 fn wrap_help_text(text: &str, max: usize, indent: usize) -> String {
114     let remaining_count = std::cmp::max(
115         // real_max
116         std::cmp::max(max, text.chars().count())
117         // take away char count
118          - text.chars().count()
119         // take away real_indent
120          - (
121              if std::cmp::max(max, text.chars().count())- text.chars().count() > indent {
122                  indent
123              } else {
124                  0
125              }),
126         0,
127     );
128 
129     format!("|{}{}{}|", INDENT_CHAR.repeat(indent), text, INDENT_CHAR.repeat(remaining_count))
130 }
131 
132 // This should be called during the constructor in order to populate the command option map
build_commands() -> HashMap<String, CommandOption>133 fn build_commands() -> HashMap<String, CommandOption> {
134     let mut command_options = HashMap::<String, CommandOption>::new();
135     command_options.insert(
136         String::from("adapter"),
137         CommandOption {
138             rules: vec![
139                 String::from("adapter enable"),
140                 String::from("adapter disable"),
141                 String::from("adapter show"),
142                 String::from("adapter discoverable <on|limited|off> <duration>"),
143                 String::from("adapter connectable <on|off>"),
144                 String::from("adapter set-name <name>"),
145             ],
146             description: String::from(
147                 "Enable/Disable/Show default bluetooth adapter. (e.g. adapter enable)\n
148                  Discoverable On/Limited/Off (e.g. adapter discoverable on 60)\n
149                  Connectable On/Off (e.g. adapter connectable on)",
150             ),
151             function_pointer: CommandHandler::cmd_adapter,
152         },
153     );
154     command_options.insert(
155         String::from("battery"),
156         CommandOption {
157             rules: vec![
158                 String::from("battery status <address>"),
159                 String::from("battery track <address>"),
160                 String::from("battery untrack <address>"),
161             ],
162             description: String::from(
163                 "
164                 status: Current battery status of a given device.\n
165                 track: Track a given device to monitor battery updates.\n
166                 untrack: Stop tracking a device for battery updates.
167             ",
168             ),
169             function_pointer: CommandHandler::cmd_battery,
170         },
171     );
172     command_options.insert(
173         String::from("bond"),
174         CommandOption {
175             rules: vec![String::from("bond <add|remove|cancel> <address>")],
176             description: String::from("Creates a bond with a device."),
177             function_pointer: CommandHandler::cmd_bond,
178         },
179     );
180     command_options.insert(
181         String::from("device"),
182         CommandOption {
183             rules: vec![
184                 String::from("device <connect|disconnect|info> <address>"),
185                 String::from("device set-pairing-confirmation <address> <accept|reject>"),
186                 String::from("device set-pairing-pin <address> <pin|reject>"),
187                 String::from("device set-pairing-passkey <address> <passkey|reject>"),
188                 String::from("device set-alias <address> <new-alias>"),
189                 String::from("device get-rssi <address>"),
190             ],
191             description: String::from("Take action on a remote device. (i.e. info)"),
192             function_pointer: CommandHandler::cmd_device,
193         },
194     );
195     command_options.insert(
196         String::from("discovery"),
197         CommandOption {
198             rules: vec![String::from("discovery <start|stop>")],
199             description: String::from("Start and stop device discovery. (e.g. discovery start)"),
200             function_pointer: CommandHandler::cmd_discovery,
201         },
202     );
203     command_options.insert(
204         String::from("floss"),
205         CommandOption {
206             rules: vec![String::from("floss <enable|disable>")],
207             description: String::from("Enable or disable Floss for dogfood."),
208             function_pointer: CommandHandler::cmd_floss,
209         },
210     );
211     command_options.insert(
212         String::from("gatt"),
213         CommandOption {
214             rules: vec![
215                 String::from("gatt register-client"),
216                 String::from("gatt client-connect <address>"),
217                 String::from("gatt client-read-phy <address>"),
218                 String::from("gatt client-discover-services <address>"),
219                 String::from("gatt client-discover-service-by-uuid-pts <address> <uuid>"),
220                 String::from("gatt client-disconnect <address>"),
221                 String::from("gatt configure-mtu <address> <mtu>"),
222                 String::from("gatt set-direct-connect <true|false>"),
223                 String::from("gatt set-connect-transport <Bredr|LE|Auto>"),
224                 String::from("gatt set-connect-opportunistic <true|false>"),
225                 String::from("gatt set-connect-phy <Phy1m|Phy2m|PhyCoded>"),
226                 String::from("gatt set-auth-req <NONE|EncNoMitm|EncMitm|SignedNoMitm|SignedMitm>"),
227                 String::from(
228                     "gatt write-characteristic <address> <handle> <NoRsp|Write|Prepare> <value>",
229                 ),
230                 String::from("gatt read-characteristic <address> <handle>"),
231                 String::from(
232                     "gatt read-characteristic-by-uuid <address> <uuid> <start_handle> <end_handle>",
233                 ),
234                 String::from("gatt register-notification <address> <handle> <enable|disable>"),
235                 String::from("gatt register-server"),
236                 String::from("gatt unregister-server <server_id>"),
237                 String::from("gatt server-connect <server_id> <client_address>"),
238                 String::from("gatt server-disconnect <server_id> <client_address>"),
239                 String::from("gatt server-add-basic-service <server_id>"),
240                 String::from("gatt server-add-service <server_id> <incl_service_instance_id>"),
241                 String::from("gatt server-remove-service <server_id> <service_handle>"),
242                 String::from("gatt server-clear-all-services <server_id>"),
243                 String::from("gatt server-send-response <server_id> <success|fail>"),
244                 String::from("gatt server-set-direct-connect <true|false>"),
245                 String::from("gatt server-set-connect-transport <Bredr|LE|Auto>"),
246             ],
247             description: String::from(
248                 "GATT tools\n\n
249                 Creating a GATT Server:\n
250                 Register a server, then add a basic (battery) service. After, a more complex\n
251                 (heartrate) service can be created with previously created services included.",
252             ),
253             function_pointer: CommandHandler::cmd_gatt,
254         },
255     );
256     command_options.insert(
257         String::from("le-scan"),
258         CommandOption {
259             rules: vec![
260                 String::from("le-scan register-scanner"),
261                 String::from("le-scan unregister-scanner <scanner-id>"),
262                 String::from("le-scan start-scan <scanner-id>"),
263                 String::from("le-scan stop-scan <scanner-id>"),
264             ],
265             description: String::from("LE scanning utilities."),
266             function_pointer: CommandHandler::cmd_le_scan,
267         },
268     );
269     command_options.insert(
270         String::from("advertise"),
271         CommandOption {
272             rules: vec![
273                 String::from("advertise <on|off|ext>"),
274                 String::from("advertise set-interval <ms>"),
275                 String::from("advertise set-scan-rsp <enable|disable>"),
276                 String::from("advertise set-raw-data <raw-adv-data> <adv-id>"),
277                 String::from("advertise set-connectable <on|off> <adv-id>"),
278             ],
279             description: String::from("Advertising utilities."),
280             function_pointer: CommandHandler::cmd_advertise,
281         },
282     );
283     command_options.insert(
284         String::from("sdp"),
285         CommandOption {
286             rules: vec![String::from("sdp search <address> <uuid>")],
287             description: String::from("Service Discovery Protocol utilities."),
288             function_pointer: CommandHandler::cmd_sdp,
289         },
290     );
291     command_options.insert(
292         String::from("socket"),
293         CommandOption {
294             rules: vec![
295                 String::from("socket listen <auth-required> <Bredr|LE>"),
296                 String::from("socket listen-rfcomm <scn>"),
297                 String::from("socket send-msc <dlci> <address>"),
298                 String::from(
299                     "socket connect <address> <l2cap|rfcomm> <psm|uuid> <auth-required> <Bredr|LE>",
300                 ),
301                 String::from("socket close <socket_id>"),
302                 String::from("socket set-on-connect-schedule <send|resend|dump>"),
303             ],
304             description: String::from("Socket manager utilities."),
305             function_pointer: CommandHandler::cmd_socket,
306         },
307     );
308     command_options.insert(
309         String::from("hid"),
310         CommandOption {
311             rules: vec![
312                 String::from("hid get-report <address> <Input|Output|Feature> <report_id>"),
313                 String::from("hid set-report <address> <Input|Output|Feature> <report_value>"),
314                 String::from("hid send-data <address> <data>"),
315             ],
316             description: String::from("Socket manager utilities."),
317             function_pointer: CommandHandler::cmd_hid,
318         },
319     );
320     command_options.insert(
321         String::from("get-address"),
322         CommandOption {
323             rules: vec![String::from("get-address")],
324             description: String::from("Gets the local device address."),
325             function_pointer: CommandHandler::cmd_get_address,
326         },
327     );
328     command_options.insert(
329         String::from("qa"),
330         CommandOption {
331             rules: vec![String::from("qa add-media-player <name> <browsing_supported>")],
332             description: String::from("Methods for testing purposes"),
333             function_pointer: CommandHandler::cmd_qa,
334         },
335     );
336     command_options.insert(
337         String::from("help"),
338         CommandOption {
339             rules: vec![String::from("help")],
340             description: String::from("Shows this menu."),
341             function_pointer: CommandHandler::cmd_help,
342         },
343     );
344     command_options.insert(
345         String::from("list"),
346         CommandOption {
347             rules: vec![String::from("list <bonded|found|connected>")],
348             description: String::from(
349                 "List bonded or found remote devices. Use: list <bonded|found>",
350             ),
351             function_pointer: CommandHandler::cmd_list_devices,
352         },
353     );
354     command_options.insert(
355         String::from("telephony"),
356         CommandOption {
357             rules: vec![
358                 String::from("telephony set-network <on|off>"),
359                 String::from("telephony set-roaming <on|off>"),
360                 String::from("telephony set-signal <strength>"),
361                 String::from("telephony set-battery <level>"),
362                 String::from("telephony set-phone-opss <on|off>"),
363                 String::from("telephony <enable|disable>"),
364                 String::from("telephony <incoming-call|dialing-call> <number>"),
365                 String::from("telephony <answer-call|hangup-call>"),
366                 String::from("telephony <set-memory-call|set-last-call> [<number>]"),
367                 String::from(
368                     "telephony <release-held|release-active-accept-held|hold-active-accept-held>",
369                 ),
370                 String::from("telephony <audio-connect|audio-disconnect> <address>"),
371             ],
372             description: String::from("Set device telephony status."),
373             function_pointer: CommandHandler::cmd_telephony,
374         },
375     );
376     command_options.insert(
377         String::from("media"),
378         CommandOption {
379             rules: vec![String::from("media log")],
380             description: String::from("Audio tools."),
381             function_pointer: CommandHandler::cmd_media,
382         },
383     );
384     command_options.insert(
385         String::from("quit"),
386         CommandOption {
387             rules: vec![String::from("quit")],
388             description: String::from("Quit out of the interactive shell."),
389             function_pointer: _noop,
390         },
391     );
392     command_options.insert(
393         String::from("dumpsys"),
394         CommandOption {
395             rules: vec![String::from("dumpsys")],
396             description: String::from("Get diagnostic output."),
397             function_pointer: CommandHandler::cmd_dumpsys,
398         },
399     );
400     command_options
401 }
402 
403 // Helper to index a vector safely. The same as `args.get(i)` but converts the None into a
404 // CommandError::InvalidArgs.
405 //
406 // Use this to safely index an argument and conveniently return the error if the argument does not
407 // exist.
get_arg<I>( args: &Vec<String>, index: I, ) -> Result<&<I as SliceIndex<[String]>>::Output, CommandError> where I: SliceIndex<[String]>,408 fn get_arg<I>(
409     args: &Vec<String>,
410     index: I,
411 ) -> Result<&<I as SliceIndex<[String]>>::Output, CommandError>
412 where
413     I: SliceIndex<[String]>,
414 {
415     args.get(index).ok_or(CommandError::InvalidArgs)
416 }
417 
418 impl CommandHandler {
419     /// Creates a new CommandHandler.
new(context: Arc<Mutex<ClientContext>>) -> CommandHandler420     pub fn new(context: Arc<Mutex<ClientContext>>) -> CommandHandler {
421         CommandHandler { context, command_options: build_commands() }
422     }
423 
424     /// Entry point for command and arguments
process_cmd_line(&mut self, command: &str, args: &Vec<String>) -> bool425     pub fn process_cmd_line(&mut self, command: &str, args: &Vec<String>) -> bool {
426         // Ignore empty line
427         match command {
428             "" => false,
429             _ => match self.command_options.get(command) {
430                 Some(cmd) => {
431                     let rules = cmd.rules.clone();
432                     match (cmd.function_pointer)(self, &args) {
433                         Ok(()) => true,
434                         Err(CommandError::InvalidArgs) => {
435                             print_error!("Invalid arguments. Usage:\n{}", rules.join("\n"));
436                             false
437                         }
438                         Err(CommandError::Failed(msg)) => {
439                             print_error!("Command failed: {}", msg);
440                             false
441                         }
442                     }
443                 }
444                 None => {
445                     println!("'{}' is an invalid command!", command);
446                     self.cmd_help(&args).ok();
447                     false
448                 }
449             },
450         }
451     }
452 
lock_context(&self) -> std::sync::MutexGuard<ClientContext>453     fn lock_context(&self) -> std::sync::MutexGuard<ClientContext> {
454         self.context.lock().unwrap()
455     }
456 
457     // Common message for when the adapter isn't ready
adapter_not_ready(&self) -> CommandError458     fn adapter_not_ready(&self) -> CommandError {
459         format!(
460             "Default adapter {} is not enabled. Enable the adapter before using this command.",
461             self.lock_context().default_adapter
462         )
463         .into()
464     }
465 
cmd_help(&mut self, args: &Vec<String>) -> CommandResult466     fn cmd_help(&mut self, args: &Vec<String>) -> CommandResult {
467         if let Some(command) = args.get(0) {
468             match self.command_options.get(command) {
469                 Some(cmd) => {
470                     println!(
471                         "\n{}{}\n{}{}\n",
472                         INDENT_CHAR.repeat(4),
473                         command,
474                         INDENT_CHAR.repeat(8),
475                         cmd.description
476                     );
477                 }
478                 None => {
479                     println!("'{}' is an invalid command!", command);
480                     self.cmd_help(&vec![]).ok();
481                 }
482             }
483         } else {
484             // Build equals bar and Shave off sides
485             let equal_bar = format!(" {} ", BAR1_CHAR.repeat(MAX_MENU_CHAR_WIDTH));
486 
487             // Build empty bar and Shave off sides
488             let empty_bar = format!("|{}|", INDENT_CHAR.repeat(MAX_MENU_CHAR_WIDTH));
489 
490             // Header
491             println!(
492                 "\n{}\n{}\n{}\n{}",
493                 equal_bar,
494                 wrap_help_text("Help Menu", MAX_MENU_CHAR_WIDTH, 2),
495                 // Minus bar
496                 format!("+{}+", BAR2_CHAR.repeat(MAX_MENU_CHAR_WIDTH)),
497                 empty_bar
498             );
499 
500             // Print commands
501             for (key, val) in self.command_options.iter() {
502                 println!(
503                     "{}\n{}\n{}",
504                     wrap_help_text(&key, MAX_MENU_CHAR_WIDTH, 4),
505                     wrap_help_text(&val.description, MAX_MENU_CHAR_WIDTH, 8),
506                     empty_bar
507                 );
508             }
509 
510             // Footer
511             println!("{}\n{}", empty_bar, equal_bar);
512         }
513 
514         Ok(())
515     }
516 
cmd_adapter(&mut self, args: &Vec<String>) -> CommandResult517     fn cmd_adapter(&mut self, args: &Vec<String>) -> CommandResult {
518         if !self.lock_context().manager_dbus.get_floss_enabled() {
519             return Err("Floss is not enabled. First run, `floss enable`".into());
520         }
521 
522         let default_adapter = self.lock_context().default_adapter;
523 
524         let command = get_arg(args, 0)?;
525 
526         match &command[..] {
527             "enable" => {
528                 if self.lock_context().is_restricted {
529                     return Err("You are not allowed to toggle adapter power".into());
530                 }
531                 self.lock_context().manager_dbus.start(default_adapter);
532             }
533             "disable" => {
534                 if self.lock_context().is_restricted {
535                     return Err("You are not allowed to toggle adapter power".into());
536                 }
537                 self.lock_context().manager_dbus.stop(default_adapter);
538             }
539             "show" => {
540                 if !self.lock_context().adapter_ready {
541                     return Err(self.adapter_not_ready());
542                 }
543 
544                 let enabled = self.lock_context().enabled;
545                 let address = self.lock_context().adapter_address.unwrap_or_default();
546                 let context = self.lock_context();
547                 let adapter_dbus = context.adapter_dbus.as_ref().unwrap();
548                 let qa_dbus = context.qa_dbus.as_ref().unwrap();
549                 let name = adapter_dbus.get_name();
550                 let modalias = qa_dbus.get_modalias();
551                 let uuids = adapter_dbus.get_uuids();
552                 let is_discoverable = adapter_dbus.get_discoverable();
553                 let discoverable_timeout = adapter_dbus.get_discoverable_timeout();
554                 let cod = adapter_dbus.get_bluetooth_class();
555                 let multi_adv_supported = adapter_dbus.is_multi_advertisement_supported();
556                 let le_ext_adv_supported = adapter_dbus.is_le_extended_advertising_supported();
557                 let wbs_supported = adapter_dbus.is_wbs_supported();
558                 let le_audio_supported = adapter_dbus.is_le_audio_supported();
559                 let supported_profiles = UuidHelper::get_supported_profiles();
560                 let connected_profiles: Vec<(Profile, ProfileConnectionState)> = supported_profiles
561                     .iter()
562                     .map(|&prof| {
563                         if let Some(&uuid) = UuidHelper::get_profile_uuid(&prof) {
564                             (prof, adapter_dbus.get_profile_connection_state(uuid))
565                         } else {
566                             (prof, ProfileConnectionState::Disconnected)
567                         }
568                     })
569                     .filter(|(_prof, state)| state != &ProfileConnectionState::Disconnected)
570                     .collect();
571                 qa_dbus.fetch_connectable();
572                 qa_dbus.fetch_alias();
573                 qa_dbus.fetch_discoverable_mode();
574                 print_info!("Address: {}", address.to_string());
575                 print_info!("Name: {}", name);
576                 print_info!("Modalias: {}", modalias);
577                 print_info!("State: {}", if enabled { "enabled" } else { "disabled" });
578                 print_info!("Discoverable: {}", is_discoverable);
579                 print_info!("DiscoverableTimeout: {}s", discoverable_timeout);
580                 print_info!("Class: {:#06x}", cod);
581                 print_info!("IsMultiAdvertisementSupported: {}", multi_adv_supported);
582                 print_info!("IsLeExtendedAdvertisingSupported: {}", le_ext_adv_supported);
583                 print_info!("Connected profiles: {:?}", connected_profiles);
584                 print_info!("IsWbsSupported: {}", wbs_supported);
585                 print_info!("IsLeAudioSupported: {}", le_audio_supported);
586                 print_info!(
587                     "Uuids: {}",
588                     DisplayList(
589                         uuids
590                             .iter()
591                             .map(|&x| UuidHelper::known_uuid_to_string(&x))
592                             .collect::<Vec<String>>()
593                     )
594                 );
595             }
596             "discoverable" => match &get_arg(args, 1)?[..] {
597                 "on" => {
598                     let duration = String::from(get_arg(args, 2)?)
599                         .parse::<u32>()
600                         .or(Err("Failed parsing duration."))?;
601 
602                     let discoverable = self
603                         .lock_context()
604                         .adapter_dbus
605                         .as_mut()
606                         .unwrap()
607                         .set_discoverable(BtDiscMode::GeneralDiscoverable, duration);
608                     print_info!(
609                         "Set discoverable for {} seconds: {}",
610                         duration,
611                         if discoverable { "succeeded" } else { "failed" }
612                     );
613                 }
614                 "limited" => {
615                     let duration = String::from(get_arg(args, 2)?)
616                         .parse::<u32>()
617                         .or(Err("Failed parsing duration."))?;
618 
619                     let discoverable = self
620                         .lock_context()
621                         .adapter_dbus
622                         .as_mut()
623                         .unwrap()
624                         .set_discoverable(BtDiscMode::LimitedDiscoverable, duration);
625                     print_info!(
626                         "Set limited discoverable for {} seconds: {}",
627                         duration,
628                         if discoverable { "succeeded" } else { "failed" }
629                     );
630                 }
631                 "off" => {
632                     let discoverable = self
633                         .lock_context()
634                         .adapter_dbus
635                         .as_mut()
636                         .unwrap()
637                         .set_discoverable(BtDiscMode::NonDiscoverable, 0 /*not used*/);
638                     print_info!(
639                         "Turn discoverable off: {}",
640                         if discoverable { "succeeded" } else { "failed" }
641                     );
642                 }
643                 other => println!("Invalid argument for adapter discoverable '{}'", other),
644             },
645             "connectable" => match &get_arg(args, 1)?[..] {
646                 "on" => {
647                     self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(true);
648                 }
649                 "off" => {
650                     self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(false);
651                 }
652                 other => println!("Invalid argument for adapter connectable '{}'", other),
653             },
654             "set-name" => {
655                 if let Some(name) = args.get(1) {
656                     self.lock_context().adapter_dbus.as_ref().unwrap().set_name(name.to_string());
657                 } else {
658                     println!("usage: adapter set-name <name>");
659                 }
660             }
661 
662             _ => return Err(CommandError::InvalidArgs),
663         };
664 
665         Ok(())
666     }
667 
cmd_get_address(&mut self, _args: &Vec<String>) -> CommandResult668     fn cmd_get_address(&mut self, _args: &Vec<String>) -> CommandResult {
669         if !self.lock_context().adapter_ready {
670             return Err(self.adapter_not_ready());
671         }
672 
673         let address = self.lock_context().update_adapter_address();
674         print_info!("Local address = {}", address.to_string());
675         Ok(())
676     }
677 
cmd_discovery(&mut self, args: &Vec<String>) -> CommandResult678     fn cmd_discovery(&mut self, args: &Vec<String>) -> CommandResult {
679         if !self.lock_context().adapter_ready {
680             return Err(self.adapter_not_ready());
681         }
682 
683         let command = get_arg(args, 0)?;
684 
685         match &command[..] {
686             "start" => {
687                 self.lock_context().adapter_dbus.as_mut().unwrap().start_discovery();
688             }
689             "stop" => {
690                 self.lock_context().adapter_dbus.as_mut().unwrap().cancel_discovery();
691             }
692             _ => return Err(CommandError::InvalidArgs),
693         }
694 
695         Ok(())
696     }
697 
cmd_battery(&mut self, args: &Vec<String>) -> CommandResult698     fn cmd_battery(&mut self, args: &Vec<String>) -> CommandResult {
699         if !self.lock_context().adapter_ready {
700             return Err(self.adapter_not_ready());
701         }
702 
703         let command = get_arg(args, 0)?;
704         let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
705         let address = addr.to_string();
706 
707         match &command[..] {
708             "status" => {
709                 match self
710                     .lock_context()
711                     .battery_manager_dbus
712                     .as_ref()
713                     .unwrap()
714                     .get_battery_information(addr)
715                 {
716                     None => println!("Battery status for device {} could not be fetched", address),
717                     Some(set) => {
718                         if set.batteries.len() == 0 {
719                             println!("Battery set for device {} is empty", set.address.to_string());
720                             return Ok(());
721                         }
722 
723                         println!(
724                             "Battery data for '{}' from source '{}' and uuid '{}':",
725                             set.address.to_string(),
726                             set.source_uuid.clone(),
727                             set.source_info.clone()
728                         );
729                         for battery in set.batteries {
730                             println!("   {}%, variant: '{}'", battery.percentage, battery.variant);
731                         }
732                     }
733                 }
734             }
735             "track" => {
736                 if self.lock_context().battery_address_filter.contains(&address) {
737                     println!("Already tracking {}", address);
738                     return Ok(());
739                 }
740                 self.lock_context().battery_address_filter.insert(address);
741 
742                 println!("Currently tracking:");
743                 for addr in self.lock_context().battery_address_filter.iter() {
744                     println!("{}", addr);
745                 }
746             }
747             "untrack" => {
748                 if !self.lock_context().battery_address_filter.remove(&address) {
749                     println!("Not tracking {}", address);
750                     return Ok(());
751                 }
752                 println!("Stopped tracking {}", address);
753 
754                 if self.lock_context().battery_address_filter.len() == 0 {
755                     println!("No longer tracking any addresses for battery status updates");
756                     return Ok(());
757                 }
758 
759                 println!("Currently tracking:");
760                 for addr in self.lock_context().battery_address_filter.iter() {
761                     println!("{}", addr);
762                 }
763             }
764             _ => return Err(CommandError::InvalidArgs),
765         }
766         Ok(())
767     }
768 
cmd_bond(&mut self, args: &Vec<String>) -> CommandResult769     fn cmd_bond(&mut self, args: &Vec<String>) -> CommandResult {
770         if !self.lock_context().adapter_ready {
771             return Err(self.adapter_not_ready());
772         }
773 
774         let command = get_arg(args, 0)?;
775 
776         match &command[..] {
777             "add" => {
778                 let device = BluetoothDevice {
779                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
780                     name: String::from("Classic Device"),
781                 };
782 
783                 let bonding_attempt = &self.lock_context().bonding_attempt.as_ref().cloned();
784 
785                 if bonding_attempt.is_some() {
786                     return Err(format!(
787                         "Already bonding [{}]. Cancel bonding first.",
788                         bonding_attempt.as_ref().unwrap().address.to_string(),
789                     )
790                     .into());
791                 }
792 
793                 let status = self
794                     .lock_context()
795                     .adapter_dbus
796                     .as_mut()
797                     .unwrap()
798                     .create_bond(device.clone(), BtTransport::Auto);
799 
800                 if status == BtStatus::Success {
801                     self.lock_context().bonding_attempt = Some(device);
802                 }
803             }
804             "remove" => {
805                 let device = BluetoothDevice {
806                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
807                     name: String::from("Classic Device"),
808                 };
809 
810                 self.lock_context().adapter_dbus.as_mut().unwrap().remove_bond(device);
811             }
812             "cancel" => {
813                 let device = BluetoothDevice {
814                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
815                     name: String::from("Classic Device"),
816                 };
817 
818                 self.lock_context().adapter_dbus.as_mut().unwrap().cancel_bond_process(device);
819             }
820             other => {
821                 println!("Invalid argument '{}'", other);
822             }
823         }
824 
825         Ok(())
826     }
827 
cmd_device(&mut self, args: &Vec<String>) -> CommandResult828     fn cmd_device(&mut self, args: &Vec<String>) -> CommandResult {
829         if !self.lock_context().adapter_ready {
830             return Err(self.adapter_not_ready());
831         }
832 
833         let command = &get_arg(args, 0)?;
834 
835         match &command[..] {
836             "connect" => {
837                 let device = BluetoothDevice {
838                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
839                     name: String::from("Classic Device"),
840                 };
841 
842                 let status = self
843                     .lock_context()
844                     .adapter_dbus
845                     .as_mut()
846                     .unwrap()
847                     .connect_all_enabled_profiles(device.clone());
848 
849                 if status == BtStatus::Success {
850                     println!("Connecting to {}", &device.address.to_string());
851                 } else {
852                     println!("Can't connect to {}", &device.address.to_string());
853                 }
854             }
855             "disconnect" => {
856                 let device = BluetoothDevice {
857                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
858                     name: String::from("Classic Device"),
859                 };
860 
861                 let success = self
862                     .lock_context()
863                     .adapter_dbus
864                     .as_mut()
865                     .unwrap()
866                     .disconnect_all_enabled_profiles(device.clone());
867 
868                 if success {
869                     println!("Disconnecting from {}", &device.address.to_string());
870                 } else {
871                     println!("Can't disconnect from {}", &device.address.to_string());
872                 }
873             }
874             "info" => {
875                 let device = BluetoothDevice {
876                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
877                     name: String::from("Classic Device"),
878                 };
879 
880                 let (
881                     name,
882                     alias,
883                     device_type,
884                     addr_type,
885                     class,
886                     appearance,
887                     bonded,
888                     connection_state,
889                     uuids,
890                     wake_allowed,
891                     dual_mode_audio,
892                 ) = {
893                     let ctx = self.lock_context();
894                     let adapter = ctx.adapter_dbus.as_ref().unwrap();
895 
896                     let name = adapter.get_remote_name(device.clone());
897                     let device_type = adapter.get_remote_type(device.clone());
898                     let addr_type = adapter.get_remote_address_type(device.clone());
899                     let alias = adapter.get_remote_alias(device.clone());
900                     let class = adapter.get_remote_class(device.clone());
901                     let appearance = adapter.get_remote_appearance(device.clone());
902                     let bonded = adapter.get_bond_state(device.clone());
903                     let connection_state = match adapter.get_connection_state(device.clone()) {
904                         BtConnectionState::NotConnected => "Not Connected",
905                         BtConnectionState::ConnectedOnly => "Connected",
906                         _ => "Connected and Paired",
907                     };
908                     let uuids = adapter.get_remote_uuids(device.clone());
909                     let wake_allowed = adapter.get_remote_wake_allowed(device.clone());
910                     let dual_mode_audio = adapter.is_dual_mode_audio_sink_device(device.clone());
911 
912                     (
913                         name,
914                         alias,
915                         device_type,
916                         addr_type,
917                         class,
918                         appearance,
919                         bonded,
920                         connection_state,
921                         uuids,
922                         wake_allowed,
923                         dual_mode_audio,
924                     )
925                 };
926 
927                 print_info!("Address: {}", &device.address.to_string());
928                 print_info!("Name: {}", name);
929                 print_info!("Alias: {}", alias);
930                 print_info!("Device Type: {:?}", device_type);
931                 print_info!("Address Type: {:?}", addr_type);
932                 print_info!("Class: {}", class);
933                 print_info!("Appearance: {}", appearance);
934                 print_info!("Wake Allowed: {}", wake_allowed);
935                 print_info!("Bond State: {:?}", bonded);
936                 print_info!("Connection State: {}", connection_state);
937                 print_info!("Dual Mode Audio Device: {}", dual_mode_audio);
938                 print_info!(
939                     "Uuids: {}",
940                     DisplayList(
941                         uuids
942                             .iter()
943                             .map(|&x| UuidHelper::known_uuid_to_string(&x))
944                             .collect::<Vec<String>>()
945                     )
946                 );
947             }
948             "set-alias" => {
949                 let new_alias = get_arg(args, 2)?;
950                 let device = BluetoothDevice {
951                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
952                     name: String::from(""),
953                 };
954                 let old_alias = self
955                     .lock_context()
956                     .adapter_dbus
957                     .as_ref()
958                     .unwrap()
959                     .get_remote_alias(device.clone());
960                 println!(
961                     "Updating alias for {}: {} -> {}",
962                     get_arg(args, 1)?,
963                     old_alias,
964                     new_alias
965                 );
966                 self.lock_context()
967                     .adapter_dbus
968                     .as_mut()
969                     .unwrap()
970                     .set_remote_alias(device.clone(), new_alias.clone());
971             }
972             "set-pairing-confirmation" => {
973                 let device = BluetoothDevice {
974                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
975                     name: String::from(""),
976                 };
977                 let accept = match &get_arg(args, 2)?[..] {
978                     "accept" => true,
979                     "reject" => false,
980                     other => {
981                         return Err(format!("Failed to parse '{}'", other).into());
982                     }
983                 };
984 
985                 self.lock_context()
986                     .adapter_dbus
987                     .as_mut()
988                     .unwrap()
989                     .set_pairing_confirmation(device.clone(), accept);
990             }
991             "set-pairing-pin" => {
992                 let device = BluetoothDevice {
993                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
994                     name: String::from(""),
995                 };
996                 let pin = get_arg(args, 2)?;
997 
998                 let (accept, pin) = match (&pin[..], pin) {
999                     ("reject", _) => (false, vec![]),
1000                     (_, p) => (true, p.as_bytes().iter().cloned().collect::<Vec<u8>>()),
1001                 };
1002 
1003                 self.lock_context().adapter_dbus.as_mut().unwrap().set_pin(
1004                     device.clone(),
1005                     accept,
1006                     pin,
1007                 );
1008             }
1009             "set-pairing-passkey" => {
1010                 let device = BluetoothDevice {
1011                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1012                     name: String::from(""),
1013                 };
1014                 let passkey = get_arg(args, 2)?;
1015                 let (accept, passkey) = match (&passkey[..], String::from(passkey).parse::<u32>()) {
1016                     (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())),
1017                     ("reject", _) => (false, vec![]),
1018                     _ => {
1019                         return Err(format!("Failed to parse '{}'", passkey).into());
1020                     }
1021                 };
1022 
1023                 self.lock_context().adapter_dbus.as_mut().unwrap().set_passkey(
1024                     device.clone(),
1025                     accept,
1026                     passkey,
1027                 );
1028             }
1029             "get-rssi" => {
1030                 let device = BluetoothDevice {
1031                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1032                     name: String::from(""),
1033                 };
1034 
1035                 match self
1036                     .lock_context()
1037                     .adapter_dbus
1038                     .as_mut()
1039                     .unwrap()
1040                     .get_remote_rssi(device.clone())
1041                 {
1042                     INVALID_RSSI => {
1043                         println!("Invalid RSSI");
1044                     }
1045                     rssi => {
1046                         println!("RSSI: {}", rssi);
1047                     }
1048                 };
1049             }
1050             other => {
1051                 println!("Invalid argument '{}'", other);
1052             }
1053         }
1054 
1055         Ok(())
1056     }
1057 
cmd_floss(&mut self, args: &Vec<String>) -> CommandResult1058     fn cmd_floss(&mut self, args: &Vec<String>) -> CommandResult {
1059         let command = get_arg(args, 0)?;
1060 
1061         match &command[..] {
1062             "enable" => {
1063                 self.lock_context().manager_dbus.set_floss_enabled(true);
1064             }
1065             "disable" => {
1066                 self.lock_context().manager_dbus.set_floss_enabled(false);
1067             }
1068             "show" => {
1069                 let (major, minor) = self.lock_context().get_floss_api_version();
1070                 print_info!("Floss API version: {}.{}", major, minor);
1071                 print_info!(
1072                     "Floss enabled: {}",
1073                     self.lock_context().manager_dbus.get_floss_enabled()
1074                 );
1075             }
1076             _ => return Err(CommandError::InvalidArgs),
1077         }
1078 
1079         Ok(())
1080     }
1081 
cmd_gatt(&mut self, args: &Vec<String>) -> CommandResult1082     fn cmd_gatt(&mut self, args: &Vec<String>) -> CommandResult {
1083         if !self.lock_context().adapter_ready {
1084             return Err(self.adapter_not_ready());
1085         }
1086 
1087         let command = get_arg(args, 0)?;
1088 
1089         match &command[..] {
1090             "register-client" => {
1091                 let dbus_connection = self.lock_context().dbus_connection.clone();
1092                 let dbus_crossroads = self.lock_context().dbus_crossroads.clone();
1093 
1094                 self.lock_context().gatt_dbus.as_mut().unwrap().register_client(
1095                     String::from(GATT_CLIENT_APP_UUID),
1096                     Box::new(BtGattCallback::new(
1097                         String::from("/org/chromium/bluetooth/client/bluetooth_gatt_callback"),
1098                         self.context.clone(),
1099                         dbus_connection,
1100                         dbus_crossroads,
1101                     )),
1102                     false,
1103                 );
1104             }
1105             "client-connect" => {
1106                 let client_id = self
1107                     .lock_context()
1108                     .gatt_client_context
1109                     .client_id
1110                     .ok_or("GATT client is not yet registered.")?;
1111 
1112                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1113                 let is_direct = self.lock_context().gatt_client_context.is_connect_direct;
1114                 let transport = self.lock_context().gatt_client_context.connect_transport;
1115                 let oppurtunistic = self.lock_context().gatt_client_context.connect_opportunistic;
1116                 let phy = self.lock_context().gatt_client_context.connect_phy;
1117 
1118                 println!("Initiating GATT client connect. client_id: {}, addr: {}, is_direct: {}, transport: {:?}, oppurtunistic: {}, phy: {:?}", client_id, addr.to_string(), is_direct, transport, oppurtunistic, phy);
1119                 self.lock_context().gatt_dbus.as_ref().unwrap().client_connect(
1120                     client_id,
1121                     addr,
1122                     is_direct,
1123                     transport,
1124                     oppurtunistic,
1125                     phy,
1126                 );
1127             }
1128             "client-disconnect" => {
1129                 let client_id = self
1130                     .lock_context()
1131                     .gatt_client_context
1132                     .client_id
1133                     .ok_or("GATT client is not yet registered.")?;
1134 
1135                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1136                 self.lock_context().gatt_dbus.as_ref().unwrap().client_disconnect(client_id, addr);
1137             }
1138             "client-read-phy" => {
1139                 let client_id = self
1140                     .lock_context()
1141                     .gatt_client_context
1142                     .client_id
1143                     .ok_or("GATT client is not yet registered.")?;
1144                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1145                 self.lock_context().gatt_dbus.as_mut().unwrap().client_read_phy(client_id, addr);
1146             }
1147             "client-discover-services" => {
1148                 let client_id = self
1149                     .lock_context()
1150                     .gatt_client_context
1151                     .client_id
1152                     .ok_or("GATT client is not yet registered.")?;
1153 
1154                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1155                 self.lock_context().gatt_dbus.as_ref().unwrap().discover_services(client_id, addr);
1156             }
1157             "client-discover-service-by-uuid-pts" => {
1158                 let client_id = self
1159                     .lock_context()
1160                     .gatt_client_context
1161                     .client_id
1162                     .ok_or("GATT client is not yet registered.")?;
1163                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1164                 let uuid = String::from(get_arg(args, 2)?);
1165                 self.lock_context()
1166                     .gatt_dbus
1167                     .as_ref()
1168                     .unwrap()
1169                     .btif_gattc_discover_service_by_uuid(client_id, addr, uuid);
1170             }
1171             "configure-mtu" => {
1172                 let client_id = self
1173                     .lock_context()
1174                     .gatt_client_context
1175                     .client_id
1176                     .ok_or("GATT client is not yet registered.")?;
1177 
1178                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1179                 let mtu =
1180                     String::from(get_arg(args, 2)?).parse::<i32>().or(Err("Failed parsing mtu"))?;
1181 
1182                 self.lock_context().gatt_dbus.as_ref().unwrap().configure_mtu(client_id, addr, mtu)
1183             }
1184             "set-direct-connect" => {
1185                 let is_direct = String::from(get_arg(args, 1)?)
1186                     .parse::<bool>()
1187                     .or(Err("Failed to parse is_direct"))?;
1188 
1189                 self.lock_context().gatt_client_context.is_connect_direct = is_direct;
1190             }
1191             "set-connect-transport" => {
1192                 let transport = match &get_arg(args, 1)?[..] {
1193                     "Bredr" => BtTransport::Bredr,
1194                     "LE" => BtTransport::Le,
1195                     "Auto" => BtTransport::Auto,
1196                     _ => {
1197                         return Err("Failed to parse transport".into());
1198                     }
1199                 };
1200                 self.lock_context().gatt_client_context.connect_transport = transport;
1201             }
1202             "set-connect-opportunistic" => {
1203                 let opportunistic = String::from(get_arg(args, 1)?)
1204                     .parse::<bool>()
1205                     .or(Err("Failed to parse opportunistic"))?;
1206 
1207                 self.lock_context().gatt_client_context.connect_opportunistic = opportunistic;
1208             }
1209             "set-connect-phy" => {
1210                 let phy = match &get_arg(args, 1)?[..] {
1211                     "Phy1m" => LePhy::Phy1m,
1212                     "Phy2m" => LePhy::Phy2m,
1213                     "PhyCoded" => LePhy::PhyCoded,
1214                     _ => {
1215                         return Err("Failed to parse phy".into());
1216                     }
1217                 };
1218 
1219                 self.lock_context().gatt_client_context.connect_phy = phy;
1220             }
1221             "set-auth-req" => {
1222                 let flag = match &get_arg(args, 1)?[..] {
1223                     "NONE" => AuthReq::NONE,
1224                     "EncNoMitm" => AuthReq::EncNoMitm,
1225                     "EncMitm" => AuthReq::EncMitm,
1226                     "SignedNoMitm" => AuthReq::SignedNoMitm,
1227                     "SignedMitm" => AuthReq::SignedMitm,
1228                     _ => {
1229                         return Err("Failed to parse auth-req".into());
1230                     }
1231                 };
1232 
1233                 self.lock_context().gatt_client_context.auth_req = flag;
1234                 println!("AuthReq: {:?}", self.lock_context().gatt_client_context.get_auth_req());
1235             }
1236             "write-characteristic" => {
1237                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1238                 let handle = String::from(get_arg(args, 2)?)
1239                     .parse::<i32>()
1240                     .or(Err("Failed to parse handle"))?;
1241 
1242                 let write_type = match &get_arg(args, 3)?[..] {
1243                     "NoRsp" => GattWriteType::WriteNoRsp,
1244                     "Write" => GattWriteType::Write,
1245                     "Prepare" => GattWriteType::WritePrepare,
1246                     _ => {
1247                         return Err("Failed to parse write-type".into());
1248                     }
1249                 };
1250 
1251                 let value = hex::decode(&get_arg(args, 4)?).or(Err("Failed to parse value"))?;
1252 
1253                 let client_id = self
1254                     .lock_context()
1255                     .gatt_client_context
1256                     .client_id
1257                     .ok_or("GATT client is not yet registered.")?;
1258 
1259                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1260 
1261                 self.lock_context()
1262                     .gatt_dbus
1263                     .as_ref()
1264                     .unwrap()
1265                     .write_characteristic(client_id, addr, handle, write_type, auth_req, value);
1266             }
1267             "read-characteristic" => {
1268                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1269                 let handle = String::from(get_arg(args, 2)?)
1270                     .parse::<i32>()
1271                     .or(Err("Failed to parse handle"))?;
1272                 let client_id = self
1273                     .lock_context()
1274                     .gatt_client_context
1275                     .client_id
1276                     .ok_or("GATT client is not yet registered.")?;
1277 
1278                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1279 
1280                 self.lock_context()
1281                     .gatt_dbus
1282                     .as_ref()
1283                     .unwrap()
1284                     .read_characteristic(client_id, addr, handle, auth_req);
1285             }
1286             "read-characteristic-by-uuid" => {
1287                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1288                 let uuid = String::from(get_arg(args, 2)?);
1289                 let start_handle = String::from(get_arg(args, 3)?)
1290                     .parse::<i32>()
1291                     .or(Err("Failed to parse start handle"))?;
1292                 let end_handle = String::from(get_arg(args, 4)?)
1293                     .parse::<i32>()
1294                     .or(Err("Failed to parse end handle"))?;
1295 
1296                 let client_id = self
1297                     .lock_context()
1298                     .gatt_client_context
1299                     .client_id
1300                     .ok_or("GATT client is not yet registered.")?;
1301 
1302                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1303 
1304                 self.lock_context().gatt_dbus.as_ref().unwrap().read_using_characteristic_uuid(
1305                     client_id,
1306                     addr,
1307                     uuid,
1308                     start_handle,
1309                     end_handle,
1310                     auth_req,
1311                 );
1312             }
1313             "register-notification" => {
1314                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1315                 let handle = String::from(get_arg(args, 2)?)
1316                     .parse::<i32>()
1317                     .or(Err("Failed to parse handle"))?;
1318                 let enable = match &get_arg(args, 3)?[..] {
1319                     "enable" => true,
1320                     "disable" => false,
1321                     _ => {
1322                         return Err("Failed to parse enable".into());
1323                     }
1324                 };
1325 
1326                 let client_id = self
1327                     .lock_context()
1328                     .gatt_client_context
1329                     .client_id
1330                     .ok_or("GATT client is not yet registered.")?;
1331 
1332                 self.lock_context()
1333                     .gatt_dbus
1334                     .as_ref()
1335                     .unwrap()
1336                     .register_for_notification(client_id, addr, handle, enable);
1337             }
1338             "register-server" => {
1339                 let dbus_connection = self.lock_context().dbus_connection.clone();
1340                 let dbus_crossroads = self.lock_context().dbus_crossroads.clone();
1341 
1342                 self.lock_context().gatt_dbus.as_mut().unwrap().register_server(
1343                     String::from(GATT_SERVER_APP_UUID),
1344                     Box::new(BtGattServerCallback::new(
1345                         String::from(
1346                             "/org/chromium/bluetooth/client/bluetooth_gatt_server_callback",
1347                         ),
1348                         self.context.clone(),
1349                         dbus_connection,
1350                         dbus_crossroads,
1351                     )),
1352                     false,
1353                 );
1354             }
1355             "unregister-server" => {
1356                 let server_id = String::from(get_arg(args, 1)?)
1357                     .parse::<i32>()
1358                     .or(Err("Failed parsing server id"))?;
1359 
1360                 self.lock_context().gatt_dbus.as_mut().unwrap().unregister_server(server_id);
1361             }
1362             "server-connect" => {
1363                 let server_id = String::from(get_arg(args, 1)?)
1364                     .parse::<i32>()
1365                     .or(Err("Failed to parse server_id"))?;
1366                 let client_addr =
1367                     RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1368                 let is_direct = self.lock_context().gatt_server_context.is_connect_direct;
1369                 let transport = self.lock_context().gatt_server_context.connect_transport;
1370 
1371                 if !self.lock_context().gatt_dbus.as_mut().unwrap().server_connect(
1372                     server_id,
1373                     client_addr,
1374                     is_direct,
1375                     transport,
1376                 ) {
1377                     return Err("Connection was unsuccessful".into());
1378                 }
1379             }
1380             "server-disconnect" => {
1381                 let server_id = String::from(get_arg(args, 1)?)
1382                     .parse::<i32>()
1383                     .or(Err("Failed to parse server_id"))?;
1384                 let client_addr =
1385                     RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1386 
1387                 if !self
1388                     .lock_context()
1389                     .gatt_dbus
1390                     .as_mut()
1391                     .unwrap()
1392                     .server_disconnect(server_id, client_addr)
1393                 {
1394                     return Err("Disconnection was unsuccessful".into());
1395                 }
1396             }
1397             "server-add-basic-service" => {
1398                 let service_uuid = Uuid::from_string(BATTERY_SERVICE_UUID).unwrap();
1399 
1400                 let server_id = String::from(get_arg(args, 1)?)
1401                     .parse::<i32>()
1402                     .or(Err("Failed to parse server_id"))?;
1403 
1404                 let service = BluetoothGattService::new(
1405                     service_uuid,
1406                     0, // libbluetooth assigns this handle once the service is added
1407                     GattDbElementType::PrimaryService.into(),
1408                 );
1409 
1410                 self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
1411             }
1412             "server-add-service" => {
1413                 let service_uuid = Uuid::from_string(HEART_RATE_SERVICE_UUID).unwrap();
1414                 let characteristic_uuid = Uuid::from_string(HEART_RATE_MEASUREMENT_UUID).unwrap();
1415                 let descriptor_uuid = Uuid::from_string(GENERIC_UUID).unwrap();
1416                 let ccc_descriptor_uuid = Uuid::from_string(CCC_DESCRIPTOR_UUID).unwrap();
1417                 let included_service_uuid = Uuid::from_string(BATTERY_SERVICE_UUID).unwrap();
1418 
1419                 let server_id = String::from(get_arg(args, 1)?)
1420                     .parse::<i32>()
1421                     .or(Err("Failed to parse server_id"))?;
1422                 let included_service_instance_id =
1423                     String::from(get_arg(args, 2)?)
1424                         .parse::<i32>()
1425                         .or(Err("Failed to parse included service instance id"))?;
1426 
1427                 let mut service = BluetoothGattService::new(
1428                     service_uuid,
1429                     0,
1430                     GattDbElementType::PrimaryService.into(),
1431                 );
1432                 let included_service = BluetoothGattService::new(
1433                     included_service_uuid,
1434                     included_service_instance_id,
1435                     GattDbElementType::IncludedService.into(),
1436                 );
1437                 let mut characteristic = BluetoothGattCharacteristic::new(
1438                     characteristic_uuid,
1439                     0,
1440                     BluetoothGattCharacteristic::PROPERTY_READ
1441                         | BluetoothGattCharacteristic::PROPERTY_WRITE
1442                         | BluetoothGattCharacteristic::PROPERTY_NOTIFY,
1443                     BluetoothGattCharacteristic::PERMISSION_READ
1444                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1445                 );
1446                 let descriptor = BluetoothGattDescriptor::new(
1447                     descriptor_uuid,
1448                     0,
1449                     BluetoothGattCharacteristic::PERMISSION_READ
1450                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1451                 );
1452                 let ccc_descriptor = BluetoothGattDescriptor::new(
1453                     ccc_descriptor_uuid,
1454                     0,
1455                     BluetoothGattCharacteristic::PERMISSION_READ
1456                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1457                 );
1458 
1459                 service.included_services.push(included_service);
1460                 characteristic.descriptors.push(ccc_descriptor);
1461                 characteristic.descriptors.push(descriptor);
1462                 service.characteristics.push(characteristic);
1463 
1464                 self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
1465             }
1466             "server-remove-service" => {
1467                 let server_id = String::from(get_arg(args, 1)?)
1468                     .parse::<i32>()
1469                     .or(Err("Failed to parse server_id"))?;
1470                 let service_handle = String::from(get_arg(args, 1)?)
1471                     .parse::<i32>()
1472                     .or(Err("Failed to parse service handle"))?;
1473 
1474                 self.lock_context()
1475                     .gatt_dbus
1476                     .as_mut()
1477                     .unwrap()
1478                     .remove_service(server_id, service_handle);
1479             }
1480             "server-clear-all-services" => {
1481                 let server_id = String::from(get_arg(args, 1)?)
1482                     .parse::<i32>()
1483                     .or(Err("Failed to parse server_id"))?;
1484                 self.lock_context().gatt_dbus.as_mut().unwrap().clear_services(server_id);
1485             }
1486             "server-send-response" => {
1487                 let server_id = String::from(get_arg(args, 1)?)
1488                     .parse::<i32>()
1489                     .or(Err("Failed to parse server_id"))?;
1490                 let status = match String::from(get_arg(args, 2)?).as_str() {
1491                     "success" => GattStatus::Success,
1492                     "fail" => GattStatus::Error,
1493                     _ => return Err("{} is not one of the following: `success`, `fail`".into()),
1494                 };
1495 
1496                 let request = match self.lock_context().pending_gatt_request.clone() {
1497                     None => return Err("No pending request to send response to".into()),
1498                     Some(r) => r,
1499                 };
1500                 self.lock_context().gatt_dbus.as_mut().unwrap().send_response(
1501                     server_id,
1502                     request.address.clone(),
1503                     request.id,
1504                     status,
1505                     request.offset,
1506                     request.value.clone(),
1507                 );
1508 
1509                 self.lock_context().pending_gatt_request = None;
1510             }
1511             "server-set-direct-connect" => {
1512                 let is_direct = String::from(get_arg(args, 1)?)
1513                     .parse::<bool>()
1514                     .or(Err("Failed to parse is_direct"))?;
1515 
1516                 self.lock_context().gatt_server_context.is_connect_direct = is_direct;
1517             }
1518             "server-set-connect-transport" => {
1519                 let transport = match &get_arg(args, 1)?[..] {
1520                     "Bredr" => BtTransport::Bredr,
1521                     "LE" => BtTransport::Le,
1522                     "Auto" => BtTransport::Auto,
1523                     _ => {
1524                         return Err("Failed to parse transport".into());
1525                     }
1526                 };
1527                 self.lock_context().gatt_server_context.connect_transport = transport;
1528             }
1529             _ => return Err(CommandError::InvalidArgs),
1530         }
1531         Ok(())
1532     }
1533 
cmd_le_scan(&mut self, args: &Vec<String>) -> CommandResult1534     fn cmd_le_scan(&mut self, args: &Vec<String>) -> CommandResult {
1535         if !self.lock_context().adapter_ready {
1536             return Err(self.adapter_not_ready());
1537         }
1538 
1539         let command = get_arg(args, 0)?;
1540 
1541         match &command[..] {
1542             "register-scanner" => {
1543                 let scanner_callback_id = self
1544                     .lock_context()
1545                     .scanner_callback_id
1546                     .ok_or("Cannot register scanner before registering scanner callback")?;
1547 
1548                 let uuid = self
1549                     .lock_context()
1550                     .gatt_dbus
1551                     .as_mut()
1552                     .unwrap()
1553                     .register_scanner(scanner_callback_id);
1554 
1555                 print_info!("Scanner to be registered with UUID = {}", uuid);
1556             }
1557             "unregister-scanner" => {
1558                 let scanner_id = String::from(get_arg(args, 1)?)
1559                     .parse::<u8>()
1560                     .or(Err("Failed parsing scanner id"))?;
1561 
1562                 self.lock_context().gatt_dbus.as_mut().unwrap().unregister_scanner(scanner_id);
1563             }
1564             "start-scan" => {
1565                 let scanner_id = String::from(get_arg(args, 1)?)
1566                     .parse::<u8>()
1567                     .or(Err("Failed parsing scanner id"))?;
1568 
1569                 self.lock_context().gatt_dbus.as_mut().unwrap().start_scan(
1570                     scanner_id,
1571                     // TODO(b/254870159): Construct real settings and filters depending on
1572                     // command line options.
1573                     None,
1574                     Some(btstack::bluetooth_gatt::ScanFilter {
1575                         rssi_high_threshold: 0,
1576                         rssi_low_threshold: 0,
1577                         rssi_low_timeout: 0,
1578                         rssi_sampling_period: 0,
1579                         condition: btstack::bluetooth_gatt::ScanFilterCondition::Patterns(vec![]),
1580                     }),
1581                 );
1582 
1583                 self.lock_context().active_scanner_ids.insert(scanner_id);
1584             }
1585             "stop-scan" => {
1586                 let scanner_id = String::from(get_arg(args, 1)?)
1587                     .parse::<u8>()
1588                     .or(Err("Failed parsing scanner id"))?;
1589 
1590                 self.lock_context().gatt_dbus.as_mut().unwrap().stop_scan(scanner_id);
1591                 self.lock_context().active_scanner_ids.remove(&scanner_id);
1592             }
1593             _ => return Err(CommandError::InvalidArgs),
1594         }
1595 
1596         Ok(())
1597     }
1598 
1599     // TODO(b/233128828): More options will be implemented to test BLE advertising.
1600     // Such as setting advertising parameters, starting multiple advertising sets, etc.
cmd_advertise(&mut self, args: &Vec<String>) -> CommandResult1601     fn cmd_advertise(&mut self, args: &Vec<String>) -> CommandResult {
1602         if !self.lock_context().adapter_ready {
1603             return Err(self.adapter_not_ready());
1604         }
1605 
1606         if self.lock_context().advertiser_callback_id == None {
1607             return Err("No advertiser callback registered".into());
1608         }
1609 
1610         let callback_id = self.lock_context().advertiser_callback_id.clone().unwrap();
1611 
1612         let command = get_arg(args, 0)?;
1613 
1614         match &command[..] {
1615             "on" => {
1616                 print_info!("Creating legacy advertising set...");
1617                 let s = AdvSet::new(true); // legacy advertising
1618                 AdvSet::start(self.context.clone(), s, callback_id);
1619             }
1620             "off" => {
1621                 AdvSet::stop_all(self.context.clone());
1622             }
1623             "ext" => {
1624                 print_info!("Creating extended advertising set...");
1625                 let s = AdvSet::new(false); // extended advertising
1626                 AdvSet::start(self.context.clone(), s, callback_id);
1627             }
1628             "set-interval" => {
1629                 let ms = String::from(get_arg(args, 1)?).parse::<i32>();
1630                 if !ms.is_ok() {
1631                     return Err("Failed parsing interval".into());
1632                 }
1633                 let interval = ms.unwrap() * 8 / 5; // in 0.625 ms.
1634 
1635                 let mut context = self.lock_context();
1636                 context.adv_sets.iter_mut().for_each(|(_, s)| s.params.interval = interval);
1637 
1638                 // To avoid borrowing context as mutable from an immutable borrow.
1639                 // Required information is collected in advance and then passed
1640                 // to the D-Bus call which requires a mutable borrow.
1641                 let advs: Vec<(_, _)> = context
1642                     .adv_sets
1643                     .iter()
1644                     .filter_map(|(_, s)| s.adv_id.map(|adv_id| (adv_id.clone(), s.params.clone())))
1645                     .collect();
1646                 for (adv_id, params) in advs {
1647                     print_info!("Setting advertising parameters for {}", adv_id);
1648                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1649                 }
1650             }
1651             "set-connectable" => {
1652                 let connectable = match &get_arg(args, 1)?[..] {
1653                     "on" => true,
1654                     "off" => false,
1655                     _ => false,
1656                 };
1657 
1658                 let adv_id = String::from(get_arg(args, 2)?)
1659                     .parse::<i32>()
1660                     .or(Err("Failed parsing adv_id"))?;
1661 
1662                 let mut context = self.context.lock().unwrap();
1663 
1664                 let advs: Vec<(_, _)> = context
1665                     .adv_sets
1666                     .iter_mut()
1667                     .filter_map(|(_, s)| {
1668                         if !(s.adv_id.map_or(false, |id| id == adv_id)) {
1669                             return None;
1670                         }
1671                         s.params.connectable = connectable;
1672                         Some((s.params.clone(), s.data.clone()))
1673                     })
1674                     .collect();
1675 
1676                 for (params, data) in advs {
1677                     print_info!("Setting advertising parameters for {}", adv_id);
1678                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1679 
1680                     // renew the flags
1681                     print_info!("Setting advertising data for {}", adv_id);
1682                     context.gatt_dbus.as_mut().unwrap().set_advertising_data(adv_id, data);
1683                 }
1684             }
1685             "set-scan-rsp" => {
1686                 let enable = match &get_arg(args, 1)?[..] {
1687                     "enable" => true,
1688                     "disable" => false,
1689                     _ => false,
1690                 };
1691 
1692                 let mut context = self.lock_context();
1693                 context.adv_sets.iter_mut().for_each(|(_, s)| s.params.scannable = enable);
1694 
1695                 let advs: Vec<(_, _, _)> = context
1696                     .adv_sets
1697                     .iter()
1698                     .filter_map(|(_, s)| {
1699                         s.adv_id
1700                             .map(|adv_id| (adv_id.clone(), s.params.clone(), s.scan_rsp.clone()))
1701                     })
1702                     .collect();
1703                 for (adv_id, params, scan_rsp) in advs {
1704                     print_info!("Setting scan response data for {}", adv_id);
1705                     context.gatt_dbus.as_mut().unwrap().set_scan_response_data(adv_id, scan_rsp);
1706                     print_info!("Setting parameters for {}", adv_id);
1707                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1708                 }
1709             }
1710             "set-raw-data" => {
1711                 let data = hex::decode(get_arg(args, 1)?).or(Err("Failed parsing data"))?;
1712 
1713                 let adv_id = String::from(get_arg(args, 2)?)
1714                     .parse::<i32>()
1715                     .or(Err("Failed parsing adv_id"))?;
1716 
1717                 let mut context = self.context.lock().unwrap();
1718                 if context
1719                     .adv_sets
1720                     .iter()
1721                     .find(|(_, s)| s.adv_id.map_or(false, |id| id == adv_id))
1722                     .is_none()
1723                 {
1724                     return Err("Failed to find advertising set".into());
1725                 }
1726 
1727                 print_info!("Setting advertising data for {}", adv_id);
1728                 context.gatt_dbus.as_mut().unwrap().set_raw_adv_data(adv_id, data);
1729             }
1730             _ => return Err(CommandError::InvalidArgs),
1731         }
1732 
1733         Ok(())
1734     }
1735 
cmd_sdp(&mut self, args: &Vec<String>) -> CommandResult1736     fn cmd_sdp(&mut self, args: &Vec<String>) -> CommandResult {
1737         if !self.lock_context().adapter_ready {
1738             return Err(self.adapter_not_ready());
1739         }
1740 
1741         let command = get_arg(args, 0)?;
1742 
1743         match &command[..] {
1744             "search" => {
1745                 let device = BluetoothDevice {
1746                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1747                     name: String::from(""),
1748                 };
1749                 let uuid = Uuid::from_string(get_arg(args, 2)?).ok_or("Invalid UUID")?;
1750                 let success =
1751                     self.lock_context().adapter_dbus.as_ref().unwrap().sdp_search(device, uuid);
1752                 if !success {
1753                     return Err("Unable to execute SDP search".into());
1754                 }
1755             }
1756             _ => return Err(CommandError::InvalidArgs),
1757         }
1758         Ok(())
1759     }
1760 
cmd_socket(&mut self, args: &Vec<String>) -> CommandResult1761     fn cmd_socket(&mut self, args: &Vec<String>) -> CommandResult {
1762         if !self.lock_context().adapter_ready {
1763             return Err(self.adapter_not_ready());
1764         }
1765 
1766         let callback_id = match self.lock_context().socket_manager_callback_id.clone() {
1767             Some(id) => id,
1768             None => {
1769                 return Err("No socket manager callback registered.".into());
1770             }
1771         };
1772 
1773         let command = get_arg(args, 0)?;
1774 
1775         match &command[..] {
1776             "set-on-connect-schedule" => {
1777                 let schedule = match &get_arg(args, 1)?[..] {
1778                     "send" => SocketSchedule {
1779                         num_frame: 1,
1780                         send_interval: Duration::from_millis(0),
1781                         disconnect_delay: Duration::from_secs(30),
1782                     },
1783                     "resend" => SocketSchedule {
1784                         num_frame: 3,
1785                         send_interval: Duration::from_millis(100),
1786                         disconnect_delay: Duration::from_secs(30),
1787                     },
1788                     "dump" => SocketSchedule {
1789                         num_frame: 0,
1790                         send_interval: Duration::from_millis(0),
1791                         disconnect_delay: Duration::from_secs(30),
1792                     },
1793                     _ => {
1794                         return Err("Failed to parse schedule".into());
1795                     }
1796                 };
1797 
1798                 self.context.lock().unwrap().socket_test_schedule = Some(schedule);
1799             }
1800             "send-msc" => {
1801                 let dlci =
1802                     String::from(get_arg(args, 1)?).parse::<u8>().or(Err("Failed parsing DLCI"))?;
1803                 let addr = RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1804                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().rfcomm_send_msc(dlci, addr);
1805             }
1806             "listen-rfcomm" => {
1807                 let scn = String::from(get_arg(args, 1)?)
1808                     .parse::<i32>()
1809                     .or(Err("Failed parsing Service Channel Number"))?;
1810                 let SocketResult { status, id } = self
1811                     .context
1812                     .lock()
1813                     .unwrap()
1814                     .socket_manager_dbus
1815                     .as_mut()
1816                     .unwrap()
1817                     .listen_using_rfcomm(callback_id, Some(scn), None, None, None);
1818                 if status != BtStatus::Success {
1819                     return Err(format!(
1820                         "Failed to request for listening using rfcomm, status = {:?}",
1821                         status,
1822                     )
1823                     .into());
1824                 }
1825                 print_info!("Requested for listening using rfcomm on socket {}", id);
1826             }
1827             "listen" => {
1828                 let auth_required = String::from(get_arg(args, 1)?)
1829                     .parse::<bool>()
1830                     .or(Err("Failed to parse auth-required"))?;
1831                 let is_le = match &get_arg(args, 2)?[..] {
1832                     "LE" => true,
1833                     "Bredr" => false,
1834                     _ => {
1835                         return Err("Failed to parse socket type".into());
1836                     }
1837                 };
1838 
1839                 let SocketResult { status, id } = {
1840                     let mut context_proxy = self.context.lock().unwrap();
1841                     let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();
1842                     if auth_required {
1843                         if is_le {
1844                             proxy.listen_using_l2cap_le_channel(callback_id)
1845                         } else {
1846                             proxy.listen_using_l2cap_channel(callback_id)
1847                         }
1848                     } else {
1849                         if is_le {
1850                             proxy.listen_using_insecure_l2cap_le_channel(callback_id)
1851                         } else {
1852                             proxy.listen_using_insecure_l2cap_channel(callback_id)
1853                         }
1854                     }
1855                 };
1856 
1857                 if status != BtStatus::Success {
1858                     return Err(format!(
1859                         "Failed to request for listening using l2cap channel, status = {:?}",
1860                         status,
1861                     )
1862                     .into());
1863                 }
1864                 print_info!("Requested for listening using l2cap channel on socket {}", id);
1865             }
1866             "connect" => {
1867                 let (addr, sock_type, psm_or_uuid) =
1868                     (&get_arg(args, 1)?, &get_arg(args, 2)?, &get_arg(args, 3)?);
1869                 let device = BluetoothDevice {
1870                     address: RawAddress::from_string(*addr).ok_or("Invalid Address")?,
1871                     name: String::from("Socket Connect Device"),
1872                 };
1873 
1874                 let auth_required = String::from(get_arg(args, 4)?)
1875                     .parse::<bool>()
1876                     .or(Err("Failed to parse auth-required"))?;
1877 
1878                 let is_le = match &get_arg(args, 5)?[..] {
1879                     "LE" => true,
1880                     "Bredr" => false,
1881                     _ => {
1882                         return Err("Failed to parse socket type".into());
1883                     }
1884                 };
1885 
1886                 let SocketResult { status, id } = {
1887                     let mut context_proxy = self.context.lock().unwrap();
1888                     let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();
1889 
1890                     match &sock_type[0..] {
1891                         "l2cap" => {
1892                             let psm = match psm_or_uuid.parse::<i32>() {
1893                                 Ok(v) => v,
1894                                 Err(e) => {
1895                                     return Err(CommandError::Failed(format!(
1896                                         "Bad PSM given. Error={}",
1897                                         e
1898                                     )));
1899                                 }
1900                             };
1901 
1902                             if auth_required {
1903                                 if is_le {
1904                                     proxy.create_l2cap_le_channel(callback_id, device, psm)
1905                                 } else {
1906                                     proxy.create_l2cap_channel(callback_id, device, psm)
1907                                 }
1908                             } else {
1909                                 if is_le {
1910                                     proxy.create_insecure_l2cap_le_channel(callback_id, device, psm)
1911                                 } else {
1912                                     proxy.create_insecure_l2cap_channel(callback_id, device, psm)
1913                                 }
1914                             }
1915                         }
1916                         "rfcomm" => {
1917                             let uuid = match Uuid::from_string(*psm_or_uuid) {
1918                                 Some(uu) => uu,
1919                                 None => {
1920                                     return Err(CommandError::Failed(format!(
1921                                         "Could not parse given uuid."
1922                                     )));
1923                                 }
1924                             };
1925 
1926                             if auth_required {
1927                                 proxy.create_rfcomm_socket_to_service_record(
1928                                     callback_id,
1929                                     device,
1930                                     uuid,
1931                                 )
1932                             } else {
1933                                 proxy.create_insecure_rfcomm_socket_to_service_record(
1934                                     callback_id,
1935                                     device,
1936                                     uuid,
1937                                 )
1938                             }
1939                         }
1940                         _ => {
1941                             return Err(CommandError::Failed(format!(
1942                                 "Unknown socket type: {}",
1943                                 sock_type
1944                             )));
1945                         }
1946                     }
1947                 };
1948 
1949                 if status != BtStatus::Success {
1950                     return Err(CommandError::Failed(format!("Failed to create socket with status={:?} against {}, type {}, with psm/uuid {}",
1951                         status, addr, sock_type, psm_or_uuid)));
1952                 } else {
1953                     print_info!("Called create socket with result ({:?}, {}) against {}, type {}, with psm/uuid {}",
1954                     status, id, addr, sock_type, psm_or_uuid);
1955                 }
1956             }
1957             "close" => {
1958                 let sockid = String::from(get_arg(args, 1)?)
1959                     .parse::<u64>()
1960                     .or(Err("Failed parsing socket ID"))?;
1961                 let status = self
1962                     .context
1963                     .lock()
1964                     .unwrap()
1965                     .socket_manager_dbus
1966                     .as_mut()
1967                     .unwrap()
1968                     .close(callback_id, sockid);
1969                 if status != BtStatus::Success {
1970                     return Err(format!(
1971                         "Failed to close the listening socket, status = {:?}",
1972                         status,
1973                     )
1974                     .into());
1975                 }
1976             }
1977 
1978             _ => return Err(CommandError::InvalidArgs),
1979         };
1980 
1981         Ok(())
1982     }
1983 
cmd_hid(&mut self, args: &Vec<String>) -> CommandResult1984     fn cmd_hid(&mut self, args: &Vec<String>) -> CommandResult {
1985         if !self.context.lock().unwrap().adapter_ready {
1986             return Err(self.adapter_not_ready());
1987         }
1988 
1989         let command = get_arg(args, 0)?;
1990 
1991         match &command[..] {
1992             "get-report" => {
1993                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1994                 let report_type = match &get_arg(args, 2)?[..] {
1995                     "Input" => BthhReportType::InputReport,
1996                     "Output" => BthhReportType::OutputReport,
1997                     "Feature" => BthhReportType::FeatureReport,
1998                     _ => {
1999                         return Err("Failed to parse report type".into());
2000                     }
2001                 };
2002                 let report_id = String::from(get_arg(args, 3)?)
2003                     .parse::<u8>()
2004                     .or(Err("Failed parsing report_id"))?;
2005 
2006                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().get_hid_report(
2007                     addr,
2008                     report_type,
2009                     report_id,
2010                 );
2011             }
2012             "set-report" => {
2013                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2014                 let report_type = match &get_arg(args, 2)?[..] {
2015                     "Input" => BthhReportType::InputReport,
2016                     "Output" => BthhReportType::OutputReport,
2017                     "Feature" => BthhReportType::FeatureReport,
2018                     _ => {
2019                         return Err("Failed to parse report type".into());
2020                     }
2021                 };
2022                 let report_value = String::from(get_arg(args, 3)?);
2023 
2024                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().set_hid_report(
2025                     addr,
2026                     report_type,
2027                     report_value,
2028                 );
2029             }
2030             "send-data" => {
2031                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2032                 let data = String::from(get_arg(args, 2)?);
2033 
2034                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().send_hid_data(addr, data);
2035             }
2036             _ => return Err(CommandError::InvalidArgs),
2037         };
2038 
2039         Ok(())
2040     }
2041 
2042     /// Get the list of rules of supported commands
get_command_rule_list(&self) -> Vec<String>2043     pub fn get_command_rule_list(&self) -> Vec<String> {
2044         self.command_options.values().flat_map(|cmd| cmd.rules.clone()).collect()
2045     }
2046 
cmd_list_devices(&mut self, args: &Vec<String>) -> CommandResult2047     fn cmd_list_devices(&mut self, args: &Vec<String>) -> CommandResult {
2048         if !self.lock_context().adapter_ready {
2049             return Err(self.adapter_not_ready());
2050         }
2051 
2052         let command = get_arg(args, 0)?;
2053 
2054         match &command[..] {
2055             "bonded" => {
2056                 print_info!("Known bonded devices:");
2057                 let devices =
2058                     self.lock_context().adapter_dbus.as_ref().unwrap().get_bonded_devices();
2059                 for device in devices.iter() {
2060                     print_info!("[{}] {}", device.address.to_string(), device.name);
2061                 }
2062             }
2063             "found" => {
2064                 print_info!("Devices found in most recent discovery session:");
2065                 for (key, val) in self.lock_context().found_devices.iter() {
2066                     print_info!("[{:17}] {}", key, val.name);
2067                 }
2068             }
2069             "connected" => {
2070                 print_info!("Connected devices:");
2071                 let devices =
2072                     self.lock_context().adapter_dbus.as_ref().unwrap().get_connected_devices();
2073                 for device in devices.iter() {
2074                     print_info!("[{}] {}", device.address.to_string(), device.name);
2075                 }
2076             }
2077             other => {
2078                 println!("Invalid argument '{}'", other);
2079             }
2080         }
2081 
2082         Ok(())
2083     }
2084 
cmd_telephony(&mut self, args: &Vec<String>) -> CommandResult2085     fn cmd_telephony(&mut self, args: &Vec<String>) -> CommandResult {
2086         if !self.context.lock().unwrap().adapter_ready {
2087             return Err(self.adapter_not_ready());
2088         }
2089 
2090         match &get_arg(args, 0)?[..] {
2091             "set-network" => {
2092                 self.context
2093                     .lock()
2094                     .unwrap()
2095                     .telephony_dbus
2096                     .as_mut()
2097                     .unwrap()
2098                     .set_network_available(match &get_arg(args, 1)?[..] {
2099                         "on" => true,
2100                         "off" => false,
2101                         other => {
2102                             return Err(format!("Invalid argument '{}'", other).into());
2103                         }
2104                     });
2105             }
2106             "set-roaming" => {
2107                 self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().set_roaming(
2108                     match &get_arg(args, 1)?[..] {
2109                         "on" => true,
2110                         "off" => false,
2111                         other => {
2112                             return Err(format!("Invalid argument '{}'", other).into());
2113                         }
2114                     },
2115                 );
2116             }
2117             "set-signal" => {
2118                 let strength = String::from(get_arg(args, 1)?)
2119                     .parse::<i32>()
2120                     .or(Err("Failed parsing signal strength"))?;
2121                 if strength < 0 || strength > 5 {
2122                     return Err(
2123                         format!("Invalid signal strength, got {}, want 0 to 5", strength).into()
2124                     );
2125                 }
2126                 self.context
2127                     .lock()
2128                     .unwrap()
2129                     .telephony_dbus
2130                     .as_mut()
2131                     .unwrap()
2132                     .set_signal_strength(strength);
2133             }
2134             "set-battery" => {
2135                 let level = String::from(get_arg(args, 1)?)
2136                     .parse::<i32>()
2137                     .or(Err("Failed parsing battery level"))?;
2138                 if level < 0 || level > 5 {
2139                     return Err(format!("Invalid battery level, got {}, want 0 to 5", level).into());
2140                 }
2141                 self.context
2142                     .lock()
2143                     .unwrap()
2144                     .telephony_dbus
2145                     .as_mut()
2146                     .unwrap()
2147                     .set_battery_level(level);
2148             }
2149             "enable" => {
2150                 let mut context = self.lock_context();
2151                 context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(true);
2152                 if context.mps_sdp_handle.is_none() {
2153                     let success = context
2154                         .adapter_dbus
2155                         .as_mut()
2156                         .unwrap()
2157                         .create_sdp_record(BtSdpRecord::Mps(BtSdpMpsRecord::default()));
2158                     if !success {
2159                         return Err(format!("Failed to create SDP record").into());
2160                     }
2161                 }
2162             }
2163             "disable" => {
2164                 let mut context = self.lock_context();
2165                 context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(false);
2166                 if let Some(handle) = context.mps_sdp_handle.take() {
2167                     let success = context.adapter_dbus.as_mut().unwrap().remove_sdp_record(handle);
2168                     if !success {
2169                         return Err(format!("Failed to remove SDP record").into());
2170                     }
2171                 }
2172             }
2173             "set-phone-ops" => {
2174                 let on_or_off = match &get_arg(args, 1)?[..] {
2175                     "on" => true,
2176                     "off" => false,
2177                     _ => {
2178                         return Err("Failed to parse on|off".into());
2179                     }
2180                 };
2181                 self.context
2182                     .lock()
2183                     .unwrap()
2184                     .telephony_dbus
2185                     .as_mut()
2186                     .unwrap()
2187                     .set_phone_ops_enabled(on_or_off);
2188             }
2189             "incoming-call" => {
2190                 let success = self
2191                     .context
2192                     .lock()
2193                     .unwrap()
2194                     .telephony_dbus
2195                     .as_mut()
2196                     .unwrap()
2197                     .incoming_call(String::from(get_arg(args, 1)?));
2198                 if !success {
2199                     return Err("IncomingCall failed".into());
2200                 }
2201             }
2202             "dialing-call" => {
2203                 let success = self
2204                     .context
2205                     .lock()
2206                     .unwrap()
2207                     .telephony_dbus
2208                     .as_mut()
2209                     .unwrap()
2210                     .dialing_call(String::from(get_arg(args, 1)?));
2211                 if !success {
2212                     return Err("DialingCall failed".into());
2213                 }
2214             }
2215             "answer-call" => {
2216                 let success =
2217                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().answer_call();
2218                 if !success {
2219                     return Err("AnswerCall failed".into());
2220                 }
2221             }
2222             "hangup-call" => {
2223                 let success =
2224                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().hangup_call();
2225                 if !success {
2226                     return Err("HangupCall failed".into());
2227                 }
2228             }
2229             "set-memory-call" => {
2230                 let success = self
2231                     .context
2232                     .lock()
2233                     .unwrap()
2234                     .telephony_dbus
2235                     .as_mut()
2236                     .unwrap()
2237                     .set_memory_call(get_arg(args, 1).ok().map(String::from));
2238                 if !success {
2239                     return Err("SetMemoryCall failed".into());
2240                 }
2241             }
2242             "set-last-call" => {
2243                 let success = self
2244                     .context
2245                     .lock()
2246                     .unwrap()
2247                     .telephony_dbus
2248                     .as_mut()
2249                     .unwrap()
2250                     .set_last_call(get_arg(args, 1).ok().map(String::from));
2251                 if !success {
2252                     return Err("SetLastCall failed".into());
2253                 }
2254             }
2255             "release-held" => {
2256                 let success =
2257                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().release_held();
2258                 if !success {
2259                     return Err("ReleaseHeld failed".into());
2260                 }
2261             }
2262             "release-active-accept-held" => {
2263                 let success = self
2264                     .context
2265                     .lock()
2266                     .unwrap()
2267                     .telephony_dbus
2268                     .as_mut()
2269                     .unwrap()
2270                     .release_active_accept_held();
2271                 if !success {
2272                     return Err("ReleaseActiveAcceptHeld failed".into());
2273                 }
2274             }
2275             "hold-active-accept-held" => {
2276                 let success = self
2277                     .context
2278                     .lock()
2279                     .unwrap()
2280                     .telephony_dbus
2281                     .as_mut()
2282                     .unwrap()
2283                     .hold_active_accept_held();
2284                 if !success {
2285                     return Err("HoldActiveAcceptHeld failed".into());
2286                 }
2287             }
2288             "audio-connect" => {
2289                 let success =
2290                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().audio_connect(
2291                         RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
2292                     );
2293                 if !success {
2294                     return Err("ConnectAudio failed".into());
2295                 }
2296             }
2297             "audio-disconnect" => {
2298                 self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().audio_disconnect(
2299                     RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
2300                 );
2301             }
2302             other => {
2303                 return Err(format!("Invalid argument '{}'", other).into());
2304             }
2305         }
2306         Ok(())
2307     }
2308 
cmd_qa(&mut self, args: &Vec<String>) -> CommandResult2309     fn cmd_qa(&mut self, args: &Vec<String>) -> CommandResult {
2310         if !self.context.lock().unwrap().adapter_ready {
2311             return Err(self.adapter_not_ready());
2312         }
2313 
2314         let command = get_arg(args, 0)?;
2315 
2316         match &command[..] {
2317             "add-media-player" => {
2318                 let name = String::from(get_arg(args, 1)?);
2319                 let browsing_supported = String::from(get_arg(args, 2)?)
2320                     .parse::<bool>()
2321                     .or(Err("Failed to parse browsing_supported"))?;
2322                 self.context
2323                     .lock()
2324                     .unwrap()
2325                     .qa_dbus
2326                     .as_mut()
2327                     .unwrap()
2328                     .add_media_player(name, browsing_supported);
2329             }
2330             _ => return Err(CommandError::InvalidArgs),
2331         };
2332 
2333         Ok(())
2334     }
2335 
cmd_media(&mut self, args: &Vec<String>) -> CommandResult2336     fn cmd_media(&mut self, args: &Vec<String>) -> CommandResult {
2337         if !self.context.lock().unwrap().adapter_ready {
2338             return Err(self.adapter_not_ready());
2339         }
2340 
2341         match &get_arg(args, 0)?[..] {
2342             "log" => {
2343                 self.context.lock().unwrap().media_dbus.as_mut().unwrap().trigger_debug_dump();
2344             }
2345             other => {
2346                 return Err(format!("Invalid argument '{}'", other).into());
2347             }
2348         }
2349 
2350         Ok(())
2351     }
2352 
cmd_dumpsys(&mut self, _args: &Vec<String>) -> CommandResult2353     fn cmd_dumpsys(&mut self, _args: &Vec<String>) -> CommandResult {
2354         if !self.lock_context().adapter_ready {
2355             return Err(self.adapter_not_ready());
2356         }
2357 
2358         let contents = self.lock_context().adapter_dbus.as_mut().unwrap().get_dumpsys();
2359         println!("{}", contents);
2360 
2361         Ok(())
2362     }
2363 }
2364 
2365 #[cfg(test)]
2366 mod tests {
2367 
2368     use super::*;
2369 
2370     #[test]
test_wrap_help_text()2371     fn test_wrap_help_text() {
2372         let text = "hello";
2373         let text_len = text.chars().count();
2374         // ensure no overflow
2375         assert_eq!(format!("|{}|", text), wrap_help_text(text, 4, 0));
2376         assert_eq!(format!("|{}|", text), wrap_help_text(text, 5, 0));
2377         assert_eq!(format!("|{}{}|", text, " "), wrap_help_text(text, 6, 0));
2378         assert_eq!(format!("|{}{}|", text, " ".repeat(2)), wrap_help_text(text, 7, 0));
2379         assert_eq!(
2380             format!("|{}{}|", text, " ".repeat(100 - text_len)),
2381             wrap_help_text(text, 100, 0)
2382         );
2383         assert_eq!(format!("|{}{}|", " ", text), wrap_help_text(text, 4, 1));
2384         assert_eq!(format!("|{}{}|", " ".repeat(2), text), wrap_help_text(text, 5, 2));
2385         assert_eq!(format!("|{}{}{}|", " ".repeat(3), text, " "), wrap_help_text(text, 6, 3));
2386         assert_eq!(
2387             format!("|{}{}{}|", " ".repeat(4), text, " ".repeat(7 - text_len)),
2388             wrap_help_text(text, 7, 4)
2389         );
2390         assert_eq!(format!("|{}{}|", " ".repeat(9), text), wrap_help_text(text, 4, 9));
2391         assert_eq!(format!("|{}{}|", " ".repeat(10), text), wrap_help_text(text, 3, 10));
2392         assert_eq!(format!("|{}{}|", " ".repeat(11), text), wrap_help_text(text, 2, 11));
2393         assert_eq!(format!("|{}{}|", " ".repeat(12), text), wrap_help_text(text, 1, 12));
2394         assert_eq!("||", wrap_help_text("", 0, 0));
2395         assert_eq!("| |", wrap_help_text("", 1, 0));
2396         assert_eq!("|  |", wrap_help_text("", 1, 1));
2397         assert_eq!("| |", wrap_help_text("", 0, 1));
2398     }
2399 }
2400