/* * Copyright 2007 Sun Microsystems, Inc. * * This file is part of jVoiceBridge. * * jVoiceBridge is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation and distributed hereunder * to you. * * jVoiceBridge 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 this program. If not, see <http://www.gnu.org/licenses/>. * * Sun designates this particular file as subject to the "Classpath" * exception as provided by Sun in the License file that accompanied this * code. */ package com.sun.voip.server; import com.sun.voip.CallEvent; import com.sun.voip.CallEventListener; import com.sun.voip.CallState; import com.sun.voip.Logger; import java.io.IOException; import org.voicebridge.Config; /** * Listen for incoming calls, play treatments to prompt the caller for * meeting id and pass code. Transfer the call to the appropriate meeting. */ public class IncomingConferenceHandler extends Thread implements CallEventListener { private String meetingCode = ""; private String passCode = ""; private int state = WAITING_FOR_MEETING_CODE; private static final int WAITING_FOR_MEETING_CODE = 1; private static final int WAITING_FOR_PASS_CODE = 2; private static final int IN_MEETING = 3; private static final String ENTER_MEETING_CODE = "enter-conf-call-number.au;then-press-pound.au" ; private static final String INVALID_MEETING_CODE = "conf-invalid.au"; private static final String INVALID_PASS_CODE = "bad_user_id_1.au"; // "badcode.au"; private static final String INCOMING_TIMEOUT = "incoming_timeout.au"; private static final String ENTER_REQUIRED_PASS_CODE = "please-enter-your.au;access-code.au;then-press-pound.au"; private static final String LEAVE_MEETING = "leaveCLICK.au"; private static final String CALL_MUTED = "conf-muted.au"; private static final String CALL_UNMUTED = "conf-unmuted.au"; private static final String CALLER_NUMBER = "you-are-caller-number.au"; private static final int DEFAULT_TIMEOUT = 30000; private static int timeout = DEFAULT_TIMEOUT; private IncomingCallHandler incomingCallHandler; private String lastDtmfKey = ""; private String phoneNo; /** * Constructor. */ public IncomingConferenceHandler(IncomingCallHandler incomingCallHandler, String phoneNo) { this.incomingCallHandler = incomingCallHandler; this.phoneNo = phoneNo; incomingCallHandler.addCallEventListener(this); Logger.println("IncomingConferenceHandler: " + phoneNo); } private String lastMessagePlayed; private void playTreatmentToCall(String treatment) { try { incomingCallHandler.playTreatmentToCall(treatment); } catch (IOException e) { Logger.println("Call " + incomingCallHandler + " Can't play treatment " + treatment); } lastMessagePlayed = treatment; } private void playConferenceId() { if (meetingCode == null || meetingCode.length() == 0) { return; } String s = "conference.au"; for (int i = 0; i < meetingCode.length(); i++) { s += ";" + meetingCode.substring(i, i + 1) + ".au"; } playTreatmentToCall(s); } private void playNumberOfCalls() { String s = incomingCallHandler.getNumberOfCallsAsTreatment(); playTreatmentToCall(s + ";conf-peopleinconf.au"); } /* * Called when status for an incoming call changes. */ public void callEventNotification(CallEvent callEvent) { //if (Logger.logLevel >= Logger.LOG_INFO) { Logger.println("IncomingConferenceHandler " + callEvent.toString()); //} if (callEvent.equals(CallEvent.STATE_CHANGED) && callEvent.getCallState().equals(CallState.ESTABLISHED)) { /* * New incoming call */ if (callEvent.getInfo() != null) { Logger.println("IncomingConferenceHandler: " + callEvent.getInfo()); } if (Config.getInstance().getMeetingCode(phoneNo) != null) { meetingCode = Config.getInstance().getMeetingCode(phoneNo); Logger.println("IncomingConferenceHandler: meeting code " + meetingCode); if (Config.getInstance().getPassCode(meetingCode, phoneNo) == null) { try { incomingCallHandler.transferCall(meetingCode); state = IN_MEETING; } catch (IOException e) { System.err.println("Exception joining meeting! " + meetingCode + " " + e.getMessage()); } } else { state = WAITING_FOR_PASS_CODE; playTreatmentToCall(ENTER_REQUIRED_PASS_CODE); start(); } } else { playTreatmentToCall(ENTER_MEETING_CODE); state = WAITING_FOR_MEETING_CODE; start(); } return; } if (callEvent.equals(CallEvent.STATE_CHANGED) && callEvent.getCallState().equals(CallState.ENDED)) { playTreatmentToCall(LEAVE_MEETING); return; } /* * We're only interested in dtmf keys */ if (callEvent.equals(CallEvent.DTMF_KEY) == false) { return; } String dtmfKey = callEvent.getDtmfKey(); if (state == WAITING_FOR_MEETING_CODE) { getMeetingCode(dtmfKey); } else if (state == WAITING_FOR_PASS_CODE) { getPassCode(dtmfKey); } else { if (lastDtmfKey.equals("*")) { if (dtmfKey.equals("1")) { incomingCallHandler.setMuted(true); playTreatmentToCall(CALL_MUTED); } else if (dtmfKey.equals("2")) { incomingCallHandler.setMuted(false); playTreatmentToCall(CALL_UNMUTED); } else if (dtmfKey.equals("9")) { playConferenceId(); } else if (dtmfKey.equals("#")) { playNumberOfCalls(); } } } lastDtmfKey = dtmfKey; } private void getMeetingCode(String dtmfKey) { if (!dtmfKey.equals("#")) { meetingCode += dtmfKey; // accumulate meeting code return; } if (meetingCode.length() == 0) { playTreatmentToCall(INVALID_MEETING_CODE + ";" + ENTER_MEETING_CODE); return; } String confRoom = null; if (Config.getInstance().isValidConference(meetingCode)) { confRoom = meetingCode; } else if (Config.getInstance().isValidConferenceExten(meetingCode)) { confRoom = Config.getInstance().getMeetingCode(meetingCode); } if (confRoom != null) { if (Config.getInstance().getPassCode(confRoom, phoneNo) == null) { try { incomingCallHandler.transferCall(confRoom); state = IN_MEETING; } catch (IOException e) { System.err.println("Exception joining meeting! " + meetingCode + " " + e.getMessage()); } } else { state = WAITING_FOR_PASS_CODE; playTreatmentToCall(ENTER_REQUIRED_PASS_CODE); return; } } else { playTreatmentToCall(INVALID_MEETING_CODE + ";" + ENTER_MEETING_CODE); meetingCode = ""; state = WAITING_FOR_MEETING_CODE; return; } } private void getPassCode(String dtmfKey) { if (!dtmfKey.equals("#")) { passCode += dtmfKey; // accumulate pass code return; } /* * For now, allow people to join without a passCode */ int intPassCode = 0; if (passCode.length() > 0) { try { intPassCode = Integer.parseInt(passCode); } catch (NumberFormatException e) { playTreatmentToCall(INVALID_PASS_CODE); passCode = ""; return; } } if (Config.getInstance().isValidConferencePin(meetingCode, passCode)) { try { incomingCallHandler.transferCall(meetingCode); state = IN_MEETING; } catch (IOException e) { System.err.println("Exception joining meeting! " + meetingCode + " " + e.getMessage()); playTreatmentToCall(INVALID_PASS_CODE); passCode = ""; state = WAITING_FOR_PASS_CODE; } } else { playTreatmentToCall(INVALID_PASS_CODE); passCode = ""; state = WAITING_FOR_PASS_CODE; } } public void run() { /* * Timeout handler to re-prompt user */ long startTime = System.currentTimeMillis(); while (state == WAITING_FOR_MEETING_CODE || state == WAITING_FOR_PASS_CODE) { int currentState = state; try { Thread.sleep(timeout); if (state != WAITING_FOR_MEETING_CODE && state != WAITING_FOR_PASS_CODE) { break; } if (currentState == state) { if (System.currentTimeMillis() - startTime >= CallSetupAgent.getDefaultCallAnswerTimeout() * 1000) { playTreatmentToCall(INCOMING_TIMEOUT); /* We'd like to wait until the treatment is done * before cancelling the call. */ try { Thread.sleep(5000); } catch (InterruptedException e) { } incomingCallHandler.cancelRequest( "Incoming call timeout"); break; } playTreatmentToCall(lastMessagePlayed); } } catch (InterruptedException e) { Logger.println("Incoming ConferenceHandler Interrupted!"); } } } }