Fechando conexões via s_client em um shell script
Eu estou tentando fazer uma conexão com um servidor IMAP dentro de um script de shell. Embora eu possa conectar e emitir os comandos, fechar a conexão adequadamente parece impossível.
Este é o comando de teste que estou usando:
openssl s_client -crlf -connect server:993 <<EOF
01 login USERNAME PASSWORD
02 LIST "" "*"
03 logout
EOF
Como a conexão é fechada assim que a entrada se esgota, isso ocorre antes que qualquer saída seja recebida, portanto, nunca recebo os dados necessários.
Se eu adicionar a opção-ign_eof
opção de modo que ele irá ignorar a entrada terminando para manter a conexão aberta a saída é retornada como desejado. Mas, em vez disso, depois que a conexão foi fechada ...
* BYE Logging out
03 OK Logout completed.
... s_client permanece vivo, portanto, a execução nunca retorna ao script.
Existe uma solução que fará com que o s_client termine quando o servidor fechar a conexão?
Ou existe um método alternativo usando ferramentas padrão? O script seria executado no Mac OS X, Debian e um derivado do Redhat, e possivelmente um emulador de terminal do Android, então eu gostaria de usar ferramentas bastante padronizadas para portabilidade, em vez de pacotes especializados.
Atualização: Eu encontrei uma resposta com a qual não estou totalmente feliz, mas que funciona. Ele usa um script para canalizar comandos para o openssl, mas que então entra em um loop infinito para manter o stdin aberto até receber um sinal para que ele saia. Aqui está o meu script de teste:
#!/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."
O script chama-se com um parâmetro para gerar os comandos IMAP que são canalizados para o openssl, cuja saída é canalizada para umread
loop para que possa ser processado. A variável MYFLAG é usada apenas para ocultar a saída de informações por openssl e apenas ecoar a saída da conexão do servidor.
Eu seleciono um nome de pasta fictício que inclui o PID da segunda instância do script como uma maneira de passar isso de volta, obviamente um arquivo temporário teria sido melhor, mas para o teste eu queria manter tudo contido e ser capaz de ver o que estava acontecendo.
Uma vez que as informações de busca foram exibidas e o servidor retorna a resposta OK, ele envia um sinal SIGUSR1 para a segunda instância do script, que envia a mensagem de logout e fecha, fechando stdin que faz com que s_client se desconecte.
Originalmente eu incluí o04 logout
comando no conjunto inicial de echos, mas quando eu fiz isso, o loop de leitura só foi exibido na medida em que a saída de busca parou, ele nem sequer mostrou o status OK para a operação, embora tudo tenha sido recebido.
Também preciso usartr
para retirar retornos de carreto à direita, mas se eu canalizar a saída de openssl até então nada é recebido pelo loop de leitura.