store_todo_sh.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #!/usr/bin/python3
  2. # This file is part of PyPass
  3. #
  4. # PyPass is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. import os
  17. from os.path import expanduser
  18. from subprocess import call, check_output
  19. from shlex import quote
  20. from PyQt5.QtWidgets import QMessageBox
  21. import pexpect
  22. class Store():
  23. def __init__(self, binary, vm, window, q):
  24. if binary == None:
  25. self.binary = "todo.sh"
  26. else:
  27. self.binary = binary
  28. self.vm = vm
  29. self.window = window
  30. def stop(self):
  31. self.notifier.stop()
  32. def getStoreLocation(self):
  33. return expanduser("~") + "/.todo/todo.txt"
  34. def call(self, command, returnOutput=False):
  35. if returnOutput:
  36. return check_output([self.binary] + command).decode("utf-8")
  37. else:
  38. call([self.binary] + command)
  39. def getSupportedCommands(self):
  40. return ["add", "addto", "append", "archive", "deduplicate", "rm", "depri", "do", "mv", "prepend", "pri", "replace"]
  41. def getCommands(self):
  42. commandsText = []
  43. commandsStarted = False
  44. # We will crash here if todo.sh is not installed.
  45. # TODO: Find a nice way to notify the user they need to install todo.sh
  46. commandText = self.call(["-h"], returnOutput=True)
  47. for line in commandText.splitlines():
  48. strippedLine = line.lstrip()
  49. if not commandsStarted:
  50. if strippedLine.startswith("Actions:"):
  51. commandsStarted = True
  52. continue
  53. else:
  54. if strippedLine == '':
  55. break
  56. lineData = strippedLine.split(" ")
  57. for variation in lineData[0].split("|"):
  58. if variation in self.getSupportedCommands():
  59. commandsText.append(variation + " " + " ".join(lineData[1:]))
  60. return commandsText
  61. def getEntries(self):
  62. entryList = []
  63. commandOutput = self.vm.ANSIEscapeRegex.sub('', self.call(["ls"], returnOutput=True)).splitlines()
  64. for line in commandOutput:
  65. if line == '--':
  66. break
  67. entryList.append(line)
  68. return entryList
  69. def copyEntryToClipboard(self, passwordName):
  70. pass
  71. def getAllEntryFields(self, passwordName):
  72. return ['']
  73. def runCommand(self, command, printOnSuccess=False, hideErrors=False):
  74. sanitizedCommandList = []
  75. for commandPart in command:
  76. sanitizedCommandList.append(quote(commandPart))
  77. proc = pexpect.spawn('/bin/sh', ['-c', self.binary + " " + " ".join(sanitizedCommandList) + (" 2>/dev/null" if hideErrors else "")])
  78. while True:
  79. result = proc.expect_exact([pexpect.EOF, pexpect.TIMEOUT, "(y/n)"], timeout=3)
  80. if result == 0:
  81. exitCode = proc.sendline("echo $?")
  82. break
  83. elif result == 1 and proc.before:
  84. self.vm.addError("Timeout error while running '{}'. This specific way of calling the command is most likely not supported yet by PyPass.".format(" ".join(command)))
  85. self.vm.addError("Command output: {}".format(self.vm.ANSIEscapeRegex.sub('', proc.before.decode("utf-8"))))
  86. return None
  87. else:
  88. proc.setecho(False)
  89. answer = QMessageBox.question(self.window, "PyPass", proc.before.decode("utf-8"), QMessageBox.Yes | QMessageBox.No)
  90. proc.waitnoecho()
  91. if answer == QMessageBox.Yes:
  92. proc.sendline('y')
  93. else:
  94. proc.sendline('n')
  95. proc.setecho(True)
  96. proc.close()
  97. exitCode = proc.exitstatus
  98. message = self.vm.ANSIEscapeRegex.sub('', proc.before.decode("utf-8")) if proc.before else ""
  99. if exitCode == 0:
  100. if printOnSuccess and message:
  101. self.vm.addMessage(message)
  102. self.vm.entryList = self.getEntries()
  103. return message
  104. else:
  105. self.vm.addError(message if message else "Error code {} running '{}'. More info may be logged to the console".format(str(exitCode), " ".join(command)))
  106. return None