aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar')
-rw-r--r--src/org/traccar/BaseProtocolDecoder.java4
-rw-r--r--src/org/traccar/MainEventHandler.java68
-rw-r--r--src/org/traccar/ServerManager.java2
-rw-r--r--src/org/traccar/geocoder/GoogleGeocoder.java5
-rw-r--r--src/org/traccar/geocoder/JsonGeocoder.java9
-rw-r--r--src/org/traccar/protocol/AtrackProtocolDecoder.java7
-rw-r--r--src/org/traccar/protocol/Gl200TextProtocolDecoder.java8
-rw-r--r--src/org/traccar/protocol/GoSafeProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/ItsProtocolDecoder.java9
-rw-r--r--src/org/traccar/protocol/L100FrameDecoder.java31
-rw-r--r--src/org/traccar/protocol/L100ProtocolDecoder.java70
-rw-r--r--src/org/traccar/protocol/MeiligaoProtocolDecoder.java2
-rw-r--r--src/org/traccar/protocol/NyitechProtocol.java37
-rw-r--r--src/org/traccar/protocol/NyitechProtocolDecoder.java123
-rw-r--r--src/org/traccar/protocol/SpotProtocolDecoder.java11
-rw-r--r--src/org/traccar/protocol/WristbandProtocolDecoder.java80
-rw-r--r--src/org/traccar/sms/HttpSmsClient.java7
17 files changed, 430 insertions, 45 deletions
diff --git a/src/org/traccar/BaseProtocolDecoder.java b/src/org/traccar/BaseProtocolDecoder.java
index 7d840960b..cbef4568d 100644
--- a/src/org/traccar/BaseProtocolDecoder.java
+++ b/src/org/traccar/BaseProtocolDecoder.java
@@ -55,13 +55,13 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder {
return protocol != null ? protocol.getName() : PROTOCOL_UNKNOWN;
}
- public String getServer(Channel channel) {
+ public String getServer(Channel channel, char delimiter) {
String server = config.getString(getProtocolName() + ".server");
if (server == null && channel != null) {
InetSocketAddress address = (InetSocketAddress) channel.localAddress();
server = address.getAddress().getHostAddress() + ":" + address.getPort();
}
- return server;
+ return server != null ? server.replace(':', delimiter) : null;
}
protected double convertSpeed(double value, String defaultUnits) {
diff --git a/src/org/traccar/MainEventHandler.java b/src/org/traccar/MainEventHandler.java
index 3032646c1..d4e1ff860 100644
--- a/src/org/traccar/MainEventHandler.java
+++ b/src/org/traccar/MainEventHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2012 - 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,23 +29,28 @@ import org.traccar.model.Position;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Set;
public class MainEventHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class);
+ private static final String DEFAULT_LOGGER_EVENTS = "time,position,speed,course,accuracy,result";
private final Set<String> connectionlessProtocols = new HashSet<>();
+ private final Set<String> logEvents;
public MainEventHandler() {
String connectionlessProtocolList = Context.getConfig().getString("status.ignoreOffline");
if (connectionlessProtocolList != null) {
connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split(",")));
}
+ logEvents = new LinkedHashSet<>(Arrays.asList(
+ Context.getConfig().getString("logger.events", DEFAULT_LOGGER_EVENTS).split(",")));
}
@Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof Position) {
Position position = (Position) msg;
@@ -61,19 +66,45 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
StringBuilder s = new StringBuilder();
s.append(formatChannel(ctx.channel())).append(" ");
s.append("id: ").append(uniqueId);
- s.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false));
- s.append(", lat: ").append(String.format("%.5f", position.getLatitude()));
- s.append(", lon: ").append(String.format("%.5f", position.getLongitude()));
- if (position.getSpeed() > 0) {
- s.append(", speed: ").append(String.format("%.1f", position.getSpeed()));
- }
- s.append(", course: ").append(String.format("%.1f", position.getCourse()));
- if (position.getAccuracy() > 0) {
- s.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy()));
- }
- Object cmdResult = position.getAttributes().get(Position.KEY_RESULT);
- if (cmdResult != null) {
- s.append(", result: ").append(cmdResult);
+ for (String event : logEvents) {
+ switch (event) {
+ case "time":
+ s.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false));
+ break;
+ case "position":
+ s.append(", lat: ").append(String.format("%.5f", position.getLatitude()));
+ s.append(", lon: ").append(String.format("%.5f", position.getLongitude()));
+ break;
+ case "speed":
+ if (position.getSpeed() > 0) {
+ s.append(", speed: ").append(String.format("%.1f", position.getSpeed()));
+ }
+ break;
+ case "course":
+ s.append(", course: ").append(String.format("%.1f", position.getCourse()));
+ break;
+ case "accuracy":
+ if (position.getAccuracy() > 0) {
+ s.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy()));
+ }
+ break;
+ case "outdated":
+ if (position.getOutdated()) {
+ s.append(", outdated");
+ }
+ break;
+ case "invalid":
+ if (!position.getValid()) {
+ s.append(", invalid");
+ }
+ break;
+ default:
+ Object value = position.getAttributes().get(event);
+ if (value != null) {
+ s.append(", ").append(event).append(": ").append(value);
+ }
+ break;
+ }
}
LOGGER.info(s.toString());
@@ -104,13 +135,16 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter {
}
@Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ while (cause.getCause() != null && cause.getCause() != cause) {
+ cause = cause.getCause();
+ }
LOGGER.warn(formatChannel(ctx.channel()) + " error", cause);
closeChannel(ctx.channel());
}
@Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof IdleStateEvent) {
LOGGER.info(formatChannel(ctx.channel()) + " timed out");
closeChannel(ctx.channel());
diff --git a/src/org/traccar/ServerManager.java b/src/org/traccar/ServerManager.java
index cdc679e8a..6a3273402 100644
--- a/src/org/traccar/ServerManager.java
+++ b/src/org/traccar/ServerManager.java
@@ -88,7 +88,7 @@ public class ServerManager {
try {
server.start();
} catch (BindException e) {
- LOGGER.warn("One of the protocols is disabled due to port conflict");
+ LOGGER.warn("Port {} is disabled due to conflict", server.getPort());
}
}
}
diff --git a/src/org/traccar/geocoder/GoogleGeocoder.java b/src/org/traccar/geocoder/GoogleGeocoder.java
index af9b58a90..9494cab45 100644
--- a/src/org/traccar/geocoder/GoogleGeocoder.java
+++ b/src/org/traccar/geocoder/GoogleGeocoder.java
@@ -90,4 +90,9 @@ public class GoogleGeocoder extends JsonGeocoder {
return null;
}
+ @Override
+ protected String parseError(JsonObject json) {
+ return json.getString("error_message");
+ }
+
}
diff --git a/src/org/traccar/geocoder/JsonGeocoder.java b/src/org/traccar/geocoder/JsonGeocoder.java
index 80123e01e..ed59a1d8d 100644
--- a/src/org/traccar/geocoder/JsonGeocoder.java
+++ b/src/org/traccar/geocoder/JsonGeocoder.java
@@ -64,10 +64,11 @@ public abstract class JsonGeocoder implements Geocoder {
}
return formattedAddress;
} else {
+ String msg = "Empty address. Error: " + parseError(json);
if (callback != null) {
- callback.onFailure(new GeocoderException("Empty address"));
+ callback.onFailure(new GeocoderException(msg));
} else {
- LOGGER.warn("Empty address");
+ LOGGER.warn(msg);
}
}
return null;
@@ -113,4 +114,8 @@ public abstract class JsonGeocoder implements Geocoder {
public abstract Address parseAddress(JsonObject json);
+ protected String parseError(JsonObject json) {
+ return null;
+ }
+
}
diff --git a/src/org/traccar/protocol/AtrackProtocolDecoder.java b/src/org/traccar/protocol/AtrackProtocolDecoder.java
index 1963763ed..71bb6791c 100644
--- a/src/org/traccar/protocol/AtrackProtocolDecoder.java
+++ b/src/org/traccar/protocol/AtrackProtocolDecoder.java
@@ -381,7 +381,7 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
.number("(d+),") // speed
.number("(d+),") // outputs
.number("(d+),") // adc
- .number("[^,]*,") // driver
+ .number("([^,]+)?,") // driver
.number("(d+),") // temp1
.number("(d+),") // temp2
.expression("[^,]*,") // text message
@@ -455,6 +455,11 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_OUTPUT, parser.nextInt());
position.set(Position.PREFIX_ADC + 1, parser.nextInt());
+
+ if (parser.hasNext()) {
+ position.set(Position.KEY_DRIVER_UNIQUE_ID, parser.next());
+ }
+
position.set(Position.PREFIX_TEMP + 1, parser.nextInt());
position.set(Position.PREFIX_TEMP + 2, parser.nextInt());
diff --git a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
index 97cc8f987..31ff4a670 100644
--- a/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
+++ b/src/org/traccar/protocol/Gl200TextProtocolDecoder.java
@@ -1079,9 +1079,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder {
return null;
}
- int hdop = parser.nextInt();
- position.setValid(hdop > 0);
- position.set(Position.KEY_HDOP, hdop);
+ if (parser.hasNext()) {
+ int hdop = parser.nextInt();
+ position.setValid(hdop > 0);
+ position.set(Position.KEY_HDOP, hdop);
+ }
position.setSpeed(UnitsConverter.knotsFromKph(parser.nextDouble(0)));
position.setCourse(parser.nextDouble(0));
diff --git a/src/org/traccar/protocol/GoSafeProtocolDecoder.java b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
index 06bd0873d..95ef18f20 100644
--- a/src/org/traccar/protocol/GoSafeProtocolDecoder.java
+++ b/src/org/traccar/protocol/GoSafeProtocolDecoder.java
@@ -112,7 +112,7 @@ public class GoSafeProtocolDecoder extends BaseProtocolDecoder {
break;
case "COT":
if (index < values.length) {
- position.set(Position.KEY_ODOMETER, Integer.parseInt(values[index++]));
+ position.set(Position.KEY_ODOMETER, Long.parseLong(values[index++]));
}
if (index < values.length) {
String[] hours = values[index].split("-");
diff --git a/src/org/traccar/protocol/ItsProtocolDecoder.java b/src/org/traccar/protocol/ItsProtocolDecoder.java
index d3cdb14c3..000e7759f 100644
--- a/src/org/traccar/protocol/ItsProtocolDecoder.java
+++ b/src/org/traccar/protocol/ItsProtocolDecoder.java
@@ -18,6 +18,7 @@ package org.traccar.protocol;
import io.netty.channel.Channel;
import org.traccar.BaseProtocolDecoder;
import org.traccar.DeviceSession;
+import org.traccar.NetworkMessage;
import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
@@ -72,7 +73,13 @@ public class ItsProtocolDecoder extends BaseProtocolDecoder {
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
- Parser parser = new Parser(PATTERN, (String) msg);
+ String sentence = (String) msg;
+
+ if (channel != null && sentence.startsWith("$,01,")) {
+ channel.writeAndFlush(new NetworkMessage("$,01,", remoteAddress));
+ }
+
+ Parser parser = new Parser(PATTERN, sentence);
if (!parser.matches()) {
return null;
}
diff --git a/src/org/traccar/protocol/L100FrameDecoder.java b/src/org/traccar/protocol/L100FrameDecoder.java
index b7caa14f4..9e08120dd 100644
--- a/src/org/traccar/protocol/L100FrameDecoder.java
+++ b/src/org/traccar/protocol/L100FrameDecoder.java
@@ -20,6 +20,8 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import org.traccar.BaseFrameDecoder;
+import java.nio.charset.StandardCharsets;
+
public class L100FrameDecoder extends BaseFrameDecoder {
@Override
@@ -30,6 +32,15 @@ public class L100FrameDecoder extends BaseFrameDecoder {
return null;
}
+ if (buf.getCharSequence(buf.readerIndex(), 4, StandardCharsets.US_ASCII).equals("ATL,")) {
+ return decodeNew(buf);
+ } else {
+ return decodeOld(buf);
+ }
+ }
+
+ private Object decodeOld(ByteBuf buf) {
+
int header = buf.getByte(buf.readerIndex());
boolean obd = header == 'L' || header == 'H';
@@ -38,9 +49,9 @@ public class L100FrameDecoder extends BaseFrameDecoder {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '*');
} else {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x02);
- if (index == -1) {
+ if (index < 0) {
index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) 0x04);
- if (index == -1) {
+ if (index < 0) {
return null;
}
}
@@ -60,4 +71,20 @@ public class L100FrameDecoder extends BaseFrameDecoder {
return null;
}
+ private Object decodeNew(ByteBuf buf) {
+
+ int index = buf.indexOf(buf.readerIndex(), buf.writerIndex(), (byte) '@');
+ if (index < 0) {
+ return null;
+ }
+
+ if (buf.writerIndex() >= index + 1) {
+ ByteBuf frame = buf.readRetainedSlice(index - buf.readerIndex());
+ buf.skipBytes(1); // delimiter
+ return frame;
+ }
+
+ return null;
+ }
+
}
diff --git a/src/org/traccar/protocol/L100ProtocolDecoder.java b/src/org/traccar/protocol/L100ProtocolDecoder.java
index 07c5622cb..4d6b8f34b 100644
--- a/src/org/traccar/protocol/L100ProtocolDecoder.java
+++ b/src/org/traccar/protocol/L100ProtocolDecoder.java
@@ -40,6 +40,7 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.text("ATL")
+ .expression(",[^,]+,").optional()
.number("(d{15}),") // imei
.text("$GPRMC,")
.number("(dd)(dd)(dd)") // time (hhmmss.sss)
@@ -109,6 +110,27 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
.expression("(.+)") // data
.compile();
+ private static final Pattern PATTERN_NEW = new PatternBuilder()
+ .groupBegin()
+ .text("ATL,")
+ .expression("[LH],") // archive
+ .number("(d{15}),") // imei
+ .groupEnd("?")
+ .expression("([NPT]),") // alarm
+ .number("(dd)(dd)(dd),") // date (ddmmyy)
+ .number("(dd)(dd)(dd),") // time (hhmmss)
+ .expression("([AV]),") // validity
+ .number("(d+.d+),([NS]),") // latitude
+ .number("(d+.d+),([EW]),") // longitude
+ .number("(d+.?d*),") // speed
+ .expression("(?:GPS|GSM|INV),")
+ .number("(d+),") // battery
+ .number("(d+),") // mcc
+ .number("(d+),") // mnc
+ .number("(d+),") // lac
+ .number("(d+)") // cid
+ .compile();
+
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
@@ -121,6 +143,8 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
} else {
return decodeObdLocation(channel, remoteAddress, sentence);
}
+ } else if (!sentence.contains("$GPRMC")) {
+ return decodeNew(channel, remoteAddress, sentence);
} else {
return decodeNormal(channel, remoteAddress, sentence);
}
@@ -264,4 +288,50 @@ public class L100ProtocolDecoder extends BaseProtocolDecoder {
return position;
}
+ private Object decodeNew(Channel channel, SocketAddress remoteAddress, String sentence) {
+
+ Parser parser = new Parser(PATTERN_NEW, sentence);
+ if (!parser.matches()) {
+ return null;
+ }
+
+ String imei = parser.next();
+ DeviceSession deviceSession;
+ if (imei != null) {
+ deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ } else {
+ deviceSession = getDeviceSession(channel, remoteAddress);
+ }
+ if (deviceSession == null) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ switch (parser.next()) {
+ case "P":
+ position.set(Position.KEY_ALARM, Position.ALARM_SOS);
+ break;
+ case "T":
+ position.set(Position.KEY_ALARM, Position.ALARM_TAMPERING);
+ break;
+ default:
+ break;
+ }
+
+ position.setTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS));
+ position.setValid(parser.next().equals("A"));
+ position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_HEM));
+ position.setSpeed(parser.nextDouble());
+
+ position.set(Position.KEY_BATTERY, parser.nextInt() * 0.001);
+
+ position.setNetwork(new Network(CellTower.from(
+ parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextHexInt())));
+
+ return position;
+ }
+
}
diff --git a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
index 06ecba357..cbfc3660a 100644
--- a/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
+++ b/src/org/traccar/protocol/MeiligaoProtocolDecoder.java
@@ -402,7 +402,7 @@ public class MeiligaoProtocolDecoder extends BaseProtocolDecoder {
sendResponse(channel, remoteAddress, id, MSG_HEARTBEAT, response);
return null;
} else if (command == MSG_SERVER) {
- ByteBuf response = Unpooled.copiedBuffer(getServer(channel), StandardCharsets.US_ASCII);
+ ByteBuf response = Unpooled.copiedBuffer(getServer(channel, ':'), StandardCharsets.US_ASCII);
sendResponse(channel, remoteAddress, id, MSG_SERVER, response);
return null;
} else if (command == MSG_UPLOAD_PHOTO) {
diff --git a/src/org/traccar/protocol/NyitechProtocol.java b/src/org/traccar/protocol/NyitechProtocol.java
new file mode 100644
index 000000000..58974be5c
--- /dev/null
+++ b/src/org/traccar/protocol/NyitechProtocol.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.traccar.protocol;
+
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import org.traccar.BaseProtocol;
+import org.traccar.PipelineBuilder;
+import org.traccar.TrackerServer;
+
+import java.nio.ByteOrder;
+
+public class NyitechProtocol extends BaseProtocol {
+
+ public NyitechProtocol() {
+ addServer(new TrackerServer(false, getName()) {
+ @Override
+ protected void addProtocolHandlers(PipelineBuilder pipeline) {
+ pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 2, 2, -4, 0, true));
+ pipeline.addLast(new NyitechProtocolDecoder(NyitechProtocol.this));
+ }
+ });
+ }
+
+}
diff --git a/src/org/traccar/protocol/NyitechProtocolDecoder.java b/src/org/traccar/protocol/NyitechProtocolDecoder.java
new file mode 100644
index 000000000..e145205f7
--- /dev/null
+++ b/src/org/traccar/protocol/NyitechProtocolDecoder.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.traccar.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import org.traccar.BaseProtocolDecoder;
+import org.traccar.DeviceSession;
+import org.traccar.Protocol;
+import org.traccar.helper.BitUtil;
+import org.traccar.helper.DateBuilder;
+import org.traccar.helper.UnitsConverter;
+import org.traccar.model.Position;
+
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+
+public class NyitechProtocolDecoder extends BaseProtocolDecoder {
+
+ public NyitechProtocolDecoder(Protocol protocol) {
+ super(protocol);
+ }
+
+ public static final short MSG_LOGIN = 0x1001;
+ public static final short MSG_COMPREHENSIVE_LIVE = 0x2001;
+ public static final short MSG_COMPREHENSIVE_HISTORY = 0x2002;
+ public static final short MSG_ALARM = 0x2003;
+ public static final short MSG_FIXED = 0x2004;
+
+ private void decodeLocation(Position position, ByteBuf buf) {
+
+ DateBuilder dateBuilder = new DateBuilder()
+ .setDateReverse(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte())
+ .setTime(buf.readUnsignedByte(), buf.readUnsignedByte(), buf.readUnsignedByte());
+ position.setTime(dateBuilder.getDate());
+
+ int flags = buf.readUnsignedByte();
+ position.setValid(BitUtil.to(flags, 2) > 0);
+
+ double lat = buf.readUnsignedIntLE() / 3600000.0;
+ double lon = buf.readUnsignedIntLE() / 3600000.0;
+
+ position.setLatitude(BitUtil.check(flags, 2) ? lat : -lat);
+ position.setLongitude(BitUtil.check(flags, 3) ? lon : -lon);
+
+ position.setSpeed(UnitsConverter.knotsFromCps(buf.readUnsignedShortLE()));
+ position.setCourse(buf.readUnsignedShortLE() * 0.1);
+ position.setAltitude(buf.readShortLE() * 0.1);
+ }
+
+ private String decodeAlarm(int type) {
+ switch (type) {
+ case 0x09:
+ return Position.ALARM_ACCELERATION;
+ case 0x0a:
+ return Position.ALARM_BRAKING;
+ case 0x0b:
+ return Position.ALARM_CORNERING;
+ case 0x0e:
+ return Position.ALARM_SOS;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ protected Object decode(
+ Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {
+
+ ByteBuf buf = (ByteBuf) msg;
+
+ buf.skipBytes(2); // header
+ buf.readUnsignedShortLE(); // length
+
+ String id = buf.readCharSequence(12, StandardCharsets.US_ASCII).toString();
+ DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, id);
+ if (deviceSession == null) {
+ return null;
+ }
+
+ int type = buf.readUnsignedShortLE();
+
+ if (type != MSG_LOGIN && type != MSG_COMPREHENSIVE_LIVE
+ && type != MSG_COMPREHENSIVE_HISTORY && type != MSG_ALARM && type != MSG_FIXED) {
+ return null;
+ }
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ if (type == MSG_COMPREHENSIVE_LIVE || type == MSG_COMPREHENSIVE_HISTORY) {
+ buf.skipBytes(6); // time
+ buf.skipBytes(3); // data
+ } else if (type == MSG_ALARM) {
+ buf.readUnsignedShortLE(); // random number
+ buf.readUnsignedByte(); // tag
+ position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte()));
+ buf.readUnsignedShortLE(); // threshold
+ buf.readUnsignedShortLE(); // value
+ buf.skipBytes(6); // time
+ } else if (type == MSG_FIXED) {
+ buf.skipBytes(6); // time
+ }
+
+ decodeLocation(position, buf);
+
+ return position;
+ }
+
+}
diff --git a/src/org/traccar/protocol/SpotProtocolDecoder.java b/src/org/traccar/protocol/SpotProtocolDecoder.java
index 78b2b0487..da36c2048 100644
--- a/src/org/traccar/protocol/SpotProtocolDecoder.java
+++ b/src/org/traccar/protocol/SpotProtocolDecoder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,14 @@ public class SpotProtocolDecoder extends BaseHttpProtocolDecoder {
public SpotProtocolDecoder(Protocol protocol) {
super(protocol);
try {
- documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+ builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ builderFactory.setXIncludeAware(false);
+ builderFactory.setExpandEntityReferences(false);
+ documentBuilder = builderFactory.newDocumentBuilder();
xPath = XPathFactory.newInstance().newXPath();
messageExpression = xPath.compile("//messageList/message");
} catch (ParserConfigurationException | XPathExpressionException e) {
diff --git a/src/org/traccar/protocol/WristbandProtocolDecoder.java b/src/org/traccar/protocol/WristbandProtocolDecoder.java
index 4e044c915..7f2b0af85 100644
--- a/src/org/traccar/protocol/WristbandProtocolDecoder.java
+++ b/src/org/traccar/protocol/WristbandProtocolDecoder.java
@@ -25,7 +25,10 @@ import org.traccar.Protocol;
import org.traccar.helper.Parser;
import org.traccar.helper.PatternBuilder;
import org.traccar.helper.UnitsConverter;
+import org.traccar.model.CellTower;
+import org.traccar.model.Network;
import org.traccar.model.Position;
+import org.traccar.model.WifiAccessPoint;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
@@ -46,12 +49,16 @@ public class WristbandProtocolDecoder extends BaseProtocolDecoder {
Channel channel, String imei, String version, int type, String data) {
if (channel != null) {
- String sentence = String.format("YX%s|%s|0|{F%d#%s}\r\n", imei, version, type, data);
+ String sentence = String.format("YX%s|%s|0|{F%02d#%s}\r\n", imei, version, type, data);
ByteBuf response = Unpooled.buffer();
- response.writeBytes(new byte[]{0x00, 0x01, 0x02});
- response.writeShort(sentence.length());
+ if (type != 91) {
+ response.writeBytes(new byte[]{0x00, 0x01, 0x02});
+ response.writeShort(sentence.length());
+ }
response.writeCharSequence(sentence, StandardCharsets.US_ASCII);
- response.writeBytes(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFC});
+ if (type != 91) {
+ response.writeBytes(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFC});
+ }
channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress()));
}
}
@@ -59,7 +66,7 @@ public class WristbandProtocolDecoder extends BaseProtocolDecoder {
private static final Pattern PATTERN = new PatternBuilder()
.expression("..") // header
.number("(d+)|") // imei
- .number("(vd+.d+)|") // version
+ .number("([vV]d+.d+)|") // version
.number("d+|") // model
.text("{")
.number("F(d+)") // function
@@ -81,12 +88,56 @@ public class WristbandProtocolDecoder extends BaseProtocolDecoder {
position.setValid(true);
position.setLongitude(Double.parseDouble(values[0]));
position.setLatitude(Double.parseDouble(values[1]));
- position.setTime(new SimpleDateFormat("yyyyMMddHHmmss").parse(values[2]));
+ position.setTime(new SimpleDateFormat("yyyyMMddHHmm").parse(values[2]));
position.setSpeed(UnitsConverter.knotsFromKph(Double.parseDouble(values[3])));
return position;
}
+ private Position decodeStatus(DeviceSession deviceSession, String sentence) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(sentence.split(",")[0]));
+
+ return position;
+ }
+
+ private Position decodeNetwork(DeviceSession deviceSession, String sentence, boolean wifi) {
+
+ Position position = new Position(getProtocolName());
+ position.setDeviceId(deviceSession.getDeviceId());
+
+ getLastLocation(position, null);
+
+ Network network = new Network();
+ String[] fragments = sentence.split("\\|");
+
+ if (wifi) {
+ for (String item : fragments[0].split("_")) {
+ String[] values = item.split(",");
+ network.addWifiAccessPoint(WifiAccessPoint.from(values[0], Integer.parseInt(values[1])));
+ }
+ }
+
+ for (String item : fragments[wifi ? 1 : 0].split(":")) {
+ String[] values = item.split(",");
+ int lac = Integer.parseInt(values[0]);
+ int mnc = Integer.parseInt(values[1]);
+ int mcc = Integer.parseInt(values[2]);
+ int cid = Integer.parseInt(values[3]);
+ int rssi = Integer.parseInt(values[4]);
+ network.addCellTower(CellTower.from(mcc, mnc, lac, cid, rssi));
+ }
+
+ position.setNetwork(network);
+
+ return position;
+ }
+
private List<Position> decodeMessage(
Channel channel, SocketAddress remoteAddress, String sentence) throws ParseException {
@@ -105,23 +156,32 @@ public class WristbandProtocolDecoder extends BaseProtocolDecoder {
int type = parser.nextInt();
List<Position> positions = new LinkedList<>();
+ String data = parser.next();
switch (type) {
case 90:
- sendResponse(channel, imei, version, type, getServer(channel));
+ sendResponse(channel, imei, version, type, getServer(channel, ','));
break;
case 91:
String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
- sendResponse(channel, imei, version, type, time + "|" + getServer(channel));
+ sendResponse(channel, imei, version, type, time + "|" + getServer(channel, ','));
break;
case 1:
- sendResponse(channel, imei, version, type, "0");
+ positions.add(decodeStatus(deviceSession, data));
+ sendResponse(channel, imei, version, type, data.split(",")[1]);
break;
case 2:
- for (String fragment : parser.next().split("\\|")) {
+ for (String fragment : data.split("\\|")) {
positions.add(decodePosition(deviceSession, fragment));
}
break;
+ case 3:
+ case 4:
+ positions.add(decodeNetwork(deviceSession, data, type == 3));
+ break;
+ case 64:
+ sendResponse(channel, imei, version, type, data);
+ break;
default:
break;
}
diff --git a/src/org/traccar/sms/HttpSmsClient.java b/src/org/traccar/sms/HttpSmsClient.java
index 994e2db4e..8e2b67bf7 100644
--- a/src/org/traccar/sms/HttpSmsClient.java
+++ b/src/org/traccar/sms/HttpSmsClient.java
@@ -38,6 +38,7 @@ public class HttpSmsClient implements SmsManager {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpSmsClient.class);
private String url;
+ private String authorizationHeader;
private String authorization;
private String template;
private boolean encode;
@@ -45,6 +46,8 @@ public class HttpSmsClient implements SmsManager {
public HttpSmsClient() {
url = Context.getConfig().getString("sms.http.url");
+ authorizationHeader = Context.getConfig().getString("sms.http.authorizationHeader",
+ SecurityRequestFilter.AUTHORIZATION_HEADER);
authorization = Context.getConfig().getString("sms.http.authorization");
if (authorization == null) {
String user = Context.getConfig().getString("sms.http.user");
@@ -70,7 +73,7 @@ public class HttpSmsClient implements SmsManager {
try {
return template
.replace("{phone}", prepareValue(destAddress))
- .replace("{message}", prepareValue(message));
+ .replace("{message}", prepareValue(message.trim()));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
@@ -78,7 +81,7 @@ public class HttpSmsClient implements SmsManager {
private Invocation.Builder getRequestBuilder() {
return Context.getClient().target(url).request()
- .header(SecurityRequestFilter.AUTHORIZATION_HEADER, authorization);
+ .header(authorizationHeader, authorization);
}
@Override