/** * This file is part of Omegle API - Java. * * Omegle API - Java is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Omegle API - Java is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Omegle API - Java. If not, see . */ package org.nikki.omegle.core; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.json.JSONArray; import org.json.JSONException; import org.nikki.omegle.Omegle; import org.nikki.omegle.event.MessageSendCallback; import org.nikki.omegle.event.OmegleEventListener; import org.nikki.omegle.util.HttpUtil; /** * Represents an active Omegle session. * * @author Nikki * */ public class OmegleSession { /** * The service used to send non-blocking messages, single threaded to ensure * message order. */ private ExecutorService eventService = Executors.newSingleThreadExecutor(); /** * The parent class */ private Omegle omegle; /** * The flag for whether this session is active, set to false when the * session is closed/disconnected. */ private boolean active = true; /** * The chat id */ private String id; /** * The URL-Safe version of the chat id */ private String encodedId; /** * The list of event listeners */ private List listeners = new LinkedList(); /** * Whether the session is seen as 'typing' or not */ private boolean typing = false; /** * The amount of failed event checks, after 3 it will disconnect. */ private int failCount = 0; /** * Constructs a new session * * @param omegle * The parent handler * @param id * The chat id */ public OmegleSession(Omegle omegle, String id) { this.omegle = omegle; this.id = id; try { this.encodedId = URLEncoder.encode(id, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } /** * An easy send function, can be used to send nonblocking messages without * the callback, same as send(text, null) * * @param text * The text to send * @param blocking * True for blocking, false for non * @throws OmegleException * If an error occurred (Only blocking, nonblocking won't report * anything) */ public void send(String text, boolean blocking) throws OmegleException { if (blocking) { send(text); } else { send(text, null); } } /** * Non-blocking send * * @param text * The text to send * @param callback * The callback to use to inform that the message was sent, or * null if none. */ public void send(final String text, final MessageSendCallback callback) { eventService.execute(new Runnable() { @Override public void run() { try { send(text); if (callback != null) callback.messageSent(OmegleSession.this, text); } catch (OmegleException e) { if (callback != null) callback.messageError(OmegleSession.this, e); } } }); } /** * Blocking send method, it's the backbone of the send functions. * * @param text * The text to send * @throws OmegleException * If an error occurred while attempting to send */ public void send(final String text) throws OmegleException { Map map = new HashMap(); map.put("id", id); map.put("msg", text); try { String resp = HttpUtil.post(Omegle.SEND_URL, map); if (!resp.equals("win")) { throw new OmegleException("Unable to send message, response: " + resp); } fireEvent(OmegleEvent.messageSent, text); } catch (IOException e) { throw new OmegleException(e); } } /** * Set the status to typing. * * @throws OmegleException * If an error occurred while attempting to set the typing * status */ public void typing() throws OmegleException { try { String resp = HttpUtil.post(Omegle.TYPING_URL, "id=" + encodedId); if (!resp.equals("win")) { throw new OmegleException( "Unable to set state to typing, response: " + resp); } typing = !typing; } catch (IOException e) { throw new OmegleException(e); } } /** * Called to check events, CAN be called by users, but the main thread will * call it again when the next cycle is received. */ public void checkEvents() { try { String resp = HttpUtil.post(Omegle.EVENT_URL, "id=" + encodedId); if (resp == null || resp.equals("null")) { if (failCount++ >= 3) { fireEvent(OmegleEvent.disconnected, null); omegle.removeSession(this); } return; } parseEvents(new JSONArray(resp)); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } } /** * Parses events from a JSON Array * @param events * The array containing events * @throws JSONException * If an error occurred while reading the JSON values */ public void parseEvents(JSONArray events) throws JSONException { for (int i = 0; i < events.length(); i++) { JSONArray e = events.getJSONArray(i); OmegleEvent event = OmegleEvent.valueOf(e.getString(0)); if(event != null) { fireEvent(event, e); } } } /** * Internal function used to call events. Note: Events are called on a * service while parsed, it is best to not use any blocking operations * (Sending chat messages, etc) in events, unless they are performed * quickly. * * @param event * The event name * @param obj * The event data */ private void fireEvent(OmegleEvent event, Object obj) { try { //Called for EVERY event. JSONArray arrayObj = obj instanceof JSONArray ? (JSONArray) obj : new JSONArray(new Object[] {obj}); for (OmegleEventListener listener : listeners) { listener.eventFired(this, event, arrayObj); } //Call the appropriate handler. switch (event) { case waiting: for (OmegleEventListener listener : listeners) { listener.chatWaiting(this); } break; case connected: for (OmegleEventListener listener : listeners) { listener.chatConnected(this); } break; case gotMessage: String message = ((JSONArray) obj).getString(1); for (OmegleEventListener listener : listeners) { listener.chatMessage(this, message); } break; case strangerDisconnected: for (OmegleEventListener listener : listeners) { listener.strangerDisconnected(this); } // Closed the session. active = false; omegle.removeSession(this); break; case typing: for (OmegleEventListener listener : listeners) { listener.strangerTyping(this); } break; case stoppedTyping: for (OmegleEventListener listener : listeners) { listener.strangerStoppedTyping(this); } break; case recaptchaRequired: Map requiredVals = HttpUtil.parseQueryString(((JSONArray) obj).getString(1)); for (OmegleEventListener listener : listeners) { listener.recaptchaRequired(this, requiredVals); } break; case recaptchaRejected: Map rejectedVals = HttpUtil.parseQueryString(((JSONArray) obj).getString(1)); for (OmegleEventListener listener : listeners) { listener.recaptchaRejected(this, rejectedVals); } break; case count: int count = ((JSONArray) obj).getInt(1); for (OmegleEventListener listener : listeners) { listener.count(this, count); } break; case spyMessage: JSONArray a = (JSONArray) obj; int strangerId = Integer.valueOf(a.getString(1).substring(9)); OmegleSpyStranger stranger = OmegleSpyStranger.values()[strangerId-1]; String spyMessage = a.getString(2); for (OmegleEventListener listener : listeners) { listener.spyMessage(this, stranger, spyMessage); } break; case spyTyping: OmegleSpyStranger typingStranger = OmegleSpyStranger.valueOf(((JSONArray) obj).getString(1).replace(" ", "_")); for (OmegleEventListener listener : listeners) { listener.spyTyping(this, typingStranger); } break; case spyStoppedTyping: OmegleSpyStranger sTypingStranger = OmegleSpyStranger.valueOf(((JSONArray) obj).getString(1).replace(" ", "_")); for (OmegleEventListener listener : listeners) { listener.spyStoppedTyping(this, sTypingStranger); } break; case spyDisconnected: OmegleSpyStranger disconnectedStranger = OmegleSpyStranger.valueOf(((JSONArray) obj).getString(1).replace(" ", "_")); for (OmegleEventListener listener : listeners) { listener.spyDisconnected(this, disconnectedStranger); } break; case question: String question = ((JSONArray) obj).getString(1); for(OmegleEventListener listener : listeners) { listener.question(this, question); } break; case error: String errorMessage = ((JSONArray) obj).getString(1); for (OmegleEventListener listener : listeners) { listener.omegleError(this, errorMessage); } break; case commonLikes: break; //Custom events case messageSent: for (OmegleEventListener listener : listeners) { listener.messageSent(this, obj.toString()); } break; case disconnected: for (OmegleEventListener listener : listeners) { listener.chatDisconnected(this); } active = false; break; } } catch (Exception e) { // Nothing e.printStackTrace(); } } /** * Disconnect from the omegle chat * * @throws OmegleException * If an error occurred while disconnecting */ public void disconnect() throws OmegleException { try { String resp = HttpUtil.post(Omegle.DISCONNECT_URL, "id=" + encodedId); if (!resp.equals("win")) { throw new OmegleException("Unable to disconnect, response: " + resp); } fireEvent(OmegleEvent.disconnected, null); omegle.removeSession(this); } catch (IOException e) { throw new OmegleException(e); } } /** * Add an OmegleEventListener to our list of listeners * * @param listener * The listener to add */ public void addListener(OmegleEventListener listener) { listeners.add(listener); } /** * Gets whether this session is active. * * @return True, if the session is active. */ public boolean isActive() { return active; } /** * Get the chat id * * @return The current chat id */ public String getId() { return id; } }