package com.inter6.mail.job.smtp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.annotation.PostConstruct;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.inter6.mail.gui.action.LogPanel;
import com.inter6.mail.model.data.ScpSourceData;
import com.inter6.mail.module.ModuleService;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScpSmtpSendJob extends AbstractSmtpSendMasterJob {
private LogPanel logPanel;
@Setter
private ScpSourceData scpSourceData;
private float progressRate;
private boolean isTerminated;
@PostConstruct
private void init() {
logPanel = tabComponentManager.getTabComponent(tabName, LogPanel.class);
}
@Override
protected void doMasterJob() throws Throwable {
Session session = null;
try {
session = new JSch().getSession(scpSourceData.getUsername(), scpSourceData.getHost(), scpSourceData.getPort());
session.setPassword(scpSourceData.getPassword());
session.setUserInfo(scpUserInfo);
session.connect(60 * 1000);
int i = 0;
for (String path : scpSourceData.getPaths()) {
if (isTerminated) {
return;
}
try {
orderRemoteFile(session, path);
} catch (Throwable e) {
this.logPanel.error("eml send order fail ! - PATH:" + path, e);
}
i++;
this.progressRate = (float) i / (float) path.length() * 100f;
}
} finally {
if (session != null) {
session.disconnect();
}
}
}
/*private List<String> findEmlPaths(Session session, String path) throws JSchException, IOException {
ChannelExec channel = null;
try {
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("find " + path + " -name \"*.eml\" -type f");
InputStream in = channel.getInputStream();
channel.connect(60 * 1000);
return IOUtils.readLines(in);
} finally {
if (channel != null) {
channel.disconnect();
}
}
}*/
private void orderRemoteFile(Session session, String path) throws JSchException, IOException {
ChannelExec channel = null;
try {
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("scp -f " + path);
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
byte[] buf = new byte[1024];
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
while (true) {
int c = checkAck(in);
if (c != 'C') {
break;
}
// read '0644 '
in.read(buf, 0, 5);
long filesize = 0L;
while (true) {
if (in.read(buf, 0, 1) < 0) {
// error
break;
}
if (buf[0] == ' ')
break;
filesize = filesize * 10L + (long) (buf[0] - '0');
}
String file;
for (int i = 0;; i++) {
in.read(buf, i, 1);
if (buf[i] == (byte) 0x0a) {
file = new String(buf, 0, i);
break;
}
}
logPanel.info("find remote file - FILE:" + file + " SIZE:" + filesize);
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
// read a content of lfile
try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
int foo;
while (true) {
if (buf.length < filesize)
foo = buf.length;
else
foo = (int) filesize;
foo = in.read(buf, 0, foo);
if (foo < 0) {
// error
break;
}
fos.write(buf, 0, foo);
filesize -= foo;
if (filesize == 0L)
break;
}
try {
MimeSmtpSendJob mimeSmtpSendJob = ModuleService.getBean(MimeSmtpSendJob.class);
mimeSmtpSendJob.setTabName(tabName);
mimeSmtpSendJob.setMessageStream(new ByteArrayInputStream(fos.toByteArray()));
mimeSmtpSendJob.setReplaceDateData(scpSourceData.getReplaceDateData());
if (scpSourceData.getSendDelayData().isUse()) {
mimeSmtpSendJob.execute();
Thread.sleep(scpSourceData.getSendDelayData().getDelaySecond() * 1000);
} else {
this.orderWorker(mimeSmtpSendJob);
}
} catch (Throwable e) {
this.logPanel.error("eml send order fail ! - PATH:" + path, e);
}
}
if (checkAck(in) != 0) {
throw new IOException();
}
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
}
} finally {
if (channel != null) {
channel.disconnect();
}
}
}
private int checkAck(InputStream in) throws IOException {
int b = in.read();
// b may be 0 for success,
// 1 for error,
// 2 for fatal error,
// -1
if (b == 0)
return b;
if (b == -1)
return b;
if (b == 1 || b == 2) {
StringBuilder sb = new StringBuilder();
int c;
do {
c = in.read();
sb.append((char) c);
} while (c != '\n');
if (b == 1) { // error
logPanel.error("access remote file fail ! - " + sb.toString(), null);
}
if (b == 2) { // fatal error
logPanel.error("access remote file fail ! - " + sb.toString(), null);
}
}
return b;
}
@Override
protected float getProgressRate() {
return this.progressRate;
}
@Override
public void terminate() throws InterruptedException {
super.terminate();
isTerminated = true;
}
@Override
public String toString() {
String info = "ScpSmtpSendJob PATH:" + this.scpSourceData.getPaths();
if (info.length() > 50) {
info = StringUtils.substring(info, 0, 100) + "...";
}
return info;
}
private UserInfo scpUserInfo = new UserInfo() {
@Override
public String getPassphrase() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean promptPassword(String message) {
return false;
}
@Override
public boolean promptPassphrase(String message) {
return false;
}
@Override
public boolean promptYesNo(String message) {
return true;
}
@Override
public void showMessage(String message) {
}
};
}