org.krakenapps.pcap.decoder.msn.MsnDecoder Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2010 NCHOVY
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.krakenapps.pcap.decoder.msn;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import org.krakenapps.pcap.decoder.tcp.TcpProcessor;
import org.krakenapps.pcap.decoder.tcp.TcpSession;
import org.krakenapps.pcap.decoder.tcp.TcpSessionKey;
import org.krakenapps.pcap.util.Buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author mindori
*/
public class MsnDecoder implements TcpProcessor {
private Logger logger = LoggerFactory.getLogger(MsnDecoder.class.getName());
private Set callbacks;
private Map sessionMap;
public MsnDecoder() {
callbacks = new HashSet();
sessionMap = new HashMap();
}
public void register(MsnProcessor processor) {
callbacks.add(processor);
}
public void unregister(MsnProcessor processor) {
callbacks.remove(processor);
}
@Override
public void handleTx(TcpSessionKey sessionKey, Buffer data) {
MsnSession session = sessionMap.get(sessionKey);
byte[] t = new byte[data.readableBytes()];
data.gets(t);
Buffer txBuffer = session.getTxBuffer();
txBuffer.addLast(t);
getChatContent(session, txBuffer, t);
}
@Override
public void handleRx(TcpSessionKey sessionKey, Buffer data) {
MsnSession session = sessionMap.get(sessionKey);
byte[] t = new byte[data.readableBytes()];
data.gets(t);
Buffer rxBuffer = session.getRxBuffer();
rxBuffer.addLast(t);
getChatContent(session, rxBuffer, t);
}
@Override
public boolean onEstablish(TcpSession session) {
TcpSessionKey sessionKey = session.getKey();
logger.debug("-> Msn Session Established: {} -> {}", sessionKey.getClientPort(), sessionKey.getServerPort());
sessionMap.put(sessionKey, new MsnSession());
return true;
}
@Override
public void onFinish(TcpSessionKey session) {
if (logger.isDebugEnabled())
logger.debug("-> Msn Session Closed: \n" + "Client Port: "
+ (int) session.getClientPort() + "\nServer Port: "
+ (int) session.getServerPort());
sessionMap.remove(session);
}
@Override
public void onReset(TcpSessionKey session) {
MsnSession msnSession = sessionMap.get(session);
if (msnSession != null) {
if (logger.isDebugEnabled())
logger.debug("Deallocate tx, rx buffer and remove Msn session.");
msnSession.clear();
sessionMap.remove(session);
}
}
private void getChatContent(MsnSession session, Buffer buffer, byte[] data) {
String content = new String(data);
String[] token = content.split("\r\n");
boolean isFindCommand = false;
int tokenIndex = 0;
while (!isFindCommand && tokenIndex < token.length) {
if (token[tokenIndex].matches("^USR.+")) {
// USR: normal case. ANS: called by opponent.
String[] usrCommand = token[tokenIndex].split(";");
String[] userAddress = usrCommand[0].split(" ");
session.setMsnUserAddress(userAddress[userAddress.length - 1]);
isFindCommand = true;
}
else if (token[tokenIndex].matches("^ANS.+") && session.getMsnUserAddress() == null) {
String[] usrCommand = token[0].split(";");
String[] userAddress = usrCommand[0].split(" ");
session.setMsnUserAddress(userAddress[2]);
isFindCommand = true;
}
else if (token[tokenIndex].matches("^MSG.+")) {
// get declared msnPayload length. split method of String is
// incomplete.
int k = 0;
int spaceIndex = 0;
while (data[k] != 0x0d) {
if (data[k] == 0x20)
spaceIndex = k;
k++;
}
byte[] payloadLenBytes = new byte[(k - 1) - spaceIndex];
for (int i = 0; i < payloadLenBytes.length; i++)
payloadLenBytes[i] = data[(spaceIndex + 1) + i];
int msnPayloadLen = session.getMsnPayloadLength();
if (msnPayloadLen == -1) {
// recording declared msnPayload length
msnPayloadLen = Integer.parseInt(new String(payloadLenBytes));
session.setMsnPayloadLength(msnPayloadLen);
}
int arrivedPayloadLen = 0;
if (!session.isGetDeclaredPayloadLength()) {
// token[k(k is MSG Header index)].length() + 2(\r\n) is MSG
// Header length.
arrivedPayloadLen = data.length - (token[0].length() + 2);
// session.setGetDeclaredPayloadLength(true);
} else
arrivedPayloadLen = data.length;
int beforeArrivedPayloadLength = session.getArrivedPayloadLength();
if (session.getMsnPayloadLength() > beforeArrivedPayloadLength + arrivedPayloadLen) {
// declared payload length as many as real payload length.
// recording arrived msnPayload length.
session.setArrivedPayloadLength(beforeArrivedPayloadLength + arrivedPayloadLen);
return;
} else {
int capacity = buffer.readableBytes();
byte[] msnData = new byte[capacity];
buffer.gets(msnData);
int index = 0;
int contentLength = 0;
while (index < msnData.length) {
if (msnData[index] == 0x0d) {
// real content length.
contentLength = msnData.length - (index + 2);
break;
}
index++;
}
String msnDataStr = new String(msnData);
String[] lines = msnDataStr.split("\r\n");
String[] param = lines[0].split(" ");
String fromAddr = "";
if (param[1].matches("^[_a-z0-9-]+(.[_a-z0-9-]+)*@(?:\\w+\\.)+\\w+$"))
fromAddr = param[1];
else
fromAddr = session.getMsnUserAddress();
int declaredPayloadLength = session.getMsnPayloadLength();
if (contentLength > declaredPayloadLength && tokenIndex == 0) {
if (session.isTruncated()) {
int remainDataLength = session.getRemainDataLength();
byte[] truncatedMsnData = session.getTruncatedMsgData();
int recordIndex = session.getMsnPayloadLength() - remainDataLength;
int offset = 0;
while (offset < msnData.length) {
truncatedMsnData[offset + recordIndex] = msnData[offset];
offset++;
}
Session mailSession = Session.getDefaultInstance(new Properties());
InputStream is = new ByteArrayInputStream(truncatedMsnData, 0,
truncatedMsnData.length);
handlingMsnContent(fromAddr, mailSession, is);
session.initTruncatedInstance();
getMsgMesssage(session, msnData, offset, fromAddr);
} else {
getMsgMesssage(session, msnData, 0, fromAddr);
}
} else {
if (session.isTruncated()) {
int remainDataLength = session.getRemainDataLength();
byte[] truncatedMsnData = session.getTruncatedMsgData();
int recordIndex = session.getMsnPayloadLength() - remainDataLength;
int offset = 0;
while (offset < msnData.length) {
truncatedMsnData[offset + recordIndex] = msnData[offset];
offset++;
}
if (remainDataLength > msnData.length) {
int newRemainDataLength = remainDataLength - msnData.length;
session.setRemainDataLength(newRemainDataLength);
session.setTruncatedMsgData(truncatedMsnData);
return;
} else {
Session mailSession = Session.getDefaultInstance(new Properties());
InputStream is = new ByteArrayInputStream(truncatedMsnData, 0,
truncatedMsnData.length);
handlingMsnContent(fromAddr, mailSession, is);
session.initTruncatedInstance();
getMsgMesssage(session, msnData, offset, fromAddr);
}
} else {
Session mailSession = Session.getDefaultInstance(new Properties());
InputStream is = new ByteArrayInputStream(msnData, 0, msnData.length);
handlingMsnContent(fromAddr, mailSession, is);
}
}
}
isFindCommand = true;
}
tokenIndex++;
}
session.clear();
}
private void getMsgMesssage(MsnSession session, byte[] msnData, int msnDataStartPoint,
String fromAddr) {
Session mailSession = Session.getDefaultInstance(new Properties());
InputStream is;
int lengthIndex = getLengthIndex(msnData, msnDataStartPoint);
int declaredPayloadLength;
if (session.isGetDeclaredPayloadLength()) {
declaredPayloadLength = session.getDeclaredPayloadLength();
} else {
declaredPayloadLength = getDeclaredLength(msnData, lengthIndex);
session.setDeclaredPayloadLength(declaredPayloadLength);
session.setGetDeclaredPayloadLength(true);
}
while (true) {
// read range: MSG header of MSN Data + declaredPayloadLength.
while (msnData[lengthIndex] != 0x0d)
lengthIndex++;
int readLength = ((lengthIndex + 2) - msnDataStartPoint) + declaredPayloadLength;
if (readLength > msnData.length - msnDataStartPoint) {
// remainDataLength is remain length of truncated data.
// so, cannot call chat callback method until next packet(valid
// sequence) arrived.
// and record bytes in MsnSession.
int remainDataLength = readLength - (msnData.length - msnDataStartPoint);
byte[] truncatedMsnData = new byte[readLength];
int offset = 0;
while (offset < (msnData.length - msnDataStartPoint)) {
truncatedMsnData[offset] = msnData[msnDataStartPoint + offset];
offset++;
}
session.setRemainDataLength(remainDataLength);
session.setTruncatedMsgData(truncatedMsnData);
return;
}
byte[] oneOfMsnData = new byte[readLength];
int offset = 0;
while (offset < readLength) {
oneOfMsnData[offset] = msnData[msnDataStartPoint + offset];
offset++;
}
is = new ByteArrayInputStream(oneOfMsnData, 0, oneOfMsnData.length);
handlingMsnContent(fromAddr, mailSession, is);
msnDataStartPoint = msnDataStartPoint + readLength;
// If start point is EOB(end of buffer), then escape loop.
if (msnDataStartPoint >= msnData.length - 1)
break;
else {
// Is remain data compose the one of MSG Message?
lengthIndex = getLengthIndex(msnData, msnDataStartPoint);
declaredPayloadLength = session.getDeclaredPayloadLength();
if (declaredPayloadLength > (msnData.length - msnDataStartPoint))
return;
}
}
}
private int getLengthIndex(byte[] msnData, int startPoint) {
int numOfSpace = 0;
for (int i = startPoint; i < msnData.length; i++) {
if (numOfSpace == 3) {
return i;
} else if (msnData[i] == 0x20)
numOfSpace++;
}
return -1;
}
private int getDeclaredLength(byte[] msnData, int lengthIndex) {
int declaredLength = -1;
int tempIndex = lengthIndex;
while (msnData[tempIndex] != 0x0d)
tempIndex++;
byte[] declaredLengthBytes = new byte[tempIndex - lengthIndex];
for (int j = 0; j < declaredLengthBytes.length; j++)
declaredLengthBytes[j] = msnData[lengthIndex + j];
try {
declaredLength = Integer.parseInt(new String(declaredLengthBytes));
} catch (NumberFormatException e) {
e.printStackTrace();
}
return declaredLength;
}
private void handlingMsnContent(String fromAddr, Session mailSession, InputStream is) {
try {
MimeMessage msg = new MimeMessage(mailSession, is);
if (msg.getHeader("X-MMS-IM-Format") != null) {
dispatchChat(fromAddr, (String) msg.getContent());
}
} catch (MessagingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void dispatchChat(String fromAddr, String chatContent) {
for (MsnProcessor processor : callbacks) {
processor.onChat(fromAddr, chatContent);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy