AbstractParser.java

  1package eu.siacs.conversations.parser;
  2
  3
  4import java.text.ParseException;
  5import java.text.SimpleDateFormat;
  6import java.util.ArrayList;
  7import java.util.List;
  8import java.util.Locale;
  9
 10import eu.siacs.conversations.entities.Account;
 11import eu.siacs.conversations.entities.Contact;
 12import eu.siacs.conversations.entities.Conversation;
 13import eu.siacs.conversations.entities.MucOptions;
 14import eu.siacs.conversations.services.XmppConnectionService;
 15import eu.siacs.conversations.xml.Element;
 16import eu.siacs.conversations.xmpp.InvalidJid;
 17import eu.siacs.conversations.xmpp.Jid;
 18import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
 19
 20public abstract class AbstractParser {
 21
 22	protected XmppConnectionService mXmppConnectionService;
 23
 24	protected AbstractParser(XmppConnectionService service) {
 25		this.mXmppConnectionService = service;
 26	}
 27
 28	public static Long parseTimestamp(Element element, Long d) {
 29		return parseTimestamp(element,d,false);
 30	}
 31
 32	public static Long parseTimestamp(Element element, Long d, boolean ignoreCsiAndSm) {
 33		long min = Long.MAX_VALUE;
 34		boolean returnDefault = true;
 35		final Jid to;
 36		if (ignoreCsiAndSm && element instanceof AbstractStanza) {
 37			to = ((AbstractStanza) element).getTo();
 38		} else {
 39			to = null;
 40		}
 41		for(Element child : element.getChildren()) {
 42			if ("delay".equals(child.getName()) && "urn:xmpp:delay".equals(child.getNamespace())) {
 43				final Jid f = to == null ? null : InvalidJid.getNullForInvalid(child.getAttributeAsJid("from"));
 44				if (f != null && (to.asBareJid().equals(f) || to.getDomain().equals(f))) {
 45					continue;
 46				}
 47				final String stamp = child.getAttribute("stamp");
 48				if (stamp != null) {
 49					try {
 50						min = Math.min(min,AbstractParser.parseTimestamp(stamp));
 51						returnDefault = false;
 52					} catch (Throwable t) {
 53						//ignore
 54					}
 55				}
 56			}
 57		}
 58		if (returnDefault) {
 59			return d;
 60		} else {
 61			return min;
 62		}
 63	}
 64
 65	public static long parseTimestamp(Element element) {
 66		return parseTimestamp(element, System.currentTimeMillis());
 67	}
 68
 69	public static long parseTimestamp(String timestamp) throws ParseException {
 70		timestamp = timestamp.replace("Z", "+0000");
 71		SimpleDateFormat dateFormat;
 72		long ms;
 73		if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') {
 74			String millis = timestamp.substring(19,timestamp.length() - 5);
 75			try {
 76				double fractions = Double.parseDouble("0" + millis);
 77				ms = Math.round(1000 * fractions);
 78			} catch (NumberFormatException e) {
 79				ms = 0;
 80			}
 81		} else {
 82			ms = 0;
 83		}
 84		timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5);
 85		dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
 86		return Math.min(dateFormat.parse(timestamp).getTime()+ms, System.currentTimeMillis());
 87	}
 88
 89	protected void updateLastseen(final Account account, final Jid from) {
 90		final Contact contact = account.getRoster().getContact(from);
 91		contact.setLastResource(from.isBareJid() ? "" : from.getResource());
 92	}
 93
 94	protected String avatarData(Element items) {
 95		Element item = items.findChild("item");
 96		if (item == null) {
 97			return null;
 98		}
 99		return item.findChildContent("data", "urn:xmpp:avatar:data");
100	}
101
102	public static MucOptions.User parseItem(Conversation conference, Element item) {
103		return parseItem(conference,item, null);
104	}
105
106	public static MucOptions.User parseItem(Conversation conference, Element item, Jid fullJid) {
107		final String local = conference.getJid().getLocal();
108		final String domain = conference.getJid().getDomain().toEscapedString();
109		String affiliation = item.getAttribute("affiliation");
110		String role = item.getAttribute("role");
111		String nick = item.getAttribute("nick");
112		if (nick != null && fullJid == null) {
113			try {
114				fullJid = Jid.of(local, domain, nick);
115			} catch (IllegalArgumentException e) {
116				fullJid = null;
117			}
118		}
119		Jid realJid = item.getAttributeAsJid("jid");
120		MucOptions.User user = new MucOptions.User(conference.getMucOptions(), fullJid);
121		if (InvalidJid.isValid(realJid)) {
122			user.setRealJid(realJid);
123		}
124		user.setAffiliation(affiliation);
125		user.setRole(role);
126		return user;
127	}
128
129	public static String extractErrorMessage(final Element packet) {
130		final Element error = packet.findChild("error");
131		if (error != null && error.getChildren().size() > 0) {
132			final List<String> errorNames = orderedElementNames(error.getChildren());
133			final String text = error.findChildContent("text");
134			if (text != null && !text.trim().isEmpty()) {
135				return prefixError(errorNames)+text;
136			} else if (errorNames.size() > 0){
137				return prefixError(errorNames)+errorNames.get(0).replace("-"," ");
138			}
139		}
140		return null;
141	}
142
143	public static String errorMessage(Element packet) {
144		final Element error = packet.findChild("error");
145		if (error != null && error.getChildren().size() > 0) {
146			final List<String> errorNames = orderedElementNames(error.getChildren());
147			final String text = error.findChildContent("text");
148			if (text != null && !text.trim().isEmpty()) {
149				return text;
150			} else if (errorNames.size() > 0){
151				return errorNames.get(0).replace("-"," ");
152			}
153		}
154		return null;
155	}
156
157	private static String prefixError(List<String> errorNames) {
158		if (errorNames.size() > 0) {
159			return errorNames.get(0)+'\u001f';
160		}
161		return "";
162	}
163
164	private static List<String> orderedElementNames(List<Element> children) {
165		List<String> names = new ArrayList<>();
166		for(Element child : children) {
167			final String name = child.getName();
168			if (name != null && !name.equals("text")) {
169				if ("urn:ietf:params:xml:ns:xmpp-stanzas".equals(child.getNamespace())) {
170					names.add(name);
171				} else {
172					names.add(0, name);
173				}
174			}
175		}
176		return names;
177	}
178}