从流行的 GNU/Linux 发行版中的 Bash 终端,如何将不受密码保护的 [OpenDocument Text (.odt)](OpenDocument Text) 文档转换为受密码保护的文档?
不幸的是,LibreOffice 手册页甚至不包含字符串“password”,因此这里没有太多帮助。
我不想将文件包装在加密容器中,例如压缩文件这需要先将其解压,然后才能由 LibreOffice 打开。重要的是,文件的收件人无需使用 LibreOffice 和知道文件密码之外的任何东西即可打开文件。
如果可能的话,我更愿意使用 LibreOffice 本身和/或标准 GNU/Linux 实用程序来实现所需的结果。否则,我宁愿只使用通常为 GNU/Linux 发行版打包的自由软件应用程序。
答案1
我创建的模块是一个快速破解;没有错误检查,因此您可能会毁掉您的宝贵文件。使用风险由您自己承担,手头有可靠的备份,并且切勿使用 root 权限运行此程序!
太尔;博士:
- 下载模块内容这里并将其保存在某处。
- 通过工具->宏->组织宏->libreoffice basic启动
Libreoffice
并进入宏组织。 - 确保从左侧的宏列表中,“LibreOffice Macros”容器中有一个名为“Tools”的库(需要其中的宏)
- 选择对话框右侧的“组织者”
- 打开容器“我的宏”,选择“标准”,然后在右侧选择“新建”
- 将模块命名为“saveWithPassword”
- 突出显示新创建的模块后,选择“编辑”。这将打开 IDE,并显示新模块
- 确保您选择了正确的模块,然后删除编辑器窗口的内容。
- 使用任何 GUI 编辑器(例如 )打开下载的模块文件
gedit
,选择全部,然后将完整的源代码剪切并粘贴到 LibreOffice 编辑器窗口中。保存并关闭,就完成了。 - 如果你熟悉编程和调试,你可以打开一个.odt文件,打开宏IDE(如上),并单步执行宏,查看变量的内容等。
现在,如何使用宏?
假设有一个应使用相同密码保护的 .odt 文件列表。受保护的文件应保存在不同的目标文件夹中(必须存在)以保持原始文件不变。然后你打电话
$ lowriter --invisible <list of .odt files> macro:///standard.saveWithPasswd.saveWithPasswd
(假设您确实按照建议创建了模块)。加载文件后,宏将启动,系统将要求您提供目标目录和密码。然后,文档将保存在目标目录中,并使用提供的密码进行保护。
如果您不想在 Windows 中打开所有文档,还有第二种(静默)方法:
确保没有正在LibreOffice
运行的实例。然后运行
$ export password=<the password to use>
$ export target=<full path to the target directory>
$ lowriter --headless <list of .odt files> macro:///standard.saveWithPasswd.saveWithPasswd
现在了解详细信息
主要功能是写入文件,受密码保护。有不同的方法可以做到这一点;如果你只是记录将要交互完成的事情,你最终会得到类似的结果
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "URL"
args1(0).Value = "file:///home/user/Untitled%201.odt"
args1(1).Name = "FilterName"
args1(1).Value = "writer8"
args1(2).Name = "EncryptionData"
args1(2).Value = Array(Array("PackageSHA256UTF8EncryptionKey",Array(-14,-81,-47,-54,-53,84,65,-91,-26,90,122,70,10,95,-104,-104,-73,-71,-117,8,-86,99,35,-94,-27,60,-117,-102,-106,-122,-51,-122)),Array("PackageSHA1UTF8EncryptionKey",Array(24,97,84,113,43,45,95,103,-111,-40,91,-102,9,-121,-71,-113,-94,49,119,-100)),Array("PackageSHA1MS1252EncryptionKey",Array(24,97,84,113,43,45,95,103,-111,-40,91,-102,9,-121,-71,-113,-94,49,119,-100)))
dispatcher.executeDispatch(document, ".uno:SaveAs", "", 0, args1())
什么太复杂了。
在[2] 5.8.3中我找到了更简单的解决方案:
Dim args(0) As New com.sun.star.beans.PropertyValue
Dim sURL$
args(0).Name ="Password"
args(0).Value = "test"
sURL=ConvertToURL("/andrew0/home/andy/test.odt")
ThisComponent.storeToURL(sURL, args())
现在要做的大部分工作是
- 将密码和目标文件名/目录传递给宏
- 迭代打开的文档
- 使用环境变量和对话
- 查找并使用现有的库函数
我将更深入地描述该模块的某些部分(我认为其余部分是微不足道的):
GlobalScope.BasicLibraries.loadLibrary("Tools")
这将加载全局LibreOffice
库“Tools”。其中的一些宏用于处理字符串等。
oComponents = StarDesktop.getComponents()
oDocs = oComponents.createEnumeration()
Do While oDocs.hasMoreElements()
oDoc = oDocs.nextElement()
.
.
Loop
这会迭代当前打开的文档/框架。至于测试和调试,IDE 也打开了,我必须测试框架是否确实包含有效文档:
sUrl = oDoc.getUrl()
If sUrl <> "" Then
现在,如果文档定义了 URL(不要在此处测试它是否确实存在...),则会创建一个新 URL,并使用密码保存文档:
sName = FileNameoutofPath(sUrl)
sName = myTargetDir & "/" & sName
sUrl = ConvertToURL(sName)
aArgs(0).Name = "Password"
aArgs(0).Value = myPassword
oDoc.storeToURL(sURL, aArgs())
oDoc.close(true)
这里使用“Tools”库的函数。特别是当lowriter
使用 option调用时--headless
,文档必须在最后关闭,否则lowriter
不会终止。
我无法设法将“密码”和“目标目录”作为参数传递给模块,因此我使用两种方式:作为 shell 环境变量,因为这可以完全自动化,以及作为对话输入。
使用“Environ”功能和默认的“InputBox”获取密码非常简单。如果您想在输入时隐藏密码,则必须创建自己的对话框。
选择目标文件夹有点棘手,因为这不是简单的运行时函数:
oFileDialog = CreateUnoService("com.sun.star.ui.dialogs.FolderPicker")
oUcb = createUnoService("com.sun.star.ucb.SimpleFileAccess")
InitPath = GetPathSettings("Work")
If oUcb.Exists(InitPath) Then
oFileDialog.SetDisplayDirectory(InitPath)
End If
如果您决定使用静态“InitPath”(“FolderPicker”打开时开始的路径),您可以定义它并剪切从oUcb =
到 的所有内容End If
,除了oFileDialog.SetDisplayDirectory
。从命令行运行时,您还可以设置InitPath = Environ("PWD")
.现在,起始文件夹是您在设置中定义为“我的文档”文件夹的文件夹LibreOffice
。
oFileDialog.SetTitle(sTitle)
iAccept = oFileDialog.Execute()
If iAccept = 1 Then
sPath = oFileDialog.Directory
getFolderName = sPath
End If
我认为这是不言自明的。但要注意,这里没有错误检查 - 如果取消文件对话框,则不会定义 TargetPath。这应该会导致宏完全中断,或者您必须定义一个while
循环而不是If
in askForTarget
:
Do While myTargetDir = ""
myTargetDir = getFolderName("Please select output directory")
Loop
你明白了...
我能想到的修改有很多。首先,进行错误检查以确保不会覆盖原始文件(例如测试是否TargetDir
为空)或造成其他损害。或者,使用原始文件名、目标和密码创建一个文本文件,并将其传递给宏以按顺序完成(您明白了吗?)。或者,您将所有原始文档放在一个文件夹中,将该文件夹路径传递给宏,然后迭代目录列表(也有示例)。
在研究过程中,我发现(并使用)了一些很好的文档,其中有很多示例:
[1]OpenOffice 宏解释经过安德鲁·皮托尼亚克(也有德语版本)
和问题/答案,例如https://ask.libreoffice.org/en/question/29997/how-to-run-a-macro-on-multiple-files-batch/
最后,谢谢你的提问和耐心。重回宏编程真是太有趣了,我重新学习了一些知识,学到了很多新东西。