smbclientng.core.CommandCompleter
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# File name : CommandCompleter.py 4# Author : Podalirius (@podalirius_) 5# Date created : 20 may 2024 6 7 8import ntpath 9import os 10import shlex 11 12 13class CommandCompleter(object): 14 """ 15 A class to handle command completion for the smbclient-ng shell. 16 17 This class provides a command completion feature that suggests possible command names based on the current input. 18 It uses a dictionary to store commands and their descriptions, which helps in providing hints during the command line 19 interaction in the smbclient-ng shell. 20 21 Attributes: 22 smbSession (SMBSession): An instance of SMBSession which maintains the current SMB session. 23 commands (dict): A dictionary containing command names as keys and their descriptions and subcommands as values. 24 25 Methods: 26 __init__(self, smbSession): Initializes the CommandCompleter with an SMBSession. 27 """ 28 29 commands = { 30 "bat": { 31 "description": [ 32 "Pretty prints the contents of a remote file.", 33 "Syntax: 'bat <file>'" 34 ], 35 "subcommands": [], 36 "autocomplete": ["remote_file"] 37 }, 38 "cat": { 39 "description": [ 40 "Get the contents of a remote file.", 41 "Syntax: 'cat <file>'" 42 ], 43 "subcommands": [], 44 "autocomplete": ["remote_file"] 45 }, 46 "cd": { 47 "description": [ 48 "Change the current working directory.", 49 "Syntax: 'cd <directory>'" 50 ], 51 "subcommands": [], 52 "autocomplete": ["remote_directory"] 53 }, 54 "close": { 55 "description": [ 56 "Closes the SMB connection to the remote machine.", 57 "Syntax: 'close'" 58 ], 59 "subcommands": [], 60 "autocomplete": [] 61 }, 62 "connect": { 63 "description": [ 64 "Connect to the remote machine (useful if connection timed out).", 65 "Syntax: 'connect'" 66 ], 67 "subcommands": [], 68 "autocomplete": [] 69 }, 70 "debug": { 71 "description": [ 72 "Command for dev debugging.", 73 "Syntax: 'debug'" 74 ], 75 "subcommands": [], 76 "autocomplete": [] 77 }, 78 "dir": { 79 "description": [ 80 "List the contents of the current working directory.", 81 "Syntax: 'dir'" 82 ], 83 "subcommands": [], 84 "autocomplete": ["remote_directory"] 85 }, 86 "exit": { 87 "description": [ 88 "Exits the smbclient-ng script.", 89 "Syntax: 'exit'" 90 ], 91 "subcommands": [], 92 "autocomplete": [] 93 }, 94 "get": { 95 "description": [ 96 "Get a remote file.", 97 "Syntax: 'get [-r] <directory or file>'" 98 ], 99 "subcommands": [], 100 "autocomplete": ["remote_file"] 101 }, 102 "help": { 103 "description": [ 104 "Displays this help message.", 105 "Syntax: 'help'" 106 ], 107 "subcommands": ["format"], 108 "autocomplete": [] 109 }, 110 "info": { 111 "description": [ 112 "Get information about the server and or the share.", 113 "Syntax: 'info [server|share]'" 114 ], 115 "subcommands": ["server", "share"], 116 "autocomplete": [] 117 }, 118 "lbat": { 119 "description": [ 120 "Pretty prints the contents of a local file.", 121 "Syntax: 'lbat <file>'" 122 ], 123 "subcommands": [], 124 "autocomplete": ["local_file"] 125 }, 126 "lcat": { 127 "description": [ 128 "Print the contents of a local file.", 129 "Syntax: 'lcat <file>'" 130 ], 131 "subcommands": [], 132 "autocomplete": ["local_file"] 133 }, 134 "lcd": { 135 "description": [ 136 "Changes the current local directory.", 137 "Syntax: 'lcd <directory>'" 138 ], 139 "subcommands": [], 140 "autocomplete": ["local_directory"] 141 }, 142 "lcp": { 143 "description": [ 144 "Create a copy of a local file.", 145 "Syntax: 'lcp <srcfile> <dstfile>'" 146 ], 147 "subcommands": [], 148 "autocomplete": ["remote_file"] 149 }, 150 "lls": { 151 "description": [ 152 "Lists the contents of the current local directory.", 153 "Syntax: 'lls'" 154 ], 155 "subcommands": [], 156 "autocomplete": ["local_directory"] 157 }, 158 "lmkdir": { 159 "description": [ 160 "Creates a new local directory.", 161 "Syntax: 'lmkdir <directory>'" 162 ], 163 "subcommands": [], 164 "autocomplete": ["local_directory"] 165 }, 166 "lpwd": { 167 "description": [ 168 "Shows the current local directory.", 169 "Syntax: 'lpwd'" 170 ], 171 "subcommands": [], 172 "autocomplete": [] 173 }, 174 "lrename": { 175 "description": [ 176 "Renames a local file.", 177 "Syntax: 'lrename <oldfilename> <newfilename>'" 178 ], 179 "subcommands": [], 180 "autocomplete": ["local_file"] 181 }, 182 "lrm": { 183 "description": [ 184 "Removes a local file.", 185 "Syntax: 'lrm <file>'" 186 ], 187 "subcommands": [], 188 "autocomplete": ["local_file"] 189 }, 190 "lrmdir": { 191 "description": [ 192 "Removes a local directory.", 193 "Syntax: 'lrmdir <directory>'" 194 ], 195 "subcommands": [], 196 "autocomplete": ["local_directory"] 197 }, 198 "ls": { 199 "description": [ 200 "List the contents of the current remote working directory.", 201 "Syntax: 'ls'" 202 ], 203 "subcommands": [], 204 "autocomplete": ["remote_directory"] 205 }, 206 "ltree": { 207 "description": [ 208 "Displays a tree view of the local directories.", 209 "Syntax: 'ltree [directory]'" 210 ], 211 "subcommands": [], 212 "autocomplete": ["local_directory"] 213 }, 214 "mkdir": { 215 "description": [ 216 "Creates a new remote directory.", 217 "Syntax: 'mkdir <directory>'" 218 ], 219 "subcommands": [], 220 "autocomplete": ["remote_directory"] 221 }, 222 "module": { 223 "description": [ 224 "Loads a specific module for additional functionalities.", 225 "Syntax: 'module <name>'" 226 ], 227 "subcommands": [], 228 "autocomplete": [] 229 }, 230 "mount": { 231 "description": [ 232 "Creates a mount point of the remote share on the local machine.", 233 "Syntax: 'mount <remote_path> <local_mountpoint>'" 234 ], 235 "subcommands": [], 236 "autocomplete": ["remote_directory"] 237 }, 238 "put": { 239 "description": [ 240 "Put a local file or directory in a remote directory.", 241 "Syntax: 'put [-r] <directory or file>'" 242 ], 243 "subcommands": [], 244 "autocomplete": ["local_file"] 245 }, 246 "reconnect": { 247 "description": [ 248 "Reconnect to the remote machine (useful if connection timed out).", 249 "Syntax: 'reconnect'" 250 ], 251 "subcommands": [], 252 "autocomplete": [] 253 }, 254 "reset": { 255 "description": [ 256 "Reset the TTY output, useful if it was broken after printing a binary file on stdout.", 257 "Syntax: 'reset'" 258 ], 259 "subcommands": [], 260 "autocomplete": [] 261 }, 262 "rmdir": { 263 "description": [ 264 "Removes a remote directory.", 265 "Syntax: 'rmdir <directory>'" 266 ], 267 "subcommands": [], 268 "autocomplete": ["remote_directory"] 269 }, 270 "rm": { 271 "description": [ 272 "Removes a remote file.", 273 "Syntax: 'rm <file>'" 274 ], 275 "subcommands": [], 276 "autocomplete": ["remote_file"] 277 }, 278 "sizeof": { 279 "description": [ 280 "Recursively compute the size of a folder.", 281 "Syntax: 'sizeof [directory|file]'" 282 ], 283 "subcommands": [], 284 "autocomplete": ["remote_directory"] 285 }, 286 "sessions": { 287 "description": [ 288 "Manage the SMB sessions.", 289 "Syntax: 'sessions [access|create|delete|execute|list]'" 290 ], 291 "subcommands": ["create", "delete", "execute", "interact", "list"], 292 "autocomplete": [] 293 }, 294 "shares": { 295 "description": [ 296 "Lists the SMB shares served by the remote machine.", 297 "Syntax: 'shares'" 298 ], 299 "subcommands": ["rights"], 300 "autocomplete": [] 301 }, 302 "tree": { 303 "description": [ 304 "Displays a tree view of the remote directories.", 305 "Syntax: 'tree [directory]'" 306 ], 307 "subcommands": [], 308 "autocomplete": ["remote_directory"] 309 }, 310 "umount": { 311 "description": [ 312 "Removes a mount point of the remote share on the local machine.", 313 "Syntax: 'umount <local_mount_point>'" 314 ], 315 "subcommands": [], 316 "autocomplete": ["remote_directory"] 317 }, 318 "use": { 319 "description": [ 320 "Use a SMB share.", 321 "Syntax: 'use <sharename>'" 322 ], 323 "subcommands": [], 324 "autocomplete": ["share"] 325 }, 326 } 327 328 def __init__(self, smbSession, config, logger): 329 # Objects 330 self.smbSession = smbSession 331 self.config = config 332 self.logger = logger 333 # Pre computing for some commands 334 self.commands["help"]["subcommands"] = ["format"] + list(self.commands.keys()) 335 self.commands["help"]["subcommands"].remove("help") 336 337 def complete(self, text, state): 338 """ 339 Function to handle command completion in the LDAP console. 340 341 This function completes the user"s input based on the available options for commands in the LDAP console. 342 343 Args: 344 text (str): The current text input by the user. 345 state (int): The current state of completion. 346 347 Returns: 348 str: The next completion suggestion based on the user"s input state. 349 """ 350 351 if state == 0: 352 353 # No text typed yet, need the list of commands available 354 if len(text) == 0: 355 self.matches = [s for s in self.commands.keys()] 356 357 # Parsing a command 358 elif len(text) != 0: 359 # This is for the main command 360 if text.count(" ") == 0: 361 self.matches = [s for s in self.commands.keys() if s and s.startswith(text)] 362 363 # This is for subcommands 364 elif text.count(" ") >= 1: 365 command, remainder = text.split(" ", 1) 366 367 if command in self.commands.keys(): 368 self.matches = [] 369 370 # Autocomplete shares 371 if "share" in self.commands[command]["autocomplete"]: 372 # Choose SMB Share to connect to 373 shares = self.smbSession.list_shares() 374 matching_entries = [] 375 for sharename in shares.keys(): 376 if sharename.lower().startswith(remainder.lower()): 377 matching_entries.append(shares[sharename]["name"]) 378 # Final matches 379 for m in matching_entries: 380 self.matches.append(command + " " + shlex.quote(m)) 381 382 # Autocomplete directory 383 if "remote_directory" in self.commands[command]["autocomplete"]: 384 # Choose remote directory 385 path = "" 386 if '\\' in remainder.strip() or '/' in remainder.strip(): 387 path = remainder.strip().replace(ntpath.sep, '/') 388 path = '/'.join(path.split('/')[:-1]) 389 # Get remote directory contents 390 directory_contents = self.smbSession.list_contents(path=path).items() 391 # 392 matching_entries = [] 393 for _, entry in directory_contents: 394 if entry.is_directory() and entry.get_longname() not in [".",".."]: 395 if len(path) != 0: 396 matching_entries.append(path + '/' + entry.get_longname() + '/') 397 else: 398 matching_entries.append(entry.get_longname() + '/') 399 # 400 for m in matching_entries: 401 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 402 self.matches.append(command + " " + shlex.quote(m)) 403 404 # Autocomplete file 405 if "remote_file" in self.commands[command]["autocomplete"]: 406 # Choose remote file 407 path = "" 408 if '\\' in remainder.strip() or '/' in remainder.strip(): 409 path = remainder.strip().replace(ntpath.sep, '/') 410 path = '/'.join(path.split('/')[:-1]) 411 # Get remote directory contents 412 directory_contents = self.smbSession.list_contents(path=path).items() 413 # 414 matching_entries = [] 415 for _, entry in directory_contents: 416 if (not entry.is_directory()) and entry.get_longname() not in [".",".."]: 417 if len(path) != 0: 418 matching_entries.append(path + '/' + entry.get_longname()) 419 else: 420 matching_entries.append(entry.get_longname()) 421 # 422 for m in matching_entries: 423 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 424 self.matches.append(command + " " + shlex.quote(m)) 425 426 # Autocomplete local_directory 427 if "local_directory" in self.commands[command]["autocomplete"]: 428 # Choose directory 429 path = "" 430 if os.path.sep in remainder.strip(): 431 path = path.split(os.path.sep)[:-1] 432 path = os.path.sep.join(path) 433 # Current dir 434 if len(path.strip()) == 0: 435 path = "." 436 # 437 directory_contents = os.listdir(path=path + os.path.sep) 438 matching_entries = [] 439 for entry in directory_contents: 440 if entry not in [".",".."]: 441 entry_path = path + os.path.sep + entry 442 if os.path.isdir(entry_path): 443 matching_entries.append(entry_path + os.path.sep) 444 # 445 for m in matching_entries: 446 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 447 self.matches.append(command + " " + shlex.quote(m)) 448 449 # Autocomplete local_file 450 if "local_file" in self.commands[command]["autocomplete"]: 451 # Choose file 452 path = "" 453 if os.path.sep in remainder.strip(): 454 path = path.split(os.path.sep)[:-1] 455 path = os.path.sep.join(path) 456 # Current dir 457 if len(path.strip()) == 0: 458 path = "." 459 # 460 directory_contents = os.listdir(path=(path + os.path.sep)) 461 matching_entries = [] 462 for entry in directory_contents: 463 if entry not in [".",".."]: 464 entry_path = path + os.path.sep + entry 465 if not os.path.isdir(entry_path): 466 matching_entries.append(entry_path) 467 # 468 for m in matching_entries: 469 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 470 self.matches.append(command + " " + shlex.quote(m)) 471 472 else: 473 # Generic case for subcommands 474 for m in self.commands[command]["subcommands"]: 475 if m.startswith(remainder): 476 self.matches.append(command + " " + m) 477 else: 478 # Unknown subcommand, skipping autocomplete 479 pass 480 else: 481 self.matches = [] 482 else: 483 self.matches = self.commands.keys()[:] 484 485 try: 486 return self.matches[state] + " " 487 except IndexError: 488 return None 489 490 def print_help(self, command=None): 491 """ 492 Prints help information for a specific command or all commands if no command is specified. 493 494 This method displays the help information for the command passed as an argument. If no command is specified, 495 it prints the help information for all available commands. The help information includes the command syntax, 496 description, and any subcommands associated with it. This method is designed to provide users with the necessary 497 guidance on how to use the commands in the smbclient-ng shell. 498 499 Args: 500 command (str, optional): The command to display help information for. If None, help for all commands is displayed. 501 502 Returns: 503 None 504 """ 505 506 if command is not None: 507 if command not in list(self.commands.keys())+["format"]: 508 command = None 509 510 # Print help for a specific command 511 if command is not None: 512 if command == "format": 513 self.print_help_format() 514 else: 515 self.logger.print("│") 516 if self.config.no_colors: 517 command_str = command + "─"* (15 - len(command)) 518 if len(self.commands[command]["description"]) == 0: 519 self.logger.print("│ ■ %s┤ " % command_str) 520 elif len(self.commands[command]["description"]) == 1: 521 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 522 else: 523 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 524 for line in self.commands[command]["description"][1:]: 525 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 526 else: 527 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 528 if len(self.commands[command]["description"]) == 0: 529 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 530 elif len(self.commands[command]["description"]) == 1: 531 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 532 else: 533 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 534 for line in self.commands[command]["description"][1:]: 535 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 536 self.logger.print("│") 537 # Generic help 538 else: 539 self.logger.print("│") 540 commands = sorted(self.commands.keys()) 541 for command in commands: 542 if self.config.no_colors: 543 command_str = command + "─"* (15 - len(command)) 544 if len(self.commands[command]["description"]) == 0: 545 self.logger.print("│ ■ %s┤ " % command_str) 546 elif len(self.commands[command]["description"]) == 1: 547 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 548 else: 549 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 550 for line in self.commands[command]["description"][1:]: 551 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 552 else: 553 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 554 if len(self.commands[command]["description"]) == 0: 555 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 556 elif len(self.commands[command]["description"]) == 1: 557 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 558 else: 559 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 560 for line in self.commands[command]["description"][1:]: 561 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 562 self.logger.print("│") 563 564 def print_help_format(self): 565 """ 566 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands. 567 568 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 569 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 570 """ 571 if self.config.no_colors: 572 self.logger.print("File attributes format:\n") 573 self.logger.print("dachnrst") 574 self.logger.print("│││││││└──> Temporary") 575 self.logger.print("││││││└───> System") 576 self.logger.print("│││││└────> Read-Only") 577 self.logger.print("││││└─────> Normal") 578 self.logger.print("│││└──────> Hidden") 579 self.logger.print("││└───────> Compressed") 580 self.logger.print("│└────────> Archived") 581 self.logger.print("└─────────> Directory") 582 else: 583 self.logger.print("File attributes format:\n") 584 self.logger.print("dachnrst") 585 self.logger.print("\x1b[90m│││││││└──>\x1b[0m Temporary") 586 self.logger.print("\x1b[90m││││││└───>\x1b[0m System") 587 self.logger.print("\x1b[90m│││││└────>\x1b[0m Read-Only") 588 self.logger.print("\x1b[90m││││└─────>\x1b[0m Normal") 589 self.logger.print("\x1b[90m│││└──────>\x1b[0m Hidden") 590 self.logger.print("\x1b[90m││└───────>\x1b[0m Compressed") 591 self.logger.print("\x1b[90m│└────────>\x1b[0m Archived") 592 self.logger.print("\x1b[90m└─────────>\x1b[0m Directory")
14class CommandCompleter(object): 15 """ 16 A class to handle command completion for the smbclient-ng shell. 17 18 This class provides a command completion feature that suggests possible command names based on the current input. 19 It uses a dictionary to store commands and their descriptions, which helps in providing hints during the command line 20 interaction in the smbclient-ng shell. 21 22 Attributes: 23 smbSession (SMBSession): An instance of SMBSession which maintains the current SMB session. 24 commands (dict): A dictionary containing command names as keys and their descriptions and subcommands as values. 25 26 Methods: 27 __init__(self, smbSession): Initializes the CommandCompleter with an SMBSession. 28 """ 29 30 commands = { 31 "bat": { 32 "description": [ 33 "Pretty prints the contents of a remote file.", 34 "Syntax: 'bat <file>'" 35 ], 36 "subcommands": [], 37 "autocomplete": ["remote_file"] 38 }, 39 "cat": { 40 "description": [ 41 "Get the contents of a remote file.", 42 "Syntax: 'cat <file>'" 43 ], 44 "subcommands": [], 45 "autocomplete": ["remote_file"] 46 }, 47 "cd": { 48 "description": [ 49 "Change the current working directory.", 50 "Syntax: 'cd <directory>'" 51 ], 52 "subcommands": [], 53 "autocomplete": ["remote_directory"] 54 }, 55 "close": { 56 "description": [ 57 "Closes the SMB connection to the remote machine.", 58 "Syntax: 'close'" 59 ], 60 "subcommands": [], 61 "autocomplete": [] 62 }, 63 "connect": { 64 "description": [ 65 "Connect to the remote machine (useful if connection timed out).", 66 "Syntax: 'connect'" 67 ], 68 "subcommands": [], 69 "autocomplete": [] 70 }, 71 "debug": { 72 "description": [ 73 "Command for dev debugging.", 74 "Syntax: 'debug'" 75 ], 76 "subcommands": [], 77 "autocomplete": [] 78 }, 79 "dir": { 80 "description": [ 81 "List the contents of the current working directory.", 82 "Syntax: 'dir'" 83 ], 84 "subcommands": [], 85 "autocomplete": ["remote_directory"] 86 }, 87 "exit": { 88 "description": [ 89 "Exits the smbclient-ng script.", 90 "Syntax: 'exit'" 91 ], 92 "subcommands": [], 93 "autocomplete": [] 94 }, 95 "get": { 96 "description": [ 97 "Get a remote file.", 98 "Syntax: 'get [-r] <directory or file>'" 99 ], 100 "subcommands": [], 101 "autocomplete": ["remote_file"] 102 }, 103 "help": { 104 "description": [ 105 "Displays this help message.", 106 "Syntax: 'help'" 107 ], 108 "subcommands": ["format"], 109 "autocomplete": [] 110 }, 111 "info": { 112 "description": [ 113 "Get information about the server and or the share.", 114 "Syntax: 'info [server|share]'" 115 ], 116 "subcommands": ["server", "share"], 117 "autocomplete": [] 118 }, 119 "lbat": { 120 "description": [ 121 "Pretty prints the contents of a local file.", 122 "Syntax: 'lbat <file>'" 123 ], 124 "subcommands": [], 125 "autocomplete": ["local_file"] 126 }, 127 "lcat": { 128 "description": [ 129 "Print the contents of a local file.", 130 "Syntax: 'lcat <file>'" 131 ], 132 "subcommands": [], 133 "autocomplete": ["local_file"] 134 }, 135 "lcd": { 136 "description": [ 137 "Changes the current local directory.", 138 "Syntax: 'lcd <directory>'" 139 ], 140 "subcommands": [], 141 "autocomplete": ["local_directory"] 142 }, 143 "lcp": { 144 "description": [ 145 "Create a copy of a local file.", 146 "Syntax: 'lcp <srcfile> <dstfile>'" 147 ], 148 "subcommands": [], 149 "autocomplete": ["remote_file"] 150 }, 151 "lls": { 152 "description": [ 153 "Lists the contents of the current local directory.", 154 "Syntax: 'lls'" 155 ], 156 "subcommands": [], 157 "autocomplete": ["local_directory"] 158 }, 159 "lmkdir": { 160 "description": [ 161 "Creates a new local directory.", 162 "Syntax: 'lmkdir <directory>'" 163 ], 164 "subcommands": [], 165 "autocomplete": ["local_directory"] 166 }, 167 "lpwd": { 168 "description": [ 169 "Shows the current local directory.", 170 "Syntax: 'lpwd'" 171 ], 172 "subcommands": [], 173 "autocomplete": [] 174 }, 175 "lrename": { 176 "description": [ 177 "Renames a local file.", 178 "Syntax: 'lrename <oldfilename> <newfilename>'" 179 ], 180 "subcommands": [], 181 "autocomplete": ["local_file"] 182 }, 183 "lrm": { 184 "description": [ 185 "Removes a local file.", 186 "Syntax: 'lrm <file>'" 187 ], 188 "subcommands": [], 189 "autocomplete": ["local_file"] 190 }, 191 "lrmdir": { 192 "description": [ 193 "Removes a local directory.", 194 "Syntax: 'lrmdir <directory>'" 195 ], 196 "subcommands": [], 197 "autocomplete": ["local_directory"] 198 }, 199 "ls": { 200 "description": [ 201 "List the contents of the current remote working directory.", 202 "Syntax: 'ls'" 203 ], 204 "subcommands": [], 205 "autocomplete": ["remote_directory"] 206 }, 207 "ltree": { 208 "description": [ 209 "Displays a tree view of the local directories.", 210 "Syntax: 'ltree [directory]'" 211 ], 212 "subcommands": [], 213 "autocomplete": ["local_directory"] 214 }, 215 "mkdir": { 216 "description": [ 217 "Creates a new remote directory.", 218 "Syntax: 'mkdir <directory>'" 219 ], 220 "subcommands": [], 221 "autocomplete": ["remote_directory"] 222 }, 223 "module": { 224 "description": [ 225 "Loads a specific module for additional functionalities.", 226 "Syntax: 'module <name>'" 227 ], 228 "subcommands": [], 229 "autocomplete": [] 230 }, 231 "mount": { 232 "description": [ 233 "Creates a mount point of the remote share on the local machine.", 234 "Syntax: 'mount <remote_path> <local_mountpoint>'" 235 ], 236 "subcommands": [], 237 "autocomplete": ["remote_directory"] 238 }, 239 "put": { 240 "description": [ 241 "Put a local file or directory in a remote directory.", 242 "Syntax: 'put [-r] <directory or file>'" 243 ], 244 "subcommands": [], 245 "autocomplete": ["local_file"] 246 }, 247 "reconnect": { 248 "description": [ 249 "Reconnect to the remote machine (useful if connection timed out).", 250 "Syntax: 'reconnect'" 251 ], 252 "subcommands": [], 253 "autocomplete": [] 254 }, 255 "reset": { 256 "description": [ 257 "Reset the TTY output, useful if it was broken after printing a binary file on stdout.", 258 "Syntax: 'reset'" 259 ], 260 "subcommands": [], 261 "autocomplete": [] 262 }, 263 "rmdir": { 264 "description": [ 265 "Removes a remote directory.", 266 "Syntax: 'rmdir <directory>'" 267 ], 268 "subcommands": [], 269 "autocomplete": ["remote_directory"] 270 }, 271 "rm": { 272 "description": [ 273 "Removes a remote file.", 274 "Syntax: 'rm <file>'" 275 ], 276 "subcommands": [], 277 "autocomplete": ["remote_file"] 278 }, 279 "sizeof": { 280 "description": [ 281 "Recursively compute the size of a folder.", 282 "Syntax: 'sizeof [directory|file]'" 283 ], 284 "subcommands": [], 285 "autocomplete": ["remote_directory"] 286 }, 287 "sessions": { 288 "description": [ 289 "Manage the SMB sessions.", 290 "Syntax: 'sessions [access|create|delete|execute|list]'" 291 ], 292 "subcommands": ["create", "delete", "execute", "interact", "list"], 293 "autocomplete": [] 294 }, 295 "shares": { 296 "description": [ 297 "Lists the SMB shares served by the remote machine.", 298 "Syntax: 'shares'" 299 ], 300 "subcommands": ["rights"], 301 "autocomplete": [] 302 }, 303 "tree": { 304 "description": [ 305 "Displays a tree view of the remote directories.", 306 "Syntax: 'tree [directory]'" 307 ], 308 "subcommands": [], 309 "autocomplete": ["remote_directory"] 310 }, 311 "umount": { 312 "description": [ 313 "Removes a mount point of the remote share on the local machine.", 314 "Syntax: 'umount <local_mount_point>'" 315 ], 316 "subcommands": [], 317 "autocomplete": ["remote_directory"] 318 }, 319 "use": { 320 "description": [ 321 "Use a SMB share.", 322 "Syntax: 'use <sharename>'" 323 ], 324 "subcommands": [], 325 "autocomplete": ["share"] 326 }, 327 } 328 329 def __init__(self, smbSession, config, logger): 330 # Objects 331 self.smbSession = smbSession 332 self.config = config 333 self.logger = logger 334 # Pre computing for some commands 335 self.commands["help"]["subcommands"] = ["format"] + list(self.commands.keys()) 336 self.commands["help"]["subcommands"].remove("help") 337 338 def complete(self, text, state): 339 """ 340 Function to handle command completion in the LDAP console. 341 342 This function completes the user"s input based on the available options for commands in the LDAP console. 343 344 Args: 345 text (str): The current text input by the user. 346 state (int): The current state of completion. 347 348 Returns: 349 str: The next completion suggestion based on the user"s input state. 350 """ 351 352 if state == 0: 353 354 # No text typed yet, need the list of commands available 355 if len(text) == 0: 356 self.matches = [s for s in self.commands.keys()] 357 358 # Parsing a command 359 elif len(text) != 0: 360 # This is for the main command 361 if text.count(" ") == 0: 362 self.matches = [s for s in self.commands.keys() if s and s.startswith(text)] 363 364 # This is for subcommands 365 elif text.count(" ") >= 1: 366 command, remainder = text.split(" ", 1) 367 368 if command in self.commands.keys(): 369 self.matches = [] 370 371 # Autocomplete shares 372 if "share" in self.commands[command]["autocomplete"]: 373 # Choose SMB Share to connect to 374 shares = self.smbSession.list_shares() 375 matching_entries = [] 376 for sharename in shares.keys(): 377 if sharename.lower().startswith(remainder.lower()): 378 matching_entries.append(shares[sharename]["name"]) 379 # Final matches 380 for m in matching_entries: 381 self.matches.append(command + " " + shlex.quote(m)) 382 383 # Autocomplete directory 384 if "remote_directory" in self.commands[command]["autocomplete"]: 385 # Choose remote directory 386 path = "" 387 if '\\' in remainder.strip() or '/' in remainder.strip(): 388 path = remainder.strip().replace(ntpath.sep, '/') 389 path = '/'.join(path.split('/')[:-1]) 390 # Get remote directory contents 391 directory_contents = self.smbSession.list_contents(path=path).items() 392 # 393 matching_entries = [] 394 for _, entry in directory_contents: 395 if entry.is_directory() and entry.get_longname() not in [".",".."]: 396 if len(path) != 0: 397 matching_entries.append(path + '/' + entry.get_longname() + '/') 398 else: 399 matching_entries.append(entry.get_longname() + '/') 400 # 401 for m in matching_entries: 402 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 403 self.matches.append(command + " " + shlex.quote(m)) 404 405 # Autocomplete file 406 if "remote_file" in self.commands[command]["autocomplete"]: 407 # Choose remote file 408 path = "" 409 if '\\' in remainder.strip() or '/' in remainder.strip(): 410 path = remainder.strip().replace(ntpath.sep, '/') 411 path = '/'.join(path.split('/')[:-1]) 412 # Get remote directory contents 413 directory_contents = self.smbSession.list_contents(path=path).items() 414 # 415 matching_entries = [] 416 for _, entry in directory_contents: 417 if (not entry.is_directory()) and entry.get_longname() not in [".",".."]: 418 if len(path) != 0: 419 matching_entries.append(path + '/' + entry.get_longname()) 420 else: 421 matching_entries.append(entry.get_longname()) 422 # 423 for m in matching_entries: 424 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 425 self.matches.append(command + " " + shlex.quote(m)) 426 427 # Autocomplete local_directory 428 if "local_directory" in self.commands[command]["autocomplete"]: 429 # Choose directory 430 path = "" 431 if os.path.sep in remainder.strip(): 432 path = path.split(os.path.sep)[:-1] 433 path = os.path.sep.join(path) 434 # Current dir 435 if len(path.strip()) == 0: 436 path = "." 437 # 438 directory_contents = os.listdir(path=path + os.path.sep) 439 matching_entries = [] 440 for entry in directory_contents: 441 if entry not in [".",".."]: 442 entry_path = path + os.path.sep + entry 443 if os.path.isdir(entry_path): 444 matching_entries.append(entry_path + os.path.sep) 445 # 446 for m in matching_entries: 447 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 448 self.matches.append(command + " " + shlex.quote(m)) 449 450 # Autocomplete local_file 451 if "local_file" in self.commands[command]["autocomplete"]: 452 # Choose file 453 path = "" 454 if os.path.sep in remainder.strip(): 455 path = path.split(os.path.sep)[:-1] 456 path = os.path.sep.join(path) 457 # Current dir 458 if len(path.strip()) == 0: 459 path = "." 460 # 461 directory_contents = os.listdir(path=(path + os.path.sep)) 462 matching_entries = [] 463 for entry in directory_contents: 464 if entry not in [".",".."]: 465 entry_path = path + os.path.sep + entry 466 if not os.path.isdir(entry_path): 467 matching_entries.append(entry_path) 468 # 469 for m in matching_entries: 470 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 471 self.matches.append(command + " " + shlex.quote(m)) 472 473 else: 474 # Generic case for subcommands 475 for m in self.commands[command]["subcommands"]: 476 if m.startswith(remainder): 477 self.matches.append(command + " " + m) 478 else: 479 # Unknown subcommand, skipping autocomplete 480 pass 481 else: 482 self.matches = [] 483 else: 484 self.matches = self.commands.keys()[:] 485 486 try: 487 return self.matches[state] + " " 488 except IndexError: 489 return None 490 491 def print_help(self, command=None): 492 """ 493 Prints help information for a specific command or all commands if no command is specified. 494 495 This method displays the help information for the command passed as an argument. If no command is specified, 496 it prints the help information for all available commands. The help information includes the command syntax, 497 description, and any subcommands associated with it. This method is designed to provide users with the necessary 498 guidance on how to use the commands in the smbclient-ng shell. 499 500 Args: 501 command (str, optional): The command to display help information for. If None, help for all commands is displayed. 502 503 Returns: 504 None 505 """ 506 507 if command is not None: 508 if command not in list(self.commands.keys())+["format"]: 509 command = None 510 511 # Print help for a specific command 512 if command is not None: 513 if command == "format": 514 self.print_help_format() 515 else: 516 self.logger.print("│") 517 if self.config.no_colors: 518 command_str = command + "─"* (15 - len(command)) 519 if len(self.commands[command]["description"]) == 0: 520 self.logger.print("│ ■ %s┤ " % command_str) 521 elif len(self.commands[command]["description"]) == 1: 522 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 523 else: 524 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 525 for line in self.commands[command]["description"][1:]: 526 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 527 else: 528 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 529 if len(self.commands[command]["description"]) == 0: 530 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 531 elif len(self.commands[command]["description"]) == 1: 532 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 533 else: 534 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 535 for line in self.commands[command]["description"][1:]: 536 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 537 self.logger.print("│") 538 # Generic help 539 else: 540 self.logger.print("│") 541 commands = sorted(self.commands.keys()) 542 for command in commands: 543 if self.config.no_colors: 544 command_str = command + "─"* (15 - len(command)) 545 if len(self.commands[command]["description"]) == 0: 546 self.logger.print("│ ■ %s┤ " % command_str) 547 elif len(self.commands[command]["description"]) == 1: 548 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 549 else: 550 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 551 for line in self.commands[command]["description"][1:]: 552 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 553 else: 554 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 555 if len(self.commands[command]["description"]) == 0: 556 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 557 elif len(self.commands[command]["description"]) == 1: 558 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 559 else: 560 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 561 for line in self.commands[command]["description"][1:]: 562 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 563 self.logger.print("│") 564 565 def print_help_format(self): 566 """ 567 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands. 568 569 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 570 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 571 """ 572 if self.config.no_colors: 573 self.logger.print("File attributes format:\n") 574 self.logger.print("dachnrst") 575 self.logger.print("│││││││└──> Temporary") 576 self.logger.print("││││││└───> System") 577 self.logger.print("│││││└────> Read-Only") 578 self.logger.print("││││└─────> Normal") 579 self.logger.print("│││└──────> Hidden") 580 self.logger.print("││└───────> Compressed") 581 self.logger.print("│└────────> Archived") 582 self.logger.print("└─────────> Directory") 583 else: 584 self.logger.print("File attributes format:\n") 585 self.logger.print("dachnrst") 586 self.logger.print("\x1b[90m│││││││└──>\x1b[0m Temporary") 587 self.logger.print("\x1b[90m││││││└───>\x1b[0m System") 588 self.logger.print("\x1b[90m│││││└────>\x1b[0m Read-Only") 589 self.logger.print("\x1b[90m││││└─────>\x1b[0m Normal") 590 self.logger.print("\x1b[90m│││└──────>\x1b[0m Hidden") 591 self.logger.print("\x1b[90m││└───────>\x1b[0m Compressed") 592 self.logger.print("\x1b[90m│└────────>\x1b[0m Archived") 593 self.logger.print("\x1b[90m└─────────>\x1b[0m Directory")
A class to handle command completion for the smbclient-ng shell.
This class provides a command completion feature that suggests possible command names based on the current input. It uses a dictionary to store commands and their descriptions, which helps in providing hints during the command line interaction in the smbclient-ng shell.
Attributes: smbSession (SMBSession): An instance of SMBSession which maintains the current SMB session. commands (dict): A dictionary containing command names as keys and their descriptions and subcommands as values.
Methods: __init__(self, smbSession): Initializes the CommandCompleter with an SMBSession.
329 def __init__(self, smbSession, config, logger): 330 # Objects 331 self.smbSession = smbSession 332 self.config = config 333 self.logger = logger 334 # Pre computing for some commands 335 self.commands["help"]["subcommands"] = ["format"] + list(self.commands.keys()) 336 self.commands["help"]["subcommands"].remove("help")
338 def complete(self, text, state): 339 """ 340 Function to handle command completion in the LDAP console. 341 342 This function completes the user"s input based on the available options for commands in the LDAP console. 343 344 Args: 345 text (str): The current text input by the user. 346 state (int): The current state of completion. 347 348 Returns: 349 str: The next completion suggestion based on the user"s input state. 350 """ 351 352 if state == 0: 353 354 # No text typed yet, need the list of commands available 355 if len(text) == 0: 356 self.matches = [s for s in self.commands.keys()] 357 358 # Parsing a command 359 elif len(text) != 0: 360 # This is for the main command 361 if text.count(" ") == 0: 362 self.matches = [s for s in self.commands.keys() if s and s.startswith(text)] 363 364 # This is for subcommands 365 elif text.count(" ") >= 1: 366 command, remainder = text.split(" ", 1) 367 368 if command in self.commands.keys(): 369 self.matches = [] 370 371 # Autocomplete shares 372 if "share" in self.commands[command]["autocomplete"]: 373 # Choose SMB Share to connect to 374 shares = self.smbSession.list_shares() 375 matching_entries = [] 376 for sharename in shares.keys(): 377 if sharename.lower().startswith(remainder.lower()): 378 matching_entries.append(shares[sharename]["name"]) 379 # Final matches 380 for m in matching_entries: 381 self.matches.append(command + " " + shlex.quote(m)) 382 383 # Autocomplete directory 384 if "remote_directory" in self.commands[command]["autocomplete"]: 385 # Choose remote directory 386 path = "" 387 if '\\' in remainder.strip() or '/' in remainder.strip(): 388 path = remainder.strip().replace(ntpath.sep, '/') 389 path = '/'.join(path.split('/')[:-1]) 390 # Get remote directory contents 391 directory_contents = self.smbSession.list_contents(path=path).items() 392 # 393 matching_entries = [] 394 for _, entry in directory_contents: 395 if entry.is_directory() and entry.get_longname() not in [".",".."]: 396 if len(path) != 0: 397 matching_entries.append(path + '/' + entry.get_longname() + '/') 398 else: 399 matching_entries.append(entry.get_longname() + '/') 400 # 401 for m in matching_entries: 402 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 403 self.matches.append(command + " " + shlex.quote(m)) 404 405 # Autocomplete file 406 if "remote_file" in self.commands[command]["autocomplete"]: 407 # Choose remote file 408 path = "" 409 if '\\' in remainder.strip() or '/' in remainder.strip(): 410 path = remainder.strip().replace(ntpath.sep, '/') 411 path = '/'.join(path.split('/')[:-1]) 412 # Get remote directory contents 413 directory_contents = self.smbSession.list_contents(path=path).items() 414 # 415 matching_entries = [] 416 for _, entry in directory_contents: 417 if (not entry.is_directory()) and entry.get_longname() not in [".",".."]: 418 if len(path) != 0: 419 matching_entries.append(path + '/' + entry.get_longname()) 420 else: 421 matching_entries.append(entry.get_longname()) 422 # 423 for m in matching_entries: 424 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 425 self.matches.append(command + " " + shlex.quote(m)) 426 427 # Autocomplete local_directory 428 if "local_directory" in self.commands[command]["autocomplete"]: 429 # Choose directory 430 path = "" 431 if os.path.sep in remainder.strip(): 432 path = path.split(os.path.sep)[:-1] 433 path = os.path.sep.join(path) 434 # Current dir 435 if len(path.strip()) == 0: 436 path = "." 437 # 438 directory_contents = os.listdir(path=path + os.path.sep) 439 matching_entries = [] 440 for entry in directory_contents: 441 if entry not in [".",".."]: 442 entry_path = path + os.path.sep + entry 443 if os.path.isdir(entry_path): 444 matching_entries.append(entry_path + os.path.sep) 445 # 446 for m in matching_entries: 447 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 448 self.matches.append(command + " " + shlex.quote(m)) 449 450 # Autocomplete local_file 451 if "local_file" in self.commands[command]["autocomplete"]: 452 # Choose file 453 path = "" 454 if os.path.sep in remainder.strip(): 455 path = path.split(os.path.sep)[:-1] 456 path = os.path.sep.join(path) 457 # Current dir 458 if len(path.strip()) == 0: 459 path = "." 460 # 461 directory_contents = os.listdir(path=(path + os.path.sep)) 462 matching_entries = [] 463 for entry in directory_contents: 464 if entry not in [".",".."]: 465 entry_path = path + os.path.sep + entry 466 if not os.path.isdir(entry_path): 467 matching_entries.append(entry_path) 468 # 469 for m in matching_entries: 470 if m.lower().startswith(remainder.lower()) or shlex.quote(m).lower().startswith(remainder.lower()): 471 self.matches.append(command + " " + shlex.quote(m)) 472 473 else: 474 # Generic case for subcommands 475 for m in self.commands[command]["subcommands"]: 476 if m.startswith(remainder): 477 self.matches.append(command + " " + m) 478 else: 479 # Unknown subcommand, skipping autocomplete 480 pass 481 else: 482 self.matches = [] 483 else: 484 self.matches = self.commands.keys()[:] 485 486 try: 487 return self.matches[state] + " " 488 except IndexError: 489 return None
Function to handle command completion in the LDAP console.
This function completes the user"s input based on the available options for commands in the LDAP console.
Args: text (str): The current text input by the user. state (int): The current state of completion.
Returns: str: The next completion suggestion based on the user"s input state.
491 def print_help(self, command=None): 492 """ 493 Prints help information for a specific command or all commands if no command is specified. 494 495 This method displays the help information for the command passed as an argument. If no command is specified, 496 it prints the help information for all available commands. The help information includes the command syntax, 497 description, and any subcommands associated with it. This method is designed to provide users with the necessary 498 guidance on how to use the commands in the smbclient-ng shell. 499 500 Args: 501 command (str, optional): The command to display help information for. If None, help for all commands is displayed. 502 503 Returns: 504 None 505 """ 506 507 if command is not None: 508 if command not in list(self.commands.keys())+["format"]: 509 command = None 510 511 # Print help for a specific command 512 if command is not None: 513 if command == "format": 514 self.print_help_format() 515 else: 516 self.logger.print("│") 517 if self.config.no_colors: 518 command_str = command + "─"* (15 - len(command)) 519 if len(self.commands[command]["description"]) == 0: 520 self.logger.print("│ ■ %s┤ " % command_str) 521 elif len(self.commands[command]["description"]) == 1: 522 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 523 else: 524 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 525 for line in self.commands[command]["description"][1:]: 526 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 527 else: 528 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 529 if len(self.commands[command]["description"]) == 0: 530 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 531 elif len(self.commands[command]["description"]) == 1: 532 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 533 else: 534 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 535 for line in self.commands[command]["description"][1:]: 536 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 537 self.logger.print("│") 538 # Generic help 539 else: 540 self.logger.print("│") 541 commands = sorted(self.commands.keys()) 542 for command in commands: 543 if self.config.no_colors: 544 command_str = command + "─"* (15 - len(command)) 545 if len(self.commands[command]["description"]) == 0: 546 self.logger.print("│ ■ %s┤ " % command_str) 547 elif len(self.commands[command]["description"]) == 1: 548 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 549 else: 550 self.logger.print("│ ■ %s┤ %s " % (command_str, self.commands[command]["description"][0])) 551 for line in self.commands[command]["description"][1:]: 552 self.logger.print("│ %s│ %s " % (" "*(15+2), line)) 553 else: 554 command_str = command + " \x1b[90m" + "─"* (15 - len(command)) + "\x1b[0m" 555 if len(self.commands[command]["description"]) == 0: 556 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m " % command_str) 557 elif len(self.commands[command]["description"]) == 1: 558 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 559 else: 560 self.logger.print("│ ■ %s\x1b[90m┤\x1b[0m %s " % (command_str, self.commands[command]["description"][0])) 561 for line in self.commands[command]["description"][1:]: 562 self.logger.print("│ %s\x1b[90m│\x1b[0m %s " % (" "*(15+3), line)) 563 self.logger.print("│")
Prints help information for a specific command or all commands if no command is specified.
This method displays the help information for the command passed as an argument. If no command is specified, it prints the help information for all available commands. The help information includes the command syntax, description, and any subcommands associated with it. This method is designed to provide users with the necessary guidance on how to use the commands in the smbclient-ng shell.
Args: command (str, optional): The command to display help information for. If None, help for all commands is displayed.
Returns: None
565 def print_help_format(self): 566 """ 567 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands. 568 569 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 570 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 571 """ 572 if self.config.no_colors: 573 self.logger.print("File attributes format:\n") 574 self.logger.print("dachnrst") 575 self.logger.print("│││││││└──> Temporary") 576 self.logger.print("││││││└───> System") 577 self.logger.print("│││││└────> Read-Only") 578 self.logger.print("││││└─────> Normal") 579 self.logger.print("│││└──────> Hidden") 580 self.logger.print("││└───────> Compressed") 581 self.logger.print("│└────────> Archived") 582 self.logger.print("└─────────> Directory") 583 else: 584 self.logger.print("File attributes format:\n") 585 self.logger.print("dachnrst") 586 self.logger.print("\x1b[90m│││││││└──>\x1b[0m Temporary") 587 self.logger.print("\x1b[90m││││││└───>\x1b[0m System") 588 self.logger.print("\x1b[90m│││││└────>\x1b[0m Read-Only") 589 self.logger.print("\x1b[90m││││└─────>\x1b[0m Normal") 590 self.logger.print("\x1b[90m│││└──────>\x1b[0m Hidden") 591 self.logger.print("\x1b[90m││└───────>\x1b[0m Compressed") 592 self.logger.print("\x1b[90m│└────────>\x1b[0m Archived") 593 self.logger.print("\x1b[90m└─────────>\x1b[0m Directory")
Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.