我正在尝试在 shell 脚本中建立与 IMAP 服务器的连接。虽然我可以连接并发出命令,但适当地关闭连接似乎是不可能的。
这是我正在使用的测试命令:
openssl s_client -crlf -connect server:993 <<EOF
01 login USERNAME PASSWORD
02 LIST "" "*"
03 logout
EOF
因为一旦输入用完连接就会关闭,这发生在接收到任何输出之前,所以我永远不会收到所需的数据。
如果我添加选项-ign_eof
选项,以便它将忽略输入结束以保持连接打开,则根据需要返回输出。但是在连接关闭之后......
* BYE Logging out
03 OK Logout completed.
...s_client 保持活动状态,因此执行永远不会返回到脚本。
是否有解决方案会导致 s_client 在服务器关闭连接时终止?
或者是否有使用标准工具的替代方法?该脚本将在 Mac OS X、Debian 和 Redhat 衍生版本以及可能的 Android 终端仿真器上运行,因此我想使用相当标准的工具来实现可移植性,而不是使用专门的软件包。
更新:我想出了一个我并不完全满意的答案,但它确实有效。它使用一个脚本将命令传送到 openssl,但随后进入一个无限循环以保持标准输入打开,直到它接收到一个告诉它退出的信号。这是我的测试脚本:
#!/bin/sh
if [ "$1" = "doit" ]; then
trap "echo \"04 logout\"; exit" SIGUSR1
echo "00 login USERNAME PASSWORD"
echo "01 SELECT PID-$$"
echo "02 SELECT FOLDER"
echo "03 FETCH 1:* (BODY[HEADER.FIELDS (Subject)])"
while :; do :; done
fi
MYFLAG=
$0 doit | openssl s_client -crlf -connect server:993 2>/dev/null | while read LINE; do
LINE=`echo "$LINE" | tr -d '\r'`
[ "${LINE:0:4}" = "* OK" ] && MYFLAG=Y
[ "${LINE:0:33}" = "01 NO Mailbox doesn't exist: PID-" ] && PID="${LINE##*PID-}"
[ "$MYFLAG" ] && echo "$LINE"
[ "$PID" -a "$LINE" = "03 OK Fetch completed." ] && kill -USR1 $PID
done
echo "Finished."
该脚本使用参数调用自身以输出通过管道传输到 openssl 的 IMAP 命令,openssl 的输出通过管道传输到read
循环中,以便对其进行处理。MYFLAG 变量只是用来隐藏 openssl 输出的信息,只是回显服务器连接的输出。
我选择了一个虚拟文件夹名称,其中包含脚本的第二个实例的 PID 作为将其传递回来的一种方式,显然临时文件会更好,但对于测试,我想保持一切自包含并能够观看什么正在发生。
一旦显示获取信息并且服务器返回 OK 响应,它会向脚本的第二个实例发送一个 SIGUSR1 信号,然后发送注销消息并退出,关闭 stdin 导致 s_client 断开连接。
最初我将04 logout
命令包含在初始的一组回显中,但是当我这样做时,读取循环只显示到 fetch 输出然后停止,它甚至没有显示操作的 OK 状态,尽管所有内容都已收到。
此外,我需要使用tr
去除尾随回车符,但如果我通过管道输出 openssl 的输出,则读取循环不会收到任何内容。