diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/org/traccar/BaseProtocolDecoder.java | 4 | ||||
-rw-r--r-- | src/org/traccar/MainEventHandler.java | 68 | ||||
-rw-r--r-- | src/org/traccar/ServerManager.java | 2 | ||||
-rw-r--r-- | src/org/traccar/geocoder/GoogleGeocoder.java | 5 | ||||
-rw-r--r-- | src/org/traccar/geocoder/JsonGeocoder.java | 9 | ||||
-rw-r--r-- | src/org/traccar/protocol/AtrackProtocolDecoder.java | 7 | ||||
-rw-r--r-- | src/org/traccar/protocol/Gl200TextProtocolDecoder.java | 8 | ||||
-rw-r--r-- | src/org/traccar/protocol/GoSafeProtocolDecoder.java | 2 | ||||
-rw-r--r-- | src/org/traccar/protocol/ItsProtocolDecoder.java | 9 | ||||
-rw-r--r-- | src/org/traccar/protocol/L100FrameDecoder.java | 31 | ||||
-rw-r--r-- | src/org/traccar/protocol/L100ProtocolDecoder.java | 70 | ||||
-rw-r--r-- | src/org/traccar/protocol/MeiligaoProtocolDecoder.java | 2 | ||||
-rw-r--r-- | src/org/traccar/protocol/NyitechProtocol.java | 37 | ||||
-rw-r--r-- | src/org/traccar/protocol/NyitechProtocolDecoder.java | 123 | ||||
-rw-r--r-- | src/org/traccar/protocol/SpotProtocolDecoder.java | 11 | ||||
-rw-r--r-- | src/org/traccar/protocol/WristbandProtocolDecoder.java | 80 | ||||
-rw-r--r-- | src/org/traccar/sms/HttpSmsClient.java | 7 |
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 |