package uk.co.mmscomputing.device.capi; import java.io.*; import java.util.*; import uk.co.mmscomputing.concurrent.*; import uk.co.mmscomputing.device.capi.ctrl.*; import uk.co.mmscomputing.device.capi.plc.*; import uk.co.mmscomputing.device.capi.ncc.*; import uk.co.mmscomputing.device.capi.protocol.*; import uk.co.mmscomputing.device.capi.exception.*; import uk.co.mmscomputing.device.capi.facility.*; public class CapiPLC extends CapiChannel{ private boolean ischangingprotocols = false; private boolean outgoing = false; private Vector nccs = new Vector(); // set of logical connections private int msgno = 0; private int reason = -1; // disconnect reason private Semaphore ds = new Semaphore(0,true); private int isonhold = 0; public CapiPLC(CapiApplication appl,ConnectInd msg){ super(appl,msg.lineid); this.outgoing=false; this.isopen=true; } public CapiPLC(CapiApplication appl,ConnectReq msg){ super(appl,0); this.outgoing=true; this.isopen=true; this.msgno=msg.msgno; // with msgno we will be able to map a ConnectConf to this ConnectReq } int getMsgno(){return msgno;} // called from CapiApplication void setLineid(int pcli){lineid=pcli;} // called from CapiApplication public CapiNCC getNCC(int ncci)throws CapiException{ CapiNCC ncc; for(Enumeration e=nccs.elements();e.hasMoreElements();){ ncc=(CapiNCC)e.nextElement(); if(ncc.getLineID()==ncci){return ncc;} } CapiException ce = new CapiException(getClass().getName()+".getNCC(0x"+Integer.toHexString(ncci)+")\n\tCannot find NCC."); ce.printStackTrace(); throw ce; } public CapiNCC getNCC(){return (CapiNCC)nccs.get(0);} private void addNCC(CapiNCC ncc){ nccs.add(ncc); ncc.setProtocol(protocol); ncc.setSpeechCoding(getSpeechCoding()); ncc.setLocalNo(getLocalNo()); ncc.setRemoteNo(getRemoteNo()); ncc.setPlugin(getPlugin()); ncc.setPickupBlocker(getPickupBlocker()); } CapiNCC addNCC(ConnectB3Ind msg){ CapiNCC ncc=new CapiNCC(appl,msg);addNCC(ncc);return ncc; } CapiNCC addNCC(ConnectB3Conf msg){ CapiNCC ncc=new CapiNCC(appl,msg);addNCC(ncc);return ncc; } void remove(CapiNCC ncc)throws CapiException{ // System.err.println("REMOVE NCC = 0x"+Integer.toHexString(lineid)); nccs.remove(ncc); // receive this signal everytime an ncc has received a DisconnectB3Ind if(nccs.isEmpty()){ if(ischangingprotocols){ ischangingprotocols=false; appl.put(new SelectBProtocolReq(applid,lineid,protocol)); }else if(isonhold==1){ // put "on hold" in process; don't disconnect plc }else{ activeDisconnect(); } } } public CapiInputStream getInputStream(int ncci)throws IOException{ return getNCC(ncci).getInputStream(); } public CapiOutputStream getOutputStream(int ncci)throws IOException{ return getNCC(ncci).getOutputStream(); } public CapiInputStream getInputStream()throws IOException{ return ((CapiNCC)nccs.get(0)).getInputStream(); } public CapiOutputStream getOutputStream()throws IOException{ return ((CapiNCC)nccs.get(0)).getOutputStream(); } void received(ConnectActiveInd msg)throws CapiException{ if(outgoing){ appl.put(new ConnectB3Req(msg.appid,msg.lineid)); } } int getDisconnectReason(){return reason;} void received(DisconnectInd msg)throws CapiException{ // No messages will be sent to plc after DisconnectInd isonhold=0; reason=msg.getErrNo(); // 0x34xx are cause values from network. Q.850/ETS 300 102 - 1: Octet 4 if(checkIsNotDisconnected()){ CapiNCC[] lines=(CapiNCC[])nccs.toArray(new CapiNCC[0]); for(int i=0;i<lines.length;i++){ // tell nccs about disconnect if still open lines[i].disconnect(reason); nccs.remove(lines[i]); } } ds.release(); // release disconnect semaphore releasePickupBlocker(); // if a thread is waiting for a connection release (CapiServerApplication.connect) } public void selectProtocol(BProtocol protocol)throws CapiException{ if(isopen){ ischangingprotocols=true; this.protocol=protocol; CapiNCC[] lines=(CapiNCC[])nccs.toArray(new CapiNCC[0]); for(int i=0;i<lines.length;i++){ try{ lines[i].setChangedProtocol(true); lines[i].close(); // CapiNCC.close will wait for DisconnectB3Ind }catch(IOException ioe){ ioe.printStackTrace(); } } } } public void selectFaxProtocol()throws CapiException{ selectProtocol(new FaxBProtocol(0,0,"","")); } private void activeDisconnect()throws CapiException{ if(checkIsNotDisconnected()){ appl.put(new DisconnectReq(applid,lineid)); } } public void close()throws IOException{ // called from none capi thread if(checkIsOpen()){ CapiNCC[] lines=(CapiNCC[])nccs.toArray(new CapiNCC[0]); for(int i=0;i<lines.length;i++){ // close all open nccs try{ lines[i].close(); // CapiNCC.close will wait for DisconnectB3Ind }catch(IOException ioe){ ioe.printStackTrace(); } } // all nccs are closed activeDisconnect(); // active disconnect } try{ds.acquire();}catch(InterruptedException ie){} // wait for DisconnectInd ds.release(); // release another thread if waiting } // ---- SUP SERVICE ---- // ---- HOLD/RETRIEVE ---- public boolean isOnHold(){ while(isonhold==1){ // wait until we receive HoldInd/RetrieveInd try{Thread.currentThread().sleep(100);}catch(Exception e){} } return isonhold==2; } public boolean hold()throws CapiException{ if(isonhold==0){ isonhold=1; appl.put(new SupServiceReq.HoldReq(applid,lineid)); } return isOnHold(); // wait until we receive HoldInd } public boolean retrieve()throws CapiException{ if(isonhold==2){ isonhold=1; appl.put(new SupServiceReq.RetrieveReq(applid,lineid)); } return !isOnHold(); // wait until we receive RetrieveInd } public CapiChannel retrieveChannel()throws CapiException{// retrieve B-Channel if(isDisconnected()){return null;} if(!isOnHold()){ put(new ConnectB3Req(applid,lineid)); while(nccs.size()==0){ // wait until we receive new NCC try{Thread.currentThread().sleep(100);}catch(Exception e){} } } return getNCC(); } // ---- END : HOLD/RETRIEVE ---- // ---- ECT Explicit Call Transfer ---- public void explicitCallTransferTo(CapiPLC active)throws CapiException{ // ECT if(!hold()){ // Need one channel on hold throw new CapiException("Explicit Call Transfer: Cannot put call on hold."); } CapiNCC[] lines=(CapiNCC[])nccs.toArray(new CapiNCC[0]); for(int i=0;i<lines.length;i++){ // close all open nccs try{ lines[i].close(); // CapiNCC.close will wait for DisconnectB3Ind }catch(IOException ioe){ ioe.printStackTrace(); } } // all nccs are closed // The PLCI of the active connection is in the parameter PLCI, and the PLCI of the held connection is in // the parameter Facility Request Parameter/Supplementary Service-specific parameter/PLCI). SupServiceReq.ECTReq ectReq=new SupServiceReq.ECTReq(applid,active.getLineID(),getLineID()); // explicit call transfer appl.put(ectReq); } // ---- END : ECT Explicit Call Transfer ---- void received(SupServiceInd msg)throws CapiException{ if(msg instanceof SupServiceInd.HoldInd){ appl.put(new SupServiceResp.HoldResp(msg.appid,msg.lineid)); isonhold=(((SupServiceInd.HoldInd)msg).getReason()==0)?2:0; }else if(msg instanceof SupServiceInd.RetrieveInd){ appl.put(new SupServiceResp.RetrieveResp(msg.appid,msg.lineid)); isonhold=(((SupServiceInd.RetrieveInd)msg).getReason()==0)?0:2; } } void received(SupServiceConf msg)throws CapiException{ if(msg instanceof SupServiceConf.HoldConf){ isonhold=(((SupServiceConf.HoldConf)msg).getInfo()==0)?1:0; }else if(msg instanceof SupServiceConf.RetrieveConf){ } } // ---- END : SUP SERVICE ---- // ---- FACILITY ---- void received(FacilityInd msg)throws CapiException{ if(msg instanceof DTMFInd){ appl.put(new FacilityResp(msg.appid,msg.lineid,((FacilityInd)msg).getSelector())); Enumeration e=nccs.elements(); while(e.hasMoreElements()){ ((CapiNCC)e.nextElement()).receivedDTMFInd((DTMFInd)msg); } }else if(msg instanceof SupServiceInd){ received((SupServiceInd)msg); }else{ appl.put(new FacilityResp(msg.appid,msg.lineid,((FacilityInd)msg).getSelector())); System.err.println(msg); new Exception().printStackTrace(); } } void received(FacilityConf msg)throws CapiException{ if(msg instanceof DTMFConf){ Enumeration e=nccs.elements(); while(e.hasMoreElements()){ ((CapiNCC)e.nextElement()).receivedDTMFConf((DTMFConf)msg); } }else if(msg instanceof SupServiceConf){ received((SupServiceConf)msg); }else if(msg instanceof EchoCancellerConf.GetSupportedServicesConf){ EchoCancellerConf.GetSupportedServicesConf ecc=(EchoCancellerConf.GetSupportedServicesConf)msg; appl.put(new EchoCancellerReq.EnableReq(msg.appid,msg.lineid,ecc.getOptions(),ecc.getMaxTailLength(),ecc.getMaxPreDelay())); } } // ---- END : FACILITY ---- public void setPlugin(CapiPlugin plugin){ super.setPlugin(plugin); Enumeration e=nccs.elements(); while(e.hasMoreElements()){ ((CapiNCC)e.nextElement()).setPlugin(plugin); } } }